[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: ci\n\non:\n  pull_request:\n    paths:\n      - '**'\n      - '!.gitignore'\n      - '!LICENSE'\n      - '!TODO'\n      - '!doc/**'\n      - '!examples/**'\n      - '.github/workflows/ci.yml'\n  push:\n    branches:\n      - '*'\n\njobs:\n  linux:\n    name: Linux (Ubuntu)\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y\n      - name: Stats\n        run: |\n          ./qjs -qd\n      - name: Run built-in tests\n        run: |\n          make test\n      - name: Run microbench\n        run: |\n          make microbench\n      - name: Run test262\n        run: |\n          make test2-bootstrap\n          make test2\n\n  linux-lto:\n    name: Linux LTO\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_LTO=y\n      - name: Run built-in tests\n        run: |\n          make test\n      - name: Run microbench\n        run: |\n          make microbench\n\n  linux-32bit:\n    name: Linux 32bit\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Install gcc-multilib\n        run: |\n          sudo apt update\n          sudo apt install -y gcc-multilib\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_M32=y\n      - name: Run built-in tests\n        run: |\n          make CONFIG_M32=y test\n      - name: Run test262\n        run: |\n          make test2-bootstrap\n          make CONFIG_M32=y test2\n\n  linux-asan:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y\n      - name: Run built-in tests\n        env:\n          ASAN_OPTIONS: halt_on_error=1\n        run: |\n          make CONFIG_ASAN=y test\n\n  linux-msan:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Build\n        env:\n          CC: clang\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_MSAN=y CONFIG_CLANG=y\n      - name: Run built-in tests\n        env:\n          MSAN_OPTIONS: halt_on_error=1\n        run: |\n          make CONFIG_MSAN=y CONFIG_CLANG=y test\n\n  linux-ubsan:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y\n      - name: Run built-in tests\n        env:\n          UBSAN_OPTIONS: halt_on_error=1\n        run: |\n          make CONFIG_UBSAN=y test\n\n  macos:\n    name: macOS\n    runs-on: macos-latest\n    strategy:\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y\n      - name: Stats\n        run: |\n          ./qjs -qd\n      - name: Run built-in tests\n        run: |\n          make test\n      - name: Run test262\n        run: |\n          make test2-bootstrap\n          make test2\n\n  macos-asan:\n    runs-on: macos-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_ASAN=y\n      - name: Run built-in tests\n        env:\n          ASAN_OPTIONS: halt_on_error=1\n        run: |\n          make CONFIG_ASAN=y test\n\n  macos-ubsan:\n    runs-on: macos-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Build\n        run: |\n          make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y CONFIG_UBSAN=y\n      - name: Run built-in tests\n        env:\n          UBSAN_OPTIONS: halt_on_error=1\n        run: |\n          make CONFIG_UBSAN=y test\n\n  freebsd:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n      - name: Build + test\n        uses: vmactions/freebsd-vm@v1\n        with:\n          usesh: true\n          copyback: false\n          mem: 16384\n          prepare: |\n            pkg install -y gmake\n          run: |\n            gmake\n            ./qjs -qd\n            gmake test\n\n  cosmopolitan:\n    name: Cosmopolitan\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Install Cosmopolitan\n        run: |\n          mkdir ~/cosmocc\n          cd ~/cosmocc\n          wget https://cosmo.zip/pub/cosmocc/cosmocc.zip\n          unzip cosmocc.zip\n          echo \"$HOME/cosmocc/bin\" >> \"$GITHUB_PATH\"\n      - name: Build\n        run: |\n          make CONFIG_COSMO=y\n      - name: Run built-in tests\n        run: |\n          make CONFIG_COSMO=y test\n      - name: Run test262\n        run: |\n          make test2-bootstrap\n          make CONFIG_COSMO=y test2\n\n  mingw-windows:\n    name: MinGW Windows target\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          submodules: true\n      - name: Install MinGW and Wine\n        run: |\n          sudo apt update\n          sudo apt install -y wine mingw-w64\n          cp /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll .\n      - name: Setup Wine\n        run: |\n          wine --version\n          winecfg /v\n          # binfmt doesn't work in GitHub Actions\n          #sudo apt install -y binfmt-support wine-binfmt\n          #echo \":Wine:M::MZ::/usr/bin/wine:\" > /etc/binfmt.d/wine.conf\n          #sudo systemctl restart systemd-binfmt\n      - name: Build\n        run: |\n          make CONFIG_WIN32=y\n      - name: Run built-in tests\n        run: |\n          # If binfmt support worked, could just run `make CONFIG_WIN32=y test`\n          make WINE=/usr/bin/wine CONFIG_WIN32=y test\n\n  windows-msys:\n    name: Windows MSYS2\n    runs-on: windows-latest\n    defaults:\n      run:\n        shell: msys2 {0}\n    steps:\n      - uses: actions/checkout@v4\n      - uses: msys2/setup-msys2@v2\n        with:\n          msystem: UCRT64\n          update: true\n          install: git make mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-dlfcn\n      - name: Build\n        run: |\n           make -j$(getconf _NPROCESSORS_ONLN) CONFIG_WERROR=y\n      - name: Stats\n        run: |\n          ./qjs -qd\n      - name: Run built-in tests\n        run: |\n          make test\n      - name: Run microbench\n        run: |\n          make microbench\n\n\n  qemu-alpine:\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        platform:\n          - linux/386\n          - linux/riscv64\n          - linux/arm64\n          - linux/arm/v6\n          - linux/arm/v7\n          - linux/s390x\n          - linux/ppc64le\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n            submodules: recursive\n      - name: Get qemu\n        # See https://github.com/tonistiigi/binfmt/issues/215#issuecomment-2613004741\n        run: docker run --privileged --rm tonistiigi/binfmt:master --install all\n      - name: Run tests on ${{ matrix.platform }}\n        run: docker run --rm --interactive --mount type=bind,source=$(pwd),target=/host --platform ${{ matrix.platform }} alpine sh -c \"apk add git patch make gcc libc-dev && cd /host && make test\"\n"
  },
  {
    "path": ".gitignore",
    "content": "*.a\n.obj/\ntests/bjson.so\nexamples/test_fib\ntest_fib.c\nexamples/*.so\nexamples/hello\nexamples/hello_module\nexamples/hello.exe\nexamples/test_fib.exe\nhello.c\nmicrobench*.txt\nqjs\nqjs.exe\nqjsc\nqjsc.exe\nhost-qjsc\nqjscalc\nqjscalc.c\nrepl.c\nrun-test262\nrun-test262.exe\ntest262\ntest262_*.txt\ntest262o\ntest262o_*.txt\nunicode\nunicode_gen\nrun_octane\nrun_sunspider_like\nlibwinpthread*.dll\n"
  },
  {
    "path": "Changelog",
    "content": "- micro optimizations (30% faster on bench-v8)\n- added resizable array buffers\n- added ArrayBuffer.prototype.transfer\n- added the Iterator object and methods\n- added set methods\n- added Atomics.pause\n- added added Map and WeakMap upsert methods\n- added Math.sumPrecise()\n- added regexp duplicate named groups\n- misc bug fixes\n\n2025-09-13:\n\n- added JSON modules and import attributes\n- added JS_PrintValue() API\n- qjs: pretty print objects in print() and console.log()\n- qjs: better promise rejection tracker heuristics\n- added RegExp v flag\n- added RegExp modifiers\n- added RegExp.escape\n- added Float16Array\n- added Promise.try\n- improved JSON parser spec conformance\n- qjs: improved compatibility of std.parseExtJSON() with JSON5 and\n  accept JSON5 modules\n- added JS_FreePropertyEnum() and JS_AtomToCStringLen() API\n- added Error.isError()\n- misc bug fixes\n\n2025-04-26:\n\n- removed the bignum extensions and qjscalc\n- new BigInt implementation optimized for small numbers\n- added WeakRef, FinalizationRegistry and symbols as weakrefs\n- added builtin float64 printing and parsing functions for more correctness\n- faster repeated string concatenation\n- qjs: promise unhandled rejections are fatal errors by default\n- added column number in debug information\n- removed the \"use strip\" extension\n- qjs: added -s and --strip-source options\n- qjsc: added -s and --keep-source options\n- added JS_GetAnyOpaque()\n- added more callbacks for exotic objects in JSClassExoticMethods\n- misc bug fixes\n\n2024-01-13:\n\n- top-level-await support in modules\n- allow 'await' in the REPL\n- added Array.prototype.{with,toReversed,toSpliced,toSorted} and\nTypedArray.prototype.{with,toReversed,toSorted}\n- added String.prototype.isWellFormed and String.prototype.toWellFormed\n- added Object.groupBy and Map.groupBy\n- added Promise.withResolvers\n- class static block\n- 'in' operator support for private fields\n- optional chaining fixes\n- added RegExp 'd' flag\n- fixed RegExp zero length match logic\n- fixed RegExp case insensitive flag\n- added os.sleepAsync(), os.getpid() and os.now()\n- added cosmopolitan build\n- misc bug fixes\n\n2023-12-09:\n\n- added Object.hasOwn, {String|Array|TypedArray}.prototype.at,\n  {Array|TypedArray}.prototype.findLast{Index}\n- BigInt support is enabled even if CONFIG_BIGNUM disabled\n- updated to Unicode 15.0.0\n- misc bug fixes\n\n2021-03-27:\n\n- faster Array.prototype.push and Array.prototype.unshift\n- added JS_UpdateStackTop()\n- fixed Windows console\n- misc bug fixes\n\n2020-11-08:\n\n- improved function parameter initializers\n- added std.setenv(), std.unsetenv() and std.getenviron()\n- added JS_EvalThis()\n- misc bug fixes\n\n2020-09-06:\n\n- added logical assignment operators\n- added IsHTMLDDA support\n- faster for-of loops\n- os.Worker now takes a module filename as parameter\n- qjsc: added -D option to compile dynamically loaded modules or workers\n- misc bug fixes\n\n2020-07-05:\n\n- modified JS_GetPrototype() to return a live value\n- REPL: support unicode characters larger than 16 bits\n- added os.Worker\n- improved object serialization\n- added std.parseExtJSON\n- misc bug fixes\n\n2020-04-12:\n\n- added cross realm support\n- added AggregateError and Promise.any\n- added env, uid and gid options in os.exec()\n- misc bug fixes\n\n2020-03-16:\n\n- reworked error handling in std and os libraries: suppressed I/O\n  exceptions in std FILE functions and return a positive errno value\n  when it is explicit\n- output exception messages to stderr\n- added std.loadFile(), std.strerror(), std.FILE.prototype.tello()\n- added JS_GetRuntimeOpaque(), JS_SetRuntimeOpaque(), JS_NewUint32()\n- updated to Unicode 13.0.0\n- misc bug fixes\n\n2020-01-19:\n\n- keep CONFIG_BIGNUM in the makefile\n- added os.chdir()\n- qjs: added -I option\n- more memory checks in the bignum operations\n- modified operator overloading semantics to be closer to the TC39\n  proposal\n- suppressed \"use bigint\" mode. Simplified \"use math\" mode\n- BigDecimal: changed suffix from 'd' to 'm'\n- misc bug fixes\n\n2020-01-05:\n\n- always compile the bignum code. Added '--bignum' option to qjs.\n- added BigDecimal\n- added String.prototype.replaceAll\n- misc bug fixes\n\n2019-12-21:\n\n- added nullish coalescing operator (ES2020)\n- added optional chaining (ES2020)\n- removed recursions in garbage collector\n- test stack overflow in the parser\n- improved backtrace logic\n- added JS_SetHostPromiseRejectionTracker()\n- allow exotic constructors\n- improved c++ compatibility\n- misc bug fixes\n\n2019-10-27:\n\n- added example of C class in a module (examples/test_point.js)\n- added JS_GetTypedArrayBuffer()\n- misc bug fixes\n\n2019-09-18:\n\n- added os.exec and other system calls\n- exported JS_ValueToAtom()\n- qjsc: added 'qjsc_' prefix to the generated C identifiers\n- added cross-compilation support\n- misc bug fixes\n\n2019-09-01:\n\n- added globalThis\n- documented JS_EVAL_FLAG_COMPILE_ONLY\n- added import.meta.url and import.meta.main\n- added 'debugger' statement\n- misc bug fixes\n\n2019-08-18:\n\n- added os.realpath, os.getcwd, os.mkdir, os.stat, os.lstat,\n  os.readlink, os.readdir, os.utimes, std.popen\n- module autodetection\n- added import.meta\n- misc bug fixes\n\n2019-08-10:\n\n- added public class fields and private class fields, methods and\n  accessors (TC39 proposal)\n- changed JS_ToCStringLen() prototype\n- qjsc: handle '-' in module names and modules with the same filename\n- added std.urlGet\n- exported JS_GetOwnPropertyNames() and JS_GetOwnProperty()\n- exported some bigint C functions\n- added support for eshost in run-test262\n- misc bug fixes\n\n2019-07-28:\n\n- added dynamic import\n- added Promise.allSettled\n- added String.prototype.matchAll\n- added Object.fromEntries\n- reduced number of ticks in await\n- added BigInt support in Atomics\n- exported JS_NewPromiseCapability()\n- misc async function and async generator fixes\n- enabled hashbang support by default\n\n2019-07-21:\n\n- updated test262 tests\n- updated to Unicode version 12.1.0\n- fixed missing Date object in qjsc\n- fixed multi-context creation\n- misc ES2020 related fixes\n- simplified power and division operators in bignum extension\n- fixed several crash conditions\n\n2019-07-09:\n\n- first public release\n"
  },
  {
    "path": "LICENSE",
    "content": "QuickJS Javascript Engine\n\nCopyright (c) 2017-2021 Fabrice Bellard\nCopyright (c) 2017-2021 Charlie Gordon\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\nTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "#\n# QuickJS Javascript Engine\n#\n# Copyright (c) 2017-2021 Fabrice Bellard\n# Copyright (c) 2017-2021 Charlie Gordon\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n\nifeq ($(shell uname -s),Darwin)\nCONFIG_DARWIN=y\nendif\nifeq ($(shell uname -s),FreeBSD)\nCONFIG_FREEBSD=y\nendif\n# Windows cross compilation from Linux\n# May need to have libwinpthread*.dll alongside the executable\n# (On Ubuntu/Debian may be installed with mingw-w64-x86-64-dev\n# to /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll)\n#CONFIG_WIN32=y\n# use link time optimization (smaller and faster executables but slower build)\n#CONFIG_LTO=y\n# consider warnings as errors (for development)\n#CONFIG_WERROR=y\n# force 32 bit build on x86_64\n#CONFIG_M32=y\n# cosmopolitan build (see https://github.com/jart/cosmopolitan)\n#CONFIG_COSMO=y\n\n# installation directory\nPREFIX?=/usr/local\n\n# use the gprof profiler\n#CONFIG_PROFILE=y\n# use address sanitizer\n#CONFIG_ASAN=y\n# use memory sanitizer\n#CONFIG_MSAN=y\n# use UB sanitizer\n#CONFIG_UBSAN=y\n\n# TEST262 bootstrap config: commit id and shallow \"since\" parameter\nTEST262_COMMIT?=d0994d64b07cb6c164dd9f345c94ed797a53d69f\nTEST262_SINCE?=2025-09-01\n\nOBJDIR=.obj\n\nifdef CONFIG_ASAN\nOBJDIR:=$(OBJDIR)/asan\nendif\nifdef CONFIG_MSAN\nOBJDIR:=$(OBJDIR)/msan\nendif\nifdef CONFIG_UBSAN\nOBJDIR:=$(OBJDIR)/ubsan\nendif\n\nifdef CONFIG_DARWIN\n# use clang instead of gcc\nCONFIG_CLANG=y\nCONFIG_DEFAULT_AR=y\nendif\nifdef CONFIG_FREEBSD\n# use clang instead of gcc\nCONFIG_CLANG=y\nCONFIG_DEFAULT_AR=y\nCONFIG_LTO=\nendif\n\nifdef CONFIG_WIN32\n  ifdef CONFIG_M32\n    CROSS_PREFIX?=i686-w64-mingw32-\n  else\n    CROSS_PREFIX?=x86_64-w64-mingw32-\n  endif\n  EXE=.exe\nelse ifdef MSYSTEM\n  CONFIG_WIN32=y\n  CROSS_PREFIX?=\n  EXE=.exe\nelse\n  CROSS_PREFIX?=\n  EXE=\nendif\n\nifdef CONFIG_CLANG\n  HOST_CC=clang\n  CC=$(CROSS_PREFIX)clang\n  CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d\n  CFLAGS += -Wextra\n  CFLAGS += -Wno-sign-compare\n  CFLAGS += -Wno-missing-field-initializers\n  CFLAGS += -Wundef -Wuninitialized\n  CFLAGS += -Wunused -Wno-unused-parameter\n  CFLAGS += -Wwrite-strings\n  CFLAGS += -Wchar-subscripts -funsigned-char\n  CFLAGS += -MMD -MF $(OBJDIR)/$(@F).d\n  ifdef CONFIG_DEFAULT_AR\n    AR=$(CROSS_PREFIX)ar\n  else\n    ifdef CONFIG_LTO\n      AR=$(CROSS_PREFIX)llvm-ar\n    else\n      AR=$(CROSS_PREFIX)ar\n    endif\n  endif\n  LIB_FUZZING_ENGINE ?= \"-fsanitize=fuzzer\"\nelse ifdef CONFIG_COSMO\n  CONFIG_LTO=\n  HOST_CC=gcc\n  CC=cosmocc\n  # cosmocc does not correct support -MF\n  CFLAGS=-g -Wall #-MMD -MF $(OBJDIR)/$(@F).d\n  CFLAGS += -Wno-array-bounds -Wno-format-truncation\n  AR=cosmoar\nelse\n  HOST_CC=gcc\n  CC=$(CROSS_PREFIX)gcc\n  CFLAGS+=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d\n  CFLAGS += -Wno-array-bounds -Wno-format-truncation -Wno-infinite-recursion\n  ifdef CONFIG_LTO\n    AR=$(CROSS_PREFIX)gcc-ar\n  else\n    AR=$(CROSS_PREFIX)ar\n  endif\nendif\nSTRIP?=$(CROSS_PREFIX)strip\nifdef CONFIG_M32\nCFLAGS+=-msse2 -mfpmath=sse # use SSE math for correct FP rounding\nifndef CONFIG_WIN32\nCFLAGS+=-m32\nLDFLAGS+=-m32\nendif\nendif\nCFLAGS+=-fwrapv # ensure that signed overflows behave as expected\nifdef CONFIG_WERROR\nCFLAGS+=-Werror\nendif\nDEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\\\"$(shell cat VERSION)\\\"\nifdef CONFIG_WIN32\nDEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior\nendif\nifndef CONFIG_WIN32\nifeq ($(shell $(CC) -o /dev/null compat/test-closefrom.c 2>/dev/null && echo 1),1)\nDEFINES+=-DHAVE_CLOSEFROM\nendif\nendif\n\nCFLAGS+=$(DEFINES)\nCFLAGS_DEBUG=$(CFLAGS) -O0\nCFLAGS_SMALL=$(CFLAGS) -Os\nCFLAGS_OPT=$(CFLAGS) -O2\nCFLAGS_NOLTO:=$(CFLAGS_OPT)\nifdef CONFIG_COSMO\nLDFLAGS+=-s # better to strip by default\nelse\nLDFLAGS+=-g\nendif\nifdef CONFIG_LTO\nCFLAGS_SMALL+=-flto\nCFLAGS_OPT+=-flto\nLDFLAGS+=-flto\nendif\nifdef CONFIG_PROFILE\nCFLAGS+=-p\nLDFLAGS+=-p\nendif\nifdef CONFIG_ASAN\nCFLAGS+=-fsanitize=address -fno-omit-frame-pointer\nLDFLAGS+=-fsanitize=address -fno-omit-frame-pointer\nendif\nifdef CONFIG_MSAN\nCFLAGS+=-fsanitize=memory -fno-omit-frame-pointer\nLDFLAGS+=-fsanitize=memory -fno-omit-frame-pointer\nendif\nifdef CONFIG_UBSAN\nCFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer\nLDFLAGS+=-fsanitize=undefined -fno-omit-frame-pointer\nendif\nifdef CONFIG_WIN32\nLDEXPORT=\nelse\nLDEXPORT=-rdynamic\nendif\n\nifndef CONFIG_COSMO\nifndef CONFIG_DARWIN\nifndef CONFIG_WIN32\nCONFIG_SHARED_LIBS=y # building shared libraries is supported\nendif\nendif\nendif\n\nPROGS=qjs$(EXE) qjsc$(EXE) run-test262$(EXE)\n\nifneq ($(CROSS_PREFIX),)\nQJSC_CC=gcc\nQJSC=./host-qjsc\nPROGS+=$(QJSC)\nelse\nQJSC_CC=$(CC)\nQJSC=./qjsc$(EXE)\nendif\nPROGS+=libquickjs.a\nifdef CONFIG_LTO\nPROGS+=libquickjs.lto.a\nendif\n\n# examples\nifeq ($(CROSS_PREFIX),)\nifndef CONFIG_ASAN\nifndef CONFIG_MSAN\nifndef CONFIG_UBSAN\nPROGS+=examples/hello examples/test_fib\n# no -m32 option in qjsc\nifndef CONFIG_M32\nifndef CONFIG_WIN32\nPROGS+=examples/hello_module\nendif\nendif\nifdef CONFIG_SHARED_LIBS\nPROGS+=examples/fib.so examples/point.so\nendif\nendif\nendif\nendif\nendif\n\nall: $(OBJDIR) $(OBJDIR)/quickjs.check.o $(OBJDIR)/qjs.check.o $(PROGS)\n\nQJS_LIB_OBJS=$(OBJDIR)/quickjs.o $(OBJDIR)/dtoa.o $(OBJDIR)/libregexp.o $(OBJDIR)/libunicode.o $(OBJDIR)/cutils.o $(OBJDIR)/quickjs-libc.o\n\nQJS_OBJS=$(OBJDIR)/qjs.o $(OBJDIR)/repl.o $(QJS_LIB_OBJS)\n\nHOST_LIBS=-lm -ldl -lpthread\nLIBS=-lm -lpthread\nifndef CONFIG_WIN32\nLIBS+=-ldl\nendif\nLIBS+=$(EXTRA_LIBS)\n\n$(OBJDIR):\n\tmkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests\n\nqjs$(EXE): $(QJS_OBJS)\n\t$(CC) $(LDFLAGS) $(LDEXPORT) -o $@ $^ $(LIBS)\n\nqjs-debug$(EXE): $(patsubst %.o, %.debug.o, $(QJS_OBJS))\n\t$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)\n\nqjsc$(EXE): $(OBJDIR)/qjsc.o $(QJS_LIB_OBJS)\n\t$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)\n\nfuzz_eval: $(OBJDIR)/fuzz_eval.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a\n\t$(CC) $(CFLAGS_OPT) $^ -o fuzz_eval $(LIB_FUZZING_ENGINE)\n\nfuzz_compile: $(OBJDIR)/fuzz_compile.o $(OBJDIR)/fuzz_common.o libquickjs.fuzz.a\n\t$(CC) $(CFLAGS_OPT) $^ -o fuzz_compile $(LIB_FUZZING_ENGINE)\n\nfuzz_regexp: $(OBJDIR)/fuzz_regexp.o $(OBJDIR)/libregexp.fuzz.o $(OBJDIR)/cutils.fuzz.o $(OBJDIR)/libunicode.fuzz.o\n\t$(CC) $(CFLAGS_OPT) $^ -o fuzz_regexp $(LIB_FUZZING_ENGINE)\n\nlibfuzzer: fuzz_eval fuzz_compile fuzz_regexp\n\nifneq ($(CROSS_PREFIX),)\n\n$(QJSC): $(OBJDIR)/qjsc.host.o \\\n    $(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))\n\t$(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)\n\nendif #CROSS_PREFIX\n\nQJSC_DEFINES:=-DCONFIG_CC=\\\"$(QJSC_CC)\\\" -DCONFIG_PREFIX=\\\"$(PREFIX)\\\"\nifdef CONFIG_LTO\nQJSC_DEFINES+=-DCONFIG_LTO\nendif\nQJSC_HOST_DEFINES:=-DCONFIG_CC=\\\"$(HOST_CC)\\\" -DCONFIG_PREFIX=\\\"$(PREFIX)\\\"\n\n$(OBJDIR)/qjsc.o: CFLAGS+=$(QJSC_DEFINES)\n$(OBJDIR)/qjsc.host.o: CFLAGS+=$(QJSC_HOST_DEFINES)\n\nifdef CONFIG_LTO\nLTOEXT=.lto\nelse\nLTOEXT=\nendif\n\nlibquickjs$(LTOEXT).a: $(QJS_LIB_OBJS)\n\t$(AR) rcs $@ $^\n\nifdef CONFIG_LTO\nlibquickjs.a: $(patsubst %.o, %.nolto.o, $(QJS_LIB_OBJS))\n\t$(AR) rcs $@ $^\nendif # CONFIG_LTO\n\nlibquickjs.fuzz.a: $(patsubst %.o, %.fuzz.o, $(QJS_LIB_OBJS))\n\t$(AR) rcs $@ $^\n\nrepl.c: $(QJSC) repl.js\n\t$(QJSC) -s -c -o $@ -m repl.js\n\nifneq ($(wildcard unicode/UnicodeData.txt),)\n$(OBJDIR)/libunicode.o $(OBJDIR)/libunicode.nolto.o: libunicode-table.h\n\nlibunicode-table.h: unicode_gen\n\t./unicode_gen unicode $@\nendif\n\nrun-test262$(EXE): $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)\n\t$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)\n\nrun-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))\n\t$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)\n\n# object suffix order: nolto\n\n$(OBJDIR)/%.o: %.c | $(OBJDIR)\n\t$(CC) $(CFLAGS_OPT) -c -o $@ $<\n\n$(OBJDIR)/fuzz_%.o: fuzz/fuzz_%.c | $(OBJDIR)\n\t$(CC) $(CFLAGS_OPT) -c -I. -o $@ $<\n\n$(OBJDIR)/%.host.o: %.c | $(OBJDIR)\n\t$(HOST_CC) $(CFLAGS_OPT) -c -o $@ $<\n\n$(OBJDIR)/%.pic.o: %.c | $(OBJDIR)\n\t$(CC) $(CFLAGS_OPT) -fPIC -DJS_SHARED_LIBRARY -c -o $@ $<\n\n$(OBJDIR)/%.nolto.o: %.c | $(OBJDIR)\n\t$(CC) $(CFLAGS_NOLTO) -c -o $@ $<\n\n$(OBJDIR)/%.debug.o: %.c | $(OBJDIR)\n\t$(CC) $(CFLAGS_DEBUG) -c -o $@ $<\n\n$(OBJDIR)/%.fuzz.o: %.c | $(OBJDIR)\n\t$(CC) $(CFLAGS_OPT) -fsanitize=fuzzer-no-link -c -o $@ $<\n\n$(OBJDIR)/%.check.o: %.c | $(OBJDIR)\n\t$(CC) $(CFLAGS) -DCONFIG_CHECK_JSVALUE -c -o $@ $<\n\nregexp_test: libregexp.c libunicode.c cutils.c\n\t$(CC) $(LDFLAGS) $(CFLAGS) -DTEST -o $@ libregexp.c libunicode.c cutils.c $(LIBS)\n\nunicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c unicode_gen_def.h\n\t$(HOST_CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o\n\nclean:\n\trm -f repl.c out.c\n\trm -f *.a *.o *.d *~ unicode_gen regexp_test fuzz_eval fuzz_compile fuzz_regexp $(PROGS)\n\trm -f hello.c test_fib.c\n\trm -f examples/*.so tests/*.so\n\trm -rf $(OBJDIR)/ *.dSYM/ qjs-debug$(EXE)\n\trm -rf run-test262-debug$(EXE)\n\trm -f run_octane run_sunspider_like\n\ninstall: all\n\tmkdir -p \"$(DESTDIR)$(PREFIX)/bin\"\n\t$(STRIP) qjs$(EXE) qjsc$(EXE)\n\tinstall -m755 qjs$(EXE) qjsc$(EXE) \"$(DESTDIR)$(PREFIX)/bin\"\n\tmkdir -p \"$(DESTDIR)$(PREFIX)/lib/quickjs\"\n\tinstall -m644 libquickjs.a \"$(DESTDIR)$(PREFIX)/lib/quickjs\"\nifdef CONFIG_LTO\n\tinstall -m644 libquickjs.lto.a \"$(DESTDIR)$(PREFIX)/lib/quickjs\"\nendif\n\tmkdir -p \"$(DESTDIR)$(PREFIX)/include/quickjs\"\n\tinstall -m644 quickjs.h quickjs-libc.h \"$(DESTDIR)$(PREFIX)/include/quickjs\"\n\n###############################################################################\n# examples\n\n# example of static JS compilation\nHELLO_SRCS=examples/hello.js\nHELLO_OPTS=-fno-string-normalize -fno-map -fno-promise -fno-typedarray \\\n           -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \\\n           -fno-date -fno-module-loader\n\nhello.c: $(QJSC) $(HELLO_SRCS)\n\t$(QJSC) -e $(HELLO_OPTS) -o $@ $(HELLO_SRCS)\n\nexamples/hello: $(OBJDIR)/hello.o $(QJS_LIB_OBJS)\n\t$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)\n\n# example of static JS compilation with modules\nHELLO_MODULE_SRCS=examples/hello_module.js\nHELLO_MODULE_OPTS=-fno-string-normalize -fno-map -fno-typedarray \\\n           -fno-typedarray -fno-regexp -fno-json -fno-eval -fno-proxy \\\n           -fno-date -m\nexamples/hello_module: $(QJSC) libquickjs$(LTOEXT).a $(HELLO_MODULE_SRCS)\n\t$(QJSC) $(HELLO_MODULE_OPTS) -o $@ $(HELLO_MODULE_SRCS)\n\n# use of an external C module (static compilation)\n\ntest_fib.c: $(QJSC) examples/test_fib.js\n\t$(QJSC) -e -M examples/fib.so,fib -m -o $@ examples/test_fib.js\n\nexamples/test_fib: $(OBJDIR)/test_fib.o $(OBJDIR)/examples/fib.o libquickjs$(LTOEXT).a\n\t$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)\n\nexamples/fib.so: $(OBJDIR)/examples/fib.pic.o\n\t$(CC) $(LDFLAGS) -shared -o $@ $^\n\nexamples/point.so: $(OBJDIR)/examples/point.pic.o\n\t$(CC) $(LDFLAGS) -shared -o $@ $^\n\n###############################################################################\n# documentation\n\nDOCS=doc/quickjs.pdf doc/quickjs.html\n\nbuild_doc: $(DOCS)\n\nclean_doc:\n\trm -f $(DOCS)\n\ndoc/version.texi: VERSION\n\t@echo \"@set VERSION `cat $<`\" > $@\n\ndoc/%.pdf: doc/%.texi doc/version.texi\n\ttexi2pdf --clean -o $@ -q $<\n\ndoc/%.html.pre: doc/%.texi doc/version.texi\n\tmakeinfo --html --no-headers --no-split --number-sections -o $@ $<\n\ndoc/%.html: doc/%.html.pre\n\tsed -e 's|</style>|</style>\\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">|' < $< > $@\n\n###############################################################################\n# tests\n\nifdef CONFIG_SHARED_LIBS\ntest: tests/bjson.so examples/point.so\nendif\n\ntest: qjs$(EXE)\n\t$(WINE) ./qjs$(EXE) tests/test_closure.js\n\t$(WINE) ./qjs$(EXE) tests/test_language.js\n\t$(WINE) ./qjs$(EXE) --std tests/test_builtin.js\n\t$(WINE) ./qjs$(EXE) tests/test_loop.js\n\t$(WINE) ./qjs$(EXE) tests/test_bigint.js\n\t$(WINE) ./qjs$(EXE) tests/test_cyclic_import.js\n\t$(WINE) ./qjs$(EXE) tests/test_worker.js\nifndef CONFIG_WIN32\n\t$(WINE) ./qjs$(EXE) tests/test_std.js\nendif\nifdef CONFIG_SHARED_LIBS\n\t$(WINE) ./qjs$(EXE) tests/test_bjson.js\n\t$(WINE) ./qjs$(EXE) examples/test_point.js\nendif\n\nstats: qjs$(EXE)\n\t$(WINE) ./qjs$(EXE) -qd\n\nmicrobench: qjs$(EXE)\n\t$(WINE) ./qjs$(EXE) --std tests/microbench.js\n\nifeq ($(wildcard test262/features.txt),)\ntest2-bootstrap:\n\tgit clone --single-branch --shallow-since=$(TEST262_SINCE) https://github.com/tc39/test262.git\n\t(cd test262 && git checkout -q $(TEST262_COMMIT) && patch -p1 < ../tests/test262.patch && cd ..)\nelse\ntest2-bootstrap:\n\t(cd test262 && git fetch && git reset --hard $(TEST262_COMMIT) && patch -p1 < ../tests/test262.patch && cd ..)\nendif\n\nifeq ($(wildcard test262o/tests.txt),)\ntest2o test2o-update:\n\t@echo test262o tests not installed\nelse\n# ES5 tests (obsolete)\ntest2o: run-test262\n\ttime ./run-test262 -t -m -c test262o.conf\n\ntest2o-update: run-test262\n\t./run-test262 -t -u -c test262o.conf\nendif\n\nifeq ($(wildcard test262/features.txt),)\ntest2 test2-update test2-default test2-check:\n\t@echo test262 tests not installed\nelse\n# Test262 tests\ntest2-default: run-test262\n\ttime ./run-test262 -t -m -c test262.conf\n\ntest2: run-test262\n\ttime ./run-test262 -t -m -c test262.conf -a\n\ntest2-update: run-test262\n\t./run-test262 -t -u -c test262.conf -a\n\ntest2-check: run-test262\n\ttime ./run-test262 -t -m -c test262.conf -E -a\nendif\n\ntestall: all test microbench test2o test2\n\ntestall-complete: testall\n\nnode-test:\n\tnode tests/test_closure.js\n\tnode tests/test_language.js\n\tnode tests/test_builtin.js\n\tnode tests/test_loop.js\n\tnode tests/test_bigint.js\n\nnode-microbench:\n\tnode tests/microbench.js -s microbench-node.txt\n\tnode --jitless tests/microbench.js -s microbench-node-jitless.txt\n\nbench-v8: qjs\n\tmake -C tests/bench-v8\n\t./qjs -d tests/bench-v8/combined.js\n\nnode-bench-v8:\n\tmake -C tests/bench-v8\n\tnode --jitless tests/bench-v8/combined.js\n\ntests/bjson.so: $(OBJDIR)/tests/bjson.pic.o\n\t$(CC) $(LDFLAGS) -shared -o $@ $^ $(LIBS)\n\nBENCHMARKDIR=../quickjs-benchmarks\n\nrun_sunspider_like: $(BENCHMARKDIR)/run_sunspider_like.c\n\t$(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS)\n\nrun_octane: $(BENCHMARKDIR)/run_octane.c\n\t$(CC) $(CFLAGS) $(LDFLAGS) -DNO_INCLUDE_DIR -I. -o $@ $< libquickjs$(LTOEXT).a $(LIBS)\n\nbenchmarks: run_sunspider_like run_octane\n\t./run_sunspider_like $(BENCHMARKDIR)/kraken-1.0/\n\t./run_sunspider_like $(BENCHMARKDIR)/kraken-1.1/\n\t./run_sunspider_like $(BENCHMARKDIR)/sunspider-1.0/\n\t./run_octane $(BENCHMARKDIR)/\n\n-include $(wildcard $(OBJDIR)/*.d)\n"
  },
  {
    "path": "TODO",
    "content": "Misc ideas:\n- use custom printf to avoid compatibility issues with floating point numbers\n- consistent naming for preprocessor defines\n- unify coding style and naming conventions\n- use names from the ECMA spec in library implementation\n- use byte code emitters with typed arguments (for clarity)\n- use 2 bytecode DynBufs in JSFunctionDef, one for reading, one for writing\n  and use the same wrappers in all phases\n- use more generic method for line numbers in resolve_variables and resolve_labels\n- use custom timezone support to avoid C library compatibility issues\n\nMemory:\n- use memory pools for objects, etc?\n- test border cases for max number of atoms, object properties, string length\n- add emergency malloc mode for out of memory exceptions.\n- test all DynBuf memory errors\n- test all js_realloc memory errors\n- improve JS_ComputeMemoryUsage() with more info\n\nBuilt-in standard library:\n- BSD sockets\n- modules: use realpath in module name normalizer and put it in quickjs-libc\n- modules: if no \".\", use a well known module loading path ?\n- get rid of __loadScript, use more common name\n\nREPL:\n- debugger\n- readline: support MS Windows terminal\n- readline: handle dynamic terminal resizing\n- readline: handle double width unicode characters\n- multiline editing\n- runtime object and function inspectors\n- interactive object browser\n- use more generic approach to display evaluation results\n- improve directive handling: dispatch, colorize, completion...\n- save history\n- close all predefined methods in repl.js and jscalc.js\n\nOptimization ideas:\n- use 64 bit JSValue in 64 bit mode\n- use JSValue as atoms and use a specific constant pool in functions to\n  reference atoms from the bytecode\n- reuse stack slots for disjoint scopes, if strip\n- add heuristic to avoid some cycles in closures\n- small String (1 codepoint) with immediate storage\n- perform static string concatenation at compile time\n- add implicit numeric strings for Uint32 numbers?\n- optimize `s += a + b`, `s += a.b` and similar simple expressions\n- ensure string canonical representation and optimise comparisons and hashes?\n- property access optimization on the global object, functions,\n  prototypes and special non extensible objects.\n- create object literals with the correct length by backpatching length argument\n- remove redundant set_loc_uninitialized/check_uninitialized opcodes\n- peephole optim: push_atom_value, to_propkey -> push_atom_value\n- peephole optim: put_loc x, get_loc_check x -> set_loc x\n- convert slow array to fast array when all properties != length are numeric\n- optimize destructuring assignments for global and local variables\n- implement some form of tail-call-optimization\n- optimize OP_apply\n- optimize f(...b)\n\nTest262o:   0/11262 errors, 463 excluded\nTest262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)\n\nTest262:\nResult: 66/83341 errors, 2567 excluded, 5767 skipped\n"
  },
  {
    "path": "VERSION",
    "content": "2025-09-13\n"
  },
  {
    "path": "compat/test-closefrom.c",
    "content": "#include <unistd.h>\n\nint main(void) {\n    closefrom(3);\n    return 0;\n}\n"
  },
  {
    "path": "cutils.c",
    "content": "/*\n * C utilities\n *\n * Copyright (c) 2017 Fabrice Bellard\n * Copyright (c) 2018 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <string.h>\n\n#include \"cutils.h\"\n\nvoid pstrcpy(char *buf, int buf_size, const char *str)\n{\n    int c;\n    char *q = buf;\n\n    if (buf_size <= 0)\n        return;\n\n    for(;;) {\n        c = *str++;\n        if (c == 0 || q >= buf + buf_size - 1)\n            break;\n        *q++ = c;\n    }\n    *q = '\\0';\n}\n\n/* strcat and truncate. */\nchar *pstrcat(char *buf, int buf_size, const char *s)\n{\n    int len;\n    len = strlen(buf);\n    if (len < buf_size)\n        pstrcpy(buf + len, buf_size - len, s);\n    return buf;\n}\n\nint strstart(const char *str, const char *val, const char **ptr)\n{\n    const char *p, *q;\n    p = str;\n    q = val;\n    while (*q != '\\0') {\n        if (*p != *q)\n            return 0;\n        p++;\n        q++;\n    }\n    if (ptr)\n        *ptr = p;\n    return 1;\n}\n\nint has_suffix(const char *str, const char *suffix)\n{\n    size_t len = strlen(str);\n    size_t slen = strlen(suffix);\n    return (len >= slen && !memcmp(str + len - slen, suffix, slen));\n}\n\n/* Dynamic buffer package */\n\nstatic void *dbuf_default_realloc(void *opaque, void *ptr, size_t size)\n{\n    return realloc(ptr, size);\n}\n\nvoid dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func)\n{\n    memset(s, 0, sizeof(*s));\n    if (!realloc_func)\n        realloc_func = dbuf_default_realloc;\n    s->opaque = opaque;\n    s->realloc_func = realloc_func;\n}\n\nvoid dbuf_init(DynBuf *s)\n{\n    dbuf_init2(s, NULL, NULL);\n}\n\n/* Try to allocate 'len' more bytes. return < 0 if error */\nint dbuf_claim(DynBuf *s, size_t len)\n{\n    size_t new_size, size;\n    uint8_t *new_buf;\n    new_size = s->size + len;\n    if (new_size < len)\n        return -1; /* overflow case */\n    if (new_size > s->allocated_size) {\n        if (s->error)\n            return -1;\n        size = s->allocated_size + (s->allocated_size / 2);\n        if (size < s->allocated_size)\n            return -1; /* overflow case */\n        if (size > new_size)\n            new_size = size;\n        new_buf = s->realloc_func(s->opaque, s->buf, new_size);\n        if (!new_buf) {\n            s->error = TRUE;\n            return -1;\n        }\n        s->buf = new_buf;\n        s->allocated_size = new_size;\n    }\n    return 0;\n}\n\nint dbuf_put(DynBuf *s, const uint8_t *data, size_t len)\n{\n    if (unlikely((s->allocated_size - s->size) < len)) {\n        if (dbuf_claim(s, len))\n            return -1;\n    }\n    memcpy_no_ub(s->buf + s->size, data, len);\n    s->size += len;\n    return 0;\n}\n\nint dbuf_put_self(DynBuf *s, size_t offset, size_t len)\n{\n    if (unlikely((s->allocated_size - s->size) < len)) {\n        if (dbuf_claim(s, len))\n            return -1;\n    }\n    memcpy(s->buf + s->size, s->buf + offset, len);\n    s->size += len;\n    return 0;\n}\n\nint __dbuf_putc(DynBuf *s, uint8_t c)\n{\n    return dbuf_put(s, &c, 1);\n}\n\nint __dbuf_put_u16(DynBuf *s, uint16_t val)\n{\n    return dbuf_put(s, (uint8_t *)&val, 2);\n}\n\nint __dbuf_put_u32(DynBuf *s, uint32_t val)\n{\n    return dbuf_put(s, (uint8_t *)&val, 4);\n}\n\nint __dbuf_put_u64(DynBuf *s, uint64_t val)\n{\n    return dbuf_put(s, (uint8_t *)&val, 8);\n}\n\nint dbuf_putstr(DynBuf *s, const char *str)\n{\n    return dbuf_put(s, (const uint8_t *)str, strlen(str));\n}\n\nint __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,\n                                                      const char *fmt, ...)\n{\n    va_list ap;\n    char buf[128];\n    int len;\n\n    va_start(ap, fmt);\n    len = vsnprintf(buf, sizeof(buf), fmt, ap);\n    va_end(ap);\n    if (len < 0)\n        return -1;\n    if (len < sizeof(buf)) {\n        /* fast case */\n        return dbuf_put(s, (uint8_t *)buf, len);\n    } else {\n        if (dbuf_claim(s, len + 1))\n            return -1;\n        va_start(ap, fmt);\n        vsnprintf((char *)(s->buf + s->size), s->allocated_size - s->size,\n                  fmt, ap);\n        va_end(ap);\n        s->size += len;\n    }\n    return 0;\n}\n\nvoid dbuf_free(DynBuf *s)\n{\n    /* we test s->buf as a fail safe to avoid crashing if dbuf_free()\n       is called twice */\n    if (s->buf) {\n        s->realloc_func(s->opaque, s->buf, 0);\n    }\n    memset(s, 0, sizeof(*s));\n}\n\n/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes\n   are output. */\nint unicode_to_utf8(uint8_t *buf, unsigned int c)\n{\n    uint8_t *q = buf;\n\n    if (c < 0x80) {\n        *q++ = c;\n    } else {\n        if (c < 0x800) {\n            *q++ = (c >> 6) | 0xc0;\n        } else {\n            if (c < 0x10000) {\n                *q++ = (c >> 12) | 0xe0;\n            } else {\n                if (c < 0x00200000) {\n                    *q++ = (c >> 18) | 0xf0;\n                } else {\n                    if (c < 0x04000000) {\n                        *q++ = (c >> 24) | 0xf8;\n                    } else if (c < 0x80000000) {\n                        *q++ = (c >> 30) | 0xfc;\n                        *q++ = ((c >> 24) & 0x3f) | 0x80;\n                    } else {\n                        return 0;\n                    }\n                    *q++ = ((c >> 18) & 0x3f) | 0x80;\n                }\n                *q++ = ((c >> 12) & 0x3f) | 0x80;\n            }\n            *q++ = ((c >> 6) & 0x3f) | 0x80;\n        }\n        *q++ = (c & 0x3f) | 0x80;\n    }\n    return q - buf;\n}\n\nstatic const unsigned int utf8_min_code[5] = {\n    0x80, 0x800, 0x10000, 0x00200000, 0x04000000,\n};\n\nstatic const unsigned char utf8_first_code_mask[5] = {\n    0x1f, 0xf, 0x7, 0x3, 0x1,\n};\n\n/* return -1 if error. *pp is not updated in this case. max_len must\n   be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */\nint unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)\n{\n    int l, c, b, i;\n\n    c = *p++;\n    if (c < 0x80) {\n        *pp = p;\n        return c;\n    }\n    switch(c) {\n    case 0xc0: case 0xc1: case 0xc2: case 0xc3:\n    case 0xc4: case 0xc5: case 0xc6: case 0xc7:\n    case 0xc8: case 0xc9: case 0xca: case 0xcb:\n    case 0xcc: case 0xcd: case 0xce: case 0xcf:\n    case 0xd0: case 0xd1: case 0xd2: case 0xd3:\n    case 0xd4: case 0xd5: case 0xd6: case 0xd7:\n    case 0xd8: case 0xd9: case 0xda: case 0xdb:\n    case 0xdc: case 0xdd: case 0xde: case 0xdf:\n        l = 1;\n        break;\n    case 0xe0: case 0xe1: case 0xe2: case 0xe3:\n    case 0xe4: case 0xe5: case 0xe6: case 0xe7:\n    case 0xe8: case 0xe9: case 0xea: case 0xeb:\n    case 0xec: case 0xed: case 0xee: case 0xef:\n        l = 2;\n        break;\n    case 0xf0: case 0xf1: case 0xf2: case 0xf3:\n    case 0xf4: case 0xf5: case 0xf6: case 0xf7:\n        l = 3;\n        break;\n    case 0xf8: case 0xf9: case 0xfa: case 0xfb:\n        l = 4;\n        break;\n    case 0xfc: case 0xfd:\n        l = 5;\n        break;\n    default:\n        return -1;\n    }\n    /* check that we have enough characters */\n    if (l > (max_len - 1))\n        return -1;\n    c &= utf8_first_code_mask[l - 1];\n    for(i = 0; i < l; i++) {\n        b = *p++;\n        if (b < 0x80 || b >= 0xc0)\n            return -1;\n        c = (c << 6) | (b & 0x3f);\n    }\n    if (c < utf8_min_code[l - 1])\n        return -1;\n    *pp = p;\n    return c;\n}\n\n#if 0\n\n#if defined(EMSCRIPTEN) || defined(__ANDROID__)\n\nstatic void *rqsort_arg;\nstatic int (*rqsort_cmp)(const void *, const void *, void *);\n\nstatic int rqsort_cmp2(const void *p1, const void *p2)\n{\n    return rqsort_cmp(p1, p2, rqsort_arg);\n}\n\n/* not reentrant, but not needed with emscripten */\nvoid rqsort(void *base, size_t nmemb, size_t size,\n            int (*cmp)(const void *, const void *, void *),\n            void *arg)\n{\n    rqsort_arg = arg;\n    rqsort_cmp = cmp;\n    qsort(base, nmemb, size, rqsort_cmp2);\n}\n\n#endif\n\n#else\n\ntypedef void (*exchange_f)(void *a, void *b, size_t size);\ntypedef int (*cmp_f)(const void *, const void *, void *opaque);\n\nstatic void exchange_bytes(void *a, void *b, size_t size) {\n    uint8_t *ap = (uint8_t *)a;\n    uint8_t *bp = (uint8_t *)b;\n\n    while (size-- != 0) {\n        uint8_t t = *ap;\n        *ap++ = *bp;\n        *bp++ = t;\n    }\n}\n\nstatic void exchange_one_byte(void *a, void *b, size_t size) {\n    uint8_t *ap = (uint8_t *)a;\n    uint8_t *bp = (uint8_t *)b;\n    uint8_t t = *ap;\n    *ap = *bp;\n    *bp = t;\n}\n\nstatic void exchange_int16s(void *a, void *b, size_t size) {\n    uint16_t *ap = (uint16_t *)a;\n    uint16_t *bp = (uint16_t *)b;\n\n    for (size /= sizeof(uint16_t); size-- != 0;) {\n        uint16_t t = *ap;\n        *ap++ = *bp;\n        *bp++ = t;\n    }\n}\n\nstatic void exchange_one_int16(void *a, void *b, size_t size) {\n    uint16_t *ap = (uint16_t *)a;\n    uint16_t *bp = (uint16_t *)b;\n    uint16_t t = *ap;\n    *ap = *bp;\n    *bp = t;\n}\n\nstatic void exchange_int32s(void *a, void *b, size_t size) {\n    uint32_t *ap = (uint32_t *)a;\n    uint32_t *bp = (uint32_t *)b;\n\n    for (size /= sizeof(uint32_t); size-- != 0;) {\n        uint32_t t = *ap;\n        *ap++ = *bp;\n        *bp++ = t;\n    }\n}\n\nstatic void exchange_one_int32(void *a, void *b, size_t size) {\n    uint32_t *ap = (uint32_t *)a;\n    uint32_t *bp = (uint32_t *)b;\n    uint32_t t = *ap;\n    *ap = *bp;\n    *bp = t;\n}\n\nstatic void exchange_int64s(void *a, void *b, size_t size) {\n    uint64_t *ap = (uint64_t *)a;\n    uint64_t *bp = (uint64_t *)b;\n\n    for (size /= sizeof(uint64_t); size-- != 0;) {\n        uint64_t t = *ap;\n        *ap++ = *bp;\n        *bp++ = t;\n    }\n}\n\nstatic void exchange_one_int64(void *a, void *b, size_t size) {\n    uint64_t *ap = (uint64_t *)a;\n    uint64_t *bp = (uint64_t *)b;\n    uint64_t t = *ap;\n    *ap = *bp;\n    *bp = t;\n}\n\nstatic void exchange_int128s(void *a, void *b, size_t size) {\n    uint64_t *ap = (uint64_t *)a;\n    uint64_t *bp = (uint64_t *)b;\n\n    for (size /= sizeof(uint64_t) * 2; size-- != 0; ap += 2, bp += 2) {\n        uint64_t t = ap[0];\n        uint64_t u = ap[1];\n        ap[0] = bp[0];\n        ap[1] = bp[1];\n        bp[0] = t;\n        bp[1] = u;\n    }\n}\n\nstatic void exchange_one_int128(void *a, void *b, size_t size) {\n    uint64_t *ap = (uint64_t *)a;\n    uint64_t *bp = (uint64_t *)b;\n    uint64_t t = ap[0];\n    uint64_t u = ap[1];\n    ap[0] = bp[0];\n    ap[1] = bp[1];\n    bp[0] = t;\n    bp[1] = u;\n}\n\nstatic inline exchange_f exchange_func(const void *base, size_t size) {\n    switch (((uintptr_t)base | (uintptr_t)size) & 15) {\n    case 0:\n        if (size == sizeof(uint64_t) * 2)\n            return exchange_one_int128;\n        else\n            return exchange_int128s;\n    case 8:\n        if (size == sizeof(uint64_t))\n            return exchange_one_int64;\n        else\n            return exchange_int64s;\n    case 4:\n    case 12:\n        if (size == sizeof(uint32_t))\n            return exchange_one_int32;\n        else\n            return exchange_int32s;\n    case 2:\n    case 6:\n    case 10:\n    case 14:\n        if (size == sizeof(uint16_t))\n            return exchange_one_int16;\n        else\n            return exchange_int16s;\n    default:\n        if (size == 1)\n            return exchange_one_byte;\n        else\n            return exchange_bytes;\n    }\n}\n\nstatic void heapsortx(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)\n{\n    uint8_t *basep = (uint8_t *)base;\n    size_t i, n, c, r;\n    exchange_f swap = exchange_func(base, size);\n\n    if (nmemb > 1) {\n        i = (nmemb / 2) * size;\n        n = nmemb * size;\n\n        while (i > 0) {\n            i -= size;\n            for (r = i; (c = r * 2 + size) < n; r = c) {\n                if (c < n - size && cmp(basep + c, basep + c + size, opaque) <= 0)\n                    c += size;\n                if (cmp(basep + r, basep + c, opaque) > 0)\n                    break;\n                swap(basep + r, basep + c, size);\n            }\n        }\n        for (i = n - size; i > 0; i -= size) {\n            swap(basep, basep + i, size);\n\n            for (r = 0; (c = r * 2 + size) < i; r = c) {\n                if (c < i - size && cmp(basep + c, basep + c + size, opaque) <= 0)\n                    c += size;\n                if (cmp(basep + r, basep + c, opaque) > 0)\n                    break;\n                swap(basep + r, basep + c, size);\n            }\n        }\n    }\n}\n\nstatic inline void *med3(void *a, void *b, void *c, cmp_f cmp, void *opaque)\n{\n    return cmp(a, b, opaque) < 0 ?\n        (cmp(b, c, opaque) < 0 ? b : (cmp(a, c, opaque) < 0 ? c : a )) :\n        (cmp(b, c, opaque) > 0 ? b : (cmp(a, c, opaque) < 0 ? a : c ));\n}\n\n/* pointer based version with local stack and insertion sort threshhold */\nvoid rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)\n{\n    struct { uint8_t *base; size_t count; int depth; } stack[50], *sp = stack;\n    uint8_t *ptr, *pi, *pj, *plt, *pgt, *top, *m;\n    size_t m4, i, lt, gt, span, span2;\n    int c, depth;\n    exchange_f swap = exchange_func(base, size);\n    exchange_f swap_block = exchange_func(base, size | 128);\n\n    if (nmemb < 2 || size <= 0)\n        return;\n\n    sp->base = (uint8_t *)base;\n    sp->count = nmemb;\n    sp->depth = 0;\n    sp++;\n\n    while (sp > stack) {\n        sp--;\n        ptr = sp->base;\n        nmemb = sp->count;\n        depth = sp->depth;\n\n        while (nmemb > 6) {\n            if (++depth > 50) {\n                /* depth check to ensure worst case logarithmic time */\n                heapsortx(ptr, nmemb, size, cmp, opaque);\n                nmemb = 0;\n                break;\n            }\n            /* select median of 3 from 1/4, 1/2, 3/4 positions */\n            /* should use median of 5 or 9? */\n            m4 = (nmemb >> 2) * size;\n            m = med3(ptr + m4, ptr + 2 * m4, ptr + 3 * m4, cmp, opaque);\n            swap(ptr, m, size);  /* move the pivot to the start or the array */\n            i = lt = 1;\n            pi = plt = ptr + size;\n            gt = nmemb;\n            pj = pgt = top = ptr + nmemb * size;\n            for (;;) {\n                while (pi < pj && (c = cmp(ptr, pi, opaque)) >= 0) {\n                    if (c == 0) {\n                        swap(plt, pi, size);\n                        lt++;\n                        plt += size;\n                    }\n                    i++;\n                    pi += size;\n                }\n                while (pi < (pj -= size) && (c = cmp(ptr, pj, opaque)) <= 0) {\n                    if (c == 0) {\n                        gt--;\n                        pgt -= size;\n                        swap(pgt, pj, size);\n                    }\n                }\n                if (pi >= pj)\n                    break;\n                swap(pi, pj, size);\n                i++;\n                pi += size;\n            }\n            /* array has 4 parts:\n             * from 0 to lt excluded: elements identical to pivot\n             * from lt to pi excluded: elements smaller than pivot\n             * from pi to gt excluded: elements greater than pivot\n             * from gt to n excluded: elements identical to pivot\n             */\n            /* move elements identical to pivot in the middle of the array: */\n            /* swap values in ranges [0..lt[ and [i-lt..i[\n               swapping the smallest span between lt and i-lt is sufficient\n             */\n            span = plt - ptr;\n            span2 = pi - plt;\n            lt = i - lt;\n            if (span > span2)\n                span = span2;\n            swap_block(ptr, pi - span, span);\n            /* swap values in ranges [gt..top[ and [i..top-(top-gt)[\n               swapping the smallest span between top-gt and gt-i is sufficient\n             */\n            span = top - pgt;\n            span2 = pgt - pi;\n            pgt = top - span2;\n            gt = nmemb - (gt - i);\n            if (span > span2)\n                span = span2;\n            swap_block(pi, top - span, span);\n\n            /* now array has 3 parts:\n             * from 0 to lt excluded: elements smaller than pivot\n             * from lt to gt excluded: elements identical to pivot\n             * from gt to n excluded: elements greater than pivot\n             */\n            /* stack the larger segment and keep processing the smaller one\n               to minimize stack use for pathological distributions */\n            if (lt > nmemb - gt) {\n                sp->base = ptr;\n                sp->count = lt;\n                sp->depth = depth;\n                sp++;\n                ptr = pgt;\n                nmemb -= gt;\n            } else {\n                sp->base = pgt;\n                sp->count = nmemb - gt;\n                sp->depth = depth;\n                sp++;\n                nmemb = lt;\n            }\n        }\n        /* Use insertion sort for small fragments */\n        for (pi = ptr + size, top = ptr + nmemb * size; pi < top; pi += size) {\n            for (pj = pi; pj > ptr && cmp(pj - size, pj, opaque) > 0; pj -= size)\n                swap(pj, pj - size, size);\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "cutils.h",
    "content": "/*\n * C utilities\n *\n * Copyright (c) 2017 Fabrice Bellard\n * Copyright (c) 2018 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef CUTILS_H\n#define CUTILS_H\n\n#include <stdlib.h>\n#include <string.h>\n#include <inttypes.h>\n\n#define likely(x)       __builtin_expect(!!(x), 1)\n#define unlikely(x)     __builtin_expect(!!(x), 0)\n#define force_inline inline __attribute__((always_inline))\n#define no_inline __attribute__((noinline))\n#define __maybe_unused __attribute__((unused))\n\n#define xglue(x, y) x ## y\n#define glue(x, y) xglue(x, y)\n#define stringify(s)    tostring(s)\n#define tostring(s)     #s\n\n#ifndef offsetof\n#define offsetof(type, field) ((size_t) &((type *)0)->field)\n#endif\n#ifndef countof\n#define countof(x) (sizeof(x) / sizeof((x)[0]))\n#endif\n#ifndef container_of\n/* return the pointer of type 'type *' containing 'ptr' as field 'member' */\n#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))\n#endif\n\n#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L\n#define minimum_length(n)  static n\n#else\n#define minimum_length(n)  n\n#endif\n\ntypedef int BOOL;\n\n#ifndef FALSE\nenum {\n    FALSE = 0,\n    TRUE = 1,\n};\n#endif\n\nvoid pstrcpy(char *buf, int buf_size, const char *str);\nchar *pstrcat(char *buf, int buf_size, const char *s);\nint strstart(const char *str, const char *val, const char **ptr);\nint has_suffix(const char *str, const char *suffix);\n\n/* Prevent UB when n == 0 and (src == NULL or dest == NULL) */\nstatic inline void memcpy_no_ub(void *dest, const void *src, size_t n) {\n    if (n)\n        memcpy(dest, src, n);\n}\n\nstatic inline int max_int(int a, int b)\n{\n    if (a > b)\n        return a;\n    else\n        return b;\n}\n\nstatic inline int min_int(int a, int b)\n{\n    if (a < b)\n        return a;\n    else\n        return b;\n}\n\nstatic inline uint32_t max_uint32(uint32_t a, uint32_t b)\n{\n    if (a > b)\n        return a;\n    else\n        return b;\n}\n\nstatic inline uint32_t min_uint32(uint32_t a, uint32_t b)\n{\n    if (a < b)\n        return a;\n    else\n        return b;\n}\n\nstatic inline int64_t max_int64(int64_t a, int64_t b)\n{\n    if (a > b)\n        return a;\n    else\n        return b;\n}\n\nstatic inline int64_t min_int64(int64_t a, int64_t b)\n{\n    if (a < b)\n        return a;\n    else\n        return b;\n}\n\n/* WARNING: undefined if a = 0 */\nstatic inline int clz32(unsigned int a)\n{\n    return __builtin_clz(a);\n}\n\n/* WARNING: undefined if a = 0 */\nstatic inline int clz64(uint64_t a)\n{\n    return __builtin_clzll(a);\n}\n\n/* WARNING: undefined if a = 0 */\nstatic inline int ctz32(unsigned int a)\n{\n    return __builtin_ctz(a);\n}\n\n/* WARNING: undefined if a = 0 */\nstatic inline int ctz64(uint64_t a)\n{\n    return __builtin_ctzll(a);\n}\n\nstruct __attribute__((packed)) packed_u64 {\n    uint64_t v;\n};\n\nstruct __attribute__((packed)) packed_u32 {\n    uint32_t v;\n};\n\nstruct __attribute__((packed)) packed_u16 {\n    uint16_t v;\n};\n\nstatic inline uint64_t get_u64(const uint8_t *tab)\n{\n    return ((const struct packed_u64 *)tab)->v;\n}\n\nstatic inline int64_t get_i64(const uint8_t *tab)\n{\n    return (int64_t)((const struct packed_u64 *)tab)->v;\n}\n\nstatic inline void put_u64(uint8_t *tab, uint64_t val)\n{\n    ((struct packed_u64 *)tab)->v = val;\n}\n\nstatic inline uint32_t get_u32(const uint8_t *tab)\n{\n    return ((const struct packed_u32 *)tab)->v;\n}\n\nstatic inline int32_t get_i32(const uint8_t *tab)\n{\n    return (int32_t)((const struct packed_u32 *)tab)->v;\n}\n\nstatic inline void put_u32(uint8_t *tab, uint32_t val)\n{\n    ((struct packed_u32 *)tab)->v = val;\n}\n\nstatic inline uint32_t get_u16(const uint8_t *tab)\n{\n    return ((const struct packed_u16 *)tab)->v;\n}\n\nstatic inline int32_t get_i16(const uint8_t *tab)\n{\n    return (int16_t)((const struct packed_u16 *)tab)->v;\n}\n\nstatic inline void put_u16(uint8_t *tab, uint16_t val)\n{\n    ((struct packed_u16 *)tab)->v = val;\n}\n\nstatic inline uint32_t get_u8(const uint8_t *tab)\n{\n    return *tab;\n}\n\nstatic inline int32_t get_i8(const uint8_t *tab)\n{\n    return (int8_t)*tab;\n}\n\nstatic inline void put_u8(uint8_t *tab, uint8_t val)\n{\n    *tab = val;\n}\n\n#ifndef bswap16\nstatic inline uint16_t bswap16(uint16_t x)\n{\n    return (x >> 8) | (x << 8);\n}\n#endif\n\n#ifndef bswap32\nstatic inline uint32_t bswap32(uint32_t v)\n{\n    return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >>  8) |\n        ((v & 0x0000ff00) <<  8) | ((v & 0x000000ff) << 24);\n}\n#endif\n\n#ifndef bswap64\nstatic inline uint64_t bswap64(uint64_t v)\n{\n    return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |\n        ((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |\n        ((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |\n        ((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |\n        ((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |\n        ((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |\n        ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |\n        ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));\n}\n#endif\n\n/* XXX: should take an extra argument to pass slack information to the caller */\ntypedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);\n\ntypedef struct DynBuf {\n    uint8_t *buf;\n    size_t size;\n    size_t allocated_size;\n    BOOL error; /* true if a memory allocation error occurred */\n    DynBufReallocFunc *realloc_func;\n    void *opaque; /* for realloc_func */\n} DynBuf;\n\nvoid dbuf_init(DynBuf *s);\nvoid dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);\nint dbuf_claim(DynBuf *s, size_t len);\nint dbuf_put(DynBuf *s, const uint8_t *data, size_t len);\nint dbuf_put_self(DynBuf *s, size_t offset, size_t len);\nint dbuf_putstr(DynBuf *s, const char *str);\nint __dbuf_putc(DynBuf *s, uint8_t c);\nint __dbuf_put_u16(DynBuf *s, uint16_t val);\nint __dbuf_put_u32(DynBuf *s, uint32_t val);\nint __dbuf_put_u64(DynBuf *s, uint64_t val);\n\nstatic inline int dbuf_putc(DynBuf *s, uint8_t val)\n{\n    if (unlikely((s->allocated_size - s->size) < 1)) {\n        return __dbuf_putc(s, val);\n    } else {\n        s->buf[s->size++] = val;\n        return 0;\n    }\n}\n\nstatic inline int dbuf_put_u16(DynBuf *s, uint16_t val)\n{\n    if (unlikely((s->allocated_size - s->size) < 2)) {\n        return __dbuf_put_u16(s, val);\n    } else {\n        put_u16(s->buf + s->size, val);\n        s->size += 2;\n        return 0;\n    }\n}\n\nstatic inline int dbuf_put_u32(DynBuf *s, uint32_t val)\n{\n    if (unlikely((s->allocated_size - s->size) < 4)) {\n        return __dbuf_put_u32(s, val);\n    } else {\n        put_u32(s->buf + s->size, val);\n        s->size += 4;\n        return 0;\n    }\n}\n\nstatic inline int dbuf_put_u64(DynBuf *s, uint64_t val)\n{\n    if (unlikely((s->allocated_size - s->size) < 8)) {\n        return __dbuf_put_u64(s, val);\n    } else {\n        put_u64(s->buf + s->size, val);\n        s->size += 8;\n        return 0;\n    }\n}\n\nint __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,\n                                                      const char *fmt, ...);\nvoid dbuf_free(DynBuf *s);\nstatic inline BOOL dbuf_error(DynBuf *s) {\n    return s->error;\n}\nstatic inline void dbuf_set_error(DynBuf *s)\n{\n    s->error = TRUE;\n}\n\n#define UTF8_CHAR_LEN_MAX 6\n\nint unicode_to_utf8(uint8_t *buf, unsigned int c);\nint unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);\n\nstatic inline BOOL is_surrogate(uint32_t c)\n{\n    return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF\n}\n\nstatic inline BOOL is_hi_surrogate(uint32_t c)\n{\n    return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF\n}\n\nstatic inline BOOL is_lo_surrogate(uint32_t c)\n{\n    return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF\n}\n\nstatic inline uint32_t get_hi_surrogate(uint32_t c)\n{\n    return (c >> 10) - (0x10000 >> 10) + 0xD800;\n}\n\nstatic inline uint32_t get_lo_surrogate(uint32_t c)\n{\n    return (c & 0x3FF) | 0xDC00;\n}\n\nstatic inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)\n{\n    return 0x10000 + 0x400 * (hi - 0xD800) + (lo - 0xDC00);\n}\n\nstatic inline int from_hex(int c)\n{\n    if (c >= '0' && c <= '9')\n        return c - '0';\n    else if (c >= 'A' && c <= 'F')\n        return c - 'A' + 10;\n    else if (c >= 'a' && c <= 'f')\n        return c - 'a' + 10;\n    else\n        return -1;\n}\n\nvoid rqsort(void *base, size_t nmemb, size_t size,\n            int (*cmp)(const void *, const void *, void *),\n            void *arg);\n\nstatic inline uint64_t float64_as_uint64(double d)\n{\n    union {\n        double d;\n        uint64_t u64;\n    } u;\n    u.d = d;\n    return u.u64;\n}\n\nstatic inline double uint64_as_float64(uint64_t u64)\n{\n    union {\n        double d;\n        uint64_t u64;\n    } u;\n    u.u64 = u64;\n    return u.d;\n}\n\nstatic inline double fromfp16(uint16_t v)\n{\n    double d;\n    uint32_t v1;\n    v1 = v & 0x7fff;\n    if (unlikely(v1 >= 0x7c00))\n        v1 += 0x1f8000; /* NaN or infinity */\n    d = uint64_as_float64(((uint64_t)(v >> 15) << 63) | ((uint64_t)v1 << (52 - 10)));\n    return d * 0x1p1008;\n}\n\nstatic inline uint16_t tofp16(double d)\n{\n    uint64_t a, addend;\n    uint32_t v, sgn;\n    int shift;\n    \n    a = float64_as_uint64(d);\n    sgn = a >> 63;\n    a = a & 0x7fffffffffffffff;\n    if (unlikely(a > 0x7ff0000000000000)) {\n        /* nan */\n        v = 0x7c01;\n    } else if (a < 0x3f10000000000000) { /* 0x1p-14 */\n        /* subnormal f16 number or zero */\n        if (a <= 0x3e60000000000000) { /* 0x1p-25 */\n            v = 0x0000; /* zero */\n        } else {\n            shift = 1051 - (a >> 52);\n            a = ((uint64_t)1 << 52) | (a & (((uint64_t)1 << 52) - 1));\n            addend = ((a >> shift) & 1) + (((uint64_t)1 << (shift - 1)) - 1);\n            v = (a + addend) >> shift;\n        }\n    } else {\n        /* normal number or infinity */\n        a -= 0x3f00000000000000; /* adjust the exponent */\n        /* round */\n        addend = ((a >> (52 - 10)) & 1) + (((uint64_t)1 << (52 - 11)) - 1);\n        v = (a + addend) >> (52 - 10);\n        /* overflow ? */\n        if (unlikely(v > 0x7c00))\n            v = 0x7c00;\n    }\n    return v | (sgn << 15);\n}\n\nstatic inline int isfp16nan(uint16_t v)\n{\n    return (v & 0x7FFF) > 0x7C00;\n}\n\nstatic inline int isfp16zero(uint16_t v)\n{\n    return (v & 0x7FFF) == 0;\n}\n\n#endif  /* CUTILS_H */\n"
  },
  {
    "path": "doc/quickjs.texi",
    "content": "\\input texinfo\n\n@iftex\n@afourpaper\n@headings double\n@end iftex\n\n@include version.texi\n\n@titlepage\n@afourpaper\n@sp 7\n@center @titlefont{QuickJS Javascript Engine}\n@sp 3\n@center Version: @value{VERSION}\n@end titlepage\n\n@setfilename spec.info\n@settitle QuickJS Javascript Engine\n\n@contents\n\n@chapter Introduction\n\nQuickJS (version @value{VERSION}) is a small and embeddable Javascript\nengine. It supports most of the ES2024 specification\n@footnote{@url{https://tc39.es/ecma262/2024 }} including modules,\nasynchronous generators, proxies and BigInt.\n\n@section Main Features\n\n@itemize\n\n@item Small and easily embeddable: just a few C files, no external dependency, 210 KiB of x86 code for a simple ``hello world'' program.\n\n@item Fast interpreter with very low startup time: runs the 77000 tests of the ECMAScript Test Suite@footnote{@url{https://github.com/tc39/test262}} in less than 2 minutes on a single core of a desktop PC. The complete life cycle of a runtime instance completes in less than 300 microseconds.\n\n@item Almost complete ES2024 support including modules, asynchronous\ngenerators and full Annex B support (legacy web compatibility). Some\nfeatures from the upcoming ES2024 specification\n@footnote{@url{https://tc39.es/ecma262/}} are also supported.\n\n@item Passes nearly 100% of the ECMAScript Test Suite tests when selecting the ES2024 features.\n\n@item Compile Javascript sources to executables with no external dependency.\n\n@item Garbage collection using reference counting (to reduce memory usage and have deterministic behavior) with cycle removal.\n\n@item Command line interpreter with contextual colorization and completion implemented in Javascript.\n\n@item Small built-in standard library with C library wrappers.\n\n@end itemize\n\n@chapter Usage\n\n@section Installation\n\nA Makefile is provided to compile the engine on Linux or MacOS/X.  A\npreliminary Windows support is available thru cross compilation on a\nLinux host with the MingGW tools.\n\nEdit the top of the @code{Makefile} if you wish to select specific\noptions then run @code{make}.\n\nYou can type @code{make install} as root if you wish to install the binaries and support files to\n@code{/usr/local} (this is not necessary to use QuickJS).\n\nNote: On some OSes atomic operations are not available or need a\nspecific library. If you get related errors, you should either add\n@code{-latomics} in the Makefile @code{LIBS} variable or disable\n@code{CONFIG_ATOMICS} in @file{quickjs.c}.\n\n@section Quick start\n\n@code{qjs} is the command line interpreter (Read-Eval-Print Loop). You can pass\nJavascript files and/or expressions as arguments to execute them:\n\n@example\n./qjs examples/hello.js\n@end example\n\n@code{qjsc} is the command line compiler:\n\n@example\n./qjsc -o hello examples/hello.js\n./hello\n@end example\n\ngenerates a @code{hello} executable with no external dependency.\n\n@section Command line options\n\n@subsection @code{qjs} interpreter\n\n@verbatim\nusage: qjs [options] [file [args]]\n@end verbatim\n\nOptions are:\n@table @code\n@item -h\n@item --help\nList options.\n\n@item -e @code{EXPR}\n@item --eval @code{EXPR}\nEvaluate EXPR.\n\n@item -i\n@item --interactive\nGo to interactive mode (it is not the default when files are provided on the command line).\n\n@item -m\n@item --module\nLoad as ES6 module (default=autodetect). A module is autodetected if\nthe filename extension is @code{.mjs} or if the first keyword of the\nsource is @code{import}.\n\n@item --script\nLoad as ES6 script (default=autodetect).\n\n@item -I file\n@item --include file\nInclude an additional file.\n\n@end table\n\nAdvanced options are:\n\n@table @code\n@item --std\nMake the @code{std} and @code{os} modules available to the loaded\nscript even if it is not a module.\n\n@item -d\n@item --dump\nDump the memory usage stats.\n\n@item -q\n@item --quit\njust instantiate the interpreter and quit.\n\n@end table\n\n@subsection @code{qjsc} compiler\n\n@verbatim\nusage: qjsc [options] [files]\n@end verbatim\n\nOptions are:\n@table @code\n@item -c\nOnly output bytecode in a C file. The default is to output an executable file.\n@item -e\nOutput @code{main()} and bytecode in a C file. The default is to output an\nexecutable file.\n@item -o output\nSet the output filename (default = @file{out.c} or @file{a.out}).\n\n@item -N cname\nSet the C name of the generated data.\n\n@item -m\nCompile as Javascript module (default=autodetect).\n\n@item -D module_name\nCompile a dynamically loaded module and its dependencies. This option\nis needed when your code uses the @code{import} keyword or the\n@code{os.Worker} constructor because the compiler cannot statically\nfind the name of the dynamically loaded modules.\n\n@item -M module_name[,cname]\nAdd initialization code for an external C module. See the\n@code{c_module} example.\n\n@item -x\nByte swapped output (only used for cross compilation).\n\n@item -flto\nUse link time optimization. The compilation is slower but the\nexecutable is smaller and faster. This option is automatically set\nwhen the @code{-fno-x} options are used.\n\n@item -fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise|bigint]\nDisable selected language features to produce a smaller executable file.\n\n@end table\n\n@section Built-in tests\n\nRun @code{make test} to run the few built-in tests included in the\nQuickJS archive.\n\n@section Test262 (ECMAScript Test Suite)\n\nA test262 runner is included in the QuickJS archive. The test262 tests\ncan be installed in the QuickJS source directory with:\n\n@example\ngit clone https://github.com/tc39/test262.git test262\ncd test262\npatch -p1 < ../tests/test262.patch\ncd ..\n@end example\n\nThe patch adds the implementation specific @code{harness} functions\nand optimizes the inefficient RegExp character classes and Unicode\nproperty escapes tests (the tests themselves are not modified, only a\nslow string initialization function is optimized).\n\nThe tests can be run with\n@example\nmake test2\n@end example\n\nThe configuration files @code{test262.conf}\n(resp. @code{test262o.conf} for the old ES5.1 tests@footnote{The old\nES5.1 tests can be extracted with @code{git clone --single-branch\n--branch es5-tests https://github.com/tc39/test262.git test262o}}))\ncontain the options to run the various tests. Tests can be excluded\nbased on features or filename.\n\nThe file @code{test262_errors.txt} contains the current list of\nerrors. The runner displays a message when a new error appears or when\nan existing error is corrected or modified. Use the @code{-u} option\nto update the current list of errors (or @code{make test2-update}).\n\nThe file @code{test262_report.txt} contains the logs of all the\ntests. It is useful to have a clearer analysis of a particular\nerror. In case of crash, the last line corresponds to the failing\ntest.\n\nUse the syntax @code{./run-test262 -c test262.conf -f filename.js} to\nrun a single test. Use the syntax @code{./run-test262 -c test262.conf\nN} to start testing at test number @code{N}.\n\nFor more information, run @code{./run-test262} to see the command line\noptions of the test262 runner.\n\n@code{run-test262} accepts the @code{-N} option to be invoked from\n@code{test262-harness}@footnote{@url{https://github.com/bterlson/test262-harness}}\nthru @code{eshost}. Unless you want to compare QuickJS with other\nengines under the same conditions, we do not recommend to run the\ntests this way as it is much slower (typically half an hour instead of\nabout 100 seconds).\n\n@chapter Specifications\n\n@section Language support\n\n@subsection ES2024 support\n\nThe ES2024 specification is almost fully supported including the Annex\nB (legacy web compatibility) and the Unicode related features.\n\nThe following features are not supported yet:\n\n@itemize\n\n@item Tail calls@footnote{We believe the current specification of tails calls is too complicated and presents limited practical interests.}\n\n@item Atomics.waitAsync\n\n@end itemize\n\n@subsection ECMA402\n\nECMA402 (Internationalization API) is not supported.\n\n@section Modules\n\nES6 modules are fully supported. The default name resolution is the\nfollowing:\n\n@itemize\n\n@item Module names with a leading @code{.} or @code{..} are relative\nto the current module path.\n\n@item Module names without a leading @code{.} or @code{..} are system\nmodules, such as @code{std} or @code{os}.\n\n@item Module names ending with @code{.so} are native modules using the\nQuickJS C API.\n\n@end itemize\n\n@section Standard library\n\nThe standard library is included by default in the command line\ninterpreter. It contains the two modules @code{std} and @code{os} and\na few global objects.\n\n@subsection Global objects\n\n@table @code\n@item scriptArgs\nProvides the command line arguments. The first argument is the script name.\n@item print(...args)\nPrint the arguments separated by spaces and a trailing newline.\n@item console.log(...args)\nSame as print().\n\n@end table\n\n@subsection @code{std} module\n\nThe @code{std} module provides wrappers to the libc @file{stdlib.h}\nand @file{stdio.h} and a few other utilities.\n\nAvailable exports:\n\n@table @code\n\n@item exit(n)\nExit the process.\n\n@item evalScript(str, options = undefined)\nEvaluate the string @code{str} as a script (global\neval). @code{options} is an optional object containing the following\noptional properties:\n\n  @table @code\n  @item backtrace_barrier\n  Boolean (default = false). If true, error backtraces do not list the\n  stack frames below the evalScript.\n  @item async\n  Boolean (default = false). If true, @code{await} is accepted in the\n  script and a promise is returned. The promise is resolved with an\n  object whose @code{value} property holds the value returned by the\n  script.\n  @end table\n\n@item loadScript(filename)\nEvaluate the file @code{filename} as a script (global eval).\n\n@item loadFile(filename)\nLoad the file @code{filename} and return it as a string assuming UTF-8\nencoding. Return @code{null} in case of I/O error.\n\n@item open(filename, flags, errorObj = undefined)\nOpen a file (wrapper to the libc @code{fopen()}). Return the FILE\nobject or @code{null} in case of I/O error. If @code{errorObj} is not\nundefined, set its @code{errno} property to the error code or to 0 if\nno error occured.\n\n@item popen(command, flags, errorObj = undefined)\nOpen a process by creating a pipe (wrapper to the libc\n@code{popen()}). Return the FILE\nobject or @code{null} in case of I/O error. If @code{errorObj} is not\nundefined, set its @code{errno} property to the error code or to 0 if\nno error occured.\n\n@item fdopen(fd, flags, errorObj = undefined)\nOpen a file from a file handle (wrapper to the libc\n@code{fdopen()}). Return the FILE\nobject or @code{null} in case of I/O error. If @code{errorObj} is not\nundefined, set its @code{errno} property to the error code or to 0 if\nno error occured.\n\n@item tmpfile(errorObj = undefined)\nOpen a temporary file. Return the FILE\nobject or @code{null} in case of I/O error. If @code{errorObj} is not\nundefined, set its @code{errno} property to the error code or to 0 if\nno error occured.\n\n@item puts(str)\nEquivalent to @code{std.out.puts(str)}.\n\n@item printf(fmt, ...args)\nEquivalent to @code{std.out.printf(fmt, ...args)}.\n\n@item sprintf(fmt, ...args)\nEquivalent to the libc sprintf().\n\n@item in\n@item out\n@item err\nWrappers to the libc file @code{stdin}, @code{stdout}, @code{stderr}.\n\n@item SEEK_SET\n@item SEEK_CUR\n@item SEEK_END\nConstants for seek().\n\n@item Error\n\nEnumeration object containing the integer value of common errors\n(additional error codes may be defined):\n\n  @table @code\n  @item EINVAL\n  @item EIO\n  @item EACCES\n  @item EEXIST\n  @item ENOSPC\n  @item ENOSYS\n  @item EBUSY\n  @item ENOENT\n  @item EPERM\n  @item EPIPE\n  @end table\n\n@item strerror(errno)\nReturn a string that describes the error @code{errno}.\n\n@item gc()\nManually invoke the cycle removal algorithm. The cycle removal\nalgorithm is automatically started when needed, so this function is\nuseful in case of specific memory constraints or for testing.\n\n@item getenv(name)\nReturn the value of the environment variable @code{name} or\n@code{undefined} if it is not defined.\n\n@item setenv(name, value)\nSet the value of the environment variable @code{name} to the string\n@code{value}.\n\n@item unsetenv(name)\nDelete the environment variable @code{name}.\n\n@item getenviron()\nReturn an object containing the environment variables as key-value pairs.\n\n@item urlGet(url, options = undefined)\n\nDownload @code{url} using the @file{curl} command line\nutility. @code{options} is an optional object containing the following\noptional properties:\n\n  @table @code\n  @item binary\n  Boolean (default = false). If true, the response is an ArrayBuffer\n  instead of a string. When a string is returned, the data is assumed\n  to be UTF-8 encoded.\n\n  @item full\n\n  Boolean (default = false). If true, return the an object contains\n  the properties @code{response} (response content),\n  @code{responseHeaders} (headers separated by CRLF), @code{status}\n  (status code). @code{response} is @code{null} is case of protocol or\n  network error. If @code{full} is false, only the response is\n  returned if the status is between 200 and 299. Otherwise @code{null}\n  is returned.\n\n  @end table\n\n@item parseExtJSON(str)\n\n  Parse @code{str} using a superset of @code{JSON.parse}. The superset\n  is very close to the JSON5 specification. The following extensions\n  are accepted:\n\n  @itemize\n  @item Single line and multiline comments\n  @item unquoted properties (ASCII-only Javascript identifiers)\n  @item trailing comma in array and object definitions\n  @item single quoted strings\n  @item @code{\\v} escape and multi-line strings with trailing @code{\\}\n  @item @code{\\f} and @code{\\v} are accepted as space characters\n  @item leading plus or decimal point in numbers\n  @item hexadecimal (@code{0x} prefix), octal (@code{0o} prefix) and binary (@code{0b} prefix) integers\n  @item @code{NaN} and @code{Infinity} are accepted as numbers\n  @end itemize\n@end table\n\nFILE prototype:\n\n@table @code\n@item close()\nClose the file. Return 0 if OK or @code{-errno} in case of I/O error.\n@item puts(str)\nOutputs the string with the UTF-8 encoding.\n@item printf(fmt, ...args)\nFormatted printf.\n\nThe same formats as the standard C library @code{printf} are\nsupported. Integer format types (e.g. @code{%d}) truncate the Numbers\nor BigInts to 32 bits. Use the @code{l} modifier (e.g. @code{%ld}) to\ntruncate to 64 bits.\n\n@item flush()\nFlush the buffered file.\n@item seek(offset, whence)\nSeek to a give file position (whence is\n@code{std.SEEK_*}). @code{offset} can be a number or a bigint. Return\n0 if OK or @code{-errno} in case of I/O error.\n@item tell()\nReturn the current file position.\n@item tello()\nReturn the current file position as a bigint.\n@item eof()\nReturn true if end of file.\n@item fileno()\nReturn the associated OS handle.\n@item error()\nReturn true if there was an error.\n@item clearerr()\nClear the error indication.\n\n@item read(buffer, position, length)\nRead @code{length} bytes from the file to the ArrayBuffer @code{buffer} at byte\nposition @code{position} (wrapper to the libc @code{fread}).\n\n@item write(buffer, position, length)\nWrite @code{length} bytes to the file from the ArrayBuffer @code{buffer} at byte\nposition @code{position} (wrapper to the libc @code{fwrite}).\n\n@item getline()\nReturn the next line from the file, assuming UTF-8 encoding, excluding\nthe trailing line feed.\n\n@item readAsString(max_size = undefined)\nRead @code{max_size} bytes from the file and return them as a string\nassuming UTF-8 encoding. If @code{max_size} is not present, the file\nis read up its end.\n\n@item getByte()\nReturn the next byte from the file. Return -1 if the end of file is reached.\n\n@item putByte(c)\nWrite one byte to the file.\n@end table\n\n@subsection @code{os} module\n\nThe @code{os} module provides Operating System specific functions:\n\n@itemize\n@item low level file access\n@item signals\n@item timers\n@item asynchronous I/O\n@item workers (threads)\n@end itemize\n\nThe OS functions usually return 0 if OK or an OS specific negative\nerror code.\n\nAvailable exports:\n\n@table @code\n@item open(filename, flags, mode = 0o666)\nOpen a file. Return a handle or < 0 if error.\n\n@item O_RDONLY\n@item O_WRONLY\n@item O_RDWR\n@item O_APPEND\n@item O_CREAT\n@item O_EXCL\n@item O_TRUNC\nPOSIX open flags.\n\n@item O_TEXT\n(Windows specific). Open the file in text mode. The default is binary mode.\n\n@item close(fd)\nClose the file handle @code{fd}.\n\n@item seek(fd, offset, whence)\nSeek in the file. Use @code{std.SEEK_*} for\n@code{whence}. @code{offset} is either a number or a bigint. If\n@code{offset} is a bigint, a bigint is returned too.\n\n@item read(fd, buffer, offset, length)\nRead @code{length} bytes from the file handle @code{fd} to the\nArrayBuffer @code{buffer} at byte position @code{offset}.\nReturn the number of read bytes or < 0 if error.\n\n@item write(fd, buffer, offset, length)\nWrite @code{length} bytes to the file handle @code{fd} from the\nArrayBuffer @code{buffer} at byte position @code{offset}.\nReturn the number of written bytes or < 0 if error.\n\n@item isatty(fd)\nReturn @code{true} is @code{fd} is a TTY (terminal) handle.\n\n@item ttyGetWinSize(fd)\nReturn the TTY size as @code{[width, height]} or @code{null} if not available.\n\n@item ttySetRaw(fd)\nSet the TTY in raw mode.\n\n@item remove(filename)\nRemove a file. Return 0 if OK or @code{-errno}.\n\n@item rename(oldname, newname)\nRename a file. Return 0 if OK or @code{-errno}.\n\n@item realpath(path)\nReturn @code{[str, err]} where @code{str} is the canonicalized absolute\npathname of @code{path} and @code{err} the error code.\n\n@item getcwd()\nReturn @code{[str, err]} where @code{str} is the current working directory\nand @code{err} the error code.\n\n@item chdir(path)\nChange the current directory. Return 0 if OK or @code{-errno}.\n\n@item mkdir(path, mode = 0o777)\nCreate a directory at @code{path}. Return 0 if OK or @code{-errno}.\n\n@item stat(path)\n@item lstat(path)\n\nReturn @code{[obj, err]} where @code{obj} is an object containing the\nfile status of @code{path}. @code{err} is the error code. The\nfollowing fields are defined in @code{obj}: dev, ino, mode, nlink,\nuid, gid, rdev, size, blocks, atime, mtime, ctime. The times are\nspecified in milliseconds since 1970. @code{lstat()} is the same as\n@code{stat()} excepts that it returns information about the link\nitself.\n\n@item S_IFMT\n@item S_IFIFO\n@item S_IFCHR\n@item S_IFDIR\n@item S_IFBLK\n@item S_IFREG\n@item S_IFSOCK\n@item S_IFLNK\n@item S_ISGID\n@item S_ISUID\nConstants to interpret the @code{mode} property returned by\n@code{stat()}. They have the same value as in the C system header\n@file{sys/stat.h}.\n\n@item utimes(path, atime, mtime)\nChange the access and modification times of the file @code{path}. The\ntimes are specified in milliseconds since 1970. Return 0 if OK or @code{-errno}.\n\n@item symlink(target, linkpath)\nCreate a link at @code{linkpath} containing the string @code{target}. Return 0 if OK or @code{-errno}.\n\n@item readlink(path)\nReturn @code{[str, err]} where @code{str} is the link target and @code{err}\nthe error code.\n\n@item readdir(path)\nReturn @code{[array, err]} where @code{array} is an array of strings\ncontaining the filenames of the directory @code{path}. @code{err} is\nthe error code.\n\n@item setReadHandler(fd, func)\nAdd a read handler to the file handle @code{fd}. @code{func} is called\neach time there is data pending for @code{fd}. A single read handler\nper file handle is supported. Use @code{func = null} to remove the\nhandler.\n\n@item setWriteHandler(fd, func)\nAdd a write handler to the file handle @code{fd}. @code{func} is\ncalled each time data can be written to @code{fd}. A single write\nhandler per file handle is supported. Use @code{func = null} to remove\nthe handler.\n\n@item signal(signal, func)\nCall the function @code{func} when the signal @code{signal}\nhappens. Only a single handler per signal number is supported. Use\n@code{null} to set the default handler or @code{undefined} to ignore\nthe signal. Signal handlers can only be defined in the main thread.\n\n@item SIGINT\n@item SIGABRT\n@item SIGFPE\n@item SIGILL\n@item SIGSEGV\n@item SIGTERM\nPOSIX signal numbers.\n\n@item kill(pid, sig)\nSend the signal @code{sig} to the process @code{pid}.\n\n@item exec(args[, options])\nExecute a process with the arguments @code{args}. @code{options} is an\nobject containing optional parameters:\n\n  @table @code\n  @item block\n  Boolean (default = true). If true, wait until the process is\n  terminated. In this case, @code{exec} return the exit code if positive\n  or the negated signal number if the process was interrupted by a\n  signal. If false, do not block and return the process id of the child.\n\n  @item usePath\n  Boolean (default = true). If true, the file is searched in the\n  @code{PATH} environment variable.\n\n  @item file\n  String (default = @code{args[0]}). Set the file to be executed.\n\n  @item cwd\n  String. If present, set the working directory of the new process.\n\n  @item stdin\n  @item stdout\n  @item stderr\n  If present, set the handle in the child for stdin, stdout or stderr.\n\n  @item env\n  Object. If present, set the process environment from the object\n  key-value pairs. Otherwise use the same environment as the current\n  process.\n\n  @item uid\n  Integer. If present, the process uid with @code{setuid}.\n\n  @item gid\n  Integer. If present, the process gid with @code{setgid}.\n\n  @end table\n\n@item getpid()\nReturn the current process ID.\n\n@item waitpid(pid, options)\n@code{waitpid} Unix system call. Return the array @code{[ret,\nstatus]}. @code{ret} contains @code{-errno} in case of error.\n\n@item WNOHANG\nConstant for the @code{options} argument of @code{waitpid}.\n\n@item dup(fd)\n@code{dup} Unix system call.\n\n@item dup2(oldfd, newfd)\n@code{dup2} Unix system call.\n\n@item pipe()\n@code{pipe} Unix system call. Return two handles as @code{[read_fd,\nwrite_fd]} or null in case of error.\n\n@item sleep(delay_ms)\nSleep during @code{delay_ms} milliseconds.\n\n@item sleepAsync(delay_ms)\nAsynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example:\n@example\nawait os.sleepAsync(500);\n@end example\n\n@item now()\nReturn a timestamp in milliseconds with more precision than\n@code{Date.now()}. The time origin is unspecified and is normally not\nimpacted by system clock adjustments.\n\n@item setTimeout(func, delay)\nCall the function @code{func} after @code{delay} ms. Return a handle\nto the timer.\n\n@item clearTimeout(handle)\nCancel a timer.\n\n@item platform\nReturn a string representing the platform: @code{\"linux\"}, @code{\"darwin\"},\n@code{\"win32\"} or @code{\"js\"}.\n\n@item Worker(module_filename)\nConstructor to create a new thread (worker) with an API close to the\n@code{WebWorkers}. @code{module_filename} is a string specifying the\nmodule filename which is executed in the newly created thread. As for\ndynamically imported module, it is relative to the current script or\nmodule path. Threads normally don't share any data and communicate\nbetween each other with messages. Nested workers are not supported. An\nexample is available in @file{tests/test_worker.js}.\n\nThe worker class has the following static properties:\n\n  @table @code\n  @item parent\n  In the created worker, @code{Worker.parent} represents the parent\n  worker and is used to send or receive messages.\n  @end table\n\nThe worker instances have the following properties:\n\n  @table @code\n  @item postMessage(msg)\n\n  Send a message to the corresponding worker. @code{msg} is cloned in\n  the destination worker using an algorithm similar to the @code{HTML}\n  structured clone algorithm. @code{SharedArrayBuffer} are shared\n  between workers.\n\n  Current limitations: @code{Map} and @code{Set} are not supported\n  yet.\n\n  @item onmessage\n\n  Getter and setter. Set a function which is called each time a\n  message is received. The function is called with a single\n  argument. It is an object with a @code{data} property containing the\n  received message. The thread is not terminated if there is at least\n  one non @code{null} @code{onmessage} handler.\n\n  @end table\n\n@end table\n\n@section QuickJS C API\n\nThe C API was designed to be simple and efficient. The C API is\ndefined in the header @code{quickjs.h}.\n\n@subsection Runtime and contexts\n\n@code{JSRuntime} represents a Javascript runtime corresponding to an\nobject heap. Several runtimes can exist at the same time but they\ncannot exchange objects. Inside a given runtime, no multi-threading is\nsupported.\n\n@code{JSContext} represents a Javascript context (or Realm). Each\nJSContext has its own global objects and system objects. There can be\nseveral JSContexts per JSRuntime and they can share objects, similar\nto frames of the same origin sharing Javascript objects in a\nweb browser.\n\n@subsection JSValue\n\n@code{JSValue} represents a Javascript value which can be a primitive\ntype or an object. Reference counting is used, so it is important to\nexplicitly duplicate (@code{JS_DupValue()}, increment the reference\ncount) or free (@code{JS_FreeValue()}, decrement the reference count)\nJSValues.\n\n@subsection C functions\n\nC functions can be created with\n@code{JS_NewCFunction()}. @code{JS_SetPropertyFunctionList()} is a\nshortcut to easily add functions, setters and getters properties to a\ngiven object.\n\nUnlike other embedded Javascript engines, there is no implicit stack,\nso C functions get their parameters as normal C parameters. As a\ngeneral rule, C functions take constant @code{JSValue}s as parameters\n(so they don't need to free them) and return a newly allocated (=live)\n@code{JSValue}.\n\n@subsection Exceptions\n\nExceptions: most C functions can return a Javascript exception. It\nmust be explicitly tested and handled by the C code. The specific\n@code{JSValue} @code{JS_EXCEPTION} indicates that an exception\noccurred. The actual exception object is stored in the\n@code{JSContext} and can be retrieved with @code{JS_GetException()}.\n\n@subsection Script evaluation\n\nUse @code{JS_Eval()} to evaluate a script or module source.\n\nIf the script or module was compiled to bytecode with @code{qjsc}, it\ncan be evaluated by calling @code{js_std_eval_binary()}. The advantage\nis that no compilation is needed so it is faster and smaller because\nthe compiler can be removed from the executable if no @code{eval} is\nrequired.\n\nNote: the bytecode format is linked to a given QuickJS\nversion. Moreover, no security check is done before its\nexecution. Hence the bytecode should not be loaded from untrusted\nsources. That's why there is no option to output the bytecode to a\nbinary file in @code{qjsc}.\n\n@subsection JS Classes\n\nC opaque data can be attached to a Javascript object. The type of the\nC opaque data is determined with the class ID (@code{JSClassID}) of\nthe object. Hence the first step is to register a new class ID and JS\nclass (@code{JS_NewClassID()}, @code{JS_NewClass()}). Then you can\ncreate objects of this class with @code{JS_NewObjectClass()} and get or\nset the C opaque point with\n@code{JS_GetOpaque()}/@code{JS_SetOpaque()}.\n\nWhen defining a new JS class, it is possible to declare a finalizer\nwhich is called when the object is destroyed. The finalizer should be\nused to release C resources. It is invalid to execute JS code from\nit. A @code{gc_mark} method can be provided so that the cycle removal\nalgorithm can find the other objects referenced by this object. Other\nmethods are available to define exotic object behaviors.\n\nThe Class ID are globally allocated (i.e. for all runtimes). The\nJSClass are allocated per @code{JSRuntime}. @code{JS_SetClassProto()}\nis used to define a prototype for a given class in a given\nJSContext. @code{JS_NewObjectClass()} sets this prototype in the\ncreated object.\n\nExamples are available in @file{quickjs-libc.c}.\n\n@subsection C Modules\n\nNative ES6 modules are supported and can be dynamically or statically\nlinked. Look at the @file{test_bjson} and @file{bjson.so}\nexamples. The standard library @file{quickjs-libc.c} is also a good example\nof a native module.\n\n@subsection Memory handling\n\nUse @code{JS_SetMemoryLimit()} to set a global memory allocation limit\nto a given JSRuntime.\n\nCustom memory allocation functions can be provided with\n@code{JS_NewRuntime2()}.\n\nThe maximum system stack size can be set with @code{JS_SetMaxStackSize()}.\n\n@subsection Execution timeout and interrupts\n\nUse @code{JS_SetInterruptHandler()} to set a callback which is\nregularly called by the engine when it is executing code. This\ncallback can be used to implement an execution timeout.\n\nIt is used by the command line interpreter to implement a\n@code{Ctrl-C} handler.\n\n@chapter Internals\n\n@section Bytecode\n\nThe compiler generates bytecode directly with no intermediate\nrepresentation such as a parse tree, hence it is very fast. Several\noptimizations passes are done over the generated bytecode.\n\nA stack-based bytecode was chosen because it is simple and generates\ncompact code.\n\nFor each function, the maximum stack size is computed at compile time so that\nno runtime stack overflow tests are needed.\n\nA separate compressed line number table is maintained for the debug\ninformation.\n\nAccess to closure variables is optimized and is almost as fast as local\nvariables.\n\nDirect @code{eval} in strict mode is optimized.\n\n@section Executable generation\n\n@subsection @code{qjsc} compiler\n\nThe @code{qjsc} compiler generates C sources from Javascript files. By\ndefault the C sources are compiled with the system compiler\n(@code{gcc} or @code{clang}).\n\nThe generated C source contains the bytecode of the compiled functions\nor modules. If a full complete executable is needed, it also\ncontains a @code{main()} function with the necessary C code to initialize the\nJavascript engine and to load and execute the compiled functions and\nmodules.\n\nJavascript code can be mixed with C modules.\n\nIn order to have smaller executables, specific Javascript features can\nbe disabled, in particular @code{eval} or the regular expressions. The\ncode removal relies on the Link Time Optimization of the system\ncompiler.\n\n@subsection Binary JSON\n\n@code{qjsc} works by compiling scripts or modules and then serializing\nthem to a binary format. A subset of this format (without functions or\nmodules) can be used as binary JSON. The example @file{test_bjson.js}\nshows how to use it.\n\nWarning: the binary JSON format may change without notice, so it\nshould not be used to store persistent data. The @file{test_bjson.js}\nexample is only used to test the binary object format functions.\n\n@section Runtime\n\n@subsection Strings\n\nStrings are stored either as an 8 bit or a 16 bit array of\ncharacters. Hence random access to characters is always fast.\n\nThe C API provides functions to convert Javascript Strings to C UTF-8 encoded\nstrings. The most common case where the Javascript string contains\nonly ASCII characters involves no copying.\n\n@subsection Objects\n\nThe object shapes (object prototype, property names and flags) are shared\nbetween objects to save memory.\n\nArrays with no holes (except at the end of the array) are optimized.\n\nTypedArray accesses are optimized.\n\n@subsection Atoms\n\nObject property names and some strings are stored as Atoms (unique\nstrings) to save memory and allow fast comparison. Atoms are\nrepresented as a 32 bit integer. Half of the atom range is reserved for\nimmediate integer literals from @math{0} to @math{2^{31}-1}.\n\n@subsection Numbers\n\nNumbers are represented either as 32-bit signed integers or 64-bit IEEE-754\nfloating point values. Most operations have fast paths for the 32-bit\ninteger case.\n\n@subsection Garbage collection\n\nReference counting is used to free objects automatically and\ndeterministically. A separate cycle removal pass is done when the allocated\nmemory becomes too large. The cycle removal algorithm only uses the\nreference counts and the object content, so no explicit garbage\ncollection roots need to be manipulated in the C code.\n\n@subsection JSValue\n\nIt is a Javascript value which can be a primitive type (such as\nNumber, String, ...) or an Object. NaN boxing is used in the 32-bit version\nto store 64-bit floating point numbers. The representation is\noptimized so that 32-bit integers and reference counted values can be\nefficiently tested.\n\nIn 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The\nrationale is that in 64-bit code memory usage is less critical.\n\nIn both cases (32 or 64 bits), JSValue exactly fits two CPU registers,\nso it can be efficiently returned by C functions.\n\n@subsection Function call\n\nThe engine is optimized so that function calls are fast. The system\nstack holds the Javascript parameters and local variables.\n\n@section RegExp\n\nA specific regular expression engine was developed. It is both small\nand efficient and supports all the ES2024 features including the\nUnicode properties. As the Javascript compiler, it directly generates\nbytecode without a parse tree.\n\nBacktracking with an explicit stack is used so that there is no\nrecursion on the system stack. Simple quantifiers are specifically\noptimized to avoid recursions.\n\nThe full regexp library weights about 15 KiB (x86 code), excluding the\nUnicode library.\n\n@section Unicode\n\nA specific Unicode library was developed so that there is no\ndependency on an external large Unicode library such as ICU. All the\nUnicode tables are compressed while keeping a reasonable access\nspeed.\n\nThe library supports case conversion, Unicode normalization, Unicode\nscript queries, Unicode general category queries and all Unicode\nbinary properties.\n\nThe full Unicode library weights about 45 KiB (x86 code).\n\n@section BigInt\n\nBigInts are represented using binary two's complement notation. An\nadditional short bigint value is used to optimize the performance on\nsmall BigInt values.\n\n@chapter License\n\nQuickJS is released under the MIT license.\n\nUnless otherwise specified, the QuickJS sources are copyright Fabrice\nBellard and Charlie Gordon.\n\n@bye\n"
  },
  {
    "path": "dtoa.c",
    "content": "/*\n * Tiny float64 printing and parsing library\n *\n * Copyright (c) 2024 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n#include <ctype.h>\n#include <sys/time.h>\n#include <math.h>\n#include <setjmp.h>\n\n#include \"cutils.h\"\n#include \"dtoa.h\"\n\n/* \n   TODO:\n   - test n_digits=101 instead of 100\n   - simplify subnormal handling\n   - reduce max memory usage\n   - free format: could add shortcut if exact result\n   - use 64 bit limb_t when possible\n   - use another algorithm for free format dtoa in base 10 (ryu ?)\n*/\n\n#define USE_POW5_TABLE\n/* use fast path to print small integers in free format */\n#define USE_FAST_INT\n\n#define LIMB_LOG2_BITS 5\n\n#define LIMB_BITS (1 << LIMB_LOG2_BITS)\n\ntypedef int32_t slimb_t;\ntypedef uint32_t limb_t;\ntypedef uint64_t dlimb_t;\n\n#define LIMB_DIGITS 9\n\n#define JS_RADIX_MAX 36\n\n#define DBIGNUM_LEN_MAX 52 /* ~ 2^(1072+53)*36^100 (dtoa) */\n#define MANT_LEN_MAX 18 /* < 36^100 */\n\ntypedef intptr_t mp_size_t;\n\n/* the represented number is sum(i, tab[i]*2^(LIMB_BITS * i)) */\ntypedef struct {\n    int len; /* >= 1 */\n    limb_t tab[];\n} mpb_t;\n\nstatic limb_t mp_add_ui(limb_t *tab, limb_t b, size_t n)\n{\n    size_t i;\n    limb_t k, a;\n\n    k=b;\n    for(i=0;i<n;i++) {\n        if (k == 0)\n            break;\n        a = tab[i] + k;\n        k = (a < k);\n        tab[i] = a;\n    }\n    return k;\n}\n\n/* tabr[] = taba[] * b + l. Return the high carry */\nstatic limb_t mp_mul1(limb_t *tabr, const limb_t *taba, limb_t n, \n                      limb_t b, limb_t l)\n{\n    limb_t i;\n    dlimb_t t;\n\n    for(i = 0; i < n; i++) {\n        t = (dlimb_t)taba[i] * (dlimb_t)b + l;\n        tabr[i] = t;\n        l = t >> LIMB_BITS;\n    }\n    return l;\n}\n\n/* WARNING: d must be >= 2^(LIMB_BITS-1) */\nstatic inline limb_t udiv1norm_init(limb_t d)\n{\n    limb_t a0, a1;\n    a1 = -d - 1;\n    a0 = -1;\n    return (((dlimb_t)a1 << LIMB_BITS) | a0) / d;\n}\n\n/* return the quotient and the remainder in '*pr'of 'a1*2^LIMB_BITS+a0\n   / d' with 0 <= a1 < d. */\nstatic inline limb_t udiv1norm(limb_t *pr, limb_t a1, limb_t a0,\n                                limb_t d, limb_t d_inv)\n{\n    limb_t n1m, n_adj, q, r, ah;\n    dlimb_t a;\n    n1m = ((slimb_t)a0 >> (LIMB_BITS - 1));\n    n_adj = a0 + (n1m & d);\n    a = (dlimb_t)d_inv * (a1 - n1m) + n_adj;\n    q = (a >> LIMB_BITS) + a1;\n    /* compute a - q * r and update q so that the remainder is between\n       0 and d - 1 */\n    a = ((dlimb_t)a1 << LIMB_BITS) | a0;\n    a = a - (dlimb_t)q * d - d;\n    ah = a >> LIMB_BITS;\n    q += 1 + ah;\n    r = (limb_t)a + (ah & d);\n    *pr = r;\n    return q;\n}\n\nstatic limb_t mp_div1(limb_t *tabr, const limb_t *taba, limb_t n,\n                      limb_t b, limb_t r)\n{\n    slimb_t i;\n    dlimb_t a1;\n    for(i = n - 1; i >= 0; i--) {\n        a1 = ((dlimb_t)r << LIMB_BITS) | taba[i];\n        tabr[i] = a1 / b;\n        r = a1 % b;\n    }\n    return r;\n}\n\n/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). \n   1 <= shift <= LIMB_BITS - 1 */\nstatic limb_t mp_shr(limb_t *tab_r, const limb_t *tab, mp_size_t n, \n                     int shift, limb_t high)\n{\n    mp_size_t i;\n    limb_t l, a;\n\n    assert(shift >= 1 && shift < LIMB_BITS);\n    l = high;\n    for(i = n - 1; i >= 0; i--) {\n        a = tab[i];\n        tab_r[i] = (a >> shift) | (l << (LIMB_BITS - shift));\n        l = a;\n    }\n    return l & (((limb_t)1 << shift) - 1);\n}\n\n/* r = (a << shift) + low. 1 <= shift <= LIMB_BITS - 1, 0 <= low <\n   2^shift. */\nstatic limb_t mp_shl(limb_t *tab_r, const limb_t *tab, mp_size_t n, \n              int shift, limb_t low)\n{\n    mp_size_t i;\n    limb_t l, a;\n\n    assert(shift >= 1 && shift < LIMB_BITS);\n    l = low;\n    for(i = 0; i < n; i++) {\n        a = tab[i];\n        tab_r[i] = (a << shift) | l;\n        l = (a >> (LIMB_BITS - shift)); \n    }\n    return l;\n}\n\nstatic no_inline limb_t mp_div1norm(limb_t *tabr, const limb_t *taba, limb_t n,\n                                    limb_t b, limb_t r, limb_t b_inv, int shift)\n{\n    slimb_t i;\n\n    if (shift != 0) {\n        r = (r << shift) | mp_shl(tabr, taba, n, shift, 0);\n    }\n    for(i = n - 1; i >= 0; i--) {\n        tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);\n    }\n    r >>= shift;\n    return r;\n}\n\nstatic __maybe_unused void mpb_dump(const char *str, const mpb_t *a)\n{\n    int i;\n    \n    printf(\"%s= 0x\", str);\n    for(i = a->len - 1; i >= 0; i--) {\n        printf(\"%08x\", a->tab[i]);\n        if (i != 0)\n            printf(\"_\");\n    }\n    printf(\"\\n\");\n}\n\nstatic void mpb_renorm(mpb_t *r)\n{\n    while (r->len > 1 && r->tab[r->len - 1] == 0)\n        r->len--;\n}\n\n#ifdef USE_POW5_TABLE\nstatic const uint32_t pow5_table[17] = {\n    0x00000005, 0x00000019, 0x0000007d, 0x00000271, \n    0x00000c35, 0x00003d09, 0x0001312d, 0x0005f5e1, \n    0x001dcd65, 0x009502f9, 0x02e90edd, 0x0e8d4a51, \n    0x48c27395, 0x6bcc41e9, 0x1afd498d, 0x86f26fc1, \n    0xa2bc2ec5, \n};\n\nstatic const uint8_t pow5h_table[4] = {\n    0x00000001, 0x00000007, 0x00000023, 0x000000b1, \n};\n\nstatic const uint32_t pow5_inv_table[13] = {\n    0x99999999, 0x47ae147a, 0x0624dd2f, 0xa36e2eb1,\n    0x4f8b588e, 0x0c6f7a0b, 0xad7f29ab, 0x5798ee23,\n    0x12e0be82, 0xb7cdfd9d, 0x5fd7fe17, 0x19799812,\n    0xc25c2684,\n};\n#endif\n\n/* return a^b */\nstatic uint64_t pow_ui(uint32_t a, uint32_t b)\n{\n    int i, n_bits;\n    uint64_t r;\n    if (b == 0)\n        return 1;\n    if (b == 1)\n        return a;\n#ifdef USE_POW5_TABLE\n    if ((a == 5 || a == 10) && b <= 17) {\n        r = pow5_table[b - 1];\n        if (b >= 14) {\n            r |= (uint64_t)pow5h_table[b - 14] << 32;\n        }\n        if (a == 10)\n            r <<= b;\n        return r;\n    }\n#endif\n    r = a;\n    n_bits = 32 - clz32(b);\n    for(i = n_bits - 2; i >= 0; i--) {\n        r *= r;\n        if ((b >> i) & 1)\n            r *= a;\n    }\n    return r;\n}\n\nstatic uint32_t pow_ui_inv(uint32_t *pr_inv, int *pshift, uint32_t a, uint32_t b)\n{\n    uint32_t r_inv, r;\n    int shift;\n#ifdef USE_POW5_TABLE\n    if (a == 5 && b >= 1 && b <= 13) {\n        r = pow5_table[b - 1];\n        shift = clz32(r);\n        r <<= shift;\n        r_inv = pow5_inv_table[b - 1];\n    } else\n#endif\n    {\n        r = pow_ui(a, b);\n        shift = clz32(r);\n        r <<= shift;\n        r_inv = udiv1norm_init(r);\n    }\n    *pshift = shift;\n    *pr_inv = r_inv;\n    return r;\n}\n\nenum {\n    JS_RNDN, /* round to nearest, ties to even */\n    JS_RNDNA, /* round to nearest, ties away from zero */\n    JS_RNDZ,\n};\n\nstatic int mpb_get_bit(const mpb_t *r, int k)\n{\n    int l;\n    \n    l = (unsigned)k / LIMB_BITS;\n    k = k & (LIMB_BITS - 1);\n    if (l >= r->len)\n        return 0;\n    else\n        return (r->tab[l] >> k) & 1;\n}\n\n/* compute round(r / 2^shift). 'shift' can be negative */\nstatic void mpb_shr_round(mpb_t *r, int shift, int rnd_mode)\n{\n    int l, i;\n\n    if (shift == 0)\n        return;\n    if (shift < 0) {\n        shift = -shift;\n        l = (unsigned)shift / LIMB_BITS;\n        shift = shift & (LIMB_BITS - 1);\n        if (shift != 0) {\n            r->tab[r->len] = mp_shl(r->tab, r->tab, r->len, shift, 0);\n            r->len++;\n            mpb_renorm(r);\n        }\n        if (l > 0) {\n            for(i = r->len - 1; i >= 0; i--)\n                r->tab[i + l] = r->tab[i];\n            for(i = 0; i < l; i++)\n                r->tab[i] = 0;\n            r->len += l;\n        }\n    } else {\n        limb_t bit1, bit2;\n        int k, add_one;\n        \n        switch(rnd_mode) {\n        default:\n        case JS_RNDZ:\n            add_one = 0;\n            break;\n        case JS_RNDN:\n        case JS_RNDNA:\n            bit1 = mpb_get_bit(r, shift - 1);\n            if (bit1) {\n                if (rnd_mode == JS_RNDNA) {\n                    bit2 = 1;\n                } else {\n                    /* bit2 = oring of all the bits after bit1 */\n                    bit2 = 0;\n                    if (shift >= 2) {\n                        k = shift - 1;\n                        l = (unsigned)k / LIMB_BITS;\n                        k = k & (LIMB_BITS - 1);\n                        for(i = 0; i < min_int(l, r->len); i++)\n                            bit2 |= r->tab[i];\n                        if (l < r->len)\n                            bit2 |= r->tab[l] & (((limb_t)1 << k) - 1);\n                    }\n                }\n                if (bit2) {\n                    add_one = 1;\n                } else {\n                    /* round to even */\n                    add_one = mpb_get_bit(r, shift);\n                }\n            } else {\n                add_one = 0;\n            }\n            break;\n        }\n\n        l = (unsigned)shift / LIMB_BITS;\n        shift = shift & (LIMB_BITS - 1);\n        if (l >= r->len) {\n            r->len = 1;\n            r->tab[0] = add_one;\n        } else {\n            if (l > 0) {\n                r->len -= l;\n                for(i = 0; i < r->len; i++)\n                    r->tab[i] = r->tab[i + l];\n            }\n            if (shift != 0) {\n                mp_shr(r->tab, r->tab, r->len, shift, 0);\n                mpb_renorm(r);\n            }\n            if (add_one) {\n                limb_t a;\n                a = mp_add_ui(r->tab, 1, r->len);\n                if (a)\n                    r->tab[r->len++] = a;\n            }\n        }\n    }\n}\n\n/* return -1, 0 or 1 */\nstatic int mpb_cmp(const mpb_t *a, const mpb_t *b)\n{\n    mp_size_t i;\n    if (a->len < b->len)\n        return -1;\n    else if (a->len > b->len)\n        return 1;\n    for(i = a->len - 1; i >= 0; i--) {\n        if (a->tab[i] != b->tab[i]) {\n            if (a->tab[i] < b->tab[i])\n                return -1;\n            else\n                return 1;\n        }\n    }\n    return 0;\n}\n\nstatic void mpb_set_u64(mpb_t *r, uint64_t m)\n{\n#if LIMB_BITS == 64\n    r->tab[0] = m;\n    r->len = 1;\n#else\n    r->tab[0] = m;\n    r->tab[1] = m >> LIMB_BITS;\n    if (r->tab[1] == 0)\n        r->len = 1;\n    else\n        r->len = 2;\n#endif\n}\n\nstatic uint64_t mpb_get_u64(mpb_t *r)\n{\n#if LIMB_BITS == 64\n    return r->tab[0];\n#else\n    if (r->len == 1) {\n        return r->tab[0];\n    } else {\n        return r->tab[0] | ((uint64_t)r->tab[1] << LIMB_BITS);\n    }\n#endif\n}\n\n/* floor_log2() = position of the first non zero bit or -1 if zero. */\nstatic int mpb_floor_log2(mpb_t *a)\n{\n    limb_t v;\n    v = a->tab[a->len - 1];\n    if (v == 0)\n        return -1;\n    else\n        return a->len * LIMB_BITS - 1 - clz32(v);\n}\n\n#define MUL_LOG2_RADIX_BASE_LOG2 24\n\n/* round((1 << MUL_LOG2_RADIX_BASE_LOG2)/log2(i + 2)) */\nstatic const uint32_t mul_log2_radix_table[JS_RADIX_MAX - 1] = {\n    0x000000, 0xa1849d, 0x000000, 0x6e40d2, \n    0x6308c9, 0x5b3065, 0x000000, 0x50c24e, \n    0x4d104d, 0x4a0027, 0x4768ce, 0x452e54, \n    0x433d00, 0x418677, 0x000000, 0x3ea16b, \n    0x3d645a, 0x3c43c2, 0x3b3b9a, 0x3a4899, \n    0x39680b, 0x3897b3, 0x37d5af, 0x372069, \n    0x367686, 0x35d6df, 0x354072, 0x34b261, \n    0x342bea, 0x33ac62, 0x000000, 0x32bfd9, \n    0x3251dd, 0x31e8d6, 0x318465,\n};\n\n/* return floor(a / log2(radix)) for -2048 <= a <= 2047 */\nstatic int mul_log2_radix(int a, int radix)\n{\n    int radix_bits, mult;\n\n    if ((radix & (radix - 1)) == 0) {\n        /* if the radix is a power of two better to do it exactly */\n        radix_bits = 31 - clz32(radix);\n        if (a < 0)\n            a -= radix_bits - 1;\n        return a / radix_bits;\n    } else {\n        mult = mul_log2_radix_table[radix - 2];\n        return ((int64_t)a * mult) >> MUL_LOG2_RADIX_BASE_LOG2;\n    }\n}\n\n#if 0\nstatic void build_mul_log2_radix_table(void)\n{\n    int base, radix, mult, col, base_log2;\n\n    base_log2 = 24;\n    base = 1 << base_log2;\n    col = 0;\n    for(radix = 2; radix <= 36; radix++) {\n        if ((radix & (radix - 1)) == 0)\n            mult = 0;\n        else\n            mult = lrint((double)base / log2(radix));\n        printf(\"0x%06x, \", mult);\n        if (++col == 4) {\n            printf(\"\\n\");\n            col = 0;\n        }\n    }\n    printf(\"\\n\");\n}\n\nstatic void mul_log2_radix_test(void)\n{\n    int radix, i, ref, r;\n    \n    for(radix = 2; radix <= 36; radix++) {\n        for(i = -2048; i <= 2047; i++) {\n            ref = (int)floor((double)i / log2(radix));\n            r = mul_log2_radix(i, radix);\n            if (ref != r) {\n                printf(\"ERROR: radix=%d i=%d r=%d ref=%d\\n\",\n                       radix, i, r, ref);\n                exit(1);\n            }\n        }\n    }\n    if (0)\n        build_mul_log2_radix_table();\n}\n#endif\n\nstatic void u32toa_len(char *buf, uint32_t n, size_t len)\n{\n    int digit, i;\n    for(i = len - 1; i >= 0; i--) {\n        digit = n % 10;\n        n = n / 10;\n        buf[i] = digit + '0';\n    }\n}\n\n/* for power of 2 radixes. len >= 1 */\nstatic void u64toa_bin_len(char *buf, uint64_t n, unsigned int radix_bits, int len)\n{\n    int digit, i;\n    unsigned int mask;\n\n    mask = (1 << radix_bits) - 1;\n    for(i = len - 1; i >= 0; i--) {\n        digit = n & mask;\n        n >>= radix_bits;\n        if (digit < 10)\n            digit += '0';\n        else\n            digit += 'a' - 10;\n        buf[i] = digit;\n    }\n}\n\n/* len >= 1. 2 <= radix <= 36 */\nstatic void limb_to_a(char *buf, limb_t n, unsigned int radix, int len)\n{\n    int digit, i;\n\n    if (radix == 10) {\n        /* specific case with constant divisor */\n#if LIMB_BITS == 32\n        u32toa_len(buf, n, len);\n#else\n        /* XXX: optimize */\n        for(i = len - 1; i >= 0; i--) {\n            digit = (limb_t)n % 10;\n            n = (limb_t)n / 10;\n            buf[i] = digit + '0';\n        }\n#endif\n    } else {\n        for(i = len - 1; i >= 0; i--) {\n            digit = (limb_t)n % radix;\n            n = (limb_t)n / radix;\n            if (digit < 10)\n                digit += '0';\n            else\n                digit += 'a' - 10;\n            buf[i] = digit;\n        }\n    }\n}\n\nsize_t u32toa(char *buf, uint32_t n)\n{\n    char buf1[10], *q;\n    size_t len;\n    \n    q = buf1 + sizeof(buf1);\n    do {\n        *--q = n % 10 + '0';\n        n /= 10;\n    } while (n != 0);\n    len = buf1 + sizeof(buf1) - q;\n    memcpy(buf, q, len);\n    return len;\n}\n\nsize_t i32toa(char *buf, int32_t n)\n{\n    if (n >= 0) {\n        return u32toa(buf, n);\n    } else {\n        buf[0] = '-';\n        return u32toa(buf + 1, -(uint32_t)n) + 1;\n    }\n}\n\n#ifdef USE_FAST_INT\nsize_t u64toa(char *buf, uint64_t n)\n{\n    if (n < 0x100000000) {\n        return u32toa(buf, n);\n    } else {\n        uint64_t n1;\n        char *q = buf;\n        uint32_t n2;\n        \n        n1 = n / 1000000000;\n        n %= 1000000000;\n        if (n1 >= 0x100000000) {\n            n2 = n1 / 1000000000;\n            n1 = n1 % 1000000000;\n            /* at most two digits */\n            if (n2 >= 10) {\n                *q++ = n2 / 10 + '0';\n                n2 %= 10;\n            }\n            *q++ = n2 + '0';\n            u32toa_len(q, n1, 9);\n            q += 9;\n        } else {\n            q += u32toa(q, n1);\n        }\n        u32toa_len(q, n, 9);\n        q += 9;\n        return q - buf;\n    }\n}\n\nsize_t i64toa(char *buf, int64_t n)\n{\n    if (n >= 0) {\n        return u64toa(buf, n);\n    } else {\n        buf[0] = '-';\n        return u64toa(buf + 1, -(uint64_t)n) + 1;\n    }\n}\n\n/* XXX: only tested for 1 <= n < 2^53 */\nsize_t u64toa_radix(char *buf, uint64_t n, unsigned int radix)\n{\n    int radix_bits, l;\n    if (likely(radix == 10))\n        return u64toa(buf, n);\n    if ((radix & (radix - 1)) == 0) {\n        radix_bits = 31 - clz32(radix);\n        if (n == 0)\n            l = 1;\n        else\n            l = (64 - clz64(n) + radix_bits - 1) / radix_bits;\n        u64toa_bin_len(buf, n, radix_bits, l);\n        return l;\n    } else {\n        char buf1[41], *q; /* maximum length for radix = 3 */\n        size_t len;\n        int digit;\n        q = buf1 + sizeof(buf1);\n        do {\n            digit = n % radix;\n            n /= radix;\n            if (digit < 10)\n                digit += '0';\n            else\n                digit += 'a' - 10;\n            *--q = digit;\n        } while (n != 0);\n        len = buf1 + sizeof(buf1) - q;\n        memcpy(buf, q, len);\n        return len;\n    }\n}\n\nsize_t i64toa_radix(char *buf, int64_t n, unsigned int radix)\n{\n    if (n >= 0) {\n        return u64toa_radix(buf, n, radix);\n    } else {\n        buf[0] = '-';\n        return u64toa_radix(buf + 1, -(uint64_t)n, radix) + 1;\n    }\n}\n#endif /* USE_FAST_INT */\n\nstatic const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = {\n#if LIMB_BITS == 32\n32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,\n#else\n64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,\n#endif\n};\n\nstatic const uint32_t radix_base_table[JS_RADIX_MAX - 1] = {\n 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,\n 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,\n 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,\n 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,\n 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,\n 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,\n 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,\n 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,\n 0x5c13d840, 0x6d91b519, 0x81bf1000,\n};\n\n/* XXX: remove the table ? */\nstatic uint8_t dtoa_max_digits_table[JS_RADIX_MAX - 1] = {\n    54, 35, 28, 24, 22, 20, 19, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12,\n};\n\n/* we limit the maximum number of significant digits for atod to about\n   128 bits of precision for non power of two bases. The only\n   requirement for Javascript is at least 20 digits in base 10. For\n   power of two bases, we do an exact rounding in all the cases. */\nstatic uint8_t atod_max_digits_table[JS_RADIX_MAX - 1] = {\n     64, 80, 32, 55, 49, 45, 21, 40, 38, 37, 35, 34, 33, 32, 16, 31, 30, 30, 29, 29, 28, 28, 27, 27, 27, 26, 26, 26, 26, 25, 12, 25, 25, 24, 24,\n};\n\n/* if abs(d) >= B^max_exponent, it is an overflow */\nstatic const int16_t max_exponent[JS_RADIX_MAX - 1] = {\n 1024,   647,   512,   442,   397,   365,   342,   324, \n  309,   297,   286,   277,   269,   263,   256,   251, \n  246,   242,   237,   234,   230,   227,   224,   221, \n  218,   216,   214,   211,   209,   207,   205,   203, \n  202,   200,   199, \n};\n\n/* if abs(d) <= B^min_exponent, it is an underflow */\nstatic const int16_t min_exponent[JS_RADIX_MAX - 1] = {\n-1075,  -679,  -538,  -463,  -416,  -383,  -359,  -340, \n -324,  -311,  -300,  -291,  -283,  -276,  -269,  -263, \n -258,  -254,  -249,  -245,  -242,  -238,  -235,  -232, \n -229,  -227,  -224,  -222,  -220,  -217,  -215,  -214, \n -212,  -210,  -208, \n};\n\n#if 0\nvoid build_tables(void)\n{\n    int r, j, radix, n, col, i;\n    \n    /* radix_base_table */\n    for(radix = 2; radix <= 36; radix++) {\n        r = 1;\n        for(j = 0; j < digits_per_limb_table[radix - 2]; j++) {\n            r *= radix;\n        }\n        printf(\" 0x%08x,\", r);\n        if ((radix % 4) == 1)\n            printf(\"\\n\");\n    }\n    printf(\"\\n\");\n\n    /* dtoa_max_digits_table */\n    for(radix = 2; radix <= 36; radix++) {\n        /* Note: over estimated when the radix is a power of two */\n        printf(\" %d,\", 1 + (int)ceil(53.0 / log2(radix)));\n    }\n    printf(\"\\n\");\n\n    /* atod_max_digits_table */\n    for(radix = 2; radix <= 36; radix++) {\n        if ((radix & (radix - 1)) == 0) {\n            /* 64 bits is more than enough */\n            n = (int)floor(64.0 / log2(radix));\n        } else {\n            n = (int)floor(128.0 / log2(radix));\n        }\n        printf(\" %d,\", n);\n    }\n    printf(\"\\n\");\n\n    printf(\"static const int16_t max_exponent[JS_RADIX_MAX - 1] = {\\n\");\n    col = 0;\n    for(radix = 2; radix <= 36; radix++) {\n        printf(\"%5d, \", (int)ceil(1024 / log2(radix)));\n        if (++col == 8) {\n            col = 0;\n            printf(\"\\n\");\n        }\n    }\n    printf(\"\\n};\\n\\n\");\n\n    printf(\"static const int16_t min_exponent[JS_RADIX_MAX - 1] = {\\n\");\n    col = 0; \n    for(radix = 2; radix <= 36; radix++) {\n        printf(\"%5d, \", (int)floor(-1075 / log2(radix)));\n        if (++col == 8) {\n            col = 0;\n            printf(\"\\n\");\n        }\n    }\n    printf(\"\\n};\\n\\n\");\n\n    printf(\"static const uint32_t pow5_table[16] = {\\n\");\n    col = 0; \n    for(i = 2; i <= 17; i++) {\n        r = 1;\n        for(j = 0; j < i; j++) {\n            r *= 5;\n        }\n        printf(\"0x%08x, \", r);\n        if (++col == 4) {\n            col = 0;\n            printf(\"\\n\");\n        }\n    }\n    printf(\"\\n};\\n\\n\");\n\n    /* high part */\n    printf(\"static const uint8_t pow5h_table[4] = {\\n\");\n    col = 0; \n    for(i = 14; i <= 17; i++) {\n        uint64_t r1;\n        r1 = 1;\n        for(j = 0; j < i; j++) {\n            r1 *= 5;\n        }\n        printf(\"0x%08x, \", (uint32_t)(r1 >> 32));\n        if (++col == 4) {\n            col = 0;\n            printf(\"\\n\");\n        }\n    }\n    printf(\"\\n};\\n\\n\");\n}\n#endif\n\n/* n_digits >= 1. 0 <= dot_pos <= n_digits. If dot_pos == n_digits,\n   the dot is not displayed. 'a' is modified. */\nstatic int output_digits(char *buf,\n                         mpb_t *a, int radix, int n_digits1,\n                         int dot_pos)\n{\n    int n_digits, digits_per_limb, radix_bits, n, len;\n\n    n_digits = n_digits1;\n    if ((radix & (radix - 1)) == 0) {\n        /* radix = 2^radix_bits */\n        radix_bits = 31 - clz32(radix);\n    } else {\n        radix_bits = 0;\n    }\n    digits_per_limb = digits_per_limb_table[radix - 2];\n    if (radix_bits != 0) {\n        for(;;) {\n            n = min_int(n_digits, digits_per_limb);\n            n_digits -= n;\n            u64toa_bin_len(buf + n_digits, a->tab[0], radix_bits, n);\n            if (n_digits == 0)\n                break;\n            mpb_shr_round(a, digits_per_limb * radix_bits, JS_RNDZ);\n        }\n    } else {\n        limb_t r;\n        while (n_digits != 0) {\n            n = min_int(n_digits, digits_per_limb);\n            n_digits -= n;\n            r = mp_div1(a->tab, a->tab, a->len, radix_base_table[radix - 2], 0);\n            mpb_renorm(a);\n            limb_to_a(buf + n_digits, r, radix, n);\n        }\n    }\n\n    /* add the dot */\n    len = n_digits1;\n    if (dot_pos != n_digits1) {\n        memmove(buf + dot_pos + 1, buf + dot_pos, n_digits1 - dot_pos);\n        buf[dot_pos] = '.';\n        len++;\n    }\n    return len;\n}\n\n/* return (a, e_offset) such that a = a * (radix1*2^radix_shift)^f *\n   2^-e_offset. 'f' can be negative. */\nstatic int mul_pow(mpb_t *a, int radix1, int radix_shift, int f, BOOL is_int, int e)\n{\n    int e_offset, d, n, n0;\n\n    e_offset = -f * radix_shift;\n    if (radix1 != 1) {\n        d = digits_per_limb_table[radix1 - 2];\n        if (f >= 0) {\n            limb_t h, b;\n            \n            b = 0;\n            n0 = 0;\n            while (f != 0) {\n                n = min_int(f, d);\n                if (n != n0) {\n                    b = pow_ui(radix1, n);\n                    n0 = n;\n                }\n                h = mp_mul1(a->tab, a->tab, a->len, b, 0);\n                if (h != 0) {\n                    a->tab[a->len++] = h;\n                }\n                f -= n;\n            }\n        } else {\n            int extra_bits, l, shift;\n            limb_t r, rem, b, b_inv;\n            \n            f = -f;\n            l = (f + d - 1) / d; /* high bound for the number of limbs (XXX: make it better) */\n            e_offset += l * LIMB_BITS;\n            if (!is_int) {\n                /* at least 'e' bits are needed in the final result for rounding */\n                extra_bits = max_int(e - mpb_floor_log2(a), 0);\n            } else {\n                /* at least two extra bits are needed in the final result\n                   for rounding */\n                extra_bits = max_int(2 + e - e_offset, 0);\n            }\n            e_offset += extra_bits;\n            mpb_shr_round(a, -(l * LIMB_BITS + extra_bits), JS_RNDZ);\n            \n            b = 0;\n            b_inv = 0;\n            shift = 0;\n            n0 = 0;\n            rem = 0;\n            while (f != 0) {\n                n = min_int(f, d);\n                if (n != n0) {\n                    b = pow_ui_inv(&b_inv, &shift, radix1, n);\n                    n0 = n;\n                }\n                r = mp_div1norm(a->tab, a->tab, a->len, b, 0, b_inv, shift);\n                rem |= r;\n                mpb_renorm(a);\n                f -= n;\n            }\n            /* if the remainder is non zero, use it for rounding */\n            a->tab[0] |= (rem != 0);\n        }\n    }\n    return e_offset;\n}\n\n/* tmp1 = round(m*2^e*radix^f). 'tmp0' is a temporary storage */\nstatic void mul_pow_round(mpb_t *tmp1, uint64_t m, int e, int radix1, int radix_shift, int f,\n                          int rnd_mode)\n{\n    int e_offset;\n\n    mpb_set_u64(tmp1, m);\n    e_offset = mul_pow(tmp1, radix1, radix_shift, f, TRUE, e);\n    mpb_shr_round(tmp1, -e + e_offset, rnd_mode);\n}\n\n/* return round(a*2^e_offset) rounded as a float64. 'a' is modified */\nstatic uint64_t round_to_d(int *pe, mpb_t *a, int e_offset, int rnd_mode)\n{\n    int e;\n    uint64_t m;\n\n    if (a->tab[0] == 0 && a->len == 1) {\n        /* zero result */\n        m = 0;\n        e = 0; /* don't care */\n    } else {\n        int prec, prec1, e_min;\n        e = mpb_floor_log2(a) + 1 - e_offset;\n        prec1 = 53;\n        e_min = -1021;\n        if (e < e_min) {\n            /* subnormal result or zero */\n            prec = prec1 - (e_min - e);\n        } else {\n            prec = prec1;\n        }\n        mpb_shr_round(a, e + e_offset - prec, rnd_mode);\n        m = mpb_get_u64(a);\n        m <<= (53 - prec);\n        /* mantissa overflow due to rounding */\n        if (m >= (uint64_t)1 << 53) {\n            m >>= 1;\n            e++;\n        }\n    }\n    *pe = e;\n    return m;\n}\n\n/* return (m, e) such that m*2^(e-53) = round(a * radix^f) with 2^52\n   <= m < 2^53 or m = 0.\n   'a' is modified. */\nstatic uint64_t mul_pow_round_to_d(int *pe, mpb_t *a,\n                                   int radix1, int radix_shift, int f, int rnd_mode)\n{\n    int e_offset;\n\n    e_offset = mul_pow(a, radix1, radix_shift, f, FALSE, 55);\n    return round_to_d(pe, a, e_offset, rnd_mode);\n}\n\n#ifdef JS_DTOA_DUMP_STATS\nstatic int out_len_count[17];\n\nvoid js_dtoa_dump_stats(void)\n{\n    int i, sum;\n    sum = 0;\n    for(i = 0; i < 17; i++)\n        sum += out_len_count[i];\n    for(i = 0; i < 17; i++) {\n        printf(\"%2d %8d %5.2f%%\\n\",\n               i + 1, out_len_count[i], (double)out_len_count[i] / sum * 100);\n    }\n}\n#endif\n\n/* return a maximum bound of the string length. The bound depends on\n   'd' only if format = JS_DTOA_FORMAT_FRAC or if JS_DTOA_EXP_DISABLED\n   is enabled. */\nint js_dtoa_max_len(double d, int radix, int n_digits, int flags)\n{\n    int fmt = flags & JS_DTOA_FORMAT_MASK;\n    int n, e;\n    uint64_t a;\n\n    if (fmt != JS_DTOA_FORMAT_FRAC) {\n        if (fmt == JS_DTOA_FORMAT_FREE) {\n            n = dtoa_max_digits_table[radix - 2];\n        } else {\n            n = n_digits;\n        }\n        if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_DISABLED) {\n            /* no exponential */\n            a = float64_as_uint64(d);\n            e = (a >> 52) & 0x7ff;\n            if (e == 0x7ff) {\n                /* NaN, Infinity */\n                n = 0;\n            } else {\n                e -= 1023;\n                /* XXX: adjust */\n                n += 10 + abs(mul_log2_radix(e - 1, radix));\n            }\n        } else {\n            /* extra: sign, 1 dot and exponent \"e-1000\" */\n            n += 1 + 1 + 6;\n        }\n    } else {\n        a = float64_as_uint64(d);\n        e = (a >> 52) & 0x7ff;\n        if (e == 0x7ff) {\n            /* NaN, Infinity */\n            n = 0;\n        } else {\n            /* high bound for the integer part */\n            e -= 1023;\n            /* x < 2^(e + 1) */\n            if (e < 0) {\n                n = 1;\n            } else {\n                n = 2 + mul_log2_radix(e - 1, radix);\n            }\n            /* sign, extra digit, 1 dot */\n            n += 1 + 1 + 1 + n_digits;\n        }\n    }\n    return max_int(n, 9); /* also include NaN and [-]Infinity */\n}\n\n#if defined(__SANITIZE_ADDRESS__) && 0\nstatic void *dtoa_malloc(uint64_t **pptr, size_t size)\n{\n    return malloc(size);\n}\nstatic void dtoa_free(void *ptr)\n{\n    free(ptr);\n}\n#else\nstatic void *dtoa_malloc(uint64_t **pptr, size_t size)\n{\n    void *ret;\n    ret = *pptr;\n    *pptr += (size + 7) / 8;\n    return ret;\n}\n\nstatic void dtoa_free(void *ptr)\n{\n}\n#endif\n\n/* return the length */\nint js_dtoa(char *buf, double d, int radix, int n_digits, int flags,\n            JSDTOATempMem *tmp_mem)\n{\n    uint64_t a, m, *mptr = tmp_mem->mem;\n    int e, sgn, l, E, P, i, E_max, radix1, radix_shift;\n    char *q;\n    mpb_t *tmp1, *mant_max;\n    int fmt = flags & JS_DTOA_FORMAT_MASK;\n\n    tmp1 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX);\n    mant_max = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * MANT_LEN_MAX);\n    assert((mptr - tmp_mem->mem) <= sizeof(JSDTOATempMem) / sizeof(mptr[0]));\n\n    radix_shift = ctz32(radix);\n    radix1 = radix >> radix_shift;\n    a = float64_as_uint64(d);\n    sgn = a >> 63;\n    e = (a >> 52) & 0x7ff;\n    m = a & (((uint64_t)1 << 52) - 1);\n    q = buf;\n    if (e == 0x7ff) {\n        if (m == 0) {\n            if (sgn)\n                *q++ = '-';\n            memcpy(q, \"Infinity\", 8);\n            q += 8;\n        } else {\n            memcpy(q, \"NaN\", 3);\n            q += 3;\n        }\n        goto done;\n    } else if (e == 0) {\n        if (m == 0) {\n            tmp1->len = 1;\n            tmp1->tab[0] = 0;\n            E = 1;\n            if (fmt == JS_DTOA_FORMAT_FREE)\n                P = 1;\n            else if (fmt == JS_DTOA_FORMAT_FRAC)\n                P = n_digits + 1;\n            else\n                P = n_digits;\n            /* \"-0\" is displayed as \"0\" if JS_DTOA_MINUS_ZERO is not present */\n            if (sgn && (flags & JS_DTOA_MINUS_ZERO))\n                *q++ = '-';\n            goto output;\n        }\n        /* denormal number: convert to a normal number */\n        l = clz64(m) - 11;\n        e -= l - 1;\n        m <<= l;\n    } else {\n        m |= (uint64_t)1 << 52;\n    }\n    if (sgn)\n        *q++ = '-';\n    /* remove the bias */\n    e -= 1022;\n    /* d = 2^(e-53)*m */\n    //    printf(\"m=0x%016\" PRIx64 \" e=%d\\n\", m, e);\n#ifdef USE_FAST_INT\n    if (fmt == JS_DTOA_FORMAT_FREE &&\n        e >= 1 && e <= 53 &&\n        (m & (((uint64_t)1 << (53 - e)) - 1)) == 0 &&\n        (flags & JS_DTOA_EXP_MASK) != JS_DTOA_EXP_ENABLED) {\n        m >>= 53 - e;\n        /* 'm' is never zero */\n        q += u64toa_radix(q, m, radix);\n        goto done;\n    }\n#endif\n    \n    /* this choice of E implies F=round(x*B^(P-E) is such as: \n       B^(P-1) <= F < 2.B^P. */\n    E = 1 + mul_log2_radix(e - 1, radix);\n    \n    if (fmt == JS_DTOA_FORMAT_FREE) {\n        int P_max, E0, e1, E_found, P_found;\n        uint64_t m1, mant_found, mant, mant_max1;\n        /* P_max is guarranteed to work by construction */\n        P_max = dtoa_max_digits_table[radix - 2];\n        E0 = E;\n        E_found = 0;\n        P_found = 0;\n        mant_found = 0;\n        /* find the minimum number of digits by successive tries */\n        P = P_max; /* P_max is guarateed to work */\n        for(;;) {\n            /* mant_max always fits on 64 bits */\n            mant_max1 = pow_ui(radix, P);\n            /* compute the mantissa in base B */\n            E = E0;\n            for(;;) {\n                /* XXX: add inexact flag */\n                mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDN);\n                mant = mpb_get_u64(tmp1);\n                if (mant < mant_max1)\n                    break;\n                E++; /* at most one iteration is possible */\n            }\n            /* remove useless trailing zero digits */\n            while ((mant % radix) == 0) {\n                mant /= radix;\n                P--;\n            }\n            /* garanteed to work for P = P_max */\n            if (P_found == 0)\n                goto prec_found;\n            /* convert back to base 2 */\n            mpb_set_u64(tmp1, mant);\n            m1 = mul_pow_round_to_d(&e1, tmp1, radix1, radix_shift, E - P, JS_RNDN);\n            //            printf(\"P=%2d: m=0x%016\" PRIx64 \" e=%d m1=0x%016\" PRIx64 \" e1=%d\\n\", P, m, e, m1, e1);\n            /* Note: (m, e) is never zero here, so the exponent for m1\n               = 0 does not matter */\n            if (m1 == m && e1 == e) {\n            prec_found:\n                P_found = P;\n                E_found = E;\n                mant_found = mant;\n                if (P == 1)\n                    break;\n                P--; /* try lower exponent */\n            } else {\n                break;\n            }\n        }\n        P = P_found;\n        E = E_found;\n        mpb_set_u64(tmp1, mant_found);\n#ifdef JS_DTOA_DUMP_STATS\n        if (radix == 10) {\n            out_len_count[P - 1]++;\n        }\n#endif        \n    } else if (fmt == JS_DTOA_FORMAT_FRAC) {\n        int len;\n\n        assert(n_digits >= 0 && n_digits <= JS_DTOA_MAX_DIGITS);\n        /* P = max_int(E, 1) + n_digits; */\n        /* frac is rounded using RNDNA */\n        mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, n_digits, JS_RNDNA);\n\n        /* we add one extra digit on the left and remove it if needed\n           to avoid testing if the result is < radix^P */\n        len = output_digits(q, tmp1, radix, max_int(E + 1, 1) + n_digits,\n                            max_int(E + 1, 1));\n        if (q[0] == '0' && len >= 2 && q[1] != '.') {\n            len--;\n            memmove(q, q + 1, len);\n        }\n        q += len;\n        goto done;\n    } else {\n        int pow_shift;\n        assert(n_digits >= 1 && n_digits <= JS_DTOA_MAX_DIGITS);\n        P = n_digits;\n        /* mant_max = radix^P */\n        mant_max->len = 1;\n        mant_max->tab[0] = 1;\n        pow_shift = mul_pow(mant_max, radix1, radix_shift, P, FALSE, 0);\n        mpb_shr_round(mant_max, pow_shift, JS_RNDZ);\n        \n        for(;;) {\n            /* fixed and frac are rounded using RNDNA */\n            mul_pow_round(tmp1, m, e - 53, radix1, radix_shift, P - E, JS_RNDNA);\n            if (mpb_cmp(tmp1, mant_max) < 0)\n                break;\n            E++; /* at most one iteration is possible */\n        }\n    }\n output:\n    if (fmt == JS_DTOA_FORMAT_FIXED)\n        E_max = n_digits;\n    else\n        E_max = dtoa_max_digits_table[radix - 2] + 4;\n    if ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_ENABLED ||\n        ((flags & JS_DTOA_EXP_MASK) == JS_DTOA_EXP_AUTO && (E <= -6 || E > E_max))) {\n        q += output_digits(q, tmp1, radix, P, 1);\n        E--;\n        if (radix == 10) {\n            *q++ = 'e';\n        } else if (radix1 == 1 && radix_shift <= 4) {\n            E *= radix_shift;\n            *q++ = 'p';\n        } else {\n            *q++ = '@';\n        }\n        if (E < 0) {\n            *q++ = '-';\n            E = -E;\n        } else {\n            *q++ = '+';\n        }\n        q += u32toa(q, E);\n    } else if (E <= 0) {\n        *q++ = '0';\n        *q++ = '.';\n        for(i = 0; i < -E; i++)\n            *q++ = '0';\n        q += output_digits(q, tmp1, radix, P, P);\n    } else {\n        q += output_digits(q, tmp1, radix, P, min_int(P, E));\n        for(i = 0; i < E - P; i++)\n            *q++ = '0';\n    }\n done:\n    *q = '\\0';\n    dtoa_free(mant_max);\n    dtoa_free(tmp1);\n    return q - buf;\n}\n\nstatic inline int to_digit(int c)\n{\n    if (c >= '0' && c <= '9')\n        return c - '0';\n    else if (c >= 'A' && c <= 'Z')\n        return c - 'A' + 10;\n    else if (c >= 'a' && c <= 'z')\n        return c - 'a' + 10;\n    else\n        return 36;\n}\n\n/* r = r * radix_base + a. radix_base = 0 means radix_base = 2^32 */\nstatic void mpb_mul1_base(mpb_t *r, limb_t radix_base, limb_t a)\n{\n    int i;\n    if (r->tab[0] == 0 && r->len == 1) {\n        r->tab[0] = a;\n    } else {\n        if (radix_base == 0) {\n            for(i = r->len; i >= 0; i--) {\n                r->tab[i + 1] = r->tab[i];\n            }\n            r->tab[0] = a;\n        } else {\n            r->tab[r->len] = mp_mul1(r->tab, r->tab, r->len,\n                                     radix_base, a);\n        }\n        r->len++;\n        mpb_renorm(r);\n    }\n}\n\n/* XXX: add fast path for small integers */\ndouble js_atod(const char *str, const char **pnext, int radix, int flags,\n               JSATODTempMem *tmp_mem)\n{\n    uint64_t *mptr = tmp_mem->mem;\n    const char *p, *p_start;\n    limb_t cur_limb, radix_base, extra_digits;\n    int is_neg, digit_count, limb_digit_count, digits_per_limb, sep, radix1, radix_shift;\n    int radix_bits, expn, e, max_digits, expn_offset, dot_pos, sig_pos, pos;\n    mpb_t *tmp0;\n    double dval;\n    BOOL is_bin_exp, is_zero, expn_overflow;\n    uint64_t m, a;\n\n    tmp0 = dtoa_malloc(&mptr, sizeof(mpb_t) + sizeof(limb_t) * DBIGNUM_LEN_MAX);\n    assert((mptr - tmp_mem->mem) <= sizeof(JSATODTempMem) / sizeof(mptr[0]));\n    /* optional separator between digits */\n    sep = (flags & JS_ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;\n\n    p = str;\n    is_neg = 0;\n    if (p[0] == '+') {\n        p++;\n        p_start = p;\n    } else if (p[0] == '-') {\n        is_neg = 1;\n        p++;\n        p_start = p;\n    } else {\n        p_start = p;\n    }\n    \n    if (p[0] == '0') {\n        if ((p[1] == 'x' || p[1] == 'X') &&\n            (radix == 0 || radix == 16)) {\n            p += 2;\n            radix = 16;\n        } else if ((p[1] == 'o' || p[1] == 'O') &&\n                   radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) {\n            p += 2;\n            radix = 8;\n        } else if ((p[1] == 'b' || p[1] == 'B') &&\n                   radix == 0 && (flags & JS_ATOD_ACCEPT_BIN_OCT)) {\n            p += 2;\n            radix = 2;\n        } else if ((p[1] >= '0' && p[1] <= '9') &&\n                   radix == 0 && (flags & JS_ATOD_ACCEPT_LEGACY_OCTAL)) {\n            int i;\n            sep = 256;\n            for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)\n                continue;\n            if (p[i] == '8' || p[i] == '9')\n                goto no_prefix;\n            p += 1;\n            radix = 8;\n        } else {\n            goto no_prefix;\n        }\n        /* there must be a digit after the prefix */\n        if (to_digit((uint8_t)*p) >= radix)\n            goto fail;\n    no_prefix: ;\n    } else {\n        if (!(flags & JS_ATOD_INT_ONLY) && strstart(p, \"Infinity\", &p))\n            goto overflow;\n    }\n    if (radix == 0)\n        radix = 10;\n\n    cur_limb = 0;\n    expn_offset = 0;\n    digit_count = 0;\n    limb_digit_count = 0;\n    max_digits = atod_max_digits_table[radix - 2];\n    digits_per_limb = digits_per_limb_table[radix - 2];\n    radix_base = radix_base_table[radix - 2];\n    radix_shift = ctz32(radix);\n    radix1 = radix >> radix_shift;\n    if (radix1 == 1) {\n        /* radix = 2^radix_bits */\n        radix_bits = radix_shift;\n    } else {\n        radix_bits = 0;\n    }\n    tmp0->len = 1;\n    tmp0->tab[0] = 0;\n    extra_digits = 0;\n    pos = 0;\n    dot_pos = -1;\n    /* skip leading zeros */\n    for(;;) {\n        if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) &&\n            !(flags & JS_ATOD_INT_ONLY)) {\n            if (*p == sep)\n                goto fail;\n            if (dot_pos >= 0)\n                break;\n            dot_pos = pos;\n            p++;\n        }\n        if (*p == sep && p > p_start && p[1] == '0')\n            p++;\n        if (*p != '0')\n            break;\n        p++;\n        pos++;\n    }\n    \n    sig_pos = pos;\n    for(;;) {\n        limb_t c;\n        if (*p == '.' && (p > p_start || to_digit(p[1]) < radix) &&\n            !(flags & JS_ATOD_INT_ONLY)) {\n            if (*p == sep)\n                goto fail;\n            if (dot_pos >= 0)\n                break;\n            dot_pos = pos;\n            p++;\n        }\n        if (*p == sep && p > p_start && to_digit(p[1]) < radix)\n            p++;\n        c = to_digit(*p);\n        if (c >= radix)\n            break;\n        p++;\n        pos++;\n        if (digit_count < max_digits) {\n            /* XXX: could be faster when radix_bits != 0 */\n            cur_limb = cur_limb * radix + c;\n            limb_digit_count++;\n            if (limb_digit_count == digits_per_limb) {\n                mpb_mul1_base(tmp0, radix_base, cur_limb);\n                cur_limb = 0;\n                limb_digit_count = 0;\n            }\n            digit_count++;\n        } else {\n            extra_digits |= c;\n        }\n    }\n    if (limb_digit_count != 0) {\n        mpb_mul1_base(tmp0, pow_ui(radix, limb_digit_count), cur_limb);\n    }\n    if (digit_count == 0) {\n        is_zero = TRUE;\n        expn_offset = 0;\n    } else {\n        is_zero = FALSE;\n        if (dot_pos < 0)\n            dot_pos = pos;\n        expn_offset = sig_pos + digit_count - dot_pos;\n    }\n    \n    /* Use the extra digits for rounding if the base is a power of\n       two. Otherwise they are just truncated. */\n    if (radix_bits != 0 && extra_digits != 0) {\n        tmp0->tab[0] |= 1;\n    }\n    \n    /* parse the exponent, if any */\n    expn = 0;\n    expn_overflow = FALSE;\n    is_bin_exp = FALSE;\n    if (!(flags & JS_ATOD_INT_ONLY) &&\n        ((radix == 10 && (*p == 'e' || *p == 'E')) ||\n         (radix != 10 && (*p == '@' ||\n                          (radix_bits >= 1 && radix_bits <= 4 && (*p == 'p' || *p == 'P'))))) &&\n        p > p_start) {\n        BOOL exp_is_neg;\n        int c;\n        is_bin_exp = (*p == 'p' || *p == 'P');\n        p++;\n        exp_is_neg = 0;\n        if (*p == '+') {\n            p++;\n        } else if (*p == '-') {\n            exp_is_neg = 1;\n            p++;\n        }\n        c = to_digit(*p);\n        if (c >= 10)\n            goto fail; /* XXX: could stop before the exponent part */\n        expn = c;\n        p++;\n        for(;;) {\n            if (*p == sep && to_digit(p[1]) < 10)\n                p++;\n            c = to_digit(*p);\n            if (c >= 10)\n                break;\n            if (!expn_overflow) {\n                if (unlikely(expn > ((INT32_MAX - 2 - 9) / 10))) {\n                    expn_overflow = TRUE;\n                } else {\n                    expn = expn * 10 + c;\n                }\n            }\n            p++;\n        }\n        if (exp_is_neg)\n            expn = -expn;\n        /* if zero result, the exponent can be arbitrarily large */\n        if (!is_zero && expn_overflow) {\n            if (exp_is_neg)\n                a = 0;\n            else\n                a = (uint64_t)0x7ff << 52; /* infinity */\n            goto done;\n        }\n    }\n\n    if (p == p_start)\n        goto fail;\n\n    if (is_zero) {\n        a = 0;\n    } else {\n        int expn1;\n        if (radix_bits != 0) {\n            if (!is_bin_exp)\n                expn *= radix_bits;\n            expn -= expn_offset * radix_bits;\n            expn1 = expn + digit_count * radix_bits;\n            if (expn1 >= 1024 + radix_bits)\n                goto overflow;\n            else if (expn1 <= -1075)\n                goto underflow;\n            m = round_to_d(&e, tmp0, -expn, JS_RNDN);\n        } else {\n            expn -= expn_offset;\n            expn1 = expn + digit_count;\n            if (expn1 >= max_exponent[radix - 2] + 1)\n                goto overflow;\n            else if (expn1 <= min_exponent[radix - 2])\n                goto underflow;\n            m = mul_pow_round_to_d(&e, tmp0, radix1, radix_shift, expn, JS_RNDN);\n        }\n        if (m == 0) {\n        underflow:\n            a = 0;\n        } else if (e > 1024) {\n        overflow:\n            /* overflow */\n            a = (uint64_t)0x7ff << 52;\n        } else if (e < -1073) {\n            /* underflow */\n            /* XXX: check rounding */\n            a = 0;\n        } else if (e < -1021) {\n            /* subnormal */\n            a = m >> (-e - 1021);\n        } else {\n            a = ((uint64_t)(e + 1022) << 52) | (m & (((uint64_t)1 << 52) - 1));\n        }\n    }\n done:\n    a |= (uint64_t)is_neg << 63;\n    dval = uint64_as_float64(a);\n done1:\n    if (pnext)\n        *pnext = p;\n    dtoa_free(tmp0);\n    return dval;\n fail:\n    dval = NAN;\n    goto done1;\n}\n"
  },
  {
    "path": "dtoa.h",
    "content": "/*\n * Tiny float64 printing and parsing library\n *\n * Copyright (c) 2024 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n//#define JS_DTOA_DUMP_STATS\n\n/* maximum number of digits for fixed and frac formats */\n#define JS_DTOA_MAX_DIGITS 101\n\n/* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */\n/* use as many digits as necessary */\n#define JS_DTOA_FORMAT_FREE  (0 << 0)\n/* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */\n#define JS_DTOA_FORMAT_FIXED (1 << 0)\n/* force fractional format: [-]dd.dd with n_digits fractional digits.\n   0 <= n_digits <= JS_DTOA_MAX_DIGITS */\n#define JS_DTOA_FORMAT_FRAC  (2 << 0)\n#define JS_DTOA_FORMAT_MASK  (3 << 0)\n\n/* select exponential notation either in fixed or free format */\n#define JS_DTOA_EXP_AUTO     (0 << 2)\n#define JS_DTOA_EXP_ENABLED  (1 << 2)\n#define JS_DTOA_EXP_DISABLED (2 << 2)\n#define JS_DTOA_EXP_MASK     (3 << 2)\n\n#define JS_DTOA_MINUS_ZERO   (1 << 4) /* show the minus sign for -0 */\n\n/* only accepts integers (no dot, no exponent) */\n#define JS_ATOD_INT_ONLY       (1 << 0)\n/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */\n#define JS_ATOD_ACCEPT_BIN_OCT (1 << 1)\n/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */\n#define JS_ATOD_ACCEPT_LEGACY_OCTAL  (1 << 2)\n/* accept _ between digits as a digit separator */\n#define JS_ATOD_ACCEPT_UNDERSCORES  (1 << 3)\n\ntypedef struct {\n    uint64_t mem[37];\n} JSDTOATempMem;\n\ntypedef struct {\n    uint64_t mem[27];\n} JSATODTempMem;\n\n/* return a maximum bound of the string length */\nint js_dtoa_max_len(double d, int radix, int n_digits, int flags);\n/* return the string length */\nint js_dtoa(char *buf, double d, int radix, int n_digits, int flags,\n            JSDTOATempMem *tmp_mem);\ndouble js_atod(const char *str, const char **pnext, int radix, int flags,\n               JSATODTempMem *tmp_mem);\n\n#ifdef JS_DTOA_DUMP_STATS\nvoid js_dtoa_dump_stats(void);\n#endif\n\n/* additional exported functions */\nsize_t u32toa(char *buf, uint32_t n);\nsize_t i32toa(char *buf, int32_t n);\nsize_t u64toa(char *buf, uint64_t n);\nsize_t i64toa(char *buf, int64_t n);\nsize_t u64toa_radix(char *buf, uint64_t n, unsigned int radix);\nsize_t i64toa_radix(char *buf, int64_t n, unsigned int radix);\n"
  },
  {
    "path": "examples/fib.c",
    "content": "/*\n * QuickJS: Example of C module\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include \"../quickjs.h\"\n\n#define countof(x) (sizeof(x) / sizeof((x)[0]))\n\nstatic int fib(int n)\n{\n    if (n <= 0)\n        return 0;\n    else if (n == 1)\n        return 1;\n    else\n        return fib(n - 1) + fib(n - 2);\n}\n\nstatic JSValue js_fib(JSContext *ctx, JSValueConst this_val,\n                      int argc, JSValueConst *argv)\n{\n    int n, res;\n    if (JS_ToInt32(ctx, &n, argv[0]))\n        return JS_EXCEPTION;\n    res = fib(n);\n    return JS_NewInt32(ctx, res);\n}\n\nstatic const JSCFunctionListEntry js_fib_funcs[] = {\n    JS_CFUNC_DEF(\"fib\", 1, js_fib ),\n};\n\nstatic int js_fib_init(JSContext *ctx, JSModuleDef *m)\n{\n    return JS_SetModuleExportList(ctx, m, js_fib_funcs,\n                                  countof(js_fib_funcs));\n}\n\n#ifdef JS_SHARED_LIBRARY\n#define JS_INIT_MODULE js_init_module\n#else\n#define JS_INIT_MODULE js_init_module_fib\n#endif\n\nJSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)\n{\n    JSModuleDef *m;\n    m = JS_NewCModule(ctx, module_name, js_fib_init);\n    if (!m)\n        return NULL;\n    JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs));\n    return m;\n}\n"
  },
  {
    "path": "examples/fib_module.js",
    "content": "/* fib module */\nexport function fib(n)\n{\n    if (n <= 0)\n        return 0;\n    else if (n == 1)\n        return 1;\n    else\n        return fib(n - 1) + fib(n - 2);\n}\n"
  },
  {
    "path": "examples/hello.js",
    "content": "console.log(\"Hello World\");\n"
  },
  {
    "path": "examples/hello_module.js",
    "content": "/* example of JS and JSON modules */\n\nimport { fib } from \"./fib_module.js\";\nimport msg from \"./message.json\";\n\nconsole.log(\"Hello World\");\nconsole.log(\"fib(10)=\", fib(10));\nconsole.log(\"msg=\", msg);\n"
  },
  {
    "path": "examples/message.json",
    "content": "{ \"x\" : 1, \"tab\": [ 1, 2, 3 ] }\n\n"
  },
  {
    "path": "examples/pi_bigint.js",
    "content": "/*\n * PI computation in Javascript using the BigInt type\n */\n\"use strict\";\n\n/* return floor(log2(a)) for a > 0 and 0 for a = 0 */\nfunction floor_log2(a)\n{\n    var k_max, a1, k, i;\n    k_max = 0n;\n    while ((a >> (2n ** k_max)) != 0n) {\n        k_max++;\n    }\n    k = 0n;\n    a1 = a;\n    for(i = k_max - 1n; i >= 0n; i--) {\n        a1 = a >> (2n ** i);\n        if (a1 != 0n) {\n            a = a1;\n            k |= (1n << i);\n        }\n    }\n    return k;\n}\n\n/* return ceil(log2(a)) for a > 0 */\nfunction ceil_log2(a)\n{\n    return floor_log2(a - 1n) + 1n;\n}\n\n/* return floor(sqrt(a)) (not efficient but simple) */\nfunction int_sqrt(a)\n{\n    var l, u, s;\n    if (a == 0n)\n        return a;\n    l = ceil_log2(a);\n    u = 1n << ((l + 1n) / 2n);\n    /* u >= floor(sqrt(a)) */\n    for(;;) {\n        s = u;\n        u = ((a / s) + s) / 2n;\n        if (u >= s)\n            break;\n    }\n    return s;\n}\n\n/* return pi * 2**prec */\nfunction calc_pi(prec) {\n    const CHUD_A = 13591409n;\n    const CHUD_B = 545140134n;\n    const CHUD_C = 640320n;\n    const CHUD_C3 = 10939058860032000n; /* C^3/24 */\n    const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */\n\n    /* return [P, Q, G] */\n    function chud_bs(a, b, need_G) {\n        var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;\n        if (a == (b - 1n)) {\n            G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);\n            P = G * (CHUD_B * b + CHUD_A);\n            if (b & 1n)\n                P = -P;\n            Q = b * b * b * CHUD_C3;\n        } else {\n            c = (a + b) >> 1n;\n            [P1, Q1, G1] = chud_bs(a, c, true);\n            [P2, Q2, G2] = chud_bs(c, b, need_G);\n            P = P1 * Q2 + P2 * G1;\n            Q = Q1 * Q2;\n            if (need_G)\n                G = G1 * G2;\n            else\n                G = 0n;\n        }\n        return [P, Q, G];\n    }\n\n    var n, P, Q, G;\n    /* number of serie terms */\n    n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;\n    [P, Q, G] = chud_bs(0n, n, false);\n    Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);\n    G = int_sqrt(CHUD_C << (2n * prec));\n    return (Q * G) >> prec;\n}\n\nfunction main(args) {\n    var r, n_digits, n_bits, out;\n    if (args.length < 1) {\n        print(\"usage: pi n_digits\");\n        return;\n    }\n    n_digits = args[0] | 0;\n\n    /* we add more bits to reduce the probability of bad rounding for\n      the last digits */\n    n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;\n    r = calc_pi(n_bits);\n    r = ((10n ** BigInt(n_digits)) * r) >> n_bits;\n    out = r.toString();\n    print(out[0] + \".\" + out.slice(1));\n}\n\nvar args;\nif (typeof scriptArgs != \"undefined\") {\n    args = scriptArgs;\n    args.shift();\n} else if (typeof arguments != \"undefined\") {\n    args = arguments;\n} else {\n    /* default: 1000 digits */\n    args=[1000];\n}\n\nmain(args);\n"
  },
  {
    "path": "examples/point.c",
    "content": "/*\n * QuickJS: Example of C module with a class\n *\n * Copyright (c) 2019 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include \"../quickjs.h\"\n#include <math.h>\n\n#define countof(x) (sizeof(x) / sizeof((x)[0]))\n\n/* Point Class */\n\ntypedef struct {\n    int x;\n    int y;\n} JSPointData;\n\nstatic JSClassID js_point_class_id;\n\nstatic void js_point_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSPointData *s = JS_GetOpaque(val, js_point_class_id);\n    /* Note: 's' can be NULL in case JS_SetOpaque() was not called */\n    js_free_rt(rt, s);\n}\n\nstatic JSValue js_point_ctor(JSContext *ctx,\n                             JSValueConst new_target,\n                             int argc, JSValueConst *argv)\n{\n    JSPointData *s;\n    JSValue obj = JS_UNDEFINED;\n    JSValue proto;\n\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s)\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &s->x, argv[0]))\n        goto fail;\n    if (JS_ToInt32(ctx, &s->y, argv[1]))\n        goto fail;\n    /* using new_target to get the prototype is necessary when the\n       class is extended. */\n    proto = JS_GetPropertyStr(ctx, new_target, \"prototype\");\n    if (JS_IsException(proto))\n        goto fail;\n    obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);\n    JS_FreeValue(ctx, proto);\n    if (JS_IsException(obj))\n        goto fail;\n    JS_SetOpaque(obj, s);\n    return obj;\n fail:\n    js_free(ctx, s);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)\n{\n    JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);\n    if (!s)\n        return JS_EXCEPTION;\n    if (magic == 0)\n        return JS_NewInt32(ctx, s->x);\n    else\n        return JS_NewInt32(ctx, s->y);\n}\n\nstatic JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic)\n{\n    JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);\n    int v;\n    if (!s)\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &v, val))\n        return JS_EXCEPTION;\n    if (magic == 0)\n        s->x = v;\n    else\n        s->y = v;\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_point_norm(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);\n    if (!s)\n        return JS_EXCEPTION;\n    return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));\n}\n\nstatic JSClassDef js_point_class = {\n    \"Point\",\n    .finalizer = js_point_finalizer,\n};\n\nstatic const JSCFunctionListEntry js_point_proto_funcs[] = {\n    JS_CGETSET_MAGIC_DEF(\"x\", js_point_get_xy, js_point_set_xy, 0),\n    JS_CGETSET_MAGIC_DEF(\"y\", js_point_get_xy, js_point_set_xy, 1),\n    JS_CFUNC_DEF(\"norm\", 0, js_point_norm),\n};\n\nstatic int js_point_init(JSContext *ctx, JSModuleDef *m)\n{\n    JSValue point_proto, point_class;\n\n    /* create the Point class */\n    JS_NewClassID(&js_point_class_id);\n    JS_NewClass(JS_GetRuntime(ctx), js_point_class_id, &js_point_class);\n\n    point_proto = JS_NewObject(ctx);\n    JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));\n\n    point_class = JS_NewCFunction2(ctx, js_point_ctor, \"Point\", 2, JS_CFUNC_constructor, 0);\n    /* set proto.constructor and ctor.prototype */\n    JS_SetConstructor(ctx, point_class, point_proto);\n    JS_SetClassProto(ctx, js_point_class_id, point_proto);\n\n    JS_SetModuleExport(ctx, m, \"Point\", point_class);\n    return 0;\n}\n\nJSModuleDef *js_init_module(JSContext *ctx, const char *module_name)\n{\n    JSModuleDef *m;\n    m = JS_NewCModule(ctx, module_name, js_point_init);\n    if (!m)\n        return NULL;\n    JS_AddModuleExport(ctx, m, \"Point\");\n    return m;\n}\n"
  },
  {
    "path": "examples/test_fib.js",
    "content": "/* example of JS module importing a C module */\n\nimport { fib } from \"./fib.so\";\n\nconsole.log(\"Hello World\");\nconsole.log(\"fib(10)=\", fib(10));\n"
  },
  {
    "path": "examples/test_point.js",
    "content": "/* example of JS module importing a C module */\nimport { Point } from \"./point.so\";\n\nfunction assert(b, str)\n{\n    if (b) {\n        return;\n    } else {\n        throw Error(\"assertion failed: \" + str);\n    }\n}\n\nclass ColorPoint extends Point {\n    constructor(x, y, color) {\n        super(x, y);\n        this.color = color;\n    }\n    get_color() {\n        return this.color;\n    }\n};\n\nfunction main()\n{\n    var pt, pt2;\n\n    pt = new Point(2, 3);\n    assert(pt.x === 2);\n    assert(pt.y === 3);\n    pt.x = 4;\n    assert(pt.x === 4);\n    assert(pt.norm() == 5);\n\n    pt2 = new ColorPoint(2, 3, 0xffffff);\n    assert(pt2.x === 2);\n    assert(pt2.color === 0xffffff);\n    assert(pt2.get_color() === 0xffffff);\n}\n\nmain();\n"
  },
  {
    "path": "fuzz/README",
    "content": "libFuzzer support for QuickJS\n=============================\n\nBuild QuickJS with libFuzzer support as follows:\n\n  CONFIG_CLANG=y make libfuzzer\n\nThis can be extended with sanitizer support to improve efficacy:\n\n  CONFIG_CLANG=y CONFIG_ASAN=y make libfuzzer\n\n\nCurrently, there are three fuzzing targets defined: fuzz_eval, fuzz_compile and fuzz_regexp.\nThe above build command will produce an executable binary for each of them, which can be\nsimply executed as:\n\n  ./fuzz_eval\n\nor with an initial corpus:\n\n  ./fuzz_compile corpus_dir/\n\nor with a predefined dictionary to improve its efficacy:\n\n  ./fuzz_eval -dict fuzz/fuzz.dict\n\nor with arbitrary CLI arguments provided by libFuzzer (https://llvm.org/docs/LibFuzzer.html).\n"
  },
  {
    "path": "fuzz/fuzz.dict",
    "content": "\"__loadScript\"\n\"abs\"\n\"acos\"\n\"acosh\"\n\"add\"\n\"AggregateError\"\n\"and\"\n\"apply\"\n\"Array\"\n\"ArrayBuffer\"\n\"asin\"\n\"asinh\"\n\"atan\"\n\"atan2\"\n\"atanh\"\n\"Atomics\"\n\"BigInt\"\n\"BigInt64Array\"\n\"BigUint64Array\"\n\"Boolean\"\n\"cbrt\"\n\"ceil\"\n\"chdir\"\n\"clearTimeout\"\n\"close\"\n\"clz32\"\n\"compareExchange\"\n\"console\"\n\"construct\"\n\"cos\"\n\"cosh\"\n\"DataView\"\n\"Date\"\n\"decodeURI\"\n\"decodeURIComponent\"\n\"defineProperty\"\n\"deleteProperty\"\n\"dup\"\n\"dup2\"\n\"E\"\n\"encodeURI\"\n\"encodeURIComponent\"\n\"err\"\n\"Error\"\n\"escape\"\n\"eval\"\n\"EvalError\"\n\"evalScript\"\n\"exchange\"\n\"exec\"\n\"exit\"\n\"exp\"\n\"expm1\"\n\"fdopen\"\n\"Float32Array\"\n\"Float64Array\"\n\"floor\"\n\"fround\"\n\"Function\"\n\"gc\"\n\"get\"\n\"getcwd\"\n\"getenv\"\n\"getenviron\"\n\"getOwnPropertyDescriptor\"\n\"getpid\"\n\"getPrototypeOf\"\n\"globalThis\"\n\"has\"\n\"hypot\"\n\"imul\"\n\"in\"\n\"Infinity\"\n\"Int16Array\"\n\"Int32Array\"\n\"Int8Array\"\n\"InternalError\"\n\"isatty\"\n\"isExtensible\"\n\"isFinite\"\n\"isLockFree\"\n\"isNaN\"\n\"iterateBuiltIns\"\n\"JSON\"\n\"kill\"\n\"length\"\n\"LN10\"\n\"LN2\"\n\"load\"\n\"loadFile\"\n\"loadScript\"\n\"log\"\n\"log10\"\n\"LOG10E\"\n\"log1p\"\n\"log2\"\n\"LOG2E\"\n\"lstat\"\n\"Map\"\n\"Math\"\n\"max\"\n\"min\"\n\"mkdir\"\n\"NaN\"\n\"notify\"\n\"now\"\n\"Number\"\n\"O_APPEND\"\n\"O_CREAT\"\n\"O_EXCL\"\n\"O_RDONLY\"\n\"O_RDWR\"\n\"O_TRUNC\"\n\"O_WRONLY\"\n\"Object\"\n\"open\"\n\"Operators\"\n\"or\"\n\"os\"\n\"out\"\n\"ownKeys\"\n\"parse\"\n\"parseExtJSON\"\n\"parseFloat\"\n\"parseInt\"\n\"PI\"\n\"pipe\"\n\"platform\"\n\"popen\"\n\"pow\"\n\"preventExtensions\"\n\"print\"\n\"printf\"\n\"Promise\"\n\"Proxy\"\n\"puts\"\n\"random\"\n\"RangeError\"\n\"read\"\n\"readdir\"\n\"readlink\"\n\"realpath\"\n\"ReferenceError\"\n\"Reflect\"\n\"RegExp\"\n\"remove\"\n\"rename\"\n\"round\"\n\"S_IFBLK\"\n\"S_IFCHR\"\n\"S_IFDIR\"\n\"S_IFIFO\"\n\"S_IFLNK\"\n\"S_IFMT\"\n\"S_IFREG\"\n\"S_IFSOCK\"\n\"S_ISGID\"\n\"S_ISUID\"\n\"scriptArgs\"\n\"seek\"\n\"SEEK_CUR\"\n\"SEEK_END\"\n\"SEEK_SET\"\n\"set\"\n\"Set\"\n\"setenv\"\n\"setPrototypeOf\"\n\"setReadHandler\"\n\"setTimeout\"\n\"setWriteHandler\"\n\"SharedArrayBuffer\"\n\"SIGABRT\"\n\"SIGALRM\"\n\"SIGCHLD\"\n\"SIGCONT\"\n\"SIGFPE\"\n\"SIGILL\"\n\"SIGINT\"\n\"sign\"\n\"signal\"\n\"SIGPIPE\"\n\"SIGQUIT\"\n\"SIGSEGV\"\n\"SIGSTOP\"\n\"SIGTERM\"\n\"SIGTSTP\"\n\"SIGTTIN\"\n\"SIGTTOU\"\n\"SIGUSR1\"\n\"SIGUSR2\"\n\"sin\"\n\"sinh\"\n\"sleep\"\n\"sleepAsync\"\n\"sprintf\"\n\"sqrt\"\n\"SQRT1_2\"\n\"SQRT2\"\n\"stat\"\n\"std\"\n\"store\"\n\"strerror\"\n\"String\"\n\"stringify\"\n\"sub\"\n\"Symbol\"\n\"symlink\"\n\"SyntaxError\"\n\"tan\"\n\"tanh\"\n\"tmpfile\"\n\"trunc\"\n\"ttyGetWinSize\"\n\"ttySetRaw\"\n\"TypeError\"\n\"Uint16Array\"\n\"Uint32Array\"\n\"Uint8Array\"\n\"Uint8ClampedArray\"\n\"undefined\"\n\"unescape\"\n\"unsetenv\"\n\"URIError\"\n\"urlGet\"\n\"utimes\"\n\"wait\"\n\"waitpid\"\n\"WeakMap\"\n\"WeakSet\"\n\"WNOHANG\"\n\"Worker\"\n\"write\"\n\"xor\"\n\"v0\"\n\"v1\"\n\"v2\"\n\"v3\"\n\"v4\"\n\"v5\"\n\"v6\"\n\"v7\"\n\"v8\"\n\"v9\"\n\"v10\"\n\"v11\"\n\"v12\"\n\"v13\"\n\"v14\"\n\"v15\"\n\"v16\"\n\"v17\"\n\"v18\"\n\"v19\"\n\"v20\"\n"
  },
  {
    "path": "fuzz/fuzz_common.c",
    "content": "/* Copyright 2020 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n */\n\n#include <string.h>\n\n#include \"fuzz/fuzz_common.h\"\n\n// handle timeouts from infinite loops\nstatic int interrupt_handler(JSRuntime *rt, void *opaque)\n{\n    nbinterrupts++;\n    return (nbinterrupts > 100);\n}\n\nvoid reset_nbinterrupts() {\n    nbinterrupts = 0;\n}\n\nvoid test_one_input_init(JSRuntime *rt, JSContext *ctx) {\n    // 64 Mo\n    JS_SetMemoryLimit(rt, 0x4000000);\n    // 64 Kb\n    JS_SetMaxStackSize(rt, 0x10000);\n\n    JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n    JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);\n    js_std_add_helpers(ctx, 0, NULL);\n\n    // Load os and std\n    js_std_init_handlers(rt);\n    js_init_module_std(ctx, \"std\");\n    js_init_module_os(ctx, \"os\");\n    const char *str = \"import * as std from 'std';\\n\"\n                \"import * as os from 'os';\\n\"\n                \"globalThis.std = std;\\n\"\n                \"globalThis.os = os;\\n\";\n    JSValue std_val = JS_Eval(ctx, str, strlen(str), \"<input>\", JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);\n    if (!JS_IsException(std_val)) {\n        js_module_set_import_meta(ctx, std_val, 1, 1);\n        std_val = JS_EvalFunction(ctx, std_val);\n    } else {\n        js_std_dump_error(ctx);\n    }\n    std_val = js_std_await(ctx, std_val);\n    JS_FreeValue(ctx, std_val);\n}\n"
  },
  {
    "path": "fuzz/fuzz_common.h",
    "content": "/* Copyright 2020 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n */\n\n#include \"quickjs.h\"\n#include \"quickjs-libc.h\"\n\nstatic int nbinterrupts = 0;\n\nvoid reset_nbinterrupts();\nvoid test_one_input_init(JSRuntime *rt, JSContext *ctx);\n"
  },
  {
    "path": "fuzz/fuzz_compile.c",
    "content": "/* Copyright 2020 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n */\n\n#include \"quickjs.h\"\n#include \"quickjs-libc.h\"\n#include \"cutils.h\"\n#include \"fuzz/fuzz_common.h\"\n\n#include <stdint.h>\n#include <stdio.h>\n\n\nint LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    if (size == 0)\n        return 0;\n\n    JSRuntime *rt = JS_NewRuntime();\n    JSContext *ctx = JS_NewContext(rt);\n    test_one_input_init(rt, ctx);\n\n    uint8_t *null_terminated_data = malloc(size + 1);\n    memcpy(null_terminated_data, data, size);\n    null_terminated_data[size] = 0;\n\n    JSValue obj = JS_Eval(ctx, (const char *)null_terminated_data, size, \"<none>\", JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_MODULE);\n    free(null_terminated_data);\n    //TODO target with JS_ParseJSON\n    if (JS_IsException(obj)) {\n        js_std_free_handlers(rt);\n        JS_FreeValue(ctx, obj);\n        JS_FreeContext(ctx);\n        JS_FreeRuntime(rt);\n        return 0;\n    }\n    obj = js_std_await(ctx, obj);\n    size_t bytecode_size;\n    uint8_t* bytecode = JS_WriteObject(ctx, &bytecode_size, obj, JS_WRITE_OBJ_BYTECODE);\n    JS_FreeValue(ctx, obj);\n    if (!bytecode) {\n        js_std_free_handlers(rt);\n        JS_FreeContext(ctx);\n        JS_FreeRuntime(rt);\n        return 0;\n    }\n    obj = JS_ReadObject(ctx, bytecode, bytecode_size, JS_READ_OBJ_BYTECODE);\n    js_free(ctx, bytecode);\n    if (JS_IsException(obj)) {\n        js_std_free_handlers(rt);\n        JS_FreeContext(ctx);\n        JS_FreeRuntime(rt);\n        return 0;\n    }\n    reset_nbinterrupts();\n    /* this is based on\n     * js_std_eval_binary(ctx, bytecode, bytecode_size, 0);\n     * modified so as not to exit on JS exception\n     */\n    JSValue val;\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {\n        if (JS_ResolveModule(ctx, obj) < 0) {\n            JS_FreeValue(ctx, obj);\n            js_std_free_handlers(rt);\n            JS_FreeContext(ctx);\n            JS_FreeRuntime(rt);\n            return 0;\n        }\n        js_module_set_import_meta(ctx, obj, FALSE, TRUE);\n    }\n    val = JS_EvalFunction(ctx, obj);\n    if (JS_IsException(val)) {\n        js_std_dump_error(ctx);\n    } else {\n        js_std_loop(ctx);\n    }\n    JS_FreeValue(ctx, val);\n    js_std_free_handlers(rt);\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n\n    return 0;\n}\n"
  },
  {
    "path": "fuzz/fuzz_eval.c",
    "content": "/* Copyright 2020 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n */\n\n#include \"quickjs.h\"\n#include \"quickjs-libc.h\"\n#include \"fuzz/fuzz_common.h\"\n\n#include <stdint.h>\n#include <stdio.h>\n#include <string.h>\n\nint LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    if (size == 0)\n        return 0;\n\n    JSRuntime *rt = JS_NewRuntime();\n    JSContext *ctx = JS_NewContext(rt);\n    test_one_input_init(rt, ctx);\n\n    uint8_t *null_terminated_data = malloc(size + 1);\n    memcpy(null_terminated_data, data, size);\n    null_terminated_data[size] = 0;\n\n    reset_nbinterrupts();\n    //the final 0 does not count (as in strlen)\n    JSValue val = JS_Eval(ctx, (const char *)null_terminated_data, size, \"<none>\", JS_EVAL_TYPE_GLOBAL);\n    free(null_terminated_data);\n    //TODO targets with JS_ParseJSON, JS_ReadObject\n    if (!JS_IsException(val)) {\n        js_std_loop(ctx);\n        JS_FreeValue(ctx, val);\n    }\n    js_std_free_handlers(rt);\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n    return 0;\n}\n"
  },
  {
    "path": "fuzz/fuzz_regexp.c",
    "content": "/* Copyright 2020 Google Inc.\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n */\n\n#include \"libregexp.h\"\n#include \"quickjs-libc.h\"\n\nstatic int nbinterrupts = 0;\n\nint lre_check_stack_overflow(void *opaque, size_t alloca_size) { return 0; }\n\nvoid *lre_realloc(void *opaque, void *ptr, size_t size)\n{\n    return realloc(ptr, size);\n}\n\nint lre_check_timeout(void *opaque)\n {\n    nbinterrupts++;\n    return (nbinterrupts > 100);\n }\n\nint LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {\n    int len, ret, i;\n    uint8_t *bc;\n    char error_msg[64];\n    const uint8_t *input;\n    uint8_t *capture[255 * 2];\n    size_t size1 = size;\n\n    //Splits buffer into 2 sub buffers delimited by null character\n    for (i = 0; i < size; i++) {\n        if (data[i] == 0) {\n            size1 = i;\n            break;\n        }\n    }\n    if (size1 == size) {\n        //missing delimiter\n        return 0;\n    }\n    bc = lre_compile(&len, error_msg, sizeof(error_msg), (const char *) data,\n                     size1, 0, NULL);\n    if (!bc) {\n        return 0;\n    }\n    input = data + size1 + 1;\n    ret = lre_exec(capture, bc, input, 0, size - (size1 + 1), 0, NULL);\n    if (ret == 1) {\n        lre_get_capture_count(bc);\n    }\n    free(bc);\n\n    return 0;\n}\n"
  },
  {
    "path": "fuzz/generate_dict.js",
    "content": "// Function to recursively iterate through built-in names.\nfunction collectBuiltinNames(obj, visited = new Set(), result = new Set()) {\n  // Check if the object has already been visited to avoid infinite recursion.\n  if (visited.has(obj))\n    return;\n\n  // Add the current object to the set of visited objects\n  visited.add(obj);\n  // Get the property names of the current object\n  const properties = Object.getOwnPropertyNames(obj);\n  // Iterate through each property\n  for (var i=0; i < properties.length; i++) {\n    var property = properties[i];\n    if (property != \"collectBuiltinNames\" && typeof property != \"number\")\n      result.add(property);\n    // Check if the property is an object and if so, recursively iterate through its properties.\n    if (typeof obj[property] === 'object' && obj[property] !== null)\n      collectBuiltinNames(obj[property], visited, result);\n  }\n  return result;\n}\n\n// Start the recursive iteration with the global object.\nconsole.log(Array.from(collectBuiltinNames(this)).join('\\n'));\n"
  },
  {
    "path": "libregexp-opcode.h",
    "content": "/*\n * Regular Expression Engine\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifdef DEF\n\nDEF(invalid, 1) /* never used */\nDEF(char, 3)\nDEF(char_i, 3)\nDEF(char32, 5)\nDEF(char32_i, 5)\nDEF(dot, 1)\nDEF(any, 1) /* same as dot but match any character including line terminator */\nDEF(space, 1)\nDEF(not_space, 1) /* must come after */\nDEF(line_start, 1)\nDEF(line_start_m, 1)\nDEF(line_end, 1)\nDEF(line_end_m, 1)\nDEF(goto, 5)\nDEF(split_goto_first, 5)\nDEF(split_next_first, 5)\nDEF(match, 1)\nDEF(lookahead_match, 1)\nDEF(negative_lookahead_match, 1) /* must come after */\nDEF(save_start, 2) /* save start position */\nDEF(save_end, 2) /* save end position, must come after saved_start */\nDEF(save_reset, 3) /* reset save positions */\nDEF(loop, 6) /* decrement the top the stack and goto if != 0 */\nDEF(loop_split_goto_first, 10) /* loop and then split */\nDEF(loop_split_next_first, 10)\nDEF(loop_check_adv_split_goto_first, 10) /* loop and then check advance and split */\nDEF(loop_check_adv_split_next_first, 10)\nDEF(set_i32, 6) /* store the immediate value to a register */\nDEF(word_boundary, 1)\nDEF(word_boundary_i, 1)\nDEF(not_word_boundary, 1)\nDEF(not_word_boundary_i, 1)\nDEF(back_reference, 2) /* variable length */\nDEF(back_reference_i, 2) /* must come after */\nDEF(backward_back_reference, 2) /* must come after */\nDEF(backward_back_reference_i, 2) /* must come after */\nDEF(range, 3) /* variable length */\nDEF(range_i, 3) /* variable length */\nDEF(range32, 3) /* variable length */\nDEF(range32_i, 3) /* variable length */\nDEF(lookahead, 5)\nDEF(negative_lookahead, 5) /* must come after */\nDEF(set_char_pos, 2) /* store the character position to a register */\nDEF(check_advance, 2) /* check that the register is different from the character position */\nDEF(prev, 1) /* go to the previous char */\n\n#endif /* DEF */\n"
  },
  {
    "path": "libregexp.c",
    "content": "/*\n * Regular Expression Engine\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"cutils.h\"\n#include \"libregexp.h\"\n#include \"libunicode.h\"\n\n/*\n  TODO:\n  - remove REOP_char_i and REOP_range_i by precomputing the case folding.\n  - add specific opcodes for simple unicode property tests so that the\n    generated bytecode is smaller.\n  - Add a lock step execution mode (=linear time execution guaranteed)\n    when the regular expression is \"simple\" i.e. no backreference nor\n    complicated lookahead. The opcodes are designed for this execution\n    model.\n*/\n\n#if defined(TEST) \n#define DUMP_REOP\n#endif\n//#define DUMP_REOP\n//#define DUMP_EXEC\n\ntypedef enum {\n#define DEF(id, size) REOP_ ## id,\n#include \"libregexp-opcode.h\"\n#undef DEF\n    REOP_COUNT,\n} REOPCodeEnum;\n\n#define CAPTURE_COUNT_MAX 255\n#define REGISTER_COUNT_MAX 255\n/* must be large enough to have a negligible runtime cost and small\n   enough to call the interrupt callback often. */\n#define INTERRUPT_COUNTER_INIT 10000\n\n/* unicode code points */\n#define CP_LS   0x2028\n#define CP_PS   0x2029\n\n#define TMP_BUF_SIZE 128\n\ntypedef struct {\n    DynBuf byte_code;\n    const uint8_t *buf_ptr;\n    const uint8_t *buf_end;\n    const uint8_t *buf_start;\n    int re_flags;\n    BOOL is_unicode;\n    BOOL unicode_sets; /* if set, is_unicode is also set */\n    BOOL ignore_case;\n    BOOL multi_line;\n    BOOL dotall;\n    uint8_t group_name_scope;\n    int capture_count;\n    int total_capture_count; /* -1 = not computed yet */\n    int has_named_captures; /* -1 = don't know, 0 = no, 1 = yes */\n    void *opaque;\n    DynBuf group_names;\n    union {\n        char error_msg[TMP_BUF_SIZE];\n        char tmp_buf[TMP_BUF_SIZE];\n    } u;\n} REParseState;\n\ntypedef struct {\n#ifdef DUMP_REOP\n    const char *name;\n#endif\n    uint8_t size;\n} REOpCode;\n\nstatic const REOpCode reopcode_info[REOP_COUNT] = {\n#ifdef DUMP_REOP\n#define DEF(id, size) { #id, size },\n#else\n#define DEF(id, size) { size },\n#endif\n#include \"libregexp-opcode.h\"\n#undef DEF\n};\n\n#define RE_HEADER_FLAGS          0\n#define RE_HEADER_CAPTURE_COUNT  2\n#define RE_HEADER_REGISTER_COUNT 3\n#define RE_HEADER_BYTECODE_LEN   4\n\n#define RE_HEADER_LEN 8\n\nstatic inline int is_digit(int c) {\n    return c >= '0' && c <= '9';\n}\n\n/* insert 'len' bytes at position 'pos'. Return < 0 if error. */\nstatic int dbuf_insert(DynBuf *s, int pos, int len)\n{\n    if (dbuf_claim(s, len))\n        return -1;\n    memmove(s->buf + pos + len, s->buf + pos, s->size - pos);\n    s->size += len;\n    return 0;\n}\n\ntypedef struct REString {\n    struct REString *next;\n    uint32_t hash;\n    uint32_t len;\n    uint32_t buf[];\n} REString;\n\ntypedef struct {\n    /* the string list is the union of 'char_range' and of the strings\n       in hash_table[]. The strings in hash_table[] have a length !=\n       1. */\n    CharRange cr;\n    uint32_t n_strings;\n    uint32_t hash_size;\n    int hash_bits;\n    REString **hash_table;\n} REStringList;\n\nstatic uint32_t re_string_hash(int len, const uint32_t *buf)\n{\n    int i;\n    uint32_t h;\n    h = 1;\n    for(i = 0; i < len; i++)\n        h = h * 263 + buf[i];\n    return h * 0x61C88647;\n}\n\nstatic void re_string_list_init(REParseState *s1, REStringList *s)\n{\n    cr_init(&s->cr, s1->opaque, lre_realloc);\n    s->n_strings = 0;\n    s->hash_size = 0;\n    s->hash_bits = 0;\n    s->hash_table = NULL;\n}\n\nstatic void re_string_list_free(REStringList *s)\n{\n    REString *p, *p_next;\n    int i;\n    for(i = 0; i < s->hash_size; i++) {\n        for(p = s->hash_table[i]; p != NULL; p = p_next) {\n            p_next = p->next;\n            lre_realloc(s->cr.mem_opaque, p, 0);\n        }\n    }\n    lre_realloc(s->cr.mem_opaque, s->hash_table, 0);\n\n    cr_free(&s->cr);\n}\n\nstatic void lre_print_char(int c, BOOL is_range)\n{\n    if (c == '\\'' || c == '\\\\' ||\n        (is_range && (c == '-' || c == ']'))) {\n        printf(\"\\\\%c\", c);\n    } else if (c >= ' ' && c <= 126) {\n        printf(\"%c\", c);\n    } else {\n        printf(\"\\\\u{%04x}\", c);\n    }\n}\n\nstatic __maybe_unused void re_string_list_dump(const char *str, const REStringList *s)\n{\n    REString *p;\n    const CharRange *cr;\n    int i, j, k;\n\n    printf(\"%s:\\n\", str);\n    printf(\"  ranges: [\");\n    cr = &s->cr;\n    for(i = 0; i < cr->len; i += 2) {\n        lre_print_char(cr->points[i], TRUE);\n        if (cr->points[i] != cr->points[i + 1] - 1) {\n            printf(\"-\");\n            lre_print_char(cr->points[i + 1] - 1, TRUE);\n        }\n    }\n    printf(\"]\\n\");\n    \n    j = 0;\n    for(i = 0; i < s->hash_size; i++) {\n        for(p = s->hash_table[i]; p != NULL; p = p->next) {\n            printf(\"  %d/%d: '\", j, s->n_strings);\n            for(k = 0; k < p->len; k++) {\n                lre_print_char(p->buf[k], FALSE);\n            }\n            printf(\"'\\n\");\n            j++;\n        }\n    }\n}\n\nstatic int re_string_find2(REStringList *s, int len, const uint32_t *buf,\n                           uint32_t h0, BOOL add_flag)\n{\n    uint32_t h = 0; /* avoid warning */\n    REString *p;\n    if (s->n_strings != 0) {\n        h = h0 >> (32 - s->hash_bits);\n        for(p = s->hash_table[h]; p != NULL; p = p->next) {\n            if (p->hash == h0 && p->len == len &&\n                !memcmp(p->buf, buf, len * sizeof(buf[0]))) {\n                return 1;\n            }\n        }\n    }\n    /* not found */\n    if (!add_flag)\n        return 0;\n    /* increase the size of the hash table if needed */\n    if (unlikely((s->n_strings + 1) > s->hash_size)) {\n        REString **new_hash_table, *p_next;\n        int new_hash_bits, i;\n        uint32_t new_hash_size;\n        new_hash_bits = max_int(s->hash_bits + 1, 4);\n        new_hash_size = 1 << new_hash_bits;\n        new_hash_table = lre_realloc(s->cr.mem_opaque, NULL,\n                                     sizeof(new_hash_table[0]) * new_hash_size);\n        if (!new_hash_table)\n            return -1;\n        memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);\n        for(i = 0; i < s->hash_size; i++) {\n            for(p = s->hash_table[i]; p != NULL; p = p_next) {\n                p_next = p->next;\n                h = p->hash >> (32 - new_hash_bits);\n                p->next = new_hash_table[h];\n                new_hash_table[h] = p;\n            }\n        }\n        lre_realloc(s->cr.mem_opaque, s->hash_table, 0);\n        s->hash_bits = new_hash_bits;\n        s->hash_size = new_hash_size;\n        s->hash_table = new_hash_table;\n        h = h0 >> (32 - s->hash_bits);\n    }\n\n    p = lre_realloc(s->cr.mem_opaque, NULL, sizeof(REString) + len * sizeof(buf[0]));\n    if (!p)\n        return -1;\n    p->next = s->hash_table[h];\n    s->hash_table[h] = p;\n    s->n_strings++;\n    p->hash = h0;\n    p->len = len;\n    memcpy(p->buf, buf, sizeof(buf[0]) * len);\n    return 1;\n}\n\nstatic int re_string_find(REStringList *s, int len, const uint32_t *buf,\n                          BOOL add_flag)\n{\n    uint32_t h0;\n    h0 = re_string_hash(len, buf);\n    return re_string_find2(s, len, buf, h0, add_flag);\n}\n\n/* return -1 if memory error, 0 if OK */\nstatic int re_string_add(REStringList *s, int len, const uint32_t *buf)\n{\n    if (len == 1) {\n        return cr_union_interval(&s->cr, buf[0], buf[0]);\n    }\n    if (re_string_find(s, len, buf, TRUE) < 0)\n        return -1;\n    return 0;\n}\n\n/* a = a op b */\nstatic int re_string_list_op(REStringList *a, REStringList *b, int op)\n{\n    int i, ret;\n    REString *p, **pp;\n\n    if (cr_op1(&a->cr, b->cr.points, b->cr.len, op))\n        return -1;\n\n    switch(op) {\n    case CR_OP_UNION:\n        if (b->n_strings != 0) {\n            for(i = 0; i < b->hash_size; i++) {\n                for(p = b->hash_table[i]; p != NULL; p = p->next) {\n                    if (re_string_find2(a, p->len, p->buf, p->hash, TRUE) < 0)\n                        return -1;\n                }\n            }\n        }\n        break;\n    case CR_OP_INTER:\n    case CR_OP_SUB:\n        for(i = 0; i < a->hash_size; i++) {\n            pp = &a->hash_table[i];\n            for(;;) {\n                p = *pp;\n                if (p == NULL)\n                    break;\n                ret = re_string_find2(b, p->len, p->buf, p->hash, FALSE);\n                if (op == CR_OP_SUB)\n                    ret = !ret;\n                if (!ret) {\n                    /* remove it */\n                    *pp = p->next;\n                    a->n_strings--;\n                    lre_realloc(a->cr.mem_opaque, p, 0);\n                } else {\n                    /* keep it */\n                    pp = &p->next;\n                }\n            }\n        }\n        break;\n    default:\n        abort();\n    }\n    return 0;\n}\n\nstatic int re_string_list_canonicalize(REParseState *s1,\n                                       REStringList *s, BOOL is_unicode)\n{\n    if (cr_regexp_canonicalize(&s->cr, is_unicode))\n        return -1;\n    if (s->n_strings != 0) {\n        REStringList a_s, *a = &a_s;\n        int i, j;\n        REString *p;\n        \n        /* XXX: simplify */\n        re_string_list_init(s1, a);\n\n        a->n_strings = s->n_strings;\n        a->hash_size = s->hash_size;\n        a->hash_bits = s->hash_bits;\n        a->hash_table = s->hash_table;\n        \n        s->n_strings = 0;\n        s->hash_size = 0;\n        s->hash_bits = 0;\n        s->hash_table = NULL;\n\n        for(i = 0; i < a->hash_size; i++) {\n            for(p = a->hash_table[i]; p != NULL; p = p->next) {\n                for(j = 0; j < p->len; j++) {\n                    p->buf[j] = lre_canonicalize(p->buf[j], is_unicode);\n                }\n                if (re_string_add(s, p->len, p->buf)) {\n                    re_string_list_free(a);\n                    return -1;\n                }\n            }\n        }\n        re_string_list_free(a);\n    }\n    return 0;\n}\n\nstatic const uint16_t char_range_d[] = {\n    1,\n    0x0030, 0x0039 + 1,\n};\n\n/* code point ranges for Zs,Zl or Zp property */\nstatic const uint16_t char_range_s[] = {\n    10,\n    0x0009, 0x000D + 1,\n    0x0020, 0x0020 + 1,\n    0x00A0, 0x00A0 + 1,\n    0x1680, 0x1680 + 1,\n    0x2000, 0x200A + 1,\n    /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */\n    /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */\n    0x2028, 0x2029 + 1,\n    0x202F, 0x202F + 1,\n    0x205F, 0x205F + 1,\n    0x3000, 0x3000 + 1,\n    /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */\n    0xFEFF, 0xFEFF + 1,\n};\n\nstatic const uint16_t char_range_w[] = {\n    4,\n    0x0030, 0x0039 + 1,\n    0x0041, 0x005A + 1,\n    0x005F, 0x005F + 1,\n    0x0061, 0x007A + 1,\n};\n\n#define CLASS_RANGE_BASE 0x40000000\n\ntypedef enum {\n    CHAR_RANGE_d,\n    CHAR_RANGE_D,\n    CHAR_RANGE_s,\n    CHAR_RANGE_S,\n    CHAR_RANGE_w,\n    CHAR_RANGE_W,\n} CharRangeEnum;\n\nstatic const uint16_t * const char_range_table[] = {\n    char_range_d,\n    char_range_s,\n    char_range_w,\n};\n\nstatic int cr_init_char_range(REParseState *s, REStringList *cr, uint32_t c)\n{\n    BOOL invert;\n    const uint16_t *c_pt;\n    int len, i;\n\n    invert = c & 1;\n    c_pt = char_range_table[c >> 1];\n    len = *c_pt++;\n    re_string_list_init(s, cr);\n    for(i = 0; i < len * 2; i++) {\n        if (cr_add_point(&cr->cr, c_pt[i]))\n            goto fail;\n    }\n    if (invert) {\n        if (cr_invert(&cr->cr))\n            goto fail;\n    }\n    return 0;\n fail:\n    re_string_list_free(cr);\n    return -1;\n}\n\n#ifdef DUMP_REOP\nstatic __maybe_unused void lre_dump_bytecode(const uint8_t *buf,\n                                                     int buf_len)\n{\n    int pos, len, opcode, bc_len, re_flags, i;\n    uint32_t val, val2;\n\n    assert(buf_len >= RE_HEADER_LEN);\n\n    re_flags = lre_get_flags(buf);\n    bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN);\n    assert(bc_len + RE_HEADER_LEN <= buf_len);\n    printf(\"flags: 0x%x capture_count=%d reg_count=%d\\n\",\n           re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_REGISTER_COUNT]);\n    if (re_flags & LRE_FLAG_NAMED_GROUPS) {\n        const char *p;\n        p = (char *)buf + RE_HEADER_LEN + bc_len;\n        printf(\"named groups: \");\n        for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) {\n            if (i != 1)\n                printf(\",\");\n            printf(\"<%s>\", p);\n            p += strlen(p) + LRE_GROUP_NAME_TRAILER_LEN;\n        }\n        printf(\"\\n\");\n        assert(p == (char *)(buf + buf_len));\n    }\n    printf(\"bytecode_len=%d\\n\", bc_len);\n\n    buf += RE_HEADER_LEN;\n    pos = 0;\n    while (pos < bc_len) {\n        printf(\"%5u: \", pos);\n        opcode = buf[pos];\n        len = reopcode_info[opcode].size;\n        if (opcode >= REOP_COUNT) {\n            printf(\" invalid opcode=0x%02x\\n\", opcode);\n            break;\n        }\n        if ((pos + len) > bc_len) {\n            printf(\" buffer overflow (opcode=0x%02x)\\n\", opcode);\n            break;\n        }\n        printf(\"%s\", reopcode_info[opcode].name);\n        switch(opcode) {\n        case REOP_char:\n        case REOP_char_i:\n            val = get_u16(buf + pos + 1);\n            if (val >= ' ' && val <= 126)\n                printf(\" '%c'\", val);\n            else\n                printf(\" 0x%04x\", val);\n            break;\n        case REOP_char32:\n        case REOP_char32_i:\n            val = get_u32(buf + pos + 1);\n            if (val >= ' ' && val <= 126)\n                printf(\" '%c'\", val);\n            else\n                printf(\" 0x%08x\", val);\n            break;\n        case REOP_goto:\n        case REOP_split_goto_first:\n        case REOP_split_next_first:\n        case REOP_lookahead:\n        case REOP_negative_lookahead:\n            val = get_u32(buf + pos + 1);\n            val += (pos + 5);\n            printf(\" %u\", val);\n            break;\n        case REOP_loop:\n            val2 = buf[pos + 1];\n            val = get_u32(buf + pos + 2);\n            val += (pos + 6);\n            printf(\" r%u, %u\", val2, val);\n            break;\n        case REOP_loop_split_goto_first:\n        case REOP_loop_split_next_first:\n        case REOP_loop_check_adv_split_goto_first:\n        case REOP_loop_check_adv_split_next_first:\n            {\n                uint32_t limit;\n                val2 = buf[pos + 1];\n                limit = get_u32(buf + pos + 2);\n                val = get_u32(buf + pos + 6);\n                val += (pos + 10);\n                printf(\" r%u, %u, %u\", val2, limit, val);\n            }\n            break;\n        case REOP_save_start:\n        case REOP_save_end:\n            printf(\" %u\", buf[pos + 1]);\n            break;\n        case REOP_back_reference:\n        case REOP_back_reference_i:\n        case REOP_backward_back_reference:\n        case REOP_backward_back_reference_i:\n            {\n                int n, i;\n                n = buf[pos + 1];\n                len += n;\n                for(i = 0; i < n; i++) {\n                    if (i != 0)\n                        printf(\",\");\n                    printf(\" %u\", buf[pos + 2 + i]);\n                }\n            }\n            break;\n        case REOP_save_reset:\n            printf(\" %u %u\", buf[pos + 1], buf[pos + 2]);\n            break;\n        case REOP_set_i32:\n            val = buf[pos + 1];\n            val2 = get_u32(buf + pos + 2);\n            printf(\" r%u, %d\", val, val2);\n            break;\n        case REOP_set_char_pos:\n        case REOP_check_advance:\n            val = buf[pos + 1];\n            printf(\" r%u\", val);\n            break;\n        case REOP_range:\n        case REOP_range_i:\n            {\n                int n, i;\n                n = get_u16(buf + pos + 1);\n                len += n * 4;\n                for(i = 0; i < n * 2; i++) {\n                    val = get_u16(buf + pos + 3 + i * 2);\n                    printf(\" 0x%04x\", val);\n                }\n            }\n            break;\n        case REOP_range32:\n        case REOP_range32_i:\n            {\n                int n, i;\n                n = get_u16(buf + pos + 1);\n                len += n * 8;\n                for(i = 0; i < n * 2; i++) {\n                    val = get_u32(buf + pos + 3 + i * 4);\n                    printf(\" 0x%08x\", val);\n                }\n            }\n            break;\n        default:\n            break;\n        }\n        printf(\"\\n\");\n        pos += len;\n    }\n}\n#endif\n\nstatic void re_emit_op(REParseState *s, int op)\n{\n    dbuf_putc(&s->byte_code, op);\n}\n\n/* return the offset of the u32 value */\nstatic int re_emit_op_u32(REParseState *s, int op, uint32_t val)\n{\n    int pos;\n    dbuf_putc(&s->byte_code, op);\n    pos = s->byte_code.size;\n    dbuf_put_u32(&s->byte_code, val);\n    return pos;\n}\n\nstatic int re_emit_goto(REParseState *s, int op, uint32_t val)\n{\n    int pos;\n    dbuf_putc(&s->byte_code, op);\n    pos = s->byte_code.size;\n    dbuf_put_u32(&s->byte_code, val - (pos + 4));\n    return pos;\n}\n\nstatic int re_emit_goto_u8(REParseState *s, int op, uint32_t arg, uint32_t val)\n{\n    int pos;\n    dbuf_putc(&s->byte_code, op);\n    dbuf_putc(&s->byte_code, arg);\n    pos = s->byte_code.size;\n    dbuf_put_u32(&s->byte_code, val - (pos + 4));\n    return pos;\n}\n\nstatic int re_emit_goto_u8_u32(REParseState *s, int op, uint32_t arg0, uint32_t arg1, uint32_t val)\n{\n    int pos;\n    dbuf_putc(&s->byte_code, op);\n    dbuf_putc(&s->byte_code, arg0);\n    dbuf_put_u32(&s->byte_code, arg1);\n    pos = s->byte_code.size;\n    dbuf_put_u32(&s->byte_code, val - (pos + 4));\n    return pos;\n}\n\nstatic void re_emit_op_u8(REParseState *s, int op, uint32_t val)\n{\n    dbuf_putc(&s->byte_code, op);\n    dbuf_putc(&s->byte_code, val);\n}\n\nstatic void re_emit_op_u16(REParseState *s, int op, uint32_t val)\n{\n    dbuf_putc(&s->byte_code, op);\n    dbuf_put_u16(&s->byte_code, val);\n}\n\nstatic int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s, const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vsnprintf(s->u.error_msg, sizeof(s->u.error_msg), fmt, ap);\n    va_end(ap);\n    return -1;\n}\n\nstatic int re_parse_out_of_memory(REParseState *s)\n{\n    return re_parse_error(s, \"out of memory\");\n}\n\n/* If allow_overflow is false, return -1 in case of\n   overflow. Otherwise return INT32_MAX. */\nstatic int parse_digits(const uint8_t **pp, BOOL allow_overflow)\n{\n    const uint8_t *p;\n    uint64_t v;\n    int c;\n\n    p = *pp;\n    v = 0;\n    for(;;) {\n        c = *p;\n        if (c < '0' || c > '9')\n            break;\n        v = v * 10 + c - '0';\n        if (v >= INT32_MAX) {\n            if (allow_overflow)\n                v = INT32_MAX;\n            else\n                return -1;\n        }\n        p++;\n    }\n    *pp = p;\n    return v;\n}\n\nstatic int re_parse_expect(REParseState *s, const uint8_t **pp, int c)\n{\n    const uint8_t *p;\n    p = *pp;\n    if (*p != c)\n        return re_parse_error(s, \"expecting '%c'\", c);\n    p++;\n    *pp = p;\n    return 0;\n}\n\n/* Parse an escape sequence, *pp points after the '\\':\n   allow_utf16 value:\n   0 : no UTF-16 escapes allowed\n   1 : UTF-16 escapes allowed\n   2 : UTF-16 escapes allowed and escapes of surrogate pairs are\n   converted to a unicode character (unicode regexp case).\n\n   Return the unicode char and update *pp if recognized,\n   return -1 if malformed escape,\n   return -2 otherwise. */\nint lre_parse_escape(const uint8_t **pp, int allow_utf16)\n{\n    const uint8_t *p;\n    uint32_t c;\n\n    p = *pp;\n    c = *p++;\n    switch(c) {\n    case 'b':\n        c = '\\b';\n        break;\n    case 'f':\n        c = '\\f';\n        break;\n    case 'n':\n        c = '\\n';\n        break;\n    case 'r':\n        c = '\\r';\n        break;\n    case 't':\n        c = '\\t';\n        break;\n    case 'v':\n        c = '\\v';\n        break;\n    case 'x':\n        {\n            int h0, h1;\n\n            h0 = from_hex(*p++);\n            if (h0 < 0)\n                return -1;\n            h1 = from_hex(*p++);\n            if (h1 < 0)\n                return -1;\n            c = (h0 << 4) | h1;\n        }\n        break;\n    case 'u':\n        {\n            int h, i;\n            uint32_t c1;\n\n            if (*p == '{' && allow_utf16) {\n                p++;\n                c = 0;\n                for(;;) {\n                    h = from_hex(*p++);\n                    if (h < 0)\n                        return -1;\n                    c = (c << 4) | h;\n                    if (c > 0x10FFFF)\n                        return -1;\n                    if (*p == '}')\n                        break;\n                }\n                p++;\n            } else {\n                c = 0;\n                for(i = 0; i < 4; i++) {\n                    h = from_hex(*p++);\n                    if (h < 0) {\n                        return -1;\n                    }\n                    c = (c << 4) | h;\n                }\n                if (is_hi_surrogate(c) &&\n                    allow_utf16 == 2 && p[0] == '\\\\' && p[1] == 'u') {\n                    /* convert an escaped surrogate pair into a\n                       unicode char */\n                    c1 = 0;\n                    for(i = 0; i < 4; i++) {\n                        h = from_hex(p[2 + i]);\n                        if (h < 0)\n                            break;\n                        c1 = (c1 << 4) | h;\n                    }\n                    if (i == 4 && is_lo_surrogate(c1)) {\n                        p += 6;\n                        c = from_surrogate(c, c1);\n                    }\n                }\n            }\n        }\n        break;\n    case '0': case '1': case '2': case '3':\n    case '4': case '5': case '6': case '7':\n        c -= '0';\n        if (allow_utf16 == 2) {\n            /* only accept \\0 not followed by digit */\n            if (c != 0 || is_digit(*p))\n                return -1;\n        } else {\n            /* parse a legacy octal sequence */\n            uint32_t v;\n            v = *p - '0';\n            if (v > 7)\n                break;\n            c = (c << 3) | v;\n            p++;\n            if (c >= 32)\n                break;\n            v = *p - '0';\n            if (v > 7)\n                break;\n            c = (c << 3) | v;\n            p++;\n        }\n        break;\n    default:\n        return -2;\n    }\n    *pp = p;\n    return c;\n}\n\n#ifdef CONFIG_ALL_UNICODE\n/* XXX: we use the same chars for name and value */\nstatic BOOL is_unicode_char(int c)\n{\n    return ((c >= '0' && c <= '9') ||\n            (c >= 'A' && c <= 'Z') ||\n            (c >= 'a' && c <= 'z') ||\n            (c == '_'));\n}\n\n/* XXX: memory error test */\nstatic void seq_prop_cb(void *opaque, const uint32_t *seq, int seq_len)\n{\n    REStringList *sl = opaque;\n    re_string_add(sl, seq_len, seq);\n}\n\nstatic int parse_unicode_property(REParseState *s, REStringList *cr,\n                                  const uint8_t **pp, BOOL is_inv,\n                                  BOOL allow_sequence_prop)\n{\n    const uint8_t *p;\n    char name[64], value[64];\n    char *q;\n    BOOL script_ext;\n    int ret;\n\n    p = *pp;\n    if (*p != '{')\n        return re_parse_error(s, \"expecting '{' after \\\\p\");\n    p++;\n    q = name;\n    while (is_unicode_char(*p)) {\n        if ((q - name) >= sizeof(name) - 1)\n            goto unknown_property_name;\n        *q++ = *p++;\n    }\n    *q = '\\0';\n    q = value;\n    if (*p == '=') {\n        p++;\n        while (is_unicode_char(*p)) {\n            if ((q - value) >= sizeof(value) - 1)\n                return re_parse_error(s, \"unknown unicode property value\");\n            *q++ = *p++;\n        }\n    }\n    *q = '\\0';\n    if (*p != '}')\n        return re_parse_error(s, \"expecting '}'\");\n    p++;\n    //    printf(\"name=%s value=%s\\n\", name, value);\n\n    if (!strcmp(name, \"Script\") || !strcmp(name, \"sc\")) {\n        script_ext = FALSE;\n        goto do_script;\n    } else if (!strcmp(name, \"Script_Extensions\") || !strcmp(name, \"scx\")) {\n        script_ext = TRUE;\n    do_script:\n        re_string_list_init(s, cr);\n        ret = unicode_script(&cr->cr, value, script_ext);\n        if (ret) {\n            re_string_list_free(cr);\n            if (ret == -2)\n                return re_parse_error(s, \"unknown unicode script\");\n            else\n                goto out_of_memory;\n        }\n    } else if (!strcmp(name, \"General_Category\") || !strcmp(name, \"gc\")) {\n        re_string_list_init(s, cr);\n        ret = unicode_general_category(&cr->cr, value);\n        if (ret) {\n            re_string_list_free(cr);\n            if (ret == -2)\n                return re_parse_error(s, \"unknown unicode general category\");\n            else\n                goto out_of_memory;\n        }\n    } else if (value[0] == '\\0') {\n        re_string_list_init(s, cr);\n        ret = unicode_general_category(&cr->cr, name);\n        if (ret == -1) {\n            re_string_list_free(cr);\n            goto out_of_memory;\n        }\n        if (ret < 0) {\n            ret = unicode_prop(&cr->cr, name);\n            if (ret == -1) {\n                re_string_list_free(cr);\n                goto out_of_memory;\n            }\n        }\n        if (ret < 0 && !is_inv && allow_sequence_prop) {\n            CharRange cr_tmp;\n            cr_init(&cr_tmp, s->opaque, lre_realloc);\n            ret = unicode_sequence_prop(name, seq_prop_cb, cr, &cr_tmp);\n            cr_free(&cr_tmp);\n            if (ret == -1) {\n                re_string_list_free(cr);\n                goto out_of_memory;\n            }\n        }\n        if (ret < 0)\n            goto unknown_property_name;\n    } else {\n    unknown_property_name:\n        return re_parse_error(s, \"unknown unicode property name\");\n    }\n\n    /* the ordering of case folding and inversion  differs with\n       unicode_sets. 'unicode_sets' ordering is more consistent */\n    /* XXX: the spec seems incorrect, we do it as the other engines\n       seem to do it. */\n    if (s->ignore_case && s->unicode_sets) {\n        if (re_string_list_canonicalize(s, cr, s->is_unicode)) {\n            re_string_list_free(cr);\n            goto out_of_memory;\n        }\n    }\n    if (is_inv) {\n        if (cr_invert(&cr->cr)) {\n            re_string_list_free(cr);\n            goto out_of_memory;\n        }\n    }\n    if (s->ignore_case && !s->unicode_sets) {\n        if (re_string_list_canonicalize(s, cr, s->is_unicode)) {\n            re_string_list_free(cr);\n            goto out_of_memory;\n        }\n    }\n    *pp = p;\n    return 0;\n out_of_memory:\n    return re_parse_out_of_memory(s);\n}\n#endif /* CONFIG_ALL_UNICODE */\n\nstatic int get_class_atom(REParseState *s, REStringList *cr,\n                          const uint8_t **pp, BOOL inclass);\n\nstatic int parse_class_string_disjunction(REParseState *s, REStringList *cr,\n                                          const uint8_t **pp)\n{\n    const uint8_t *p;\n    DynBuf str;\n    int c;\n    \n    p = *pp;\n    if (*p != '{')\n        return re_parse_error(s, \"expecting '{' after \\\\q\");\n\n    dbuf_init2(&str, s->opaque, lre_realloc);\n    re_string_list_init(s, cr);\n    \n    p++;\n    for(;;) {\n        str.size = 0;\n        while (*p != '}' && *p != '|') {\n            c = get_class_atom(s, NULL, &p, FALSE);\n            if (c < 0)\n                goto fail;\n            if (dbuf_put_u32(&str, c)) {\n                re_parse_out_of_memory(s);\n                goto fail;\n            }\n        }\n        if (re_string_add(cr, str.size / 4, (uint32_t *)str.buf)) {\n            re_parse_out_of_memory(s);\n            goto fail;\n        }\n        if (*p == '}')\n            break;\n        p++;\n    }\n    if (s->ignore_case) {\n        if (re_string_list_canonicalize(s, cr, TRUE))\n            goto fail;\n    }\n    p++; /* skip the '}' */\n    dbuf_free(&str);\n    *pp = p;\n    return 0;\n fail:\n    dbuf_free(&str);\n    re_string_list_free(cr);\n    return -1;\n}\n\n/* return -1 if error otherwise the character or a class range\n   (CLASS_RANGE_BASE) if cr != NULL. In case of class range, 'cr' is\n   initialized. Otherwise, it is ignored. */\nstatic int get_class_atom(REParseState *s, REStringList *cr,\n                          const uint8_t **pp, BOOL inclass)\n{\n    const uint8_t *p;\n    uint32_t c;\n    int ret;\n\n    p = *pp;\n\n    c = *p;\n    switch(c) {\n    case '\\\\':\n        p++;\n        if (p >= s->buf_end)\n            goto unexpected_end;\n        c = *p++;\n        switch(c) {\n        case 'd':\n            c = CHAR_RANGE_d;\n            goto class_range;\n        case 'D':\n            c = CHAR_RANGE_D;\n            goto class_range;\n        case 's':\n            c = CHAR_RANGE_s;\n            goto class_range;\n        case 'S':\n            c = CHAR_RANGE_S;\n            goto class_range;\n        case 'w':\n            c = CHAR_RANGE_w;\n            goto class_range;\n        case 'W':\n            c = CHAR_RANGE_W;\n        class_range:\n            if (!cr)\n                goto default_escape;\n            if (cr_init_char_range(s, cr, c))\n                return -1;\n            c += CLASS_RANGE_BASE;\n            break;\n        case 'c':\n            c = *p;\n            if ((c >= 'a' && c <= 'z') ||\n                (c >= 'A' && c <= 'Z') ||\n                (((c >= '0' && c <= '9') || c == '_') &&\n                 inclass && !s->is_unicode)) {   /* Annex B.1.4 */\n                c &= 0x1f;\n                p++;\n            } else if (s->is_unicode) {\n                goto invalid_escape;\n            } else {\n                /* otherwise return '\\' and 'c' */\n                p--;\n                c = '\\\\';\n            }\n            break;\n        case '-':\n            if (!inclass && s->is_unicode)\n                goto invalid_escape;\n            break;\n        case '^':\n        case '$':\n        case '\\\\':\n        case '.':\n        case '*':\n        case '+':\n        case '?':\n        case '(':\n        case ')':\n        case '[':\n        case ']':\n        case '{':\n        case '}':\n        case '|':\n        case '/':\n            /* always valid to escape these characters */\n            break;\n#ifdef CONFIG_ALL_UNICODE\n        case 'p':\n        case 'P':\n            if (s->is_unicode && cr) {\n                if (parse_unicode_property(s, cr, &p, (c == 'P'), s->unicode_sets))\n                    return -1;\n                c = CLASS_RANGE_BASE;\n                break;\n            }\n            goto default_escape;\n#endif\n        case 'q':\n            if (s->unicode_sets && cr && inclass) {\n                if (parse_class_string_disjunction(s, cr, &p))\n                    return -1;\n                c = CLASS_RANGE_BASE;\n                break;\n            }\n            goto default_escape;\n        default:\n        default_escape:\n            p--;\n            ret = lre_parse_escape(&p, s->is_unicode * 2);\n            if (ret >= 0) {\n                c = ret;\n            } else {\n                if (s->is_unicode) {\n                invalid_escape:\n                    return re_parse_error(s, \"invalid escape sequence in regular expression\");\n                } else {\n                    /* just ignore the '\\' */\n                    goto normal_char;\n                }\n            }\n            break;\n        }\n        break;\n    case '\\0':\n        if (p >= s->buf_end) {\n        unexpected_end:\n            return re_parse_error(s, \"unexpected end\");\n        }\n        /* fall thru */\n        goto normal_char;\n\n    case '&':\n    case '!':\n    case '#':\n    case '$':\n    case '%':\n    case '*':\n    case '+':\n    case ',':\n    case '.':\n    case ':':\n    case ';':\n    case '<':\n    case '=':\n    case '>':\n    case '?':\n    case '@':\n    case '^':\n    case '`':\n    case '~':\n        if (s->unicode_sets && p[1] == c) {\n            /* forbidden double characters */\n            return re_parse_error(s, \"invalid class set operation in regular expression\");\n        }\n        goto normal_char;\n\n    case '(':\n    case ')':\n    case '[':\n    case ']':\n    case '{':\n    case '}':\n    case '/':\n    case '-':\n    case '|':\n        if (s->unicode_sets) {\n            /* invalid characters in unicode sets */\n            return re_parse_error(s, \"invalid character in class in regular expression\");\n        }\n        goto normal_char;\n\n    default:\n    normal_char:\n        /* normal char */\n        if (c >= 128) {\n            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n            if ((unsigned)c > 0xffff && !s->is_unicode) {\n                /* XXX: should handle non BMP-1 code points */\n                return re_parse_error(s, \"malformed unicode char\");\n            }\n        } else {\n            p++;\n        }\n        break;\n    }\n    *pp = p;\n    return c;\n}\n\nstatic int re_emit_range(REParseState *s, const CharRange *cr)\n{\n    int len, i;\n    uint32_t high;\n\n    len = (unsigned)cr->len / 2;\n    if (len >= 65535)\n        return re_parse_error(s, \"too many ranges\");\n    if (len == 0) {\n        re_emit_op_u32(s, REOP_char32, -1);\n    } else {\n        high = cr->points[cr->len - 1];\n        if (high == UINT32_MAX)\n            high = cr->points[cr->len - 2];\n        if (high <= 0xffff) {\n            /* can use 16 bit ranges with the conversion that 0xffff =\n               infinity */\n            re_emit_op_u16(s, s->ignore_case ? REOP_range_i : REOP_range, len);\n            for(i = 0; i < cr->len; i += 2) {\n                dbuf_put_u16(&s->byte_code, cr->points[i]);\n                high = cr->points[i + 1] - 1;\n                if (high == UINT32_MAX - 1)\n                    high = 0xffff;\n                dbuf_put_u16(&s->byte_code, high);\n            }\n        } else {\n            re_emit_op_u16(s, s->ignore_case ? REOP_range32_i : REOP_range32, len);\n            for(i = 0; i < cr->len; i += 2) {\n                dbuf_put_u32(&s->byte_code, cr->points[i]);\n                dbuf_put_u32(&s->byte_code, cr->points[i + 1] - 1);\n            }\n        }\n    }\n    return 0;\n}\n\nstatic int re_string_cmp_len(const void *a, const void *b, void *arg)\n{\n    REString *p1 = *(REString **)a;\n    REString *p2 = *(REString **)b;\n    return (p1->len < p2->len) - (p1->len > p2->len);\n}\n\nstatic void re_emit_char(REParseState *s, int c)\n{\n    if (c <= 0xffff)\n        re_emit_op_u16(s, s->ignore_case ? REOP_char_i : REOP_char, c);\n    else\n        re_emit_op_u32(s, s->ignore_case ? REOP_char32_i : REOP_char32, c);\n}\n\nstatic int re_emit_string_list(REParseState *s, const REStringList *sl)\n{\n    REString **tab, *p;\n    int i, j, split_pos, last_match_pos, n;\n    BOOL has_empty_string, is_last;\n    \n    //    re_string_list_dump(\"sl\", sl);\n    if (sl->n_strings == 0) {\n        /* simple case: only characters */\n        if (re_emit_range(s, &sl->cr))\n            return -1;\n    } else {\n        /* at least one string list is present : match the longest ones first */\n        /* XXX: add a new op_switch opcode to compile as a trie */\n        tab = lre_realloc(s->opaque, NULL, sizeof(tab[0]) * sl->n_strings);\n        if (!tab) {\n            re_parse_out_of_memory(s);\n            return -1;\n        }\n        has_empty_string = FALSE;\n        n = 0;\n        for(i = 0; i < sl->hash_size; i++) {\n            for(p = sl->hash_table[i]; p != NULL; p = p->next) {\n                if (p->len == 0) {\n                    has_empty_string = TRUE;\n                } else {\n                    tab[n++] = p;\n                }\n            }\n        }\n        assert(n <= sl->n_strings);\n        \n        rqsort(tab, n, sizeof(tab[0]), re_string_cmp_len, NULL);\n\n        last_match_pos = -1;\n        for(i = 0; i < n; i++) {\n            p = tab[i];\n            is_last = !has_empty_string && sl->cr.len == 0 && i == (n - 1);\n            if (!is_last)\n                split_pos = re_emit_op_u32(s, REOP_split_next_first, 0);\n            else\n                split_pos = 0;\n            for(j = 0; j < p->len; j++) {\n                re_emit_char(s, p->buf[j]);\n            }\n            if (!is_last) {\n                last_match_pos = re_emit_op_u32(s, REOP_goto, last_match_pos);\n                put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4));\n            }\n        }\n\n        if (sl->cr.len != 0) {\n            /* char range */\n            is_last = !has_empty_string;\n            if (!is_last)\n                split_pos = re_emit_op_u32(s, REOP_split_next_first, 0);\n            else\n                split_pos = 0; /* not used */\n            if (re_emit_range(s, &sl->cr)) {\n                lre_realloc(s->opaque, tab, 0);\n                return -1;\n            }\n            if (!is_last)\n                put_u32(s->byte_code.buf + split_pos, s->byte_code.size - (split_pos + 4));\n        }\n\n        /* patch the 'goto match' */\n        while (last_match_pos != -1) {\n            int next_pos = get_u32(s->byte_code.buf + last_match_pos);\n            put_u32(s->byte_code.buf + last_match_pos, s->byte_code.size - (last_match_pos + 4));\n            last_match_pos = next_pos;\n        }\n        \n        lre_realloc(s->opaque, tab, 0);\n    }\n    return 0;\n}\n\nstatic int re_parse_nested_class(REParseState *s, REStringList *cr, const uint8_t **pp);\n\nstatic int re_parse_class_set_operand(REParseState *s, REStringList *cr, const uint8_t **pp)\n{\n    int c1;\n    const uint8_t *p = *pp;\n    \n    if (*p == '[') {\n        if (re_parse_nested_class(s, cr, pp))\n            return -1;\n    } else {\n        c1 = get_class_atom(s, cr, pp, TRUE);\n        if (c1 < 0)\n            return -1;\n        if (c1 < CLASS_RANGE_BASE) {\n            /* create a range with a single character */\n            re_string_list_init(s, cr);\n            if (s->ignore_case)\n                c1 = lre_canonicalize(c1, s->is_unicode);\n            if (cr_union_interval(&cr->cr, c1, c1)) {\n                re_string_list_free(cr);\n                return -1;\n            }\n        }\n    }\n    return 0;\n}\n\nstatic int re_parse_nested_class(REParseState *s, REStringList *cr, const uint8_t **pp)\n{\n    const uint8_t *p;\n    uint32_t c1, c2;\n    int ret;\n    REStringList cr1_s, *cr1 = &cr1_s;\n    BOOL invert, is_first;\n\n    if (lre_check_stack_overflow(s->opaque, 0))\n        return re_parse_error(s, \"stack overflow\");\n\n    re_string_list_init(s, cr);\n    p = *pp;\n    p++;    /* skip '[' */\n\n    invert = FALSE;\n    if (*p == '^') {\n        p++;\n        invert = TRUE;\n    }\n    \n    /* handle unions */\n    is_first = TRUE;\n    for(;;) {\n        if (*p == ']')\n            break;\n        if (*p == '[' && s->unicode_sets) {\n            if (re_parse_nested_class(s, cr1, &p))\n                goto fail;\n            goto class_union;\n        } else {\n            c1 = get_class_atom(s, cr1, &p, TRUE);\n            if ((int)c1 < 0)\n                goto fail;\n            if (*p == '-' && p[1] != ']') {\n                const uint8_t *p0 = p + 1;\n                if (p[1] == '-' && s->unicode_sets && is_first)\n                    goto class_atom; /* first character class followed by '--' */\n                if (c1 >= CLASS_RANGE_BASE) {\n                    if (s->is_unicode) {\n                        re_string_list_free(cr1);\n                        goto invalid_class_range;\n                    }\n                    /* Annex B: match '-' character */\n                    goto class_atom;\n                }\n                c2 = get_class_atom(s, cr1, &p0, TRUE);\n                if ((int)c2 < 0)\n                    goto fail;\n                if (c2 >= CLASS_RANGE_BASE) {\n                    re_string_list_free(cr1);\n                    if (s->is_unicode) {\n                        goto invalid_class_range;\n                    }\n                    /* Annex B: match '-' character */\n                    goto class_atom;\n                }\n                p = p0;\n                if (c2 < c1) {\n                invalid_class_range:\n                    re_parse_error(s, \"invalid class range\");\n                    goto fail;\n                }\n                if (s->ignore_case) {\n                    CharRange cr2_s, *cr2 = &cr2_s;\n                    cr_init(cr2, s->opaque, lre_realloc);\n                    if (cr_add_interval(cr2, c1, c2 + 1) ||\n                        cr_regexp_canonicalize(cr2, s->is_unicode) ||\n                        cr_op1(&cr->cr, cr2->points, cr2->len, CR_OP_UNION)) {\n                        cr_free(cr2);\n                        goto memory_error;\n                    }\n                    cr_free(cr2);\n                } else {\n                    if (cr_union_interval(&cr->cr, c1, c2))\n                        goto memory_error;\n                }\n                is_first = FALSE; /* union operation */\n            } else {\n            class_atom:\n                if (c1 >= CLASS_RANGE_BASE) {\n                class_union:\n                    ret = re_string_list_op(cr, cr1, CR_OP_UNION);\n                    re_string_list_free(cr1);\n                    if (ret)\n                        goto memory_error;\n                } else {\n                    if (s->ignore_case)\n                        c1 = lre_canonicalize(c1, s->is_unicode);\n                    if (cr_union_interval(&cr->cr, c1, c1))\n                        goto memory_error;\n                }\n            }\n        }\n        if (s->unicode_sets && is_first) {\n            if (*p == '&' && p[1] == '&' && p[2] != '&') {\n                /* handle '&&' */\n                for(;;) {\n                    if (*p == ']') {\n                        break;\n                    } else if (*p == '&' && p[1] == '&' && p[2] != '&') {\n                        p += 2;\n                    } else {\n                        goto invalid_operation;\n                    }\n                    if (re_parse_class_set_operand(s, cr1, &p))\n                        goto fail;\n                    ret = re_string_list_op(cr, cr1, CR_OP_INTER);\n                    re_string_list_free(cr1);\n                    if (ret)\n                        goto memory_error;\n                }\n            } else if (*p == '-' && p[1] == '-') {\n                /* handle '--' */\n                for(;;) {\n                    if (*p == ']') {\n                        break;\n                    } else if (*p == '-' && p[1] == '-') {\n                        p += 2;\n                    } else {\n                    invalid_operation:\n                        re_parse_error(s, \"invalid operation in regular expression\");\n                        goto fail;\n                    }\n                    if (re_parse_class_set_operand(s, cr1, &p))\n                        goto fail;\n                    ret = re_string_list_op(cr, cr1, CR_OP_SUB);\n                    re_string_list_free(cr1);\n                    if (ret)\n                        goto memory_error;\n                }\n            }\n        }\n        is_first = FALSE;\n    }\n\n    p++;    /* skip ']' */\n    *pp = p;\n    if (invert) {\n        /* XXX: add may_contain_string syntax check to be fully\n           compliant. The test here accepts more input than the\n           spec. */\n        if (cr->n_strings != 0) {\n            re_parse_error(s, \"negated character class with strings in regular expression debugger eval code\");\n            goto fail;\n        }\n        if (cr_invert(&cr->cr))\n            goto memory_error;\n    }\n    return 0;\n memory_error:\n    re_parse_out_of_memory(s);\n fail:\n    re_string_list_free(cr);\n    return -1;\n}\n\nstatic int re_parse_char_class(REParseState *s, const uint8_t **pp)\n{\n    REStringList cr_s, *cr = &cr_s;\n\n    if (re_parse_nested_class(s, cr, pp))\n        return -1;\n    if (re_emit_string_list(s, cr))\n        goto fail;\n    re_string_list_free(cr);\n    return 0;\n fail:\n    re_string_list_free(cr);\n    return -1;\n}\n\n/* need_check_adv: false if the opcodes always advance the char pointer\n   need_capture_init: true if all the captures in the atom are not set\n*/\nstatic BOOL re_need_check_adv_and_capture_init(BOOL *pneed_capture_init,\n                                               const uint8_t *bc_buf, int bc_buf_len)\n{\n    int pos, opcode, len;\n    uint32_t val;\n    BOOL need_check_adv, need_capture_init;\n\n    need_check_adv = TRUE;\n    need_capture_init = FALSE;\n    pos = 0;\n    while (pos < bc_buf_len) {\n        opcode = bc_buf[pos];\n        len = reopcode_info[opcode].size;\n        switch(opcode) {\n        case REOP_range:\n        case REOP_range_i:\n            val = get_u16(bc_buf + pos + 1);\n            len += val * 4;\n            need_check_adv = FALSE;\n            break;\n        case REOP_range32:\n        case REOP_range32_i:\n            val = get_u16(bc_buf + pos + 1);\n            len += val * 8;\n            need_check_adv = FALSE;\n            break;\n        case REOP_char:\n        case REOP_char_i:\n        case REOP_char32:\n        case REOP_char32_i:\n        case REOP_dot:\n        case REOP_any:\n        case REOP_space:\n        case REOP_not_space:\n            need_check_adv = FALSE;\n            break;\n        case REOP_line_start:\n        case REOP_line_start_m:\n        case REOP_line_end:\n        case REOP_line_end_m:\n        case REOP_set_i32:\n        case REOP_set_char_pos:\n        case REOP_word_boundary:\n        case REOP_word_boundary_i:\n        case REOP_not_word_boundary:\n        case REOP_not_word_boundary_i:\n        case REOP_prev:\n            /* no effect */\n            break;\n        case REOP_save_start:\n        case REOP_save_end:\n        case REOP_save_reset:\n            break;\n        case REOP_back_reference:\n        case REOP_back_reference_i:\n        case REOP_backward_back_reference:\n        case REOP_backward_back_reference_i:\n            val = bc_buf[pos + 1];\n            len += val;\n            need_capture_init = TRUE;\n            break;\n        default:\n            /* safe behavior: we cannot predict the outcome */\n            need_capture_init = TRUE;\n            goto done;\n        }\n        pos += len;\n    }\n done:\n    *pneed_capture_init = need_capture_init;\n    return need_check_adv;\n}\n\n/* '*pp' is the first char after '<' */\nstatic int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)\n{\n    const uint8_t *p, *p1;\n    uint32_t c, d;\n    char *q;\n\n    p = *pp;\n    q = buf;\n    for(;;) {\n        c = *p;\n        if (c == '\\\\') {\n            p++;\n            if (*p != 'u')\n                return -1;\n            c = lre_parse_escape(&p, 2); // accept surrogate pairs\n        } else if (c == '>') {\n            break;\n        } else if (c >= 128) {\n            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n            if (is_hi_surrogate(c)) {\n                d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);\n                if (is_lo_surrogate(d)) {\n                    c = from_surrogate(c, d);\n                    p = p1;\n                }\n            }\n        } else {\n            p++;\n        }\n        if (c > 0x10FFFF)\n            return -1;\n        if (q == buf) {\n            if (!lre_js_is_ident_first(c))\n                return -1;\n        } else {\n            if (!lre_js_is_ident_next(c))\n                return -1;\n        }\n        if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size)\n            return -1;\n        if (c < 128) {\n            *q++ = c;\n        } else {\n            q += unicode_to_utf8((uint8_t*)q, c);\n        }\n    }\n    if (q == buf)\n        return -1;\n    *q = '\\0';\n    p++;\n    *pp = p;\n    return 0;\n}\n\n/* if capture_name = NULL: return the number of captures + 1.\n   Otherwise, return the number of matching capture groups  */\nstatic int re_parse_captures(REParseState *s, int *phas_named_captures,\n                             const char *capture_name, BOOL emit_group_index)\n{\n    const uint8_t *p;\n    int capture_index, n;\n    char name[TMP_BUF_SIZE];\n\n    capture_index = 1;\n    n = 0;\n    *phas_named_captures = 0;\n    for (p = s->buf_start; p < s->buf_end; p++) {\n        switch (*p) {\n        case '(':\n            if (p[1] == '?') {\n                if (p[2] == '<' && p[3] != '=' && p[3] != '!') {\n                    *phas_named_captures = 1;\n                    /* potential named capture */\n                    if (capture_name) {\n                        p += 3;\n                        if (re_parse_group_name(name, sizeof(name), &p) == 0) {\n                            if (!strcmp(name, capture_name)) {\n                                if (emit_group_index)\n                                    dbuf_putc(&s->byte_code, capture_index);\n                                n++;\n                            }\n                        }\n                    }\n                    capture_index++;\n                    if (capture_index >= CAPTURE_COUNT_MAX)\n                        goto done;\n                }\n            } else {\n                capture_index++;\n                if (capture_index >= CAPTURE_COUNT_MAX)\n                    goto done;\n            }\n            break;\n        case '\\\\':\n            p++;\n            break;\n        case '[':\n            for (p += 1 + (*p == ']'); p < s->buf_end && *p != ']'; p++) {\n                if (*p == '\\\\')\n                    p++;\n            }\n            break;\n        }\n    }\n done:\n    if (capture_name) {\n        return n;\n    } else {\n        return capture_index;\n    }\n}\n\nstatic int re_count_captures(REParseState *s)\n{\n    if (s->total_capture_count < 0) {\n        s->total_capture_count = re_parse_captures(s, &s->has_named_captures,\n                                                   NULL, FALSE);\n    }\n    return s->total_capture_count;\n}\n\nstatic BOOL re_has_named_captures(REParseState *s)\n{\n    if (s->has_named_captures < 0)\n        re_count_captures(s);\n    return s->has_named_captures;\n}\n\nstatic int find_group_name(REParseState *s, const char *name, BOOL emit_group_index)\n{\n    const char *p, *buf_end;\n    size_t len, name_len;\n    int capture_index, n;\n\n    p = (char *)s->group_names.buf;\n    if (!p)\n        return 0;\n    buf_end = (char *)s->group_names.buf + s->group_names.size;\n    name_len = strlen(name);\n    capture_index = 1;\n    n = 0;\n    while (p < buf_end) {\n        len = strlen(p);\n        if (len == name_len && memcmp(name, p, name_len) == 0) {\n            if (emit_group_index)\n                dbuf_putc(&s->byte_code, capture_index);\n            n++;\n        }\n        p += len + LRE_GROUP_NAME_TRAILER_LEN;\n        capture_index++;\n    }\n    return n;\n}\n\nstatic BOOL is_duplicate_group_name(REParseState *s, const char *name, int scope)\n{\n    const char *p, *buf_end;\n    size_t len, name_len;\n    int scope1;\n    \n    p = (char *)s->group_names.buf;\n    if (!p)\n        return 0;\n    buf_end = (char *)s->group_names.buf + s->group_names.size;\n    name_len = strlen(name);\n    while (p < buf_end) {\n        len = strlen(p);\n        if (len == name_len && memcmp(name, p, name_len) == 0) {\n            scope1 = (uint8_t)p[len + 1];\n            if (scope == scope1)\n                return TRUE;\n        }\n        p += len + LRE_GROUP_NAME_TRAILER_LEN;\n    }\n    return FALSE;\n}\n\nstatic int re_parse_disjunction(REParseState *s, BOOL is_backward_dir);\n\nstatic int re_parse_modifiers(REParseState *s, const uint8_t **pp)\n{\n    const uint8_t *p = *pp;\n    int mask = 0;\n    int val;\n\n    for(;;) {\n        if (*p == 'i') {\n            val = LRE_FLAG_IGNORECASE;\n        } else if (*p == 'm') {\n            val = LRE_FLAG_MULTILINE;\n        } else if (*p == 's') {\n            val = LRE_FLAG_DOTALL;\n        } else {\n            break;\n        }\n        if (mask & val)\n            return re_parse_error(s, \"duplicate modifier: '%c'\", *p);\n        mask |= val;\n        p++;\n    }\n    *pp = p;\n    return mask;\n}\n\nstatic BOOL update_modifier(BOOL val, int add_mask, int remove_mask,\n                            int mask)\n{\n    if (add_mask & mask)\n        val = TRUE;\n    if (remove_mask & mask)\n        val = FALSE;\n    return val;\n}\n\nstatic int re_parse_term(REParseState *s, BOOL is_backward_dir)\n{\n    const uint8_t *p;\n    int c, last_atom_start, quant_min, quant_max, last_capture_count;\n    BOOL greedy, is_neg, is_backward_lookahead;\n    REStringList cr_s, *cr = &cr_s;\n\n    last_atom_start = -1;\n    last_capture_count = 0;\n    p = s->buf_ptr;\n    c = *p;\n    switch(c) {\n    case '^':\n        p++;\n        re_emit_op(s, s->multi_line ? REOP_line_start_m : REOP_line_start);\n        break;\n    case '$':\n        p++;\n        re_emit_op(s, s->multi_line ? REOP_line_end_m : REOP_line_end);\n        break;\n    case '.':\n        p++;\n        last_atom_start = s->byte_code.size;\n        last_capture_count = s->capture_count;\n        if (is_backward_dir)\n            re_emit_op(s, REOP_prev);\n        re_emit_op(s, s->dotall ? REOP_any : REOP_dot);\n        if (is_backward_dir)\n            re_emit_op(s, REOP_prev);\n        break;\n    case '{':\n        if (s->is_unicode) {\n            return re_parse_error(s, \"syntax error\");\n        } else if (!is_digit(p[1])) {\n            /* Annex B: we accept '{' not followed by digits as a\n               normal atom */\n            goto parse_class_atom;\n        } else {\n            const uint8_t *p1 = p + 1;\n            /* Annex B: error if it is like a repetition count */\n            parse_digits(&p1, TRUE);\n            if (*p1 == ',') {\n                p1++;\n                if (is_digit(*p1)) {\n                    parse_digits(&p1, TRUE);\n                }\n            }\n            if (*p1 != '}') {\n                goto parse_class_atom;\n            }\n        }\n        /* fall thru */\n    case '*':\n    case '+':\n    case '?':\n        return re_parse_error(s, \"nothing to repeat\");\n    case '(':\n        if (p[1] == '?') {\n            if (p[2] == ':') {\n                p += 3;\n                last_atom_start = s->byte_code.size;\n                last_capture_count = s->capture_count;\n                s->buf_ptr = p;\n                if (re_parse_disjunction(s, is_backward_dir))\n                    return -1;\n                p = s->buf_ptr;\n                if (re_parse_expect(s, &p, ')'))\n                    return -1;\n            } else if (p[2] == 'i' || p[2] == 'm' || p[2] == 's' || p[2] == '-') {\n                BOOL saved_ignore_case, saved_multi_line, saved_dotall;\n                int add_mask, remove_mask;\n                p += 2;\n                remove_mask = 0;\n                add_mask = re_parse_modifiers(s, &p);\n                if (add_mask < 0)\n                    return -1;\n                if (*p == '-') {\n                    p++;\n                    remove_mask = re_parse_modifiers(s, &p);\n                    if (remove_mask < 0)\n                        return -1;\n                }\n                if ((add_mask == 0 && remove_mask == 0) ||\n                    (add_mask & remove_mask) != 0) {\n                    return re_parse_error(s, \"invalid modifiers\");\n                }\n                if (re_parse_expect(s, &p, ':'))\n                    return -1;\n                saved_ignore_case = s->ignore_case;\n                saved_multi_line = s->multi_line;\n                saved_dotall = s->dotall;\n                s->ignore_case = update_modifier(s->ignore_case, add_mask, remove_mask, LRE_FLAG_IGNORECASE);\n                s->multi_line = update_modifier(s->multi_line, add_mask, remove_mask, LRE_FLAG_MULTILINE);\n                s->dotall = update_modifier(s->dotall, add_mask, remove_mask, LRE_FLAG_DOTALL);\n\n                last_atom_start = s->byte_code.size;\n                last_capture_count = s->capture_count;\n                s->buf_ptr = p;\n                if (re_parse_disjunction(s, is_backward_dir))\n                    return -1;\n                p = s->buf_ptr;\n                if (re_parse_expect(s, &p, ')'))\n                    return -1;\n                s->ignore_case = saved_ignore_case;\n                s->multi_line = saved_multi_line;\n                s->dotall = saved_dotall;\n            } else if ((p[2] == '=' || p[2] == '!')) {\n                is_neg = (p[2] == '!');\n                is_backward_lookahead = FALSE;\n                p += 3;\n                goto lookahead;\n            } else if (p[2] == '<' &&\n                       (p[3] == '=' || p[3] == '!')) {\n                int pos;\n                is_neg = (p[3] == '!');\n                is_backward_lookahead = TRUE;\n                p += 4;\n                /* lookahead */\n            lookahead:\n                /* Annex B allows lookahead to be used as an atom for\n                   the quantifiers */\n                if (!s->is_unicode && !is_backward_lookahead)  {\n                    last_atom_start = s->byte_code.size;\n                    last_capture_count = s->capture_count;\n                }\n                pos = re_emit_op_u32(s, REOP_lookahead + is_neg, 0);\n                s->buf_ptr = p;\n                if (re_parse_disjunction(s, is_backward_lookahead))\n                    return -1;\n                p = s->buf_ptr;\n                if (re_parse_expect(s, &p, ')'))\n                    return -1;\n                re_emit_op(s, REOP_lookahead_match + is_neg);\n                /* jump after the 'match' after the lookahead is successful */\n                if (dbuf_error(&s->byte_code))\n                    return -1;\n                put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4));\n            } else if (p[2] == '<') {\n                p += 3;\n                if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),\n                                        &p)) {\n                    return re_parse_error(s, \"invalid group name\");\n                }\n                /* poor's man method to test duplicate group\n                   names. */\n                /* XXX: this method does not catch all the errors*/\n                if (is_duplicate_group_name(s, s->u.tmp_buf, s->group_name_scope)) {\n                    return re_parse_error(s, \"duplicate group name\");\n                }\n                /* group name with a trailing zero */\n                dbuf_put(&s->group_names, (uint8_t *)s->u.tmp_buf,\n                         strlen(s->u.tmp_buf) + 1);\n                dbuf_putc(&s->group_names, s->group_name_scope);\n                s->has_named_captures = 1;\n                goto parse_capture;\n            } else {\n                return re_parse_error(s, \"invalid group\");\n            }\n        } else {\n            int capture_index;\n            p++;\n            /* capture without group name */\n            dbuf_putc(&s->group_names, 0);\n            dbuf_putc(&s->group_names, 0);\n        parse_capture:\n            if (s->capture_count >= CAPTURE_COUNT_MAX)\n                return re_parse_error(s, \"too many captures\");\n            last_atom_start = s->byte_code.size;\n            last_capture_count = s->capture_count;\n            capture_index = s->capture_count++;\n            re_emit_op_u8(s, REOP_save_start + is_backward_dir,\n                          capture_index);\n\n            s->buf_ptr = p;\n            if (re_parse_disjunction(s, is_backward_dir))\n                return -1;\n            p = s->buf_ptr;\n\n            re_emit_op_u8(s, REOP_save_start + 1 - is_backward_dir,\n                          capture_index);\n\n            if (re_parse_expect(s, &p, ')'))\n                return -1;\n        }\n        break;\n    case '\\\\':\n        switch(p[1]) {\n        case 'b':\n        case 'B':\n            if (p[1] != 'b') {\n                re_emit_op(s, s->ignore_case && s->is_unicode ? REOP_not_word_boundary_i : REOP_not_word_boundary);\n            } else {\n                re_emit_op(s, s->ignore_case && s->is_unicode ? REOP_word_boundary_i : REOP_word_boundary);\n            }\n            p += 2;\n            break;\n        case 'k':\n            {\n                const uint8_t *p1;\n                int dummy_res, n;\n                BOOL is_forward;\n                \n                p1 = p;\n                if (p1[2] != '<') {\n                    /* annex B: we tolerate invalid group names in non\n                       unicode mode if there is no named capture\n                       definition */\n                    if (s->is_unicode || re_has_named_captures(s))\n                        return re_parse_error(s, \"expecting group name\");\n                    else\n                        goto parse_class_atom;\n                }\n                p1 += 3;\n                if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),\n                                        &p1)) {\n                    if (s->is_unicode || re_has_named_captures(s))\n                        return re_parse_error(s, \"invalid group name\");\n                    else\n                        goto parse_class_atom;\n                }\n                is_forward = FALSE;\n                n = find_group_name(s, s->u.tmp_buf, FALSE);\n                if (n == 0) {\n                    /* no capture name parsed before, try to look\n                       after (inefficient, but hopefully not common */\n                    n = re_parse_captures(s, &dummy_res, s->u.tmp_buf, FALSE);\n                    if (n == 0) {\n                        if (s->is_unicode || re_has_named_captures(s))\n                            return re_parse_error(s, \"group name not defined\");\n                        else\n                            goto parse_class_atom;\n                    }\n                    is_forward = TRUE;\n                }\n                last_atom_start = s->byte_code.size;\n                last_capture_count = s->capture_count;\n                \n                /* emit back references to all the captures indexes matching the group name */\n                re_emit_op_u8(s, REOP_back_reference + 2 * is_backward_dir + s->ignore_case, n);\n                if (is_forward) {\n                    re_parse_captures(s, &dummy_res, s->u.tmp_buf, TRUE);\n                } else {\n                    find_group_name(s, s->u.tmp_buf, TRUE);\n                }\n                p = p1;\n            }\n            break;\n        case '0':\n            p += 2;\n            c = 0;\n            if (s->is_unicode) {\n                if (is_digit(*p)) {\n                    return re_parse_error(s, \"invalid decimal escape in regular expression\");\n                }\n            } else {\n                /* Annex B.1.4: accept legacy octal */\n                if (*p >= '0' && *p <= '7') {\n                    c = *p++ - '0';\n                    if (*p >= '0' && *p <= '7') {\n                        c = (c << 3) + *p++ - '0';\n                    }\n                }\n            }\n            goto normal_char;\n        case '1': case '2': case '3': case '4':\n        case '5': case '6': case '7': case '8':\n        case '9':\n            {\n                const uint8_t *q = ++p;\n\n                c = parse_digits(&p, FALSE);\n                if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) {\n                    if (!s->is_unicode) {\n                        /* Annex B.1.4: accept legacy octal */\n                        p = q;\n                        if (*p <= '7') {\n                            c = 0;\n                            if (*p <= '3')\n                                c = *p++ - '0';\n                            if (*p >= '0' && *p <= '7') {\n                                c = (c << 3) + *p++ - '0';\n                                if (*p >= '0' && *p <= '7') {\n                                    c = (c << 3) + *p++ - '0';\n                                }\n                            }\n                        } else {\n                            c = *p++;\n                        }\n                        goto normal_char;\n                    }\n                    return re_parse_error(s, \"back reference out of range in regular expression\");\n                }\n                last_atom_start = s->byte_code.size;\n                last_capture_count = s->capture_count;\n                \n                re_emit_op_u8(s, REOP_back_reference + 2 * is_backward_dir + s->ignore_case, 1);\n                dbuf_putc(&s->byte_code, c);\n            }\n            break;\n        default:\n            goto parse_class_atom;\n        }\n        break;\n    case '[':\n        last_atom_start = s->byte_code.size;\n        last_capture_count = s->capture_count;\n        if (is_backward_dir)\n            re_emit_op(s, REOP_prev);\n        if (re_parse_char_class(s, &p))\n            return -1;\n        if (is_backward_dir)\n            re_emit_op(s, REOP_prev);\n        break;\n    case ']':\n    case '}':\n        if (s->is_unicode)\n            return re_parse_error(s, \"syntax error\");\n        goto parse_class_atom;\n    default:\n    parse_class_atom:\n        c = get_class_atom(s, cr, &p, FALSE);\n        if ((int)c < 0)\n            return -1;\n    normal_char:\n        last_atom_start = s->byte_code.size;\n        last_capture_count = s->capture_count;\n        if (is_backward_dir)\n            re_emit_op(s, REOP_prev);\n        if (c >= CLASS_RANGE_BASE) {\n            int ret = 0;\n            /* optimize the common 'space' tests */\n            if (c == (CLASS_RANGE_BASE + CHAR_RANGE_s)) {\n                re_emit_op(s, REOP_space);\n            } else if (c == (CLASS_RANGE_BASE + CHAR_RANGE_S)) {\n                re_emit_op(s, REOP_not_space);\n            } else {\n                ret = re_emit_string_list(s, cr);\n            }\n            re_string_list_free(cr);\n            if (ret)\n                return -1;\n        } else {\n            if (s->ignore_case)\n                c = lre_canonicalize(c, s->is_unicode);\n            re_emit_char(s, c);\n        }\n        if (is_backward_dir)\n            re_emit_op(s, REOP_prev);\n        break;\n    }\n\n    /* quantifier */\n    if (last_atom_start >= 0) {\n        c = *p;\n        switch(c) {\n        case '*':\n            p++;\n            quant_min = 0;\n            quant_max = INT32_MAX;\n            goto quantifier;\n        case '+':\n            p++;\n            quant_min = 1;\n            quant_max = INT32_MAX;\n            goto quantifier;\n        case '?':\n            p++;\n            quant_min = 0;\n            quant_max = 1;\n            goto quantifier;\n        case '{':\n            {\n                const uint8_t *p1 = p;\n                /* As an extension (see ES6 annex B), we accept '{' not\n                   followed by digits as a normal atom */\n                if (!is_digit(p[1])) {\n                    if (s->is_unicode)\n                        goto invalid_quant_count;\n                    break;\n                }\n                p++;\n                quant_min = parse_digits(&p, TRUE);\n                quant_max = quant_min;\n                if (*p == ',') {\n                    p++;\n                    if (is_digit(*p)) {\n                        quant_max = parse_digits(&p, TRUE);\n                        if (quant_max < quant_min) {\n                        invalid_quant_count:\n                            return re_parse_error(s, \"invalid repetition count\");\n                        }\n                    } else {\n                        quant_max = INT32_MAX; /* infinity */\n                    }\n                }\n                if (*p != '}' && !s->is_unicode) {\n                    /* Annex B: normal atom if invalid '{' syntax */\n                    p = p1;\n                    break;\n                }\n                if (re_parse_expect(s, &p, '}'))\n                    return -1;\n            }\n        quantifier:\n            greedy = TRUE;\n            if (*p == '?') {\n                p++;\n                greedy = FALSE;\n            }\n            if (last_atom_start < 0) {\n                return re_parse_error(s, \"nothing to repeat\");\n            }\n            {\n                BOOL need_capture_init, add_zero_advance_check;\n                int len, pos;\n                \n                /* the spec tells that if there is no advance when\n                   running the atom after the first quant_min times,\n                   then there is no match. We remove this test when we\n                   are sure the atom always advances the position. */\n                add_zero_advance_check =\n                    re_need_check_adv_and_capture_init(&need_capture_init,\n                                                       s->byte_code.buf + last_atom_start,\n                                                       s->byte_code.size - last_atom_start);\n            \n                /* general case: need to reset the capture at each\n                   iteration. We don't do it if there are no captures\n                   in the atom or if we are sure all captures are\n                   initialized in the atom. If quant_min = 0, we still\n                   need to reset once the captures in case the atom\n                   does not match. */\n                if (need_capture_init && last_capture_count != s->capture_count) {\n                    if (dbuf_insert(&s->byte_code, last_atom_start, 3))\n                        goto out_of_memory;\n                    int pos = last_atom_start;\n                    s->byte_code.buf[pos++] = REOP_save_reset;\n                    s->byte_code.buf[pos++] = last_capture_count;\n                    s->byte_code.buf[pos++] = s->capture_count - 1;\n                }\n\n                len = s->byte_code.size - last_atom_start;\n                if (quant_min == 0) {\n                    /* need to reset the capture in case the atom is\n                       not executed */\n                    if (!need_capture_init && last_capture_count != s->capture_count) {\n                        if (dbuf_insert(&s->byte_code, last_atom_start, 3))\n                            goto out_of_memory;\n                        s->byte_code.buf[last_atom_start++] = REOP_save_reset;\n                        s->byte_code.buf[last_atom_start++] = last_capture_count;\n                        s->byte_code.buf[last_atom_start++] = s->capture_count - 1;\n                    }\n                    if (quant_max == 0) {\n                        s->byte_code.size = last_atom_start;\n                    } else if (quant_max == 1 || quant_max == INT32_MAX) {\n                        BOOL has_goto = (quant_max == INT32_MAX);\n                        if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check * 2))\n                            goto out_of_memory;\n                        s->byte_code.buf[last_atom_start] = REOP_split_goto_first +\n                            greedy;\n                        put_u32(s->byte_code.buf + last_atom_start + 1,\n                                len + 5 * has_goto + add_zero_advance_check * 2 * 2);\n                        if (add_zero_advance_check) {\n                            s->byte_code.buf[last_atom_start + 1 + 4] = REOP_set_char_pos;\n                            s->byte_code.buf[last_atom_start + 1 + 4 + 1] = 0;\n                            re_emit_op_u8(s, REOP_check_advance, 0);\n                        }\n                        if (has_goto)\n                            re_emit_goto(s, REOP_goto, last_atom_start);\n                    } else {\n                        if (dbuf_insert(&s->byte_code, last_atom_start, 11 + add_zero_advance_check * 2))\n                            goto out_of_memory;\n                        pos = last_atom_start;\n                        s->byte_code.buf[pos++] = REOP_split_goto_first + greedy;\n                        put_u32(s->byte_code.buf + pos, 6 + add_zero_advance_check * 2 + len + 10);\n                        pos += 4;\n\n                        s->byte_code.buf[pos++] = REOP_set_i32;\n                        s->byte_code.buf[pos++] = 0;\n                        put_u32(s->byte_code.buf + pos, quant_max);\n                        pos += 4;\n                        last_atom_start = pos;\n                        if (add_zero_advance_check) {\n                            s->byte_code.buf[pos++] = REOP_set_char_pos;\n                            s->byte_code.buf[pos++] = 0;\n                        }\n                        re_emit_goto_u8_u32(s, (add_zero_advance_check ? REOP_loop_check_adv_split_next_first : REOP_loop_split_next_first) - greedy, 0, quant_max, last_atom_start);\n                    }\n                } else if (quant_min == 1 && quant_max == INT32_MAX &&\n                           !add_zero_advance_check) {\n                    re_emit_goto(s, REOP_split_next_first - greedy,\n                                 last_atom_start);\n                } else {\n                    if (quant_min == quant_max)\n                        add_zero_advance_check = FALSE;\n                    if (dbuf_insert(&s->byte_code, last_atom_start, 6 + add_zero_advance_check * 2))\n                        goto out_of_memory;\n                    /* Note: we assume the string length is < INT32_MAX */\n                    pos = last_atom_start;\n                    s->byte_code.buf[pos++] = REOP_set_i32;\n                    s->byte_code.buf[pos++] = 0;\n                    put_u32(s->byte_code.buf + pos, quant_max);\n                    pos += 4;\n                    last_atom_start = pos;\n                    if (add_zero_advance_check) {\n                        s->byte_code.buf[pos++] = REOP_set_char_pos;\n                        s->byte_code.buf[pos++] = 0;\n                    }\n                    if (quant_min == quant_max) {\n                        /* a simple loop is enough */\n                        re_emit_goto_u8(s, REOP_loop, 0, last_atom_start);\n                    } else {\n                        re_emit_goto_u8_u32(s, (add_zero_advance_check ? REOP_loop_check_adv_split_next_first : REOP_loop_split_next_first) - greedy, 0, quant_max - quant_min, last_atom_start);\n                    }\n                }\n                last_atom_start = -1;\n            }\n            break;\n        default:\n            break;\n        }\n    }\n    s->buf_ptr = p;\n    return 0;\n out_of_memory:\n    return re_parse_out_of_memory(s);\n}\n\nstatic int re_parse_alternative(REParseState *s, BOOL is_backward_dir)\n{\n    const uint8_t *p;\n    int ret;\n    size_t start, term_start, end, term_size;\n\n    start = s->byte_code.size;\n    for(;;) {\n        p = s->buf_ptr;\n        if (p >= s->buf_end)\n            break;\n        if (*p == '|' || *p == ')')\n            break;\n        term_start = s->byte_code.size;\n        ret = re_parse_term(s, is_backward_dir);\n        if (ret)\n            return ret;\n        if (is_backward_dir) {\n            /* reverse the order of the terms (XXX: inefficient, but\n               speed is not really critical here) */\n            end = s->byte_code.size;\n            term_size = end - term_start;\n            if (dbuf_claim(&s->byte_code, term_size))\n                return -1;\n            memmove(s->byte_code.buf + start + term_size,\n                    s->byte_code.buf + start,\n                    end - start);\n            memcpy(s->byte_code.buf + start, s->byte_code.buf + end,\n                   term_size);\n        }\n    }\n    return 0;\n}\n\nstatic int re_parse_disjunction(REParseState *s, BOOL is_backward_dir)\n{\n    int start, len, pos;\n\n    if (lre_check_stack_overflow(s->opaque, 0))\n        return re_parse_error(s, \"stack overflow\");\n\n    start = s->byte_code.size;\n    if (re_parse_alternative(s, is_backward_dir))\n        return -1;\n    while (*s->buf_ptr == '|') {\n        s->buf_ptr++;\n\n        len = s->byte_code.size - start;\n\n        /* insert a split before the first alternative */\n        if (dbuf_insert(&s->byte_code, start, 5)) {\n            return re_parse_out_of_memory(s);\n        }\n        s->byte_code.buf[start] = REOP_split_next_first;\n        put_u32(s->byte_code.buf + start + 1, len + 5);\n\n        pos = re_emit_op_u32(s, REOP_goto, 0);\n\n        s->group_name_scope++;\n        \n        if (re_parse_alternative(s, is_backward_dir))\n            return -1;\n\n        /* patch the goto */\n        len = s->byte_code.size - (pos + 4);\n        put_u32(s->byte_code.buf + pos, len);\n    }\n    return 0;\n}\n\n/* Allocate the registers as a stack. The control flow is recursive so\n   the analysis can be linear. */\nstatic int compute_register_count(uint8_t *bc_buf, int bc_buf_len)\n{\n    int stack_size, stack_size_max, pos, opcode, len;\n    uint32_t val;\n\n    stack_size = 0;\n    stack_size_max = 0;\n    bc_buf += RE_HEADER_LEN;\n    bc_buf_len -= RE_HEADER_LEN;\n    pos = 0;\n    while (pos < bc_buf_len) {\n        opcode = bc_buf[pos];\n        len = reopcode_info[opcode].size;\n        assert(opcode < REOP_COUNT);\n        assert((pos + len) <= bc_buf_len);\n        switch(opcode) {\n        case REOP_set_i32:\n        case REOP_set_char_pos:\n            bc_buf[pos + 1] = stack_size;\n            stack_size++;\n            if (stack_size > stack_size_max) {\n                if (stack_size > REGISTER_COUNT_MAX)\n                    return -1;\n                stack_size_max = stack_size;\n            }\n            break;\n        case REOP_check_advance:\n        case REOP_loop:\n        case REOP_loop_split_goto_first:\n        case REOP_loop_split_next_first:\n            assert(stack_size > 0);\n            stack_size--;\n            bc_buf[pos + 1] = stack_size;\n            break;\n        case REOP_loop_check_adv_split_goto_first:\n        case REOP_loop_check_adv_split_next_first:\n            assert(stack_size >= 2);\n            stack_size -= 2;\n            bc_buf[pos + 1] = stack_size;\n            break;\n        case REOP_range:\n        case REOP_range_i:\n            val = get_u16(bc_buf + pos + 1);\n            len += val * 4;\n            break;\n        case REOP_range32:\n        case REOP_range32_i:\n            val = get_u16(bc_buf + pos + 1);\n            len += val * 8;\n            break;\n        case REOP_back_reference:\n        case REOP_back_reference_i:\n        case REOP_backward_back_reference:\n        case REOP_backward_back_reference_i:\n            val = bc_buf[pos + 1];\n            len += val;\n            break;\n        }\n        pos += len;\n    }\n    return stack_size_max;\n}\n\nstatic void *lre_bytecode_realloc(void *opaque, void *ptr, size_t size)\n{\n    if (size > (INT32_MAX / 2)) {\n        /* the bytecode cannot be larger than 2G. Leave some slack to \n           avoid some overflows. */\n        return NULL;\n    } else {\n        return lre_realloc(opaque, ptr, size);\n    }\n}\n\n/* 'buf' must be a zero terminated UTF-8 string of length buf_len.\n   Return NULL if error and allocate an error message in *perror_msg,\n   otherwise the compiled bytecode and its length in plen.\n*/\nuint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,\n                     const char *buf, size_t buf_len, int re_flags,\n                     void *opaque)\n{\n    REParseState s_s, *s = &s_s;\n    int register_count;\n    BOOL is_sticky;\n\n    memset(s, 0, sizeof(*s));\n    s->opaque = opaque;\n    s->buf_ptr = (const uint8_t *)buf;\n    s->buf_end = s->buf_ptr + buf_len;\n    s->buf_start = s->buf_ptr;\n    s->re_flags = re_flags;\n    s->is_unicode = ((re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0);\n    is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0);\n    s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);\n    s->multi_line = ((re_flags & LRE_FLAG_MULTILINE) != 0);\n    s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0);\n    s->unicode_sets = ((re_flags & LRE_FLAG_UNICODE_SETS) != 0);\n    s->capture_count = 1;\n    s->total_capture_count = -1;\n    s->has_named_captures = -1;\n\n    dbuf_init2(&s->byte_code, opaque, lre_bytecode_realloc);\n    dbuf_init2(&s->group_names, opaque, lre_realloc);\n\n    dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */\n    dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */\n    dbuf_putc(&s->byte_code, 0); /* stack size */\n    dbuf_put_u32(&s->byte_code, 0); /* bytecode length */\n\n    if (!is_sticky) {\n        /* iterate thru all positions (about the same as .*?( ... ) )\n           .  We do it without an explicit loop so that lock step\n           thread execution will be possible in an optimized\n           implementation */\n        re_emit_op_u32(s, REOP_split_goto_first, 1 + 5);\n        re_emit_op(s, REOP_any);\n        re_emit_op_u32(s, REOP_goto, -(5 + 1 + 5));\n    }\n    re_emit_op_u8(s, REOP_save_start, 0);\n\n    if (re_parse_disjunction(s, FALSE)) {\n    error:\n        dbuf_free(&s->byte_code);\n        dbuf_free(&s->group_names);\n        pstrcpy(error_msg, error_msg_size, s->u.error_msg);\n        *plen = 0;\n        return NULL;\n    }\n\n    re_emit_op_u8(s, REOP_save_end, 0);\n\n    re_emit_op(s, REOP_match);\n\n    if (*s->buf_ptr != '\\0') {\n        re_parse_error(s, \"extraneous characters at the end\");\n        goto error;\n    }\n\n    if (dbuf_error(&s->byte_code)) {\n        re_parse_out_of_memory(s);\n        goto error;\n    }\n\n    register_count = compute_register_count(s->byte_code.buf, s->byte_code.size);\n    if (register_count < 0) {\n        re_parse_error(s, \"too many imbricated quantifiers\");\n        goto error;\n    }\n\n    s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count;\n    s->byte_code.buf[RE_HEADER_REGISTER_COUNT] = register_count;\n    put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN,\n            s->byte_code.size - RE_HEADER_LEN);\n\n    /* add the named groups if needed */\n    if (s->group_names.size > (s->capture_count - 1) * LRE_GROUP_NAME_TRAILER_LEN) {\n        dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size);\n        put_u16(s->byte_code.buf + RE_HEADER_FLAGS,\n                lre_get_flags(s->byte_code.buf) | LRE_FLAG_NAMED_GROUPS);\n    }\n    dbuf_free(&s->group_names);\n\n#ifdef DUMP_REOP\n    lre_dump_bytecode(s->byte_code.buf, s->byte_code.size);\n#endif\n\n    error_msg[0] = '\\0';\n    *plen = s->byte_code.size;\n    return s->byte_code.buf;\n}\n\nstatic BOOL is_line_terminator(uint32_t c)\n{\n    return (c == '\\n' || c == '\\r' || c == CP_LS || c == CP_PS);\n}\n\n#define GET_CHAR(c, cptr, cbuf_end, cbuf_type)                          \\\n    do {                                                                \\\n        if (cbuf_type == 0) {                                           \\\n            c = *cptr++;                                                \\\n        } else {                                                        \\\n            const uint16_t *_p = (const uint16_t *)cptr;                \\\n            const uint16_t *_end = (const uint16_t *)cbuf_end;          \\\n            c = *_p++;                                                  \\\n            if (is_hi_surrogate(c) && cbuf_type == 2) {                 \\\n                if (_p < _end && is_lo_surrogate(*_p)) {                \\\n                    c = from_surrogate(c, *_p++);                       \\\n                }                                                       \\\n            }                                                           \\\n            cptr = (const void *)_p;                                    \\\n        }                                                               \\\n    } while (0)\n\n#define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type)                         \\\n    do {                                                                \\\n        if (cbuf_type == 0) {                                           \\\n            c = cptr[0];                                                \\\n        } else {                                                        \\\n            const uint16_t *_p = (const uint16_t *)cptr;                \\\n            const uint16_t *_end = (const uint16_t *)cbuf_end;          \\\n            c = *_p++;                                                  \\\n            if (is_hi_surrogate(c) && cbuf_type == 2) {                 \\\n                if (_p < _end && is_lo_surrogate(*_p)) {                \\\n                    c = from_surrogate(c, *_p);                         \\\n                }                                                       \\\n            }                                                           \\\n        }                                                               \\\n    } while (0)\n\n#define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type)                  \\\n    do {                                                                \\\n        if (cbuf_type == 0) {                                           \\\n            c = cptr[-1];                                               \\\n        } else {                                                        \\\n            const uint16_t *_p = (const uint16_t *)cptr - 1;            \\\n            const uint16_t *_start = (const uint16_t *)cbuf_start;      \\\n            c = *_p;                                                    \\\n            if (is_lo_surrogate(c) && cbuf_type == 2) {                 \\\n                if (_p > _start && is_hi_surrogate(_p[-1])) {           \\\n                    c = from_surrogate(*--_p, c);                       \\\n                }                                                       \\\n            }                                                           \\\n        }                                                               \\\n    } while (0)\n\n#define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type)                   \\\n    do {                                                                \\\n        if (cbuf_type == 0) {                                           \\\n            cptr--;                                                     \\\n            c = cptr[0];                                                \\\n        } else {                                                        \\\n            const uint16_t *_p = (const uint16_t *)cptr - 1;            \\\n            const uint16_t *_start = (const uint16_t *)cbuf_start;      \\\n            c = *_p;                                                    \\\n            if (is_lo_surrogate(c) && cbuf_type == 2) {                 \\\n                if (_p > _start && is_hi_surrogate(_p[-1])) {           \\\n                    c = from_surrogate(*--_p, c);                       \\\n                }                                                       \\\n            }                                                           \\\n            cptr = (const void *)_p;                                    \\\n        }                                                               \\\n    } while (0)\n\n#define PREV_CHAR(cptr, cbuf_start, cbuf_type)                          \\\n    do {                                                                \\\n        if (cbuf_type == 0) {                                           \\\n            cptr--;                                                     \\\n        } else {                                                        \\\n            const uint16_t *_p = (const uint16_t *)cptr - 1;            \\\n            const uint16_t *_start = (const uint16_t *)cbuf_start;      \\\n            if (is_lo_surrogate(*_p) && cbuf_type == 2) {               \\\n                if (_p > _start && is_hi_surrogate(_p[-1])) {           \\\n                    --_p;                                               \\\n                }                                                       \\\n            }                                                           \\\n            cptr = (const void *)_p;                                    \\\n        }                                                               \\\n    } while (0)\n\ntypedef enum {\n    RE_EXEC_STATE_SPLIT,\n    RE_EXEC_STATE_LOOKAHEAD,\n    RE_EXEC_STATE_NEGATIVE_LOOKAHEAD,\n} REExecStateEnum;\n\n#if INTPTR_MAX >= INT64_MAX\n#define BP_TYPE_BITS 3\n#else\n#define BP_TYPE_BITS 2\n#endif\n\ntypedef union {\n    uint8_t *ptr;\n    intptr_t val; /* for bp, the low BP_SHIFT bits store REExecStateEnum */\n    struct {\n        uintptr_t val : sizeof(uintptr_t) * 8 - BP_TYPE_BITS;\n        uintptr_t type : BP_TYPE_BITS;\n    } bp;\n} StackElem;\n\ntypedef struct {\n    const uint8_t *cbuf;\n    const uint8_t *cbuf_end;\n    /* 0 = 8 bit chars, 1 = 16 bit chars, 2 = 16 bit chars, UTF-16 */\n    int cbuf_type;\n    int capture_count;\n    BOOL is_unicode;\n    int interrupt_counter;\n    void *opaque; /* used for stack overflow check */\n\n    StackElem *stack_buf;\n    size_t stack_size;\n    StackElem static_stack_buf[32]; /* static stack to avoid allocation in most cases */\n} REExecContext;\n\nstatic int lre_poll_timeout(REExecContext *s)\n{\n    if (unlikely(--s->interrupt_counter <= 0)) {\n        s->interrupt_counter = INTERRUPT_COUNTER_INIT;\n        if (lre_check_timeout(s->opaque))\n            return LRE_RET_TIMEOUT;\n    }\n    return 0;\n}\n\nstatic no_inline int stack_realloc(REExecContext *s, size_t n)\n{\n    StackElem *new_stack;\n    size_t new_size;\n    new_size = s->stack_size * 3 / 2;\n    if (new_size < n)\n        new_size = n;\n    if (s->stack_buf == s->static_stack_buf) {\n        new_stack = lre_realloc(s->opaque, NULL, new_size * sizeof(StackElem));\n        if (!new_stack)\n            return -1;\n        /* XXX: could use correct size */\n        memcpy(new_stack, s->stack_buf, s->stack_size * sizeof(StackElem));\n    } else {\n        new_stack = lre_realloc(s->opaque, s->stack_buf, new_size * sizeof(StackElem));\n        if (!new_stack)\n            return -1;\n    }\n    s->stack_size = new_size;\n    s->stack_buf = new_stack;\n    return 0;\n}\n\n/* return 1 if match, 0 if not match or < 0 if error. */\nstatic intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,\n                                   const uint8_t *pc, const uint8_t *cptr)\n{\n    int opcode;\n    int cbuf_type;\n    uint32_t val, c, idx;\n    const uint8_t *cbuf_end;\n    StackElem *sp, *bp, *stack_end;\n#ifdef DUMP_EXEC\n    const uint8_t *pc_start = pc; /* TEST */\n#endif\n    cbuf_type = s->cbuf_type;\n    cbuf_end = s->cbuf_end;\n\n    sp = s->stack_buf;\n    bp = s->stack_buf;\n    stack_end = s->stack_buf + s->stack_size;\n    \n#define CHECK_STACK_SPACE(n)                            \\\n    if (unlikely((stack_end - sp) < (n))) {             \\\n        size_t saved_sp = sp - s->stack_buf;            \\\n        size_t saved_bp = bp - s->stack_buf;            \\\n        if (stack_realloc(s, sp - s->stack_buf + (n)))  \\\n            return LRE_RET_MEMORY_ERROR;                \\\n        stack_end = s->stack_buf + s->stack_size;       \\\n        sp = s->stack_buf + saved_sp;                   \\\n        bp = s->stack_buf + saved_bp;                   \\\n    }\n\n    /* XXX: could test if the value was saved to reduce the stack size\n       but slower */\n#define SAVE_CAPTURE(idx, value)                        \\\n    {                                                   \\\n        CHECK_STACK_SPACE(2);                           \\\n        sp[0].val = idx;                                \\\n        sp[1].ptr = capture[idx];                       \\\n        sp += 2;                                        \\\n        capture[idx] = (value);                         \\\n    }\n\n    /* avoid saving the previous value if already saved */\n#define SAVE_CAPTURE_CHECK(idx, value)          \\\n    {                                           \\\n        StackElem *sp1;                         \\\n        sp1 = sp;                               \\\n        for(;;) {                               \\\n            if (sp1 > bp) {                             \\\n                if (sp1[-2].val == idx)                 \\\n                    break;                              \\\n                sp1 -= 2;                               \\\n            } else {                                    \\\n                CHECK_STACK_SPACE(2);                   \\\n                sp[0].val = idx;                        \\\n                sp[1].ptr = capture[idx];               \\\n                sp += 2;                                \\\n                break;                                  \\\n            }                                           \\\n        }                                               \\\n        capture[idx] = (value);                         \\\n    }\n\n\n#ifdef DUMP_EXEC\n    printf(\"%5s %5s %5s %5s %s\\n\", \"PC\", \"CP\", \"BP\", \"SP\", \"OPCODE\");\n#endif    \n    for(;;) {\n        opcode = *pc++;\n#ifdef DUMP_EXEC\n        printf(\"%5ld %5ld %5ld %5ld %s\\n\",\n               pc - 1 - pc_start,\n               cbuf_type == 0 ? cptr - s->cbuf : (cptr - s->cbuf) / 2,\n               bp - s->stack_buf,\n               sp - s->stack_buf,\n               reopcode_info[opcode].name);\n#endif        \n        switch(opcode) {\n        case REOP_match:\n            return 1;\n        no_match:\n            for(;;) {\n                REExecStateEnum type;\n                if (bp == s->stack_buf)\n                    return 0;\n                /* undo the modifications to capture[] */\n                while (sp > bp) {\n                    capture[sp[-2].val] = sp[-1].ptr;\n                    sp -= 2;\n                }\n                \n                pc = sp[-3].ptr;\n                cptr = sp[-2].ptr;\n                type = sp[-1].bp.type;\n                bp = s->stack_buf + sp[-1].bp.val;\n                sp -= 3;\n                if (type != RE_EXEC_STATE_LOOKAHEAD)\n                    break;\n            }\n            if (lre_poll_timeout(s))\n                return LRE_RET_TIMEOUT;\n            break;\n        case REOP_lookahead_match:\n            /* pop all the saved states until reaching the start of\n               the lookahead and keep the updated captures and\n               variables and the corresponding undo info. */\n            {\n                StackElem *sp1, *sp_top, *next_sp;\n                REExecStateEnum type;\n\n                sp_top = sp;\n                for(;;) {\n                    sp1 = sp;\n                    sp = bp;\n                    pc = sp[-3].ptr;\n                    cptr = sp[-2].ptr;\n                    type = sp[-1].bp.type;\n                    bp = s->stack_buf + sp[-1].bp.val;\n                    sp[-1].ptr = (void *)sp1; /* save the next value for the copy step */\n                    sp -= 3;\n                    if (type == RE_EXEC_STATE_LOOKAHEAD)\n                        break;\n                }\n                if (sp != s->stack_buf) {\n                    /* keep the undo info if there is a saved state */\n                    sp1 = sp;\n                    while (sp1 < sp_top) {\n                        next_sp = (void *)sp1[2].ptr;\n                        sp1 += 3;\n                        while (sp1 < next_sp)\n                            *sp++ = *sp1++;\n                    }\n                }\n            }\n            break;\n        case REOP_negative_lookahead_match:\n            /* pop all the saved states until reaching start of the negative lookahead */\n            for(;;) {\n                REExecStateEnum type;\n                type = bp[-1].bp.type;\n                /* undo the modifications to capture[] */\n                while (sp > bp) {\n                    capture[sp[-2].val] = sp[-1].ptr;\n                    sp -= 2;\n                }\n                pc = sp[-3].ptr;\n                cptr = sp[-2].ptr;\n                type = sp[-1].bp.type;\n                bp = s->stack_buf + sp[-1].bp.val;\n                sp -= 3;\n                if (type == RE_EXEC_STATE_NEGATIVE_LOOKAHEAD)\n                    break;\n            }\n            goto no_match;\n        case REOP_char32:\n        case REOP_char32_i:\n            val = get_u32(pc);\n            pc += 4;\n            goto test_char;\n        case REOP_char:\n        case REOP_char_i:\n            val = get_u16(pc);\n            pc += 2;\n        test_char:\n            if (cptr >= cbuf_end)\n                goto no_match;\n            GET_CHAR(c, cptr, cbuf_end, cbuf_type);\n            if (opcode == REOP_char_i || opcode == REOP_char32_i) {\n                c = lre_canonicalize(c, s->is_unicode);\n            }\n            if (val != c)\n                goto no_match;\n            break;\n        case REOP_split_goto_first:\n        case REOP_split_next_first:\n            {\n                const uint8_t *pc1;\n\n                val = get_u32(pc);\n                pc += 4;\n                if (opcode == REOP_split_next_first) {\n                    pc1 = pc + (int)val;\n                } else {\n                    pc1 = pc;\n                    pc = pc + (int)val;\n                }\n                CHECK_STACK_SPACE(3);\n                sp[0].ptr = (uint8_t *)pc1;\n                sp[1].ptr = (uint8_t *)cptr;\n                sp[2].bp.val = bp - s->stack_buf;\n                sp[2].bp.type = RE_EXEC_STATE_SPLIT;\n                sp += 3;\n                bp = sp;\n            }\n            break;\n        case REOP_lookahead:\n        case REOP_negative_lookahead:\n            val = get_u32(pc);\n            pc += 4;\n            CHECK_STACK_SPACE(3);\n            sp[0].ptr = (uint8_t *)(pc + (int)val);\n            sp[1].ptr = (uint8_t *)cptr;\n            sp[2].bp.val = bp - s->stack_buf;\n            sp[2].bp.type = RE_EXEC_STATE_LOOKAHEAD + opcode - REOP_lookahead;\n            sp += 3;\n            bp = sp;\n            break;\n        case REOP_goto:\n            val = get_u32(pc);\n            pc += 4 + (int)val;\n            if (lre_poll_timeout(s))\n                return LRE_RET_TIMEOUT;\n            break;\n        case REOP_line_start:\n        case REOP_line_start_m:\n            if (cptr == s->cbuf)\n                break;\n            if (opcode == REOP_line_start)\n                goto no_match;\n            PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);\n            if (!is_line_terminator(c))\n                goto no_match;\n            break;\n        case REOP_line_end:\n        case REOP_line_end_m:\n            if (cptr == cbuf_end)\n                break;\n            if (opcode == REOP_line_end)\n                goto no_match;\n            PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);\n            if (!is_line_terminator(c))\n                goto no_match;\n            break;\n        case REOP_dot:\n            if (cptr == cbuf_end)\n                goto no_match;\n            GET_CHAR(c, cptr, cbuf_end, cbuf_type);\n            if (is_line_terminator(c))\n                goto no_match;\n            break;\n        case REOP_any:\n            if (cptr == cbuf_end)\n                goto no_match;\n            GET_CHAR(c, cptr, cbuf_end, cbuf_type);\n            break;\n        case REOP_space:\n            if (cptr == cbuf_end)\n                goto no_match;\n            GET_CHAR(c, cptr, cbuf_end, cbuf_type);\n            if (!lre_is_space(c))\n                goto no_match;\n            break;\n        case REOP_not_space:\n            if (cptr == cbuf_end)\n                goto no_match;\n            GET_CHAR(c, cptr, cbuf_end, cbuf_type);\n            if (lre_is_space(c))\n                goto no_match;\n            break;\n        case REOP_save_start:\n        case REOP_save_end:\n            val = *pc++;\n            assert(val < s->capture_count);\n            idx = 2 * val + opcode - REOP_save_start;\n            SAVE_CAPTURE(idx, (uint8_t *)cptr);\n            break;\n        case REOP_save_reset:\n            {\n                uint32_t val2;\n                val = pc[0];\n                val2 = pc[1];\n                pc += 2;\n                assert(val2 < s->capture_count);\n                CHECK_STACK_SPACE(2 * (val2 - val + 1));\n                while (val <= val2) {\n                    idx = 2 * val;\n                    SAVE_CAPTURE(idx, NULL);\n                    idx = 2 * val + 1;\n                    SAVE_CAPTURE(idx, NULL);\n                    val++;\n                }\n            }\n            break;\n        case REOP_set_i32:\n            idx = 2 * s->capture_count + pc[0];\n            val = get_u32(pc + 1);\n            pc += 5;\n            SAVE_CAPTURE_CHECK(idx, (void *)(uintptr_t)val);\n            break;\n        case REOP_loop:\n            {\n                uint32_t val2;\n                idx = 2 * s->capture_count + pc[0];\n                val = get_u32(pc + 1);\n                pc += 5;\n\n                val2 = (uintptr_t)capture[idx] - 1;\n                SAVE_CAPTURE_CHECK(idx, (void *)(uintptr_t)val2);\n                if (val2 != 0) {\n                    pc += (int)val;\n                    if (lre_poll_timeout(s))\n                        return LRE_RET_TIMEOUT;\n                }\n            }\n            break;\n        case REOP_loop_split_goto_first:\n        case REOP_loop_split_next_first:\n        case REOP_loop_check_adv_split_goto_first:\n        case REOP_loop_check_adv_split_next_first:\n            {\n                const uint8_t *pc1;\n                uint32_t val2, limit;\n                idx = 2 * s->capture_count + pc[0];\n                limit = get_u32(pc + 1);\n                val = get_u32(pc + 5);\n                pc += 9;\n\n                /* decrement the counter */\n                val2 = (uintptr_t)capture[idx] - 1;\n                SAVE_CAPTURE_CHECK(idx, (void *)(uintptr_t)val2);\n\n                if (val2 > limit) {\n                    /* normal loop if counter > limit */\n                    pc += (int)val;\n                    if (lre_poll_timeout(s))\n                        return LRE_RET_TIMEOUT;\n                } else {\n                    /* check advance */\n                    if ((opcode == REOP_loop_check_adv_split_goto_first ||\n                         opcode == REOP_loop_check_adv_split_next_first) &&\n                        capture[idx + 1] == cptr &&\n                        val2 != limit) {\n                        goto no_match;\n                    }\n                    \n                    /* otherwise conditional split */\n                    if (val2 != 0) {\n                        if (opcode == REOP_loop_split_next_first ||\n                            opcode == REOP_loop_check_adv_split_next_first) {\n                            pc1 = pc + (int)val;\n                        } else {\n                            pc1 = pc;\n                            pc = pc + (int)val;\n                        }\n                        CHECK_STACK_SPACE(3);\n                        sp[0].ptr = (uint8_t *)pc1;\n                        sp[1].ptr = (uint8_t *)cptr;\n                        sp[2].bp.val = bp - s->stack_buf;\n                        sp[2].bp.type = RE_EXEC_STATE_SPLIT;\n                        sp += 3;\n                        bp = sp;\n                    }\n                }\n            }\n            break;\n        case REOP_set_char_pos:\n            idx = 2 * s->capture_count + pc[0];\n            pc++;\n            SAVE_CAPTURE_CHECK(idx, (uint8_t *)cptr);\n            break;\n        case REOP_check_advance:\n            idx = 2 * s->capture_count + pc[0];\n            pc++;\n            if (capture[idx] == cptr)\n                goto no_match;\n            break;\n        case REOP_word_boundary:\n        case REOP_word_boundary_i:\n        case REOP_not_word_boundary:\n        case REOP_not_word_boundary_i:\n            {\n                BOOL v1, v2;\n                int ignore_case = (opcode == REOP_word_boundary_i || opcode == REOP_not_word_boundary_i);\n                BOOL is_boundary = (opcode == REOP_word_boundary || opcode == REOP_word_boundary_i);\n                /* char before */\n                if (cptr == s->cbuf) {\n                    v1 = FALSE;\n                } else {\n                    PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);\n                    if (c < 256) {\n                        v1 = (lre_is_word_byte(c) != 0);\n                    } else {\n                        v1 = ignore_case && (c == 0x017f || c == 0x212a);\n                    }\n                }\n                /* current char */\n                if (cptr >= cbuf_end) {\n                    v2 = FALSE;\n                } else {\n                    PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);\n                    if (c < 256) {\n                        v2 = (lre_is_word_byte(c) != 0);\n                    } else {\n                        v2 = ignore_case && (c == 0x017f || c == 0x212a);\n                    }\n                }\n                if (v1 ^ v2 ^ is_boundary)\n                    goto no_match;\n            }\n            break;\n        case REOP_back_reference:\n        case REOP_back_reference_i:\n        case REOP_backward_back_reference:\n        case REOP_backward_back_reference_i:\n            {\n                const uint8_t *cptr1, *cptr1_end, *cptr1_start;\n                const uint8_t *pc1;\n                uint32_t c1, c2;\n                int i, n;\n\n                n = *pc++;\n                pc1 = pc;\n                pc += n;\n\n                for(i = 0; i < n; i++) {\n                    val = pc1[i];\n                    if (val >= s->capture_count)\n                        goto no_match;\n                    cptr1_start = capture[2 * val];\n                    cptr1_end = capture[2 * val + 1];\n                    /* test the first not empty capture */\n                    if (cptr1_start && cptr1_end) {\n                        if (opcode == REOP_back_reference ||\n                            opcode == REOP_back_reference_i) {\n                            cptr1 = cptr1_start;\n                            while (cptr1 < cptr1_end) {\n                                if (cptr >= cbuf_end)\n                                    goto no_match;\n                                GET_CHAR(c1, cptr1, cptr1_end, cbuf_type);\n                                GET_CHAR(c2, cptr, cbuf_end, cbuf_type);\n                                if (opcode == REOP_back_reference_i) {\n                                    c1 = lre_canonicalize(c1, s->is_unicode);\n                                    c2 = lre_canonicalize(c2, s->is_unicode);\n                                }\n                                if (c1 != c2)\n                                    goto no_match;\n                            }\n                        } else {\n                            cptr1 = cptr1_end;\n                            while (cptr1 > cptr1_start) {\n                                if (cptr == s->cbuf)\n                                    goto no_match;\n                                GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type);\n                                GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type);\n                                if (opcode == REOP_backward_back_reference_i) {\n                                    c1 = lre_canonicalize(c1, s->is_unicode);\n                                    c2 = lre_canonicalize(c2, s->is_unicode);\n                                }\n                                if (c1 != c2)\n                                    goto no_match;\n                            }\n                        }\n                        break;\n                    }\n                }\n            }\n            break;\n        case REOP_range:\n        case REOP_range_i:\n            {\n                int n;\n                uint32_t low, high, idx_min, idx_max, idx;\n\n                n = get_u16(pc); /* n must be >= 1 */\n                pc += 2;\n                if (cptr >= cbuf_end)\n                    goto no_match;\n                GET_CHAR(c, cptr, cbuf_end, cbuf_type);\n                if (opcode == REOP_range_i) {\n                    c = lre_canonicalize(c, s->is_unicode);\n                }\n                idx_min = 0;\n                low = get_u16(pc + 0 * 4);\n                if (c < low)\n                    goto no_match;\n                idx_max = n - 1;\n                high = get_u16(pc + idx_max * 4 + 2);\n                /* 0xffff in for last value means +infinity */\n                if (unlikely(c >= 0xffff) && high == 0xffff)\n                    goto range_match;\n                if (c > high)\n                    goto no_match;\n                while (idx_min <= idx_max) {\n                    idx = (idx_min + idx_max) / 2;\n                    low = get_u16(pc + idx * 4);\n                    high = get_u16(pc + idx * 4 + 2);\n                    if (c < low)\n                        idx_max = idx - 1;\n                    else if (c > high)\n                        idx_min = idx + 1;\n                    else\n                        goto range_match;\n                }\n                goto no_match;\n            range_match:\n                pc += 4 * n;\n            }\n            break;\n        case REOP_range32:\n        case REOP_range32_i:\n            {\n                int n;\n                uint32_t low, high, idx_min, idx_max, idx;\n\n                n = get_u16(pc); /* n must be >= 1 */\n                pc += 2;\n                if (cptr >= cbuf_end)\n                    goto no_match;\n                GET_CHAR(c, cptr, cbuf_end, cbuf_type);\n                if (opcode == REOP_range32_i) {\n                    c = lre_canonicalize(c, s->is_unicode);\n                }\n                idx_min = 0;\n                low = get_u32(pc + 0 * 8);\n                if (c < low)\n                    goto no_match;\n                idx_max = n - 1;\n                high = get_u32(pc + idx_max * 8 + 4);\n                if (c > high)\n                    goto no_match;\n                while (idx_min <= idx_max) {\n                    idx = (idx_min + idx_max) / 2;\n                    low = get_u32(pc + idx * 8);\n                    high = get_u32(pc + idx * 8 + 4);\n                    if (c < low)\n                        idx_max = idx - 1;\n                    else if (c > high)\n                        idx_min = idx + 1;\n                    else\n                        goto range32_match;\n                }\n                goto no_match;\n            range32_match:\n                pc += 8 * n;\n            }\n            break;\n        case REOP_prev:\n            /* go to the previous char */\n            if (cptr == s->cbuf)\n                goto no_match;\n            PREV_CHAR(cptr, s->cbuf, cbuf_type);\n            break;\n        default:\n#ifdef DUMP_EXEC\n            printf(\"unknown opcode pc=%ld\\n\", pc - 1 - pc_start);\n#endif            \n            abort();\n        }\n    }\n}\n\n/* Return 1 if match, 0 if not match or < 0 if error (see LRE_RET_x). cindex is the\n   starting position of the match and must be such as 0 <= cindex <=\n   clen. */\nint lre_exec(uint8_t **capture,\n             const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,\n             int cbuf_type, void *opaque)\n{\n    REExecContext s_s, *s = &s_s;\n    int re_flags, i, ret;\n    const uint8_t *cptr;\n\n    re_flags = lre_get_flags(bc_buf);\n    s->is_unicode = (re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0;\n    s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT];\n    s->cbuf = cbuf;\n    s->cbuf_end = cbuf + (clen << cbuf_type);\n    s->cbuf_type = cbuf_type;\n    if (s->cbuf_type == 1 && s->is_unicode)\n        s->cbuf_type = 2;\n    s->interrupt_counter = INTERRUPT_COUNTER_INIT;\n    s->opaque = opaque;\n\n    s->stack_buf = s->static_stack_buf;\n    s->stack_size = countof(s->static_stack_buf);\n\n    for(i = 0; i < s->capture_count * 2; i++)\n        capture[i] = NULL;\n\n    cptr = cbuf + (cindex << cbuf_type);\n    if (0 < cindex && cindex < clen && s->cbuf_type == 2) {\n        const uint16_t *p = (const uint16_t *)cptr;\n        if (is_lo_surrogate(*p) && is_hi_surrogate(p[-1])) {\n            cptr = (const uint8_t *)(p - 1);\n        }\n    }\n\n    ret = lre_exec_backtrack(s, capture, bc_buf + RE_HEADER_LEN, cptr);\n\n    if (s->stack_buf != s->static_stack_buf)\n        lre_realloc(s->opaque, s->stack_buf, 0);\n    return ret;\n}\n\nint lre_get_alloc_count(const uint8_t *bc_buf)\n{\n    return bc_buf[RE_HEADER_CAPTURE_COUNT] * 2 +\n        bc_buf[RE_HEADER_REGISTER_COUNT];\n}\n\nint lre_get_capture_count(const uint8_t *bc_buf)\n{\n    return bc_buf[RE_HEADER_CAPTURE_COUNT];\n}\n\nint lre_get_flags(const uint8_t *bc_buf)\n{\n    return get_u16(bc_buf + RE_HEADER_FLAGS);\n}\n\n/* Return NULL if no group names. Otherwise, return a pointer to\n   'capture_count - 1' zero terminated UTF-8 strings. */\nconst char *lre_get_groupnames(const uint8_t *bc_buf)\n{\n    uint32_t re_bytecode_len;\n    if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)\n        return NULL;\n    re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);\n    return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len);\n}\n\n#ifdef TEST\n\nBOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)\n{\n    return FALSE;\n}\n\nvoid *lre_realloc(void *opaque, void *ptr, size_t size)\n{\n    return realloc(ptr, size);\n}\n\nint main(int argc, char **argv)\n{\n    int len, flags, ret, i;\n    uint8_t *bc;\n    char error_msg[64];\n    uint8_t *capture;\n    const char *input;\n    int input_len, capture_count;\n\n    if (argc < 4) {\n        printf(\"usage: %s regexp flags input\\n\", argv[0]);\n        return 1;\n    }\n    flags = atoi(argv[2]);\n    bc = lre_compile(&len, error_msg, sizeof(error_msg), argv[1],\n                     strlen(argv[1]), flags, NULL);\n    if (!bc) {\n        fprintf(stderr, \"error: %s\\n\", error_msg);\n        exit(1);\n    }\n\n    input = argv[3];\n    input_len = strlen(input);\n\n    capture = malloc(sizeof(capture[0]) * lre_get_alloc_count(bc));\n    ret = lre_exec(capture, bc, (uint8_t *)input, 0, input_len, 0, NULL);\n    printf(\"ret=%d\\n\", ret);\n    if (ret == 1) {\n        capture_count = lre_get_capture_count(bc);\n        for(i = 0; i < 2 * capture_count; i++) {\n            uint8_t *ptr;\n            ptr = capture[i];\n            printf(\"%d: \", i);\n            if (!ptr)\n                printf(\"<nil>\");\n            else\n                printf(\"%u\", (int)(ptr - (uint8_t *)input));\n            printf(\"\\n\");\n        }\n    }\n    free(capture);\n    return 0;\n}\n#endif\n"
  },
  {
    "path": "libregexp.h",
    "content": "/*\n * Regular Expression Engine\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef LIBREGEXP_H\n#define LIBREGEXP_H\n\n#include <stddef.h>\n#include <stdint.h>\n\n#define LRE_FLAG_GLOBAL     (1 << 0)\n#define LRE_FLAG_IGNORECASE (1 << 1)\n#define LRE_FLAG_MULTILINE  (1 << 2)\n#define LRE_FLAG_DOTALL     (1 << 3)\n#define LRE_FLAG_UNICODE    (1 << 4)\n#define LRE_FLAG_STICKY     (1 << 5)\n#define LRE_FLAG_INDICES    (1 << 6) /* Unused by libregexp, just recorded. */\n#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */\n#define LRE_FLAG_UNICODE_SETS (1 << 8)\n\n#define LRE_RET_MEMORY_ERROR (-1)\n#define LRE_RET_TIMEOUT      (-2)\n\n/* trailer length after the group name including the trailing '\\0' */\n#define LRE_GROUP_NAME_TRAILER_LEN 2 \n\nuint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,\n                     const char *buf, size_t buf_len, int re_flags,\n                     void *opaque);\nint lre_get_alloc_count(const uint8_t *bc_buf);\nint lre_get_capture_count(const uint8_t *bc_buf);\nint lre_get_flags(const uint8_t *bc_buf);\nconst char *lre_get_groupnames(const uint8_t *bc_buf);\nint lre_exec(uint8_t **capture,\n             const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,\n             int cbuf_type, void *opaque);\n\nint lre_parse_escape(const uint8_t **pp, int allow_utf16);\n\n/* must be provided by the user, return non zero if overflow */\nint lre_check_stack_overflow(void *opaque, size_t alloca_size);\n/* must be provided by the user, return non zero if time out */\nint lre_check_timeout(void *opaque);\nvoid *lre_realloc(void *opaque, void *ptr, size_t size);\n\n#endif /* LIBREGEXP_H */\n"
  },
  {
    "path": "libunicode-table.h",
    "content": "/* Compressed unicode tables */\n/* Automatically generated file - do not edit */\n\n#include <stdint.h>\n\nstatic const uint32_t case_conv_table1[378] = {\n    0x00209a30, 0x00309a00, 0x005a8173, 0x00601730,\n    0x006c0730, 0x006f81b3, 0x00701700, 0x007c0700,\n    0x007f8100, 0x00803040, 0x009801c3, 0x00988190,\n    0x00990640, 0x009c9040, 0x00a481b4, 0x00a52e40,\n    0x00bc0130, 0x00bc8640, 0x00bf8170, 0x00c00100,\n    0x00c08130, 0x00c10440, 0x00c30130, 0x00c38240,\n    0x00c48230, 0x00c58240, 0x00c70130, 0x00c78130,\n    0x00c80130, 0x00c88240, 0x00c98130, 0x00ca0130,\n    0x00ca8100, 0x00cb0130, 0x00cb8130, 0x00cc0240,\n    0x00cd0100, 0x00cd8101, 0x00ce0130, 0x00ce8130,\n    0x00cf0100, 0x00cf8130, 0x00d00640, 0x00d30130,\n    0x00d38240, 0x00d48130, 0x00d60240, 0x00d70130,\n    0x00d78240, 0x00d88230, 0x00d98440, 0x00db8130,\n    0x00dc0240, 0x00de0240, 0x00df8100, 0x00e20350,\n    0x00e38350, 0x00e50350, 0x00e69040, 0x00ee8100,\n    0x00ef1240, 0x00f801b4, 0x00f88350, 0x00fa0240,\n    0x00fb0130, 0x00fb8130, 0x00fc2840, 0x01100130,\n    0x01111240, 0x011d0131, 0x011d8240, 0x011e8130,\n    0x011f0131, 0x011f8201, 0x01208240, 0x01218130,\n    0x01220130, 0x01228130, 0x01230a40, 0x01280101,\n    0x01288101, 0x01290101, 0x01298100, 0x012a0100,\n    0x012b0200, 0x012c8100, 0x012d8100, 0x012e0101,\n    0x01300100, 0x01308101, 0x01318100, 0x01320101,\n    0x01328101, 0x01330101, 0x01340100, 0x01348100,\n    0x01350101, 0x01358101, 0x01360101, 0x01378100,\n    0x01388101, 0x01390100, 0x013a8100, 0x013e8101,\n    0x01400100, 0x01410101, 0x01418100, 0x01438101,\n    0x01440100, 0x01448100, 0x01450200, 0x01460100,\n    0x01490100, 0x014e8101, 0x014f0101, 0x01a28173,\n    0x01b80440, 0x01bb0240, 0x01bd8300, 0x01bf8130,\n    0x01c30130, 0x01c40330, 0x01c60130, 0x01c70230,\n    0x01c801d0, 0x01c89130, 0x01d18930, 0x01d60100,\n    0x01d68300, 0x01d801d3, 0x01d89100, 0x01e10173,\n    0x01e18900, 0x01e60100, 0x01e68200, 0x01e78130,\n    0x01e80173, 0x01e88173, 0x01ea8173, 0x01eb0173,\n    0x01eb8100, 0x01ec1840, 0x01f80173, 0x01f88173,\n    0x01f90100, 0x01f98100, 0x01fa01a0, 0x01fa8173,\n    0x01fb8240, 0x01fc8130, 0x01fd0240, 0x01fe8330,\n    0x02001030, 0x02082030, 0x02182000, 0x02281000,\n    0x02302240, 0x02453640, 0x02600130, 0x02608e40,\n    0x02678100, 0x02686040, 0x0298a630, 0x02b0a600,\n    0x02c381b5, 0x08502631, 0x08638131, 0x08668131,\n    0x08682b00, 0x087e8300, 0x09d05011, 0x09f80610,\n    0x09fc0620, 0x0e400174, 0x0e408174, 0x0e410174,\n    0x0e418174, 0x0e420174, 0x0e428174, 0x0e430174,\n    0x0e438180, 0x0e440180, 0x0e448240, 0x0e482b30,\n    0x0e5e8330, 0x0ebc8101, 0x0ebe8101, 0x0ec70101,\n    0x0f007e40, 0x0f3f1840, 0x0f4b01b5, 0x0f4b81b6,\n    0x0f4c01b6, 0x0f4c81b6, 0x0f4d01b7, 0x0f4d8180,\n    0x0f4f0130, 0x0f506040, 0x0f800800, 0x0f840830,\n    0x0f880600, 0x0f8c0630, 0x0f900800, 0x0f940830,\n    0x0f980800, 0x0f9c0830, 0x0fa00600, 0x0fa40630,\n    0x0fa801b0, 0x0fa88100, 0x0fa901d3, 0x0fa98100,\n    0x0faa01d3, 0x0faa8100, 0x0fab01d3, 0x0fab8100,\n    0x0fac8130, 0x0fad8130, 0x0fae8130, 0x0faf8130,\n    0x0fb00800, 0x0fb40830, 0x0fb80200, 0x0fb90400,\n    0x0fbb0201, 0x0fbc0201, 0x0fbd0201, 0x0fbe0201,\n    0x0fc008b7, 0x0fc40867, 0x0fc808b8, 0x0fcc0868,\n    0x0fd008b8, 0x0fd40868, 0x0fd80200, 0x0fd901b9,\n    0x0fd981b1, 0x0fda01b9, 0x0fdb01b1, 0x0fdb81d7,\n    0x0fdc0230, 0x0fdd0230, 0x0fde0161, 0x0fdf0173,\n    0x0fe101b9, 0x0fe181b2, 0x0fe201ba, 0x0fe301b2,\n    0x0fe381d8, 0x0fe40430, 0x0fe60162, 0x0fe80201,\n    0x0fe901d0, 0x0fe981d0, 0x0feb01b0, 0x0feb81d0,\n    0x0fec0230, 0x0fed0230, 0x0ff00201, 0x0ff101d3,\n    0x0ff181d3, 0x0ff201ba, 0x0ff28101, 0x0ff301b0,\n    0x0ff381d3, 0x0ff40231, 0x0ff50230, 0x0ff60131,\n    0x0ff901ba, 0x0ff981b2, 0x0ffa01bb, 0x0ffb01b2,\n    0x0ffb81d9, 0x0ffc0230, 0x0ffd0230, 0x0ffe0162,\n    0x109301a0, 0x109501a0, 0x109581a0, 0x10990131,\n    0x10a70101, 0x10b01031, 0x10b81001, 0x10c18240,\n    0x125b1a31, 0x12681a01, 0x16003031, 0x16183001,\n    0x16300240, 0x16310130, 0x16318130, 0x16320130,\n    0x16328100, 0x16330100, 0x16338640, 0x16368130,\n    0x16370130, 0x16378130, 0x16380130, 0x16390240,\n    0x163a8240, 0x163f0230, 0x16406440, 0x16758440,\n    0x16790240, 0x16802600, 0x16938100, 0x16968100,\n    0x53202e40, 0x53401c40, 0x53910e40, 0x53993e40,\n    0x53bc8440, 0x53be8130, 0x53bf0a40, 0x53c58240,\n    0x53c68130, 0x53c80440, 0x53ca0101, 0x53cb1440,\n    0x53d50130, 0x53d58130, 0x53d60130, 0x53d68130,\n    0x53d70130, 0x53d80130, 0x53d88130, 0x53d90130,\n    0x53d98131, 0x53da1040, 0x53e20131, 0x53e28130,\n    0x53e30130, 0x53e38440, 0x53e58130, 0x53e61040,\n    0x53ee0130, 0x53fa8240, 0x55a98101, 0x55b85020,\n    0x7d8001b2, 0x7d8081b2, 0x7d8101b2, 0x7d8181da,\n    0x7d8201da, 0x7d8281b3, 0x7d8301b3, 0x7d8981bb,\n    0x7d8a01bb, 0x7d8a81bb, 0x7d8b01bc, 0x7d8b81bb,\n    0x7f909a31, 0x7fa09a01, 0x82002831, 0x82142801,\n    0x82582431, 0x826c2401, 0x82b80b31, 0x82be0f31,\n    0x82c60731, 0x82ca0231, 0x82cb8b01, 0x82d18f01,\n    0x82d98701, 0x82dd8201, 0x86403331, 0x86603301,\n    0x86a81631, 0x86b81601, 0x8c502031, 0x8c602001,\n    0xb7202031, 0xb7302001, 0xb7501931, 0xb75d9901,\n    0xf4802231, 0xf4912201,\n};\n\nstatic const uint8_t case_conv_table2[378] = {\n    0x01, 0x00, 0x9c, 0x06, 0x07, 0x4d, 0x03, 0x04,\n    0x10, 0x00, 0x8f, 0x0b, 0x00, 0x00, 0x11, 0x00,\n    0x08, 0x00, 0x53, 0x4b, 0x52, 0x00, 0x53, 0x00,\n    0x54, 0x00, 0x3b, 0x55, 0x56, 0x00, 0x58, 0x5a,\n    0x40, 0x5f, 0x5e, 0x00, 0x47, 0x50, 0x63, 0x65,\n    0x43, 0x66, 0x00, 0x68, 0x00, 0x6a, 0x00, 0x6c,\n    0x00, 0x6e, 0x00, 0x70, 0x00, 0x00, 0x41, 0x00,\n    0x00, 0x00, 0x00, 0x1a, 0x00, 0x93, 0x00, 0x00,\n    0x20, 0x36, 0x00, 0x28, 0x00, 0x24, 0x00, 0x24,\n    0x25, 0x2d, 0x00, 0x13, 0x6d, 0x6f, 0x00, 0x29,\n    0x27, 0x2a, 0x14, 0x16, 0x18, 0x1b, 0x1c, 0x41,\n    0x1e, 0x42, 0x1f, 0x4e, 0x3c, 0x40, 0x22, 0x21,\n    0x44, 0x21, 0x43, 0x26, 0x28, 0x27, 0x29, 0x23,\n    0x2b, 0x4b, 0x2d, 0x46, 0x2f, 0x4c, 0x31, 0x4d,\n    0x33, 0x47, 0x45, 0x99, 0x00, 0x00, 0x97, 0x91,\n    0x7f, 0x80, 0x85, 0x86, 0x12, 0x82, 0x84, 0x78,\n    0x79, 0x12, 0x7d, 0xa3, 0x7e, 0x7a, 0x7b, 0x8c,\n    0x92, 0x98, 0xa6, 0xa0, 0x87, 0x00, 0x9a, 0xa1,\n    0x95, 0x77, 0x33, 0x95, 0x00, 0x90, 0x00, 0x76,\n    0x9b, 0x9a, 0x99, 0x98, 0x00, 0x00, 0xa0, 0x00,\n    0x9e, 0x00, 0xa3, 0xa2, 0x15, 0x31, 0x32, 0x33,\n    0xb7, 0xb8, 0x53, 0xac, 0xab, 0x12, 0x14, 0x1e,\n    0x21, 0x22, 0x22, 0x2a, 0x34, 0x35, 0x00, 0xa8,\n    0xa9, 0x39, 0x22, 0x4c, 0x00, 0x00, 0x97, 0x01,\n    0x5a, 0xda, 0x1d, 0x36, 0x05, 0x00, 0xc7, 0xc6,\n    0xc9, 0xc8, 0xcb, 0xca, 0xcd, 0xcc, 0xcf, 0xce,\n    0xc4, 0xd8, 0x45, 0xd9, 0x42, 0xda, 0x46, 0xdb,\n    0xd1, 0xd3, 0xd5, 0xd7, 0xdd, 0xdc, 0xf1, 0xf9,\n    0x01, 0x11, 0x0a, 0x12, 0x80, 0x9f, 0x00, 0x21,\n    0x80, 0xa3, 0xf0, 0x00, 0xc0, 0x40, 0xc6, 0x60,\n    0xea, 0xde, 0xe6, 0x99, 0xc0, 0x00, 0x00, 0x06,\n    0x60, 0xdf, 0x29, 0x00, 0x15, 0x12, 0x06, 0x16,\n    0xfb, 0xe0, 0x09, 0x15, 0x12, 0x84, 0x0b, 0xc6,\n    0x16, 0x02, 0xe2, 0x06, 0xc0, 0x40, 0x00, 0x46,\n    0x60, 0xe1, 0xe3, 0x6d, 0x37, 0x38, 0x39, 0x18,\n    0x17, 0x1a, 0x19, 0x00, 0x1d, 0x1c, 0x1f, 0x1e,\n    0x00, 0x61, 0xba, 0x67, 0x45, 0x48, 0x00, 0x50,\n    0x64, 0x4f, 0x51, 0x00, 0x00, 0x49, 0x00, 0x00,\n    0x00, 0xa5, 0xa6, 0xa7, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0xb9, 0x00, 0x00, 0x5c, 0x00, 0x4a, 0x00,\n    0x5d, 0x57, 0x59, 0x62, 0x60, 0x72, 0x6b, 0x71,\n    0x52, 0x00, 0x3e, 0x69, 0xbb, 0x00, 0x5b, 0x00,\n    0x25, 0x00, 0x48, 0xaa, 0x8a, 0x8b, 0x8c, 0xab,\n    0xac, 0x58, 0x58, 0xaf, 0x94, 0xb0, 0x6f, 0xb2,\n    0x61, 0x60, 0x63, 0x62, 0x65, 0x64, 0x6a, 0x6b,\n    0x6c, 0x6d, 0x66, 0x67, 0x68, 0x69, 0x6f, 0x6e,\n    0x71, 0x70, 0x73, 0x72, 0x75, 0x74, 0x77, 0x76,\n    0x79, 0x78,\n};\n\nstatic const uint16_t case_conv_ext[58] = {\n    0x0399, 0x0308, 0x0301, 0x03a5, 0x0313, 0x0300, 0x0342, 0x0391,\n    0x0397, 0x03a9, 0x0046, 0x0049, 0x004c, 0x0053, 0x0069, 0x0307,\n    0x02bc, 0x004e, 0x004a, 0x030c, 0x0535, 0x0552, 0x0048, 0x0331,\n    0x0054, 0x0057, 0x030a, 0x0059, 0x0041, 0x02be, 0x1f08, 0x1f80,\n    0x1f28, 0x1f90, 0x1f68, 0x1fa0, 0x1fba, 0x0386, 0x1fb3, 0x1fca,\n    0x0389, 0x1fc3, 0x03a1, 0x1ffa, 0x038f, 0x1ff3, 0x0544, 0x0546,\n    0x053b, 0x054e, 0x053d, 0x03b8, 0x0462, 0xa64a, 0x1e60, 0x03c9,\n    0x006b, 0x00e5,\n};\n\nstatic const uint8_t unicode_prop_Cased1_table[190] = {\n    0x40, 0xa9, 0x80, 0x8e, 0x80, 0xfc, 0x80, 0xd3,\n    0x80, 0x9b, 0x81, 0x8d, 0x02, 0x80, 0xe1, 0x80,\n    0x91, 0x85, 0x9a, 0x01, 0x00, 0x01, 0x11, 0x03,\n    0x04, 0x08, 0x01, 0x08, 0x30, 0x08, 0x01, 0x15,\n    0x20, 0x01, 0x31, 0x99, 0x31, 0x9d, 0x84, 0x40,\n    0x94, 0x80, 0xd6, 0x82, 0xa6, 0x80, 0x41, 0x62,\n    0x80, 0xa6, 0x80, 0x4b, 0x72, 0x80, 0x4c, 0x02,\n    0xf8, 0x02, 0x80, 0x8f, 0x80, 0xb0, 0x40, 0xdb,\n    0x08, 0x80, 0x41, 0xd0, 0x80, 0x8c, 0x80, 0x8f,\n    0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00, 0x14, 0x28,\n    0x10, 0x11, 0x02, 0x01, 0x18, 0x0b, 0x24, 0x4b,\n    0x26, 0x01, 0x01, 0x86, 0xe5, 0x80, 0x60, 0x79,\n    0xb6, 0x81, 0x40, 0x91, 0x81, 0xbd, 0x88, 0x94,\n    0x05, 0x80, 0x98, 0x80, 0xc0, 0x1a, 0x82, 0x43,\n    0x34, 0xa2, 0x06, 0x80, 0x8d, 0x60, 0x5c, 0x15,\n    0x01, 0x10, 0xa9, 0x80, 0x88, 0x60, 0xcc, 0x44,\n    0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b, 0x80,\n    0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f, 0x06,\n    0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80, 0x41,\n    0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e, 0x80,\n    0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e, 0x80,\n    0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47, 0x33,\n    0x89, 0x80, 0x93, 0x2d, 0x41, 0x04, 0xbd, 0x50,\n    0xc1, 0x99, 0x85, 0x99, 0x85, 0x99,\n};\n\nstatic const uint8_t unicode_prop_Cased1_index[18] = {\n    0xb9, 0x02, 0x80,  //  002B9 at 36\n    0xa0, 0x1e, 0x40,  //  01EA0 at 66\n    0x9e, 0xa6, 0x40,  //  0A69E at 98\n    0x55, 0xd4, 0x21,  //  1D455 at 129\n    0x15, 0xd7, 0x21,  //  1D715 at 161\n    0x8a, 0xf1, 0x01,  //  1F18A at 192 (upper bound)\n};\n\nstatic const uint8_t unicode_prop_Case_Ignorable_table[785] = {\n    0xa6, 0x05, 0x80, 0x8a, 0x80, 0xa2, 0x00, 0x80,\n    0xc6, 0x03, 0x00, 0x03, 0x01, 0x81, 0x41, 0xf6,\n    0x40, 0xbf, 0x19, 0x18, 0x88, 0x08, 0x80, 0x40,\n    0xfa, 0x86, 0x40, 0xce, 0x04, 0x80, 0xb0, 0xac,\n    0x00, 0x01, 0x01, 0x00, 0xab, 0x80, 0x8a, 0x85,\n    0x89, 0x8a, 0x00, 0xa2, 0x80, 0x89, 0x94, 0x8f,\n    0x80, 0xe4, 0x38, 0x89, 0x03, 0xa0, 0x00, 0x80,\n    0x9d, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0x18, 0x08,\n    0x97, 0x97, 0xaa, 0x82, 0xab, 0x06, 0x0c, 0x88,\n    0xa8, 0xb9, 0xb6, 0x00, 0x03, 0x3b, 0x02, 0x86,\n    0x89, 0x81, 0x8c, 0x80, 0x8e, 0x80, 0xb9, 0x03,\n    0x1f, 0x80, 0x93, 0x81, 0x99, 0x01, 0x81, 0xb8,\n    0x03, 0x0b, 0x09, 0x12, 0x80, 0x9d, 0x0a, 0x80,\n    0x8a, 0x81, 0xb8, 0x03, 0x20, 0x0b, 0x80, 0x93,\n    0x81, 0x95, 0x28, 0x80, 0xb9, 0x01, 0x00, 0x1f,\n    0x06, 0x81, 0x8a, 0x81, 0x9d, 0x80, 0xbc, 0x80,\n    0x8b, 0x80, 0xb1, 0x02, 0x80, 0xb6, 0x00, 0x14,\n    0x10, 0x1e, 0x81, 0x8a, 0x81, 0x9c, 0x80, 0xb9,\n    0x01, 0x05, 0x04, 0x81, 0x93, 0x81, 0x9b, 0x81,\n    0xb8, 0x0b, 0x1f, 0x80, 0x93, 0x81, 0x9c, 0x80,\n    0xc7, 0x06, 0x10, 0x80, 0xd9, 0x01, 0x86, 0x8a,\n    0x88, 0xe1, 0x01, 0x88, 0x88, 0x00, 0x86, 0xc8,\n    0x81, 0x9a, 0x00, 0x00, 0x80, 0xb6, 0x8d, 0x04,\n    0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88, 0x80, 0xe5,\n    0x18, 0x28, 0x09, 0x81, 0x98, 0x0b, 0x82, 0x8f,\n    0x83, 0x8c, 0x01, 0x0d, 0x80, 0x8e, 0x80, 0xdd,\n    0x80, 0x42, 0x5f, 0x82, 0x43, 0xb1, 0x82, 0x9c,\n    0x81, 0x9d, 0x81, 0x9d, 0x81, 0xbf, 0x08, 0x37,\n    0x01, 0x8a, 0x10, 0x20, 0xac, 0x84, 0xb2, 0x80,\n    0xc0, 0x81, 0xa1, 0x80, 0xf5, 0x13, 0x81, 0x88,\n    0x05, 0x82, 0x40, 0xda, 0x09, 0x80, 0xb9, 0x00,\n    0x30, 0x00, 0x01, 0x3d, 0x89, 0x08, 0xa6, 0x07,\n    0xad, 0x81, 0x8b, 0x93, 0x83, 0xaf, 0x00, 0x20,\n    0x04, 0x80, 0xa7, 0x88, 0x8b, 0x81, 0x9f, 0x19,\n    0x08, 0x82, 0xb7, 0x00, 0x0a, 0x00, 0x82, 0xb9,\n    0x39, 0x81, 0xbf, 0x85, 0xd1, 0x10, 0x8c, 0x06,\n    0x18, 0x28, 0x11, 0xb1, 0xbe, 0x8c, 0x80, 0xa1,\n    0xe4, 0x41, 0xbc, 0x00, 0x82, 0x8a, 0x82, 0x8c,\n    0x82, 0x8c, 0x82, 0x8c, 0x81, 0x8b, 0x27, 0x81,\n    0x89, 0x01, 0x01, 0x84, 0xb0, 0x20, 0x89, 0x00,\n    0x8c, 0x80, 0x8f, 0x8c, 0xb2, 0xa0, 0x4b, 0x8a,\n    0x81, 0xf0, 0x82, 0xfc, 0x80, 0x8e, 0x80, 0xdf,\n    0x9f, 0xae, 0x80, 0x41, 0xd4, 0x80, 0xa3, 0x1a,\n    0x24, 0x80, 0xdc, 0x85, 0xdc, 0x82, 0x60, 0x6f,\n    0x15, 0x80, 0x44, 0xe1, 0x85, 0x41, 0x0d, 0x80,\n    0xe1, 0x18, 0x89, 0x00, 0x9b, 0x83, 0xcf, 0x81,\n    0x8d, 0xa1, 0xcd, 0x80, 0x96, 0x82, 0xe5, 0x1a,\n    0x0f, 0x02, 0x03, 0x80, 0x98, 0x0c, 0x80, 0x40,\n    0x96, 0x81, 0x99, 0x91, 0x8c, 0x80, 0xa5, 0x87,\n    0x98, 0x8a, 0xad, 0x82, 0xaf, 0x01, 0x19, 0x81,\n    0x90, 0x80, 0x94, 0x81, 0xc1, 0x29, 0x09, 0x81,\n    0x8b, 0x07, 0x80, 0xa2, 0x80, 0x8a, 0x80, 0xb2,\n    0x00, 0x11, 0x0c, 0x08, 0x80, 0x9a, 0x80, 0x8d,\n    0x0c, 0x08, 0x80, 0xe3, 0x84, 0x88, 0x82, 0xf8,\n    0x01, 0x03, 0x80, 0x60, 0x4f, 0x2f, 0x80, 0x40,\n    0x92, 0x90, 0x42, 0x3c, 0x8f, 0x10, 0x8b, 0x8f,\n    0xa1, 0x01, 0x80, 0x40, 0xa8, 0x06, 0x05, 0x80,\n    0x8a, 0x80, 0xa2, 0x00, 0x80, 0xae, 0x80, 0xac,\n    0x81, 0xc2, 0x80, 0x94, 0x82, 0x42, 0x00, 0x80,\n    0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x44, 0x04,\n    0x28, 0xa9, 0x80, 0x88, 0x42, 0x45, 0x10, 0x0c,\n    0x83, 0xa7, 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42,\n    0x3c, 0x83, 0xa5, 0x80, 0x99, 0x20, 0x80, 0x41,\n    0x3a, 0x81, 0x97, 0x80, 0xb3, 0x85, 0xc5, 0x8a,\n    0xb0, 0x83, 0xfa, 0x80, 0xb5, 0x8e, 0xa8, 0x01,\n    0x81, 0x89, 0x82, 0xb0, 0x19, 0x09, 0x03, 0x80,\n    0x89, 0x80, 0xb1, 0x82, 0xa3, 0x20, 0x87, 0xbd,\n    0x80, 0x8b, 0x81, 0xb3, 0x88, 0x89, 0x19, 0x80,\n    0xde, 0x11, 0x00, 0x0d, 0x01, 0x80, 0x40, 0x9c,\n    0x02, 0x87, 0x94, 0x81, 0xb8, 0x0a, 0x80, 0xa4,\n    0x32, 0x84, 0xc5, 0x85, 0x8c, 0x00, 0x00, 0x80,\n    0x8d, 0x81, 0xd4, 0x39, 0x10, 0x80, 0x96, 0x80,\n    0xd3, 0x28, 0x03, 0x08, 0x81, 0x40, 0xed, 0x1d,\n    0x08, 0x81, 0x9a, 0x81, 0xd4, 0x39, 0x00, 0x81,\n    0xe9, 0x00, 0x01, 0x28, 0x80, 0xe4, 0x00, 0x01,\n    0x18, 0x84, 0x41, 0x02, 0x88, 0x01, 0x40, 0xff,\n    0x08, 0x03, 0x80, 0x40, 0x8f, 0x19, 0x0b, 0x80,\n    0x9f, 0x89, 0xa7, 0x29, 0x1f, 0x80, 0x88, 0x29,\n    0x82, 0xad, 0x8c, 0x01, 0x40, 0xc5, 0x00, 0x10,\n    0x80, 0x40, 0xc8, 0x30, 0x28, 0x80, 0xd1, 0x95,\n    0x0e, 0x01, 0x01, 0xf9, 0x2a, 0x00, 0x08, 0x30,\n    0x80, 0xc7, 0x0a, 0x00, 0x80, 0xc0, 0x80, 0x41,\n    0x18, 0x81, 0x8a, 0x81, 0xb3, 0x24, 0x00, 0x80,\n    0x96, 0x80, 0x54, 0xd4, 0x90, 0x85, 0x8e, 0x60,\n    0x2c, 0xc7, 0x8b, 0x12, 0x49, 0xbf, 0x84, 0xba,\n    0x86, 0x88, 0x83, 0x41, 0xfb, 0x82, 0xa7, 0x81,\n    0x41, 0xe1, 0x80, 0xbe, 0x90, 0xbf, 0x08, 0x81,\n    0x8c, 0x81, 0x60, 0x3f, 0xfb, 0x18, 0x30, 0x81,\n    0x4c, 0x9d, 0x08, 0x83, 0x52, 0x5b, 0xad, 0x81,\n    0x96, 0x42, 0x1f, 0x82, 0x88, 0x8f, 0x0e, 0x9d,\n    0x83, 0x40, 0x93, 0x82, 0x47, 0xba, 0xb6, 0x83,\n    0xb1, 0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45,\n    0x4f, 0x30, 0x90, 0x0e, 0x01, 0x04, 0x84, 0xbd,\n    0xa0, 0x80, 0x40, 0x9f, 0x8d, 0x41, 0x6f, 0x80,\n    0xbc, 0x83, 0x41, 0xfa, 0x84, 0x40, 0xfd, 0x81,\n    0x40, 0xf2, 0x01, 0x06, 0x0c, 0x80, 0x88, 0x80,\n    0x41, 0xcf, 0x86, 0xec, 0x87, 0x4a, 0xae, 0x84,\n    0x6c, 0x0c, 0x00, 0x80, 0x9d, 0xdf, 0xff, 0x40,\n    0xef,\n};\n\nstatic const uint8_t unicode_prop_Case_Ignorable_index[75] = {\n    0xbe, 0x05, 0x00,  //  005BE at 32\n    0xfe, 0x07, 0x00,  //  007FE at 64\n    0x52, 0x0a, 0xa0,  //  00A52 at 101\n    0xc1, 0x0b, 0x00,  //  00BC1 at 128\n    0x82, 0x0d, 0x00,  //  00D82 at 160\n    0x3f, 0x10, 0x80,  //  0103F at 196\n    0xd4, 0x17, 0x40,  //  017D4 at 226\n    0xde, 0x1a, 0x20,  //  01ADE at 257\n    0xe9, 0x1c, 0x00,  //  01CE9 at 288\n    0x72, 0x20, 0x00,  //  02072 at 320\n    0x16, 0xa0, 0x40,  //  0A016 at 354\n    0xc6, 0xa8, 0x40,  //  0A8C6 at 386\n    0xc2, 0xaa, 0xa0,  //  0AAC2 at 421\n    0x30, 0xfe, 0x00,  //  0FE30 at 448\n    0xb1, 0x07, 0x41,  //  107B1 at 482\n    0x51, 0x0f, 0x01,  //  10F51 at 512\n    0xd0, 0x11, 0x01,  //  111D0 at 544\n    0x5f, 0x14, 0x01,  //  1145F at 576\n    0x44, 0x19, 0x61,  //  11944 at 611\n    0xa8, 0x1c, 0x01,  //  11CA8 at 640\n    0x2a, 0x61, 0x61,  //  1612A at 675\n    0xff, 0xaf, 0x01,  //  1AFFF at 704\n    0x19, 0xe0, 0x61,  //  1E019 at 739\n    0x00, 0xe7, 0x01,  //  1E700 at 768\n    0xf0, 0x01, 0x0e,  //  E01F0 at 800 (upper bound)\n};\n\nstatic const uint8_t unicode_prop_ID_Start_table[1146] = {\n    0xc0, 0x99, 0x85, 0x99, 0xae, 0x80, 0x89, 0x03,\n    0x04, 0x96, 0x80, 0x9e, 0x80, 0x41, 0xc9, 0x83,\n    0x8b, 0x8d, 0x26, 0x00, 0x80, 0x40, 0x80, 0x20,\n    0x09, 0x18, 0x05, 0x00, 0x10, 0x00, 0x93, 0x80,\n    0xd2, 0x80, 0x40, 0x8a, 0x87, 0x40, 0xa5, 0x80,\n    0xa5, 0x08, 0x85, 0xa8, 0xc6, 0x9a, 0x1b, 0xac,\n    0xaa, 0xa2, 0x08, 0xe2, 0x00, 0x8e, 0x0e, 0x81,\n    0x89, 0x11, 0x80, 0x8f, 0x00, 0x9d, 0x9c, 0xd8,\n    0x8a, 0x80, 0x97, 0xa0, 0x88, 0x0b, 0x04, 0x95,\n    0x18, 0x88, 0x02, 0x80, 0x96, 0x98, 0x86, 0x8a,\n    0x84, 0x97, 0x06, 0x8f, 0xa9, 0xb9, 0xb5, 0x10,\n    0x91, 0x06, 0x89, 0x8e, 0x8f, 0x1f, 0x09, 0x81,\n    0x95, 0x06, 0x00, 0x13, 0x10, 0x8f, 0x80, 0x8c,\n    0x08, 0x82, 0x8d, 0x81, 0x89, 0x07, 0x2b, 0x09,\n    0x95, 0x06, 0x01, 0x01, 0x01, 0x9e, 0x18, 0x80,\n    0x92, 0x82, 0x8f, 0x88, 0x02, 0x80, 0x95, 0x06,\n    0x01, 0x04, 0x10, 0x91, 0x80, 0x8e, 0x81, 0x96,\n    0x80, 0x8a, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04,\n    0x10, 0x9d, 0x08, 0x82, 0x8e, 0x80, 0x90, 0x00,\n    0x2a, 0x10, 0x1a, 0x08, 0x00, 0x0a, 0x0a, 0x12,\n    0x8b, 0x95, 0x80, 0xb3, 0x38, 0x10, 0x96, 0x80,\n    0x8f, 0x10, 0x99, 0x10, 0x09, 0x81, 0x9d, 0x03,\n    0x38, 0x10, 0x96, 0x80, 0x89, 0x04, 0x10, 0x9d,\n    0x10, 0x81, 0x8e, 0x81, 0x90, 0x88, 0x02, 0x80,\n    0xa8, 0x08, 0x8f, 0x04, 0x17, 0x82, 0x97, 0x2c,\n    0x91, 0x82, 0x97, 0x80, 0x88, 0x00, 0x0e, 0xb9,\n    0xaf, 0x01, 0x8b, 0x86, 0xb9, 0x08, 0x00, 0x20,\n    0x97, 0x00, 0x80, 0x89, 0x01, 0x88, 0x01, 0x20,\n    0x80, 0x94, 0x83, 0x9f, 0x80, 0xbe, 0x38, 0xa3,\n    0x9a, 0x84, 0xf2, 0xaa, 0x93, 0x80, 0x8f, 0x2b,\n    0x1a, 0x02, 0x0e, 0x13, 0x8c, 0x8b, 0x80, 0x90,\n    0xa5, 0x00, 0x20, 0x81, 0xaa, 0x80, 0x41, 0x4c,\n    0x03, 0x0e, 0x00, 0x03, 0x81, 0xa8, 0x03, 0x81,\n    0xa0, 0x03, 0x0e, 0x00, 0x03, 0x81, 0x8e, 0x80,\n    0xb8, 0x03, 0x81, 0xc2, 0xa4, 0x8f, 0x8f, 0xd5,\n    0x0d, 0x82, 0x42, 0x6b, 0x81, 0x90, 0x80, 0x99,\n    0x84, 0xca, 0x82, 0x8a, 0x86, 0x91, 0x8c, 0x92,\n    0x8d, 0x91, 0x8d, 0x8c, 0x02, 0x8e, 0xb3, 0xa2,\n    0x03, 0x80, 0xc2, 0xd8, 0x86, 0xa8, 0x00, 0x84,\n    0xc5, 0x89, 0x9e, 0xb0, 0x9d, 0x0c, 0x8a, 0xab,\n    0x83, 0x99, 0xb5, 0x96, 0x88, 0xb4, 0xd1, 0x80,\n    0xdc, 0xae, 0x90, 0x87, 0xb5, 0x9d, 0x8c, 0x81,\n    0x89, 0xab, 0x99, 0xa3, 0xa8, 0x82, 0x89, 0xa3,\n    0x81, 0x8a, 0x84, 0xaa, 0x0a, 0xa8, 0x18, 0x28,\n    0x0a, 0x04, 0x40, 0xbf, 0xbf, 0x41, 0x15, 0x0d,\n    0x81, 0xa5, 0x0d, 0x0f, 0x00, 0x00, 0x00, 0x80,\n    0x9e, 0x81, 0xb4, 0x06, 0x00, 0x12, 0x06, 0x13,\n    0x0d, 0x83, 0x8c, 0x22, 0x06, 0xf3, 0x80, 0x8c,\n    0x80, 0x8f, 0x8c, 0xe4, 0x03, 0x01, 0x89, 0x00,\n    0x0d, 0x28, 0x00, 0x00, 0x80, 0x8f, 0x0b, 0x24,\n    0x18, 0x90, 0xa8, 0x4a, 0x76, 0x40, 0xe4, 0x2b,\n    0x11, 0x8b, 0xa5, 0x00, 0x20, 0x81, 0xb7, 0x30,\n    0x8f, 0x96, 0x88, 0x30, 0x30, 0x30, 0x30, 0x30,\n    0x30, 0x30, 0x86, 0x42, 0x25, 0x82, 0x98, 0x88,\n    0x34, 0x0c, 0x83, 0xd5, 0x1c, 0x80, 0xd9, 0x03,\n    0x84, 0xaa, 0x80, 0xdd, 0x90, 0x9f, 0xaf, 0x8f,\n    0x41, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x56, 0x8c,\n    0xc2, 0xad, 0x81, 0x41, 0x0c, 0x82, 0x8f, 0x89,\n    0x81, 0x93, 0xae, 0x8f, 0x9e, 0x81, 0xcf, 0xa6,\n    0x88, 0x81, 0xe6, 0x81, 0xd1, 0x93, 0x90, 0x02,\n    0x03, 0x80, 0x96, 0x9c, 0xb3, 0x8d, 0xb1, 0xbd,\n    0x2a, 0x00, 0x81, 0x8a, 0x9b, 0x89, 0x96, 0x98,\n    0x9c, 0x86, 0xae, 0x9b, 0x80, 0x8f, 0x20, 0x89,\n    0x89, 0x20, 0xa8, 0x96, 0x10, 0x87, 0x93, 0x96,\n    0x10, 0x82, 0xb1, 0x00, 0x11, 0x0c, 0x08, 0x00,\n    0x97, 0x11, 0x8a, 0x32, 0x8b, 0x29, 0x29, 0x85,\n    0x88, 0x30, 0x30, 0xaa, 0x80, 0x8d, 0x85, 0xf2,\n    0x9c, 0x60, 0x2b, 0xa3, 0x8b, 0x96, 0x83, 0xb0,\n    0x60, 0x21, 0x03, 0x41, 0x6d, 0x81, 0xe9, 0xa5,\n    0x86, 0x8b, 0x24, 0x00, 0x89, 0x80, 0x8c, 0x04,\n    0x00, 0x01, 0x01, 0x80, 0xeb, 0xa0, 0x41, 0x6a,\n    0x91, 0xbf, 0x81, 0xb5, 0xa7, 0x8b, 0xf3, 0x20,\n    0x40, 0x86, 0xa3, 0x99, 0x85, 0x99, 0x8a, 0xd8,\n    0x15, 0x0d, 0x0d, 0x0a, 0xa2, 0x8b, 0x80, 0x99,\n    0x80, 0x92, 0x01, 0x80, 0x8e, 0x81, 0x8d, 0xa1,\n    0xfa, 0xc4, 0xb4, 0x41, 0x0a, 0x9c, 0x82, 0xb0,\n    0xae, 0x9f, 0x8c, 0x9d, 0x84, 0xa5, 0x89, 0x9d,\n    0x81, 0xa3, 0x1f, 0x04, 0xa9, 0x40, 0x9d, 0x91,\n    0xa3, 0x83, 0xa3, 0x83, 0xa7, 0x87, 0xb3, 0x8b,\n    0x8a, 0x80, 0x8e, 0x06, 0x01, 0x80, 0x8a, 0x80,\n    0x8e, 0x06, 0x01, 0x82, 0xb3, 0x8b, 0x41, 0x36,\n    0x88, 0x95, 0x89, 0x87, 0x97, 0x28, 0xa9, 0x80,\n    0x88, 0xc4, 0x29, 0x00, 0xab, 0x01, 0x10, 0x81,\n    0x96, 0x89, 0x96, 0x88, 0x9e, 0xc0, 0x92, 0x01,\n    0x89, 0x95, 0x89, 0x99, 0x85, 0x99, 0xa5, 0xb7,\n    0x29, 0xbf, 0x80, 0x8e, 0x18, 0x10, 0x9c, 0xa9,\n    0x9c, 0x82, 0x9c, 0xa2, 0x38, 0x9b, 0x9a, 0xb5,\n    0x89, 0x95, 0x89, 0x92, 0x8c, 0x91, 0xed, 0xc8,\n    0xb6, 0xb2, 0x8c, 0xb2, 0x8c, 0xa3, 0xa5, 0x9b,\n    0x88, 0x96, 0x40, 0xf9, 0xa9, 0x29, 0x8f, 0x85,\n    0xb7, 0x9c, 0x89, 0x07, 0x95, 0xa9, 0x91, 0xad,\n    0x94, 0x9a, 0x96, 0x8b, 0xb4, 0xb8, 0x09, 0x80,\n    0x8c, 0xac, 0x9f, 0x98, 0x99, 0xa3, 0x9c, 0x01,\n    0x07, 0xa2, 0x10, 0x8b, 0xaf, 0x8d, 0x83, 0x94,\n    0x00, 0x80, 0xa2, 0x91, 0x80, 0x98, 0x92, 0x81,\n    0xbe, 0x30, 0x00, 0x18, 0x8e, 0x80, 0x89, 0x86,\n    0xae, 0xa5, 0x39, 0x09, 0x95, 0x06, 0x01, 0x04,\n    0x10, 0x91, 0x80, 0x8b, 0x84, 0x9d, 0x89, 0x00,\n    0x08, 0x80, 0xa5, 0x00, 0x98, 0x00, 0x80, 0xab,\n    0xb4, 0x91, 0x83, 0x93, 0x82, 0x9d, 0xaf, 0x93,\n    0x08, 0x80, 0x40, 0xb7, 0xae, 0xa8, 0x83, 0xa3,\n    0xaf, 0x93, 0x80, 0xba, 0xaa, 0x8c, 0x80, 0xc6,\n    0x9a, 0xa4, 0x86, 0x40, 0xb8, 0xab, 0xf3, 0xbf,\n    0x9e, 0x39, 0x01, 0x38, 0x08, 0x97, 0x8e, 0x00,\n    0x80, 0xdd, 0x39, 0xa6, 0x8f, 0x00, 0x80, 0x9b,\n    0x80, 0x89, 0xa7, 0x30, 0x94, 0x80, 0x8a, 0xad,\n    0x92, 0x80, 0x91, 0xc8, 0x40, 0xc6, 0xa0, 0x9e,\n    0x88, 0x80, 0xa4, 0x90, 0x80, 0xb0, 0x9d, 0xef,\n    0x30, 0x08, 0xa5, 0x94, 0x80, 0x98, 0x28, 0x08,\n    0x9f, 0x8d, 0x80, 0x96, 0xab, 0x41, 0x03, 0x92,\n    0x8e, 0x00, 0x8c, 0x80, 0xa1, 0xfb, 0x80, 0xce,\n    0x43, 0x99, 0xe5, 0xee, 0x90, 0x40, 0xc3, 0x4a,\n    0x4b, 0xe0, 0x8e, 0x44, 0x2f, 0x90, 0x85, 0x98,\n    0x4f, 0x9a, 0x84, 0x42, 0x46, 0x5a, 0xb8, 0x9d,\n    0x46, 0xe1, 0x42, 0x38, 0x86, 0x9e, 0x90, 0xce,\n    0x90, 0x9d, 0x91, 0xaf, 0x8f, 0x83, 0x9e, 0x94,\n    0x84, 0x92, 0x41, 0xaf, 0xac, 0x40, 0xd2, 0xbf,\n    0x9f, 0x98, 0x81, 0x98, 0xab, 0xca, 0x20, 0xc1,\n    0x8c, 0xbf, 0x08, 0x80, 0x8d, 0x84, 0x88, 0x5c,\n    0xd5, 0xa8, 0x9f, 0xe0, 0xf2, 0x60, 0x21, 0xfc,\n    0x18, 0x30, 0x08, 0x41, 0x22, 0x8e, 0x80, 0x9c,\n    0x11, 0x80, 0x8d, 0x1f, 0x41, 0x8b, 0x49, 0x03,\n    0xea, 0x84, 0x8c, 0x82, 0x88, 0x86, 0x89, 0x57,\n    0x65, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b,\n    0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f,\n    0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80,\n    0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e,\n    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e,\n    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x47,\n    0x33, 0x9e, 0x2d, 0x41, 0x04, 0xbd, 0x40, 0x91,\n    0xac, 0x89, 0x86, 0x8f, 0x80, 0x41, 0x40, 0x9d,\n    0x91, 0xab, 0x41, 0xe3, 0x9b, 0x40, 0xe3, 0x9d,\n    0x08, 0x40, 0xce, 0x9e, 0x02, 0x01, 0x06, 0x0c,\n    0x88, 0x81, 0x40, 0xdf, 0x30, 0x18, 0x08, 0x8e,\n    0x80, 0x40, 0xc4, 0xba, 0xc3, 0x30, 0x44, 0xb3,\n    0x18, 0x9a, 0x01, 0x00, 0x08, 0x80, 0x89, 0x03,\n    0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x02, 0x01,\n    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,\n    0x0b, 0x06, 0x03, 0x03, 0x00, 0x80, 0x89, 0x80,\n    0x90, 0x22, 0x04, 0x80, 0x90, 0x51, 0x43, 0x60,\n    0xa6, 0xdf, 0x9f, 0x51, 0x1d, 0x81, 0x56, 0x8d,\n    0x81, 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x49, 0xa1,\n    0x42, 0x1d, 0x45, 0xe1, 0x53, 0x4a, 0x84, 0x60,\n    0x21, 0x29,\n};\n\nstatic const uint8_t unicode_prop_ID_Start_index[108] = {\n    0xf6, 0x03, 0x20,  //  003F6 at 33\n    0xa6, 0x07, 0x00,  //  007A6 at 64\n    0xa9, 0x09, 0x20,  //  009A9 at 97\n    0xb1, 0x0a, 0x00,  //  00AB1 at 128\n    0xba, 0x0b, 0x20,  //  00BBA at 161\n    0x3b, 0x0d, 0x20,  //  00D3B at 193\n    0xc7, 0x0e, 0x20,  //  00EC7 at 225\n    0x49, 0x12, 0x00,  //  01249 at 256\n    0x9b, 0x16, 0x00,  //  0169B at 288\n    0xac, 0x19, 0x00,  //  019AC at 320\n    0xc0, 0x1d, 0x80,  //  01DC0 at 356\n    0x80, 0x20, 0x20,  //  02080 at 385\n    0x70, 0x2d, 0x00,  //  02D70 at 416\n    0x00, 0x32, 0x00,  //  03200 at 448\n    0x06, 0xa8, 0x00,  //  0A806 at 480\n    0x77, 0xaa, 0x00,  //  0AA77 at 512\n    0xfc, 0xd7, 0x00,  //  0D7FC at 544\n    0xfd, 0xfe, 0x40,  //  0FEFD at 578\n    0xd1, 0x02, 0x01,  //  102D1 at 608\n    0xb2, 0x05, 0x21,  //  105B2 at 641\n    0xf6, 0x08, 0x01,  //  108F6 at 672\n    0x49, 0x0c, 0x01,  //  10C49 at 704\n    0x76, 0x10, 0x01,  //  11076 at 736\n    0xdf, 0x12, 0x21,  //  112DF at 769\n    0xc8, 0x14, 0x41,  //  114C8 at 802\n    0x42, 0x19, 0x21,  //  11942 at 833\n    0x31, 0x1d, 0x61,  //  11D31 at 867\n    0xf1, 0x2f, 0x41,  //  12FF1 at 898\n    0x78, 0x6b, 0x01,  //  16B78 at 928\n    0x23, 0xb1, 0xa1,  //  1B123 at 965\n    0xad, 0xd4, 0x01,  //  1D4AD at 992\n    0x6f, 0xd7, 0x01,  //  1D76F at 1024\n    0xee, 0xe5, 0x01,  //  1E5EE at 1056\n    0x38, 0xee, 0x01,  //  1EE38 at 1088\n    0xe0, 0xa6, 0x42,  //  2A6E0 at 1122\n    0x7a, 0x34, 0x03,  //  3347A at 1152 (upper bound)\n};\n\nstatic const uint8_t unicode_prop_ID_Continue1_table[708] = {\n    0xaf, 0x89, 0xa4, 0x80, 0xd6, 0x80, 0x42, 0x47,\n    0xef, 0x96, 0x80, 0x40, 0xfa, 0x84, 0x41, 0x08,\n    0xac, 0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf,\n    0x9e, 0x28, 0xe4, 0x31, 0x29, 0x08, 0x19, 0x89,\n    0x96, 0x80, 0x9d, 0x9a, 0xda, 0x8a, 0x8e, 0x89,\n    0xa0, 0x88, 0x88, 0x80, 0x97, 0x18, 0x88, 0x02,\n    0x04, 0xaa, 0x82, 0xba, 0x88, 0xa9, 0x97, 0x80,\n    0xa0, 0xb5, 0x10, 0x91, 0x06, 0x89, 0x09, 0x89,\n    0x90, 0x82, 0xb7, 0x00, 0x31, 0x09, 0x82, 0x88,\n    0x80, 0x89, 0x09, 0x89, 0x8d, 0x01, 0x82, 0xb7,\n    0x00, 0x23, 0x09, 0x12, 0x80, 0x93, 0x8b, 0x10,\n    0x8a, 0x82, 0xb7, 0x00, 0x38, 0x10, 0x82, 0x93,\n    0x09, 0x89, 0x89, 0x28, 0x82, 0xb7, 0x00, 0x31,\n    0x09, 0x16, 0x82, 0x89, 0x09, 0x89, 0x91, 0x80,\n    0xba, 0x22, 0x10, 0x83, 0x88, 0x80, 0x8d, 0x89,\n    0x8f, 0x84, 0xb6, 0x00, 0x30, 0x10, 0x1e, 0x81,\n    0x8a, 0x09, 0x89, 0x90, 0x82, 0xb7, 0x00, 0x30,\n    0x10, 0x1e, 0x81, 0x8a, 0x09, 0x89, 0x10, 0x8b,\n    0x83, 0xb6, 0x08, 0x30, 0x10, 0x83, 0x88, 0x80,\n    0x89, 0x09, 0x89, 0x90, 0x82, 0xc5, 0x03, 0x28,\n    0x00, 0x3d, 0x89, 0x09, 0xbc, 0x01, 0x86, 0x8b,\n    0x38, 0x89, 0xd6, 0x01, 0x88, 0x8a, 0x30, 0x89,\n    0xbd, 0x0d, 0x89, 0x8a, 0x00, 0x00, 0x03, 0x81,\n    0xb0, 0x93, 0x01, 0x84, 0x8a, 0x80, 0xa3, 0x88,\n    0x80, 0xe3, 0x93, 0x80, 0x89, 0x8b, 0x1b, 0x10,\n    0x11, 0x32, 0x83, 0x8c, 0x8b, 0x80, 0x8e, 0x42,\n    0xbe, 0x82, 0x88, 0x88, 0x43, 0x9f, 0x83, 0x9b,\n    0x82, 0x9c, 0x81, 0x9d, 0x81, 0xbf, 0x9f, 0x88,\n    0x01, 0x89, 0xa0, 0x10, 0x8a, 0x40, 0x8e, 0x80,\n    0xf5, 0x8b, 0x83, 0x8b, 0x89, 0x89, 0xff, 0x8a,\n    0xbb, 0x84, 0xb8, 0x89, 0x80, 0x9c, 0x81, 0x8a,\n    0x85, 0x89, 0x95, 0x8d, 0x80, 0x9e, 0x81, 0x8b,\n    0x93, 0x84, 0xae, 0x90, 0x8a, 0x89, 0x90, 0x88,\n    0x8b, 0x82, 0x9d, 0x8c, 0x81, 0x89, 0xab, 0x8d,\n    0xaf, 0x93, 0x87, 0x89, 0x85, 0x89, 0xf5, 0x10,\n    0x94, 0x18, 0x28, 0x0a, 0x40, 0xc5, 0xbf, 0x42,\n    0x0b, 0x81, 0xb0, 0x81, 0x92, 0x80, 0xfa, 0x8c,\n    0x18, 0x82, 0x8b, 0x4b, 0xfd, 0x82, 0x40, 0x8c,\n    0x80, 0xdf, 0x9f, 0x42, 0x29, 0x85, 0xe8, 0x81,\n    0xdf, 0x80, 0x60, 0x75, 0x23, 0x89, 0xc4, 0x03,\n    0x89, 0x9f, 0x81, 0xcf, 0x81, 0x41, 0x0f, 0x02,\n    0x03, 0x80, 0x96, 0x23, 0x80, 0xd2, 0x81, 0xb1,\n    0x91, 0x89, 0x89, 0x85, 0x91, 0x8c, 0x8a, 0x9b,\n    0x87, 0x98, 0x8c, 0xab, 0x83, 0xae, 0x8d, 0x8e,\n    0x89, 0x8a, 0x80, 0x89, 0x89, 0xae, 0x8d, 0x8b,\n    0x07, 0x09, 0x89, 0xa0, 0x82, 0xb1, 0x00, 0x11,\n    0x0c, 0x08, 0x80, 0xa8, 0x24, 0x81, 0x40, 0xeb,\n    0x38, 0x09, 0x89, 0x60, 0x4f, 0x23, 0x80, 0x42,\n    0xe0, 0x8f, 0x8f, 0x8f, 0x11, 0x97, 0x82, 0x40,\n    0xbf, 0x89, 0xa4, 0x80, 0xa4, 0x80, 0x42, 0x96,\n    0x80, 0x40, 0xe1, 0x80, 0x40, 0x94, 0x84, 0x41,\n    0x24, 0x89, 0x45, 0x56, 0x10, 0x0c, 0x83, 0xa7,\n    0x13, 0x80, 0x40, 0xa4, 0x81, 0x42, 0x3c, 0x1f,\n    0x89, 0x85, 0x89, 0x9e, 0x84, 0x41, 0x3c, 0x81,\n    0xcc, 0x85, 0xc5, 0x8a, 0xb0, 0x83, 0xf9, 0x82,\n    0xb4, 0x8e, 0x9e, 0x8a, 0x09, 0x89, 0x83, 0xac,\n    0x8a, 0x30, 0xac, 0x89, 0x2a, 0xa3, 0x8d, 0x80,\n    0x89, 0x21, 0xab, 0x80, 0x8b, 0x82, 0xaf, 0x8d,\n    0x3b, 0x80, 0x8b, 0xd1, 0x8b, 0x28, 0x08, 0x40,\n    0x9c, 0x8b, 0x84, 0x89, 0x2b, 0xb6, 0x08, 0x31,\n    0x09, 0x82, 0x88, 0x80, 0x89, 0x09, 0x32, 0x84,\n    0xc2, 0x88, 0x00, 0x08, 0x03, 0x04, 0x00, 0x8d,\n    0x81, 0xd1, 0x91, 0x88, 0x89, 0x18, 0xd0, 0x93,\n    0x8b, 0x89, 0x40, 0xd4, 0x31, 0x88, 0x9a, 0x81,\n    0xd1, 0x90, 0x8e, 0x89, 0xd0, 0x8c, 0x87, 0x89,\n    0x85, 0x93, 0xb8, 0x8e, 0x83, 0x89, 0x40, 0xf1,\n    0x8e, 0x40, 0xa4, 0x89, 0xc5, 0x28, 0x09, 0x18,\n    0x00, 0x81, 0x8b, 0x89, 0xf6, 0x31, 0x32, 0x80,\n    0x9b, 0x89, 0xa7, 0x30, 0x1f, 0x80, 0x88, 0x8a,\n    0xad, 0x8f, 0x40, 0xc5, 0x87, 0x40, 0x87, 0x89,\n    0xb4, 0x38, 0x87, 0x8f, 0x89, 0xb7, 0x95, 0x80,\n    0x8d, 0xf9, 0x2a, 0x00, 0x08, 0x30, 0x07, 0x89,\n    0xaf, 0x20, 0x08, 0x27, 0x89, 0xb5, 0x89, 0x41,\n    0x08, 0x83, 0x88, 0x08, 0x80, 0xaf, 0x32, 0x84,\n    0x8c, 0x8a, 0x54, 0xe4, 0x05, 0x8e, 0x60, 0x2c,\n    0xc7, 0x9b, 0x49, 0x25, 0x89, 0xd5, 0x89, 0xa5,\n    0x84, 0xba, 0x86, 0x98, 0x89, 0x42, 0x15, 0x89,\n    0x41, 0xd4, 0x00, 0xb6, 0x33, 0xd0, 0x80, 0x8a,\n    0x81, 0x60, 0x4c, 0xaa, 0x81, 0x50, 0x50, 0x89,\n    0x42, 0x05, 0xad, 0x81, 0x96, 0x42, 0x1d, 0x22,\n    0x2f, 0x39, 0x86, 0x9d, 0x83, 0x40, 0x93, 0x82,\n    0x45, 0x88, 0xb1, 0x41, 0xff, 0xb6, 0x83, 0xb1,\n    0x38, 0x8d, 0x80, 0x95, 0x20, 0x8e, 0x45, 0x4f,\n    0x30, 0x90, 0x0e, 0x01, 0x04, 0xe3, 0x80, 0x40,\n    0x9f, 0x86, 0x88, 0x89, 0x41, 0x63, 0x80, 0xbc,\n    0x8d, 0x41, 0xf1, 0x8d, 0x40, 0xf3, 0x08, 0x89,\n    0x40, 0xe7, 0x01, 0x06, 0x0c, 0x80, 0x41, 0xd9,\n    0x86, 0xec, 0x34, 0x89, 0x52, 0x95, 0x89, 0x6c,\n    0x05, 0x05, 0x40, 0xef,\n};\n\nstatic const uint8_t unicode_prop_ID_Continue1_index[66] = {\n    0xfa, 0x06, 0x00,  //  006FA at 32\n    0x70, 0x09, 0x00,  //  00970 at 64\n    0xf0, 0x0a, 0x40,  //  00AF0 at 98\n    0x57, 0x0c, 0x00,  //  00C57 at 128\n    0xf0, 0x0d, 0x60,  //  00DF0 at 163\n    0xc7, 0x0f, 0x20,  //  00FC7 at 193\n    0xea, 0x17, 0x40,  //  017EA at 226\n    0xec, 0x1a, 0x00,  //  01AEC at 256\n    0x0e, 0x20, 0x40,  //  0200E at 290\n    0x7e, 0xa6, 0x20,  //  0A67E at 321\n    0xda, 0xa9, 0x20,  //  0A9DA at 353\n    0x10, 0xfe, 0x40,  //  0FE10 at 386\n    0x40, 0x0a, 0x41,  //  10A40 at 418\n    0xbb, 0x10, 0x21,  //  110BB at 449\n    0x4e, 0x13, 0x41,  //  1134E at 482\n    0xde, 0x15, 0x01,  //  115DE at 512\n    0xe5, 0x19, 0x01,  //  119E5 at 544\n    0x5a, 0x1d, 0x01,  //  11D5A at 576\n    0xf5, 0x6a, 0x21,  //  16AF5 at 609\n    0x8c, 0xd1, 0x61,  //  1D18C at 643\n    0x37, 0xe1, 0x41,  //  1E137 at 674\n    0xf0, 0x01, 0x0e,  //  E01F0 at 704 (upper bound)\n};\n\n#ifdef CONFIG_ALL_UNICODE\n\nstatic const uint8_t unicode_cc_table[937] = {\n    0xb2, 0xcf, 0xd4, 0x00, 0xe8, 0x03, 0xdc, 0x00,\n    0xe8, 0x00, 0xd8, 0x04, 0xdc, 0x01, 0xca, 0x03,\n    0xdc, 0x01, 0xca, 0x0a, 0xdc, 0x04, 0x01, 0x03,\n    0xdc, 0xc7, 0x00, 0xf0, 0xc0, 0x02, 0xdc, 0xc2,\n    0x01, 0xdc, 0x80, 0xc2, 0x03, 0xdc, 0xc0, 0x00,\n    0xe8, 0x01, 0xdc, 0xc0, 0x41, 0xe9, 0x00, 0xea,\n    0x41, 0xe9, 0x00, 0xea, 0x00, 0xe9, 0xcc, 0xb0,\n    0xe2, 0xc4, 0xb0, 0xd8, 0x00, 0xdc, 0xc3, 0x00,\n    0xdc, 0xc2, 0x00, 0xde, 0x00, 0xdc, 0xc5, 0x05,\n    0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xde, 0x00,\n    0xe4, 0xc0, 0x49, 0x0a, 0x43, 0x13, 0x80, 0x00,\n    0x17, 0x80, 0x41, 0x18, 0x80, 0xc0, 0x00, 0xdc,\n    0x80, 0x00, 0x12, 0xb0, 0x17, 0xc7, 0x42, 0x1e,\n    0xaf, 0x47, 0x1b, 0xc1, 0x01, 0xdc, 0xc4, 0x00,\n    0xdc, 0xc1, 0x00, 0xdc, 0x8f, 0x00, 0x23, 0xb0,\n    0x34, 0xc6, 0x81, 0xc3, 0x00, 0xdc, 0xc0, 0x81,\n    0xc1, 0x80, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xa2,\n    0x00, 0x24, 0x9d, 0xc0, 0x00, 0xdc, 0xc1, 0x00,\n    0xdc, 0xc1, 0x02, 0xdc, 0xc0, 0x01, 0xdc, 0xc0,\n    0x00, 0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x00, 0xdc,\n    0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xc1, 0xb0,\n    0x6f, 0xc6, 0x00, 0xdc, 0xc0, 0x88, 0x00, 0xdc,\n    0x97, 0xc3, 0x80, 0xc8, 0x80, 0xc2, 0x80, 0xc4,\n    0xaa, 0x02, 0xdc, 0xb0, 0x0a, 0xc1, 0x02, 0xdc,\n    0xc3, 0xa9, 0xc4, 0x04, 0xdc, 0xcd, 0x80, 0x00,\n    0xdc, 0xc1, 0x00, 0xdc, 0xc1, 0x00, 0xdc, 0xc2,\n    0x02, 0xdc, 0x42, 0x1b, 0xc2, 0x00, 0xdc, 0xc1,\n    0x01, 0xdc, 0xc4, 0xb0, 0x0b, 0x00, 0x07, 0x8f,\n    0x00, 0x09, 0x82, 0xc0, 0x00, 0xdc, 0xc1, 0xb0,\n    0x36, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xaf, 0xc0,\n    0xb0, 0x0c, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0,\n    0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3d,\n    0x00, 0x07, 0x8f, 0x00, 0x09, 0xb0, 0x4e, 0x00,\n    0x09, 0xb0, 0x3d, 0x00, 0x07, 0x8f, 0x00, 0x09,\n    0x86, 0x00, 0x54, 0x00, 0x5b, 0xb0, 0x34, 0x00,\n    0x07, 0x8f, 0x00, 0x09, 0xb0, 0x3c, 0x01, 0x09,\n    0x8f, 0x00, 0x09, 0xb0, 0x4b, 0x00, 0x09, 0xb0,\n    0x3c, 0x01, 0x67, 0x00, 0x09, 0x8c, 0x03, 0x6b,\n    0xb0, 0x3b, 0x01, 0x76, 0x00, 0x09, 0x8c, 0x03,\n    0x7a, 0xb0, 0x1b, 0x01, 0xdc, 0x9a, 0x00, 0xdc,\n    0x80, 0x00, 0xdc, 0x80, 0x00, 0xd8, 0xb0, 0x06,\n    0x41, 0x81, 0x80, 0x00, 0x84, 0x84, 0x03, 0x82,\n    0x81, 0x00, 0x82, 0x80, 0xc1, 0x00, 0x09, 0x80,\n    0xc1, 0xb0, 0x0d, 0x00, 0xdc, 0xb0, 0x3f, 0x00,\n    0x07, 0x80, 0x01, 0x09, 0xb0, 0x21, 0x00, 0xdc,\n    0xb2, 0x9e, 0xc2, 0xb3, 0x83, 0x01, 0x09, 0x9d,\n    0x00, 0x09, 0xb0, 0x6c, 0x00, 0x09, 0x89, 0xc0,\n    0xb0, 0x9a, 0x00, 0xe4, 0xb0, 0x5e, 0x00, 0xde,\n    0xc0, 0x00, 0xdc, 0xb0, 0xaa, 0xc0, 0x00, 0xdc,\n    0xb0, 0x16, 0x00, 0x09, 0x93, 0xc7, 0x81, 0x00,\n    0xdc, 0xaf, 0xc4, 0x05, 0xdc, 0xc1, 0x00, 0xdc,\n    0x80, 0x01, 0xdc, 0xc1, 0x01, 0xdc, 0xc4, 0x00,\n    0xdc, 0xd1, 0x00, 0xdc, 0x81, 0xc5, 0x00, 0xdc,\n    0xc3, 0x00, 0xea, 0xb0, 0x17, 0x00, 0x07, 0x8e,\n    0x00, 0x09, 0xa5, 0xc0, 0x00, 0xdc, 0xc6, 0xb0,\n    0x05, 0x01, 0x09, 0xb0, 0x09, 0x00, 0x07, 0x8a,\n    0x01, 0x09, 0xb0, 0x12, 0x00, 0x07, 0xb0, 0x67,\n    0xc2, 0x41, 0x00, 0x04, 0xdc, 0xc1, 0x03, 0xdc,\n    0xc0, 0x41, 0x00, 0x05, 0x01, 0x83, 0x00, 0xdc,\n    0x85, 0xc0, 0x82, 0xc1, 0xb0, 0x95, 0xc1, 0x00,\n    0xdc, 0xc6, 0x00, 0xdc, 0xc1, 0x00, 0xea, 0x00,\n    0xd6, 0x00, 0xdc, 0x00, 0xca, 0xe4, 0x00, 0xe8,\n    0x01, 0xe4, 0x00, 0xdc, 0x00, 0xda, 0xc0, 0x00,\n    0xe9, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb2, 0x9f,\n    0xc1, 0x01, 0x01, 0xc3, 0x02, 0x01, 0xc1, 0x83,\n    0xc0, 0x82, 0x01, 0x01, 0xc0, 0x00, 0xdc, 0xc0,\n    0x01, 0x01, 0x03, 0xdc, 0xc0, 0xb8, 0x03, 0xcd,\n    0xc2, 0xb0, 0x5c, 0x00, 0x09, 0xb0, 0x2f, 0xdf,\n    0xb1, 0xf9, 0x00, 0xda, 0x00, 0xe4, 0x00, 0xe8,\n    0x00, 0xde, 0x01, 0xe0, 0xb0, 0x38, 0x01, 0x08,\n    0xb8, 0x6d, 0xa3, 0xc0, 0x83, 0xc9, 0x9f, 0xc1,\n    0xb0, 0x1f, 0xc1, 0xb0, 0xe3, 0x00, 0x09, 0xa4,\n    0x00, 0x09, 0xb0, 0x66, 0x00, 0x09, 0x9a, 0xd1,\n    0xb0, 0x08, 0x02, 0xdc, 0xa4, 0x00, 0x09, 0xb0,\n    0x2e, 0x00, 0x07, 0x8b, 0x00, 0x09, 0xb0, 0xbe,\n    0xc0, 0x80, 0xc1, 0x00, 0xdc, 0x81, 0xc1, 0x84,\n    0xc1, 0x80, 0xc0, 0xb0, 0x03, 0x00, 0x09, 0xb0,\n    0xc5, 0x00, 0x09, 0xb8, 0x46, 0xff, 0x00, 0x1a,\n    0xb2, 0xd0, 0xc6, 0x06, 0xdc, 0xc1, 0xb3, 0x9c,\n    0x00, 0xdc, 0xb0, 0xb1, 0x00, 0xdc, 0xb0, 0x64,\n    0xc4, 0xb6, 0x61, 0x00, 0xdc, 0x80, 0xc0, 0xa7,\n    0xc0, 0x00, 0x01, 0x00, 0xdc, 0x83, 0x00, 0x09,\n    0xb0, 0x74, 0xc0, 0x00, 0xdc, 0xb2, 0x0c, 0xc3,\n    0xb0, 0x10, 0xc4, 0xb1, 0x0c, 0xc1, 0xb0, 0x1c,\n    0x01, 0xdc, 0x80, 0x02, 0xdc, 0xb0, 0x15, 0x01,\n    0xdc, 0xc2, 0x00, 0xdc, 0xc0, 0x03, 0xdc, 0xb0,\n    0x00, 0xc0, 0x00, 0xdc, 0xc0, 0x00, 0xdc, 0xb0,\n    0x8f, 0x00, 0x09, 0xa8, 0x00, 0x09, 0x8d, 0x00,\n    0x09, 0xb0, 0x08, 0x00, 0x09, 0x00, 0x07, 0xb0,\n    0x14, 0xc2, 0xaf, 0x01, 0x09, 0xb0, 0x0d, 0x00,\n    0x07, 0xb0, 0x1b, 0x00, 0x09, 0x88, 0x00, 0x07,\n    0xb0, 0x39, 0x00, 0x09, 0x00, 0x07, 0xb0, 0x81,\n    0x00, 0x07, 0x00, 0x09, 0xb0, 0x1f, 0x01, 0x07,\n    0x8f, 0x00, 0x09, 0x97, 0xc6, 0x82, 0xc4, 0xb0,\n    0x28, 0x02, 0x09, 0xb0, 0x40, 0x00, 0x09, 0x82,\n    0x00, 0x07, 0x96, 0xc0, 0xb0, 0x32, 0x00, 0x09,\n    0x00, 0x07, 0xb0, 0xca, 0x00, 0x09, 0x00, 0x07,\n    0xb0, 0x4d, 0x00, 0x09, 0xb0, 0x45, 0x00, 0x09,\n    0x00, 0x07, 0xb0, 0x42, 0x00, 0x09, 0xb0, 0xdc,\n    0x00, 0x09, 0x00, 0x07, 0xb0, 0xd1, 0x01, 0x09,\n    0x83, 0x00, 0x07, 0xb0, 0x6b, 0x00, 0x09, 0xb0,\n    0x22, 0x00, 0x09, 0x91, 0x00, 0x09, 0xb0, 0x20,\n    0x00, 0x09, 0xb1, 0x74, 0x00, 0x09, 0xb0, 0xd1,\n    0x00, 0x07, 0x80, 0x01, 0x09, 0xb0, 0x20, 0x00,\n    0x09, 0xb1, 0x78, 0x01, 0x09, 0xb8, 0x39, 0xbb,\n    0x00, 0x09, 0xb8, 0x01, 0x8f, 0x04, 0x01, 0xb0,\n    0x0a, 0xc6, 0xb4, 0x88, 0x01, 0x06, 0xb8, 0x44,\n    0x7b, 0x00, 0x01, 0xb8, 0x0c, 0x95, 0x01, 0xd8,\n    0x02, 0x01, 0x82, 0x00, 0xe2, 0x04, 0xd8, 0x87,\n    0x07, 0xdc, 0x81, 0xc4, 0x01, 0xdc, 0x9d, 0xc3,\n    0xb0, 0x63, 0xc2, 0xb8, 0x05, 0x8a, 0xc6, 0x80,\n    0xd0, 0x81, 0xc6, 0x80, 0xc1, 0x80, 0xc4, 0xb0,\n    0x33, 0xc0, 0xb0, 0x6f, 0xc6, 0xb1, 0x46, 0xc0,\n    0xb0, 0x0c, 0xc3, 0xb1, 0xcb, 0x01, 0xe8, 0x00,\n    0xdc, 0xc0, 0xb0, 0xcd, 0xc0, 0x00, 0xdc, 0xb0,\n    0xc2, 0xc0, 0x81, 0xc0, 0x86, 0xc1, 0x84, 0xc0,\n    0xb1, 0xa9, 0x06, 0xdc, 0xb0, 0x3c, 0xc5, 0x00,\n    0x07,\n};\n\nstatic const uint8_t unicode_cc_index[90] = {\n    0x4d, 0x03, 0x00,  //  0034D at 32\n    0x97, 0x05, 0x20,  //  00597 at 65\n    0xc6, 0x05, 0x00,  //  005C6 at 96\n    0xe7, 0x06, 0x00,  //  006E7 at 128\n    0x45, 0x07, 0x00,  //  00745 at 160\n    0x9c, 0x08, 0x00,  //  0089C at 192\n    0x4d, 0x09, 0x00,  //  0094D at 224\n    0x3c, 0x0b, 0x00,  //  00B3C at 256\n    0x3d, 0x0d, 0x00,  //  00D3D at 288\n    0x36, 0x0f, 0x00,  //  00F36 at 320\n    0x38, 0x10, 0x20,  //  01038 at 353\n    0x3a, 0x19, 0x00,  //  0193A at 384\n    0xcb, 0x1a, 0x20,  //  01ACB at 417\n    0xf2, 0x1b, 0x00,  //  01BF2 at 448\n    0xc3, 0x1d, 0x20,  //  01DC3 at 481\n    0xd0, 0x20, 0x00,  //  020D0 at 512\n    0x00, 0x2e, 0x00,  //  02E00 at 544\n    0x2c, 0xa8, 0x00,  //  0A82C at 576\n    0xbe, 0xaa, 0x00,  //  0AABE at 608\n    0x76, 0x03, 0x01,  //  10376 at 640\n    0xfa, 0x0e, 0x01,  //  10EFA at 672\n    0x80, 0x10, 0x21,  //  11080 at 705\n    0xe9, 0x12, 0x01,  //  112E9 at 736\n    0xc3, 0x14, 0x01,  //  114C3 at 768\n    0x3f, 0x19, 0x01,  //  1193F at 800\n    0x98, 0x1d, 0x21,  //  11D98 at 833\n    0x67, 0xd1, 0x01,  //  1D167 at 864\n    0x8f, 0xe0, 0x21,  //  1E08F at 897\n    0xf6, 0xe6, 0x01,  //  1E6F6 at 928\n    0x4b, 0xe9, 0x01,  //  1E94B at 960 (upper bound)\n};\n\nstatic const uint32_t unicode_decomp_table1[709] = {\n    0x00280081, 0x002a0097, 0x002a8081, 0x002bc097,\n    0x002c8115, 0x002d0097, 0x002d4081, 0x002e0097,\n    0x002e4115, 0x002f0199, 0x00302016, 0x00400842,\n    0x00448a42, 0x004a0442, 0x004c0096, 0x004c8117,\n    0x004d0242, 0x004e4342, 0x004fc12f, 0x0050c342,\n    0x005240bf, 0x00530342, 0x00550942, 0x005a0842,\n    0x005e0096, 0x005e4342, 0x005fc081, 0x00680142,\n    0x006bc142, 0x00710185, 0x0071c317, 0x00734844,\n    0x00778344, 0x00798342, 0x007b02be, 0x007c4197,\n    0x007d0142, 0x007e0444, 0x00800e42, 0x00878142,\n    0x00898744, 0x00ac0483, 0x00b60317, 0x00b80283,\n    0x00d00214, 0x00d10096, 0x00dd0080, 0x00de8097,\n    0x00df8080, 0x00e10097, 0x00e1413e, 0x00e1c080,\n    0x00e204be, 0x00ea83ae, 0x00f282ae, 0x00f401ad,\n    0x00f4c12e, 0x00f54103, 0x00fc0303, 0x00fe4081,\n    0x0100023e, 0x0101c0be, 0x010301be, 0x010640be,\n    0x010e40be, 0x0114023e, 0x0115c0be, 0x011701be,\n    0x011d8144, 0x01304144, 0x01340244, 0x01358144,\n    0x01368344, 0x01388344, 0x013a8644, 0x013e0144,\n    0x0161c085, 0x018882ae, 0x019d422f, 0x01b00184,\n    0x01b4c084, 0x024a4084, 0x024c4084, 0x024d0084,\n    0x0256042e, 0x0272c12e, 0x02770120, 0x0277c084,\n    0x028cc084, 0x028d8084, 0x029641ae, 0x02978084,\n    0x02d20084, 0x02d2c12e, 0x02d70120, 0x02e50084,\n    0x02f281ae, 0x03120084, 0x03300084, 0x0331c122,\n    0x0332812e, 0x035281ae, 0x03768084, 0x037701ae,\n    0x038cc085, 0x03acc085, 0x03b7012f, 0x03c30081,\n    0x03d0c084, 0x03d34084, 0x03d48084, 0x03d5c084,\n    0x03d70084, 0x03da4084, 0x03dcc084, 0x03dd412e,\n    0x03ddc085, 0x03de0084, 0x03de4085, 0x03e04084,\n    0x03e4c084, 0x03e74084, 0x03e88084, 0x03e9c084,\n    0x03eb0084, 0x03ee4084, 0x04098084, 0x043f0081,\n    0x06c18484, 0x06c48084, 0x06cec184, 0x06d00120,\n    0x06d0c084, 0x074b0383, 0x074cc41f, 0x074f1783,\n    0x075e0081, 0x0766d283, 0x07801d44, 0x078e8942,\n    0x07931844, 0x079f0d42, 0x07a58216, 0x07a68085,\n    0x07a6c0be, 0x07a80d44, 0x07aea044, 0x07c00122,\n    0x07c08344, 0x07c20122, 0x07c28344, 0x07c40122,\n    0x07c48244, 0x07c60122, 0x07c68244, 0x07c8113e,\n    0x07d08244, 0x07d20122, 0x07d28244, 0x07d40122,\n    0x07d48344, 0x07d64c3e, 0x07dc4080, 0x07dc80be,\n    0x07dcc080, 0x07dd00be, 0x07dd4080, 0x07dd80be,\n    0x07ddc080, 0x07de00be, 0x07de4080, 0x07de80be,\n    0x07dec080, 0x07df00be, 0x07df4080, 0x07e00820,\n    0x07e40820, 0x07e80820, 0x07ec05be, 0x07eec080,\n    0x07ef00be, 0x07ef4097, 0x07ef8080, 0x07efc117,\n    0x07f0443e, 0x07f24080, 0x07f280be, 0x07f2c080,\n    0x07f303be, 0x07f4c080, 0x07f582ae, 0x07f6c080,\n    0x07f7433e, 0x07f8c080, 0x07f903ae, 0x07fac080,\n    0x07fb013e, 0x07fb8102, 0x07fc83be, 0x07fe4080,\n    0x07fe80be, 0x07fec080, 0x07ff00be, 0x07ff4080,\n    0x07ff8097, 0x0800011e, 0x08008495, 0x08044081,\n    0x0805c097, 0x08090081, 0x08094097, 0x08098099,\n    0x080bc081, 0x080cc085, 0x080d00b1, 0x080d8085,\n    0x080dc0b1, 0x080f0197, 0x0811c197, 0x0815c0b3,\n    0x0817c081, 0x081c0595, 0x081ec081, 0x081f0215,\n    0x0820051f, 0x08228583, 0x08254415, 0x082a0097,\n    0x08400119, 0x08408081, 0x0840c0bf, 0x08414119,\n    0x0841c081, 0x084240bf, 0x0842852d, 0x08454081,\n    0x08458097, 0x08464295, 0x08480097, 0x08484099,\n    0x08488097, 0x08490081, 0x08498080, 0x084a0081,\n    0x084a8102, 0x084b0495, 0x084d421f, 0x084e4081,\n    0x084ec099, 0x084f0283, 0x08514295, 0x08540119,\n    0x0854809b, 0x0854c619, 0x0857c097, 0x08580081,\n    0x08584097, 0x08588099, 0x0858c097, 0x08590081,\n    0x08594097, 0x08598099, 0x0859c09b, 0x085a0097,\n    0x085a4081, 0x085a8097, 0x085ac099, 0x085b0295,\n    0x085c4097, 0x085c8099, 0x085cc097, 0x085d0081,\n    0x085d4097, 0x085d8099, 0x085dc09b, 0x085e0097,\n    0x085e4081, 0x085e8097, 0x085ec099, 0x085f0215,\n    0x08624099, 0x0866813e, 0x086b80be, 0x087341be,\n    0x088100be, 0x088240be, 0x088300be, 0x088901be,\n    0x088b0085, 0x088b40b1, 0x088bc085, 0x088c00b1,\n    0x089040be, 0x089100be, 0x0891c1be, 0x089801be,\n    0x089b42be, 0x089d0144, 0x089e0144, 0x08a00144,\n    0x08a10144, 0x08a20144, 0x08ab023e, 0x08b80244,\n    0x08ba8220, 0x08ca411e, 0x0918049f, 0x091a4523,\n    0x091cc097, 0x091d04a5, 0x091f452b, 0x0921c09b,\n    0x092204a1, 0x09244525, 0x0926c099, 0x09270d25,\n    0x092d8d1f, 0x09340d1f, 0x093a8081, 0x0a8300b3,\n    0x0a9d0099, 0x0a9d4097, 0x0a9d8099, 0x0ab700be,\n    0x0b1f0115, 0x0b5bc081, 0x0ba7c081, 0x0bbcc081,\n    0x0bc004ad, 0x0bc244ad, 0x0bc484ad, 0x0bc6f383,\n    0x0be0852d, 0x0be31d03, 0x0bf1882d, 0x0c000081,\n    0x0c0d8283, 0x0c130b84, 0x0c194284, 0x0c1c0122,\n    0x0c1cc122, 0x0c1d8122, 0x0c1e4122, 0x0c1f0122,\n    0x0c250084, 0x0c26c123, 0x0c278084, 0x0c27c085,\n    0x0c2b0b84, 0x0c314284, 0x0c340122, 0x0c34c122,\n    0x0c358122, 0x0c364122, 0x0c370122, 0x0c3d0084,\n    0x0c3dc220, 0x0c3f8084, 0x0c3fc085, 0x0c4c4a2d,\n    0x0c51451f, 0x0c53ca9f, 0x0c5915ad, 0x0c648703,\n    0x0c800741, 0x0c838089, 0x0c83c129, 0x0c8441a9,\n    0x0c850089, 0x0c854129, 0x0c85c2a9, 0x0c870089,\n    0x0c87408f, 0x0c87808d, 0x0c881241, 0x0c910203,\n    0x0c940099, 0x0c9444a3, 0x0c968323, 0x0c98072d,\n    0x0c9b84af, 0x0c9dc2a1, 0x0c9f00b5, 0x0c9f40b3,\n    0x0c9f8085, 0x0ca01883, 0x0cac4223, 0x0cad4523,\n    0x0cafc097, 0x0cb004a1, 0x0cb241a5, 0x0cb30097,\n    0x0cb34099, 0x0cb38097, 0x0cb3c099, 0x0cb417ad,\n    0x0cbfc085, 0x0cc001b3, 0x0cc0c0b1, 0x0cc100b3,\n    0x0cc14131, 0x0cc1c0b5, 0x0cc200b3, 0x0cc241b1,\n    0x0cc30133, 0x0cc38131, 0x0cc40085, 0x0cc440b1,\n    0x0cc48133, 0x0cc50085, 0x0cc540b5, 0x0cc580b7,\n    0x0cc5c0b5, 0x0cc600b1, 0x0cc64135, 0x0cc6c0b3,\n    0x0cc701b1, 0x0cc7c0b3, 0x0cc800b5, 0x0cc840b3,\n    0x0cc881b1, 0x0cc9422f, 0x0cca4131, 0x0ccac0b5,\n    0x0ccb00b1, 0x0ccb40b3, 0x0ccb80b5, 0x0ccbc0b1,\n    0x0ccc012f, 0x0ccc80b5, 0x0cccc0b3, 0x0ccd00b5,\n    0x0ccd40b1, 0x0ccd80b5, 0x0ccdc085, 0x0cce02b1,\n    0x0ccf40b3, 0x0ccf80b1, 0x0ccfc085, 0x0cd001b1,\n    0x0cd0c0b3, 0x0cd101b1, 0x0cd1c0b5, 0x0cd200b3,\n    0x0cd24085, 0x0cd280b5, 0x0cd2c085, 0x0cd30133,\n    0x0cd381b1, 0x0cd440b3, 0x0cd48085, 0x0cd4c0b1,\n    0x0cd500b3, 0x0cd54085, 0x0cd580b5, 0x0cd5c0b1,\n    0x0cd60521, 0x0cd88525, 0x0cdb02a5, 0x0cdc4099,\n    0x0cdc8117, 0x0cdd0099, 0x0cdd4197, 0x0cde0127,\n    0x0cde8285, 0x0cdfc089, 0x0ce0043f, 0x0ce20099,\n    0x0ce2409b, 0x0ce283bf, 0x0ce44219, 0x0ce54205,\n    0x0ce6433f, 0x0ce7c131, 0x0ce84085, 0x0ce881b1,\n    0x0ce94085, 0x0ce98107, 0x0cea0089, 0x0cea4097,\n    0x0cea8219, 0x0ceb809d, 0x0cebc08d, 0x0cec083f,\n    0x0cf00105, 0x0cf0809b, 0x0cf0c197, 0x0cf1809b,\n    0x0cf1c099, 0x0cf20517, 0x0cf48099, 0x0cf4c117,\n    0x0cf54119, 0x0cf5c097, 0x0cf6009b, 0x0cf64099,\n    0x0cf68217, 0x0cf78119, 0x0cf804a1, 0x0cfa4525,\n    0x0cfcc525, 0x0cff4125, 0x0cffc099, 0x29a70103,\n    0x29dc0081, 0x29fc4215, 0x29fe0103, 0x2ad70203,\n    0x2ada4081, 0x3e401482, 0x3e4a7f82, 0x3e6a3f82,\n    0x3e8aa102, 0x3e9b0110, 0x3e9c2f82, 0x3eb3c590,\n    0x3ec00197, 0x3ec0c119, 0x3ec1413f, 0x3ec4c2af,\n    0x3ec74184, 0x3ec804ad, 0x3eca4081, 0x3eca8304,\n    0x3ecc03a0, 0x3ece02a0, 0x3ecf8084, 0x3ed00120,\n    0x3ed0c120, 0x3ed184ae, 0x3ed3c085, 0x3ed4312d,\n    0x3ef4cbad, 0x3efa892f, 0x3eff022d, 0x3f002f2f,\n    0x3f1782a5, 0x3f18c0b1, 0x3f1907af, 0x3f1cffaf,\n    0x3f3c81a5, 0x3f3d64af, 0x3f542031, 0x3f649b31,\n    0x3f7c0131, 0x3f7c83b3, 0x3f7e40b1, 0x3f7e80bd,\n    0x3f7ec0bb, 0x3f7f00b3, 0x3f840503, 0x3f8c01ad,\n    0x3f8cc315, 0x3f8e462d, 0x3f91cc03, 0x3f97c695,\n    0x3f9c01af, 0x3f9d0085, 0x3f9d852f, 0x3fa03aad,\n    0x3fbd442f, 0x3fc06f1f, 0x3fd7c11f, 0x3fd85fad,\n    0x3fe80081, 0x3fe84f1f, 0x3ff0831f, 0x3ff2831f,\n    0x3ff4831f, 0x3ff6819f, 0x3ff80783, 0x41724092,\n    0x41790092, 0x41e04d83, 0x41e70f91, 0x44268192,\n    0x442ac092, 0x444b8112, 0x44d2c112, 0x44e0c192,\n    0x44e38092, 0x44e44092, 0x44f14212, 0x452ec212,\n    0x456e8112, 0x464e0092, 0x58484412, 0x5b5a0192,\n    0x73358d1f, 0x733c051f, 0x74578392, 0x746ec312,\n    0x75000d1f, 0x75068d1f, 0x750d0d1f, 0x7513839f,\n    0x7515891f, 0x751a0d1f, 0x75208d1f, 0x75271015,\n    0x752f439f, 0x7531459f, 0x75340d1f, 0x753a8d1f,\n    0x75410395, 0x7543441f, 0x7545839f, 0x75478d1f,\n    0x754e0795, 0x7552839f, 0x75548d1f, 0x755b0d1f,\n    0x75618d1f, 0x75680d1f, 0x756e8d1f, 0x75750d1f,\n    0x757b8d1f, 0x75820d1f, 0x75888d1f, 0x758f0d1f,\n    0x75958d1f, 0x759c0d1f, 0x75a28d1f, 0x75a90103,\n    0x75aa089f, 0x75ae4081, 0x75ae839f, 0x75b04081,\n    0x75b08c9f, 0x75b6c081, 0x75b7032d, 0x75b8889f,\n    0x75bcc081, 0x75bd039f, 0x75bec081, 0x75bf0c9f,\n    0x75c54081, 0x75c5832d, 0x75c7089f, 0x75cb4081,\n    0x75cb839f, 0x75cd4081, 0x75cd8c9f, 0x75d3c081,\n    0x75d4032d, 0x75d5889f, 0x75d9c081, 0x75da039f,\n    0x75dbc081, 0x75dc0c9f, 0x75e24081, 0x75e2832d,\n    0x75e4089f, 0x75e84081, 0x75e8839f, 0x75ea4081,\n    0x75ea8c9f, 0x75f0c081, 0x75f1042d, 0x75f3851f,\n    0x75f6051f, 0x75f8851f, 0x75fb051f, 0x75fd851f,\n    0x780c049f, 0x780e419f, 0x780f059f, 0x7811c203,\n    0x7812d0ad, 0x781b0103, 0x7b80022d, 0x7b814dad,\n    0x7b884203, 0x7b89c081, 0x7b8a452d, 0x7b8d0403,\n    0x7b908081, 0x7b91dc03, 0x7ba0052d, 0x7ba2c8ad,\n    0x7ba84483, 0x7baac8ad, 0x7c400097, 0x7c404521,\n    0x7c440d25, 0x7c4a8087, 0x7c4ac115, 0x7c4b4117,\n    0x7c4c0d1f, 0x7c528217, 0x7c538099, 0x7c53c097,\n    0x7c5a8197, 0x7c640097, 0x7c80012f, 0x7c808081,\n    0x7c841603, 0x7c9004c1, 0x7c940103, 0x7efc051f,\n    0xbe0001ac, 0xbe00d110, 0xbe0947ac, 0xbe0d3910,\n    0xbe29872c, 0xbe2d022c, 0xbe2e3790, 0xbe49ff90,\n    0xbe69bc10,\n};\n\nstatic const uint16_t unicode_decomp_table2[709] = {\n    0x0020, 0x0000, 0x0061, 0x0002, 0x0004, 0x0006, 0x03bc, 0x0008,\n    0x000a, 0x000c, 0x0015, 0x0095, 0x00a5, 0x00b9, 0x00c1, 0x00c3,\n    0x00c7, 0x00cb, 0x00d1, 0x00d7, 0x00dd, 0x00e0, 0x00e6, 0x00f8,\n    0x0108, 0x010a, 0x0073, 0x0110, 0x0112, 0x0114, 0x0120, 0x012c,\n    0x0144, 0x014d, 0x0153, 0x0162, 0x0168, 0x016a, 0x0176, 0x0192,\n    0x0194, 0x01a9, 0x01bb, 0x01c7, 0x01d1, 0x01d5, 0x02b9, 0x01d7,\n    0x003b, 0x01d9, 0x01db, 0x00b7, 0x01e1, 0x01fc, 0x020c, 0x0218,\n    0x021d, 0x0223, 0x0227, 0x03a3, 0x0233, 0x023f, 0x0242, 0x024b,\n    0x024e, 0x0251, 0x025d, 0x0260, 0x0269, 0x026c, 0x026f, 0x0275,\n    0x0278, 0x0281, 0x028a, 0x029c, 0x029f, 0x02a3, 0x02af, 0x02b9,\n    0x02c5, 0x02c9, 0x02cd, 0x02d1, 0x02d5, 0x02e7, 0x02ed, 0x02f1,\n    0x02f5, 0x02f9, 0x02fd, 0x0305, 0x0309, 0x030d, 0x0313, 0x0317,\n    0x031b, 0x0323, 0x0327, 0x032b, 0x032f, 0x0335, 0x033d, 0x0341,\n    0x0349, 0x034d, 0x0351, 0x0f0b, 0x0357, 0x035b, 0x035f, 0x0363,\n    0x0367, 0x036b, 0x036f, 0x0373, 0x0379, 0x037d, 0x0381, 0x0385,\n    0x0389, 0x038d, 0x0391, 0x0395, 0x0399, 0x039d, 0x03a1, 0x10dc,\n    0x03a5, 0x03c9, 0x03cd, 0x03d9, 0x03dd, 0x03e1, 0x03ef, 0x03f1,\n    0x043d, 0x044f, 0x0499, 0x04f0, 0x0502, 0x054a, 0x0564, 0x056c,\n    0x0570, 0x0573, 0x059a, 0x05fa, 0x05fe, 0x0607, 0x060b, 0x0614,\n    0x0618, 0x061e, 0x0622, 0x0628, 0x068e, 0x0694, 0x0698, 0x069e,\n    0x06a2, 0x06ab, 0x03ac, 0x06f3, 0x03ad, 0x06f6, 0x03ae, 0x06f9,\n    0x03af, 0x06fc, 0x03cc, 0x06ff, 0x03cd, 0x0702, 0x03ce, 0x0705,\n    0x0709, 0x070d, 0x0711, 0x0386, 0x0732, 0x0735, 0x03b9, 0x0737,\n    0x073b, 0x0388, 0x0753, 0x0389, 0x0756, 0x0390, 0x076b, 0x038a,\n    0x0777, 0x03b0, 0x0789, 0x038e, 0x0799, 0x079f, 0x07a3, 0x038c,\n    0x07b8, 0x038f, 0x07bb, 0x00b4, 0x07be, 0x07c0, 0x07c2, 0x2010,\n    0x07cb, 0x002e, 0x07cd, 0x07cf, 0x0020, 0x07d2, 0x07d6, 0x07db,\n    0x07df, 0x07e4, 0x07ea, 0x07f0, 0x0020, 0x07f6, 0x2212, 0x0801,\n    0x0805, 0x0807, 0x081d, 0x0825, 0x0827, 0x0043, 0x082d, 0x0830,\n    0x0190, 0x0836, 0x0839, 0x004e, 0x0845, 0x0847, 0x084c, 0x084e,\n    0x0851, 0x005a, 0x03a9, 0x005a, 0x0853, 0x0857, 0x0860, 0x0069,\n    0x0862, 0x0865, 0x086f, 0x0874, 0x087a, 0x087e, 0x08a2, 0x0049,\n    0x08a4, 0x08a6, 0x08a9, 0x0056, 0x08ab, 0x08ad, 0x08b0, 0x08b4,\n    0x0058, 0x08b6, 0x08b8, 0x08bb, 0x08c0, 0x08c2, 0x08c5, 0x0076,\n    0x08c7, 0x08c9, 0x08cc, 0x08d0, 0x0078, 0x08d2, 0x08d4, 0x08d7,\n    0x08db, 0x08de, 0x08e4, 0x08e7, 0x08f0, 0x08f3, 0x08f6, 0x08f9,\n    0x0902, 0x0906, 0x090b, 0x090f, 0x0914, 0x0917, 0x091a, 0x0923,\n    0x092c, 0x093b, 0x093e, 0x0941, 0x0944, 0x0947, 0x094a, 0x0956,\n    0x095c, 0x0960, 0x0962, 0x0964, 0x0968, 0x096a, 0x0970, 0x0978,\n    0x097c, 0x0980, 0x0986, 0x0989, 0x098f, 0x0991, 0x0030, 0x0993,\n    0x0999, 0x099c, 0x099e, 0x09a1, 0x09a4, 0x2d61, 0x6bcd, 0x9f9f,\n    0x09a6, 0x09b1, 0x09bc, 0x09c7, 0x0a95, 0x0aa1, 0x0b15, 0x0020,\n    0x0b27, 0x0b31, 0x0b8d, 0x0ba1, 0x0ba5, 0x0ba9, 0x0bad, 0x0bb1,\n    0x0bb5, 0x0bb9, 0x0bbd, 0x0bc1, 0x0bc5, 0x0c21, 0x0c35, 0x0c39,\n    0x0c3d, 0x0c41, 0x0c45, 0x0c49, 0x0c4d, 0x0c51, 0x0c55, 0x0c59,\n    0x0c6f, 0x0c71, 0x0c73, 0x0ca0, 0x0cbc, 0x0cdc, 0x0ce4, 0x0cec,\n    0x0cf4, 0x0cfc, 0x0d04, 0x0d0c, 0x0d14, 0x0d22, 0x0d2e, 0x0d7a,\n    0x0d82, 0x0d85, 0x0d89, 0x0d8d, 0x0d9d, 0x0db1, 0x0db5, 0x0dbc,\n    0x0dc2, 0x0dc6, 0x0e28, 0x0e2c, 0x0e30, 0x0e32, 0x0e36, 0x0e3c,\n    0x0e3e, 0x0e41, 0x0e43, 0x0e46, 0x0e77, 0x0e7b, 0x0e89, 0x0e8e,\n    0x0e94, 0x0e9c, 0x0ea3, 0x0ea9, 0x0eb4, 0x0ebe, 0x0ec6, 0x0eca,\n    0x0ecf, 0x0ed9, 0x0edd, 0x0ee4, 0x0eec, 0x0ef3, 0x0ef8, 0x0f04,\n    0x0f0a, 0x0f15, 0x0f1b, 0x0f22, 0x0f28, 0x0f33, 0x0f3d, 0x0f45,\n    0x0f4c, 0x0f51, 0x0f57, 0x0f5e, 0x0f63, 0x0f69, 0x0f70, 0x0f76,\n    0x0f7d, 0x0f82, 0x0f89, 0x0f8d, 0x0f9e, 0x0fa4, 0x0fa9, 0x0fad,\n    0x0fb8, 0x0fbe, 0x0fc9, 0x0fd0, 0x0fd6, 0x0fda, 0x0fe1, 0x0fe5,\n    0x0fef, 0x0ffa, 0x1000, 0x1004, 0x1009, 0x100f, 0x1013, 0x101a,\n    0x101f, 0x1023, 0x1029, 0x102f, 0x1032, 0x1036, 0x1039, 0x103f,\n    0x1045, 0x1059, 0x1061, 0x1079, 0x107c, 0x1080, 0x1095, 0x10a1,\n    0x10b1, 0x10c3, 0x10cb, 0x10cf, 0x10da, 0x10de, 0x10ea, 0x10f2,\n    0x10f4, 0x1100, 0x1105, 0x1111, 0x1141, 0x1149, 0x114d, 0x1153,\n    0x1157, 0x115a, 0x116e, 0x1171, 0x1175, 0x117b, 0x117d, 0x1181,\n    0x1184, 0x118c, 0x1192, 0x1196, 0x119c, 0x11a2, 0x11a8, 0x11ab,\n    0xa76f, 0x11af, 0x11b3, 0x11b7, 0x028d, 0x11bf, 0x1211, 0x130f,\n    0x140d, 0x1491, 0x1496, 0x1554, 0x156d, 0x1573, 0x1579, 0x157f,\n    0x158b, 0x1597, 0x002b, 0x15a2, 0x15ba, 0x15be, 0x15c2, 0x15c6,\n    0x15ca, 0x15ce, 0x15e2, 0x15e6, 0x164a, 0x1663, 0x1689, 0x168f,\n    0x174d, 0x1753, 0x1758, 0x1778, 0x1878, 0x187e, 0x1912, 0x19d4,\n    0x1a78, 0x1a80, 0x1a9e, 0x1aa3, 0x1ab7, 0x1ac1, 0x1ac7, 0x1adb,\n    0x1ae0, 0x1ae6, 0x1af4, 0x1b24, 0x1b31, 0x1b39, 0x1b3d, 0x1b53,\n    0x1bca, 0x1bdc, 0x1bde, 0x1be0, 0x3164, 0x1c21, 0x1c23, 0x1c25,\n    0x1c27, 0x1c29, 0x1c2b, 0x1c49, 0x1c4e, 0x1c53, 0x1c89, 0x1ccf,\n    0x1cdd, 0x1ce2, 0x1ceb, 0x1cf4, 0x1d02, 0x1d07, 0x1d0c, 0x1d1e,\n    0x1d30, 0x1d39, 0x1d3e, 0x1d62, 0x1d70, 0x1d72, 0x1d74, 0x1d94,\n    0x1daf, 0x1db1, 0x1db3, 0x1db5, 0x1db7, 0x1db9, 0x1dbb, 0x1dbd,\n    0x1ddd, 0x1ddf, 0x1de1, 0x1de3, 0x1de5, 0x1dec, 0x1dee, 0x1df0,\n    0x1df2, 0x1e01, 0x1e03, 0x1e05, 0x1e07, 0x1e09, 0x1e0b, 0x1e0d,\n    0x1e0f, 0x1e11, 0x1e13, 0x1e15, 0x1e17, 0x1e19, 0x1e1b, 0x1e1d,\n    0x1e21, 0x03f4, 0x1e23, 0x2207, 0x1e25, 0x2202, 0x1e27, 0x1e2f,\n    0x03f4, 0x1e31, 0x2207, 0x1e33, 0x2202, 0x1e35, 0x1e3d, 0x03f4,\n    0x1e3f, 0x2207, 0x1e41, 0x2202, 0x1e43, 0x1e4b, 0x03f4, 0x1e4d,\n    0x2207, 0x1e4f, 0x2202, 0x1e51, 0x1e59, 0x03f4, 0x1e5b, 0x2207,\n    0x1e5d, 0x2202, 0x1e5f, 0x1e69, 0x1e6b, 0x1e6d, 0x1e6f, 0x1e71,\n    0x1e73, 0x1e75, 0x1e77, 0x1e79, 0x1e81, 0x1ea4, 0x1ea8, 0x1eae,\n    0x1ecb, 0x062d, 0x1ed3, 0x1edf, 0x062c, 0x1eef, 0x1f5f, 0x1f6b,\n    0x1f7e, 0x1f90, 0x1fa3, 0x1fa5, 0x1fa9, 0x1faf, 0x1fb5, 0x1fb7,\n    0x1fbb, 0x1fbd, 0x1fc5, 0x1fc8, 0x1fca, 0x1fd0, 0x1fd2, 0x30b5,\n    0x1fd8, 0x2030, 0x2046, 0x204a, 0x204c, 0x2051, 0x209e, 0x20af,\n    0x21b0, 0x21c0, 0x21c6, 0x22c0, 0x23de,\n};\n\nstatic const uint8_t unicode_decomp_data[9452] = {\n    0x20, 0x88, 0x20, 0x84, 0x32, 0x33, 0x20, 0x81,\n    0x20, 0xa7, 0x31, 0x6f, 0x31, 0xd0, 0x34, 0x31,\n    0xd0, 0x32, 0x33, 0xd0, 0x34, 0x41, 0x80, 0x41,\n    0x81, 0x41, 0x82, 0x41, 0x83, 0x41, 0x88, 0x41,\n    0x8a, 0x00, 0x00, 0x43, 0xa7, 0x45, 0x80, 0x45,\n    0x81, 0x45, 0x82, 0x45, 0x88, 0x49, 0x80, 0x49,\n    0x81, 0x49, 0x82, 0x49, 0x88, 0x00, 0x00, 0x4e,\n    0x83, 0x4f, 0x80, 0x4f, 0x81, 0x4f, 0x82, 0x4f,\n    0x83, 0x4f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x55,\n    0x80, 0x55, 0x81, 0x55, 0x82, 0x55, 0x88, 0x59,\n    0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x80, 0x61,\n    0x81, 0x61, 0x82, 0x61, 0x83, 0x61, 0x88, 0x61,\n    0x8a, 0x00, 0x00, 0x63, 0xa7, 0x65, 0x80, 0x65,\n    0x81, 0x65, 0x82, 0x65, 0x88, 0x69, 0x80, 0x69,\n    0x81, 0x69, 0x82, 0x69, 0x88, 0x00, 0x00, 0x6e,\n    0x83, 0x6f, 0x80, 0x6f, 0x81, 0x6f, 0x82, 0x6f,\n    0x83, 0x6f, 0x88, 0x00, 0x00, 0x00, 0x00, 0x75,\n    0x80, 0x75, 0x81, 0x75, 0x82, 0x75, 0x88, 0x79,\n    0x81, 0x00, 0x00, 0x79, 0x88, 0x41, 0x84, 0x41,\n    0x86, 0x41, 0xa8, 0x43, 0x81, 0x43, 0x82, 0x43,\n    0x87, 0x43, 0x8c, 0x44, 0x8c, 0x45, 0x84, 0x45,\n    0x86, 0x45, 0x87, 0x45, 0xa8, 0x45, 0x8c, 0x47,\n    0x82, 0x47, 0x86, 0x47, 0x87, 0x47, 0xa7, 0x48,\n    0x82, 0x49, 0x83, 0x49, 0x84, 0x49, 0x86, 0x49,\n    0xa8, 0x49, 0x87, 0x49, 0x4a, 0x69, 0x6a, 0x4a,\n    0x82, 0x4b, 0xa7, 0x4c, 0x81, 0x4c, 0xa7, 0x4c,\n    0x8c, 0x4c, 0x00, 0x00, 0x6b, 0x20, 0x6b, 0x4e,\n    0x81, 0x4e, 0xa7, 0x4e, 0x8c, 0xbc, 0x02, 0x6e,\n    0x4f, 0x84, 0x4f, 0x86, 0x4f, 0x8b, 0x52, 0x81,\n    0x52, 0xa7, 0x52, 0x8c, 0x53, 0x81, 0x53, 0x82,\n    0x53, 0xa7, 0x53, 0x8c, 0x54, 0xa7, 0x54, 0x8c,\n    0x55, 0x83, 0x55, 0x84, 0x55, 0x86, 0x55, 0x8a,\n    0x55, 0x8b, 0x55, 0xa8, 0x57, 0x82, 0x59, 0x82,\n    0x59, 0x88, 0x5a, 0x81, 0x5a, 0x87, 0x5a, 0x8c,\n    0x4f, 0x9b, 0x55, 0x9b, 0x44, 0x00, 0x7d, 0x01,\n    0x44, 0x00, 0x7e, 0x01, 0x64, 0x00, 0x7e, 0x01,\n    0x4c, 0x4a, 0x4c, 0x6a, 0x6c, 0x6a, 0x4e, 0x4a,\n    0x4e, 0x6a, 0x6e, 0x6a, 0x41, 0x00, 0x8c, 0x49,\n    0x00, 0x8c, 0x4f, 0x00, 0x8c, 0x55, 0x00, 0x8c,\n    0xdc, 0x00, 0x84, 0xdc, 0x00, 0x81, 0xdc, 0x00,\n    0x8c, 0xdc, 0x00, 0x80, 0xc4, 0x00, 0x84, 0x26,\n    0x02, 0x84, 0xc6, 0x00, 0x84, 0x47, 0x8c, 0x4b,\n    0x8c, 0x4f, 0xa8, 0xea, 0x01, 0x84, 0xeb, 0x01,\n    0x84, 0xb7, 0x01, 0x8c, 0x92, 0x02, 0x8c, 0x6a,\n    0x00, 0x8c, 0x44, 0x5a, 0x44, 0x7a, 0x64, 0x7a,\n    0x47, 0x81, 0x4e, 0x00, 0x80, 0xc5, 0x00, 0x81,\n    0xc6, 0x00, 0x81, 0xd8, 0x00, 0x81, 0x41, 0x8f,\n    0x41, 0x91, 0x45, 0x8f, 0x45, 0x91, 0x49, 0x8f,\n    0x49, 0x91, 0x4f, 0x8f, 0x4f, 0x91, 0x52, 0x8f,\n    0x52, 0x91, 0x55, 0x8f, 0x55, 0x91, 0x53, 0xa6,\n    0x54, 0xa6, 0x48, 0x8c, 0x41, 0x00, 0x87, 0x45,\n    0x00, 0xa7, 0xd6, 0x00, 0x84, 0xd5, 0x00, 0x84,\n    0x4f, 0x00, 0x87, 0x2e, 0x02, 0x84, 0x59, 0x00,\n    0x84, 0x68, 0x00, 0x66, 0x02, 0x6a, 0x00, 0x72,\n    0x00, 0x79, 0x02, 0x7b, 0x02, 0x81, 0x02, 0x77,\n    0x00, 0x79, 0x00, 0x20, 0x86, 0x20, 0x87, 0x20,\n    0x8a, 0x20, 0xa8, 0x20, 0x83, 0x20, 0x8b, 0x63,\n    0x02, 0x6c, 0x00, 0x73, 0x00, 0x78, 0x00, 0x95,\n    0x02, 0x80, 0x81, 0x00, 0x93, 0x88, 0x81, 0x20,\n    0xc5, 0x20, 0x81, 0xa8, 0x00, 0x81, 0x91, 0x03,\n    0x81, 0x95, 0x03, 0x81, 0x97, 0x03, 0x81, 0x99,\n    0x03, 0x81, 0x00, 0x00, 0x00, 0x9f, 0x03, 0x81,\n    0x00, 0x00, 0x00, 0xa5, 0x03, 0x81, 0xa9, 0x03,\n    0x81, 0xca, 0x03, 0x81, 0x01, 0x03, 0x98, 0x07,\n    0xa4, 0x07, 0xb0, 0x00, 0xb4, 0x00, 0xb6, 0x00,\n    0xb8, 0x00, 0xca, 0x00, 0x01, 0x03, 0xb8, 0x07,\n    0xc4, 0x07, 0xbe, 0x00, 0xc4, 0x00, 0xc8, 0x00,\n    0xa5, 0x03, 0x0d, 0x13, 0x00, 0x01, 0x03, 0xd1,\n    0x00, 0xd1, 0x07, 0xc6, 0x03, 0xc0, 0x03, 0xba,\n    0x03, 0xc1, 0x03, 0xc2, 0x03, 0x00, 0x00, 0x98,\n    0x03, 0xb5, 0x03, 0x15, 0x04, 0x80, 0x15, 0x04,\n    0x88, 0x00, 0x00, 0x00, 0x13, 0x04, 0x81, 0x06,\n    0x04, 0x88, 0x1a, 0x04, 0x81, 0x18, 0x04, 0x80,\n    0x23, 0x04, 0x86, 0x18, 0x04, 0x86, 0x38, 0x04,\n    0x86, 0x35, 0x04, 0x80, 0x35, 0x04, 0x88, 0x00,\n    0x00, 0x00, 0x33, 0x04, 0x81, 0x56, 0x04, 0x88,\n    0x3a, 0x04, 0x81, 0x38, 0x04, 0x80, 0x43, 0x04,\n    0x86, 0x74, 0x04, 0x8f, 0x16, 0x04, 0x86, 0x10,\n    0x04, 0x86, 0x10, 0x04, 0x88, 0x15, 0x04, 0x86,\n    0xd8, 0x04, 0x88, 0x16, 0x04, 0x88, 0x17, 0x04,\n    0x88, 0x18, 0x04, 0x84, 0x18, 0x04, 0x88, 0x1e,\n    0x04, 0x88, 0xe8, 0x04, 0x88, 0x2d, 0x04, 0x88,\n    0x23, 0x04, 0x84, 0x23, 0x04, 0x88, 0x23, 0x04,\n    0x8b, 0x27, 0x04, 0x88, 0x2b, 0x04, 0x88, 0x65,\n    0x05, 0x82, 0x05, 0x27, 0x06, 0x00, 0x2c, 0x00,\n    0x2d, 0x21, 0x2d, 0x00, 0x2e, 0x23, 0x2d, 0x27,\n    0x06, 0x00, 0x4d, 0x21, 0x4d, 0xa0, 0x4d, 0x23,\n    0x4d, 0xd5, 0x06, 0x54, 0x06, 0x00, 0x00, 0x00,\n    0x00, 0xc1, 0x06, 0x54, 0x06, 0xd2, 0x06, 0x54,\n    0x06, 0x28, 0x09, 0x3c, 0x09, 0x30, 0x09, 0x3c,\n    0x09, 0x33, 0x09, 0x3c, 0x09, 0x15, 0x09, 0x00,\n    0x27, 0x01, 0x27, 0x02, 0x27, 0x07, 0x27, 0x0c,\n    0x27, 0x0d, 0x27, 0x16, 0x27, 0x1a, 0x27, 0xbe,\n    0x09, 0x09, 0x00, 0x09, 0x19, 0xa1, 0x09, 0xbc,\n    0x09, 0xaf, 0x09, 0xbc, 0x09, 0x32, 0x0a, 0x3c,\n    0x0a, 0x38, 0x0a, 0x3c, 0x0a, 0x16, 0x0a, 0x00,\n    0x26, 0x01, 0x26, 0x06, 0x26, 0x2b, 0x0a, 0x3c,\n    0x0a, 0x47, 0x0b, 0x56, 0x0b, 0x3e, 0x0b, 0x09,\n    0x00, 0x09, 0x19, 0x21, 0x0b, 0x3c, 0x0b, 0x92,\n    0x0b, 0xd7, 0x0b, 0xbe, 0x0b, 0x08, 0x00, 0x09,\n    0x00, 0x08, 0x19, 0x46, 0x0c, 0x56, 0x0c, 0xbf,\n    0x0c, 0xd5, 0x0c, 0xc6, 0x0c, 0xd5, 0x0c, 0xc2,\n    0x0c, 0x04, 0x00, 0x08, 0x13, 0x3e, 0x0d, 0x08,\n    0x00, 0x09, 0x00, 0x08, 0x19, 0xd9, 0x0d, 0xca,\n    0x0d, 0xca, 0x0d, 0x0f, 0x05, 0x12, 0x00, 0x0f,\n    0x15, 0x4d, 0x0e, 0x32, 0x0e, 0xcd, 0x0e, 0xb2,\n    0x0e, 0x99, 0x0e, 0x12, 0x00, 0x12, 0x08, 0x42,\n    0x0f, 0xb7, 0x0f, 0x4c, 0x0f, 0xb7, 0x0f, 0x51,\n    0x0f, 0xb7, 0x0f, 0x56, 0x0f, 0xb7, 0x0f, 0x5b,\n    0x0f, 0xb7, 0x0f, 0x40, 0x0f, 0xb5, 0x0f, 0x71,\n    0x0f, 0x72, 0x0f, 0x71, 0x0f, 0x00, 0x03, 0x41,\n    0x0f, 0xb2, 0x0f, 0x81, 0x0f, 0xb3, 0x0f, 0x80,\n    0x0f, 0xb3, 0x0f, 0x81, 0x0f, 0x71, 0x0f, 0x80,\n    0x0f, 0x92, 0x0f, 0xb7, 0x0f, 0x9c, 0x0f, 0xb7,\n    0x0f, 0xa1, 0x0f, 0xb7, 0x0f, 0xa6, 0x0f, 0xb7,\n    0x0f, 0xab, 0x0f, 0xb7, 0x0f, 0x90, 0x0f, 0xb5,\n    0x0f, 0x25, 0x10, 0x2e, 0x10, 0x05, 0x1b, 0x35,\n    0x1b, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1b, 0x35,\n    0x1b, 0x00, 0x00, 0x00, 0x00, 0x09, 0x1b, 0x35,\n    0x1b, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1b, 0x35,\n    0x1b, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x1b, 0x35,\n    0x1b, 0x11, 0x1b, 0x35, 0x1b, 0x3a, 0x1b, 0x35,\n    0x1b, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x1b, 0x35,\n    0x1b, 0x3e, 0x1b, 0x35, 0x1b, 0x42, 0x1b, 0x35,\n    0x1b, 0x41, 0x00, 0xc6, 0x00, 0x42, 0x00, 0x00,\n    0x00, 0x44, 0x00, 0x45, 0x00, 0x8e, 0x01, 0x47,\n    0x00, 0x4f, 0x00, 0x22, 0x02, 0x50, 0x00, 0x52,\n    0x00, 0x54, 0x00, 0x55, 0x00, 0x57, 0x00, 0x61,\n    0x00, 0x50, 0x02, 0x51, 0x02, 0x02, 0x1d, 0x62,\n    0x00, 0x64, 0x00, 0x65, 0x00, 0x59, 0x02, 0x5b,\n    0x02, 0x5c, 0x02, 0x67, 0x00, 0x00, 0x00, 0x6b,\n    0x00, 0x6d, 0x00, 0x4b, 0x01, 0x6f, 0x00, 0x54,\n    0x02, 0x16, 0x1d, 0x17, 0x1d, 0x70, 0x00, 0x74,\n    0x00, 0x75, 0x00, 0x1d, 0x1d, 0x6f, 0x02, 0x76,\n    0x00, 0x25, 0x1d, 0xb2, 0x03, 0xb3, 0x03, 0xb4,\n    0x03, 0xc6, 0x03, 0xc7, 0x03, 0x69, 0x00, 0x72,\n    0x00, 0x75, 0x00, 0x76, 0x00, 0xb2, 0x03, 0xb3,\n    0x03, 0xc1, 0x03, 0xc6, 0x03, 0xc7, 0x03, 0x52,\n    0x02, 0x63, 0x00, 0x55, 0x02, 0xf0, 0x00, 0x5c,\n    0x02, 0x66, 0x00, 0x5f, 0x02, 0x61, 0x02, 0x65,\n    0x02, 0x68, 0x02, 0x69, 0x02, 0x6a, 0x02, 0x7b,\n    0x1d, 0x9d, 0x02, 0x6d, 0x02, 0x85, 0x1d, 0x9f,\n    0x02, 0x71, 0x02, 0x70, 0x02, 0x72, 0x02, 0x73,\n    0x02, 0x74, 0x02, 0x75, 0x02, 0x78, 0x02, 0x82,\n    0x02, 0x83, 0x02, 0xab, 0x01, 0x89, 0x02, 0x8a,\n    0x02, 0x1c, 0x1d, 0x8b, 0x02, 0x8c, 0x02, 0x7a,\n    0x00, 0x90, 0x02, 0x91, 0x02, 0x92, 0x02, 0xb8,\n    0x03, 0x41, 0x00, 0xa5, 0x42, 0x00, 0x87, 0x42,\n    0x00, 0xa3, 0x42, 0x00, 0xb1, 0xc7, 0x00, 0x81,\n    0x44, 0x00, 0x87, 0x44, 0x00, 0xa3, 0x44, 0x00,\n    0xb1, 0x44, 0x00, 0xa7, 0x44, 0x00, 0xad, 0x12,\n    0x01, 0x80, 0x12, 0x01, 0x81, 0x45, 0x00, 0xad,\n    0x45, 0x00, 0xb0, 0x28, 0x02, 0x86, 0x46, 0x00,\n    0x87, 0x47, 0x00, 0x84, 0x48, 0x00, 0x87, 0x48,\n    0x00, 0xa3, 0x48, 0x00, 0x88, 0x48, 0x00, 0xa7,\n    0x48, 0x00, 0xae, 0x49, 0x00, 0xb0, 0xcf, 0x00,\n    0x81, 0x4b, 0x00, 0x81, 0x4b, 0x00, 0xa3, 0x4b,\n    0x00, 0xb1, 0x4c, 0x00, 0xa3, 0x36, 0x1e, 0x84,\n    0x4c, 0xb1, 0x4c, 0xad, 0x4d, 0x81, 0x4d, 0x87,\n    0x4d, 0xa3, 0x4e, 0x87, 0x4e, 0xa3, 0x4e, 0xb1,\n    0x4e, 0xad, 0xd5, 0x00, 0x81, 0xd5, 0x00, 0x88,\n    0x4c, 0x01, 0x80, 0x4c, 0x01, 0x81, 0x50, 0x00,\n    0x81, 0x50, 0x00, 0x87, 0x52, 0x00, 0x87, 0x52,\n    0x00, 0xa3, 0x5a, 0x1e, 0x84, 0x52, 0x00, 0xb1,\n    0x53, 0x00, 0x87, 0x53, 0x00, 0xa3, 0x5a, 0x01,\n    0x87, 0x60, 0x01, 0x87, 0x62, 0x1e, 0x87, 0x54,\n    0x00, 0x87, 0x54, 0x00, 0xa3, 0x54, 0x00, 0xb1,\n    0x54, 0x00, 0xad, 0x55, 0x00, 0xa4, 0x55, 0x00,\n    0xb0, 0x55, 0x00, 0xad, 0x68, 0x01, 0x81, 0x6a,\n    0x01, 0x88, 0x56, 0x83, 0x56, 0xa3, 0x57, 0x80,\n    0x57, 0x81, 0x57, 0x88, 0x57, 0x87, 0x57, 0xa3,\n    0x58, 0x87, 0x58, 0x88, 0x59, 0x87, 0x5a, 0x82,\n    0x5a, 0xa3, 0x5a, 0xb1, 0x68, 0xb1, 0x74, 0x88,\n    0x77, 0x8a, 0x79, 0x8a, 0x61, 0x00, 0xbe, 0x02,\n    0x7f, 0x01, 0x87, 0x41, 0x00, 0xa3, 0x41, 0x00,\n    0x89, 0xc2, 0x00, 0x81, 0xc2, 0x00, 0x80, 0xc2,\n    0x00, 0x89, 0xc2, 0x00, 0x83, 0xa0, 0x1e, 0x82,\n    0x02, 0x01, 0x81, 0x02, 0x01, 0x80, 0x02, 0x01,\n    0x89, 0x02, 0x01, 0x83, 0xa0, 0x1e, 0x86, 0x45,\n    0x00, 0xa3, 0x45, 0x00, 0x89, 0x45, 0x00, 0x83,\n    0xca, 0x00, 0x81, 0xca, 0x00, 0x80, 0xca, 0x00,\n    0x89, 0xca, 0x00, 0x83, 0xb8, 0x1e, 0x82, 0x49,\n    0x00, 0x89, 0x49, 0x00, 0xa3, 0x4f, 0x00, 0xa3,\n    0x4f, 0x00, 0x89, 0xd4, 0x00, 0x81, 0xd4, 0x00,\n    0x80, 0xd4, 0x00, 0x89, 0xd4, 0x00, 0x83, 0xcc,\n    0x1e, 0x82, 0xa0, 0x01, 0x81, 0xa0, 0x01, 0x80,\n    0xa0, 0x01, 0x89, 0xa0, 0x01, 0x83, 0xa0, 0x01,\n    0xa3, 0x55, 0x00, 0xa3, 0x55, 0x00, 0x89, 0xaf,\n    0x01, 0x81, 0xaf, 0x01, 0x80, 0xaf, 0x01, 0x89,\n    0xaf, 0x01, 0x83, 0xaf, 0x01, 0xa3, 0x59, 0x00,\n    0x80, 0x59, 0x00, 0xa3, 0x59, 0x00, 0x89, 0x59,\n    0x00, 0x83, 0xb1, 0x03, 0x13, 0x03, 0x00, 0x1f,\n    0x80, 0x00, 0x1f, 0x81, 0x00, 0x1f, 0xc2, 0x91,\n    0x03, 0x13, 0x03, 0x08, 0x1f, 0x80, 0x08, 0x1f,\n    0x81, 0x08, 0x1f, 0xc2, 0xb5, 0x03, 0x13, 0x03,\n    0x10, 0x1f, 0x80, 0x10, 0x1f, 0x81, 0x95, 0x03,\n    0x13, 0x03, 0x18, 0x1f, 0x80, 0x18, 0x1f, 0x81,\n    0xb7, 0x03, 0x93, 0xb7, 0x03, 0x94, 0x20, 0x1f,\n    0x80, 0x21, 0x1f, 0x80, 0x20, 0x1f, 0x81, 0x21,\n    0x1f, 0x81, 0x20, 0x1f, 0xc2, 0x21, 0x1f, 0xc2,\n    0x97, 0x03, 0x93, 0x97, 0x03, 0x94, 0x28, 0x1f,\n    0x80, 0x29, 0x1f, 0x80, 0x28, 0x1f, 0x81, 0x29,\n    0x1f, 0x81, 0x28, 0x1f, 0xc2, 0x29, 0x1f, 0xc2,\n    0xb9, 0x03, 0x93, 0xb9, 0x03, 0x94, 0x30, 0x1f,\n    0x80, 0x31, 0x1f, 0x80, 0x30, 0x1f, 0x81, 0x31,\n    0x1f, 0x81, 0x30, 0x1f, 0xc2, 0x31, 0x1f, 0xc2,\n    0x99, 0x03, 0x93, 0x99, 0x03, 0x94, 0x38, 0x1f,\n    0x80, 0x39, 0x1f, 0x80, 0x38, 0x1f, 0x81, 0x39,\n    0x1f, 0x81, 0x38, 0x1f, 0xc2, 0x39, 0x1f, 0xc2,\n    0xbf, 0x03, 0x93, 0xbf, 0x03, 0x94, 0x40, 0x1f,\n    0x80, 0x40, 0x1f, 0x81, 0x9f, 0x03, 0x13, 0x03,\n    0x48, 0x1f, 0x80, 0x48, 0x1f, 0x81, 0xc5, 0x03,\n    0x13, 0x03, 0x50, 0x1f, 0x80, 0x50, 0x1f, 0x81,\n    0x50, 0x1f, 0xc2, 0xa5, 0x03, 0x94, 0x00, 0x00,\n    0x00, 0x59, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x59,\n    0x1f, 0x81, 0x00, 0x00, 0x00, 0x59, 0x1f, 0xc2,\n    0xc9, 0x03, 0x93, 0xc9, 0x03, 0x94, 0x60, 0x1f,\n    0x80, 0x61, 0x1f, 0x80, 0x60, 0x1f, 0x81, 0x61,\n    0x1f, 0x81, 0x60, 0x1f, 0xc2, 0x61, 0x1f, 0xc2,\n    0xa9, 0x03, 0x93, 0xa9, 0x03, 0x94, 0x68, 0x1f,\n    0x80, 0x69, 0x1f, 0x80, 0x68, 0x1f, 0x81, 0x69,\n    0x1f, 0x81, 0x68, 0x1f, 0xc2, 0x69, 0x1f, 0xc2,\n    0xb1, 0x03, 0x80, 0xb5, 0x03, 0x80, 0xb7, 0x03,\n    0x80, 0xb9, 0x03, 0x80, 0xbf, 0x03, 0x80, 0xc5,\n    0x03, 0x80, 0xc9, 0x03, 0x80, 0x00, 0x1f, 0x45,\n    0x03, 0x20, 0x1f, 0x45, 0x03, 0x60, 0x1f, 0x45,\n    0x03, 0xb1, 0x03, 0x86, 0xb1, 0x03, 0x84, 0x70,\n    0x1f, 0xc5, 0xb1, 0x03, 0xc5, 0xac, 0x03, 0xc5,\n    0x00, 0x00, 0x00, 0xb1, 0x03, 0xc2, 0xb6, 0x1f,\n    0xc5, 0x91, 0x03, 0x86, 0x91, 0x03, 0x84, 0x91,\n    0x03, 0x80, 0x91, 0x03, 0xc5, 0x20, 0x93, 0x20,\n    0x93, 0x20, 0xc2, 0xa8, 0x00, 0xc2, 0x74, 0x1f,\n    0xc5, 0xb7, 0x03, 0xc5, 0xae, 0x03, 0xc5, 0x00,\n    0x00, 0x00, 0xb7, 0x03, 0xc2, 0xc6, 0x1f, 0xc5,\n    0x95, 0x03, 0x80, 0x97, 0x03, 0x80, 0x97, 0x03,\n    0xc5, 0xbf, 0x1f, 0x80, 0xbf, 0x1f, 0x81, 0xbf,\n    0x1f, 0xc2, 0xb9, 0x03, 0x86, 0xb9, 0x03, 0x84,\n    0xca, 0x03, 0x80, 0x00, 0x03, 0xb9, 0x42, 0xca,\n    0x42, 0x99, 0x06, 0x99, 0x04, 0x99, 0x00, 0xfe,\n    0x1f, 0x80, 0xfe, 0x1f, 0x81, 0xfe, 0x1f, 0xc2,\n    0xc5, 0x03, 0x86, 0xc5, 0x03, 0x84, 0xcb, 0x03,\n    0x80, 0x00, 0x03, 0xc1, 0x13, 0xc1, 0x14, 0xc5,\n    0x42, 0xcb, 0x42, 0xa5, 0x06, 0xa5, 0x04, 0xa5,\n    0x00, 0xa1, 0x03, 0x94, 0xa8, 0x00, 0x80, 0x85,\n    0x03, 0x60, 0x00, 0x7c, 0x1f, 0xc5, 0xc9, 0x03,\n    0xc5, 0xce, 0x03, 0xc5, 0x00, 0x00, 0x00, 0xc9,\n    0x03, 0xc2, 0xf6, 0x1f, 0xc5, 0x9f, 0x03, 0x80,\n    0xa9, 0x03, 0x80, 0xa9, 0x03, 0xc5, 0x20, 0x94,\n    0x02, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n    0x20, 0x20, 0x20, 0x20, 0xb3, 0x2e, 0x2e, 0x2e,\n    0x2e, 0x2e, 0x32, 0x20, 0x32, 0x20, 0x32, 0x20,\n    0x00, 0x00, 0x00, 0x35, 0x20, 0x35, 0x20, 0x35,\n    0x20, 0x00, 0x00, 0x00, 0x21, 0x21, 0x00, 0x00,\n    0x20, 0x85, 0x3f, 0x3f, 0x3f, 0x21, 0x21, 0x3f,\n    0x32, 0x20, 0x00, 0x00, 0x00, 0x00, 0x30, 0x69,\n    0x00, 0x00, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,\n    0x2b, 0x3d, 0x28, 0x29, 0x6e, 0x30, 0x00, 0x2b,\n    0x00, 0x12, 0x22, 0x3d, 0x00, 0x28, 0x00, 0x29,\n    0x00, 0x00, 0x00, 0x61, 0x00, 0x65, 0x00, 0x6f,\n    0x00, 0x78, 0x00, 0x59, 0x02, 0x68, 0x6b, 0x6c,\n    0x6d, 0x6e, 0x70, 0x73, 0x74, 0x52, 0x73, 0x61,\n    0x2f, 0x63, 0x61, 0x2f, 0x73, 0xb0, 0x00, 0x43,\n    0x63, 0x2f, 0x6f, 0x63, 0x2f, 0x75, 0xb0, 0x00,\n    0x46, 0x48, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20,\n    0xdf, 0x01, 0x01, 0x04, 0x24, 0x4e, 0x6f, 0x50,\n    0x51, 0x52, 0x52, 0x52, 0x53, 0x4d, 0x54, 0x45,\n    0x4c, 0x54, 0x4d, 0x4b, 0x00, 0xc5, 0x00, 0x42,\n    0x43, 0x00, 0x65, 0x45, 0x46, 0x00, 0x4d, 0x6f,\n    0xd0, 0x05, 0x46, 0x41, 0x58, 0xc0, 0x03, 0xb3,\n    0x03, 0x93, 0x03, 0xa0, 0x03, 0x11, 0x22, 0x44,\n    0x64, 0x65, 0x69, 0x6a, 0x31, 0xd0, 0x37, 0x31,\n    0xd0, 0x39, 0x31, 0xd0, 0x31, 0x30, 0x31, 0xd0,\n    0x33, 0x32, 0xd0, 0x33, 0x31, 0xd0, 0x35, 0x32,\n    0xd0, 0x35, 0x33, 0xd0, 0x35, 0x34, 0xd0, 0x35,\n    0x31, 0xd0, 0x36, 0x35, 0xd0, 0x36, 0x31, 0xd0,\n    0x38, 0x33, 0xd0, 0x38, 0x35, 0xd0, 0x38, 0x37,\n    0xd0, 0x38, 0x31, 0xd0, 0x49, 0x49, 0x49, 0x49,\n    0x49, 0x49, 0x56, 0x56, 0x49, 0x56, 0x49, 0x49,\n    0x56, 0x49, 0x49, 0x49, 0x49, 0x58, 0x58, 0x49,\n    0x58, 0x49, 0x49, 0x4c, 0x43, 0x44, 0x4d, 0x69,\n    0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x76, 0x76,\n    0x69, 0x76, 0x69, 0x69, 0x76, 0x69, 0x69, 0x69,\n    0x69, 0x78, 0x78, 0x69, 0x78, 0x69, 0x69, 0x6c,\n    0x63, 0x64, 0x6d, 0x30, 0xd0, 0x33, 0x90, 0x21,\n    0xb8, 0x92, 0x21, 0xb8, 0x94, 0x21, 0xb8, 0xd0,\n    0x21, 0xb8, 0xd4, 0x21, 0xb8, 0xd2, 0x21, 0xb8,\n    0x03, 0x22, 0xb8, 0x08, 0x22, 0xb8, 0x0b, 0x22,\n    0xb8, 0x23, 0x22, 0xb8, 0x00, 0x00, 0x00, 0x25,\n    0x22, 0xb8, 0x2b, 0x22, 0x2b, 0x22, 0x2b, 0x22,\n    0x00, 0x00, 0x00, 0x2e, 0x22, 0x2e, 0x22, 0x2e,\n    0x22, 0x00, 0x00, 0x00, 0x3c, 0x22, 0xb8, 0x43,\n    0x22, 0xb8, 0x45, 0x22, 0xb8, 0x00, 0x00, 0x00,\n    0x48, 0x22, 0xb8, 0x3d, 0x00, 0xb8, 0x00, 0x00,\n    0x00, 0x61, 0x22, 0xb8, 0x4d, 0x22, 0xb8, 0x3c,\n    0x00, 0xb8, 0x3e, 0x00, 0xb8, 0x64, 0x22, 0xb8,\n    0x65, 0x22, 0xb8, 0x72, 0x22, 0xb8, 0x76, 0x22,\n    0xb8, 0x7a, 0x22, 0xb8, 0x82, 0x22, 0xb8, 0x86,\n    0x22, 0xb8, 0xa2, 0x22, 0xb8, 0xa8, 0x22, 0xb8,\n    0xa9, 0x22, 0xb8, 0xab, 0x22, 0xb8, 0x7c, 0x22,\n    0xb8, 0x91, 0x22, 0xb8, 0xb2, 0x22, 0x38, 0x03,\n    0x08, 0x30, 0x31, 0x00, 0x31, 0x00, 0x30, 0x00,\n    0x32, 0x30, 0x28, 0x00, 0x31, 0x00, 0x29, 0x00,\n    0x28, 0x00, 0x31, 0x00, 0x30, 0x00, 0x29, 0x00,\n    0x28, 0x32, 0x30, 0x29, 0x31, 0x00, 0x2e, 0x00,\n    0x31, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x32, 0x30,\n    0x2e, 0x28, 0x00, 0x61, 0x00, 0x29, 0x00, 0x41,\n    0x00, 0x61, 0x00, 0x2b, 0x22, 0x00, 0x00, 0x00,\n    0x00, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d,\n    0x3d, 0xdd, 0x2a, 0xb8, 0x6a, 0x56, 0x00, 0x4e,\n    0x00, 0x28, 0x36, 0x3f, 0x59, 0x85, 0x8c, 0xa0,\n    0xba, 0x3f, 0x51, 0x00, 0x26, 0x2c, 0x43, 0x57,\n    0x6c, 0xa1, 0xb6, 0xc1, 0x9b, 0x52, 0x00, 0x5e,\n    0x7a, 0x7f, 0x9d, 0xa6, 0xc1, 0xce, 0xe7, 0xb6,\n    0x53, 0xc8, 0x53, 0xe3, 0x53, 0xd7, 0x56, 0x1f,\n    0x57, 0xeb, 0x58, 0x02, 0x59, 0x0a, 0x59, 0x15,\n    0x59, 0x27, 0x59, 0x73, 0x59, 0x50, 0x5b, 0x80,\n    0x5b, 0xf8, 0x5b, 0x0f, 0x5c, 0x22, 0x5c, 0x38,\n    0x5c, 0x6e, 0x5c, 0x71, 0x5c, 0xdb, 0x5d, 0xe5,\n    0x5d, 0xf1, 0x5d, 0xfe, 0x5d, 0x72, 0x5e, 0x7a,\n    0x5e, 0x7f, 0x5e, 0xf4, 0x5e, 0xfe, 0x5e, 0x0b,\n    0x5f, 0x13, 0x5f, 0x50, 0x5f, 0x61, 0x5f, 0x73,\n    0x5f, 0xc3, 0x5f, 0x08, 0x62, 0x36, 0x62, 0x4b,\n    0x62, 0x2f, 0x65, 0x34, 0x65, 0x87, 0x65, 0x97,\n    0x65, 0xa4, 0x65, 0xb9, 0x65, 0xe0, 0x65, 0xe5,\n    0x65, 0xf0, 0x66, 0x08, 0x67, 0x28, 0x67, 0x20,\n    0x6b, 0x62, 0x6b, 0x79, 0x6b, 0xb3, 0x6b, 0xcb,\n    0x6b, 0xd4, 0x6b, 0xdb, 0x6b, 0x0f, 0x6c, 0x14,\n    0x6c, 0x34, 0x6c, 0x6b, 0x70, 0x2a, 0x72, 0x36,\n    0x72, 0x3b, 0x72, 0x3f, 0x72, 0x47, 0x72, 0x59,\n    0x72, 0x5b, 0x72, 0xac, 0x72, 0x84, 0x73, 0x89,\n    0x73, 0xdc, 0x74, 0xe6, 0x74, 0x18, 0x75, 0x1f,\n    0x75, 0x28, 0x75, 0x30, 0x75, 0x8b, 0x75, 0x92,\n    0x75, 0x76, 0x76, 0x7d, 0x76, 0xae, 0x76, 0xbf,\n    0x76, 0xee, 0x76, 0xdb, 0x77, 0xe2, 0x77, 0xf3,\n    0x77, 0x3a, 0x79, 0xb8, 0x79, 0xbe, 0x79, 0x74,\n    0x7a, 0xcb, 0x7a, 0xf9, 0x7a, 0x73, 0x7c, 0xf8,\n    0x7c, 0x36, 0x7f, 0x51, 0x7f, 0x8a, 0x7f, 0xbd,\n    0x7f, 0x01, 0x80, 0x0c, 0x80, 0x12, 0x80, 0x33,\n    0x80, 0x7f, 0x80, 0x89, 0x80, 0xe3, 0x81, 0x00,\n    0x07, 0x10, 0x19, 0x29, 0x38, 0x3c, 0x8b, 0x8f,\n    0x95, 0x4d, 0x86, 0x6b, 0x86, 0x40, 0x88, 0x4c,\n    0x88, 0x63, 0x88, 0x7e, 0x89, 0x8b, 0x89, 0xd2,\n    0x89, 0x00, 0x8a, 0x37, 0x8c, 0x46, 0x8c, 0x55,\n    0x8c, 0x78, 0x8c, 0x9d, 0x8c, 0x64, 0x8d, 0x70,\n    0x8d, 0xb3, 0x8d, 0xab, 0x8e, 0xca, 0x8e, 0x9b,\n    0x8f, 0xb0, 0x8f, 0xb5, 0x8f, 0x91, 0x90, 0x49,\n    0x91, 0xc6, 0x91, 0xcc, 0x91, 0xd1, 0x91, 0x77,\n    0x95, 0x80, 0x95, 0x1c, 0x96, 0xb6, 0x96, 0xb9,\n    0x96, 0xe8, 0x96, 0x51, 0x97, 0x5e, 0x97, 0x62,\n    0x97, 0x69, 0x97, 0xcb, 0x97, 0xed, 0x97, 0xf3,\n    0x97, 0x01, 0x98, 0xa8, 0x98, 0xdb, 0x98, 0xdf,\n    0x98, 0x96, 0x99, 0x99, 0x99, 0xac, 0x99, 0xa8,\n    0x9a, 0xd8, 0x9a, 0xdf, 0x9a, 0x25, 0x9b, 0x2f,\n    0x9b, 0x32, 0x9b, 0x3c, 0x9b, 0x5a, 0x9b, 0xe5,\n    0x9c, 0x75, 0x9e, 0x7f, 0x9e, 0xa5, 0x9e, 0x00,\n    0x16, 0x1e, 0x28, 0x2c, 0x54, 0x58, 0x69, 0x6e,\n    0x7b, 0x96, 0xa5, 0xad, 0xe8, 0xf7, 0xfb, 0x12,\n    0x30, 0x00, 0x00, 0x41, 0x53, 0x44, 0x53, 0x45,\n    0x53, 0x4b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x4d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x4f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x51, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x53, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x55, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x57, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x59, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x5b, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x5d, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x5f, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0x61, 0x30, 0x99, 0x30, 0x64, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0x66, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0x68, 0x30, 0x99,\n    0x30, 0x6f, 0x30, 0x99, 0x30, 0x72, 0x30, 0x99,\n    0x30, 0x75, 0x30, 0x99, 0x30, 0x78, 0x30, 0x99,\n    0x30, 0x7b, 0x30, 0x99, 0x30, 0x46, 0x30, 0x99,\n    0x30, 0x20, 0x00, 0x99, 0x30, 0x9d, 0x30, 0x99,\n    0x30, 0x88, 0x30, 0x8a, 0x30, 0xab, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xad, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x30, 0x99,\n    0x30, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x30, 0x99,\n    0x30, 0xc4, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0xc6, 0x30, 0x99, 0x30, 0x00, 0x00, 0x00,\n    0x00, 0xc8, 0x30, 0x99, 0x30, 0xcf, 0x30, 0x99,\n    0x30, 0xd2, 0x30, 0x99, 0x30, 0xd5, 0x30, 0x99,\n    0x30, 0xd8, 0x30, 0x99, 0x30, 0xdb, 0x30, 0x99,\n    0x30, 0xa6, 0x30, 0x99, 0x30, 0xef, 0x30, 0x99,\n    0x30, 0xfd, 0x30, 0x99, 0x30, 0xb3, 0x30, 0xc8,\n    0x30, 0x00, 0x11, 0x00, 0x01, 0xaa, 0x02, 0xac,\n    0xad, 0x03, 0x04, 0x05, 0xb0, 0xb1, 0xb2, 0xb3,\n    0xb4, 0xb5, 0x1a, 0x06, 0x07, 0x08, 0x21, 0x09,\n    0x11, 0x61, 0x11, 0x14, 0x11, 0x4c, 0x00, 0x01,\n    0xb3, 0xb4, 0xb8, 0xba, 0xbf, 0xc3, 0xc5, 0x08,\n    0xc9, 0xcb, 0x09, 0x0a, 0x0c, 0x0e, 0x0f, 0x13,\n    0x15, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1e, 0x22,\n    0x2c, 0x33, 0x38, 0xdd, 0xde, 0x43, 0x44, 0x45,\n    0x70, 0x71, 0x74, 0x7d, 0x7e, 0x80, 0x8a, 0x8d,\n    0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56,\n    0x0a, 0x4e, 0x2d, 0x4e, 0x0b, 0x4e, 0x32, 0x75,\n    0x59, 0x4e, 0x19, 0x4e, 0x01, 0x4e, 0x29, 0x59,\n    0x30, 0x57, 0xba, 0x4e, 0x28, 0x00, 0x29, 0x00,\n    0x00, 0x11, 0x02, 0x11, 0x03, 0x11, 0x05, 0x11,\n    0x06, 0x11, 0x07, 0x11, 0x09, 0x11, 0x0b, 0x11,\n    0x0c, 0x11, 0x0e, 0x11, 0x0f, 0x11, 0x10, 0x11,\n    0x11, 0x11, 0x12, 0x11, 0x28, 0x00, 0x00, 0x11,\n    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x02, 0x11,\n    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x05, 0x11,\n    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x09, 0x11,\n    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,\n    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0e, 0x11,\n    0x61, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0c, 0x11,\n    0x6e, 0x11, 0x29, 0x00, 0x28, 0x00, 0x0b, 0x11,\n    0x69, 0x11, 0x0c, 0x11, 0x65, 0x11, 0xab, 0x11,\n    0x29, 0x00, 0x28, 0x00, 0x0b, 0x11, 0x69, 0x11,\n    0x12, 0x11, 0x6e, 0x11, 0x29, 0x00, 0x28, 0x00,\n    0x29, 0x00, 0x00, 0x4e, 0x8c, 0x4e, 0x09, 0x4e,\n    0xdb, 0x56, 0x94, 0x4e, 0x6d, 0x51, 0x03, 0x4e,\n    0x6b, 0x51, 0x5d, 0x4e, 0x41, 0x53, 0x08, 0x67,\n    0x6b, 0x70, 0x34, 0x6c, 0x28, 0x67, 0xd1, 0x91,\n    0x1f, 0x57, 0xe5, 0x65, 0x2a, 0x68, 0x09, 0x67,\n    0x3e, 0x79, 0x0d, 0x54, 0x79, 0x72, 0xa1, 0x8c,\n    0x5d, 0x79, 0xb4, 0x52, 0xe3, 0x4e, 0x7c, 0x54,\n    0x66, 0x5b, 0xe3, 0x76, 0x01, 0x4f, 0xc7, 0x8c,\n    0x54, 0x53, 0x6d, 0x79, 0x11, 0x4f, 0xea, 0x81,\n    0xf3, 0x81, 0x4f, 0x55, 0x7c, 0x5e, 0x87, 0x65,\n    0x8f, 0x7b, 0x50, 0x54, 0x45, 0x32, 0x00, 0x31,\n    0x00, 0x33, 0x00, 0x30, 0x00, 0x00, 0x11, 0x00,\n    0x02, 0x03, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x0c,\n    0x0e, 0x0f, 0x10, 0x11, 0x12, 0x00, 0x11, 0x00,\n    0x61, 0x02, 0x61, 0x03, 0x61, 0x05, 0x61, 0x06,\n    0x61, 0x07, 0x61, 0x09, 0x61, 0x0b, 0x61, 0x0c,\n    0x61, 0x0e, 0x11, 0x61, 0x11, 0x00, 0x11, 0x0e,\n    0x61, 0xb7, 0x00, 0x69, 0x0b, 0x11, 0x01, 0x63,\n    0x00, 0x69, 0x0b, 0x11, 0x6e, 0x11, 0x00, 0x4e,\n    0x8c, 0x4e, 0x09, 0x4e, 0xdb, 0x56, 0x94, 0x4e,\n    0x6d, 0x51, 0x03, 0x4e, 0x6b, 0x51, 0x5d, 0x4e,\n    0x41, 0x53, 0x08, 0x67, 0x6b, 0x70, 0x34, 0x6c,\n    0x28, 0x67, 0xd1, 0x91, 0x1f, 0x57, 0xe5, 0x65,\n    0x2a, 0x68, 0x09, 0x67, 0x3e, 0x79, 0x0d, 0x54,\n    0x79, 0x72, 0xa1, 0x8c, 0x5d, 0x79, 0xb4, 0x52,\n    0xd8, 0x79, 0x37, 0x75, 0x73, 0x59, 0x69, 0x90,\n    0x2a, 0x51, 0x70, 0x53, 0xe8, 0x6c, 0x05, 0x98,\n    0x11, 0x4f, 0x99, 0x51, 0x63, 0x6b, 0x0a, 0x4e,\n    0x2d, 0x4e, 0x0b, 0x4e, 0xe6, 0x5d, 0xf3, 0x53,\n    0x3b, 0x53, 0x97, 0x5b, 0x66, 0x5b, 0xe3, 0x76,\n    0x01, 0x4f, 0xc7, 0x8c, 0x54, 0x53, 0x1c, 0x59,\n    0x33, 0x00, 0x36, 0x00, 0x34, 0x00, 0x30, 0x00,\n    0x35, 0x30, 0x31, 0x00, 0x08, 0x67, 0x31, 0x00,\n    0x30, 0x00, 0x08, 0x67, 0x48, 0x67, 0x65, 0x72,\n    0x67, 0x65, 0x56, 0x4c, 0x54, 0x44, 0xa2, 0x30,\n    0x00, 0x02, 0x04, 0x06, 0x08, 0x09, 0x0b, 0x0d,\n    0x0f, 0x11, 0x13, 0x15, 0x17, 0x19, 0x1b, 0x1d,\n    0x1f, 0x22, 0x24, 0x26, 0x28, 0x29, 0x2a, 0x2b,\n    0x2c, 0x2d, 0x30, 0x33, 0x36, 0x39, 0x3c, 0x3d,\n    0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x47, 0x48,\n    0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0xe4,\n    0x4e, 0x8c, 0x54, 0xa1, 0x30, 0x01, 0x30, 0x5b,\n    0x27, 0x01, 0x4a, 0x34, 0x00, 0x01, 0x52, 0x39,\n    0x01, 0xa2, 0x30, 0x00, 0x5a, 0x49, 0xa4, 0x30,\n    0x00, 0x27, 0x4f, 0x0c, 0xa4, 0x30, 0x00, 0x4f,\n    0x1d, 0x02, 0x05, 0x4f, 0xa8, 0x30, 0x00, 0x11,\n    0x07, 0x54, 0x21, 0xa8, 0x30, 0x00, 0x54, 0x03,\n    0x54, 0xa4, 0x30, 0x06, 0x4f, 0x15, 0x06, 0x58,\n    0x3c, 0x07, 0x00, 0x46, 0xab, 0x30, 0x00, 0x3e,\n    0x18, 0x1d, 0x00, 0x42, 0x3f, 0x51, 0xac, 0x30,\n    0x00, 0x41, 0x47, 0x00, 0x47, 0x32, 0xae, 0x30,\n    0xac, 0x30, 0xae, 0x30, 0x00, 0x1d, 0x4e, 0xad,\n    0x30, 0x00, 0x38, 0x3d, 0x4f, 0x01, 0x3e, 0x13,\n    0x4f, 0xad, 0x30, 0xed, 0x30, 0xad, 0x30, 0x00,\n    0x40, 0x03, 0x3c, 0x33, 0xad, 0x30, 0x00, 0x40,\n    0x34, 0x4f, 0x1b, 0x3e, 0xad, 0x30, 0x00, 0x40,\n    0x42, 0x16, 0x1b, 0xb0, 0x30, 0x00, 0x39, 0x30,\n    0xa4, 0x30, 0x0c, 0x45, 0x3c, 0x24, 0x4f, 0x0b,\n    0x47, 0x18, 0x00, 0x49, 0xaf, 0x30, 0x00, 0x3e,\n    0x4d, 0x1e, 0xb1, 0x30, 0x00, 0x4b, 0x08, 0x02,\n    0x3a, 0x19, 0x02, 0x4b, 0x2c, 0xa4, 0x30, 0x11,\n    0x00, 0x0b, 0x47, 0xb5, 0x30, 0x00, 0x3e, 0x0c,\n    0x47, 0x2b, 0xb0, 0x30, 0x07, 0x3a, 0x43, 0x00,\n    0xb9, 0x30, 0x02, 0x3a, 0x08, 0x02, 0x3a, 0x0f,\n    0x07, 0x43, 0x00, 0xb7, 0x30, 0x10, 0x00, 0x12,\n    0x34, 0x11, 0x3c, 0x13, 0x17, 0xa4, 0x30, 0x2a,\n    0x1f, 0x24, 0x2b, 0x00, 0x20, 0xbb, 0x30, 0x16,\n    0x41, 0x00, 0x38, 0x0d, 0xc4, 0x30, 0x0d, 0x38,\n    0x00, 0xd0, 0x30, 0x00, 0x2c, 0x1c, 0x1b, 0xa2,\n    0x30, 0x32, 0x00, 0x17, 0x26, 0x49, 0xaf, 0x30,\n    0x25, 0x00, 0x3c, 0xb3, 0x30, 0x21, 0x00, 0x20,\n    0x38, 0xa1, 0x30, 0x34, 0x00, 0x48, 0x22, 0x28,\n    0xa3, 0x30, 0x32, 0x00, 0x59, 0x25, 0xa7, 0x30,\n    0x2f, 0x1c, 0x10, 0x00, 0x44, 0xd5, 0x30, 0x00,\n    0x14, 0x1e, 0xaf, 0x30, 0x29, 0x00, 0x10, 0x4d,\n    0x3c, 0xda, 0x30, 0xbd, 0x30, 0xb8, 0x30, 0x22,\n    0x13, 0x1a, 0x20, 0x33, 0x0c, 0x22, 0x3b, 0x01,\n    0x22, 0x44, 0x00, 0x21, 0x44, 0x07, 0xa4, 0x30,\n    0x39, 0x00, 0x4f, 0x24, 0xc8, 0x30, 0x14, 0x23,\n    0x00, 0xdb, 0x30, 0xf3, 0x30, 0xc9, 0x30, 0x14,\n    0x2a, 0x00, 0x12, 0x33, 0x22, 0x12, 0x33, 0x2a,\n    0xa4, 0x30, 0x3a, 0x00, 0x0b, 0x49, 0xa4, 0x30,\n    0x3a, 0x00, 0x47, 0x3a, 0x1f, 0x2b, 0x3a, 0x47,\n    0x0b, 0xb7, 0x30, 0x27, 0x3c, 0x00, 0x30, 0x3c,\n    0xaf, 0x30, 0x30, 0x00, 0x3e, 0x44, 0xdf, 0x30,\n    0xea, 0x30, 0xd0, 0x30, 0x0f, 0x1a, 0x00, 0x2c,\n    0x1b, 0xe1, 0x30, 0xac, 0x30, 0xac, 0x30, 0x35,\n    0x00, 0x1c, 0x47, 0x35, 0x50, 0x1c, 0x3f, 0xa2,\n    0x30, 0x42, 0x5a, 0x27, 0x42, 0x5a, 0x49, 0x44,\n    0x00, 0x51, 0xc3, 0x30, 0x27, 0x00, 0x05, 0x28,\n    0xea, 0x30, 0xe9, 0x30, 0xd4, 0x30, 0x17, 0x00,\n    0x28, 0xd6, 0x30, 0x15, 0x26, 0x00, 0x15, 0xec,\n    0x30, 0xe0, 0x30, 0xb2, 0x30, 0x3a, 0x41, 0x16,\n    0x00, 0x41, 0xc3, 0x30, 0x2c, 0x00, 0x05, 0x30,\n    0x00, 0xb9, 0x70, 0x31, 0x00, 0x30, 0x00, 0xb9,\n    0x70, 0x32, 0x00, 0x30, 0x00, 0xb9, 0x70, 0x68,\n    0x50, 0x61, 0x64, 0x61, 0x41, 0x55, 0x62, 0x61,\n    0x72, 0x6f, 0x56, 0x70, 0x63, 0x64, 0x6d, 0x64,\n    0x00, 0x6d, 0x00, 0xb2, 0x00, 0x49, 0x00, 0x55,\n    0x00, 0x73, 0x5e, 0x10, 0x62, 0x2d, 0x66, 0x8c,\n    0x54, 0x27, 0x59, 0x63, 0x6b, 0x0e, 0x66, 0xbb,\n    0x6c, 0x2a, 0x68, 0x0f, 0x5f, 0x1a, 0x4f, 0x3e,\n    0x79, 0x70, 0x00, 0x41, 0x6e, 0x00, 0x41, 0xbc,\n    0x03, 0x41, 0x6d, 0x00, 0x41, 0x6b, 0x00, 0x41,\n    0x4b, 0x00, 0x42, 0x4d, 0x00, 0x42, 0x47, 0x00,\n    0x42, 0x63, 0x61, 0x6c, 0x6b, 0x63, 0x61, 0x6c,\n    0x70, 0x00, 0x46, 0x6e, 0x00, 0x46, 0xbc, 0x03,\n    0x46, 0xbc, 0x03, 0x67, 0x6d, 0x00, 0x67, 0x6b,\n    0x00, 0x67, 0x48, 0x00, 0x7a, 0x6b, 0x48, 0x7a,\n    0x4d, 0x48, 0x7a, 0x47, 0x48, 0x7a, 0x54, 0x48,\n    0x7a, 0xbc, 0x03, 0x13, 0x21, 0x6d, 0x00, 0x13,\n    0x21, 0x64, 0x00, 0x13, 0x21, 0x6b, 0x00, 0x13,\n    0x21, 0x66, 0x00, 0x6d, 0x6e, 0x00, 0x6d, 0xbc,\n    0x03, 0x6d, 0x6d, 0x00, 0x6d, 0x63, 0x00, 0x6d,\n    0x6b, 0x00, 0x6d, 0x63, 0x00, 0x0a, 0x0a, 0x4f,\n    0x00, 0x0a, 0x4f, 0x6d, 0x00, 0xb2, 0x00, 0x63,\n    0x00, 0x08, 0x0a, 0x4f, 0x0a, 0x0a, 0x50, 0x00,\n    0x0a, 0x50, 0x6d, 0x00, 0xb3, 0x00, 0x6b, 0x00,\n    0x6d, 0x00, 0xb3, 0x00, 0x6d, 0x00, 0x15, 0x22,\n    0x73, 0x00, 0x6d, 0x00, 0x15, 0x22, 0x73, 0x00,\n    0xb2, 0x00, 0x50, 0x61, 0x6b, 0x50, 0x61, 0x4d,\n    0x50, 0x61, 0x47, 0x50, 0x61, 0x72, 0x61, 0x64,\n    0x72, 0x61, 0x64, 0xd1, 0x73, 0x72, 0x00, 0x61,\n    0x00, 0x64, 0x00, 0x15, 0x22, 0x73, 0x00, 0xb2,\n    0x00, 0x70, 0x00, 0x73, 0x6e, 0x00, 0x73, 0xbc,\n    0x03, 0x73, 0x6d, 0x00, 0x73, 0x70, 0x00, 0x56,\n    0x6e, 0x00, 0x56, 0xbc, 0x03, 0x56, 0x6d, 0x00,\n    0x56, 0x6b, 0x00, 0x56, 0x4d, 0x00, 0x56, 0x70,\n    0x00, 0x57, 0x6e, 0x00, 0x57, 0xbc, 0x03, 0x57,\n    0x6d, 0x00, 0x57, 0x6b, 0x00, 0x57, 0x4d, 0x00,\n    0x57, 0x6b, 0x00, 0xa9, 0x03, 0x4d, 0x00, 0xa9,\n    0x03, 0x61, 0x2e, 0x6d, 0x2e, 0x42, 0x71, 0x63,\n    0x63, 0x63, 0x64, 0x43, 0xd1, 0x6b, 0x67, 0x43,\n    0x6f, 0x2e, 0x64, 0x42, 0x47, 0x79, 0x68, 0x61,\n    0x48, 0x50, 0x69, 0x6e, 0x4b, 0x4b, 0x4b, 0x4d,\n    0x6b, 0x74, 0x6c, 0x6d, 0x6c, 0x6e, 0x6c, 0x6f,\n    0x67, 0x6c, 0x78, 0x6d, 0x62, 0x6d, 0x69, 0x6c,\n    0x6d, 0x6f, 0x6c, 0x50, 0x48, 0x70, 0x2e, 0x6d,\n    0x2e, 0x50, 0x50, 0x4d, 0x50, 0x52, 0x73, 0x72,\n    0x53, 0x76, 0x57, 0x62, 0x56, 0xd1, 0x6d, 0x41,\n    0xd1, 0x6d, 0x31, 0x00, 0xe5, 0x65, 0x31, 0x00,\n    0x30, 0x00, 0xe5, 0x65, 0x32, 0x00, 0x30, 0x00,\n    0xe5, 0x65, 0x33, 0x00, 0x30, 0x00, 0xe5, 0x65,\n    0x67, 0x61, 0x6c, 0x4a, 0x04, 0x4c, 0x04, 0x53,\n    0x43, 0x46, 0x51, 0x26, 0x01, 0x53, 0x01, 0x27,\n    0xa7, 0x37, 0xab, 0x6b, 0x02, 0x52, 0xab, 0x48,\n    0x8c, 0xf4, 0x66, 0xca, 0x8e, 0xc8, 0x8c, 0xd1,\n    0x6e, 0x32, 0x4e, 0xe5, 0x53, 0x9c, 0x9f, 0x9c,\n    0x9f, 0x51, 0x59, 0xd1, 0x91, 0x87, 0x55, 0x48,\n    0x59, 0xf6, 0x61, 0x69, 0x76, 0x85, 0x7f, 0x3f,\n    0x86, 0xba, 0x87, 0xf8, 0x88, 0x8f, 0x90, 0x02,\n    0x6a, 0x1b, 0x6d, 0xd9, 0x70, 0xde, 0x73, 0x3d,\n    0x84, 0x6a, 0x91, 0xf1, 0x99, 0x82, 0x4e, 0x75,\n    0x53, 0x04, 0x6b, 0x1b, 0x72, 0x2d, 0x86, 0x1e,\n    0x9e, 0x50, 0x5d, 0xeb, 0x6f, 0xcd, 0x85, 0x64,\n    0x89, 0xc9, 0x62, 0xd8, 0x81, 0x1f, 0x88, 0xca,\n    0x5e, 0x17, 0x67, 0x6a, 0x6d, 0xfc, 0x72, 0xce,\n    0x90, 0x86, 0x4f, 0xb7, 0x51, 0xde, 0x52, 0xc4,\n    0x64, 0xd3, 0x6a, 0x10, 0x72, 0xe7, 0x76, 0x01,\n    0x80, 0x06, 0x86, 0x5c, 0x86, 0xef, 0x8d, 0x32,\n    0x97, 0x6f, 0x9b, 0xfa, 0x9d, 0x8c, 0x78, 0x7f,\n    0x79, 0xa0, 0x7d, 0xc9, 0x83, 0x04, 0x93, 0x7f,\n    0x9e, 0xd6, 0x8a, 0xdf, 0x58, 0x04, 0x5f, 0x60,\n    0x7c, 0x7e, 0x80, 0x62, 0x72, 0xca, 0x78, 0xc2,\n    0x8c, 0xf7, 0x96, 0xd8, 0x58, 0x62, 0x5c, 0x13,\n    0x6a, 0xda, 0x6d, 0x0f, 0x6f, 0x2f, 0x7d, 0x37,\n    0x7e, 0x4b, 0x96, 0xd2, 0x52, 0x8b, 0x80, 0xdc,\n    0x51, 0xcc, 0x51, 0x1c, 0x7a, 0xbe, 0x7d, 0xf1,\n    0x83, 0x75, 0x96, 0x80, 0x8b, 0xcf, 0x62, 0x02,\n    0x6a, 0xfe, 0x8a, 0x39, 0x4e, 0xe7, 0x5b, 0x12,\n    0x60, 0x87, 0x73, 0x70, 0x75, 0x17, 0x53, 0xfb,\n    0x78, 0xbf, 0x4f, 0xa9, 0x5f, 0x0d, 0x4e, 0xcc,\n    0x6c, 0x78, 0x65, 0x22, 0x7d, 0xc3, 0x53, 0x5e,\n    0x58, 0x01, 0x77, 0x49, 0x84, 0xaa, 0x8a, 0xba,\n    0x6b, 0xb0, 0x8f, 0x88, 0x6c, 0xfe, 0x62, 0xe5,\n    0x82, 0xa0, 0x63, 0x65, 0x75, 0xae, 0x4e, 0x69,\n    0x51, 0xc9, 0x51, 0x81, 0x68, 0xe7, 0x7c, 0x6f,\n    0x82, 0xd2, 0x8a, 0xcf, 0x91, 0xf5, 0x52, 0x42,\n    0x54, 0x73, 0x59, 0xec, 0x5e, 0xc5, 0x65, 0xfe,\n    0x6f, 0x2a, 0x79, 0xad, 0x95, 0x6a, 0x9a, 0x97,\n    0x9e, 0xce, 0x9e, 0x9b, 0x52, 0xc6, 0x66, 0x77,\n    0x6b, 0x62, 0x8f, 0x74, 0x5e, 0x90, 0x61, 0x00,\n    0x62, 0x9a, 0x64, 0x23, 0x6f, 0x49, 0x71, 0x89,\n    0x74, 0xca, 0x79, 0xf4, 0x7d, 0x6f, 0x80, 0x26,\n    0x8f, 0xee, 0x84, 0x23, 0x90, 0x4a, 0x93, 0x17,\n    0x52, 0xa3, 0x52, 0xbd, 0x54, 0xc8, 0x70, 0xc2,\n    0x88, 0xaa, 0x8a, 0xc9, 0x5e, 0xf5, 0x5f, 0x7b,\n    0x63, 0xae, 0x6b, 0x3e, 0x7c, 0x75, 0x73, 0xe4,\n    0x4e, 0xf9, 0x56, 0xe7, 0x5b, 0xba, 0x5d, 0x1c,\n    0x60, 0xb2, 0x73, 0x69, 0x74, 0x9a, 0x7f, 0x46,\n    0x80, 0x34, 0x92, 0xf6, 0x96, 0x48, 0x97, 0x18,\n    0x98, 0x8b, 0x4f, 0xae, 0x79, 0xb4, 0x91, 0xb8,\n    0x96, 0xe1, 0x60, 0x86, 0x4e, 0xda, 0x50, 0xee,\n    0x5b, 0x3f, 0x5c, 0x99, 0x65, 0x02, 0x6a, 0xce,\n    0x71, 0x42, 0x76, 0xfc, 0x84, 0x7c, 0x90, 0x8d,\n    0x9f, 0x88, 0x66, 0x2e, 0x96, 0x89, 0x52, 0x7b,\n    0x67, 0xf3, 0x67, 0x41, 0x6d, 0x9c, 0x6e, 0x09,\n    0x74, 0x59, 0x75, 0x6b, 0x78, 0x10, 0x7d, 0x5e,\n    0x98, 0x6d, 0x51, 0x2e, 0x62, 0x78, 0x96, 0x2b,\n    0x50, 0x19, 0x5d, 0xea, 0x6d, 0x2a, 0x8f, 0x8b,\n    0x5f, 0x44, 0x61, 0x17, 0x68, 0x87, 0x73, 0x86,\n    0x96, 0x29, 0x52, 0x0f, 0x54, 0x65, 0x5c, 0x13,\n    0x66, 0x4e, 0x67, 0xa8, 0x68, 0xe5, 0x6c, 0x06,\n    0x74, 0xe2, 0x75, 0x79, 0x7f, 0xcf, 0x88, 0xe1,\n    0x88, 0xcc, 0x91, 0xe2, 0x96, 0x3f, 0x53, 0xba,\n    0x6e, 0x1d, 0x54, 0xd0, 0x71, 0x98, 0x74, 0xfa,\n    0x85, 0xa3, 0x96, 0x57, 0x9c, 0x9f, 0x9e, 0x97,\n    0x67, 0xcb, 0x6d, 0xe8, 0x81, 0xcb, 0x7a, 0x20,\n    0x7b, 0x92, 0x7c, 0xc0, 0x72, 0x99, 0x70, 0x58,\n    0x8b, 0xc0, 0x4e, 0x36, 0x83, 0x3a, 0x52, 0x07,\n    0x52, 0xa6, 0x5e, 0xd3, 0x62, 0xd6, 0x7c, 0x85,\n    0x5b, 0x1e, 0x6d, 0xb4, 0x66, 0x3b, 0x8f, 0x4c,\n    0x88, 0x4d, 0x96, 0x8b, 0x89, 0xd3, 0x5e, 0x40,\n    0x51, 0xc0, 0x55, 0x00, 0x00, 0x00, 0x00, 0x5a,\n    0x58, 0x00, 0x00, 0x74, 0x66, 0x00, 0x00, 0x00,\n    0x00, 0xde, 0x51, 0x2a, 0x73, 0xca, 0x76, 0x3c,\n    0x79, 0x5e, 0x79, 0x65, 0x79, 0x8f, 0x79, 0x56,\n    0x97, 0xbe, 0x7c, 0xbd, 0x7f, 0x00, 0x00, 0x12,\n    0x86, 0x00, 0x00, 0xf8, 0x8a, 0x00, 0x00, 0x00,\n    0x00, 0x38, 0x90, 0xfd, 0x90, 0xef, 0x98, 0xfc,\n    0x98, 0x28, 0x99, 0xb4, 0x9d, 0xde, 0x90, 0xb7,\n    0x96, 0xae, 0x4f, 0xe7, 0x50, 0x4d, 0x51, 0xc9,\n    0x52, 0xe4, 0x52, 0x51, 0x53, 0x9d, 0x55, 0x06,\n    0x56, 0x68, 0x56, 0x40, 0x58, 0xa8, 0x58, 0x64,\n    0x5c, 0x6e, 0x5c, 0x94, 0x60, 0x68, 0x61, 0x8e,\n    0x61, 0xf2, 0x61, 0x4f, 0x65, 0xe2, 0x65, 0x91,\n    0x66, 0x85, 0x68, 0x77, 0x6d, 0x1a, 0x6e, 0x22,\n    0x6f, 0x6e, 0x71, 0x2b, 0x72, 0x22, 0x74, 0x91,\n    0x78, 0x3e, 0x79, 0x49, 0x79, 0x48, 0x79, 0x50,\n    0x79, 0x56, 0x79, 0x5d, 0x79, 0x8d, 0x79, 0x8e,\n    0x79, 0x40, 0x7a, 0x81, 0x7a, 0xc0, 0x7b, 0xf4,\n    0x7d, 0x09, 0x7e, 0x41, 0x7e, 0x72, 0x7f, 0x05,\n    0x80, 0xed, 0x81, 0x79, 0x82, 0x79, 0x82, 0x57,\n    0x84, 0x10, 0x89, 0x96, 0x89, 0x01, 0x8b, 0x39,\n    0x8b, 0xd3, 0x8c, 0x08, 0x8d, 0xb6, 0x8f, 0x38,\n    0x90, 0xe3, 0x96, 0xff, 0x97, 0x3b, 0x98, 0x75,\n    0x60, 0xee, 0x42, 0x18, 0x82, 0x02, 0x26, 0x4e,\n    0xb5, 0x51, 0x68, 0x51, 0x80, 0x4f, 0x45, 0x51,\n    0x80, 0x51, 0xc7, 0x52, 0xfa, 0x52, 0x9d, 0x55,\n    0x55, 0x55, 0x99, 0x55, 0xe2, 0x55, 0x5a, 0x58,\n    0xb3, 0x58, 0x44, 0x59, 0x54, 0x59, 0x62, 0x5a,\n    0x28, 0x5b, 0xd2, 0x5e, 0xd9, 0x5e, 0x69, 0x5f,\n    0xad, 0x5f, 0xd8, 0x60, 0x4e, 0x61, 0x08, 0x61,\n    0x8e, 0x61, 0x60, 0x61, 0xf2, 0x61, 0x34, 0x62,\n    0xc4, 0x63, 0x1c, 0x64, 0x52, 0x64, 0x56, 0x65,\n    0x74, 0x66, 0x17, 0x67, 0x1b, 0x67, 0x56, 0x67,\n    0x79, 0x6b, 0xba, 0x6b, 0x41, 0x6d, 0xdb, 0x6e,\n    0xcb, 0x6e, 0x22, 0x6f, 0x1e, 0x70, 0x6e, 0x71,\n    0xa7, 0x77, 0x35, 0x72, 0xaf, 0x72, 0x2a, 0x73,\n    0x71, 0x74, 0x06, 0x75, 0x3b, 0x75, 0x1d, 0x76,\n    0x1f, 0x76, 0xca, 0x76, 0xdb, 0x76, 0xf4, 0x76,\n    0x4a, 0x77, 0x40, 0x77, 0xcc, 0x78, 0xb1, 0x7a,\n    0xc0, 0x7b, 0x7b, 0x7c, 0x5b, 0x7d, 0xf4, 0x7d,\n    0x3e, 0x7f, 0x05, 0x80, 0x52, 0x83, 0xef, 0x83,\n    0x79, 0x87, 0x41, 0x89, 0x86, 0x89, 0x96, 0x89,\n    0xbf, 0x8a, 0xf8, 0x8a, 0xcb, 0x8a, 0x01, 0x8b,\n    0xfe, 0x8a, 0xed, 0x8a, 0x39, 0x8b, 0x8a, 0x8b,\n    0x08, 0x8d, 0x38, 0x8f, 0x72, 0x90, 0x99, 0x91,\n    0x76, 0x92, 0x7c, 0x96, 0xe3, 0x96, 0x56, 0x97,\n    0xdb, 0x97, 0xff, 0x97, 0x0b, 0x98, 0x3b, 0x98,\n    0x12, 0x9b, 0x9c, 0x9f, 0x4a, 0x28, 0x44, 0x28,\n    0xd5, 0x33, 0x9d, 0x3b, 0x18, 0x40, 0x39, 0x40,\n    0x49, 0x52, 0xd0, 0x5c, 0xd3, 0x7e, 0x43, 0x9f,\n    0x8e, 0x9f, 0x2a, 0xa0, 0x02, 0x66, 0x66, 0x66,\n    0x69, 0x66, 0x6c, 0x66, 0x66, 0x69, 0x66, 0x66,\n    0x6c, 0x7f, 0x01, 0x74, 0x73, 0x00, 0x74, 0x65,\n    0x05, 0x0f, 0x11, 0x0f, 0x00, 0x0f, 0x06, 0x19,\n    0x11, 0x0f, 0x08, 0xd9, 0x05, 0xb4, 0x05, 0x00,\n    0x00, 0x00, 0x00, 0xf2, 0x05, 0xb7, 0x05, 0xd0,\n    0x05, 0x12, 0x00, 0x03, 0x04, 0x0b, 0x0c, 0x0d,\n    0x18, 0x1a, 0xe9, 0x05, 0xc1, 0x05, 0xe9, 0x05,\n    0xc2, 0x05, 0x49, 0xfb, 0xc1, 0x05, 0x49, 0xfb,\n    0xc2, 0x05, 0xd0, 0x05, 0xb7, 0x05, 0xd0, 0x05,\n    0xb8, 0x05, 0xd0, 0x05, 0xbc, 0x05, 0xd8, 0x05,\n    0xbc, 0x05, 0xde, 0x05, 0xbc, 0x05, 0xe0, 0x05,\n    0xbc, 0x05, 0xe3, 0x05, 0xbc, 0x05, 0xb9, 0x05,\n    0x2d, 0x03, 0x2e, 0x03, 0x2f, 0x03, 0x30, 0x03,\n    0x31, 0x03, 0x1c, 0x00, 0x18, 0x06, 0x22, 0x06,\n    0x2b, 0x06, 0xd0, 0x05, 0xdc, 0x05, 0x71, 0x06,\n    0x00, 0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x0d, 0x0d,\n    0x0d, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x09, 0x09,\n    0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, 0x08, 0x08,\n    0x08, 0x08, 0x33, 0x33, 0x33, 0x33, 0x35, 0x35,\n    0x35, 0x35, 0x13, 0x13, 0x13, 0x13, 0x12, 0x12,\n    0x12, 0x12, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16,\n    0x16, 0x16, 0x1c, 0x1c, 0x1b, 0x1b, 0x1d, 0x1d,\n    0x17, 0x17, 0x27, 0x27, 0x20, 0x20, 0x38, 0x38,\n    0x38, 0x38, 0x3e, 0x3e, 0x3e, 0x3e, 0x42, 0x42,\n    0x42, 0x42, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49,\n    0x4a, 0x4a, 0x4a, 0x4a, 0x4f, 0x4f, 0x50, 0x50,\n    0x50, 0x50, 0x4d, 0x4d, 0x4d, 0x4d, 0x61, 0x61,\n    0x62, 0x62, 0x49, 0x06, 0x64, 0x64, 0x64, 0x64,\n    0x7e, 0x7e, 0x7d, 0x7d, 0x7f, 0x7f, 0x2e, 0x82,\n    0x82, 0x7c, 0x7c, 0x80, 0x80, 0x87, 0x87, 0x87,\n    0x87, 0x00, 0x00, 0x26, 0x06, 0x00, 0x01, 0x00,\n    0x01, 0x00, 0xaf, 0x00, 0xaf, 0x00, 0x22, 0x00,\n    0x22, 0x00, 0xa1, 0x00, 0xa1, 0x00, 0xa0, 0x00,\n    0xa0, 0x00, 0xa2, 0x00, 0xa2, 0x00, 0xaa, 0x00,\n    0xaa, 0x00, 0xaa, 0x00, 0x23, 0x00, 0x23, 0x00,\n    0x23, 0xcc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x26,\n    0x06, 0x00, 0x06, 0x00, 0x07, 0x00, 0x1f, 0x00,\n    0x23, 0x00, 0x24, 0x02, 0x06, 0x02, 0x07, 0x02,\n    0x08, 0x02, 0x1f, 0x02, 0x23, 0x02, 0x24, 0x04,\n    0x06, 0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04,\n    0x23, 0x04, 0x24, 0x05, 0x06, 0x05, 0x1f, 0x05,\n    0x23, 0x05, 0x24, 0x06, 0x07, 0x06, 0x1f, 0x07,\n    0x06, 0x07, 0x1f, 0x08, 0x06, 0x08, 0x07, 0x08,\n    0x1f, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x08, 0x0d,\n    0x1f, 0x0f, 0x07, 0x0f, 0x1f, 0x10, 0x06, 0x10,\n    0x07, 0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x11,\n    0x1f, 0x12, 0x1f, 0x13, 0x06, 0x13, 0x1f, 0x14,\n    0x06, 0x14, 0x1f, 0x1b, 0x06, 0x1b, 0x07, 0x1b,\n    0x08, 0x1b, 0x1f, 0x1b, 0x23, 0x1b, 0x24, 0x1c,\n    0x07, 0x1c, 0x1f, 0x1c, 0x23, 0x1c, 0x24, 0x1d,\n    0x01, 0x1d, 0x06, 0x1d, 0x07, 0x1d, 0x08, 0x1d,\n    0x1e, 0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e,\n    0x06, 0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e,\n    0x23, 0x1e, 0x24, 0x1f, 0x06, 0x1f, 0x07, 0x1f,\n    0x08, 0x1f, 0x1f, 0x1f, 0x23, 0x1f, 0x24, 0x20,\n    0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f, 0x20,\n    0x23, 0x20, 0x24, 0x21, 0x06, 0x21, 0x1f, 0x21,\n    0x23, 0x21, 0x24, 0x24, 0x06, 0x24, 0x07, 0x24,\n    0x08, 0x24, 0x1f, 0x24, 0x23, 0x24, 0x24, 0x0a,\n    0x4a, 0x0b, 0x4a, 0x23, 0x4a, 0x20, 0x00, 0x4c,\n    0x06, 0x51, 0x06, 0x51, 0x06, 0xff, 0x00, 0x1f,\n    0x26, 0x06, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x1f,\n    0x00, 0x20, 0x00, 0x23, 0x00, 0x24, 0x02, 0x0b,\n    0x02, 0x0c, 0x02, 0x1f, 0x02, 0x20, 0x02, 0x23,\n    0x02, 0x24, 0x04, 0x0b, 0x04, 0x0c, 0x04, 0x1f,\n    0x26, 0x06, 0x04, 0x20, 0x04, 0x23, 0x04, 0x24,\n    0x05, 0x0b, 0x05, 0x0c, 0x05, 0x1f, 0x05, 0x20,\n    0x05, 0x23, 0x05, 0x24, 0x1b, 0x23, 0x1b, 0x24,\n    0x1c, 0x23, 0x1c, 0x24, 0x1d, 0x01, 0x1d, 0x1e,\n    0x1d, 0x1f, 0x1d, 0x23, 0x1d, 0x24, 0x1e, 0x1f,\n    0x1e, 0x23, 0x1e, 0x24, 0x1f, 0x01, 0x1f, 0x1f,\n    0x20, 0x0b, 0x20, 0x0c, 0x20, 0x1f, 0x20, 0x20,\n    0x20, 0x23, 0x20, 0x24, 0x23, 0x4a, 0x24, 0x0b,\n    0x24, 0x0c, 0x24, 0x1f, 0x24, 0x20, 0x24, 0x23,\n    0x24, 0x24, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08,\n    0x00, 0x1f, 0x00, 0x21, 0x02, 0x06, 0x02, 0x07,\n    0x02, 0x08, 0x02, 0x1f, 0x02, 0x21, 0x04, 0x06,\n    0x04, 0x07, 0x04, 0x08, 0x04, 0x1f, 0x04, 0x21,\n    0x05, 0x1f, 0x06, 0x07, 0x06, 0x1f, 0x07, 0x06,\n    0x07, 0x1f, 0x08, 0x06, 0x08, 0x1f, 0x0d, 0x06,\n    0x0d, 0x07, 0x0d, 0x08, 0x0d, 0x1f, 0x0f, 0x07,\n    0x0f, 0x08, 0x0f, 0x1f, 0x10, 0x06, 0x10, 0x07,\n    0x10, 0x08, 0x10, 0x1f, 0x11, 0x07, 0x12, 0x1f,\n    0x13, 0x06, 0x13, 0x1f, 0x14, 0x06, 0x14, 0x1f,\n    0x1b, 0x06, 0x1b, 0x07, 0x1b, 0x08, 0x1b, 0x1f,\n    0x1c, 0x07, 0x1c, 0x1f, 0x1d, 0x06, 0x1d, 0x07,\n    0x1d, 0x08, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x06,\n    0x1e, 0x07, 0x1e, 0x08, 0x1e, 0x1f, 0x1e, 0x21,\n    0x1f, 0x06, 0x1f, 0x07, 0x1f, 0x08, 0x1f, 0x1f,\n    0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x1f,\n    0x20, 0x21, 0x21, 0x06, 0x21, 0x1f, 0x21, 0x4a,\n    0x24, 0x06, 0x24, 0x07, 0x24, 0x08, 0x24, 0x1f,\n    0x24, 0x21, 0x00, 0x1f, 0x00, 0x21, 0x02, 0x1f,\n    0x02, 0x21, 0x04, 0x1f, 0x04, 0x21, 0x05, 0x1f,\n    0x05, 0x21, 0x0d, 0x1f, 0x0d, 0x21, 0x0e, 0x1f,\n    0x0e, 0x21, 0x1d, 0x1e, 0x1d, 0x1f, 0x1e, 0x1f,\n    0x20, 0x1f, 0x20, 0x21, 0x24, 0x1f, 0x24, 0x21,\n    0x40, 0x06, 0x4e, 0x06, 0x51, 0x06, 0x27, 0x06,\n    0x10, 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23,\n    0x13, 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23,\n    0x0d, 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23,\n    0x05, 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23,\n    0x0e, 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23,\n    0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e,\n    0x0d, 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a,\n    0x10, 0x22, 0x10, 0x23, 0x12, 0x22, 0x12, 0x23,\n    0x13, 0x22, 0x13, 0x23, 0x0c, 0x22, 0x0c, 0x23,\n    0x0d, 0x22, 0x0d, 0x23, 0x06, 0x22, 0x06, 0x23,\n    0x05, 0x22, 0x05, 0x23, 0x07, 0x22, 0x07, 0x23,\n    0x0e, 0x22, 0x0e, 0x23, 0x0f, 0x22, 0x0f, 0x23,\n    0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e,\n    0x0d, 0x0a, 0x0c, 0x0a, 0x0e, 0x0a, 0x0f, 0x0a,\n    0x0d, 0x05, 0x0d, 0x06, 0x0d, 0x07, 0x0d, 0x1e,\n    0x0c, 0x20, 0x0d, 0x20, 0x10, 0x1e, 0x0c, 0x05,\n    0x0c, 0x06, 0x0c, 0x07, 0x0d, 0x05, 0x0d, 0x06,\n    0x0d, 0x07, 0x10, 0x1e, 0x11, 0x1e, 0x00, 0x24,\n    0x00, 0x24, 0x2a, 0x06, 0x00, 0x02, 0x1b, 0x00,\n    0x03, 0x02, 0x00, 0x03, 0x02, 0x00, 0x03, 0x1b,\n    0x00, 0x04, 0x1b, 0x00, 0x1b, 0x02, 0x00, 0x1b,\n    0x03, 0x00, 0x1b, 0x04, 0x02, 0x1b, 0x03, 0x02,\n    0x1b, 0x03, 0x03, 0x1b, 0x20, 0x03, 0x1b, 0x1f,\n    0x09, 0x03, 0x02, 0x09, 0x02, 0x03, 0x09, 0x02,\n    0x1f, 0x09, 0x1b, 0x03, 0x09, 0x1b, 0x03, 0x09,\n    0x1b, 0x02, 0x09, 0x1b, 0x1b, 0x09, 0x1b, 0x1b,\n    0x0b, 0x03, 0x03, 0x0b, 0x03, 0x03, 0x0b, 0x1b,\n    0x1b, 0x0a, 0x03, 0x1b, 0x0a, 0x03, 0x1b, 0x0a,\n    0x02, 0x20, 0x0a, 0x1b, 0x04, 0x0a, 0x1b, 0x04,\n    0x0a, 0x1b, 0x1b, 0x0a, 0x1b, 0x1b, 0x0c, 0x03,\n    0x1f, 0x0c, 0x04, 0x1b, 0x0c, 0x04, 0x1b, 0x0d,\n    0x1b, 0x03, 0x0d, 0x1b, 0x03, 0x0d, 0x1b, 0x1b,\n    0x0d, 0x1b, 0x20, 0x0f, 0x02, 0x1b, 0x0f, 0x1b,\n    0x1b, 0x0f, 0x1b, 0x1b, 0x0f, 0x1b, 0x1f, 0x10,\n    0x1b, 0x1b, 0x10, 0x1b, 0x20, 0x10, 0x1b, 0x1f,\n    0x17, 0x04, 0x1b, 0x17, 0x04, 0x1b, 0x18, 0x1b,\n    0x03, 0x18, 0x1b, 0x1b, 0x1a, 0x03, 0x1b, 0x1a,\n    0x03, 0x20, 0x1a, 0x03, 0x1f, 0x1a, 0x02, 0x02,\n    0x1a, 0x02, 0x02, 0x1a, 0x04, 0x1b, 0x1a, 0x04,\n    0x1b, 0x1a, 0x1b, 0x03, 0x1a, 0x1b, 0x03, 0x1b,\n    0x03, 0x02, 0x1b, 0x03, 0x1b, 0x1b, 0x03, 0x20,\n    0x1b, 0x02, 0x03, 0x1b, 0x02, 0x1b, 0x1b, 0x04,\n    0x02, 0x1b, 0x04, 0x1b, 0x28, 0x06, 0x1d, 0x04,\n    0x06, 0x1f, 0x1d, 0x04, 0x1f, 0x1d, 0x1d, 0x1e,\n    0x05, 0x1d, 0x1e, 0x05, 0x21, 0x1e, 0x04, 0x1d,\n    0x1e, 0x04, 0x1d, 0x1e, 0x04, 0x21, 0x1e, 0x1d,\n    0x22, 0x1e, 0x1d, 0x21, 0x22, 0x1d, 0x1d, 0x22,\n    0x1d, 0x1d, 0x00, 0x06, 0x22, 0x02, 0x04, 0x22,\n    0x02, 0x04, 0x21, 0x02, 0x06, 0x22, 0x02, 0x06,\n    0x21, 0x02, 0x1d, 0x22, 0x02, 0x1d, 0x21, 0x04,\n    0x1d, 0x22, 0x04, 0x05, 0x21, 0x04, 0x1d, 0x21,\n    0x0b, 0x06, 0x21, 0x0d, 0x05, 0x22, 0x0c, 0x05,\n    0x22, 0x0e, 0x05, 0x22, 0x1c, 0x04, 0x22, 0x1c,\n    0x1d, 0x22, 0x22, 0x05, 0x22, 0x22, 0x04, 0x22,\n    0x22, 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1a, 0x1d,\n    0x22, 0x1e, 0x05, 0x22, 0x1a, 0x1d, 0x05, 0x1c,\n    0x05, 0x1d, 0x11, 0x1d, 0x22, 0x1b, 0x1d, 0x22,\n    0x1e, 0x04, 0x05, 0x1d, 0x06, 0x22, 0x1c, 0x04,\n    0x1d, 0x1b, 0x1d, 0x1d, 0x1c, 0x04, 0x1d, 0x1e,\n    0x04, 0x05, 0x04, 0x05, 0x22, 0x05, 0x04, 0x22,\n    0x1d, 0x04, 0x22, 0x19, 0x1d, 0x22, 0x00, 0x05,\n    0x22, 0x1b, 0x1d, 0x1d, 0x11, 0x04, 0x1d, 0x0d,\n    0x1d, 0x1d, 0x0b, 0x06, 0x22, 0x1e, 0x04, 0x22,\n    0x35, 0x06, 0x00, 0x0f, 0x9d, 0x0d, 0x0f, 0x9d,\n    0x27, 0x06, 0x00, 0x1d, 0x1d, 0x20, 0x00, 0x1c,\n    0x01, 0x0a, 0x1e, 0x06, 0x1e, 0x08, 0x0e, 0x1d,\n    0x12, 0x1e, 0x0a, 0x0c, 0x21, 0x1d, 0x12, 0x1d,\n    0x23, 0x20, 0x21, 0x0c, 0x1d, 0x1e, 0x35, 0x06,\n    0x00, 0x0f, 0x14, 0x27, 0x06, 0x0e, 0x1d, 0x22,\n    0xff, 0x00, 0x1d, 0x1d, 0x20, 0xff, 0x12, 0x1d,\n    0x23, 0x20, 0xff, 0x21, 0x0c, 0x1d, 0x1e, 0x27,\n    0x06, 0x05, 0x1d, 0xff, 0x05, 0x1d, 0x00, 0x1d,\n    0x20, 0x27, 0x06, 0x0a, 0xa5, 0x00, 0x1d, 0x2c,\n    0x00, 0x01, 0x30, 0x02, 0x30, 0x3a, 0x00, 0x3b,\n    0x00, 0x21, 0x00, 0x3f, 0x00, 0x16, 0x30, 0x17,\n    0x30, 0x26, 0x20, 0x13, 0x20, 0x12, 0x01, 0x00,\n    0x5f, 0x5f, 0x28, 0x29, 0x7b, 0x7d, 0x08, 0x30,\n    0x0c, 0x0d, 0x08, 0x09, 0x02, 0x03, 0x00, 0x01,\n    0x04, 0x05, 0x06, 0x07, 0x5b, 0x00, 0x5d, 0x00,\n    0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20, 0x3e, 0x20,\n    0x5f, 0x00, 0x5f, 0x00, 0x5f, 0x00, 0x2c, 0x00,\n    0x01, 0x30, 0x2e, 0x00, 0x00, 0x00, 0x3b, 0x00,\n    0x3a, 0x00, 0x3f, 0x00, 0x21, 0x00, 0x14, 0x20,\n    0x28, 0x00, 0x29, 0x00, 0x7b, 0x00, 0x7d, 0x00,\n    0x14, 0x30, 0x15, 0x30, 0x23, 0x26, 0x2a, 0x2b,\n    0x2d, 0x3c, 0x3e, 0x3d, 0x00, 0x5c, 0x24, 0x25,\n    0x40, 0x40, 0x06, 0xff, 0x0b, 0x00, 0x0b, 0xff,\n    0x0c, 0x20, 0x00, 0x4d, 0x06, 0x40, 0x06, 0xff,\n    0x0e, 0x00, 0x0e, 0xff, 0x0f, 0x00, 0x0f, 0xff,\n    0x10, 0x00, 0x10, 0xff, 0x11, 0x00, 0x11, 0xff,\n    0x12, 0x00, 0x12, 0x21, 0x06, 0x00, 0x01, 0x01,\n    0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05,\n    0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07,\n    0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a,\n    0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c,\n    0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e,\n    0x0f, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12,\n    0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14,\n    0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16,\n    0x16, 0x16, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18,\n    0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x20, 0x20,\n    0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22,\n    0x22, 0x22, 0x23, 0x23, 0x23, 0x23, 0x24, 0x24,\n    0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26,\n    0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29,\n    0x29, 0x29, 0x22, 0x06, 0x22, 0x00, 0x22, 0x00,\n    0x22, 0x01, 0x22, 0x01, 0x22, 0x03, 0x22, 0x03,\n    0x22, 0x05, 0x22, 0x05, 0x21, 0x00, 0x85, 0x29,\n    0x01, 0x30, 0x01, 0x0b, 0x0c, 0x00, 0xfa, 0xf1,\n    0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xe2, 0xe4, 0xe6,\n    0xc2, 0xfb, 0xa1, 0xa3, 0xa5, 0xa7, 0xa9, 0xaa,\n    0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba,\n    0xbc, 0xbe, 0xc0, 0xc3, 0xc5, 0xc7, 0xc9, 0xca,\n    0xcb, 0xcc, 0xcd, 0xce, 0xd1, 0xd4, 0xd7, 0xda,\n    0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe7,\n    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xee, 0xf2, 0x98,\n    0x99, 0x31, 0x31, 0x4f, 0x31, 0x55, 0x31, 0x5b,\n    0x31, 0x61, 0x31, 0xa2, 0x00, 0xa3, 0x00, 0xac,\n    0x00, 0xaf, 0x00, 0xa6, 0x00, 0xa5, 0x00, 0xa9,\n    0x20, 0x00, 0x00, 0x02, 0x25, 0x90, 0x21, 0x91,\n    0x21, 0x92, 0x21, 0x93, 0x21, 0xa0, 0x25, 0xcb,\n    0x25, 0xd2, 0x05, 0x07, 0x03, 0x01, 0xda, 0x05,\n    0x07, 0x03, 0x01, 0xd0, 0x02, 0xd1, 0x02, 0xe6,\n    0x00, 0x99, 0x02, 0x53, 0x02, 0x00, 0x00, 0xa3,\n    0x02, 0x66, 0xab, 0xa5, 0x02, 0xa4, 0x02, 0x56,\n    0x02, 0x57, 0x02, 0x91, 0x1d, 0x58, 0x02, 0x5e,\n    0x02, 0xa9, 0x02, 0x64, 0x02, 0x62, 0x02, 0x60,\n    0x02, 0x9b, 0x02, 0x27, 0x01, 0x9c, 0x02, 0x67,\n    0x02, 0x84, 0x02, 0xaa, 0x02, 0xab, 0x02, 0x6c,\n    0x02, 0x04, 0xdf, 0x8e, 0xa7, 0x6e, 0x02, 0x05,\n    0xdf, 0x8e, 0x02, 0x06, 0xdf, 0xf8, 0x00, 0x76,\n    0x02, 0x77, 0x02, 0x71, 0x00, 0x7a, 0x02, 0x08,\n    0xdf, 0x7d, 0x02, 0x7e, 0x02, 0x80, 0x02, 0xa8,\n    0x02, 0xa6, 0x02, 0x67, 0xab, 0xa7, 0x02, 0x88,\n    0x02, 0x71, 0x2c, 0x00, 0x00, 0x8f, 0x02, 0xa1,\n    0x02, 0xa2, 0x02, 0x98, 0x02, 0xc0, 0x01, 0xc1,\n    0x01, 0xc2, 0x01, 0x0a, 0xdf, 0x1e, 0xdf, 0x41,\n    0x04, 0x40, 0x00, 0x00, 0x00, 0x00, 0x14, 0x99,\n    0x10, 0xba, 0x10, 0x00, 0x00, 0x00, 0x00, 0x9b,\n    0x10, 0xba, 0x10, 0x05, 0x05, 0xa5, 0x10, 0xba,\n    0x10, 0x05, 0x31, 0x11, 0x27, 0x11, 0x32, 0x11,\n    0x27, 0x11, 0x55, 0x47, 0x13, 0x3e, 0x13, 0x47,\n    0x13, 0x57, 0x13, 0x55, 0x82, 0x13, 0xc9, 0x13,\n    0x00, 0x00, 0x00, 0x00, 0x84, 0x13, 0xbb, 0x13,\n    0x05, 0x05, 0x8b, 0x13, 0xc2, 0x13, 0x05, 0x90,\n    0x13, 0xc9, 0x13, 0x05, 0xc2, 0x13, 0xc2, 0x13,\n    0x00, 0x00, 0x00, 0x00, 0xc2, 0x13, 0xb8, 0x13,\n    0xc2, 0x13, 0xc9, 0x13, 0x05, 0x55, 0xb9, 0x14,\n    0xba, 0x14, 0xb9, 0x14, 0xb0, 0x14, 0x00, 0x00,\n    0x00, 0x00, 0xb9, 0x14, 0xbd, 0x14, 0x55, 0x50,\n    0xb8, 0x15, 0xaf, 0x15, 0xb9, 0x15, 0xaf, 0x15,\n    0x55, 0x35, 0x19, 0x30, 0x19, 0x05, 0x1e, 0x61,\n    0x1e, 0x61, 0x1e, 0x61, 0x29, 0x61, 0x1e, 0x61,\n    0x1f, 0x61, 0x29, 0x61, 0x1f, 0x61, 0x1e, 0x61,\n    0x20, 0x61, 0x21, 0x61, 0x1f, 0x61, 0x22, 0x61,\n    0x1f, 0x61, 0x21, 0x61, 0x20, 0x61, 0x55, 0x55,\n    0x55, 0x55, 0x67, 0x6d, 0x67, 0x6d, 0x63, 0x6d,\n    0x67, 0x6d, 0x69, 0x6d, 0x67, 0x6d, 0x55, 0x05,\n    0x41, 0x00, 0x30, 0x00, 0x57, 0xd1, 0x65, 0xd1,\n    0x58, 0xd1, 0x65, 0xd1, 0x5f, 0xd1, 0x6e, 0xd1,\n    0x5f, 0xd1, 0x6f, 0xd1, 0x5f, 0xd1, 0x70, 0xd1,\n    0x5f, 0xd1, 0x71, 0xd1, 0x5f, 0xd1, 0x72, 0xd1,\n    0x55, 0x55, 0x55, 0x05, 0xb9, 0xd1, 0x65, 0xd1,\n    0xba, 0xd1, 0x65, 0xd1, 0xbb, 0xd1, 0x6e, 0xd1,\n    0xbc, 0xd1, 0x6e, 0xd1, 0xbb, 0xd1, 0x6f, 0xd1,\n    0xbc, 0xd1, 0x6f, 0xd1, 0x55, 0x55, 0x55, 0x41,\n    0x00, 0x61, 0x00, 0x41, 0x00, 0x61, 0x00, 0x69,\n    0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x43,\n    0x44, 0x00, 0x00, 0x47, 0x00, 0x00, 0x4a, 0x4b,\n    0x00, 0x00, 0x4e, 0x4f, 0x50, 0x51, 0x00, 0x53,\n    0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61,\n    0x62, 0x63, 0x64, 0x00, 0x66, 0x68, 0x00, 0x70,\n    0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x42, 0x00,\n    0x44, 0x45, 0x46, 0x47, 0x4a, 0x00, 0x53, 0x00,\n    0x61, 0x00, 0x41, 0x42, 0x00, 0x44, 0x45, 0x46,\n    0x47, 0x00, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x00,\n    0x4f, 0x53, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61,\n    0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61,\n    0x00, 0x41, 0x00, 0x61, 0x00, 0x41, 0x00, 0x61,\n    0x00, 0x41, 0x00, 0x61, 0x00, 0x31, 0x01, 0x37,\n    0x02, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1,\n    0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x91,\n    0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24,\n    0x00, 0x1f, 0x04, 0x20, 0x05, 0x91, 0x03, 0xa3,\n    0x03, 0xb1, 0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f,\n    0x04, 0x20, 0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1,\n    0x03, 0xd1, 0x03, 0x24, 0x00, 0x1f, 0x04, 0x20,\n    0x05, 0x91, 0x03, 0xa3, 0x03, 0xb1, 0x03, 0xd1,\n    0x03, 0x24, 0x00, 0x1f, 0x04, 0x20, 0x05, 0x0b,\n    0x0c, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30,\n    0x00, 0x30, 0x00, 0x30, 0x04, 0x3a, 0x04, 0x3e,\n    0x04, 0x4b, 0x04, 0x4d, 0x04, 0x4e, 0x04, 0x89,\n    0xa6, 0x30, 0x04, 0xa9, 0x26, 0x28, 0xb9, 0x7f,\n    0x9f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,\n    0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x0f, 0x11, 0x13,\n    0x14, 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x61,\n    0x26, 0x25, 0x2f, 0x7b, 0x51, 0xa6, 0xb1, 0x04,\n    0x27, 0x06, 0x00, 0x01, 0x05, 0x08, 0x2a, 0x06,\n    0x1e, 0x08, 0x03, 0x0d, 0x20, 0x19, 0x1a, 0x1b,\n    0x1c, 0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a,\n    0x00, 0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x44,\n    0x90, 0x77, 0x45, 0x28, 0x06, 0x2c, 0x06, 0x00,\n    0x00, 0x47, 0x06, 0x33, 0x06, 0x17, 0x10, 0x11,\n    0x12, 0x13, 0x00, 0x06, 0x0e, 0x02, 0x0f, 0x34,\n    0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e, 0x06, 0x00,\n    0x00, 0x36, 0x06, 0x00, 0x00, 0x3a, 0x06, 0x2d,\n    0x06, 0x00, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x44,\n    0x06, 0x00, 0x00, 0x46, 0x06, 0x33, 0x06, 0x39,\n    0x06, 0x00, 0x00, 0x35, 0x06, 0x42, 0x06, 0x00,\n    0x00, 0x34, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2e,\n    0x06, 0x00, 0x00, 0x36, 0x06, 0x00, 0x00, 0x3a,\n    0x06, 0x00, 0x00, 0xba, 0x06, 0x00, 0x00, 0x6f,\n    0x06, 0x00, 0x00, 0x28, 0x06, 0x2c, 0x06, 0x00,\n    0x00, 0x47, 0x06, 0x00, 0x00, 0x00, 0x00, 0x2d,\n    0x06, 0x37, 0x06, 0x4a, 0x06, 0x43, 0x06, 0x00,\n    0x00, 0x45, 0x06, 0x46, 0x06, 0x33, 0x06, 0x39,\n    0x06, 0x41, 0x06, 0x35, 0x06, 0x42, 0x06, 0x00,\n    0x00, 0x34, 0x06, 0x2a, 0x06, 0x2b, 0x06, 0x2e,\n    0x06, 0x00, 0x00, 0x36, 0x06, 0x38, 0x06, 0x3a,\n    0x06, 0x6e, 0x06, 0x00, 0x00, 0xa1, 0x06, 0x27,\n    0x06, 0x00, 0x01, 0x05, 0x08, 0x20, 0x21, 0x0b,\n    0x06, 0x10, 0x23, 0x2a, 0x06, 0x1a, 0x1b, 0x1c,\n    0x09, 0x0f, 0x17, 0x0b, 0x18, 0x07, 0x0a, 0x00,\n    0x01, 0x04, 0x06, 0x0c, 0x0e, 0x10, 0x28, 0x06,\n    0x2c, 0x06, 0x2f, 0x06, 0x00, 0x00, 0x48, 0x06,\n    0x32, 0x06, 0x2d, 0x06, 0x37, 0x06, 0x4a, 0x06,\n    0x2a, 0x06, 0x1a, 0x1b, 0x1c, 0x09, 0x0f, 0x17,\n    0x0b, 0x18, 0x07, 0x0a, 0x00, 0x01, 0x04, 0x06,\n    0x0c, 0x0e, 0x10, 0x30, 0x2e, 0x30, 0x00, 0x2c,\n    0x00, 0x28, 0x00, 0x41, 0x00, 0x29, 0x00, 0x14,\n    0x30, 0x53, 0x00, 0x15, 0x30, 0x43, 0x52, 0x43,\n    0x44, 0x57, 0x5a, 0x41, 0x00, 0x48, 0x56, 0x4d,\n    0x56, 0x53, 0x44, 0x53, 0x53, 0x50, 0x50, 0x56,\n    0x57, 0x43, 0x4d, 0x43, 0x4d, 0x44, 0x4d, 0x52,\n    0x44, 0x4a, 0x4b, 0x30, 0x30, 0x00, 0x68, 0x68,\n    0x4b, 0x62, 0x57, 0x5b, 0xcc, 0x53, 0xc7, 0x30,\n    0x8c, 0x4e, 0x1a, 0x59, 0xe3, 0x89, 0x29, 0x59,\n    0xa4, 0x4e, 0x20, 0x66, 0x21, 0x71, 0x99, 0x65,\n    0x4d, 0x52, 0x8c, 0x5f, 0x8d, 0x51, 0xb0, 0x65,\n    0x1d, 0x52, 0x42, 0x7d, 0x1f, 0x75, 0xa9, 0x8c,\n    0xf0, 0x58, 0x39, 0x54, 0x14, 0x6f, 0x95, 0x62,\n    0x55, 0x63, 0x00, 0x4e, 0x09, 0x4e, 0x4a, 0x90,\n    0xe6, 0x5d, 0x2d, 0x4e, 0xf3, 0x53, 0x07, 0x63,\n    0x70, 0x8d, 0x53, 0x62, 0x81, 0x79, 0x7a, 0x7a,\n    0x08, 0x54, 0x80, 0x6e, 0x09, 0x67, 0x08, 0x67,\n    0x33, 0x75, 0x72, 0x52, 0xb6, 0x55, 0x4d, 0x91,\n    0x14, 0x30, 0x15, 0x30, 0x2c, 0x67, 0x09, 0x4e,\n    0x8c, 0x4e, 0x89, 0x5b, 0xb9, 0x70, 0x53, 0x62,\n    0xd7, 0x76, 0xdd, 0x52, 0x57, 0x65, 0x97, 0x5f,\n    0xef, 0x53, 0x30, 0x00, 0x38, 0x4e, 0x05, 0x00,\n    0x09, 0x22, 0x01, 0x60, 0x4f, 0xae, 0x4f, 0xbb,\n    0x4f, 0x02, 0x50, 0x7a, 0x50, 0x99, 0x50, 0xe7,\n    0x50, 0xcf, 0x50, 0x9e, 0x34, 0x3a, 0x06, 0x4d,\n    0x51, 0x54, 0x51, 0x64, 0x51, 0x77, 0x51, 0x1c,\n    0x05, 0xb9, 0x34, 0x67, 0x51, 0x8d, 0x51, 0x4b,\n    0x05, 0x97, 0x51, 0xa4, 0x51, 0xcc, 0x4e, 0xac,\n    0x51, 0xb5, 0x51, 0xdf, 0x91, 0xf5, 0x51, 0x03,\n    0x52, 0xdf, 0x34, 0x3b, 0x52, 0x46, 0x52, 0x72,\n    0x52, 0x77, 0x52, 0x15, 0x35, 0x02, 0x00, 0x20,\n    0x80, 0x80, 0x00, 0x08, 0x00, 0x00, 0xc7, 0x52,\n    0x00, 0x02, 0x1d, 0x33, 0x3e, 0x3f, 0x50, 0x82,\n    0x8a, 0x93, 0xac, 0xb6, 0xb8, 0xb8, 0xb8, 0x2c,\n    0x0a, 0x70, 0x70, 0xca, 0x53, 0xdf, 0x53, 0x63,\n    0x0b, 0xeb, 0x53, 0xf1, 0x53, 0x06, 0x54, 0x9e,\n    0x54, 0x38, 0x54, 0x48, 0x54, 0x68, 0x54, 0xa2,\n    0x54, 0xf6, 0x54, 0x10, 0x55, 0x53, 0x55, 0x63,\n    0x55, 0x84, 0x55, 0x84, 0x55, 0x99, 0x55, 0xab,\n    0x55, 0xb3, 0x55, 0xc2, 0x55, 0x16, 0x57, 0x06,\n    0x56, 0x17, 0x57, 0x51, 0x56, 0x74, 0x56, 0x07,\n    0x52, 0xee, 0x58, 0xce, 0x57, 0xf4, 0x57, 0x0d,\n    0x58, 0x8b, 0x57, 0x32, 0x58, 0x31, 0x58, 0xac,\n    0x58, 0xe4, 0x14, 0xf2, 0x58, 0xf7, 0x58, 0x06,\n    0x59, 0x1a, 0x59, 0x22, 0x59, 0x62, 0x59, 0xa8,\n    0x16, 0xea, 0x16, 0xec, 0x59, 0x1b, 0x5a, 0x27,\n    0x5a, 0xd8, 0x59, 0x66, 0x5a, 0xee, 0x36, 0xfc,\n    0x36, 0x08, 0x5b, 0x3e, 0x5b, 0x3e, 0x5b, 0xc8,\n    0x19, 0xc3, 0x5b, 0xd8, 0x5b, 0xe7, 0x5b, 0xf3,\n    0x5b, 0x18, 0x1b, 0xff, 0x5b, 0x06, 0x5c, 0x53,\n    0x5f, 0x22, 0x5c, 0x81, 0x37, 0x60, 0x5c, 0x6e,\n    0x5c, 0xc0, 0x5c, 0x8d, 0x5c, 0xe4, 0x1d, 0x43,\n    0x5d, 0xe6, 0x1d, 0x6e, 0x5d, 0x6b, 0x5d, 0x7c,\n    0x5d, 0xe1, 0x5d, 0xe2, 0x5d, 0x2f, 0x38, 0xfd,\n    0x5d, 0x28, 0x5e, 0x3d, 0x5e, 0x69, 0x5e, 0x62,\n    0x38, 0x83, 0x21, 0x7c, 0x38, 0xb0, 0x5e, 0xb3,\n    0x5e, 0xb6, 0x5e, 0xca, 0x5e, 0x92, 0xa3, 0xfe,\n    0x5e, 0x31, 0x23, 0x31, 0x23, 0x01, 0x82, 0x22,\n    0x5f, 0x22, 0x5f, 0xc7, 0x38, 0xb8, 0x32, 0xda,\n    0x61, 0x62, 0x5f, 0x6b, 0x5f, 0xe3, 0x38, 0x9a,\n    0x5f, 0xcd, 0x5f, 0xd7, 0x5f, 0xf9, 0x5f, 0x81,\n    0x60, 0x3a, 0x39, 0x1c, 0x39, 0x94, 0x60, 0xd4,\n    0x26, 0xc7, 0x60, 0x02, 0x02, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0a, 0x00,\n    0x00, 0x02, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00,\n    0x08, 0x80, 0x28, 0x80, 0x02, 0x00, 0x00, 0x02,\n    0x48, 0x61, 0x00, 0x04, 0x06, 0x04, 0x32, 0x46,\n    0x6a, 0x5c, 0x67, 0x96, 0xaa, 0xae, 0xc8, 0xd3,\n    0x5d, 0x62, 0x00, 0x54, 0x77, 0xf3, 0x0c, 0x2b,\n    0x3d, 0x63, 0xfc, 0x62, 0x68, 0x63, 0x83, 0x63,\n    0xe4, 0x63, 0xf1, 0x2b, 0x22, 0x64, 0xc5, 0x63,\n    0xa9, 0x63, 0x2e, 0x3a, 0x69, 0x64, 0x7e, 0x64,\n    0x9d, 0x64, 0x77, 0x64, 0x6c, 0x3a, 0x4f, 0x65,\n    0x6c, 0x65, 0x0a, 0x30, 0xe3, 0x65, 0xf8, 0x66,\n    0x49, 0x66, 0x19, 0x3b, 0x91, 0x66, 0x08, 0x3b,\n    0xe4, 0x3a, 0x92, 0x51, 0x95, 0x51, 0x00, 0x67,\n    0x9c, 0x66, 0xad, 0x80, 0xd9, 0x43, 0x17, 0x67,\n    0x1b, 0x67, 0x21, 0x67, 0x5e, 0x67, 0x53, 0x67,\n    0xc3, 0x33, 0x49, 0x3b, 0xfa, 0x67, 0x85, 0x67,\n    0x52, 0x68, 0x85, 0x68, 0x6d, 0x34, 0x8e, 0x68,\n    0x1f, 0x68, 0x14, 0x69, 0x9d, 0x3b, 0x42, 0x69,\n    0xa3, 0x69, 0xea, 0x69, 0xa8, 0x6a, 0xa3, 0x36,\n    0xdb, 0x6a, 0x18, 0x3c, 0x21, 0x6b, 0xa7, 0x38,\n    0x54, 0x6b, 0x4e, 0x3c, 0x72, 0x6b, 0x9f, 0x6b,\n    0xba, 0x6b, 0xbb, 0x6b, 0x8d, 0x3a, 0x0b, 0x1d,\n    0xfa, 0x3a, 0x4e, 0x6c, 0xbc, 0x3c, 0xbf, 0x6c,\n    0xcd, 0x6c, 0x67, 0x6c, 0x16, 0x6d, 0x3e, 0x6d,\n    0x77, 0x6d, 0x41, 0x6d, 0x69, 0x6d, 0x78, 0x6d,\n    0x85, 0x6d, 0x1e, 0x3d, 0x34, 0x6d, 0x2f, 0x6e,\n    0x6e, 0x6e, 0x33, 0x3d, 0xcb, 0x6e, 0xc7, 0x6e,\n    0xd1, 0x3e, 0xf9, 0x6d, 0x6e, 0x6f, 0x5e, 0x3f,\n    0x8e, 0x3f, 0xc6, 0x6f, 0x39, 0x70, 0x1e, 0x70,\n    0x1b, 0x70, 0x96, 0x3d, 0x4a, 0x70, 0x7d, 0x70,\n    0x77, 0x70, 0xad, 0x70, 0x25, 0x05, 0x45, 0x71,\n    0x63, 0x42, 0x9c, 0x71, 0xab, 0x43, 0x28, 0x72,\n    0x35, 0x72, 0x50, 0x72, 0x08, 0x46, 0x80, 0x72,\n    0x95, 0x72, 0x35, 0x47, 0x02, 0x20, 0x00, 0x00,\n    0x20, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00,\n    0x00, 0x02, 0x02, 0x80, 0x8a, 0x00, 0x00, 0x20,\n    0x00, 0x08, 0x0a, 0x00, 0x80, 0x88, 0x80, 0x20,\n    0x14, 0x48, 0x7a, 0x73, 0x8b, 0x73, 0xac, 0x3e,\n    0xa5, 0x73, 0xb8, 0x3e, 0xb8, 0x3e, 0x47, 0x74,\n    0x5c, 0x74, 0x71, 0x74, 0x85, 0x74, 0xca, 0x74,\n    0x1b, 0x3f, 0x24, 0x75, 0x36, 0x4c, 0x3e, 0x75,\n    0x92, 0x4c, 0x70, 0x75, 0x9f, 0x21, 0x10, 0x76,\n    0xa1, 0x4f, 0xb8, 0x4f, 0x44, 0x50, 0xfc, 0x3f,\n    0x08, 0x40, 0xf4, 0x76, 0xf3, 0x50, 0xf2, 0x50,\n    0x19, 0x51, 0x33, 0x51, 0x1e, 0x77, 0x1f, 0x77,\n    0x1f, 0x77, 0x4a, 0x77, 0x39, 0x40, 0x8b, 0x77,\n    0x46, 0x40, 0x96, 0x40, 0x1d, 0x54, 0x4e, 0x78,\n    0x8c, 0x78, 0xcc, 0x78, 0xe3, 0x40, 0x26, 0x56,\n    0x56, 0x79, 0x9a, 0x56, 0xc5, 0x56, 0x8f, 0x79,\n    0xeb, 0x79, 0x2f, 0x41, 0x40, 0x7a, 0x4a, 0x7a,\n    0x4f, 0x7a, 0x7c, 0x59, 0xa7, 0x5a, 0xa7, 0x5a,\n    0xee, 0x7a, 0x02, 0x42, 0xab, 0x5b, 0xc6, 0x7b,\n    0xc9, 0x7b, 0x27, 0x42, 0x80, 0x5c, 0xd2, 0x7c,\n    0xa0, 0x42, 0xe8, 0x7c, 0xe3, 0x7c, 0x00, 0x7d,\n    0x86, 0x5f, 0x63, 0x7d, 0x01, 0x43, 0xc7, 0x7d,\n    0x02, 0x7e, 0x45, 0x7e, 0x34, 0x43, 0x28, 0x62,\n    0x47, 0x62, 0x59, 0x43, 0xd9, 0x62, 0x7a, 0x7f,\n    0x3e, 0x63, 0x95, 0x7f, 0xfa, 0x7f, 0x05, 0x80,\n    0xda, 0x64, 0x23, 0x65, 0x60, 0x80, 0xa8, 0x65,\n    0x70, 0x80, 0x5f, 0x33, 0xd5, 0x43, 0xb2, 0x80,\n    0x03, 0x81, 0x0b, 0x44, 0x3e, 0x81, 0xb5, 0x5a,\n    0xa7, 0x67, 0xb5, 0x67, 0x93, 0x33, 0x9c, 0x33,\n    0x01, 0x82, 0x04, 0x82, 0x9e, 0x8f, 0x6b, 0x44,\n    0x91, 0x82, 0x8b, 0x82, 0x9d, 0x82, 0xb3, 0x52,\n    0xb1, 0x82, 0xb3, 0x82, 0xbd, 0x82, 0xe6, 0x82,\n    0x3c, 0x6b, 0xe5, 0x82, 0x1d, 0x83, 0x63, 0x83,\n    0xad, 0x83, 0x23, 0x83, 0xbd, 0x83, 0xe7, 0x83,\n    0x57, 0x84, 0x53, 0x83, 0xca, 0x83, 0xcc, 0x83,\n    0xdc, 0x83, 0x36, 0x6c, 0x6b, 0x6d, 0x02, 0x00,\n    0x00, 0x20, 0x22, 0x2a, 0xa0, 0x0a, 0x00, 0x20,\n    0x80, 0x28, 0x00, 0xa8, 0x20, 0x20, 0x00, 0x02,\n    0x80, 0x22, 0x02, 0x8a, 0x08, 0x00, 0xaa, 0x00,\n    0x00, 0x00, 0x02, 0x00, 0x00, 0x28, 0xd5, 0x6c,\n    0x2b, 0x45, 0xf1, 0x84, 0xf3, 0x84, 0x16, 0x85,\n    0xca, 0x73, 0x64, 0x85, 0x2c, 0x6f, 0x5d, 0x45,\n    0x61, 0x45, 0xb1, 0x6f, 0xd2, 0x70, 0x6b, 0x45,\n    0x50, 0x86, 0x5c, 0x86, 0x67, 0x86, 0x69, 0x86,\n    0xa9, 0x86, 0x88, 0x86, 0x0e, 0x87, 0xe2, 0x86,\n    0x79, 0x87, 0x28, 0x87, 0x6b, 0x87, 0x86, 0x87,\n    0xd7, 0x45, 0xe1, 0x87, 0x01, 0x88, 0xf9, 0x45,\n    0x60, 0x88, 0x63, 0x88, 0x67, 0x76, 0xd7, 0x88,\n    0xde, 0x88, 0x35, 0x46, 0xfa, 0x88, 0xbb, 0x34,\n    0xae, 0x78, 0x66, 0x79, 0xbe, 0x46, 0xc7, 0x46,\n    0xa0, 0x8a, 0xed, 0x8a, 0x8a, 0x8b, 0x55, 0x8c,\n    0xa8, 0x7c, 0xab, 0x8c, 0xc1, 0x8c, 0x1b, 0x8d,\n    0x77, 0x8d, 0x2f, 0x7f, 0x04, 0x08, 0xcb, 0x8d,\n    0xbc, 0x8d, 0xf0, 0x8d, 0xde, 0x08, 0xd4, 0x8e,\n    0x38, 0x8f, 0xd2, 0x85, 0xed, 0x85, 0x94, 0x90,\n    0xf1, 0x90, 0x11, 0x91, 0x2e, 0x87, 0x1b, 0x91,\n    0x38, 0x92, 0xd7, 0x92, 0xd8, 0x92, 0x7c, 0x92,\n    0xf9, 0x93, 0x15, 0x94, 0xfa, 0x8b, 0x8b, 0x95,\n    0x95, 0x49, 0xb7, 0x95, 0x77, 0x8d, 0xe6, 0x49,\n    0xc3, 0x96, 0xb2, 0x5d, 0x23, 0x97, 0x45, 0x91,\n    0x1a, 0x92, 0x6e, 0x4a, 0x76, 0x4a, 0xe0, 0x97,\n    0x0a, 0x94, 0xb2, 0x4a, 0x96, 0x94, 0x0b, 0x98,\n    0x0b, 0x98, 0x29, 0x98, 0xb6, 0x95, 0xe2, 0x98,\n    0x33, 0x4b, 0x29, 0x99, 0xa7, 0x99, 0xc2, 0x99,\n    0xfe, 0x99, 0xce, 0x4b, 0x30, 0x9b, 0x12, 0x9b,\n    0x40, 0x9c, 0xfd, 0x9c, 0xce, 0x4c, 0xed, 0x4c,\n    0x67, 0x9d, 0xce, 0xa0, 0xf8, 0x4c, 0x05, 0xa1,\n    0x0e, 0xa2, 0x91, 0xa2, 0xbb, 0x9e, 0x56, 0x4d,\n    0xf9, 0x9e, 0xfe, 0x9e, 0x05, 0x9f, 0x0f, 0x9f,\n    0x16, 0x9f, 0x3b, 0x9f, 0x00, 0xa6, 0x02, 0x88,\n    0xa0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x28,\n    0x00, 0x08, 0xa0, 0x80, 0xa0, 0x80, 0x00, 0x80,\n    0x80, 0x00, 0x0a, 0x88, 0x80, 0x00, 0x80, 0x00,\n    0x20, 0x2a, 0x00, 0x80,\n};\n\nstatic const uint16_t unicode_comp_table[965] = {\n    0x4a01, 0x49c0, 0x4a02, 0x0280, 0x0281, 0x0282, 0x0283, 0x02c0,\n    0x02c2, 0x0a00, 0x0284, 0x2442, 0x0285, 0x07c0, 0x0980, 0x0982,\n    0x2440, 0x2280, 0x02c4, 0x2282, 0x2284, 0x2286, 0x02c6, 0x02c8,\n    0x02ca, 0x02cc, 0x0287, 0x228a, 0x02ce, 0x228c, 0x2290, 0x2292,\n    0x228e, 0x0288, 0x0289, 0x028a, 0x2482, 0x0300, 0x0302, 0x0304,\n    0x028b, 0x2480, 0x0308, 0x0984, 0x0986, 0x2458, 0x0a02, 0x0306,\n    0x2298, 0x229a, 0x229e, 0x0900, 0x030a, 0x22a0, 0x030c, 0x030e,\n    0x0840, 0x0310, 0x0312, 0x22a2, 0x22a6, 0x09c0, 0x22a4, 0x22a8,\n    0x22aa, 0x028c, 0x028d, 0x028e, 0x0340, 0x0342, 0x0344, 0x0380,\n    0x028f, 0x248e, 0x07c2, 0x0988, 0x098a, 0x2490, 0x0346, 0x22ac,\n    0x0400, 0x22b0, 0x0842, 0x22b2, 0x0402, 0x22b4, 0x0440, 0x0444,\n    0x22b6, 0x0442, 0x22c2, 0x22c0, 0x22c4, 0x22c6, 0x22c8, 0x0940,\n    0x04c0, 0x0291, 0x22ca, 0x04c4, 0x22cc, 0x04c2, 0x22d0, 0x22ce,\n    0x0292, 0x0293, 0x0294, 0x0295, 0x0540, 0x0542, 0x0a08, 0x0296,\n    0x2494, 0x0544, 0x07c4, 0x098c, 0x098e, 0x06c0, 0x2492, 0x0844,\n    0x2308, 0x230a, 0x0580, 0x230c, 0x0584, 0x0990, 0x0992, 0x230e,\n    0x0582, 0x2312, 0x0586, 0x0588, 0x2314, 0x058c, 0x2316, 0x0998,\n    0x058a, 0x231e, 0x0590, 0x2320, 0x099a, 0x058e, 0x2324, 0x2322,\n    0x0299, 0x029a, 0x029b, 0x05c0, 0x05c2, 0x05c4, 0x029c, 0x24ac,\n    0x05c6, 0x05c8, 0x07c6, 0x0994, 0x0996, 0x0700, 0x24aa, 0x2326,\n    0x05ca, 0x232a, 0x2328, 0x2340, 0x2342, 0x2344, 0x2346, 0x05cc,\n    0x234a, 0x2348, 0x234c, 0x234e, 0x2350, 0x24b8, 0x029d, 0x05ce,\n    0x24be, 0x0a0c, 0x2352, 0x0600, 0x24bc, 0x24ba, 0x0640, 0x2354,\n    0x0642, 0x0644, 0x2356, 0x2358, 0x02a0, 0x02a1, 0x02a2, 0x02a3,\n    0x02c1, 0x02c3, 0x0a01, 0x02a4, 0x2443, 0x02a5, 0x07c1, 0x0981,\n    0x0983, 0x2441, 0x2281, 0x02c5, 0x2283, 0x2285, 0x2287, 0x02c7,\n    0x02c9, 0x02cb, 0x02cd, 0x02a7, 0x228b, 0x02cf, 0x228d, 0x2291,\n    0x2293, 0x228f, 0x02a8, 0x02a9, 0x02aa, 0x2483, 0x0301, 0x0303,\n    0x0305, 0x02ab, 0x2481, 0x0309, 0x0985, 0x0987, 0x2459, 0x0a03,\n    0x0307, 0x2299, 0x229b, 0x229f, 0x0901, 0x030b, 0x22a1, 0x030d,\n    0x030f, 0x0841, 0x0311, 0x0313, 0x22a3, 0x22a7, 0x09c1, 0x22a5,\n    0x22a9, 0x22ab, 0x2380, 0x02ac, 0x02ad, 0x02ae, 0x0341, 0x0343,\n    0x0345, 0x02af, 0x248f, 0x07c3, 0x0989, 0x098b, 0x2491, 0x0347,\n    0x22ad, 0x0401, 0x0884, 0x22b1, 0x0843, 0x22b3, 0x0403, 0x22b5,\n    0x0441, 0x0445, 0x22b7, 0x0443, 0x22c3, 0x22c1, 0x22c5, 0x22c7,\n    0x22c9, 0x0941, 0x04c1, 0x02b1, 0x22cb, 0x04c5, 0x22cd, 0x04c3,\n    0x22d1, 0x22cf, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x0541, 0x0543,\n    0x0a09, 0x02b6, 0x2495, 0x0545, 0x07c5, 0x098d, 0x098f, 0x06c1,\n    0x2493, 0x0845, 0x2309, 0x230b, 0x0581, 0x230d, 0x0585, 0x0991,\n    0x0993, 0x230f, 0x0583, 0x2313, 0x0587, 0x0589, 0x2315, 0x058d,\n    0x2317, 0x0999, 0x058b, 0x231f, 0x2381, 0x0591, 0x2321, 0x099b,\n    0x058f, 0x2325, 0x2323, 0x02b9, 0x02ba, 0x02bb, 0x05c1, 0x05c3,\n    0x05c5, 0x02bc, 0x24ad, 0x05c7, 0x05c9, 0x07c7, 0x0995, 0x0997,\n    0x0701, 0x24ab, 0x2327, 0x05cb, 0x232b, 0x2329, 0x2341, 0x2343,\n    0x2345, 0x2347, 0x05cd, 0x234b, 0x2349, 0x2382, 0x234d, 0x234f,\n    0x2351, 0x24b9, 0x02bd, 0x05cf, 0x24bf, 0x0a0d, 0x2353, 0x02bf,\n    0x24bd, 0x2383, 0x24bb, 0x0641, 0x2355, 0x0643, 0x0645, 0x2357,\n    0x2359, 0x3101, 0x0c80, 0x2e00, 0x2446, 0x2444, 0x244a, 0x2448,\n    0x0800, 0x0942, 0x0944, 0x0804, 0x2288, 0x2486, 0x2484, 0x248a,\n    0x2488, 0x22ae, 0x2498, 0x2496, 0x249c, 0x249a, 0x2300, 0x0a06,\n    0x2302, 0x0a04, 0x0946, 0x07ce, 0x07ca, 0x07c8, 0x07cc, 0x2447,\n    0x2445, 0x244b, 0x2449, 0x0801, 0x0943, 0x0945, 0x0805, 0x2289,\n    0x2487, 0x2485, 0x248b, 0x2489, 0x22af, 0x2499, 0x2497, 0x249d,\n    0x249b, 0x2301, 0x0a07, 0x2303, 0x0a05, 0x0947, 0x07cf, 0x07cb,\n    0x07c9, 0x07cd, 0x2450, 0x244e, 0x2454, 0x2452, 0x2451, 0x244f,\n    0x2455, 0x2453, 0x2294, 0x2296, 0x2295, 0x2297, 0x2304, 0x2306,\n    0x2305, 0x2307, 0x2318, 0x2319, 0x231a, 0x231b, 0x232c, 0x232d,\n    0x232e, 0x232f, 0x2400, 0x24a2, 0x24a0, 0x24a6, 0x24a4, 0x24a8,\n    0x24a3, 0x24a1, 0x24a7, 0x24a5, 0x24a9, 0x24b0, 0x24ae, 0x24b4,\n    0x24b2, 0x24b6, 0x24b1, 0x24af, 0x24b5, 0x24b3, 0x24b7, 0x0882,\n    0x0880, 0x0881, 0x0802, 0x0803, 0x229c, 0x229d, 0x0a0a, 0x0a0b,\n    0x0883, 0x0b40, 0x2c8a, 0x0c81, 0x2c89, 0x2c88, 0x2540, 0x2541,\n    0x2d00, 0x2e07, 0x0d00, 0x2640, 0x2641, 0x2e80, 0x0d01, 0x26c8,\n    0x26c9, 0x2f00, 0x2f84, 0x0d02, 0x2f83, 0x2f82, 0x0d40, 0x26d8,\n    0x26d9, 0x3186, 0x0d04, 0x2740, 0x2741, 0x3100, 0x3086, 0x0d06,\n    0x3085, 0x3084, 0x0d41, 0x2840, 0x3200, 0x0d07, 0x284f, 0x2850,\n    0x3280, 0x2c84, 0x2e03, 0x2857, 0x0d42, 0x2c81, 0x2c80, 0x24c0,\n    0x24c1, 0x2c86, 0x2c83, 0x28c0, 0x0d43, 0x25c0, 0x25c1, 0x2940,\n    0x0d44, 0x26c0, 0x26c1, 0x2e05, 0x2e02, 0x29c0, 0x0d45, 0x2f05,\n    0x2f04, 0x0d80, 0x26d0, 0x26d1, 0x2f80, 0x2a40, 0x0d82, 0x26e0,\n    0x26e1, 0x3080, 0x3081, 0x2ac0, 0x0d83, 0x3004, 0x3003, 0x0d81,\n    0x27c0, 0x27c1, 0x3082, 0x2b40, 0x0d84, 0x2847, 0x2848, 0x3184,\n    0x3181, 0x2f06, 0x0d08, 0x2f81, 0x3005, 0x0d46, 0x3083, 0x3182,\n    0x0e00, 0x0e01, 0x0f40, 0x1180, 0x1182, 0x0f03, 0x0f00, 0x11c0,\n    0x0f01, 0x1140, 0x1202, 0x1204, 0x0f81, 0x1240, 0x0fc0, 0x1242,\n    0x0f80, 0x1244, 0x1284, 0x0f82, 0x1286, 0x1288, 0x128a, 0x12c0,\n    0x1282, 0x1181, 0x1183, 0x1043, 0x1040, 0x11c1, 0x1041, 0x1141,\n    0x1203, 0x1205, 0x10c1, 0x1241, 0x1000, 0x1243, 0x10c0, 0x1245,\n    0x1285, 0x10c2, 0x1287, 0x1289, 0x128b, 0x12c1, 0x1283, 0x1080,\n    0x1100, 0x1101, 0x1200, 0x1201, 0x1280, 0x1281, 0x1340, 0x1341,\n    0x1343, 0x1342, 0x1344, 0x13c2, 0x1400, 0x13c0, 0x1440, 0x1480,\n    0x14c0, 0x1540, 0x1541, 0x1740, 0x1700, 0x1741, 0x17c0, 0x1800,\n    0x1802, 0x1801, 0x1840, 0x1880, 0x1900, 0x18c0, 0x18c1, 0x1901,\n    0x1940, 0x1942, 0x1941, 0x1980, 0x19c0, 0x19c2, 0x19c1, 0x1c80,\n    0x1cc0, 0x1dc0, 0x1f80, 0x2000, 0x2002, 0x2004, 0x2006, 0x2008,\n    0x2040, 0x2080, 0x2082, 0x20c0, 0x20c1, 0x2100, 0x22b8, 0x22b9,\n    0x2310, 0x2311, 0x231c, 0x231d, 0x244c, 0x2456, 0x244d, 0x2457,\n    0x248c, 0x248d, 0x249e, 0x249f, 0x2500, 0x2502, 0x2504, 0x2bc0,\n    0x2501, 0x2503, 0x2505, 0x2bc1, 0x2bc2, 0x2bc3, 0x2bc4, 0x2bc5,\n    0x2bc6, 0x2bc7, 0x2580, 0x2582, 0x2584, 0x2bc8, 0x2581, 0x2583,\n    0x2585, 0x2bc9, 0x2bca, 0x2bcb, 0x2bcc, 0x2bcd, 0x2bce, 0x2bcf,\n    0x2600, 0x2602, 0x2601, 0x2603, 0x2680, 0x2682, 0x2681, 0x2683,\n    0x26c2, 0x26c4, 0x26c6, 0x2c00, 0x26c3, 0x26c5, 0x26c7, 0x2c01,\n    0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07, 0x26ca, 0x26cc,\n    0x26ce, 0x2c08, 0x26cb, 0x26cd, 0x26cf, 0x2c09, 0x2c0a, 0x2c0b,\n    0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f, 0x26d2, 0x26d4, 0x26d6, 0x26d3,\n    0x26d5, 0x26d7, 0x26da, 0x26dc, 0x26de, 0x26db, 0x26dd, 0x26df,\n    0x2700, 0x2702, 0x2701, 0x2703, 0x2780, 0x2782, 0x2781, 0x2783,\n    0x2800, 0x2802, 0x2804, 0x2801, 0x2803, 0x2805, 0x2842, 0x2844,\n    0x2846, 0x2849, 0x284b, 0x284d, 0x2c40, 0x284a, 0x284c, 0x284e,\n    0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2851,\n    0x2853, 0x2855, 0x2c48, 0x2852, 0x2854, 0x2856, 0x2c49, 0x2c4a,\n    0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c82, 0x2e01, 0x3180,\n    0x2c87, 0x2f01, 0x2f02, 0x2f03, 0x2e06, 0x3185, 0x3000, 0x3001,\n    0x3002, 0x4640, 0x4641, 0x4680, 0x46c0, 0x46c2, 0x46c1, 0x4700,\n    0x4740, 0x4780, 0x47c0, 0x47c2, 0x4900, 0x4940, 0x4980, 0x4982,\n    0x4a00, 0x49c2, 0x4a03, 0x4a04, 0x4a40, 0x4a41, 0x4a80, 0x4a81,\n    0x4ac0, 0x4ac1, 0x4bc0, 0x4bc1, 0x4b00, 0x4b01, 0x4b40, 0x4b41,\n    0x4bc2, 0x4bc3, 0x4b80, 0x4b81, 0x4b82, 0x4b83, 0x4c00, 0x4c01,\n    0x4c02, 0x4c03, 0x5600, 0x5440, 0x5442, 0x5444, 0x5446, 0x5448,\n    0x544a, 0x544c, 0x544e, 0x5450, 0x5452, 0x5454, 0x5456, 0x5480,\n    0x5482, 0x5484, 0x54c0, 0x54c1, 0x5500, 0x5501, 0x5540, 0x5541,\n    0x5580, 0x5581, 0x55c0, 0x55c1, 0x5680, 0x58c0, 0x5700, 0x5702,\n    0x5704, 0x5706, 0x5708, 0x570a, 0x570c, 0x570e, 0x5710, 0x5712,\n    0x5714, 0x5716, 0x5740, 0x5742, 0x5744, 0x5780, 0x5781, 0x57c0,\n    0x57c1, 0x5800, 0x5801, 0x5840, 0x5841, 0x5880, 0x5881, 0x5900,\n    0x5901, 0x5902, 0x5903, 0x5940, 0x8ec0, 0x8f00, 0x8fc0, 0x8fc2,\n    0x9000, 0x9040, 0x9041, 0x9080, 0x9081, 0x90c0, 0x90c2, 0x9100,\n    0x9140, 0x9182, 0x9180, 0x9183, 0x91c1, 0x91c0, 0x91c3, 0x9200,\n    0x9201, 0x9240, 0x9280, 0x9282, 0x9284, 0x9281, 0x9285, 0x9287,\n    0x9286, 0x9283, 0x92c1, 0x92c0, 0x92c2,\n};\n\ntypedef enum {\n    UNICODE_GC_Cn,\n    UNICODE_GC_Lu,\n    UNICODE_GC_Ll,\n    UNICODE_GC_Lt,\n    UNICODE_GC_Lm,\n    UNICODE_GC_Lo,\n    UNICODE_GC_Mn,\n    UNICODE_GC_Mc,\n    UNICODE_GC_Me,\n    UNICODE_GC_Nd,\n    UNICODE_GC_Nl,\n    UNICODE_GC_No,\n    UNICODE_GC_Sm,\n    UNICODE_GC_Sc,\n    UNICODE_GC_Sk,\n    UNICODE_GC_So,\n    UNICODE_GC_Pc,\n    UNICODE_GC_Pd,\n    UNICODE_GC_Ps,\n    UNICODE_GC_Pe,\n    UNICODE_GC_Pi,\n    UNICODE_GC_Pf,\n    UNICODE_GC_Po,\n    UNICODE_GC_Zs,\n    UNICODE_GC_Zl,\n    UNICODE_GC_Zp,\n    UNICODE_GC_Cc,\n    UNICODE_GC_Cf,\n    UNICODE_GC_Cs,\n    UNICODE_GC_Co,\n    UNICODE_GC_LC,\n    UNICODE_GC_L,\n    UNICODE_GC_M,\n    UNICODE_GC_N,\n    UNICODE_GC_S,\n    UNICODE_GC_P,\n    UNICODE_GC_Z,\n    UNICODE_GC_C,\n    UNICODE_GC_COUNT,\n} UnicodeGCEnum;\n\nstatic const char unicode_gc_name_table[] =\n    \"Cn,Unassigned\"            \"\\0\"\n    \"Lu,Uppercase_Letter\"      \"\\0\"\n    \"Ll,Lowercase_Letter\"      \"\\0\"\n    \"Lt,Titlecase_Letter\"      \"\\0\"\n    \"Lm,Modifier_Letter\"       \"\\0\"\n    \"Lo,Other_Letter\"          \"\\0\"\n    \"Mn,Nonspacing_Mark\"       \"\\0\"\n    \"Mc,Spacing_Mark\"          \"\\0\"\n    \"Me,Enclosing_Mark\"        \"\\0\"\n    \"Nd,Decimal_Number,digit\"  \"\\0\"\n    \"Nl,Letter_Number\"         \"\\0\"\n    \"No,Other_Number\"          \"\\0\"\n    \"Sm,Math_Symbol\"           \"\\0\"\n    \"Sc,Currency_Symbol\"       \"\\0\"\n    \"Sk,Modifier_Symbol\"       \"\\0\"\n    \"So,Other_Symbol\"          \"\\0\"\n    \"Pc,Connector_Punctuation\" \"\\0\"\n    \"Pd,Dash_Punctuation\"      \"\\0\"\n    \"Ps,Open_Punctuation\"      \"\\0\"\n    \"Pe,Close_Punctuation\"     \"\\0\"\n    \"Pi,Initial_Punctuation\"   \"\\0\"\n    \"Pf,Final_Punctuation\"     \"\\0\"\n    \"Po,Other_Punctuation\"     \"\\0\"\n    \"Zs,Space_Separator\"       \"\\0\"\n    \"Zl,Line_Separator\"        \"\\0\"\n    \"Zp,Paragraph_Separator\"   \"\\0\"\n    \"Cc,Control,cntrl\"         \"\\0\"\n    \"Cf,Format\"                \"\\0\"\n    \"Cs,Surrogate\"             \"\\0\"\n    \"Co,Private_Use\"           \"\\0\"\n    \"LC,Cased_Letter\"          \"\\0\"\n    \"L,Letter\"                 \"\\0\"\n    \"M,Mark,Combining_Mark\"    \"\\0\"\n    \"N,Number\"                 \"\\0\"\n    \"S,Symbol\"                 \"\\0\"\n    \"P,Punctuation,punct\"      \"\\0\"\n    \"Z,Separator\"              \"\\0\"\n    \"C,Other\"                  \"\\0\"\n;\n\nstatic const uint8_t unicode_gc_table[4122] = {\n    0xfa, 0x18, 0x17, 0x56, 0x0d, 0x56, 0x12, 0x13,\n    0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02, 0x36,\n    0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13, 0x0e,\n    0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13, 0x0c,\n    0xfa, 0x19, 0x17, 0x16, 0x6d, 0x0f, 0x16, 0x0e,\n    0x0f, 0x05, 0x14, 0x0c, 0x1b, 0x0f, 0x0e, 0x0f,\n    0x0c, 0x2b, 0x0e, 0x02, 0x36, 0x0e, 0x0b, 0x05,\n    0x15, 0x4b, 0x16, 0xe1, 0x0f, 0x0c, 0xc1, 0xe2,\n    0x10, 0x0c, 0xe2, 0x00, 0xff, 0x30, 0x02, 0xff,\n    0x08, 0x02, 0xff, 0x27, 0xbf, 0x22, 0x21, 0x02,\n    0x5f, 0x5f, 0x21, 0x22, 0x61, 0x02, 0x21, 0x02,\n    0x41, 0x42, 0x21, 0x02, 0x21, 0x02, 0x9f, 0x7f,\n    0x02, 0x5f, 0x5f, 0x21, 0x02, 0x5f, 0x3f, 0x02,\n    0x05, 0x3f, 0x22, 0x65, 0x01, 0x03, 0x02, 0x01,\n    0x03, 0x02, 0x01, 0x03, 0x02, 0xff, 0x08, 0x02,\n    0xff, 0x0a, 0x02, 0x01, 0x03, 0x02, 0x5f, 0x21,\n    0x02, 0xff, 0x32, 0xa2, 0x21, 0x02, 0x21, 0x22,\n    0x5f, 0x41, 0x02, 0xff, 0x00, 0xe2, 0x3c, 0x25,\n    0xe2, 0x12, 0xe4, 0x0a, 0x6e, 0xe4, 0x04, 0xee,\n    0x06, 0x84, 0xce, 0x04, 0x0e, 0x04, 0xee, 0x09,\n    0xe6, 0x68, 0x7f, 0x04, 0x0e, 0x3f, 0x20, 0x04,\n    0x42, 0x16, 0x01, 0x60, 0x2e, 0x01, 0x16, 0x41,\n    0x00, 0x01, 0x00, 0x21, 0x02, 0xe1, 0x09, 0x00,\n    0xe1, 0x01, 0xe2, 0x1b, 0x3f, 0x02, 0x41, 0x42,\n    0xff, 0x10, 0x62, 0x3f, 0x0c, 0x5f, 0x3f, 0x02,\n    0xe1, 0x2b, 0xe2, 0x28, 0xff, 0x1a, 0x0f, 0x86,\n    0x28, 0xff, 0x2f, 0xff, 0x06, 0x02, 0xff, 0x58,\n    0x00, 0xe1, 0x1e, 0x20, 0x04, 0xb6, 0xe2, 0x21,\n    0x16, 0x11, 0x20, 0x2f, 0x0d, 0x00, 0xe6, 0x25,\n    0x11, 0x06, 0x16, 0x26, 0x16, 0x26, 0x16, 0x06,\n    0xe0, 0x00, 0xe5, 0x13, 0x60, 0x65, 0x36, 0xe0,\n    0x03, 0xbb, 0x4c, 0x36, 0x0d, 0x36, 0x2f, 0xe6,\n    0x03, 0x16, 0x1b, 0x56, 0xe5, 0x18, 0x04, 0xe5,\n    0x02, 0xe6, 0x0d, 0xe9, 0x02, 0x76, 0x25, 0x06,\n    0xe5, 0x5b, 0x16, 0x05, 0xc6, 0x1b, 0x0f, 0xa6,\n    0x24, 0x26, 0x0f, 0x66, 0x25, 0xe9, 0x02, 0x45,\n    0x2f, 0x05, 0xf6, 0x06, 0x00, 0x1b, 0x05, 0x06,\n    0xe5, 0x16, 0xe6, 0x13, 0x20, 0xe5, 0x51, 0xe6,\n    0x03, 0x05, 0xe0, 0x06, 0xe9, 0x02, 0xe5, 0x19,\n    0xe6, 0x01, 0x24, 0x0f, 0x56, 0x04, 0x20, 0x06,\n    0x2d, 0xe5, 0x0e, 0x66, 0x04, 0xe6, 0x01, 0x04,\n    0x46, 0x04, 0x86, 0x20, 0xf6, 0x07, 0x00, 0xe5,\n    0x11, 0x46, 0x20, 0x16, 0x00, 0xe5, 0x03, 0x80,\n    0xe5, 0x10, 0x0e, 0xc5, 0x3b, 0x80, 0xe6, 0x01,\n    0xe5, 0x21, 0x04, 0xe6, 0x10, 0x1b, 0xe6, 0x18,\n    0x07, 0xe5, 0x2e, 0x06, 0x07, 0x06, 0x05, 0x47,\n    0xe6, 0x00, 0x67, 0x06, 0x27, 0x05, 0xc6, 0xe5,\n    0x02, 0x26, 0x36, 0xe9, 0x02, 0x16, 0x04, 0xe5,\n    0x07, 0x06, 0x27, 0x00, 0xe5, 0x00, 0x20, 0x25,\n    0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x05, 0x40,\n    0x65, 0x20, 0x06, 0x05, 0x47, 0x66, 0x20, 0x27,\n    0x20, 0x27, 0x06, 0x05, 0xe0, 0x00, 0x07, 0x60,\n    0x25, 0x00, 0x45, 0x26, 0x20, 0xe9, 0x02, 0x25,\n    0x2d, 0xab, 0x0f, 0x0d, 0x05, 0x16, 0x06, 0x20,\n    0x26, 0x07, 0x00, 0xa5, 0x60, 0x25, 0x20, 0xe5,\n    0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00, 0x25, 0x00,\n    0x25, 0x20, 0x06, 0x00, 0x47, 0x26, 0x60, 0x26,\n    0x20, 0x46, 0x40, 0x06, 0xc0, 0x65, 0x00, 0x05,\n    0xc0, 0xe9, 0x02, 0x26, 0x45, 0x06, 0x16, 0xe0,\n    0x02, 0x26, 0x07, 0x00, 0xe5, 0x01, 0x00, 0x45,\n    0x00, 0xe5, 0x0e, 0x00, 0xc5, 0x00, 0x25, 0x00,\n    0x85, 0x20, 0x06, 0x05, 0x47, 0x86, 0x00, 0x26,\n    0x07, 0x00, 0x27, 0x06, 0x20, 0x05, 0xe0, 0x07,\n    0x25, 0x26, 0x20, 0xe9, 0x02, 0x16, 0x0d, 0xc0,\n    0x05, 0xa6, 0x00, 0x06, 0x27, 0x00, 0xe5, 0x00,\n    0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5, 0x00,\n    0x25, 0x00, 0x85, 0x20, 0x06, 0x05, 0x07, 0x06,\n    0x07, 0x66, 0x20, 0x27, 0x20, 0x27, 0x06, 0xc0,\n    0x26, 0x07, 0x60, 0x25, 0x00, 0x45, 0x26, 0x20,\n    0xe9, 0x02, 0x0f, 0x05, 0xab, 0xe0, 0x02, 0x06,\n    0x05, 0x00, 0xa5, 0x40, 0x45, 0x00, 0x65, 0x40,\n    0x25, 0x00, 0x05, 0x00, 0x25, 0x40, 0x25, 0x40,\n    0x45, 0x40, 0xe5, 0x04, 0x60, 0x27, 0x06, 0x27,\n    0x40, 0x47, 0x00, 0x47, 0x06, 0x20, 0x05, 0xa0,\n    0x07, 0xe0, 0x06, 0xe9, 0x02, 0x4b, 0xaf, 0x0d,\n    0x0f, 0x80, 0x06, 0x47, 0x06, 0xe5, 0x00, 0x00,\n    0x45, 0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x08, 0x20,\n    0x06, 0x05, 0x46, 0x67, 0x00, 0x46, 0x00, 0x66,\n    0xc0, 0x26, 0x00, 0x45, 0x00, 0x25, 0x20, 0x25,\n    0x26, 0x20, 0xe9, 0x02, 0xc0, 0x16, 0xcb, 0x0f,\n    0x05, 0x06, 0x27, 0x16, 0xe5, 0x00, 0x00, 0x45,\n    0x00, 0xe5, 0x0f, 0x00, 0xe5, 0x02, 0x00, 0x85,\n    0x20, 0x06, 0x05, 0x07, 0x06, 0x87, 0x00, 0x06,\n    0x27, 0x00, 0x27, 0x26, 0xc0, 0x27, 0x80, 0x45,\n    0x00, 0x25, 0x26, 0x20, 0xe9, 0x02, 0x00, 0x25,\n    0x07, 0xe0, 0x04, 0x26, 0x27, 0xe5, 0x01, 0x00,\n    0x45, 0x00, 0xe5, 0x21, 0x26, 0x05, 0x47, 0x66,\n    0x00, 0x47, 0x00, 0x47, 0x06, 0x05, 0x0f, 0x60,\n    0x45, 0x07, 0xcb, 0x45, 0x26, 0x20, 0xe9, 0x02,\n    0xeb, 0x01, 0x0f, 0xa5, 0x00, 0x06, 0x27, 0x00,\n    0xe5, 0x0a, 0x40, 0xe5, 0x10, 0x00, 0xe5, 0x01,\n    0x00, 0x05, 0x20, 0xc5, 0x40, 0x06, 0x60, 0x47,\n    0x46, 0x00, 0x06, 0x00, 0xe7, 0x00, 0xa0, 0xe9,\n    0x02, 0x20, 0x27, 0x16, 0xe0, 0x04, 0xe5, 0x28,\n    0x06, 0x25, 0xc6, 0x60, 0x0d, 0xa5, 0x04, 0xe6,\n    0x00, 0x16, 0xe9, 0x02, 0x36, 0xe0, 0x1d, 0x25,\n    0x00, 0x05, 0x00, 0x85, 0x00, 0xe5, 0x10, 0x00,\n    0x05, 0x00, 0xe5, 0x02, 0x06, 0x25, 0xe6, 0x01,\n    0x05, 0x20, 0x85, 0x00, 0x04, 0x00, 0xc6, 0x00,\n    0xe9, 0x02, 0x20, 0x65, 0xe0, 0x18, 0x05, 0x4f,\n    0xf6, 0x07, 0x0f, 0x16, 0x4f, 0x26, 0xaf, 0xe9,\n    0x02, 0xeb, 0x02, 0x0f, 0x06, 0x0f, 0x06, 0x0f,\n    0x06, 0x12, 0x13, 0x12, 0x13, 0x27, 0xe5, 0x00,\n    0x00, 0xe5, 0x1c, 0x60, 0xe6, 0x06, 0x07, 0x86,\n    0x16, 0x26, 0x85, 0xe6, 0x03, 0x00, 0xe6, 0x1c,\n    0x00, 0xef, 0x00, 0x06, 0xaf, 0x00, 0x2f, 0x96,\n    0x6f, 0x36, 0xe0, 0x1d, 0xe5, 0x23, 0x27, 0x66,\n    0x07, 0xa6, 0x07, 0x26, 0x27, 0x26, 0x05, 0xe9,\n    0x02, 0xb6, 0xa5, 0x27, 0x26, 0x65, 0x46, 0x05,\n    0x47, 0x25, 0xc7, 0x45, 0x66, 0xe5, 0x05, 0x06,\n    0x27, 0x26, 0xa7, 0x06, 0x05, 0x07, 0xe9, 0x02,\n    0x47, 0x06, 0x2f, 0xe1, 0x1e, 0x00, 0x01, 0x80,\n    0x01, 0x20, 0xe2, 0x23, 0x16, 0x04, 0x42, 0xe5,\n    0x80, 0xc1, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05,\n    0x00, 0x65, 0x20, 0xe5, 0x21, 0x00, 0x65, 0x20,\n    0xe5, 0x19, 0x00, 0x65, 0x20, 0xc5, 0x00, 0x05,\n    0x00, 0x65, 0x20, 0xe5, 0x07, 0x00, 0xe5, 0x31,\n    0x00, 0x65, 0x20, 0xe5, 0x3b, 0x20, 0x46, 0xf6,\n    0x01, 0xeb, 0x0c, 0x40, 0xe5, 0x08, 0xef, 0x02,\n    0xa0, 0xe1, 0x4e, 0x20, 0xa2, 0x20, 0x11, 0xe5,\n    0x81, 0xe4, 0x0f, 0x16, 0xe5, 0x09, 0x17, 0xe5,\n    0x12, 0x12, 0x13, 0x40, 0xe5, 0x43, 0x56, 0x4a,\n    0xe5, 0x00, 0xc0, 0xe5, 0x0a, 0x46, 0x07, 0xe0,\n    0x01, 0xe5, 0x0b, 0x26, 0x07, 0x36, 0xe0, 0x01,\n    0xe5, 0x0a, 0x26, 0xe0, 0x04, 0xe5, 0x05, 0x00,\n    0x45, 0x00, 0x26, 0xe0, 0x04, 0xe5, 0x2c, 0x26,\n    0x07, 0xc6, 0xe7, 0x00, 0x06, 0x27, 0xe6, 0x03,\n    0x56, 0x04, 0x56, 0x0d, 0x05, 0x06, 0x20, 0xe9,\n    0x02, 0xa0, 0xeb, 0x02, 0xa0, 0xb6, 0x11, 0x76,\n    0x46, 0x1b, 0x06, 0xe9, 0x02, 0xa0, 0xe5, 0x1b,\n    0x04, 0xe5, 0x2d, 0xc0, 0x85, 0x26, 0xe5, 0x1a,\n    0x06, 0x05, 0x80, 0xe5, 0x3e, 0xe0, 0x02, 0xe5,\n    0x17, 0x00, 0x46, 0x67, 0x26, 0x47, 0x60, 0x27,\n    0x06, 0xa7, 0x46, 0x60, 0x0f, 0x40, 0x36, 0xe9,\n    0x02, 0xe5, 0x16, 0x20, 0x85, 0xe0, 0x03, 0xe5,\n    0x24, 0x60, 0xe5, 0x12, 0xa0, 0xe9, 0x02, 0x0b,\n    0x40, 0xef, 0x1a, 0xe5, 0x0f, 0x26, 0x27, 0x06,\n    0x20, 0x36, 0xe5, 0x2d, 0x07, 0x06, 0x07, 0xc6,\n    0x00, 0x06, 0x07, 0x06, 0x27, 0xe6, 0x00, 0xa7,\n    0xe6, 0x02, 0x20, 0x06, 0xe9, 0x02, 0xa0, 0xe9,\n    0x02, 0xa0, 0xd6, 0x04, 0xb6, 0x20, 0xe6, 0x06,\n    0x08, 0xe6, 0x17, 0x20, 0xe6, 0x04, 0xe0, 0x0c,\n    0x66, 0x07, 0xe5, 0x27, 0x06, 0x07, 0x86, 0x07,\n    0x06, 0x87, 0x06, 0x27, 0xe5, 0x00, 0x00, 0x36,\n    0xe9, 0x02, 0xd6, 0xef, 0x02, 0xe6, 0x01, 0xef,\n    0x01, 0x56, 0x26, 0x07, 0xe5, 0x16, 0x07, 0x66,\n    0x27, 0x26, 0x07, 0x46, 0x25, 0xe9, 0x02, 0xe5,\n    0x24, 0x06, 0x07, 0x26, 0x47, 0x06, 0x07, 0x46,\n    0x27, 0xe0, 0x00, 0x76, 0xe5, 0x1c, 0xe7, 0x00,\n    0xe6, 0x00, 0x27, 0x26, 0x40, 0x96, 0xe9, 0x02,\n    0x40, 0x45, 0xe9, 0x02, 0xe5, 0x16, 0xa4, 0x36,\n    0xe2, 0x01, 0x3f, 0x80, 0xe1, 0x23, 0x20, 0x41,\n    0xf6, 0x00, 0xe0, 0x00, 0x46, 0x16, 0xe6, 0x05,\n    0x07, 0xc6, 0x65, 0x06, 0xa5, 0x06, 0x25, 0x07,\n    0x26, 0x05, 0x80, 0xe2, 0x24, 0xe4, 0x37, 0xe2,\n    0x05, 0x04, 0xe2, 0x1a, 0xe4, 0x1d, 0xe6, 0x38,\n    0xff, 0x80, 0x0e, 0xe2, 0x00, 0xff, 0x5a, 0xe2,\n    0x00, 0xe1, 0x00, 0xa2, 0x20, 0xa1, 0x20, 0xe2,\n    0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe1, 0x00, 0xa2,\n    0x20, 0xa1, 0x20, 0xe2, 0x00, 0x00, 0x01, 0x00,\n    0x01, 0x00, 0x01, 0x00, 0x3f, 0xc2, 0xe1, 0x00,\n    0xe2, 0x06, 0x20, 0xe2, 0x00, 0xe3, 0x00, 0xe2,\n    0x00, 0xe3, 0x00, 0xe2, 0x00, 0xe3, 0x00, 0x82,\n    0x00, 0x22, 0x61, 0x03, 0x0e, 0x02, 0x4e, 0x42,\n    0x00, 0x22, 0x61, 0x03, 0x4e, 0x62, 0x20, 0x22,\n    0x61, 0x00, 0x4e, 0xe2, 0x00, 0x81, 0x4e, 0x20,\n    0x42, 0x00, 0x22, 0x61, 0x03, 0x2e, 0x00, 0xf7,\n    0x03, 0x9b, 0xb1, 0x36, 0x14, 0x15, 0x12, 0x34,\n    0x15, 0x12, 0x14, 0xf6, 0x00, 0x18, 0x19, 0x9b,\n    0x17, 0xf6, 0x01, 0x14, 0x15, 0x76, 0x30, 0x56,\n    0x0c, 0x12, 0x13, 0xf6, 0x03, 0x0c, 0x16, 0x10,\n    0xf6, 0x02, 0x17, 0x9b, 0x00, 0xfb, 0x02, 0x0b,\n    0x04, 0x20, 0xab, 0x4c, 0x12, 0x13, 0x04, 0xeb,\n    0x02, 0x4c, 0x12, 0x13, 0x00, 0xe4, 0x05, 0x40,\n    0xed, 0x1a, 0xe0, 0x06, 0xe6, 0x05, 0x68, 0x06,\n    0x48, 0xe6, 0x04, 0xe0, 0x07, 0x2f, 0x01, 0x6f,\n    0x01, 0x2f, 0x02, 0x41, 0x22, 0x41, 0x02, 0x0f,\n    0x01, 0x2f, 0x0c, 0x81, 0xaf, 0x01, 0x0f, 0x01,\n    0x0f, 0x01, 0x0f, 0x61, 0x0f, 0x02, 0x61, 0x02,\n    0x65, 0x02, 0x2f, 0x22, 0x21, 0x8c, 0x3f, 0x42,\n    0x0f, 0x0c, 0x2f, 0x02, 0x0f, 0xeb, 0x08, 0xea,\n    0x1b, 0x3f, 0x6a, 0x0b, 0x2f, 0x60, 0x8c, 0x8f,\n    0x2c, 0x6f, 0x0c, 0x2f, 0x0c, 0x2f, 0x0c, 0xcf,\n    0x0c, 0xef, 0x17, 0x2c, 0x2f, 0x0c, 0x0f, 0x0c,\n    0xef, 0x17, 0xec, 0x80, 0x84, 0xef, 0x00, 0x12,\n    0x13, 0x12, 0x13, 0xef, 0x0c, 0x2c, 0xcf, 0x12,\n    0x13, 0xef, 0x49, 0x0c, 0xef, 0x16, 0xec, 0x11,\n    0xef, 0x20, 0xac, 0xef, 0x40, 0xe0, 0x0e, 0xef,\n    0x03, 0xe0, 0x0d, 0xeb, 0x34, 0xef, 0x46, 0xeb,\n    0x0e, 0xef, 0x80, 0x2f, 0x0c, 0xef, 0x01, 0x0c,\n    0xef, 0x2e, 0xec, 0x00, 0xef, 0x67, 0x0c, 0xef,\n    0x80, 0x70, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,\n    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,\n    0xeb, 0x16, 0xef, 0x24, 0x8c, 0x12, 0x13, 0xec,\n    0x17, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,\n    0x13, 0x12, 0x13, 0xec, 0x08, 0xef, 0x80, 0x78,\n    0xec, 0x7b, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,\n    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,\n    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,\n    0xec, 0x37, 0x12, 0x13, 0x12, 0x13, 0xec, 0x18,\n    0x12, 0x13, 0xec, 0x80, 0x7a, 0xef, 0x28, 0xec,\n    0x0d, 0x2f, 0xac, 0xef, 0x1f, 0x20, 0xef, 0x80,\n    0x02, 0xe1, 0x28, 0xe2, 0x28, 0x5f, 0x21, 0x22,\n    0xdf, 0x41, 0x02, 0x3f, 0x02, 0x3f, 0x82, 0x24,\n    0x41, 0x02, 0xff, 0x5a, 0x02, 0xaf, 0x7f, 0x46,\n    0x3f, 0x80, 0x76, 0x0b, 0x36, 0xe2, 0x1e, 0x00,\n    0x02, 0x80, 0x02, 0x20, 0xe5, 0x30, 0xc0, 0x04,\n    0x16, 0xe0, 0x06, 0x06, 0xe5, 0x0f, 0xe0, 0x01,\n    0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,\n    0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00, 0xc5, 0x00,\n    0xe6, 0x18, 0x36, 0x14, 0x15, 0x14, 0x15, 0x56,\n    0x14, 0x15, 0x16, 0x14, 0x15, 0xf6, 0x01, 0x11,\n    0x36, 0x11, 0x16, 0x14, 0x15, 0x36, 0x14, 0x15,\n    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13,\n    0x96, 0x04, 0xf6, 0x02, 0x31, 0x76, 0x11, 0x16,\n    0x12, 0xf6, 0x05, 0x2f, 0x56, 0x12, 0x13, 0x12,\n    0x13, 0x12, 0x13, 0x12, 0x13, 0x11, 0xe0, 0x1a,\n    0xef, 0x12, 0x00, 0xef, 0x51, 0xe0, 0x04, 0xef,\n    0x80, 0x4e, 0xe0, 0x12, 0xef, 0x08, 0x17, 0x56,\n    0x0f, 0x04, 0x05, 0x0a, 0x12, 0x13, 0x12, 0x13,\n    0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x2f, 0x12,\n    0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x11,\n    0x12, 0x33, 0x0f, 0xea, 0x01, 0x66, 0x27, 0x11,\n    0x84, 0x2f, 0x4a, 0x04, 0x05, 0x16, 0x2f, 0x00,\n    0xe5, 0x4e, 0x20, 0x26, 0x2e, 0x24, 0x05, 0x11,\n    0xe5, 0x52, 0x16, 0x44, 0x05, 0x80, 0xe5, 0x23,\n    0x00, 0xe5, 0x56, 0x00, 0x2f, 0x6b, 0xef, 0x02,\n    0xe5, 0x18, 0xef, 0x1e, 0xe0, 0x01, 0x0f, 0xe5,\n    0x08, 0xef, 0x17, 0x00, 0xeb, 0x02, 0xef, 0x16,\n    0xeb, 0x00, 0x0f, 0xeb, 0x07, 0xef, 0x18, 0xeb,\n    0x02, 0xef, 0x1f, 0xeb, 0x07, 0xef, 0x80, 0xb8,\n    0xe5, 0x99, 0x38, 0xef, 0x38, 0xe5, 0xc0, 0x11,\n    0x8d, 0x04, 0xe5, 0x83, 0xef, 0x40, 0xef, 0x2f,\n    0xe0, 0x01, 0xe5, 0x20, 0xa4, 0x36, 0xe5, 0x80,\n    0x84, 0x04, 0x56, 0xe5, 0x08, 0xe9, 0x02, 0x25,\n    0xe0, 0x0c, 0xff, 0x26, 0x05, 0x06, 0x48, 0x16,\n    0xe6, 0x02, 0x16, 0x04, 0xff, 0x14, 0x24, 0x26,\n    0xe5, 0x3e, 0xea, 0x02, 0x26, 0xb6, 0xe0, 0x00,\n    0xee, 0x0f, 0xe4, 0x01, 0x2e, 0xff, 0x06, 0x22,\n    0xff, 0x36, 0x04, 0xe2, 0x00, 0x9f, 0xff, 0x02,\n    0x04, 0x2e, 0x7f, 0x05, 0x7f, 0x22, 0xff, 0x0d,\n    0x61, 0x02, 0x81, 0x02, 0xff, 0x07, 0x41, 0x02,\n    0x5f, 0xff, 0x09, 0xe0, 0x0c, 0x64, 0x3f, 0x05,\n    0x24, 0x02, 0xc5, 0x06, 0x45, 0x06, 0x65, 0x06,\n    0xe5, 0x0f, 0x27, 0x26, 0x07, 0x6f, 0x06, 0x40,\n    0xab, 0x2f, 0x0d, 0x0f, 0xa0, 0xe5, 0x2c, 0x76,\n    0xe0, 0x00, 0x27, 0xe5, 0x2a, 0xe7, 0x08, 0x26,\n    0xe0, 0x00, 0x36, 0xe9, 0x02, 0xa0, 0xe6, 0x0a,\n    0xa5, 0x56, 0x05, 0x16, 0x25, 0x06, 0xe9, 0x02,\n    0xe5, 0x14, 0xe6, 0x00, 0x36, 0xe5, 0x0f, 0xe6,\n    0x03, 0x27, 0xe0, 0x03, 0x16, 0xe5, 0x15, 0x40,\n    0x46, 0x07, 0xe5, 0x27, 0x06, 0x27, 0x66, 0x27,\n    0x26, 0x47, 0xf6, 0x05, 0x00, 0x04, 0xe9, 0x02,\n    0x60, 0x36, 0x85, 0x06, 0x04, 0xe5, 0x01, 0xe9,\n    0x02, 0x85, 0x00, 0xe5, 0x21, 0xa6, 0x27, 0x26,\n    0x27, 0x26, 0xe0, 0x01, 0x45, 0x06, 0xe5, 0x00,\n    0x06, 0x07, 0x20, 0xe9, 0x02, 0x20, 0x76, 0xe5,\n    0x08, 0x04, 0xa5, 0x4f, 0x05, 0x07, 0x06, 0x07,\n    0xe5, 0x2a, 0x06, 0x05, 0x46, 0x25, 0x26, 0x85,\n    0x26, 0x05, 0x06, 0x05, 0xe0, 0x10, 0x25, 0x04,\n    0x36, 0xe5, 0x03, 0x07, 0x26, 0x27, 0x36, 0x05,\n    0x24, 0x07, 0x06, 0xe0, 0x02, 0xa5, 0x20, 0xa5,\n    0x20, 0xa5, 0xe0, 0x01, 0xc5, 0x00, 0xc5, 0x00,\n    0xe2, 0x23, 0x0e, 0x64, 0xe2, 0x01, 0x04, 0x2e,\n    0x60, 0xe2, 0x48, 0xe5, 0x1b, 0x27, 0x06, 0x27,\n    0x06, 0x27, 0x16, 0x07, 0x06, 0x20, 0xe9, 0x02,\n    0xa0, 0xe5, 0xab, 0x1c, 0xe0, 0x04, 0xe5, 0x0f,\n    0x60, 0xe5, 0x29, 0x60, 0xfc, 0x87, 0x78, 0xfd,\n    0x98, 0x78, 0xe5, 0x80, 0xe6, 0x20, 0xe5, 0x62,\n    0xe0, 0x1e, 0xc2, 0xe0, 0x04, 0x82, 0x80, 0x05,\n    0x06, 0xe5, 0x02, 0x0c, 0xe5, 0x05, 0x00, 0x85,\n    0x00, 0x05, 0x00, 0x25, 0x00, 0x25, 0x00, 0xe5,\n    0x64, 0xee, 0x09, 0xef, 0x08, 0xe5, 0x80, 0xe3,\n    0x13, 0x12, 0xef, 0x08, 0xe5, 0x38, 0x2f, 0xe5,\n    0x2e, 0xef, 0x00, 0xe0, 0x18, 0xe5, 0x04, 0x0d,\n    0x4f, 0xe6, 0x08, 0xd6, 0x12, 0x13, 0x16, 0xa0,\n    0xe6, 0x08, 0x16, 0x31, 0x30, 0x12, 0x13, 0x12,\n    0x13, 0x12, 0x13, 0x12, 0x13, 0x12, 0x13, 0x12,\n    0x13, 0x12, 0x13, 0x12, 0x13, 0x36, 0x12, 0x13,\n    0x76, 0x50, 0x56, 0x00, 0x76, 0x11, 0x12, 0x13,\n    0x12, 0x13, 0x12, 0x13, 0x56, 0x0c, 0x11, 0x4c,\n    0x00, 0x16, 0x0d, 0x36, 0x60, 0x85, 0x00, 0xe5,\n    0x7f, 0x20, 0x1b, 0x00, 0x56, 0x0d, 0x56, 0x12,\n    0x13, 0x16, 0x0c, 0x16, 0x11, 0x36, 0xe9, 0x02,\n    0x36, 0x4c, 0x36, 0xe1, 0x12, 0x12, 0x16, 0x13,\n    0x0e, 0x10, 0x0e, 0xe2, 0x12, 0x12, 0x0c, 0x13,\n    0x0c, 0x12, 0x13, 0x16, 0x12, 0x13, 0x36, 0xe5,\n    0x02, 0x04, 0xe5, 0x25, 0x24, 0xe5, 0x17, 0x40,\n    0xa5, 0x20, 0xa5, 0x20, 0xa5, 0x20, 0x45, 0x40,\n    0x2d, 0x0c, 0x0e, 0x0f, 0x2d, 0x00, 0x0f, 0x6c,\n    0x2f, 0xe0, 0x02, 0x5b, 0x2f, 0x20, 0xe5, 0x04,\n    0x00, 0xe5, 0x12, 0x00, 0xe5, 0x0b, 0x00, 0x25,\n    0x00, 0xe5, 0x07, 0x20, 0xe5, 0x06, 0xe0, 0x1a,\n    0xe5, 0x73, 0x80, 0x56, 0x60, 0xeb, 0x25, 0x40,\n    0xef, 0x01, 0xea, 0x2d, 0x6b, 0xef, 0x09, 0x2b,\n    0x4f, 0x00, 0xef, 0x05, 0x40, 0x0f, 0xe0, 0x27,\n    0xef, 0x25, 0x06, 0xe0, 0x7a, 0xe5, 0x15, 0x40,\n    0xe5, 0x29, 0xe0, 0x07, 0x06, 0xeb, 0x13, 0x60,\n    0xe5, 0x18, 0x6b, 0xe0, 0x01, 0xe5, 0x0c, 0x0a,\n    0xe5, 0x00, 0x0a, 0x80, 0xe5, 0x1e, 0x86, 0x80,\n    0xe5, 0x16, 0x00, 0x16, 0xe5, 0x1c, 0x60, 0xe5,\n    0x00, 0x16, 0x8a, 0xe0, 0x22, 0xe1, 0x20, 0xe2,\n    0x20, 0xe5, 0x46, 0x20, 0xe9, 0x02, 0xa0, 0xe1,\n    0x1c, 0x60, 0xe2, 0x1c, 0x60, 0xe5, 0x20, 0xe0,\n    0x00, 0xe5, 0x2c, 0xe0, 0x03, 0x16, 0xe1, 0x03,\n    0x00, 0xe1, 0x07, 0x00, 0xc1, 0x00, 0x21, 0x00,\n    0xe2, 0x03, 0x00, 0xe2, 0x07, 0x00, 0xc2, 0x00,\n    0x22, 0x40, 0xe5, 0x2c, 0xe0, 0x04, 0xe5, 0x80,\n    0xaf, 0xe0, 0x01, 0xe5, 0x0e, 0xe0, 0x02, 0xe5,\n    0x00, 0xe0, 0x10, 0xa4, 0x00, 0xe4, 0x22, 0x00,\n    0xe4, 0x01, 0xe0, 0x3d, 0xa5, 0x20, 0x05, 0x00,\n    0xe5, 0x24, 0x00, 0x25, 0x40, 0x05, 0x20, 0xe5,\n    0x0f, 0x00, 0x16, 0xeb, 0x00, 0xe5, 0x0f, 0x2f,\n    0xcb, 0xe5, 0x17, 0xe0, 0x00, 0xeb, 0x01, 0xe0,\n    0x28, 0xe5, 0x0b, 0x00, 0x25, 0x80, 0x8b, 0xe5,\n    0x0e, 0xab, 0x40, 0x16, 0xe5, 0x12, 0x80, 0x16,\n    0xe5, 0x12, 0xe0, 0x1e, 0xe5, 0x30, 0x60, 0x2b,\n    0x25, 0xeb, 0x08, 0x20, 0xeb, 0x26, 0x05, 0x46,\n    0x00, 0x26, 0x80, 0x66, 0x65, 0x00, 0x45, 0x00,\n    0xe5, 0x15, 0x20, 0x46, 0x60, 0x06, 0xeb, 0x01,\n    0xc0, 0xf6, 0x01, 0xc0, 0xe5, 0x15, 0x2b, 0x16,\n    0xe5, 0x15, 0x4b, 0xe0, 0x18, 0xe5, 0x00, 0x0f,\n    0xe5, 0x14, 0x26, 0x60, 0x8b, 0xd6, 0xe0, 0x01,\n    0xe5, 0x2e, 0x40, 0xd6, 0xe5, 0x0e, 0x20, 0xeb,\n    0x00, 0xe5, 0x0b, 0x80, 0xeb, 0x00, 0xe5, 0x0a,\n    0xc0, 0x76, 0xe0, 0x04, 0xcb, 0xe0, 0x48, 0xe5,\n    0x41, 0xe0, 0x2f, 0xe1, 0x2b, 0xe0, 0x05, 0xe2,\n    0x2b, 0xc0, 0xab, 0xe5, 0x1c, 0x66, 0xe0, 0x00,\n    0xe9, 0x02, 0xa0, 0xe9, 0x02, 0x65, 0x04, 0x05,\n    0xe1, 0x0e, 0x40, 0x86, 0x11, 0x04, 0xe2, 0x0e,\n    0xe0, 0x00, 0x2c, 0xe0, 0x80, 0x48, 0xeb, 0x17,\n    0x00, 0xe5, 0x22, 0x00, 0x26, 0x11, 0x20, 0x25,\n    0xe0, 0x08, 0x45, 0x04, 0x25, 0xe0, 0x00, 0x16,\n    0xef, 0x00, 0xe0, 0x19, 0xa6, 0xe5, 0x15, 0xeb,\n    0x02, 0x05, 0xe0, 0x00, 0xe5, 0x0e, 0xe6, 0x03,\n    0x6b, 0x96, 0xe0, 0x0e, 0xe5, 0x0a, 0x66, 0x76,\n    0xe0, 0x1e, 0xe5, 0x0d, 0xcb, 0xe0, 0x0c, 0xe5,\n    0x0f, 0xe0, 0x01, 0x07, 0x06, 0x07, 0xe5, 0x2d,\n    0xe6, 0x07, 0xd6, 0x60, 0xeb, 0x0c, 0xe9, 0x02,\n    0x06, 0x25, 0x26, 0x05, 0xe0, 0x01, 0x46, 0x07,\n    0xe5, 0x25, 0x47, 0x66, 0x27, 0x26, 0x36, 0x1b,\n    0x76, 0x06, 0xe0, 0x02, 0x1b, 0x20, 0xe5, 0x11,\n    0xc0, 0xe9, 0x02, 0xa0, 0x46, 0xe5, 0x1c, 0x86,\n    0x07, 0xe6, 0x00, 0x00, 0xe9, 0x02, 0x76, 0x05,\n    0x27, 0x05, 0xe0, 0x00, 0xe5, 0x1b, 0x06, 0x36,\n    0x05, 0xe0, 0x01, 0x26, 0x07, 0xe5, 0x28, 0x47,\n    0xe6, 0x01, 0x27, 0x65, 0x76, 0x66, 0x16, 0x07,\n    0x06, 0xe9, 0x02, 0x05, 0x16, 0x05, 0x56, 0x00,\n    0xeb, 0x0c, 0xe0, 0x03, 0xe5, 0x0a, 0x00, 0xe5,\n    0x11, 0x47, 0x46, 0x27, 0x06, 0x07, 0x26, 0xb6,\n    0x06, 0x25, 0x06, 0xe0, 0x36, 0xc5, 0x00, 0x05,\n    0x00, 0x65, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x02,\n    0x16, 0xa0, 0xe5, 0x27, 0x06, 0x47, 0xe6, 0x00,\n    0x80, 0xe9, 0x02, 0xa0, 0x26, 0x27, 0x00, 0xe5,\n    0x00, 0x20, 0x25, 0x20, 0xe5, 0x0e, 0x00, 0xc5,\n    0x00, 0x25, 0x00, 0x85, 0x00, 0x26, 0x05, 0x27,\n    0x06, 0x67, 0x20, 0x27, 0x20, 0x47, 0x20, 0x05,\n    0xa0, 0x07, 0x80, 0x85, 0x27, 0x20, 0xc6, 0x40,\n    0x86, 0xe0, 0x03, 0xe5, 0x02, 0x00, 0x05, 0x20,\n    0x05, 0x00, 0xe5, 0x1e, 0x00, 0x05, 0x47, 0xa6,\n    0x00, 0x07, 0x20, 0x07, 0x00, 0x67, 0x00, 0x27,\n    0x06, 0x07, 0x06, 0x05, 0x06, 0x05, 0x36, 0x00,\n    0x36, 0xe0, 0x00, 0x26, 0xe0, 0x15, 0xe5, 0x2d,\n    0x47, 0xe6, 0x00, 0x27, 0x46, 0x07, 0x06, 0x65,\n    0x96, 0xe9, 0x02, 0x36, 0x00, 0x16, 0x06, 0x45,\n    0xe0, 0x16, 0xe5, 0x28, 0x47, 0xa6, 0x07, 0x06,\n    0x67, 0x26, 0x07, 0x26, 0x25, 0x16, 0x05, 0xe0,\n    0x00, 0xe9, 0x02, 0xe0, 0x80, 0x1e, 0xe5, 0x27,\n    0x47, 0x66, 0x20, 0x67, 0x26, 0x07, 0x26, 0xf6,\n    0x0f, 0x65, 0x26, 0xe0, 0x1a, 0xe5, 0x28, 0x47,\n    0xe6, 0x00, 0x27, 0x06, 0x07, 0x26, 0x56, 0x05,\n    0xe0, 0x03, 0xe9, 0x02, 0xa0, 0xf6, 0x05, 0xe0,\n    0x0b, 0xe5, 0x23, 0x06, 0x07, 0x06, 0x27, 0xa6,\n    0x07, 0x06, 0x05, 0x16, 0xa0, 0xe9, 0x02, 0xa0,\n    0xe9, 0x0c, 0xe0, 0x14, 0xe5, 0x13, 0x20, 0x06,\n    0x07, 0x06, 0x27, 0x66, 0x07, 0x86, 0x60, 0xe9,\n    0x02, 0x2b, 0x56, 0x0f, 0xc5, 0xe0, 0x80, 0x31,\n    0xe5, 0x24, 0x47, 0xe6, 0x01, 0x07, 0x26, 0x16,\n    0xe0, 0x5c, 0xe1, 0x18, 0xe2, 0x18, 0xe9, 0x02,\n    0xeb, 0x01, 0xe0, 0x04, 0xe5, 0x00, 0x20, 0x05,\n    0x20, 0xe5, 0x00, 0x00, 0x25, 0x00, 0xe5, 0x10,\n    0xa7, 0x00, 0x27, 0x20, 0x26, 0x07, 0x06, 0x05,\n    0x07, 0x05, 0x07, 0x06, 0x56, 0xe0, 0x01, 0xe9,\n    0x02, 0xe0, 0x3e, 0xe5, 0x00, 0x20, 0xe5, 0x1f,\n    0x47, 0x66, 0x20, 0x26, 0x67, 0x06, 0x05, 0x16,\n    0x05, 0x07, 0xe0, 0x13, 0x05, 0xe6, 0x02, 0xe5,\n    0x20, 0xa6, 0x07, 0x05, 0x66, 0xf6, 0x00, 0x06,\n    0xe0, 0x00, 0x05, 0xa6, 0x27, 0x46, 0xe5, 0x26,\n    0xe6, 0x05, 0x07, 0x26, 0x56, 0x05, 0x96, 0xe0,\n    0x05, 0xe5, 0x41, 0xc0, 0xf6, 0x02, 0xe0, 0x4e,\n    0x06, 0x07, 0x46, 0x07, 0x06, 0x07, 0xe0, 0x50,\n    0xe5, 0x19, 0x16, 0xe0, 0x06, 0xe9, 0x02, 0xa0,\n    0xe5, 0x01, 0x00, 0xe5, 0x1d, 0x07, 0xc6, 0x00,\n    0xa6, 0x07, 0x06, 0x05, 0x96, 0xe0, 0x02, 0xe9,\n    0x02, 0xeb, 0x0b, 0x40, 0x36, 0xe5, 0x16, 0x20,\n    0xe6, 0x0e, 0x00, 0x07, 0xc6, 0x07, 0x26, 0x07,\n    0x26, 0xe0, 0x41, 0xc5, 0x00, 0x25, 0x00, 0xe5,\n    0x1e, 0xa6, 0x40, 0x06, 0x00, 0x26, 0x00, 0xc6,\n    0x05, 0x06, 0xe0, 0x00, 0xe9, 0x02, 0xa0, 0xa5,\n    0x00, 0x25, 0x00, 0xe5, 0x18, 0x87, 0x00, 0x26,\n    0x00, 0x27, 0x06, 0x07, 0x06, 0x05, 0xc0, 0xe9,\n    0x02, 0xa0, 0xe5, 0x21, 0x04, 0x25, 0x60, 0xe9,\n    0x02, 0xe0, 0x80, 0x6e, 0xe5, 0x0b, 0x26, 0x27,\n    0x36, 0xc0, 0x26, 0x05, 0x07, 0xe5, 0x05, 0x00,\n    0xe5, 0x1a, 0x27, 0x86, 0x40, 0x27, 0x06, 0x07,\n    0x06, 0xf6, 0x05, 0xe9, 0x02, 0x06, 0xe0, 0x4d,\n    0x05, 0xe0, 0x07, 0xeb, 0x0d, 0xef, 0x00, 0x6d,\n    0xef, 0x09, 0xe0, 0x05, 0x16, 0xe5, 0x83, 0x12,\n    0xe0, 0x5e, 0xea, 0x67, 0x00, 0x96, 0xe0, 0x03,\n    0xe5, 0x80, 0x3c, 0xe0, 0x89, 0xc4, 0xe5, 0x59,\n    0x36, 0xe0, 0x05, 0xe5, 0x83, 0xa8, 0xfb, 0x08,\n    0x06, 0xa5, 0xe6, 0x07, 0xe0, 0x02, 0xe5, 0x8f,\n    0x13, 0x80, 0xe5, 0x81, 0xbf, 0xe0, 0x9a, 0x31,\n    0xe5, 0x16, 0xe6, 0x04, 0x47, 0x46, 0xe9, 0x02,\n    0xe0, 0x86, 0x3e, 0xe5, 0x81, 0xb1, 0xc0, 0xe5,\n    0x17, 0x00, 0xe9, 0x02, 0x60, 0x36, 0xe5, 0x47,\n    0x00, 0xe9, 0x02, 0xa0, 0xe5, 0x16, 0x20, 0x86,\n    0x16, 0xe0, 0x02, 0xe5, 0x28, 0xc6, 0x96, 0x6f,\n    0x64, 0x16, 0x0f, 0xe0, 0x02, 0xe9, 0x02, 0x00,\n    0xcb, 0x00, 0xe5, 0x0d, 0x80, 0xe5, 0x0b, 0xe0,\n    0x81, 0x28, 0x44, 0xe5, 0x20, 0x24, 0x56, 0xe9,\n    0x02, 0xe0, 0x80, 0x3e, 0xe1, 0x18, 0xe2, 0x18,\n    0xeb, 0x0f, 0x76, 0x80, 0xe1, 0x11, 0x20, 0xe2,\n    0x11, 0xe0, 0x24, 0xe5, 0x43, 0x60, 0x06, 0x05,\n    0xe7, 0x2f, 0xc0, 0x66, 0xe4, 0x05, 0xe0, 0x38,\n    0x24, 0x16, 0x04, 0x06, 0xe0, 0x03, 0x27, 0x24,\n    0x4a, 0xe0, 0x01, 0xe5, 0x9c, 0x4e, 0xe0, 0x21,\n    0xe5, 0x18, 0xe0, 0x59, 0xe5, 0x6b, 0xe0, 0xa1,\n    0x75, 0x64, 0x00, 0xc4, 0x00, 0x24, 0x00, 0xe5,\n    0x80, 0x9b, 0xe0, 0x07, 0x05, 0xe0, 0x15, 0x45,\n    0x20, 0x05, 0xe0, 0x06, 0x65, 0xe0, 0x00, 0xe5,\n    0x81, 0x04, 0xe0, 0x88, 0x7c, 0xe5, 0x63, 0x80,\n    0xe5, 0x05, 0x40, 0xe5, 0x01, 0xc0, 0xe5, 0x02,\n    0x20, 0x0f, 0x26, 0x16, 0x7b, 0xe0, 0x8e, 0xd4,\n    0xef, 0x80, 0x68, 0xe9, 0x02, 0x4f, 0x40, 0xef,\n    0x81, 0x2c, 0xa0, 0xef, 0x0f, 0xe0, 0x07, 0xef,\n    0x08, 0x0c, 0xe0, 0x07, 0xe6, 0x26, 0x20, 0xe6,\n    0x0f, 0xe0, 0x01, 0xef, 0x6c, 0xe0, 0x34, 0xef,\n    0x80, 0x6e, 0xe0, 0x02, 0xef, 0x1f, 0x20, 0xef,\n    0x34, 0x27, 0x46, 0x4f, 0xa7, 0xfb, 0x00, 0xe6,\n    0x00, 0x2f, 0xc6, 0xef, 0x16, 0x66, 0xef, 0x35,\n    0xe0, 0x0d, 0xef, 0x3a, 0x46, 0x0f, 0xe0, 0x72,\n    0xeb, 0x0c, 0xe0, 0x04, 0xeb, 0x0c, 0xe0, 0x04,\n    0xef, 0x4f, 0xe0, 0x01, 0xeb, 0x11, 0xe0, 0x7f,\n    0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xc2, 0x00,\n    0xe2, 0x0a, 0xe1, 0x12, 0xe2, 0x12, 0x01, 0x00,\n    0x21, 0x20, 0x01, 0x20, 0x21, 0x20, 0x61, 0x00,\n    0xe1, 0x00, 0x62, 0x00, 0x02, 0x00, 0xc2, 0x00,\n    0xe2, 0x03, 0xe1, 0x12, 0xe2, 0x12, 0x21, 0x00,\n    0x61, 0x20, 0xe1, 0x00, 0x00, 0xc1, 0x00, 0xe2,\n    0x12, 0x21, 0x00, 0x61, 0x00, 0x81, 0x00, 0x01,\n    0x40, 0xc1, 0x00, 0xe2, 0x12, 0xe1, 0x12, 0xe2,\n    0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2,\n    0x12, 0xe1, 0x12, 0xe2, 0x12, 0xe1, 0x12, 0xe2,\n    0x12, 0xe1, 0x12, 0xe2, 0x14, 0x20, 0xe1, 0x11,\n    0x0c, 0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c,\n    0xe2, 0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2,\n    0x11, 0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11,\n    0x0c, 0xa2, 0xe1, 0x11, 0x0c, 0xe2, 0x11, 0x0c,\n    0xa2, 0x3f, 0x20, 0xe9, 0x2a, 0xef, 0x81, 0x78,\n    0xe6, 0x2f, 0x6f, 0xe6, 0x2a, 0xef, 0x00, 0x06,\n    0xef, 0x06, 0x06, 0x2f, 0x96, 0xe0, 0x07, 0x86,\n    0x00, 0xe6, 0x07, 0xe0, 0x83, 0xc8, 0xe2, 0x02,\n    0x05, 0xe2, 0x0c, 0xa0, 0xa2, 0xe0, 0x80, 0x4d,\n    0xc6, 0x00, 0xe6, 0x09, 0x20, 0xc6, 0x00, 0x26,\n    0x00, 0x86, 0x80, 0xe4, 0x36, 0xe0, 0x19, 0x06,\n    0xe0, 0x68, 0xe5, 0x25, 0x40, 0xc6, 0xc4, 0x20,\n    0xe9, 0x02, 0x60, 0x05, 0x0f, 0xe0, 0x80, 0xb8,\n    0xe5, 0x16, 0x06, 0xe0, 0x09, 0xe5, 0x24, 0x66,\n    0xe9, 0x02, 0x80, 0x0d, 0xe0, 0x81, 0x48, 0xe5,\n    0x13, 0x04, 0x66, 0xe9, 0x02, 0xe0, 0x80, 0x4e,\n    0xe5, 0x16, 0x26, 0x05, 0xe9, 0x02, 0x60, 0x16,\n    0xe0, 0x80, 0x38, 0xe5, 0x17, 0x00, 0x45, 0x06,\n    0x25, 0x06, 0xc5, 0x26, 0x85, 0x06, 0xe0, 0x00,\n    0x05, 0x04, 0xe0, 0x80, 0x58, 0xc5, 0x00, 0x65,\n    0x00, 0x25, 0x00, 0xe5, 0x07, 0x00, 0xe5, 0x80,\n    0x3d, 0x20, 0xeb, 0x01, 0xc6, 0xe0, 0x21, 0xe1,\n    0x1a, 0xe2, 0x1a, 0xc6, 0x04, 0x60, 0xe9, 0x02,\n    0x60, 0x36, 0xe0, 0x82, 0x89, 0xeb, 0x33, 0x0f,\n    0x4b, 0x0d, 0x6b, 0xe0, 0x44, 0xeb, 0x25, 0x0f,\n    0xeb, 0x07, 0xe0, 0x80, 0x3a, 0x65, 0x00, 0xe5,\n    0x13, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05, 0x00,\n    0xe5, 0x02, 0x00, 0x65, 0x00, 0x05, 0x00, 0x05,\n    0xa0, 0x05, 0x60, 0x05, 0x00, 0x05, 0x00, 0x05,\n    0x00, 0x45, 0x00, 0x25, 0x00, 0x05, 0x20, 0x05,\n    0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,\n    0x00, 0x25, 0x00, 0x05, 0x20, 0x65, 0x00, 0xc5,\n    0x00, 0x65, 0x00, 0x65, 0x00, 0x05, 0x00, 0xe5,\n    0x02, 0x00, 0xe5, 0x09, 0x80, 0x45, 0x00, 0x85,\n    0x00, 0xe5, 0x09, 0xe0, 0x2c, 0x2c, 0xe0, 0x80,\n    0x86, 0xef, 0x24, 0x60, 0xef, 0x5c, 0xe0, 0x04,\n    0xef, 0x07, 0x20, 0xef, 0x07, 0x00, 0xef, 0x07,\n    0x00, 0xef, 0x1d, 0xe0, 0x02, 0xeb, 0x05, 0xef,\n    0x80, 0x19, 0xe0, 0x30, 0xef, 0x15, 0xe0, 0x05,\n    0xef, 0x24, 0x60, 0xef, 0x01, 0xc0, 0x2f, 0xe0,\n    0x06, 0xaf, 0xe0, 0x80, 0x12, 0xef, 0x80, 0x73,\n    0x8e, 0xef, 0x82, 0x51, 0x40, 0xef, 0x09, 0x40,\n    0xef, 0x05, 0x40, 0xef, 0x80, 0x52, 0xa0, 0xef,\n    0x04, 0x60, 0x0f, 0xe0, 0x07, 0xef, 0x04, 0x60,\n    0xef, 0x30, 0xe0, 0x00, 0xef, 0x02, 0xa0, 0xef,\n    0x20, 0xe0, 0x00, 0xef, 0x16, 0x20, 0xef, 0x04,\n    0x60, 0x2f, 0xe0, 0x06, 0xec, 0x01, 0xe0, 0x1f,\n    0xef, 0x80, 0xd0, 0xe0, 0x00, 0xef, 0x06, 0x20,\n    0xef, 0x05, 0x40, 0xef, 0x03, 0x40, 0xef, 0x31,\n    0x00, 0x0f, 0x60, 0xef, 0x08, 0x20, 0xef, 0x04,\n    0x60, 0xef, 0x02, 0xc0, 0xef, 0x80, 0x0b, 0x00,\n    0xef, 0x54, 0xe9, 0x02, 0x0f, 0xe0, 0x83, 0x7d,\n    0xe5, 0xc0, 0x66, 0x58, 0xe0, 0x18, 0xe5, 0x90,\n    0x96, 0x20, 0xe5, 0x96, 0x06, 0x20, 0xe5, 0x9c,\n    0xa9, 0xe0, 0x07, 0xe5, 0x81, 0xe6, 0xe0, 0x89,\n    0x1a, 0xe5, 0x81, 0x96, 0xe0, 0x85, 0x5a, 0xe5,\n    0x92, 0xc3, 0x80, 0xe5, 0xa0, 0xa2, 0xe0, 0xca,\n    0x8a, 0xff, 0x1b, 0xe0, 0x16, 0xfb, 0x58, 0xe0,\n    0x78, 0xe6, 0x80, 0x68, 0xe0, 0xc0, 0xbd, 0x88,\n    0xfd, 0xc0, 0xbf, 0x76, 0x20, 0xfd, 0xc0, 0xbf,\n    0x76, 0x20,\n};\n\ntypedef enum {\n    UNICODE_SCRIPT_Unknown,\n    UNICODE_SCRIPT_Adlam,\n    UNICODE_SCRIPT_Ahom,\n    UNICODE_SCRIPT_Anatolian_Hieroglyphs,\n    UNICODE_SCRIPT_Arabic,\n    UNICODE_SCRIPT_Armenian,\n    UNICODE_SCRIPT_Avestan,\n    UNICODE_SCRIPT_Balinese,\n    UNICODE_SCRIPT_Bamum,\n    UNICODE_SCRIPT_Bassa_Vah,\n    UNICODE_SCRIPT_Batak,\n    UNICODE_SCRIPT_Beria_Erfe,\n    UNICODE_SCRIPT_Bengali,\n    UNICODE_SCRIPT_Bhaiksuki,\n    UNICODE_SCRIPT_Bopomofo,\n    UNICODE_SCRIPT_Brahmi,\n    UNICODE_SCRIPT_Braille,\n    UNICODE_SCRIPT_Buginese,\n    UNICODE_SCRIPT_Buhid,\n    UNICODE_SCRIPT_Canadian_Aboriginal,\n    UNICODE_SCRIPT_Carian,\n    UNICODE_SCRIPT_Caucasian_Albanian,\n    UNICODE_SCRIPT_Chakma,\n    UNICODE_SCRIPT_Cham,\n    UNICODE_SCRIPT_Cherokee,\n    UNICODE_SCRIPT_Chorasmian,\n    UNICODE_SCRIPT_Common,\n    UNICODE_SCRIPT_Coptic,\n    UNICODE_SCRIPT_Cuneiform,\n    UNICODE_SCRIPT_Cypriot,\n    UNICODE_SCRIPT_Cyrillic,\n    UNICODE_SCRIPT_Cypro_Minoan,\n    UNICODE_SCRIPT_Deseret,\n    UNICODE_SCRIPT_Devanagari,\n    UNICODE_SCRIPT_Dives_Akuru,\n    UNICODE_SCRIPT_Dogra,\n    UNICODE_SCRIPT_Duployan,\n    UNICODE_SCRIPT_Egyptian_Hieroglyphs,\n    UNICODE_SCRIPT_Elbasan,\n    UNICODE_SCRIPT_Elymaic,\n    UNICODE_SCRIPT_Ethiopic,\n    UNICODE_SCRIPT_Garay,\n    UNICODE_SCRIPT_Georgian,\n    UNICODE_SCRIPT_Glagolitic,\n    UNICODE_SCRIPT_Gothic,\n    UNICODE_SCRIPT_Grantha,\n    UNICODE_SCRIPT_Greek,\n    UNICODE_SCRIPT_Gujarati,\n    UNICODE_SCRIPT_Gunjala_Gondi,\n    UNICODE_SCRIPT_Gurmukhi,\n    UNICODE_SCRIPT_Gurung_Khema,\n    UNICODE_SCRIPT_Han,\n    UNICODE_SCRIPT_Hangul,\n    UNICODE_SCRIPT_Hanifi_Rohingya,\n    UNICODE_SCRIPT_Hanunoo,\n    UNICODE_SCRIPT_Hatran,\n    UNICODE_SCRIPT_Hebrew,\n    UNICODE_SCRIPT_Hiragana,\n    UNICODE_SCRIPT_Imperial_Aramaic,\n    UNICODE_SCRIPT_Inherited,\n    UNICODE_SCRIPT_Inscriptional_Pahlavi,\n    UNICODE_SCRIPT_Inscriptional_Parthian,\n    UNICODE_SCRIPT_Javanese,\n    UNICODE_SCRIPT_Kaithi,\n    UNICODE_SCRIPT_Kannada,\n    UNICODE_SCRIPT_Katakana,\n    UNICODE_SCRIPT_Katakana_Or_Hiragana,\n    UNICODE_SCRIPT_Kawi,\n    UNICODE_SCRIPT_Kayah_Li,\n    UNICODE_SCRIPT_Kharoshthi,\n    UNICODE_SCRIPT_Khmer,\n    UNICODE_SCRIPT_Khojki,\n    UNICODE_SCRIPT_Khitan_Small_Script,\n    UNICODE_SCRIPT_Khudawadi,\n    UNICODE_SCRIPT_Kirat_Rai,\n    UNICODE_SCRIPT_Lao,\n    UNICODE_SCRIPT_Latin,\n    UNICODE_SCRIPT_Lepcha,\n    UNICODE_SCRIPT_Limbu,\n    UNICODE_SCRIPT_Linear_A,\n    UNICODE_SCRIPT_Linear_B,\n    UNICODE_SCRIPT_Lisu,\n    UNICODE_SCRIPT_Lycian,\n    UNICODE_SCRIPT_Lydian,\n    UNICODE_SCRIPT_Makasar,\n    UNICODE_SCRIPT_Mahajani,\n    UNICODE_SCRIPT_Malayalam,\n    UNICODE_SCRIPT_Mandaic,\n    UNICODE_SCRIPT_Manichaean,\n    UNICODE_SCRIPT_Marchen,\n    UNICODE_SCRIPT_Masaram_Gondi,\n    UNICODE_SCRIPT_Medefaidrin,\n    UNICODE_SCRIPT_Meetei_Mayek,\n    UNICODE_SCRIPT_Mende_Kikakui,\n    UNICODE_SCRIPT_Meroitic_Cursive,\n    UNICODE_SCRIPT_Meroitic_Hieroglyphs,\n    UNICODE_SCRIPT_Miao,\n    UNICODE_SCRIPT_Modi,\n    UNICODE_SCRIPT_Mongolian,\n    UNICODE_SCRIPT_Mro,\n    UNICODE_SCRIPT_Multani,\n    UNICODE_SCRIPT_Myanmar,\n    UNICODE_SCRIPT_Nabataean,\n    UNICODE_SCRIPT_Nag_Mundari,\n    UNICODE_SCRIPT_Nandinagari,\n    UNICODE_SCRIPT_New_Tai_Lue,\n    UNICODE_SCRIPT_Newa,\n    UNICODE_SCRIPT_Nko,\n    UNICODE_SCRIPT_Nushu,\n    UNICODE_SCRIPT_Nyiakeng_Puachue_Hmong,\n    UNICODE_SCRIPT_Ogham,\n    UNICODE_SCRIPT_Ol_Chiki,\n    UNICODE_SCRIPT_Ol_Onal,\n    UNICODE_SCRIPT_Old_Hungarian,\n    UNICODE_SCRIPT_Old_Italic,\n    UNICODE_SCRIPT_Old_North_Arabian,\n    UNICODE_SCRIPT_Old_Permic,\n    UNICODE_SCRIPT_Old_Persian,\n    UNICODE_SCRIPT_Old_Sogdian,\n    UNICODE_SCRIPT_Old_South_Arabian,\n    UNICODE_SCRIPT_Old_Turkic,\n    UNICODE_SCRIPT_Old_Uyghur,\n    UNICODE_SCRIPT_Oriya,\n    UNICODE_SCRIPT_Osage,\n    UNICODE_SCRIPT_Osmanya,\n    UNICODE_SCRIPT_Pahawh_Hmong,\n    UNICODE_SCRIPT_Palmyrene,\n    UNICODE_SCRIPT_Pau_Cin_Hau,\n    UNICODE_SCRIPT_Phags_Pa,\n    UNICODE_SCRIPT_Phoenician,\n    UNICODE_SCRIPT_Psalter_Pahlavi,\n    UNICODE_SCRIPT_Rejang,\n    UNICODE_SCRIPT_Runic,\n    UNICODE_SCRIPT_Samaritan,\n    UNICODE_SCRIPT_Saurashtra,\n    UNICODE_SCRIPT_Sharada,\n    UNICODE_SCRIPT_Shavian,\n    UNICODE_SCRIPT_Siddham,\n    UNICODE_SCRIPT_Sidetic,\n    UNICODE_SCRIPT_SignWriting,\n    UNICODE_SCRIPT_Sinhala,\n    UNICODE_SCRIPT_Sogdian,\n    UNICODE_SCRIPT_Sora_Sompeng,\n    UNICODE_SCRIPT_Soyombo,\n    UNICODE_SCRIPT_Sundanese,\n    UNICODE_SCRIPT_Sunuwar,\n    UNICODE_SCRIPT_Syloti_Nagri,\n    UNICODE_SCRIPT_Syriac,\n    UNICODE_SCRIPT_Tagalog,\n    UNICODE_SCRIPT_Tagbanwa,\n    UNICODE_SCRIPT_Tai_Le,\n    UNICODE_SCRIPT_Tai_Tham,\n    UNICODE_SCRIPT_Tai_Viet,\n    UNICODE_SCRIPT_Tai_Yo,\n    UNICODE_SCRIPT_Takri,\n    UNICODE_SCRIPT_Tamil,\n    UNICODE_SCRIPT_Tangut,\n    UNICODE_SCRIPT_Telugu,\n    UNICODE_SCRIPT_Thaana,\n    UNICODE_SCRIPT_Thai,\n    UNICODE_SCRIPT_Tibetan,\n    UNICODE_SCRIPT_Tifinagh,\n    UNICODE_SCRIPT_Tirhuta,\n    UNICODE_SCRIPT_Tangsa,\n    UNICODE_SCRIPT_Todhri,\n    UNICODE_SCRIPT_Tolong_Siki,\n    UNICODE_SCRIPT_Toto,\n    UNICODE_SCRIPT_Tulu_Tigalari,\n    UNICODE_SCRIPT_Ugaritic,\n    UNICODE_SCRIPT_Vai,\n    UNICODE_SCRIPT_Vithkuqi,\n    UNICODE_SCRIPT_Wancho,\n    UNICODE_SCRIPT_Warang_Citi,\n    UNICODE_SCRIPT_Yezidi,\n    UNICODE_SCRIPT_Yi,\n    UNICODE_SCRIPT_Zanabazar_Square,\n    UNICODE_SCRIPT_COUNT,\n} UnicodeScriptEnum;\n\nstatic const char unicode_script_name_table[] =\n    \"Unknown,Zzzz\"                \"\\0\"\n    \"Adlam,Adlm\"                  \"\\0\"\n    \"Ahom,Ahom\"                   \"\\0\"\n    \"Anatolian_Hieroglyphs,Hluw\"  \"\\0\"\n    \"Arabic,Arab\"                 \"\\0\"\n    \"Armenian,Armn\"               \"\\0\"\n    \"Avestan,Avst\"                \"\\0\"\n    \"Balinese,Bali\"               \"\\0\"\n    \"Bamum,Bamu\"                  \"\\0\"\n    \"Bassa_Vah,Bass\"              \"\\0\"\n    \"Batak,Batk\"                  \"\\0\"\n    \"Beria_Erfe,Berf\"             \"\\0\"\n    \"Bengali,Beng\"                \"\\0\"\n    \"Bhaiksuki,Bhks\"              \"\\0\"\n    \"Bopomofo,Bopo\"               \"\\0\"\n    \"Brahmi,Brah\"                 \"\\0\"\n    \"Braille,Brai\"                \"\\0\"\n    \"Buginese,Bugi\"               \"\\0\"\n    \"Buhid,Buhd\"                  \"\\0\"\n    \"Canadian_Aboriginal,Cans\"    \"\\0\"\n    \"Carian,Cari\"                 \"\\0\"\n    \"Caucasian_Albanian,Aghb\"     \"\\0\"\n    \"Chakma,Cakm\"                 \"\\0\"\n    \"Cham,Cham\"                   \"\\0\"\n    \"Cherokee,Cher\"               \"\\0\"\n    \"Chorasmian,Chrs\"             \"\\0\"\n    \"Common,Zyyy\"                 \"\\0\"\n    \"Coptic,Copt,Qaac\"            \"\\0\"\n    \"Cuneiform,Xsux\"              \"\\0\"\n    \"Cypriot,Cprt\"                \"\\0\"\n    \"Cyrillic,Cyrl\"               \"\\0\"\n    \"Cypro_Minoan,Cpmn\"           \"\\0\"\n    \"Deseret,Dsrt\"                \"\\0\"\n    \"Devanagari,Deva\"             \"\\0\"\n    \"Dives_Akuru,Diak\"            \"\\0\"\n    \"Dogra,Dogr\"                  \"\\0\"\n    \"Duployan,Dupl\"               \"\\0\"\n    \"Egyptian_Hieroglyphs,Egyp\"   \"\\0\"\n    \"Elbasan,Elba\"                \"\\0\"\n    \"Elymaic,Elym\"                \"\\0\"\n    \"Ethiopic,Ethi\"               \"\\0\"\n    \"Garay,Gara\"                  \"\\0\"\n    \"Georgian,Geor\"               \"\\0\"\n    \"Glagolitic,Glag\"             \"\\0\"\n    \"Gothic,Goth\"                 \"\\0\"\n    \"Grantha,Gran\"                \"\\0\"\n    \"Greek,Grek\"                  \"\\0\"\n    \"Gujarati,Gujr\"               \"\\0\"\n    \"Gunjala_Gondi,Gong\"          \"\\0\"\n    \"Gurmukhi,Guru\"               \"\\0\"\n    \"Gurung_Khema,Gukh\"           \"\\0\"\n    \"Han,Hani\"                    \"\\0\"\n    \"Hangul,Hang\"                 \"\\0\"\n    \"Hanifi_Rohingya,Rohg\"        \"\\0\"\n    \"Hanunoo,Hano\"                \"\\0\"\n    \"Hatran,Hatr\"                 \"\\0\"\n    \"Hebrew,Hebr\"                 \"\\0\"\n    \"Hiragana,Hira\"               \"\\0\"\n    \"Imperial_Aramaic,Armi\"       \"\\0\"\n    \"Inherited,Zinh,Qaai\"         \"\\0\"\n    \"Inscriptional_Pahlavi,Phli\"  \"\\0\"\n    \"Inscriptional_Parthian,Prti\" \"\\0\"\n    \"Javanese,Java\"               \"\\0\"\n    \"Kaithi,Kthi\"                 \"\\0\"\n    \"Kannada,Knda\"                \"\\0\"\n    \"Katakana,Kana\"               \"\\0\"\n    \"Katakana_Or_Hiragana,Hrkt\"   \"\\0\"\n    \"Kawi,Kawi\"                   \"\\0\"\n    \"Kayah_Li,Kali\"               \"\\0\"\n    \"Kharoshthi,Khar\"             \"\\0\"\n    \"Khmer,Khmr\"                  \"\\0\"\n    \"Khojki,Khoj\"                 \"\\0\"\n    \"Khitan_Small_Script,Kits\"    \"\\0\"\n    \"Khudawadi,Sind\"              \"\\0\"\n    \"Kirat_Rai,Krai\"              \"\\0\"\n    \"Lao,Laoo\"                    \"\\0\"\n    \"Latin,Latn\"                  \"\\0\"\n    \"Lepcha,Lepc\"                 \"\\0\"\n    \"Limbu,Limb\"                  \"\\0\"\n    \"Linear_A,Lina\"               \"\\0\"\n    \"Linear_B,Linb\"               \"\\0\"\n    \"Lisu,Lisu\"                   \"\\0\"\n    \"Lycian,Lyci\"                 \"\\0\"\n    \"Lydian,Lydi\"                 \"\\0\"\n    \"Makasar,Maka\"                \"\\0\"\n    \"Mahajani,Mahj\"               \"\\0\"\n    \"Malayalam,Mlym\"              \"\\0\"\n    \"Mandaic,Mand\"                \"\\0\"\n    \"Manichaean,Mani\"             \"\\0\"\n    \"Marchen,Marc\"                \"\\0\"\n    \"Masaram_Gondi,Gonm\"          \"\\0\"\n    \"Medefaidrin,Medf\"            \"\\0\"\n    \"Meetei_Mayek,Mtei\"           \"\\0\"\n    \"Mende_Kikakui,Mend\"          \"\\0\"\n    \"Meroitic_Cursive,Merc\"       \"\\0\"\n    \"Meroitic_Hieroglyphs,Mero\"   \"\\0\"\n    \"Miao,Plrd\"                   \"\\0\"\n    \"Modi,Modi\"                   \"\\0\"\n    \"Mongolian,Mong\"              \"\\0\"\n    \"Mro,Mroo\"                    \"\\0\"\n    \"Multani,Mult\"                \"\\0\"\n    \"Myanmar,Mymr\"                \"\\0\"\n    \"Nabataean,Nbat\"              \"\\0\"\n    \"Nag_Mundari,Nagm\"            \"\\0\"\n    \"Nandinagari,Nand\"            \"\\0\"\n    \"New_Tai_Lue,Talu\"            \"\\0\"\n    \"Newa,Newa\"                   \"\\0\"\n    \"Nko,Nkoo\"                    \"\\0\"\n    \"Nushu,Nshu\"                  \"\\0\"\n    \"Nyiakeng_Puachue_Hmong,Hmnp\" \"\\0\"\n    \"Ogham,Ogam\"                  \"\\0\"\n    \"Ol_Chiki,Olck\"               \"\\0\"\n    \"Ol_Onal,Onao\"                \"\\0\"\n    \"Old_Hungarian,Hung\"          \"\\0\"\n    \"Old_Italic,Ital\"             \"\\0\"\n    \"Old_North_Arabian,Narb\"      \"\\0\"\n    \"Old_Permic,Perm\"             \"\\0\"\n    \"Old_Persian,Xpeo\"            \"\\0\"\n    \"Old_Sogdian,Sogo\"            \"\\0\"\n    \"Old_South_Arabian,Sarb\"      \"\\0\"\n    \"Old_Turkic,Orkh\"             \"\\0\"\n    \"Old_Uyghur,Ougr\"             \"\\0\"\n    \"Oriya,Orya\"                  \"\\0\"\n    \"Osage,Osge\"                  \"\\0\"\n    \"Osmanya,Osma\"                \"\\0\"\n    \"Pahawh_Hmong,Hmng\"           \"\\0\"\n    \"Palmyrene,Palm\"              \"\\0\"\n    \"Pau_Cin_Hau,Pauc\"            \"\\0\"\n    \"Phags_Pa,Phag\"               \"\\0\"\n    \"Phoenician,Phnx\"             \"\\0\"\n    \"Psalter_Pahlavi,Phlp\"        \"\\0\"\n    \"Rejang,Rjng\"                 \"\\0\"\n    \"Runic,Runr\"                  \"\\0\"\n    \"Samaritan,Samr\"              \"\\0\"\n    \"Saurashtra,Saur\"             \"\\0\"\n    \"Sharada,Shrd\"                \"\\0\"\n    \"Shavian,Shaw\"                \"\\0\"\n    \"Siddham,Sidd\"                \"\\0\"\n    \"Sidetic,Sidt\"                \"\\0\"\n    \"SignWriting,Sgnw\"            \"\\0\"\n    \"Sinhala,Sinh\"                \"\\0\"\n    \"Sogdian,Sogd\"                \"\\0\"\n    \"Sora_Sompeng,Sora\"           \"\\0\"\n    \"Soyombo,Soyo\"                \"\\0\"\n    \"Sundanese,Sund\"              \"\\0\"\n    \"Sunuwar,Sunu\"                \"\\0\"\n    \"Syloti_Nagri,Sylo\"           \"\\0\"\n    \"Syriac,Syrc\"                 \"\\0\"\n    \"Tagalog,Tglg\"                \"\\0\"\n    \"Tagbanwa,Tagb\"               \"\\0\"\n    \"Tai_Le,Tale\"                 \"\\0\"\n    \"Tai_Tham,Lana\"               \"\\0\"\n    \"Tai_Viet,Tavt\"               \"\\0\"\n    \"Tai_Yo,Tayo\"                 \"\\0\"\n    \"Takri,Takr\"                  \"\\0\"\n    \"Tamil,Taml\"                  \"\\0\"\n    \"Tangut,Tang\"                 \"\\0\"\n    \"Telugu,Telu\"                 \"\\0\"\n    \"Thaana,Thaa\"                 \"\\0\"\n    \"Thai,Thai\"                   \"\\0\"\n    \"Tibetan,Tibt\"                \"\\0\"\n    \"Tifinagh,Tfng\"               \"\\0\"\n    \"Tirhuta,Tirh\"                \"\\0\"\n    \"Tangsa,Tnsa\"                 \"\\0\"\n    \"Todhri,Todr\"                 \"\\0\"\n    \"Tolong_Siki,Tols\"            \"\\0\"\n    \"Toto,Toto\"                   \"\\0\"\n    \"Tulu_Tigalari,Tutg\"          \"\\0\"\n    \"Ugaritic,Ugar\"               \"\\0\"\n    \"Vai,Vaii\"                    \"\\0\"\n    \"Vithkuqi,Vith\"               \"\\0\"\n    \"Wancho,Wcho\"                 \"\\0\"\n    \"Warang_Citi,Wara\"            \"\\0\"\n    \"Yezidi,Yezi\"                 \"\\0\"\n    \"Yi,Yiii\"                     \"\\0\"\n    \"Zanabazar_Square,Zanb\"       \"\\0\"\n;\n\nstatic const uint8_t unicode_script_table[2818] = {\n    0xc0, 0x1a, 0x99, 0x4c, 0x85, 0x1a, 0x99, 0x4c,\n    0xae, 0x1a, 0x80, 0x4c, 0x8e, 0x1a, 0x80, 0x4c,\n    0x84, 0x1a, 0x96, 0x4c, 0x80, 0x1a, 0x9e, 0x4c,\n    0x80, 0x1a, 0xe1, 0x60, 0x4c, 0xa6, 0x1a, 0x84,\n    0x4c, 0x84, 0x1a, 0x81, 0x0e, 0x93, 0x1a, 0xe0,\n    0x0f, 0x3b, 0x83, 0x2e, 0x80, 0x1a, 0x82, 0x2e,\n    0x01, 0x83, 0x2e, 0x80, 0x1a, 0x80, 0x2e, 0x03,\n    0x80, 0x2e, 0x80, 0x1a, 0x80, 0x2e, 0x80, 0x1a,\n    0x82, 0x2e, 0x00, 0x80, 0x2e, 0x00, 0x93, 0x2e,\n    0x00, 0xbe, 0x2e, 0x8d, 0x1b, 0x8f, 0x2e, 0xe0,\n    0x24, 0x1e, 0x81, 0x3b, 0xe0, 0x48, 0x1e, 0x00,\n    0xa5, 0x05, 0x01, 0xb1, 0x05, 0x01, 0x82, 0x05,\n    0x00, 0xb6, 0x38, 0x07, 0x9a, 0x38, 0x03, 0x85,\n    0x38, 0x0a, 0x84, 0x04, 0x80, 0x1a, 0x85, 0x04,\n    0x80, 0x1a, 0x8d, 0x04, 0x80, 0x1a, 0x82, 0x04,\n    0x80, 0x1a, 0x9f, 0x04, 0x80, 0x1a, 0x89, 0x04,\n    0x8a, 0x3b, 0x99, 0x04, 0x80, 0x3b, 0xe0, 0x0b,\n    0x04, 0x80, 0x1a, 0xa1, 0x04, 0x8d, 0x93, 0x00,\n    0xbb, 0x93, 0x01, 0x82, 0x93, 0xaf, 0x04, 0xb1,\n    0x9e, 0x0d, 0xba, 0x6b, 0x01, 0x82, 0x6b, 0xad,\n    0x85, 0x01, 0x8e, 0x85, 0x00, 0x9b, 0x57, 0x01,\n    0x80, 0x57, 0x00, 0x8a, 0x93, 0x04, 0xa1, 0x04,\n    0x04, 0xca, 0x04, 0x80, 0x1a, 0x9c, 0x04, 0xd0,\n    0x21, 0x83, 0x3b, 0x8e, 0x21, 0x81, 0x1a, 0x99,\n    0x21, 0x83, 0x0c, 0x00, 0x87, 0x0c, 0x01, 0x81,\n    0x0c, 0x01, 0x95, 0x0c, 0x00, 0x86, 0x0c, 0x00,\n    0x80, 0x0c, 0x02, 0x83, 0x0c, 0x01, 0x88, 0x0c,\n    0x01, 0x81, 0x0c, 0x01, 0x83, 0x0c, 0x07, 0x80,\n    0x0c, 0x03, 0x81, 0x0c, 0x00, 0x84, 0x0c, 0x01,\n    0x98, 0x0c, 0x01, 0x82, 0x31, 0x00, 0x85, 0x31,\n    0x03, 0x81, 0x31, 0x01, 0x95, 0x31, 0x00, 0x86,\n    0x31, 0x00, 0x81, 0x31, 0x00, 0x81, 0x31, 0x00,\n    0x81, 0x31, 0x01, 0x80, 0x31, 0x00, 0x84, 0x31,\n    0x03, 0x81, 0x31, 0x01, 0x82, 0x31, 0x02, 0x80,\n    0x31, 0x06, 0x83, 0x31, 0x00, 0x80, 0x31, 0x06,\n    0x90, 0x31, 0x09, 0x82, 0x2f, 0x00, 0x88, 0x2f,\n    0x00, 0x82, 0x2f, 0x00, 0x95, 0x2f, 0x00, 0x86,\n    0x2f, 0x00, 0x81, 0x2f, 0x00, 0x84, 0x2f, 0x01,\n    0x89, 0x2f, 0x00, 0x82, 0x2f, 0x00, 0x82, 0x2f,\n    0x01, 0x80, 0x2f, 0x0e, 0x83, 0x2f, 0x01, 0x8b,\n    0x2f, 0x06, 0x86, 0x2f, 0x00, 0x82, 0x7a, 0x00,\n    0x87, 0x7a, 0x01, 0x81, 0x7a, 0x01, 0x95, 0x7a,\n    0x00, 0x86, 0x7a, 0x00, 0x81, 0x7a, 0x00, 0x84,\n    0x7a, 0x01, 0x88, 0x7a, 0x01, 0x81, 0x7a, 0x01,\n    0x82, 0x7a, 0x06, 0x82, 0x7a, 0x03, 0x81, 0x7a,\n    0x00, 0x84, 0x7a, 0x01, 0x91, 0x7a, 0x09, 0x81,\n    0x9b, 0x00, 0x85, 0x9b, 0x02, 0x82, 0x9b, 0x00,\n    0x83, 0x9b, 0x02, 0x81, 0x9b, 0x00, 0x80, 0x9b,\n    0x00, 0x81, 0x9b, 0x02, 0x81, 0x9b, 0x02, 0x82,\n    0x9b, 0x02, 0x8b, 0x9b, 0x03, 0x84, 0x9b, 0x02,\n    0x82, 0x9b, 0x00, 0x83, 0x9b, 0x01, 0x80, 0x9b,\n    0x05, 0x80, 0x9b, 0x0d, 0x94, 0x9b, 0x04, 0x8c,\n    0x9d, 0x00, 0x82, 0x9d, 0x00, 0x96, 0x9d, 0x00,\n    0x8f, 0x9d, 0x01, 0x88, 0x9d, 0x00, 0x82, 0x9d,\n    0x00, 0x83, 0x9d, 0x06, 0x81, 0x9d, 0x00, 0x82,\n    0x9d, 0x00, 0x81, 0x9d, 0x01, 0x83, 0x9d, 0x01,\n    0x89, 0x9d, 0x06, 0x88, 0x9d, 0x8c, 0x40, 0x00,\n    0x82, 0x40, 0x00, 0x96, 0x40, 0x00, 0x89, 0x40,\n    0x00, 0x84, 0x40, 0x01, 0x88, 0x40, 0x00, 0x82,\n    0x40, 0x00, 0x83, 0x40, 0x06, 0x81, 0x40, 0x04,\n    0x82, 0x40, 0x00, 0x83, 0x40, 0x01, 0x89, 0x40,\n    0x00, 0x82, 0x40, 0x0b, 0x8c, 0x56, 0x00, 0x82,\n    0x56, 0x00, 0xb2, 0x56, 0x00, 0x82, 0x56, 0x00,\n    0x85, 0x56, 0x03, 0x8f, 0x56, 0x01, 0x99, 0x56,\n    0x00, 0x82, 0x8c, 0x00, 0x91, 0x8c, 0x02, 0x97,\n    0x8c, 0x00, 0x88, 0x8c, 0x00, 0x80, 0x8c, 0x01,\n    0x86, 0x8c, 0x02, 0x80, 0x8c, 0x03, 0x85, 0x8c,\n    0x00, 0x80, 0x8c, 0x00, 0x87, 0x8c, 0x05, 0x89,\n    0x8c, 0x01, 0x82, 0x8c, 0x0b, 0xb9, 0x9f, 0x03,\n    0x80, 0x1a, 0x9b, 0x9f, 0x24, 0x81, 0x4b, 0x00,\n    0x80, 0x4b, 0x00, 0x84, 0x4b, 0x00, 0x97, 0x4b,\n    0x00, 0x80, 0x4b, 0x00, 0x96, 0x4b, 0x01, 0x84,\n    0x4b, 0x00, 0x80, 0x4b, 0x00, 0x86, 0x4b, 0x00,\n    0x89, 0x4b, 0x01, 0x83, 0x4b, 0x1f, 0xc7, 0xa0,\n    0x00, 0xa3, 0xa0, 0x03, 0xa6, 0xa0, 0x00, 0xa3,\n    0xa0, 0x00, 0x8e, 0xa0, 0x00, 0x86, 0xa0, 0x83,\n    0x1a, 0x81, 0xa0, 0x24, 0xe0, 0x3f, 0x65, 0xa5,\n    0x2a, 0x00, 0x80, 0x2a, 0x04, 0x80, 0x2a, 0x01,\n    0xaa, 0x2a, 0x80, 0x1a, 0x83, 0x2a, 0xe0, 0x9f,\n    0x34, 0xc8, 0x28, 0x00, 0x83, 0x28, 0x01, 0x86,\n    0x28, 0x00, 0x80, 0x28, 0x00, 0x83, 0x28, 0x01,\n    0xa8, 0x28, 0x00, 0x83, 0x28, 0x01, 0xa0, 0x28,\n    0x00, 0x83, 0x28, 0x01, 0x86, 0x28, 0x00, 0x80,\n    0x28, 0x00, 0x83, 0x28, 0x01, 0x8e, 0x28, 0x00,\n    0xb8, 0x28, 0x00, 0x83, 0x28, 0x01, 0xc2, 0x28,\n    0x01, 0x9f, 0x28, 0x02, 0x99, 0x28, 0x05, 0xd5,\n    0x18, 0x01, 0x85, 0x18, 0x01, 0xe2, 0x1f, 0x13,\n    0x9c, 0x6e, 0x02, 0xca, 0x84, 0x82, 0x1a, 0x8a,\n    0x84, 0x06, 0x95, 0x94, 0x08, 0x80, 0x94, 0x94,\n    0x36, 0x81, 0x1a, 0x08, 0x93, 0x12, 0x0b, 0x8c,\n    0x95, 0x00, 0x82, 0x95, 0x00, 0x81, 0x95, 0x0b,\n    0xdd, 0x46, 0x01, 0x89, 0x46, 0x05, 0x89, 0x46,\n    0x05, 0x81, 0x62, 0x81, 0x1a, 0x80, 0x62, 0x80,\n    0x1a, 0x93, 0x62, 0x05, 0xd8, 0x62, 0x06, 0xaa,\n    0x62, 0x04, 0xc5, 0x13, 0x09, 0x9e, 0x4e, 0x00,\n    0x8b, 0x4e, 0x03, 0x8b, 0x4e, 0x03, 0x80, 0x4e,\n    0x02, 0x8b, 0x4e, 0x9d, 0x96, 0x01, 0x84, 0x96,\n    0x0a, 0xab, 0x69, 0x03, 0x99, 0x69, 0x05, 0x8a,\n    0x69, 0x02, 0x81, 0x69, 0x9f, 0x46, 0x9b, 0x11,\n    0x01, 0x81, 0x11, 0xbe, 0x97, 0x00, 0x9c, 0x97,\n    0x01, 0x8a, 0x97, 0x05, 0x89, 0x97, 0x05, 0x8d,\n    0x97, 0x01, 0xad, 0x3b, 0x01, 0x8b, 0x3b, 0x13,\n    0xcc, 0x07, 0x00, 0xb1, 0x07, 0xbf, 0x90, 0xb3,\n    0x0a, 0x07, 0x83, 0x0a, 0xb7, 0x4d, 0x02, 0x8e,\n    0x4d, 0x02, 0x82, 0x4d, 0xaf, 0x6f, 0x8a, 0x1e,\n    0x04, 0xaa, 0x2a, 0x01, 0x82, 0x2a, 0x87, 0x90,\n    0x07, 0x82, 0x3b, 0x80, 0x1a, 0x8c, 0x3b, 0x80,\n    0x1a, 0x86, 0x3b, 0x83, 0x1a, 0x80, 0x3b, 0x85,\n    0x1a, 0x80, 0x3b, 0x82, 0x1a, 0x81, 0x3b, 0x80,\n    0x1a, 0x04, 0xa5, 0x4c, 0x84, 0x2e, 0x80, 0x1e,\n    0xb0, 0x4c, 0x84, 0x2e, 0x83, 0x4c, 0x84, 0x2e,\n    0x8c, 0x4c, 0x80, 0x1e, 0xc5, 0x4c, 0x80, 0x2e,\n    0xbf, 0x3b, 0xe0, 0x9f, 0x4c, 0x95, 0x2e, 0x01,\n    0x85, 0x2e, 0x01, 0xa5, 0x2e, 0x01, 0x85, 0x2e,\n    0x01, 0x87, 0x2e, 0x00, 0x80, 0x2e, 0x00, 0x80,\n    0x2e, 0x00, 0x80, 0x2e, 0x00, 0x9e, 0x2e, 0x01,\n    0xb4, 0x2e, 0x00, 0x8e, 0x2e, 0x00, 0x8d, 0x2e,\n    0x01, 0x85, 0x2e, 0x00, 0x92, 0x2e, 0x01, 0x82,\n    0x2e, 0x00, 0x88, 0x2e, 0x00, 0x8b, 0x1a, 0x81,\n    0x3b, 0xd6, 0x1a, 0x00, 0x8a, 0x1a, 0x80, 0x4c,\n    0x01, 0x8a, 0x1a, 0x80, 0x4c, 0x8e, 0x1a, 0x00,\n    0x8c, 0x4c, 0x02, 0xa1, 0x1a, 0x0d, 0xa0, 0x3b,\n    0x0e, 0xa5, 0x1a, 0x80, 0x2e, 0x82, 0x1a, 0x81,\n    0x4c, 0x85, 0x1a, 0x80, 0x4c, 0x9a, 0x1a, 0x80,\n    0x4c, 0x90, 0x1a, 0xa8, 0x4c, 0x82, 0x1a, 0x03,\n    0xe2, 0x39, 0x1a, 0x15, 0x8a, 0x1a, 0x14, 0xe3,\n    0x3f, 0x1a, 0xe0, 0x9f, 0x10, 0xe2, 0x13, 0x1a,\n    0x01, 0xe0, 0x29, 0x1a, 0xdf, 0x2b, 0x9f, 0x4c,\n    0xe0, 0x13, 0x1b, 0x04, 0x86, 0x1b, 0xa5, 0x2a,\n    0x00, 0x80, 0x2a, 0x04, 0x80, 0x2a, 0x01, 0xb7,\n    0xa1, 0x06, 0x81, 0xa1, 0x0d, 0x80, 0xa1, 0x96,\n    0x28, 0x08, 0x86, 0x28, 0x00, 0x86, 0x28, 0x00,\n    0x86, 0x28, 0x00, 0x86, 0x28, 0x00, 0x86, 0x28,\n    0x00, 0x86, 0x28, 0x00, 0x86, 0x28, 0x00, 0x86,\n    0x28, 0x00, 0x9f, 0x1e, 0xdd, 0x1a, 0x21, 0x99,\n    0x33, 0x00, 0xd8, 0x33, 0x0b, 0xe0, 0x75, 0x33,\n    0x19, 0x94, 0x1a, 0x80, 0x33, 0x80, 0x1a, 0x80,\n    0x33, 0x98, 0x1a, 0x88, 0x33, 0x83, 0x3b, 0x81,\n    0x34, 0x87, 0x1a, 0x83, 0x33, 0x83, 0x1a, 0x00,\n    0xd5, 0x39, 0x01, 0x81, 0x3b, 0x81, 0x1a, 0x82,\n    0x39, 0x80, 0x1a, 0xd9, 0x41, 0x81, 0x1a, 0x82,\n    0x41, 0x04, 0xaa, 0x0e, 0x00, 0xdd, 0x34, 0x00,\n    0x8f, 0x1a, 0x9f, 0x0e, 0xa5, 0x1a, 0x08, 0x80,\n    0x1a, 0x8f, 0x41, 0x9e, 0x34, 0x00, 0xbf, 0x1a,\n    0x9e, 0x34, 0xd0, 0x1a, 0xae, 0x41, 0x80, 0x1a,\n    0xd7, 0x41, 0xe0, 0x47, 0x1a, 0xf0, 0x09, 0x5f,\n    0x33, 0xbf, 0x1a, 0xf0, 0x41, 0x9f, 0x33, 0xe4,\n    0x2c, 0xae, 0x02, 0xb6, 0xae, 0x08, 0xaf, 0x51,\n    0xe0, 0xcb, 0xa9, 0x13, 0xdf, 0x1e, 0xd7, 0x08,\n    0x07, 0xa1, 0x1a, 0xe0, 0x05, 0x4c, 0x82, 0x1a,\n    0xd1, 0x4c, 0x13, 0x8e, 0x4c, 0xac, 0x92, 0x02,\n    0x89, 0x1a, 0x05, 0xb7, 0x80, 0x07, 0xc5, 0x86,\n    0x07, 0x8b, 0x86, 0x05, 0x9f, 0x21, 0xad, 0x44,\n    0x80, 0x1a, 0x80, 0x44, 0xa3, 0x83, 0x0a, 0x80,\n    0x83, 0x9c, 0x34, 0x02, 0xcd, 0x3e, 0x00, 0x80,\n    0x1a, 0x89, 0x3e, 0x03, 0x81, 0x3e, 0x9e, 0x65,\n    0x00, 0xb6, 0x17, 0x08, 0x8d, 0x17, 0x01, 0x89,\n    0x17, 0x01, 0x83, 0x17, 0x9f, 0x65, 0xc2, 0x98,\n    0x17, 0x84, 0x98, 0x96, 0x5c, 0x09, 0x85, 0x28,\n    0x01, 0x85, 0x28, 0x01, 0x85, 0x28, 0x08, 0x86,\n    0x28, 0x00, 0x86, 0x28, 0x00, 0xaa, 0x4c, 0x80,\n    0x1a, 0x88, 0x4c, 0x80, 0x2e, 0x83, 0x4c, 0x81,\n    0x1a, 0x03, 0xcf, 0x18, 0xad, 0x5c, 0x01, 0x89,\n    0x5c, 0x05, 0xf0, 0x1b, 0x43, 0x34, 0x0b, 0x96,\n    0x34, 0x03, 0xb0, 0x34, 0x70, 0x10, 0xa3, 0xe1,\n    0x0d, 0x33, 0x01, 0xe0, 0x09, 0x33, 0x25, 0x86,\n    0x4c, 0x0b, 0x84, 0x05, 0x04, 0x99, 0x38, 0x00,\n    0x84, 0x38, 0x00, 0x80, 0x38, 0x00, 0x81, 0x38,\n    0x00, 0x81, 0x38, 0x00, 0x89, 0x38, 0xe1, 0x8d,\n    0x04, 0x81, 0x1a, 0xe0, 0x2f, 0x04, 0x1f, 0x8f,\n    0x04, 0x8f, 0x3b, 0x89, 0x1a, 0x05, 0x8d, 0x3b,\n    0x81, 0x1e, 0xa2, 0x1a, 0x00, 0x92, 0x1a, 0x00,\n    0x83, 0x1a, 0x03, 0x84, 0x04, 0x00, 0xe0, 0x26,\n    0x04, 0x01, 0x80, 0x1a, 0x00, 0x9f, 0x1a, 0x99,\n    0x4c, 0x85, 0x1a, 0x99, 0x4c, 0x8a, 0x1a, 0x89,\n    0x41, 0x80, 0x1a, 0xac, 0x41, 0x81, 0x1a, 0x9e,\n    0x34, 0x02, 0x85, 0x34, 0x01, 0x85, 0x34, 0x01,\n    0x85, 0x34, 0x01, 0x82, 0x34, 0x02, 0x86, 0x1a,\n    0x00, 0x86, 0x1a, 0x09, 0x84, 0x1a, 0x01, 0x8b,\n    0x50, 0x00, 0x99, 0x50, 0x00, 0x92, 0x50, 0x00,\n    0x81, 0x50, 0x00, 0x8e, 0x50, 0x01, 0x8d, 0x50,\n    0x21, 0xe0, 0x1a, 0x50, 0x04, 0x82, 0x1a, 0x03,\n    0xac, 0x1a, 0x02, 0x88, 0x1a, 0xce, 0x2e, 0x00,\n    0x8c, 0x1a, 0x02, 0x80, 0x2e, 0x2e, 0xac, 0x1a,\n    0x80, 0x3b, 0x60, 0x21, 0x9c, 0x52, 0x02, 0xb0,\n    0x14, 0x0e, 0x80, 0x3b, 0x9a, 0x1a, 0x03, 0xa3,\n    0x72, 0x08, 0x82, 0x72, 0x9a, 0x2c, 0x04, 0xaa,\n    0x74, 0x04, 0x9d, 0xa8, 0x00, 0x80, 0xa8, 0xa3,\n    0x75, 0x03, 0x8d, 0x75, 0x29, 0xcf, 0x20, 0xaf,\n    0x88, 0x9d, 0x7c, 0x01, 0x89, 0x7c, 0x05, 0xa3,\n    0x7b, 0x03, 0xa3, 0x7b, 0x03, 0xa7, 0x26, 0x07,\n    0xb3, 0x15, 0x0a, 0x80, 0x15, 0x8a, 0xaa, 0x00,\n    0x8e, 0xaa, 0x00, 0x86, 0xaa, 0x00, 0x81, 0xaa,\n    0x00, 0x8a, 0xaa, 0x00, 0x8e, 0xaa, 0x00, 0x86,\n    0xaa, 0x00, 0x81, 0xaa, 0x02, 0xb3, 0xa4, 0x0b,\n    0xe0, 0xd6, 0x4f, 0x08, 0x95, 0x4f, 0x09, 0x87,\n    0x4f, 0x17, 0x85, 0x4c, 0x00, 0xa9, 0x4c, 0x00,\n    0x88, 0x4c, 0x44, 0x85, 0x1d, 0x01, 0x80, 0x1d,\n    0x00, 0xab, 0x1d, 0x00, 0x81, 0x1d, 0x02, 0x80,\n    0x1d, 0x01, 0x80, 0x1d, 0x95, 0x3a, 0x00, 0x88,\n    0x3a, 0x9f, 0x7e, 0x9e, 0x66, 0x07, 0x88, 0x66,\n    0x2f, 0x92, 0x37, 0x00, 0x81, 0x37, 0x04, 0x84,\n    0x37, 0x9b, 0x81, 0x02, 0x80, 0x81, 0x99, 0x53,\n    0x04, 0x80, 0x53, 0x99, 0x8a, 0x25, 0x9f, 0x5f,\n    0x97, 0x5e, 0x03, 0x93, 0x5e, 0x01, 0xad, 0x5e,\n    0x83, 0x45, 0x00, 0x81, 0x45, 0x04, 0x87, 0x45,\n    0x00, 0x82, 0x45, 0x00, 0x9c, 0x45, 0x01, 0x82,\n    0x45, 0x03, 0x89, 0x45, 0x06, 0x88, 0x45, 0x06,\n    0x9f, 0x77, 0x9f, 0x73, 0x1f, 0xa6, 0x58, 0x03,\n    0x8b, 0x58, 0x08, 0xb5, 0x06, 0x02, 0x86, 0x06,\n    0x95, 0x3d, 0x01, 0x87, 0x3d, 0x92, 0x3c, 0x04,\n    0x87, 0x3c, 0x91, 0x82, 0x06, 0x83, 0x82, 0x0b,\n    0x86, 0x82, 0x4f, 0xc8, 0x78, 0x36, 0xb2, 0x71,\n    0x0c, 0xb2, 0x71, 0x06, 0x85, 0x71, 0xa7, 0x35,\n    0x07, 0x89, 0x35, 0x05, 0xa5, 0x29, 0x02, 0x9c,\n    0x29, 0x07, 0x81, 0x29, 0x60, 0x6f, 0x9e, 0x04,\n    0x00, 0xa9, 0xad, 0x00, 0x82, 0xad, 0x01, 0x81,\n    0xad, 0x0f, 0x85, 0x04, 0x07, 0x88, 0x04, 0x20,\n    0x85, 0x04, 0xa7, 0x76, 0x07, 0xa9, 0x8d, 0x15,\n    0x99, 0x79, 0x25, 0x9b, 0x19, 0x13, 0x96, 0x27,\n    0x08, 0xcd, 0x0f, 0x03, 0xa3, 0x0f, 0x08, 0x80,\n    0x0f, 0xc2, 0x3f, 0x09, 0x80, 0x3f, 0x01, 0x98,\n    0x8e, 0x06, 0x89, 0x8e, 0x05, 0xb4, 0x16, 0x00,\n    0x91, 0x16, 0x07, 0xa6, 0x55, 0x08, 0xdf, 0x87,\n    0x00, 0x93, 0x8c, 0x0a, 0x91, 0x47, 0x00, 0xae,\n    0x47, 0x3d, 0x86, 0x64, 0x00, 0x80, 0x64, 0x00,\n    0x83, 0x64, 0x00, 0x8e, 0x64, 0x00, 0x8a, 0x64,\n    0x05, 0xba, 0x49, 0x04, 0x89, 0x49, 0x05, 0x83,\n    0x2d, 0x00, 0x87, 0x2d, 0x01, 0x81, 0x2d, 0x01,\n    0x95, 0x2d, 0x00, 0x86, 0x2d, 0x00, 0x81, 0x2d,\n    0x00, 0x84, 0x2d, 0x00, 0x80, 0x3b, 0x88, 0x2d,\n    0x01, 0x81, 0x2d, 0x01, 0x82, 0x2d, 0x01, 0x80,\n    0x2d, 0x05, 0x80, 0x2d, 0x04, 0x86, 0x2d, 0x01,\n    0x86, 0x2d, 0x02, 0x84, 0x2d, 0x0a, 0x89, 0xa7,\n    0x00, 0x80, 0xa7, 0x01, 0x80, 0xa7, 0x00, 0xa5,\n    0xa7, 0x00, 0x89, 0xa7, 0x00, 0x80, 0xa7, 0x01,\n    0x80, 0xa7, 0x00, 0x83, 0xa7, 0x00, 0x89, 0xa7,\n    0x00, 0x81, 0xa7, 0x07, 0x81, 0xa7, 0x1c, 0xdb,\n    0x6a, 0x00, 0x84, 0x6a, 0x1d, 0xc7, 0xa2, 0x07,\n    0x89, 0xa2, 0x60, 0x45, 0xb5, 0x89, 0x01, 0xa5,\n    0x89, 0x21, 0xc4, 0x61, 0x0a, 0x89, 0x61, 0x05,\n    0x8c, 0x62, 0x12, 0xb9, 0x9a, 0x05, 0x89, 0x9a,\n    0x05, 0x93, 0x65, 0x1b, 0x9a, 0x02, 0x01, 0x8e,\n    0x02, 0x03, 0x96, 0x02, 0x60, 0x58, 0xbb, 0x23,\n    0x60, 0x03, 0xd2, 0xac, 0x0b, 0x80, 0xac, 0x86,\n    0x22, 0x01, 0x80, 0x22, 0x01, 0x87, 0x22, 0x00,\n    0x81, 0x22, 0x00, 0x9d, 0x22, 0x00, 0x81, 0x22,\n    0x01, 0x8b, 0x22, 0x08, 0x89, 0x22, 0x45, 0x87,\n    0x68, 0x01, 0xad, 0x68, 0x01, 0x8a, 0x68, 0x1a,\n    0xc7, 0xaf, 0x07, 0xd2, 0x8f, 0x0c, 0x8f, 0x13,\n    0xb8, 0x7f, 0x06, 0x89, 0x21, 0x55, 0x87, 0x87,\n    0x57, 0xa1, 0x91, 0x0d, 0x89, 0x91, 0x05, 0x88,\n    0x0d, 0x00, 0xac, 0x0d, 0x00, 0x8d, 0x0d, 0x09,\n    0x9c, 0x0d, 0x02, 0x9f, 0x59, 0x01, 0x95, 0x59,\n    0x00, 0x8d, 0x59, 0x48, 0x86, 0x5a, 0x00, 0x81,\n    0x5a, 0x00, 0xab, 0x5a, 0x02, 0x80, 0x5a, 0x00,\n    0x81, 0x5a, 0x00, 0x88, 0x5a, 0x07, 0x89, 0x5a,\n    0x05, 0x85, 0x30, 0x00, 0x81, 0x30, 0x00, 0xa4,\n    0x30, 0x00, 0x81, 0x30, 0x00, 0x85, 0x30, 0x06,\n    0x89, 0x30, 0x05, 0xab, 0xa5, 0x03, 0x89, 0xa5,\n    0x60, 0x95, 0x98, 0x54, 0x06, 0x90, 0x43, 0x00,\n    0xa8, 0x43, 0x02, 0x9c, 0x43, 0x54, 0x80, 0x51,\n    0x0e, 0xb1, 0x9b, 0x0c, 0x80, 0x9b, 0xe3, 0x39,\n    0x1c, 0x60, 0x05, 0xe0, 0x0e, 0x1c, 0x00, 0x84,\n    0x1c, 0x0a, 0xe0, 0x63, 0x1c, 0x69, 0xeb, 0xe0,\n    0x02, 0x1f, 0x0c, 0xe3, 0xf5, 0x25, 0x09, 0xef,\n    0x3a, 0x25, 0x04, 0xe1, 0xe6, 0x03, 0x70, 0x0a,\n    0x58, 0xb9, 0x32, 0x66, 0x65, 0xe1, 0xd8, 0x08,\n    0x06, 0x9e, 0x63, 0x00, 0x89, 0x63, 0x03, 0x81,\n    0x63, 0xce, 0xa3, 0x00, 0x89, 0xa3, 0x05, 0x9d,\n    0x09, 0x01, 0x85, 0x09, 0x09, 0xc5, 0x7d, 0x09,\n    0x89, 0x7d, 0x00, 0x86, 0x7d, 0x00, 0x94, 0x7d,\n    0x04, 0x92, 0x7d, 0x61, 0x4f, 0xb9, 0x4a, 0x60,\n    0x65, 0xda, 0x5b, 0x04, 0x98, 0x0b, 0x01, 0x98,\n    0x0b, 0x2b, 0xca, 0x60, 0x03, 0xb8, 0x60, 0x06,\n    0x90, 0x60, 0x3f, 0x80, 0x9c, 0x80, 0x6c, 0x81,\n    0x33, 0x80, 0x48, 0x0a, 0x86, 0x33, 0x08, 0xf0,\n    0x0a, 0x9f, 0x9c, 0xe1, 0x75, 0x48, 0x28, 0x80,\n    0x48, 0x9e, 0x9c, 0x60, 0x00, 0xe0, 0x12, 0x9c,\n    0x70, 0x11, 0x9c, 0x83, 0x41, 0x00, 0x86, 0x41,\n    0x00, 0x81, 0x41, 0x00, 0x80, 0x41, 0xe0, 0xbe,\n    0x39, 0x82, 0x41, 0x0e, 0x80, 0x39, 0x1c, 0x82,\n    0x39, 0x01, 0x80, 0x41, 0x0d, 0x83, 0x41, 0x07,\n    0xe1, 0x2b, 0x6c, 0x68, 0xa3, 0xe0, 0x0a, 0x24,\n    0x04, 0x8c, 0x24, 0x02, 0x88, 0x24, 0x06, 0x89,\n    0x24, 0x01, 0x83, 0x24, 0x83, 0x1a, 0x6e, 0xfb,\n    0xe0, 0x9c, 0x1a, 0x02, 0xe1, 0x53, 0x1a, 0x05,\n    0x96, 0x1a, 0x0e, 0x90, 0x1a, 0x0e, 0xad, 0x3b,\n    0x01, 0x96, 0x3b, 0x08, 0xe0, 0x13, 0x1a, 0x3b,\n    0xe0, 0x95, 0x1a, 0x09, 0xa6, 0x1a, 0x01, 0xbd,\n    0x1a, 0x82, 0x3b, 0x90, 0x1a, 0x87, 0x3b, 0x81,\n    0x1a, 0x86, 0x3b, 0x9d, 0x1a, 0x83, 0x3b, 0xbc,\n    0x1a, 0x14, 0xc5, 0x2e, 0x60, 0x19, 0x93, 0x1a,\n    0x0b, 0x93, 0x1a, 0x0b, 0xd6, 0x1a, 0x08, 0x98,\n    0x1a, 0x60, 0x26, 0xd4, 0x1a, 0x00, 0xc6, 0x1a,\n    0x00, 0x81, 0x1a, 0x01, 0x80, 0x1a, 0x01, 0x81,\n    0x1a, 0x01, 0x83, 0x1a, 0x00, 0x8b, 0x1a, 0x00,\n    0x80, 0x1a, 0x00, 0x86, 0x1a, 0x00, 0xc0, 0x1a,\n    0x00, 0x83, 0x1a, 0x01, 0x87, 0x1a, 0x00, 0x86,\n    0x1a, 0x00, 0x9b, 0x1a, 0x00, 0x83, 0x1a, 0x00,\n    0x84, 0x1a, 0x00, 0x80, 0x1a, 0x02, 0x86, 0x1a,\n    0x00, 0xe0, 0xf3, 0x1a, 0x01, 0xe0, 0xc3, 0x1a,\n    0x01, 0xb1, 0x1a, 0xe2, 0x2b, 0x8b, 0x0e, 0x84,\n    0x8b, 0x00, 0x8e, 0x8b, 0x63, 0xef, 0x9e, 0x4c,\n    0x05, 0x85, 0x4c, 0x60, 0x74, 0x86, 0x2b, 0x00,\n    0x90, 0x2b, 0x01, 0x86, 0x2b, 0x00, 0x81, 0x2b,\n    0x00, 0x84, 0x2b, 0x04, 0xbd, 0x1e, 0x20, 0x80,\n    0x1e, 0x60, 0x0f, 0xac, 0x6d, 0x02, 0x8d, 0x6d,\n    0x01, 0x89, 0x6d, 0x03, 0x81, 0x6d, 0x60, 0xdf,\n    0x9e, 0xa6, 0x10, 0xb9, 0xab, 0x04, 0x80, 0xab,\n    0x61, 0x6f, 0xa9, 0x67, 0x60, 0x75, 0xaa, 0x70,\n    0x03, 0x80, 0x70, 0x60, 0x5f, 0x9e, 0x99, 0x00,\n    0x95, 0x99, 0x07, 0x81, 0x99, 0x60, 0x7f, 0x86,\n    0x28, 0x00, 0x83, 0x28, 0x00, 0x81, 0x28, 0x00,\n    0x8e, 0x28, 0x00, 0xe0, 0x64, 0x5d, 0x01, 0x8f,\n    0x5d, 0x28, 0xcb, 0x01, 0x03, 0x89, 0x01, 0x03,\n    0x81, 0x01, 0x62, 0xb0, 0xc3, 0x1a, 0x4b, 0xbc,\n    0x1a, 0x60, 0x61, 0x83, 0x04, 0x00, 0x9a, 0x04,\n    0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01, 0x80,\n    0x04, 0x00, 0x89, 0x04, 0x00, 0x83, 0x04, 0x00,\n    0x80, 0x04, 0x00, 0x80, 0x04, 0x05, 0x80, 0x04,\n    0x03, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80,\n    0x04, 0x00, 0x82, 0x04, 0x00, 0x81, 0x04, 0x00,\n    0x80, 0x04, 0x01, 0x80, 0x04, 0x00, 0x80, 0x04,\n    0x00, 0x80, 0x04, 0x00, 0x80, 0x04, 0x00, 0x80,\n    0x04, 0x00, 0x81, 0x04, 0x00, 0x80, 0x04, 0x01,\n    0x83, 0x04, 0x00, 0x86, 0x04, 0x00, 0x83, 0x04,\n    0x00, 0x83, 0x04, 0x00, 0x80, 0x04, 0x00, 0x89,\n    0x04, 0x00, 0x90, 0x04, 0x04, 0x82, 0x04, 0x00,\n    0x84, 0x04, 0x00, 0x90, 0x04, 0x33, 0x81, 0x04,\n    0x60, 0xad, 0xab, 0x1a, 0x03, 0xe0, 0x03, 0x1a,\n    0x0b, 0x8e, 0x1a, 0x01, 0x8e, 0x1a, 0x00, 0x8e,\n    0x1a, 0x00, 0xa4, 0x1a, 0x09, 0xe0, 0x4d, 0x1a,\n    0x37, 0x99, 0x1a, 0x80, 0x39, 0x81, 0x1a, 0x0c,\n    0xab, 0x1a, 0x03, 0x88, 0x1a, 0x06, 0x81, 0x1a,\n    0x0d, 0x85, 0x1a, 0x60, 0x39, 0xe3, 0x78, 0x1a,\n    0x02, 0x90, 0x1a, 0x02, 0x8c, 0x1a, 0x02, 0xe0,\n    0x79, 0x1a, 0x05, 0x8b, 0x1a, 0x03, 0x80, 0x1a,\n    0x0e, 0x8b, 0x1a, 0x03, 0xb7, 0x1a, 0x07, 0x89,\n    0x1a, 0x05, 0xa7, 0x1a, 0x07, 0x9d, 0x1a, 0x01,\n    0x8b, 0x1a, 0x03, 0x81, 0x1a, 0x0d, 0x88, 0x1a,\n    0x26, 0xe0, 0xf7, 0x1a, 0x07, 0x8d, 0x1a, 0x01,\n    0x8c, 0x1a, 0x02, 0x8a, 0x1a, 0x02, 0xb8, 0x1a,\n    0x00, 0x80, 0x1a, 0x03, 0x8f, 0x1a, 0x01, 0x8b,\n    0x1a, 0x03, 0x89, 0x1a, 0x06, 0xe0, 0x32, 0x1a,\n    0x00, 0xe0, 0x06, 0x1a, 0x63, 0xa4, 0xf0, 0x96,\n    0x7f, 0x33, 0x1f, 0xf0, 0x00, 0xbd, 0x33, 0x01,\n    0xf0, 0x06, 0x2d, 0x33, 0x01, 0xf0, 0x0c, 0xd0,\n    0x33, 0x0e, 0xe2, 0x0d, 0x33, 0x69, 0x41, 0xe1,\n    0xbd, 0x33, 0x65, 0x81, 0xf0, 0x02, 0xea, 0x33,\n    0x04, 0xf0, 0x10, 0xc9, 0x33, 0x7a, 0xbb, 0x26,\n    0x80, 0x1a, 0x1d, 0xdf, 0x1a, 0x60, 0x1f, 0xe0,\n    0x8f, 0x3b,\n};\n\nstatic const uint8_t unicode_script_ext_table[1278] = {\n    0x80, 0x36, 0x00, 0x00, 0x10, 0x06, 0x14, 0x1b,\n    0x24, 0x26, 0x2a, 0x2b, 0x30, 0x2c, 0x2e, 0x33,\n    0x4c, 0x53, 0x55, 0x74, 0x88, 0x81, 0x83, 0x00,\n    0x00, 0x07, 0x0c, 0x1e, 0x21, 0x4c, 0x51, 0x9f,\n    0xa6, 0x09, 0x00, 0x00, 0x02, 0x0e, 0x4c, 0x00,\n    0x00, 0x02, 0x02, 0x0e, 0x4c, 0x00, 0x00, 0x00,\n    0x02, 0x4c, 0x51, 0x08, 0x00, 0x00, 0x02, 0x4c,\n    0x9f, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x4c, 0x25,\n    0x00, 0x00, 0x08, 0x18, 0x1b, 0x1e, 0x2e, 0x4c,\n    0x74, 0x91, 0x96, 0x00, 0x08, 0x18, 0x1e, 0x2e,\n    0x4c, 0x7b, 0x91, 0x96, 0xa4, 0x00, 0x04, 0x18,\n    0x1e, 0x4c, 0xa1, 0x00, 0x05, 0x2b, 0x4c, 0x91,\n    0x93, 0x9f, 0x00, 0x0b, 0x15, 0x18, 0x1b, 0x1e,\n    0x2c, 0x2e, 0x4c, 0x7b, 0x93, 0xa1, 0xa4, 0x00,\n    0x06, 0x1b, 0x26, 0x2b, 0x2c, 0x41, 0x4c, 0x00,\n    0x05, 0x1e, 0x2e, 0x4c, 0x74, 0xa1, 0x00, 0x09,\n    0x1b, 0x24, 0x38, 0x4c, 0x74, 0x93, 0x96, 0xa1,\n    0xa4, 0x00, 0x0b, 0x05, 0x1e, 0x24, 0x2c, 0x2e,\n    0x38, 0x4c, 0x74, 0x93, 0x96, 0xa1, 0x00, 0x02,\n    0x4c, 0xa1, 0x00, 0x03, 0x24, 0x4c, 0x93, 0x00,\n    0x04, 0x18, 0x1e, 0x4c, 0x7b, 0x00, 0x03, 0x18,\n    0x4c, 0x96, 0x00, 0x02, 0x4c, 0x91, 0x00, 0x02,\n    0x28, 0x4c, 0x00, 0x00, 0x00, 0x02, 0x4c, 0x91,\n    0x00, 0x03, 0x1e, 0x4c, 0xa4, 0x00, 0x00, 0x00,\n    0x04, 0x2e, 0x4c, 0x74, 0xa4, 0x0e, 0x00, 0x00,\n    0x06, 0x18, 0x24, 0x41, 0x4c, 0x93, 0xa1, 0x00,\n    0x04, 0x18, 0x24, 0x4c, 0x93, 0x00, 0x02, 0x4c,\n    0x93, 0x06, 0x00, 0x00, 0x03, 0x4c, 0x91, 0x93,\n    0x00, 0x02, 0x4c, 0x93, 0x00, 0x00, 0x00, 0x03,\n    0x18, 0x4c, 0x93, 0x00, 0x07, 0x15, 0x18, 0x2c,\n    0x4c, 0x91, 0x93, 0x9f, 0x0f, 0x00, 0x00, 0x01,\n    0x2e, 0x01, 0x00, 0x00, 0x01, 0x2e, 0x11, 0x00,\n    0x00, 0x02, 0x4c, 0x7b, 0x04, 0x00, 0x00, 0x03,\n    0x15, 0x4c, 0xa4, 0x03, 0x00, 0x0c, 0x01, 0x4c,\n    0x03, 0x00, 0x01, 0x02, 0x1b, 0x2e, 0x80, 0x8c,\n    0x00, 0x00, 0x02, 0x1e, 0x74, 0x00, 0x02, 0x1e,\n    0x2b, 0x01, 0x02, 0x1e, 0x4c, 0x00, 0x02, 0x1e,\n    0x2b, 0x80, 0x80, 0x00, 0x00, 0x03, 0x05, 0x2a,\n    0x2b, 0x80, 0x01, 0x00, 0x00, 0x07, 0x04, 0x29,\n    0x6b, 0x35, 0x93, 0x9e, 0xad, 0x0d, 0x00, 0x00,\n    0x07, 0x04, 0x29, 0x6b, 0x35, 0x93, 0x9e, 0xad,\n    0x00, 0x03, 0x04, 0x93, 0x9e, 0x01, 0x00, 0x00,\n    0x08, 0x01, 0x04, 0x29, 0x6b, 0x35, 0x93, 0x9e,\n    0xad, 0x1f, 0x00, 0x00, 0x09, 0x01, 0x04, 0x57,\n    0x58, 0x79, 0x82, 0x35, 0x8d, 0x93, 0x09, 0x00,\n    0x0a, 0x02, 0x04, 0x93, 0x09, 0x00, 0x09, 0x03,\n    0x04, 0x9e, 0xad, 0x05, 0x00, 0x00, 0x02, 0x04,\n    0x93, 0x62, 0x00, 0x00, 0x02, 0x04, 0x35, 0x81,\n    0xfb, 0x00, 0x00, 0x0f, 0x0c, 0x21, 0x2d, 0x2f,\n    0x31, 0x40, 0x4c, 0x56, 0x68, 0x6a, 0x7a, 0x87,\n    0x9b, 0x9d, 0xa2, 0x00, 0x0d, 0x0c, 0x21, 0x2d,\n    0x2f, 0x31, 0x40, 0x4c, 0x56, 0x6a, 0x7a, 0x9b,\n    0x9d, 0xa2, 0x10, 0x00, 0x00, 0x15, 0x0c, 0x21,\n    0x23, 0x30, 0x5a, 0x2d, 0x2f, 0x31, 0x40, 0x55,\n    0x56, 0x68, 0x70, 0x7a, 0x49, 0x8c, 0x92, 0x9a,\n    0x9b, 0x9d, 0xa2, 0x00, 0x17, 0x0c, 0x21, 0x23,\n    0x30, 0x5a, 0x2d, 0x2f, 0x32, 0x31, 0x40, 0x4e,\n    0x55, 0x56, 0x68, 0x70, 0x7a, 0x49, 0x8c, 0x92,\n    0x9a, 0x9b, 0x9d, 0xa2, 0x09, 0x04, 0x21, 0x23,\n    0x3f, 0x55, 0x75, 0x00, 0x09, 0x03, 0x0c, 0x16,\n    0x92, 0x75, 0x00, 0x09, 0x02, 0x31, 0x64, 0x75,\n    0x00, 0x09, 0x02, 0x2f, 0x47, 0x80, 0x75, 0x00,\n    0x0d, 0x02, 0x2d, 0x9b, 0x80, 0x71, 0x00, 0x09,\n    0x03, 0x40, 0x68, 0xa7, 0x82, 0xcf, 0x00, 0x09,\n    0x03, 0x16, 0x65, 0x96, 0x80, 0x30, 0x00, 0x00,\n    0x03, 0x2a, 0x2b, 0x4c, 0x85, 0x6e, 0x00, 0x02,\n    0x01, 0x84, 0x46, 0x00, 0x01, 0x04, 0x12, 0x36,\n    0x95, 0x94, 0x80, 0x4a, 0x00, 0x01, 0x02, 0x62,\n    0x80, 0x00, 0x00, 0x00, 0x02, 0x62, 0x80, 0x84,\n    0x49, 0x00, 0x00, 0x04, 0x0c, 0x21, 0x2d, 0x40,\n    0x00, 0x01, 0x21, 0x00, 0x04, 0x0c, 0x21, 0x2d,\n    0x40, 0x00, 0x03, 0x21, 0x2d, 0x40, 0x00, 0x01,\n    0x21, 0x00, 0x05, 0x0c, 0x21, 0x6a, 0x9d, 0xa2,\n    0x00, 0x03, 0x0c, 0x21, 0x9d, 0x00, 0x03, 0x21,\n    0x6a, 0x87, 0x00, 0x04, 0x0c, 0x21, 0x6a, 0x9d,\n    0x00, 0x02, 0x21, 0x87, 0x00, 0x06, 0x21, 0x40,\n    0x56, 0x7a, 0x9b, 0x9d, 0x00, 0x01, 0x21, 0x01,\n    0x02, 0x21, 0x87, 0x01, 0x01, 0x21, 0x00, 0x02,\n    0x21, 0x87, 0x00, 0x02, 0x0c, 0x21, 0x00, 0x03,\n    0x21, 0x6a, 0xa2, 0x05, 0x01, 0x21, 0x00, 0x03,\n    0x21, 0x68, 0x6a, 0x00, 0x03, 0x0c, 0x21, 0x87,\n    0x00, 0x02, 0x21, 0x6a, 0x00, 0x01, 0x21, 0x00,\n    0x04, 0x0c, 0x21, 0x6a, 0x87, 0x03, 0x01, 0x21,\n    0x00, 0x0b, 0x0c, 0x21, 0x2d, 0x40, 0x56, 0x68,\n    0x7a, 0x8c, 0x9d, 0xa2, 0xa7, 0x00, 0x02, 0x21,\n    0x2d, 0x00, 0x04, 0x21, 0x2d, 0x40, 0xa7, 0x01,\n    0x02, 0x0c, 0x21, 0x00, 0x01, 0x0c, 0x01, 0x02,\n    0x21, 0x2d, 0x00, 0x01, 0x68, 0x80, 0x44, 0x00,\n    0x01, 0x01, 0x2e, 0x35, 0x00, 0x00, 0x03, 0x1e,\n    0x4c, 0x93, 0x00, 0x00, 0x00, 0x01, 0x93, 0x81,\n    0xb3, 0x00, 0x00, 0x03, 0x4c, 0x62, 0x80, 0x1e,\n    0x00, 0x00, 0x02, 0x01, 0x04, 0x09, 0x00, 0x00,\n    0x06, 0x14, 0x2a, 0x2b, 0x71, 0x52, 0x78, 0x01,\n    0x00, 0x00, 0x04, 0x14, 0x2e, 0x71, 0x5f, 0x80,\n    0x11, 0x00, 0x00, 0x03, 0x21, 0x2d, 0x4c, 0x8c,\n    0xa5, 0x00, 0x00, 0x02, 0x1b, 0x4c, 0x17, 0x00,\n    0x00, 0x02, 0x06, 0x78, 0x00, 0x07, 0x06, 0x14,\n    0x2a, 0x71, 0x3f, 0x53, 0x85, 0x09, 0x00, 0x00,\n    0x01, 0x24, 0x03, 0x00, 0x00, 0x03, 0x01, 0x04,\n    0x71, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x2b, 0x81,\n    0x2b, 0x00, 0x0f, 0x02, 0x33, 0x9c, 0x00, 0x00,\n    0x00, 0x07, 0x0e, 0x34, 0x33, 0x39, 0x41, 0x62,\n    0xae, 0x00, 0x08, 0x0e, 0x34, 0x33, 0x39, 0x41,\n    0x62, 0x80, 0xae, 0x00, 0x05, 0x0e, 0x34, 0x33,\n    0x39, 0x41, 0x01, 0x00, 0x00, 0x01, 0x33, 0x00,\n    0x00, 0x01, 0x08, 0x0e, 0x34, 0x33, 0x39, 0x41,\n    0x62, 0xa0, 0xae, 0x01, 0x09, 0x0e, 0x34, 0x33,\n    0x39, 0x41, 0x51, 0x62, 0xa0, 0xae, 0x05, 0x06,\n    0x0e, 0x34, 0x33, 0x39, 0x41, 0xae, 0x00, 0x00,\n    0x00, 0x05, 0x0e, 0x34, 0x33, 0x39, 0x41, 0x07,\n    0x06, 0x0e, 0x34, 0x33, 0x39, 0x41, 0xae, 0x03,\n    0x05, 0x0e, 0x34, 0x33, 0x39, 0x41, 0x09, 0x00,\n    0x03, 0x02, 0x0e, 0x33, 0x01, 0x00, 0x00, 0x05,\n    0x0e, 0x34, 0x33, 0x39, 0x41, 0x04, 0x02, 0x39,\n    0x41, 0x00, 0x00, 0x00, 0x05, 0x0e, 0x34, 0x33,\n    0x39, 0x41, 0x03, 0x00, 0x01, 0x03, 0x33, 0x39,\n    0x41, 0x01, 0x01, 0x33, 0x58, 0x00, 0x03, 0x02,\n    0x39, 0x41, 0x02, 0x00, 0x00, 0x02, 0x39, 0x41,\n    0x59, 0x00, 0x00, 0x06, 0x0e, 0x34, 0x33, 0x39,\n    0x41, 0xae, 0x00, 0x02, 0x39, 0x41, 0x80, 0x12,\n    0x00, 0x0f, 0x01, 0x33, 0x1f, 0x00, 0x25, 0x01,\n    0x33, 0x08, 0x00, 0x00, 0x02, 0x33, 0x9c, 0x2f,\n    0x00, 0x27, 0x01, 0x33, 0x37, 0x00, 0x30, 0x01,\n    0x33, 0x0e, 0x00, 0x0b, 0x01, 0x33, 0x32, 0x00,\n    0x00, 0x01, 0x33, 0x57, 0x00, 0x18, 0x01, 0x33,\n    0x09, 0x00, 0x04, 0x01, 0x33, 0x5f, 0x00, 0x1e,\n    0x01, 0x33, 0xc0, 0x31, 0xef, 0x00, 0x00, 0x02,\n    0x1e, 0x2b, 0x80, 0x0f, 0x00, 0x07, 0x02, 0x33,\n    0x4c, 0x80, 0xa7, 0x00, 0x02, 0x10, 0x21, 0x23,\n    0x2f, 0x31, 0x47, 0x40, 0x3f, 0x55, 0x56, 0x61,\n    0x68, 0x87, 0x49, 0x9a, 0xa2, 0xa7, 0x02, 0x0f,\n    0x21, 0x23, 0x2f, 0x31, 0x47, 0x40, 0x3f, 0x55,\n    0x61, 0x68, 0x87, 0x49, 0x9a, 0xa2, 0xa7, 0x01,\n    0x0b, 0x21, 0x23, 0x2f, 0x31, 0x47, 0x3f, 0x55,\n    0x61, 0x49, 0x9a, 0xa2, 0x00, 0x0c, 0x21, 0x23,\n    0x2f, 0x31, 0x47, 0x3f, 0x55, 0x61, 0x87, 0x49,\n    0x9a, 0xa2, 0x00, 0x0b, 0x21, 0x23, 0x2f, 0x31,\n    0x47, 0x3f, 0x55, 0x61, 0x49, 0x9a, 0xa2, 0x80,\n    0x36, 0x00, 0x00, 0x03, 0x0c, 0x21, 0xa7, 0x00,\n    0x00, 0x00, 0x02, 0x21, 0x9b, 0x39, 0x00, 0x00,\n    0x03, 0x44, 0x4c, 0x65, 0x80, 0x1f, 0x00, 0x00,\n    0x02, 0x11, 0x3e, 0xc0, 0x12, 0xed, 0x00, 0x01,\n    0x02, 0x04, 0x6b, 0x80, 0x31, 0x00, 0x00, 0x02,\n    0x04, 0x9e, 0x09, 0x00, 0x00, 0x02, 0x04, 0x9e,\n    0x46, 0x00, 0x01, 0x05, 0x0e, 0x34, 0x33, 0x39,\n    0x41, 0x80, 0x99, 0x00, 0x04, 0x06, 0x0e, 0x34,\n    0x33, 0x39, 0x41, 0xae, 0x09, 0x00, 0x00, 0x02,\n    0x39, 0x41, 0x2c, 0x00, 0x01, 0x02, 0x39, 0x41,\n    0x80, 0xdf, 0x00, 0x01, 0x03, 0x1f, 0x1d, 0x50,\n    0x00, 0x02, 0x1d, 0x50, 0x03, 0x00, 0x2c, 0x03,\n    0x1d, 0x4f, 0x50, 0x02, 0x00, 0x08, 0x02, 0x1d,\n    0x50, 0x81, 0x1f, 0x00, 0x1b, 0x02, 0x04, 0x1b,\n    0x87, 0x75, 0x00, 0x00, 0x02, 0x58, 0x79, 0x87,\n    0x8d, 0x00, 0x00, 0x02, 0x2d, 0x9b, 0x00, 0x00,\n    0x00, 0x02, 0x2d, 0x9b, 0x36, 0x00, 0x01, 0x02,\n    0x2d, 0x9b, 0x8c, 0x12, 0x00, 0x01, 0x02, 0x2d,\n    0x9b, 0x00, 0x00, 0x00, 0x02, 0x2d, 0x9b, 0xc0,\n    0x5c, 0x4b, 0x00, 0x03, 0x01, 0x24, 0x96, 0x3b,\n    0x00, 0x11, 0x01, 0x33, 0x9e, 0x5d, 0x00, 0x01,\n    0x01, 0x33, 0xce, 0xcd, 0x2d, 0x00,\n};\n\nstatic const uint8_t unicode_prop_Hyphen_table[28] = {\n    0xac, 0x80, 0xfe, 0x80, 0x44, 0xdb, 0x80, 0x52,\n    0x7a, 0x80, 0x48, 0x08, 0x81, 0x4e, 0x04, 0x80,\n    0x42, 0xe2, 0x80, 0x60, 0xcd, 0x66, 0x80, 0x40,\n    0xa8, 0x80, 0xd6, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Other_Math_table[200] = {\n    0xdd, 0x80, 0x43, 0x70, 0x11, 0x80, 0x99, 0x09,\n    0x81, 0x5c, 0x1f, 0x80, 0x9a, 0x82, 0x8a, 0x80,\n    0x9f, 0x83, 0x97, 0x81, 0x8d, 0x81, 0xc0, 0x8c,\n    0x18, 0x11, 0x1c, 0x91, 0x03, 0x01, 0x89, 0x00,\n    0x14, 0x28, 0x11, 0x09, 0x02, 0x05, 0x13, 0x24,\n    0xca, 0x21, 0x18, 0x08, 0x08, 0x00, 0x21, 0x0b,\n    0x0b, 0x91, 0x09, 0x00, 0x06, 0x00, 0x29, 0x41,\n    0x21, 0x83, 0x40, 0xa7, 0x08, 0x80, 0x97, 0x80,\n    0x90, 0x80, 0x41, 0xbc, 0x81, 0x8b, 0x88, 0x24,\n    0x21, 0x09, 0x14, 0x8d, 0x00, 0x01, 0x85, 0x97,\n    0x81, 0xb8, 0x00, 0x80, 0x9c, 0x83, 0x88, 0x81,\n    0x41, 0x55, 0x81, 0x9e, 0x89, 0x41, 0x92, 0x95,\n    0xbe, 0x83, 0x9f, 0x81, 0x60, 0xd4, 0x62, 0x00,\n    0x03, 0x80, 0x40, 0xd2, 0x00, 0x80, 0x60, 0xd4,\n    0xc0, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09, 0x0b,\n    0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03, 0x0f,\n    0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16, 0x80,\n    0x41, 0x53, 0x81, 0x98, 0x80, 0x98, 0x80, 0x9e,\n    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x80, 0x9e,\n    0x80, 0x98, 0x80, 0x9e, 0x80, 0x98, 0x07, 0x81,\n    0xb1, 0x55, 0xff, 0x18, 0x9a, 0x01, 0x00, 0x08,\n    0x80, 0x89, 0x03, 0x00, 0x00, 0x28, 0x18, 0x00,\n    0x00, 0x02, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00,\n    0x00, 0x01, 0x00, 0x0b, 0x06, 0x03, 0x03, 0x00,\n    0x80, 0x89, 0x80, 0x90, 0x22, 0x04, 0x80, 0x90,\n};\n\nstatic const uint8_t unicode_prop_Other_Alphabetic_table[452] = {\n    0x43, 0x44, 0x80, 0x9c, 0x8c, 0x42, 0x3f, 0x8d,\n    0x00, 0x01, 0x01, 0x00, 0xc7, 0x8a, 0xaf, 0x8c,\n    0x06, 0x8f, 0x80, 0xe4, 0x33, 0x19, 0x0b, 0x80,\n    0xa2, 0x80, 0x9d, 0x8f, 0xe5, 0x8a, 0xe4, 0x0a,\n    0x88, 0x02, 0x03, 0xe9, 0x80, 0xbb, 0x8b, 0x16,\n    0x85, 0x93, 0xb5, 0x09, 0x8e, 0x01, 0x22, 0x89,\n    0x81, 0x9c, 0x82, 0xb9, 0x31, 0x09, 0x81, 0x89,\n    0x80, 0x89, 0x81, 0x9c, 0x82, 0xb9, 0x23, 0x09,\n    0x0b, 0x80, 0x9d, 0x0a, 0x80, 0x8a, 0x82, 0xb9,\n    0x38, 0x10, 0x81, 0x94, 0x81, 0x95, 0x13, 0x82,\n    0xb9, 0x31, 0x09, 0x81, 0x88, 0x81, 0x89, 0x81,\n    0x9d, 0x80, 0xba, 0x22, 0x10, 0x82, 0x89, 0x80,\n    0xa7, 0x84, 0xb8, 0x30, 0x10, 0x17, 0x81, 0x8a,\n    0x81, 0x9c, 0x82, 0xb9, 0x30, 0x10, 0x17, 0x81,\n    0x8a, 0x81, 0x8e, 0x80, 0x8b, 0x83, 0xb9, 0x30,\n    0x10, 0x82, 0x89, 0x80, 0x89, 0x81, 0x9c, 0x82,\n    0xca, 0x28, 0x00, 0x87, 0x91, 0x81, 0xbc, 0x01,\n    0x86, 0x91, 0x80, 0xe2, 0x01, 0x28, 0x81, 0x8f,\n    0x80, 0x40, 0xa2, 0x92, 0x88, 0x8a, 0x80, 0xa3,\n    0xed, 0x8b, 0x00, 0x0b, 0x96, 0x1b, 0x10, 0x11,\n    0x32, 0x83, 0x8c, 0x8b, 0x00, 0x89, 0x83, 0x46,\n    0x73, 0x81, 0x9d, 0x81, 0x9d, 0x81, 0x9d, 0x81,\n    0xc1, 0x92, 0x40, 0xbb, 0x81, 0xa1, 0x80, 0xf5,\n    0x8b, 0x83, 0x88, 0x40, 0xdd, 0x84, 0xb8, 0x89,\n    0x81, 0x93, 0xc9, 0x81, 0x8a, 0x82, 0xb0, 0x84,\n    0xaf, 0x8e, 0xbb, 0x82, 0x9d, 0x88, 0x09, 0xb8,\n    0x8a, 0xb1, 0x92, 0x41, 0x9b, 0xa1, 0x46, 0xc0,\n    0xb3, 0x48, 0xf5, 0x9f, 0x60, 0x78, 0x73, 0x87,\n    0xa1, 0x81, 0x41, 0x61, 0x07, 0x80, 0x96, 0x84,\n    0xd7, 0x81, 0xb1, 0x8f, 0x00, 0xb8, 0x80, 0xa5,\n    0x84, 0x9b, 0x8b, 0xac, 0x83, 0xaf, 0x8b, 0xa4,\n    0x80, 0xc2, 0x8d, 0x8b, 0x07, 0x81, 0xac, 0x82,\n    0xb1, 0x00, 0x11, 0x0c, 0x80, 0xab, 0x24, 0x80,\n    0x40, 0xec, 0x87, 0x60, 0x4f, 0x32, 0x80, 0x48,\n    0x56, 0x84, 0x46, 0x85, 0x10, 0x0c, 0x83, 0x43,\n    0x13, 0x83, 0xc0, 0x80, 0x41, 0x40, 0x81, 0xcc,\n    0x82, 0x41, 0x02, 0x82, 0xb4, 0x8d, 0xac, 0x81,\n    0x8a, 0x82, 0xac, 0x88, 0x88, 0x80, 0xbc, 0x82,\n    0xa3, 0x8b, 0x91, 0x81, 0xb8, 0x82, 0xaf, 0x8c,\n    0x8d, 0x81, 0xdb, 0x88, 0x08, 0x28, 0x08, 0x40,\n    0x9c, 0x89, 0x96, 0x83, 0xb9, 0x31, 0x09, 0x81,\n    0x89, 0x80, 0x89, 0x81, 0xd3, 0x88, 0x00, 0x08,\n    0x03, 0x01, 0xe6, 0x8c, 0x02, 0xe9, 0x91, 0x40,\n    0xec, 0x31, 0x86, 0x9c, 0x81, 0xd1, 0x8e, 0x00,\n    0xe9, 0x8a, 0xe6, 0x8d, 0x41, 0x00, 0x8c, 0x40,\n    0xf6, 0x28, 0x09, 0x0a, 0x00, 0x80, 0x40, 0x8d,\n    0x31, 0x2b, 0x80, 0x9b, 0x89, 0xa9, 0x20, 0x83,\n    0x91, 0x8a, 0xad, 0x8d, 0x40, 0xc7, 0x87, 0x40,\n    0xc6, 0x38, 0x86, 0xd2, 0x95, 0x80, 0x8d, 0xf9,\n    0x2a, 0x00, 0x08, 0x10, 0x02, 0x80, 0xc1, 0x20,\n    0x08, 0x83, 0x41, 0x5b, 0x83, 0x88, 0x08, 0x80,\n    0xaf, 0x32, 0x82, 0x60, 0x41, 0xdc, 0x90, 0x4e,\n    0x1f, 0x00, 0xb6, 0x33, 0xdc, 0x81, 0x60, 0x4c,\n    0xab, 0x80, 0x60, 0x23, 0x60, 0x30, 0x90, 0x0e,\n    0x01, 0x04, 0xe3, 0x80, 0x46, 0x52, 0x01, 0x06,\n    0x0c, 0x80, 0x42, 0x50, 0x80, 0x47, 0xe7, 0x99,\n    0x85, 0x99, 0x85, 0x99,\n};\n\nstatic const uint8_t unicode_prop_Other_Lowercase_table[68] = {\n    0x40, 0xa9, 0x80, 0x8e, 0x80, 0x41, 0xf4, 0x88,\n    0x31, 0x9d, 0x84, 0xdf, 0x80, 0xb3, 0x80, 0x4d,\n    0x80, 0x80, 0x4c, 0x2e, 0xbe, 0x8c, 0x80, 0xa1,\n    0xa4, 0x42, 0xb0, 0x80, 0x8c, 0x80, 0x8f, 0x8c,\n    0x40, 0xd2, 0x8f, 0x43, 0x4f, 0x99, 0x47, 0x91,\n    0x81, 0x60, 0x7a, 0x1d, 0x81, 0x40, 0xd1, 0x80,\n    0xff, 0x1a, 0x81, 0x43, 0x61, 0x83, 0x88, 0x80,\n    0x60, 0x5c, 0x15, 0x01, 0x10, 0xa9, 0x80, 0x88,\n    0x60, 0xd8, 0x74, 0xbd,\n};\n\nstatic const uint8_t unicode_prop_Other_Uppercase_table[15] = {\n    0x60, 0x21, 0x5f, 0x8f, 0x43, 0x45, 0x99, 0x61,\n    0xcc, 0x5f, 0x99, 0x85, 0x99, 0x85, 0x99,\n};\n\nstatic const uint8_t unicode_prop_Other_Grapheme_Extend_table[112] = {\n    0x49, 0xbd, 0x80, 0x97, 0x80, 0x41, 0x65, 0x80,\n    0x97, 0x80, 0xe5, 0x80, 0x97, 0x80, 0x40, 0xe7,\n    0x00, 0x03, 0x08, 0x81, 0x88, 0x81, 0xe6, 0x80,\n    0x97, 0x80, 0xf6, 0x80, 0x8e, 0x80, 0x49, 0x34,\n    0x80, 0x9d, 0x80, 0x43, 0xff, 0x04, 0x00, 0x04,\n    0x81, 0xe4, 0x80, 0xc6, 0x81, 0x44, 0x17, 0x80,\n    0x50, 0x20, 0x81, 0x60, 0x79, 0x22, 0x80, 0xeb,\n    0x80, 0x60, 0x55, 0xdc, 0x81, 0x52, 0x1f, 0x80,\n    0xf3, 0x80, 0x41, 0x07, 0x80, 0x8d, 0x80, 0x88,\n    0x80, 0xdf, 0x80, 0x88, 0x01, 0x00, 0x14, 0x80,\n    0x40, 0xdf, 0x80, 0x8b, 0x80, 0x40, 0xf0, 0x80,\n    0x41, 0x05, 0x80, 0x42, 0x78, 0x80, 0x8b, 0x80,\n    0x46, 0x02, 0x80, 0x60, 0x50, 0xad, 0x81, 0x60,\n    0x61, 0x72, 0x0d, 0x85, 0x6c, 0x2e, 0xac, 0xdf,\n};\n\nstatic const uint8_t unicode_prop_Other_Default_Ignorable_Code_Point_table[32] = {\n    0x43, 0x4e, 0x80, 0x4e, 0x0e, 0x81, 0x46, 0x52,\n    0x81, 0x48, 0xae, 0x80, 0x50, 0xfd, 0x80, 0x60,\n    0xce, 0x3a, 0x80, 0xce, 0x88, 0x6d, 0x00, 0x06,\n    0x00, 0x9d, 0xdf, 0xff, 0x40, 0xef, 0x4e, 0x0f,\n};\n\nstatic const uint8_t unicode_prop_Other_ID_Start_table[11] = {\n    0x58, 0x84, 0x81, 0x48, 0x90, 0x80, 0x94, 0x80,\n    0x4f, 0x6b, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Other_ID_Continue_table[22] = {\n    0x40, 0xb6, 0x80, 0x42, 0xce, 0x80, 0x4f, 0xe0,\n    0x88, 0x46, 0x67, 0x80, 0x46, 0x30, 0x81, 0x50,\n    0xec, 0x80, 0x60, 0xce, 0x68, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Prepended_Concatenation_Mark_table[19] = {\n    0x45, 0xff, 0x85, 0x40, 0xd6, 0x80, 0xb0, 0x80,\n    0x41, 0x7f, 0x81, 0xcf, 0x80, 0x61, 0x07, 0xd9,\n    0x80, 0x8e, 0x80,\n};\n\nstatic const uint8_t unicode_prop_XID_Start1_table[31] = {\n    0x43, 0x79, 0x80, 0x4a, 0xb7, 0x80, 0xfe, 0x80,\n    0x60, 0x21, 0xe6, 0x81, 0x60, 0xcb, 0xc0, 0x85,\n    0x41, 0x95, 0x81, 0xf3, 0x00, 0x00, 0x00, 0x00,\n    0x00, 0x00, 0x00, 0x80, 0x41, 0x1e, 0x81,\n};\n\nstatic const uint8_t unicode_prop_XID_Continue1_table[23] = {\n    0x43, 0x79, 0x80, 0x60, 0x2d, 0x1f, 0x81, 0x60,\n    0xcb, 0xc0, 0x85, 0x41, 0x95, 0x81, 0xf3, 0x00,\n    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Changes_When_Titlecased1_table[22] = {\n    0x41, 0xc3, 0x08, 0x08, 0x81, 0xa4, 0x81, 0x4e,\n    0xdc, 0xaa, 0x0a, 0x4e, 0x87, 0x3f, 0x3f, 0x87,\n    0x8b, 0x80, 0x8e, 0x80, 0xae, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Changes_When_Casefolded1_table[29] = {\n    0x41, 0xef, 0x80, 0x41, 0x9e, 0x80, 0x9e, 0x80,\n    0x5a, 0xe4, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00,\n    0x80, 0xde, 0x06, 0x06, 0x80, 0x8a, 0x09, 0x81,\n    0x89, 0x10, 0x81, 0x8d, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Changes_When_NFKC_Casefolded1_table[449] = {\n    0x40, 0x9f, 0x06, 0x00, 0x01, 0x00, 0x01, 0x12,\n    0x10, 0x82, 0xf3, 0x80, 0x8b, 0x80, 0x40, 0x84,\n    0x01, 0x01, 0x80, 0xa2, 0x01, 0x80, 0x40, 0xbb,\n    0x88, 0x9e, 0x29, 0x84, 0xda, 0x08, 0x81, 0x89,\n    0x80, 0xa3, 0x04, 0x02, 0x04, 0x08, 0x07, 0x80,\n    0x9e, 0x80, 0xa0, 0x82, 0x9c, 0x80, 0x42, 0x28,\n    0x80, 0xd7, 0x83, 0x42, 0xde, 0x87, 0xfb, 0x08,\n    0x80, 0xd2, 0x01, 0x80, 0xa1, 0x11, 0x80, 0x40,\n    0xfc, 0x81, 0x42, 0xd4, 0x80, 0xfe, 0x80, 0xa7,\n    0x81, 0xad, 0x80, 0xb5, 0x80, 0x88, 0x03, 0x03,\n    0x03, 0x80, 0x8b, 0x80, 0x88, 0x00, 0x26, 0x80,\n    0x90, 0x80, 0x88, 0x03, 0x03, 0x03, 0x80, 0x8b,\n    0x80, 0x41, 0x41, 0x80, 0xe1, 0x81, 0x46, 0x52,\n    0x81, 0xd4, 0x84, 0x45, 0x1b, 0x10, 0x8a, 0x80,\n    0x91, 0x80, 0x9b, 0x8c, 0x80, 0xa1, 0xa4, 0x40,\n    0xd5, 0x83, 0x40, 0xb5, 0x00, 0x00, 0x00, 0x80,\n    0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,\n    0xb7, 0x05, 0x00, 0x13, 0x05, 0x11, 0x02, 0x0c,\n    0x11, 0x00, 0x00, 0x0c, 0x15, 0x05, 0x08, 0x8f,\n    0x00, 0x20, 0x8b, 0x12, 0x2a, 0x08, 0x0b, 0x00,\n    0x07, 0x82, 0x8c, 0x06, 0x92, 0x81, 0x9a, 0x80,\n    0x8c, 0x8a, 0x80, 0xd6, 0x18, 0x10, 0x8a, 0x01,\n    0x0c, 0x0a, 0x00, 0x10, 0x11, 0x02, 0x06, 0x05,\n    0x1c, 0x85, 0x8f, 0x8f, 0x8f, 0x88, 0x80, 0x40,\n    0xa1, 0x08, 0x81, 0x40, 0xf7, 0x81, 0x41, 0x34,\n    0xd5, 0x99, 0x9a, 0x45, 0x20, 0x80, 0xe6, 0x82,\n    0xe4, 0x80, 0x41, 0x9e, 0x81, 0x40, 0xf0, 0x80,\n    0x41, 0x2e, 0x80, 0xd2, 0x80, 0x8b, 0x40, 0xd5,\n    0xa9, 0x80, 0xb4, 0x00, 0x82, 0xdf, 0x09, 0x80,\n    0xde, 0x80, 0xb0, 0xdd, 0x82, 0x8d, 0xdf, 0x9e,\n    0x80, 0xa7, 0x87, 0xae, 0x80, 0x41, 0x7f, 0x60,\n    0x72, 0x9b, 0x81, 0x40, 0xd1, 0x80, 0xff, 0x1a,\n    0x81, 0x43, 0x61, 0x83, 0x88, 0x80, 0x60, 0x4d,\n    0x95, 0x41, 0x0d, 0x08, 0x00, 0x81, 0x89, 0x00,\n    0x00, 0x09, 0x82, 0xc3, 0x81, 0xe9, 0xc2, 0x00,\n    0x97, 0x04, 0x00, 0x01, 0x01, 0x80, 0xeb, 0xa0,\n    0x41, 0x6a, 0x91, 0xbf, 0x81, 0xb5, 0xa7, 0x8c,\n    0x82, 0x99, 0x95, 0x94, 0x81, 0x8b, 0x80, 0x92,\n    0x03, 0x1a, 0x00, 0x80, 0x40, 0x86, 0x08, 0x80,\n    0x9f, 0x99, 0x40, 0x83, 0x15, 0x0d, 0x0d, 0x0a,\n    0x16, 0x06, 0x80, 0x88, 0x47, 0x87, 0x20, 0xa9,\n    0x80, 0x88, 0x60, 0xb4, 0xe4, 0x83, 0x50, 0x31,\n    0xa3, 0x44, 0x63, 0x86, 0x8d, 0x87, 0xbf, 0x85,\n    0x42, 0x3e, 0xd4, 0x80, 0xc6, 0x01, 0x08, 0x09,\n    0x0b, 0x80, 0x8b, 0x00, 0x06, 0x80, 0xc0, 0x03,\n    0x0f, 0x06, 0x80, 0x9b, 0x03, 0x04, 0x00, 0x16,\n    0x80, 0x41, 0x53, 0x81, 0x41, 0x23, 0x81, 0xb1,\n    0x48, 0x2f, 0xbd, 0x4d, 0x91, 0x18, 0x9a, 0x01,\n    0x00, 0x08, 0x80, 0x89, 0x03, 0x00, 0x00, 0x28,\n    0x18, 0x00, 0x00, 0x02, 0x01, 0x00, 0x08, 0x00,\n    0x00, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x06, 0x03,\n    0x03, 0x00, 0x80, 0x89, 0x80, 0x90, 0x22, 0x04,\n    0x80, 0x90, 0x42, 0x43, 0x8a, 0x84, 0x9e, 0x80,\n    0x9f, 0x99, 0x82, 0xa2, 0x80, 0xee, 0x82, 0x8c,\n    0xab, 0x83, 0x88, 0x31, 0x49, 0x9d, 0x89, 0x60,\n    0xfc, 0x05, 0x42, 0x1d, 0x6b, 0x05, 0xe1, 0x4f,\n    0xff,\n};\n\nstatic const uint8_t unicode_prop_Basic_Emoji1_table[144] = {\n    0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01,\n    0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b,\n    0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90,\n    0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03,\n    0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00,\n    0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d,\n    0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61,\n    0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd,\n    0x01, 0x89, 0xe5, 0x80, 0x97, 0x80, 0x93, 0x01,\n    0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0, 0x8b,\n    0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa, 0x1c,\n    0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80, 0x40,\n    0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91, 0x80,\n    0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf, 0xc5,\n    0x28, 0x12, 0x0b, 0x13, 0x8a, 0x0e, 0x88, 0x40,\n    0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89,\n    0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x8a, 0x82,\n    0xb8, 0x00, 0x83, 0x8f, 0x81, 0x8b, 0x83, 0x89,\n};\n\nstatic const uint8_t unicode_prop_Basic_Emoji2_table[183] = {\n    0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b,\n    0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85,\n    0x8e, 0x81, 0x41, 0x7c, 0x80, 0x40, 0xa5, 0x80,\n    0x9c, 0x10, 0x0c, 0x82, 0x40, 0xc6, 0x80, 0x40,\n    0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, 0xb9, 0x0a,\n    0x84, 0x88, 0x01, 0x05, 0x03, 0x01, 0x00, 0x09,\n    0x02, 0x02, 0x0f, 0x14, 0x00, 0x80, 0x9b, 0x09,\n    0x00, 0x08, 0x80, 0x91, 0x01, 0x80, 0x92, 0x00,\n    0x18, 0x00, 0x0a, 0x05, 0x07, 0x81, 0x95, 0x05,\n    0x00, 0x00, 0x80, 0x94, 0x05, 0x09, 0x01, 0x17,\n    0x04, 0x09, 0x08, 0x01, 0x00, 0x00, 0x05, 0x02,\n    0x80, 0x90, 0x81, 0x8e, 0x01, 0x80, 0x9a, 0x81,\n    0xbb, 0x80, 0x41, 0x91, 0x81, 0x41, 0xce, 0x82,\n    0x45, 0x27, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00,\n    0x80, 0x61, 0xbe, 0xd5, 0x81, 0x8b, 0x81, 0x40,\n    0x81, 0x80, 0xb3, 0x80, 0x40, 0xe8, 0x01, 0x88,\n    0x88, 0x80, 0xc5, 0x80, 0x97, 0x08, 0x11, 0x81,\n    0xaa, 0x1c, 0x8b, 0x92, 0x00, 0x00, 0x80, 0xc6,\n    0x00, 0x80, 0x40, 0xba, 0x80, 0xca, 0x81, 0xa3,\n    0x09, 0x86, 0x8c, 0x01, 0x19, 0x80, 0x93, 0x01,\n    0x07, 0x81, 0x88, 0x04, 0x82, 0x8b, 0x17, 0x11,\n    0x00, 0x03, 0x05, 0x02, 0x05, 0x80, 0x40, 0xcf,\n    0x00, 0x82, 0x8f, 0x2a, 0x05, 0x01, 0x80,\n};\n\nstatic const uint8_t unicode_prop_RGI_Emoji_Modifier_Sequence_table[72] = {\n    0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f,\n    0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01,\n    0x82, 0xf4, 0x09, 0x8a, 0x94, 0x18, 0x8d, 0x10,\n    0x1a, 0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8,\n    0x0b, 0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12,\n    0x84, 0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a,\n    0x80, 0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88,\n    0x89, 0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80,\n    0x90, 0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88,\n};\n\nstatic const uint8_t unicode_prop_RGI_Emoji_Flag_Sequence_table[128] = {\n    0x0c, 0x00, 0x09, 0x00, 0x04, 0x01, 0x02, 0x06,\n    0x03, 0x03, 0x01, 0x02, 0x01, 0x03, 0x07, 0x0d,\n    0x18, 0x00, 0x09, 0x00, 0x00, 0x89, 0x08, 0x00,\n    0x00, 0x81, 0x88, 0x83, 0x8c, 0x10, 0x00, 0x01,\n    0x07, 0x08, 0x29, 0x10, 0x28, 0x00, 0x80, 0x8a,\n    0x00, 0x0a, 0x00, 0x0e, 0x15, 0x18, 0x83, 0x89,\n    0x06, 0x00, 0x81, 0x8d, 0x00, 0x12, 0x08, 0x00,\n    0x03, 0x00, 0x24, 0x00, 0x05, 0x21, 0x00, 0x00,\n    0x29, 0x90, 0x00, 0x02, 0x00, 0x08, 0x09, 0x00,\n    0x08, 0x18, 0x8b, 0x80, 0x8c, 0x02, 0x19, 0x1a,\n    0x11, 0x00, 0x00, 0x80, 0x9c, 0x80, 0x88, 0x02,\n    0x00, 0x00, 0x02, 0x20, 0x88, 0x0a, 0x00, 0x03,\n    0x01, 0x02, 0x05, 0x08, 0x00, 0x01, 0x09, 0x20,\n    0x21, 0x18, 0x22, 0x00, 0x00, 0x00, 0x00, 0x18,\n    0x28, 0x89, 0x80, 0x8b, 0x80, 0x90, 0x80, 0x92,\n    0x80, 0x8d, 0x05, 0x80, 0x8a, 0x80, 0x88, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Emoji_Keycap_Sequence_table[4] = {\n    0xa2, 0x05, 0x04, 0x89,\n};\n\nstatic const uint8_t unicode_prop_ASCII_Hex_Digit_table[5] = {\n    0xaf, 0x89, 0x35, 0x99, 0x85,\n};\n\nstatic const uint8_t unicode_prop_Bidi_Control_table[10] = {\n    0x46, 0x1b, 0x80, 0x59, 0xf0, 0x81, 0x99, 0x84,\n    0xb6, 0x83,\n};\n\nstatic const uint8_t unicode_prop_Dash_table[58] = {\n    0xac, 0x80, 0x45, 0x5b, 0x80, 0xb2, 0x80, 0x4e,\n    0x40, 0x80, 0x44, 0x04, 0x80, 0x48, 0x08, 0x85,\n    0xbc, 0x80, 0xa6, 0x80, 0x8e, 0x80, 0x41, 0x85,\n    0x80, 0x4c, 0x03, 0x01, 0x80, 0x9e, 0x0b, 0x80,\n    0x9b, 0x80, 0x41, 0xbd, 0x80, 0x92, 0x80, 0xee,\n    0x80, 0x60, 0xcd, 0x8f, 0x81, 0xa4, 0x80, 0x89,\n    0x80, 0x40, 0xa8, 0x80, 0x4e, 0x5f, 0x80, 0x41,\n    0x3d, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Deprecated_table[23] = {\n    0x41, 0x48, 0x80, 0x45, 0x28, 0x80, 0x49, 0x02,\n    0x00, 0x80, 0x48, 0x28, 0x81, 0x48, 0xc4, 0x85,\n    0x42, 0xb8, 0x81, 0x6d, 0xdc, 0xd5, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Diacritic_table[447] = {\n    0xdd, 0x00, 0x80, 0xc6, 0x05, 0x03, 0x01, 0x81,\n    0x41, 0xf6, 0x40, 0x9e, 0x07, 0x25, 0x90, 0x0b,\n    0x80, 0x88, 0x81, 0x40, 0xfc, 0x84, 0x40, 0xd0,\n    0x80, 0xb6, 0xac, 0x00, 0x01, 0x01, 0x00, 0x40,\n    0x82, 0x3b, 0x81, 0x40, 0x85, 0x0b, 0x0a, 0x82,\n    0xc2, 0x9a, 0xda, 0x8a, 0xb9, 0x8a, 0xa1, 0x81,\n    0xfd, 0x87, 0xa8, 0x89, 0x8f, 0x9b, 0xbc, 0x80,\n    0x8f, 0x02, 0x83, 0x9b, 0x80, 0xc9, 0x80, 0x8f,\n    0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80, 0x8f,\n    0x80, 0xae, 0x82, 0xbb, 0x80, 0x8f, 0x06, 0x80,\n    0xf6, 0x80, 0xed, 0x80, 0x8f, 0x80, 0xed, 0x80,\n    0x8f, 0x80, 0xec, 0x81, 0x8f, 0x80, 0xfb, 0x80,\n    0xee, 0x80, 0x8b, 0x28, 0x80, 0xea, 0x80, 0x8c,\n    0x84, 0xca, 0x81, 0x9a, 0x00, 0x00, 0x03, 0x81,\n    0xc1, 0x10, 0x81, 0xbd, 0x80, 0xef, 0x00, 0x81,\n    0xa7, 0x0b, 0x84, 0x98, 0x30, 0x80, 0x89, 0x81,\n    0x42, 0xc0, 0x82, 0x43, 0xb3, 0x81, 0x9d, 0x80,\n    0x40, 0x93, 0x8a, 0x88, 0x80, 0x41, 0x5a, 0x82,\n    0x41, 0x23, 0x80, 0x93, 0x39, 0x80, 0xaf, 0x8e,\n    0x81, 0x8a, 0x82, 0x8e, 0x81, 0x8b, 0xc7, 0x80,\n    0x8e, 0x80, 0xa5, 0x88, 0xb5, 0x81, 0xb9, 0x80,\n    0x8a, 0x81, 0xc1, 0x81, 0xbf, 0x85, 0xd1, 0x98,\n    0x18, 0x28, 0x0a, 0xb1, 0xbe, 0xaf, 0xa3, 0x84,\n    0x8b, 0xa4, 0x8a, 0x41, 0xbc, 0x00, 0x82, 0x8a,\n    0x82, 0x8c, 0x82, 0x8c, 0x82, 0x8c, 0x81, 0x4c,\n    0xef, 0x82, 0x41, 0x3c, 0x80, 0x41, 0xf9, 0x85,\n    0xe8, 0x83, 0xde, 0x80, 0x60, 0x75, 0x71, 0x80,\n    0x8b, 0x08, 0x80, 0x9b, 0x81, 0xd1, 0x81, 0x8d,\n    0xa1, 0xe5, 0x82, 0xe5, 0x05, 0x81, 0x8b, 0x80,\n    0xa4, 0x80, 0x40, 0x96, 0x80, 0x9a, 0x91, 0xb8,\n    0x83, 0xa3, 0x80, 0xde, 0x80, 0x8b, 0x80, 0xa3,\n    0x80, 0x40, 0x94, 0x82, 0xc0, 0x83, 0xb2, 0x80,\n    0xe3, 0x84, 0x88, 0x82, 0xff, 0x81, 0x60, 0x4f,\n    0x2f, 0x80, 0x43, 0x00, 0x8f, 0x41, 0x0d, 0x00,\n    0x80, 0xae, 0x80, 0xac, 0x81, 0xc2, 0x80, 0x42,\n    0xfb, 0x80, 0x44, 0x9e, 0x28, 0xa9, 0x80, 0x88,\n    0x42, 0x7c, 0x13, 0x80, 0x40, 0xa4, 0x81, 0x42,\n    0x3a, 0x85, 0xa5, 0x80, 0x99, 0x84, 0x41, 0x8b,\n    0x01, 0x82, 0xc5, 0x8a, 0xb0, 0x83, 0x40, 0xbf,\n    0x80, 0xa8, 0x80, 0xc7, 0x81, 0xf7, 0x81, 0xbd,\n    0x80, 0xcb, 0x80, 0x88, 0x82, 0xe7, 0x81, 0x40,\n    0xb1, 0x81, 0xcf, 0x81, 0x8f, 0x80, 0x97, 0x32,\n    0x84, 0xd8, 0x10, 0x81, 0x8c, 0x81, 0xde, 0x02,\n    0x80, 0xfa, 0x81, 0x40, 0xfa, 0x81, 0xfd, 0x80,\n    0xf5, 0x81, 0xf2, 0x80, 0x41, 0x0c, 0x81, 0x41,\n    0x01, 0x0b, 0x80, 0x40, 0x9b, 0x80, 0xd2, 0x80,\n    0x91, 0x80, 0xd0, 0x80, 0x41, 0xa4, 0x80, 0x41,\n    0x01, 0x00, 0x81, 0xd0, 0x80, 0xc0, 0x80, 0x41,\n    0x66, 0x81, 0x96, 0x80, 0x54, 0xeb, 0x8e, 0x60,\n    0x2c, 0xd8, 0x80, 0x49, 0xbf, 0x84, 0xba, 0x86,\n    0x42, 0x33, 0x81, 0x42, 0x21, 0x90, 0xcf, 0x81,\n    0x60, 0x3f, 0xfd, 0x18, 0x30, 0x81, 0x5f, 0x00,\n    0xad, 0x81, 0x96, 0x42, 0x1f, 0x12, 0x2f, 0x39,\n    0x86, 0x9d, 0x83, 0x4e, 0x81, 0xbd, 0x40, 0xc1,\n    0x86, 0x41, 0x76, 0x80, 0xbc, 0x83, 0x42, 0xfd,\n    0x81, 0x42, 0xdf, 0x86, 0xec, 0x10, 0x82,\n};\n\nstatic const uint8_t unicode_prop_Extender_table[116] = {\n    0x40, 0xb6, 0x80, 0x42, 0x17, 0x81, 0x43, 0x6d,\n    0x80, 0x41, 0xb8, 0x80, 0x42, 0x75, 0x80, 0x40,\n    0x88, 0x80, 0xd8, 0x80, 0x42, 0xef, 0x80, 0xfe,\n    0x80, 0x49, 0x42, 0x80, 0xb7, 0x80, 0x42, 0x62,\n    0x80, 0x41, 0x8d, 0x80, 0xc3, 0x80, 0x53, 0x88,\n    0x80, 0xaa, 0x84, 0xe6, 0x81, 0xdc, 0x82, 0x60,\n    0x6f, 0x15, 0x80, 0x45, 0xf5, 0x80, 0x43, 0xc1,\n    0x80, 0x95, 0x80, 0x40, 0x88, 0x80, 0xeb, 0x80,\n    0x94, 0x81, 0x60, 0x54, 0x7a, 0x80, 0x48, 0x0f,\n    0x81, 0x45, 0xca, 0x80, 0x9a, 0x03, 0x80, 0x44,\n    0xc6, 0x80, 0x41, 0x24, 0x80, 0xf3, 0x81, 0x41,\n    0xf1, 0x82, 0x44, 0xce, 0x80, 0x43, 0x3f, 0x80,\n    0x60, 0x4d, 0x67, 0x81, 0x44, 0x9b, 0x08, 0x80,\n    0x8d, 0x81, 0x60, 0x71, 0x47, 0x81, 0x44, 0xb0,\n    0x80, 0x43, 0x53, 0x82,\n};\n\nstatic const uint8_t unicode_prop_Hex_Digit_table[12] = {\n    0xaf, 0x89, 0x35, 0x99, 0x85, 0x60, 0xfe, 0xa8,\n    0x89, 0x35, 0x99, 0x85,\n};\n\nstatic const uint8_t unicode_prop_IDS_Unary_Operator_table[4] = {\n    0x60, 0x2f, 0xfd, 0x81,\n};\n\nstatic const uint8_t unicode_prop_IDS_Binary_Operator_table[8] = {\n    0x60, 0x2f, 0xef, 0x09, 0x89, 0x41, 0xf0, 0x80,\n};\n\nstatic const uint8_t unicode_prop_IDS_Trinary_Operator_table[4] = {\n    0x60, 0x2f, 0xf1, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Ideographic_table[71] = {\n    0x60, 0x30, 0x05, 0x81, 0x98, 0x88, 0x8d, 0x82,\n    0x43, 0xc4, 0x59, 0xbf, 0xbf, 0x60, 0x51, 0xff,\n    0x60, 0x58, 0xff, 0x41, 0x6d, 0x81, 0xe9, 0x60,\n    0x75, 0x09, 0x80, 0x8c, 0x84, 0x88, 0x5c, 0xd5,\n    0xa8, 0x9f, 0xe0, 0xf2, 0x60, 0x23, 0x7c, 0x41,\n    0x8b, 0x60, 0x4d, 0x03, 0x60, 0xa6, 0xdf, 0x9f,\n    0x51, 0x1d, 0x81, 0x56, 0x8d, 0x81, 0x5d, 0x30,\n    0x8e, 0x42, 0x6d, 0x49, 0xa1, 0x42, 0x1d, 0x45,\n    0xe1, 0x53, 0x4a, 0x84, 0x60, 0x21, 0x29,\n};\n\nstatic const uint8_t unicode_prop_Join_Control_table[4] = {\n    0x60, 0x20, 0x0b, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Logical_Order_Exception_table[15] = {\n    0x4e, 0x3f, 0x84, 0xfa, 0x84, 0x4a, 0xef, 0x11,\n    0x80, 0x60, 0x90, 0xf9, 0x09, 0x00, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Modifier_Combining_Mark_table[16] = {\n    0x46, 0x53, 0x09, 0x80, 0x40, 0x82, 0x05, 0x02,\n    0x81, 0x41, 0xe0, 0x08, 0x12, 0x80, 0x9e, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Noncharacter_Code_Point_table[71] = {\n    0x60, 0xfd, 0xcf, 0x9f, 0x42, 0x0d, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81, 0x60,\n    0xff, 0xfd, 0x81, 0x60, 0xff, 0xfd, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Pattern_Syntax_table[58] = {\n    0xa0, 0x8e, 0x89, 0x86, 0x99, 0x18, 0x80, 0x99,\n    0x83, 0xa1, 0x30, 0x00, 0x08, 0x00, 0x0b, 0x03,\n    0x02, 0x80, 0x96, 0x80, 0x9e, 0x80, 0x5f, 0x17,\n    0x97, 0x87, 0x8e, 0x81, 0x92, 0x80, 0x89, 0x41,\n    0x30, 0x42, 0xcf, 0x40, 0x9f, 0x42, 0x75, 0x9d,\n    0x44, 0x6b, 0x41, 0xff, 0xff, 0x41, 0x80, 0x13,\n    0x98, 0x8e, 0x80, 0x60, 0xcd, 0x0c, 0x81, 0x41,\n    0x04, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Pattern_White_Space_table[11] = {\n    0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x5f, 0x87,\n    0x81, 0x97, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Quotation_Mark_table[31] = {\n    0xa1, 0x03, 0x80, 0x40, 0x82, 0x80, 0x8e, 0x80,\n    0x5f, 0x5b, 0x87, 0x98, 0x81, 0x4e, 0x06, 0x80,\n    0x41, 0xc8, 0x83, 0x8c, 0x82, 0x60, 0xce, 0x20,\n    0x83, 0x40, 0xbc, 0x03, 0x80, 0xd9, 0x81,\n};\n\nstatic const uint8_t unicode_prop_Radical_table[9] = {\n    0x60, 0x2e, 0x7f, 0x99, 0x80, 0xd8, 0x8b, 0x40,\n    0xd5,\n};\n\nstatic const uint8_t unicode_prop_Regional_Indicator_table[4] = {\n    0x61, 0xf1, 0xe5, 0x99,\n};\n\nstatic const uint8_t unicode_prop_Sentence_Terminal_table[213] = {\n    0xa0, 0x80, 0x8b, 0x80, 0x8f, 0x80, 0x45, 0x48,\n    0x80, 0x40, 0x92, 0x82, 0x40, 0xb3, 0x80, 0xaa,\n    0x82, 0x40, 0xf5, 0x80, 0xbc, 0x00, 0x02, 0x81,\n    0x41, 0x24, 0x81, 0x46, 0xe3, 0x81, 0x43, 0x15,\n    0x03, 0x81, 0x43, 0x04, 0x80, 0x40, 0xc5, 0x81,\n    0x40, 0x9c, 0x81, 0xac, 0x04, 0x80, 0x41, 0x39,\n    0x81, 0x41, 0x61, 0x83, 0x40, 0xa1, 0x81, 0x89,\n    0x09, 0x81, 0x9c, 0x82, 0x40, 0xba, 0x81, 0xc0,\n    0x81, 0x43, 0xa3, 0x80, 0x96, 0x81, 0x88, 0x82,\n    0x4c, 0xae, 0x82, 0x41, 0x31, 0x80, 0x8c, 0x80,\n    0x95, 0x81, 0x41, 0xac, 0x80, 0x60, 0x74, 0xfb,\n    0x80, 0x41, 0x0d, 0x81, 0x40, 0xe2, 0x02, 0x80,\n    0x41, 0x7d, 0x81, 0xd5, 0x81, 0xde, 0x80, 0x40,\n    0x97, 0x81, 0x40, 0x92, 0x82, 0x40, 0x8f, 0x81,\n    0x40, 0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81,\n    0xba, 0x02, 0x81, 0x40, 0xa8, 0x80, 0x8b, 0x80,\n    0x8f, 0x80, 0xc0, 0x80, 0x4a, 0xf3, 0x81, 0x44,\n    0xfc, 0x84, 0xab, 0x83, 0x40, 0xbc, 0x81, 0xf4,\n    0x83, 0xfe, 0x82, 0x40, 0x80, 0x0d, 0x80, 0x8f,\n    0x81, 0xd7, 0x08, 0x81, 0xeb, 0x80, 0x41, 0x29,\n    0x81, 0xf4, 0x81, 0x41, 0x74, 0x0c, 0x8e, 0xe8,\n    0x81, 0x40, 0xf8, 0x82, 0x42, 0x04, 0x00, 0x80,\n    0x40, 0xfa, 0x81, 0xd6, 0x81, 0x41, 0xa3, 0x81,\n    0x42, 0xb3, 0x81, 0xc9, 0x81, 0x60, 0x4b, 0x28,\n    0x81, 0x40, 0x84, 0x80, 0xc0, 0x81, 0x8a, 0x80,\n    0x42, 0x28, 0x81, 0x41, 0x27, 0x80, 0x60, 0x4e,\n    0x05, 0x80, 0x5d, 0xe7, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Soft_Dotted_table[79] = {\n    0xe8, 0x81, 0x40, 0xc3, 0x80, 0x41, 0x18, 0x80,\n    0x9d, 0x80, 0xb3, 0x80, 0x93, 0x80, 0x41, 0x3f,\n    0x80, 0xe1, 0x00, 0x80, 0x59, 0x08, 0x80, 0xb2,\n    0x80, 0x8c, 0x02, 0x80, 0x40, 0x83, 0x80, 0x40,\n    0x9c, 0x80, 0x41, 0xa4, 0x80, 0x40, 0xd5, 0x81,\n    0x4b, 0x31, 0x80, 0x61, 0xa7, 0xa4, 0x81, 0xb1,\n    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,\n    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1,\n    0x81, 0xb1, 0x81, 0xb1, 0x81, 0xb1, 0x81, 0x48,\n    0x85, 0x80, 0x41, 0x30, 0x81, 0x99, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Terminal_Punctuation_table[264] = {\n    0xa0, 0x80, 0x89, 0x00, 0x80, 0x8a, 0x0a, 0x80,\n    0x43, 0x3d, 0x07, 0x80, 0x42, 0x00, 0x80, 0xb8,\n    0x80, 0xc7, 0x80, 0x8d, 0x00, 0x82, 0x40, 0xb3,\n    0x80, 0xaa, 0x8a, 0x00, 0x40, 0xea, 0x81, 0xb5,\n    0x28, 0x87, 0x9e, 0x80, 0x41, 0x04, 0x81, 0x44,\n    0xf3, 0x81, 0x40, 0xab, 0x03, 0x85, 0x41, 0x36,\n    0x81, 0x43, 0x14, 0x87, 0x43, 0x04, 0x80, 0xfb,\n    0x82, 0xc6, 0x81, 0x40, 0x9c, 0x12, 0x80, 0xa6,\n    0x19, 0x81, 0x41, 0x39, 0x81, 0x41, 0x61, 0x83,\n    0x40, 0xa1, 0x81, 0x89, 0x08, 0x82, 0x9c, 0x82,\n    0x40, 0xba, 0x84, 0xbd, 0x81, 0x43, 0xa3, 0x80,\n    0x96, 0x81, 0x88, 0x82, 0x4c, 0xae, 0x82, 0x41,\n    0x31, 0x80, 0x8c, 0x03, 0x80, 0x89, 0x00, 0x0a,\n    0x81, 0x41, 0xab, 0x81, 0x60, 0x74, 0xfa, 0x81,\n    0x41, 0x0c, 0x82, 0x40, 0xe2, 0x84, 0x41, 0x7d,\n    0x81, 0xd5, 0x81, 0xde, 0x80, 0x40, 0x96, 0x82,\n    0x40, 0x92, 0x82, 0xfe, 0x80, 0x8f, 0x81, 0x40,\n    0xf8, 0x80, 0x60, 0x52, 0x25, 0x01, 0x81, 0xb8,\n    0x10, 0x83, 0x40, 0xa8, 0x80, 0x89, 0x00, 0x80,\n    0x8a, 0x0a, 0x80, 0xc0, 0x01, 0x80, 0x44, 0x39,\n    0x80, 0xaf, 0x80, 0x44, 0x85, 0x80, 0x40, 0xc6,\n    0x80, 0x41, 0x35, 0x81, 0x40, 0x97, 0x85, 0xc3,\n    0x85, 0xd8, 0x83, 0x43, 0xb7, 0x84, 0xab, 0x83,\n    0x40, 0xbc, 0x86, 0xef, 0x83, 0xfe, 0x82, 0x40,\n    0x80, 0x0d, 0x80, 0x8f, 0x81, 0xd7, 0x84, 0xeb,\n    0x80, 0x41, 0x29, 0x81, 0xf4, 0x82, 0x8b, 0x81,\n    0x41, 0x65, 0x1a, 0x8e, 0xe8, 0x81, 0x40, 0xf8,\n    0x82, 0x42, 0x04, 0x00, 0x80, 0x40, 0xfa, 0x81,\n    0xd6, 0x0b, 0x81, 0x41, 0x9d, 0x82, 0xac, 0x80,\n    0x42, 0x84, 0x81, 0xc9, 0x81, 0x45, 0x2a, 0x84,\n    0x60, 0x45, 0xf8, 0x81, 0x40, 0x84, 0x80, 0xc0,\n    0x82, 0x89, 0x80, 0x42, 0x28, 0x81, 0x41, 0x26,\n    0x81, 0x60, 0x4e, 0x05, 0x80, 0x5d, 0xe6, 0x83,\n};\n\nstatic const uint8_t unicode_prop_Unified_Ideograph_table[46] = {\n    0x60, 0x33, 0xff, 0x59, 0xbf, 0xbf, 0x60, 0x51,\n    0xff, 0x60, 0x5a, 0x0d, 0x08, 0x00, 0x81, 0x89,\n    0x00, 0x00, 0x09, 0x82, 0x61, 0x05, 0xd5, 0x60,\n    0xa6, 0xdf, 0x9f, 0x51, 0x1d, 0x81, 0x56, 0x8d,\n    0x81, 0x5d, 0x30, 0x8e, 0x42, 0x6d, 0x51, 0xa1,\n    0x53, 0x4a, 0x84, 0x60, 0x21, 0x29,\n};\n\nstatic const uint8_t unicode_prop_Variation_Selector_table[13] = {\n    0x58, 0x0a, 0x10, 0x80, 0x60, 0xe5, 0xef, 0x8f,\n    0x6d, 0x02, 0xef, 0x40, 0xef,\n};\n\nstatic const uint8_t unicode_prop_White_Space_table[22] = {\n    0x88, 0x84, 0x91, 0x80, 0xe3, 0x80, 0x99, 0x80,\n    0x55, 0xde, 0x80, 0x49, 0x7e, 0x8a, 0x9c, 0x0c,\n    0x80, 0xae, 0x80, 0x4f, 0x9f, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Bidi_Mirrored_table[173] = {\n    0xa7, 0x81, 0x91, 0x00, 0x80, 0x9b, 0x00, 0x80,\n    0x9c, 0x00, 0x80, 0xac, 0x80, 0x8e, 0x80, 0x4e,\n    0x7d, 0x83, 0x47, 0x5c, 0x81, 0x49, 0x9b, 0x81,\n    0x89, 0x81, 0xb5, 0x81, 0x8d, 0x81, 0x40, 0xb0,\n    0x80, 0x40, 0xbf, 0x1a, 0x2a, 0x02, 0x0a, 0x18,\n    0x18, 0x00, 0x03, 0x88, 0x20, 0x80, 0x91, 0x23,\n    0x88, 0x08, 0x00, 0x38, 0x9f, 0x0b, 0x20, 0x88,\n    0x09, 0x92, 0x21, 0x88, 0x21, 0x0b, 0x97, 0x81,\n    0x8f, 0x3b, 0x93, 0x0e, 0x81, 0x44, 0x3c, 0x8d,\n    0xc9, 0x01, 0x18, 0x08, 0x14, 0x1c, 0x12, 0x8d,\n    0x41, 0x92, 0x95, 0x0d, 0x80, 0x8d, 0x38, 0x35,\n    0x10, 0x1c, 0x01, 0x0c, 0x18, 0x02, 0x09, 0x89,\n    0x29, 0x81, 0x8b, 0x92, 0x03, 0x08, 0x00, 0x08,\n    0x03, 0x21, 0x2a, 0x97, 0x81, 0x8a, 0x0b, 0x18,\n    0x09, 0x0b, 0xaa, 0x0f, 0x80, 0xa7, 0x20, 0x00,\n    0x14, 0x22, 0x18, 0x14, 0x00, 0x40, 0xff, 0x80,\n    0x42, 0x02, 0x1a, 0x08, 0x81, 0x8d, 0x09, 0x89,\n    0xaa, 0x87, 0x41, 0xaa, 0x89, 0x0f, 0x60, 0xce,\n    0x3c, 0x2c, 0x81, 0x40, 0xa1, 0x81, 0x91, 0x00,\n    0x80, 0x9b, 0x00, 0x80, 0x9c, 0x00, 0x00, 0x08,\n    0x81, 0x60, 0xd7, 0x76, 0x80, 0xb8, 0x80, 0xb8,\n    0x80, 0xb8, 0x80, 0xb8, 0x80,\n};\n\nstatic const uint8_t unicode_prop_Emoji_table[239] = {\n    0xa2, 0x05, 0x04, 0x89, 0xee, 0x03, 0x80, 0x5f,\n    0x8c, 0x80, 0x8b, 0x80, 0x40, 0xd7, 0x80, 0x95,\n    0x80, 0xd9, 0x85, 0x8e, 0x81, 0x41, 0x6e, 0x81,\n    0x8b, 0x80, 0x40, 0xa5, 0x80, 0x98, 0x8a, 0x1a,\n    0x40, 0xc6, 0x80, 0x40, 0xe6, 0x81, 0x89, 0x80,\n    0x88, 0x80, 0xb9, 0x18, 0x84, 0x88, 0x01, 0x01,\n    0x09, 0x03, 0x01, 0x00, 0x09, 0x02, 0x02, 0x0f,\n    0x14, 0x00, 0x04, 0x8b, 0x8a, 0x09, 0x00, 0x08,\n    0x80, 0x91, 0x01, 0x81, 0x91, 0x28, 0x00, 0x0a,\n    0x0c, 0x01, 0x0b, 0x81, 0x8a, 0x0c, 0x09, 0x04,\n    0x08, 0x00, 0x81, 0x93, 0x0c, 0x28, 0x19, 0x03,\n    0x01, 0x01, 0x28, 0x01, 0x00, 0x00, 0x05, 0x02,\n    0x05, 0x80, 0x89, 0x81, 0x8e, 0x01, 0x03, 0x00,\n    0x03, 0x10, 0x80, 0x8a, 0x81, 0xaf, 0x82, 0x88,\n    0x80, 0x8d, 0x80, 0x8d, 0x80, 0x41, 0x73, 0x81,\n    0x41, 0xce, 0x82, 0x92, 0x81, 0xb2, 0x03, 0x80,\n    0x44, 0xd9, 0x80, 0x8b, 0x80, 0x42, 0x58, 0x00,\n    0x80, 0x61, 0xbd, 0x69, 0x80, 0x40, 0xc9, 0x80,\n    0x40, 0x9f, 0x81, 0x8b, 0x81, 0x8d, 0x01, 0x89,\n    0xca, 0x99, 0x01, 0x96, 0x80, 0x93, 0x01, 0x88,\n    0x94, 0x81, 0x40, 0xad, 0xa1, 0x81, 0xef, 0x09,\n    0x02, 0x81, 0xd2, 0x0a, 0x80, 0x41, 0x06, 0x80,\n    0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01,\n    0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88,\n    0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05,\n    0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x0b, 0x82,\n    0x89, 0x10, 0x01, 0x10, 0x81, 0x89, 0x40, 0xe2,\n    0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80, 0x89, 0x80,\n    0x40, 0xb8, 0xef, 0x8c, 0x82, 0x8a, 0x82, 0xb8,\n    0x00, 0x83, 0x8f, 0x81, 0x8b, 0x83, 0x89,\n};\n\nstatic const uint8_t unicode_prop_Emoji_Component_table[28] = {\n    0xa2, 0x05, 0x04, 0x89, 0x5f, 0xd2, 0x80, 0x40,\n    0xd4, 0x80, 0x60, 0xdd, 0x2a, 0x80, 0x60, 0xf3,\n    0xd5, 0x99, 0x41, 0xfa, 0x84, 0x45, 0xaf, 0x83,\n    0x6c, 0x06, 0x6b, 0xdf,\n};\n\nstatic const uint8_t unicode_prop_Emoji_Modifier_table[4] = {\n    0x61, 0xf3, 0xfa, 0x84,\n};\n\nstatic const uint8_t unicode_prop_Emoji_Modifier_Base_table[71] = {\n    0x60, 0x26, 0x1c, 0x80, 0x40, 0xda, 0x80, 0x8f,\n    0x83, 0x61, 0xcc, 0x76, 0x80, 0xbb, 0x11, 0x01,\n    0x82, 0xf4, 0x09, 0x8a, 0x94, 0x92, 0x10, 0x1a,\n    0x02, 0x30, 0x00, 0x97, 0x80, 0x40, 0xc8, 0x0b,\n    0x80, 0x94, 0x03, 0x81, 0x40, 0xad, 0x12, 0x84,\n    0xd2, 0x80, 0x8f, 0x82, 0x88, 0x80, 0x8a, 0x80,\n    0x42, 0x3e, 0x01, 0x07, 0x3d, 0x80, 0x88, 0x89,\n    0x0a, 0xb7, 0x80, 0xbc, 0x08, 0x08, 0x80, 0x90,\n    0x10, 0x8c, 0x40, 0xe4, 0x82, 0xa9, 0x88,\n};\n\nstatic const uint8_t unicode_prop_Emoji_Presentation_table[145] = {\n    0x60, 0x23, 0x19, 0x81, 0x40, 0xcc, 0x1a, 0x01,\n    0x80, 0x42, 0x08, 0x81, 0x94, 0x81, 0xb1, 0x8b,\n    0xaa, 0x80, 0x92, 0x80, 0x8c, 0x07, 0x81, 0x90,\n    0x0c, 0x0f, 0x04, 0x80, 0x94, 0x06, 0x08, 0x03,\n    0x01, 0x06, 0x03, 0x81, 0x9b, 0x80, 0xa2, 0x00,\n    0x03, 0x10, 0x80, 0xbc, 0x82, 0x97, 0x80, 0x8d,\n    0x80, 0x43, 0x5a, 0x81, 0xb2, 0x03, 0x80, 0x61,\n    0xc4, 0xad, 0x80, 0x40, 0xc9, 0x80, 0x40, 0xbd,\n    0x01, 0x89, 0xca, 0x99, 0x00, 0x97, 0x80, 0x93,\n    0x01, 0x20, 0x82, 0x94, 0x81, 0x40, 0xad, 0xa0,\n    0x8b, 0x88, 0x80, 0xc5, 0x80, 0x95, 0x8b, 0xaa,\n    0x1c, 0x8b, 0x90, 0x10, 0x82, 0xc6, 0x00, 0x80,\n    0x40, 0xba, 0x81, 0xbe, 0x8c, 0x18, 0x97, 0x91,\n    0x80, 0x99, 0x81, 0x8c, 0x80, 0xd5, 0xd4, 0xaf,\n    0xc5, 0x28, 0x12, 0x0b, 0x13, 0x8a, 0x0e, 0x88,\n    0x40, 0xe2, 0x8b, 0x18, 0x41, 0x1a, 0xae, 0x80,\n    0x89, 0x80, 0x40, 0xb8, 0xef, 0x8c, 0x82, 0x8a,\n    0x82, 0xb8, 0x00, 0x83, 0x8f, 0x81, 0x8b, 0x83,\n    0x89,\n};\n\nstatic const uint8_t unicode_prop_Extended_Pictographic_table[254] = {\n    0x40, 0xa8, 0x03, 0x80, 0x5f, 0x8c, 0x80, 0x8b,\n    0x80, 0x40, 0xd7, 0x80, 0x95, 0x80, 0xd9, 0x85,\n    0x8e, 0x81, 0x41, 0x6e, 0x81, 0x8b, 0x80, 0x40,\n    0xa5, 0x80, 0x98, 0x8a, 0x1a, 0x40, 0xc6, 0x80,\n    0x40, 0xe6, 0x81, 0x89, 0x80, 0x88, 0x80, 0xb9,\n    0x18, 0x84, 0x88, 0x01, 0x01, 0x09, 0x03, 0x01,\n    0x00, 0x09, 0x02, 0x02, 0x0f, 0x14, 0x00, 0x04,\n    0x8b, 0x8a, 0x09, 0x00, 0x08, 0x80, 0x91, 0x01,\n    0x81, 0x91, 0x28, 0x00, 0x0a, 0x0c, 0x01, 0x0b,\n    0x81, 0x8a, 0x0c, 0x09, 0x04, 0x08, 0x00, 0x81,\n    0x93, 0x0c, 0x28, 0x19, 0x03, 0x01, 0x01, 0x28,\n    0x01, 0x00, 0x00, 0x05, 0x02, 0x05, 0x80, 0x89,\n    0x81, 0x8e, 0x01, 0x03, 0x00, 0x03, 0x10, 0x80,\n    0x8a, 0x81, 0xaf, 0x82, 0x88, 0x80, 0x8d, 0x80,\n    0x8d, 0x80, 0x41, 0x73, 0x81, 0x41, 0xce, 0x82,\n    0x92, 0x81, 0xb2, 0x03, 0x80, 0x44, 0xd9, 0x80,\n    0x8b, 0x80, 0x42, 0x58, 0x00, 0x80, 0x61, 0xbd,\n    0x69, 0x80, 0xa6, 0x83, 0xe3, 0x8b, 0x8e, 0x81,\n    0x8e, 0x80, 0x8d, 0x81, 0xa4, 0x89, 0xef, 0x81,\n    0x8b, 0x81, 0x8d, 0x01, 0x89, 0x92, 0xb7, 0x9a,\n    0x8e, 0x89, 0x80, 0x93, 0x01, 0x88, 0x03, 0x88,\n    0x96, 0x85, 0x40, 0xbb, 0x81, 0xef, 0x09, 0x02,\n    0x81, 0xd2, 0x0a, 0x03, 0x84, 0x40, 0xfd, 0x80,\n    0xbe, 0x8a, 0x28, 0x97, 0x31, 0x0f, 0x8b, 0x01,\n    0x19, 0x03, 0x81, 0x8c, 0x09, 0x07, 0x81, 0x88,\n    0x04, 0x82, 0x8b, 0x17, 0x11, 0x00, 0x03, 0x05,\n    0x02, 0x05, 0xd5, 0xaf, 0xc5, 0x27, 0x81, 0x90,\n    0x10, 0x05, 0x81, 0x8c, 0x40, 0xd9, 0xa5, 0x8b,\n    0x83, 0xb7, 0x87, 0x89, 0x85, 0xa7, 0x87, 0x9d,\n    0x81, 0x8b, 0x19, 0x8d, 0x88, 0xa6, 0x8b, 0xae,\n    0x80, 0x89, 0x80, 0x40, 0xb8, 0xd7, 0x87, 0x8d,\n    0x40, 0x91, 0x40, 0xff, 0x43, 0xfd,\n};\n\nstatic const uint8_t unicode_prop_Default_Ignorable_Code_Point_table[51] = {\n    0x40, 0xac, 0x80, 0x42, 0xa0, 0x80, 0x42, 0xcb,\n    0x80, 0x4b, 0x41, 0x81, 0x46, 0x52, 0x81, 0xd4,\n    0x84, 0x47, 0xfa, 0x84, 0x99, 0x84, 0xb0, 0x8f,\n    0x50, 0xf3, 0x80, 0x60, 0xcc, 0x9a, 0x8f, 0x40,\n    0xee, 0x80, 0x40, 0x9f, 0x80, 0xce, 0x88, 0x60,\n    0xbc, 0xa6, 0x83, 0x54, 0xce, 0x87, 0x6c, 0x2e,\n    0x84, 0x4f, 0xff,\n};\n\ntypedef enum {\n    UNICODE_PROP_Hyphen,\n    UNICODE_PROP_Other_Math,\n    UNICODE_PROP_Other_Alphabetic,\n    UNICODE_PROP_Other_Lowercase,\n    UNICODE_PROP_Other_Uppercase,\n    UNICODE_PROP_Other_Grapheme_Extend,\n    UNICODE_PROP_Other_Default_Ignorable_Code_Point,\n    UNICODE_PROP_Other_ID_Start,\n    UNICODE_PROP_Other_ID_Continue,\n    UNICODE_PROP_Prepended_Concatenation_Mark,\n    UNICODE_PROP_ID_Continue1,\n    UNICODE_PROP_XID_Start1,\n    UNICODE_PROP_XID_Continue1,\n    UNICODE_PROP_Changes_When_Titlecased1,\n    UNICODE_PROP_Changes_When_Casefolded1,\n    UNICODE_PROP_Changes_When_NFKC_Casefolded1,\n    UNICODE_PROP_Basic_Emoji1,\n    UNICODE_PROP_Basic_Emoji2,\n    UNICODE_PROP_RGI_Emoji_Modifier_Sequence,\n    UNICODE_PROP_RGI_Emoji_Flag_Sequence,\n    UNICODE_PROP_Emoji_Keycap_Sequence,\n    UNICODE_PROP_ASCII_Hex_Digit,\n    UNICODE_PROP_Bidi_Control,\n    UNICODE_PROP_Dash,\n    UNICODE_PROP_Deprecated,\n    UNICODE_PROP_Diacritic,\n    UNICODE_PROP_Extender,\n    UNICODE_PROP_Hex_Digit,\n    UNICODE_PROP_IDS_Unary_Operator,\n    UNICODE_PROP_IDS_Binary_Operator,\n    UNICODE_PROP_IDS_Trinary_Operator,\n    UNICODE_PROP_Ideographic,\n    UNICODE_PROP_Join_Control,\n    UNICODE_PROP_Logical_Order_Exception,\n    UNICODE_PROP_Modifier_Combining_Mark,\n    UNICODE_PROP_Noncharacter_Code_Point,\n    UNICODE_PROP_Pattern_Syntax,\n    UNICODE_PROP_Pattern_White_Space,\n    UNICODE_PROP_Quotation_Mark,\n    UNICODE_PROP_Radical,\n    UNICODE_PROP_Regional_Indicator,\n    UNICODE_PROP_Sentence_Terminal,\n    UNICODE_PROP_Soft_Dotted,\n    UNICODE_PROP_Terminal_Punctuation,\n    UNICODE_PROP_Unified_Ideograph,\n    UNICODE_PROP_Variation_Selector,\n    UNICODE_PROP_White_Space,\n    UNICODE_PROP_Bidi_Mirrored,\n    UNICODE_PROP_Emoji,\n    UNICODE_PROP_Emoji_Component,\n    UNICODE_PROP_Emoji_Modifier,\n    UNICODE_PROP_Emoji_Modifier_Base,\n    UNICODE_PROP_Emoji_Presentation,\n    UNICODE_PROP_Extended_Pictographic,\n    UNICODE_PROP_Default_Ignorable_Code_Point,\n    UNICODE_PROP_ID_Start,\n    UNICODE_PROP_Case_Ignorable,\n    UNICODE_PROP_ASCII,\n    UNICODE_PROP_Alphabetic,\n    UNICODE_PROP_Any,\n    UNICODE_PROP_Assigned,\n    UNICODE_PROP_Cased,\n    UNICODE_PROP_Changes_When_Casefolded,\n    UNICODE_PROP_Changes_When_Casemapped,\n    UNICODE_PROP_Changes_When_Lowercased,\n    UNICODE_PROP_Changes_When_NFKC_Casefolded,\n    UNICODE_PROP_Changes_When_Titlecased,\n    UNICODE_PROP_Changes_When_Uppercased,\n    UNICODE_PROP_Grapheme_Base,\n    UNICODE_PROP_Grapheme_Extend,\n    UNICODE_PROP_ID_Continue,\n    UNICODE_PROP_ID_Compat_Math_Start,\n    UNICODE_PROP_ID_Compat_Math_Continue,\n    UNICODE_PROP_InCB,\n    UNICODE_PROP_Lowercase,\n    UNICODE_PROP_Math,\n    UNICODE_PROP_Uppercase,\n    UNICODE_PROP_XID_Continue,\n    UNICODE_PROP_XID_Start,\n    UNICODE_PROP_Cased1,\n    UNICODE_PROP_COUNT,\n} UnicodePropertyEnum;\n\nstatic const char unicode_prop_name_table[] =\n    \"ASCII_Hex_Digit,AHex\"               \"\\0\"\n    \"Bidi_Control,Bidi_C\"                \"\\0\"\n    \"Dash\"                               \"\\0\"\n    \"Deprecated,Dep\"                     \"\\0\"\n    \"Diacritic,Dia\"                      \"\\0\"\n    \"Extender,Ext\"                       \"\\0\"\n    \"Hex_Digit,Hex\"                      \"\\0\"\n    \"IDS_Unary_Operator,IDSU\"            \"\\0\"\n    \"IDS_Binary_Operator,IDSB\"           \"\\0\"\n    \"IDS_Trinary_Operator,IDST\"          \"\\0\"\n    \"Ideographic,Ideo\"                   \"\\0\"\n    \"Join_Control,Join_C\"                \"\\0\"\n    \"Logical_Order_Exception,LOE\"        \"\\0\"\n    \"Modifier_Combining_Mark,MCM\"        \"\\0\"\n    \"Noncharacter_Code_Point,NChar\"      \"\\0\"\n    \"Pattern_Syntax,Pat_Syn\"             \"\\0\"\n    \"Pattern_White_Space,Pat_WS\"         \"\\0\"\n    \"Quotation_Mark,QMark\"               \"\\0\"\n    \"Radical\"                            \"\\0\"\n    \"Regional_Indicator,RI\"              \"\\0\"\n    \"Sentence_Terminal,STerm\"            \"\\0\"\n    \"Soft_Dotted,SD\"                     \"\\0\"\n    \"Terminal_Punctuation,Term\"          \"\\0\"\n    \"Unified_Ideograph,UIdeo\"            \"\\0\"\n    \"Variation_Selector,VS\"              \"\\0\"\n    \"White_Space,space\"                  \"\\0\"\n    \"Bidi_Mirrored,Bidi_M\"               \"\\0\"\n    \"Emoji\"                              \"\\0\"\n    \"Emoji_Component,EComp\"              \"\\0\"\n    \"Emoji_Modifier,EMod\"                \"\\0\"\n    \"Emoji_Modifier_Base,EBase\"          \"\\0\"\n    \"Emoji_Presentation,EPres\"           \"\\0\"\n    \"Extended_Pictographic,ExtPict\"      \"\\0\"\n    \"Default_Ignorable_Code_Point,DI\"    \"\\0\"\n    \"ID_Start,IDS\"                       \"\\0\"\n    \"Case_Ignorable,CI\"                  \"\\0\"\n    \"ASCII\"                              \"\\0\"\n    \"Alphabetic,Alpha\"                   \"\\0\"\n    \"Any\"                                \"\\0\"\n    \"Assigned\"                           \"\\0\"\n    \"Cased\"                              \"\\0\"\n    \"Changes_When_Casefolded,CWCF\"       \"\\0\"\n    \"Changes_When_Casemapped,CWCM\"       \"\\0\"\n    \"Changes_When_Lowercased,CWL\"        \"\\0\"\n    \"Changes_When_NFKC_Casefolded,CWKCF\" \"\\0\"\n    \"Changes_When_Titlecased,CWT\"        \"\\0\"\n    \"Changes_When_Uppercased,CWU\"        \"\\0\"\n    \"Grapheme_Base,Gr_Base\"              \"\\0\"\n    \"Grapheme_Extend,Gr_Ext\"             \"\\0\"\n    \"ID_Continue,IDC\"                    \"\\0\"\n    \"ID_Compat_Math_Start\"               \"\\0\"\n    \"ID_Compat_Math_Continue\"            \"\\0\"\n    \"InCB\"                               \"\\0\"\n    \"Lowercase,Lower\"                    \"\\0\"\n    \"Math\"                               \"\\0\"\n    \"Uppercase,Upper\"                    \"\\0\"\n    \"XID_Continue,XIDC\"                  \"\\0\"\n    \"XID_Start,XIDS\"                     \"\\0\"\n;\n\nstatic const uint8_t * const unicode_prop_table[] = {\n    unicode_prop_Hyphen_table,\n    unicode_prop_Other_Math_table,\n    unicode_prop_Other_Alphabetic_table,\n    unicode_prop_Other_Lowercase_table,\n    unicode_prop_Other_Uppercase_table,\n    unicode_prop_Other_Grapheme_Extend_table,\n    unicode_prop_Other_Default_Ignorable_Code_Point_table,\n    unicode_prop_Other_ID_Start_table,\n    unicode_prop_Other_ID_Continue_table,\n    unicode_prop_Prepended_Concatenation_Mark_table,\n    unicode_prop_ID_Continue1_table,\n    unicode_prop_XID_Start1_table,\n    unicode_prop_XID_Continue1_table,\n    unicode_prop_Changes_When_Titlecased1_table,\n    unicode_prop_Changes_When_Casefolded1_table,\n    unicode_prop_Changes_When_NFKC_Casefolded1_table,\n    unicode_prop_Basic_Emoji1_table,\n    unicode_prop_Basic_Emoji2_table,\n    unicode_prop_RGI_Emoji_Modifier_Sequence_table,\n    unicode_prop_RGI_Emoji_Flag_Sequence_table,\n    unicode_prop_Emoji_Keycap_Sequence_table,\n    unicode_prop_ASCII_Hex_Digit_table,\n    unicode_prop_Bidi_Control_table,\n    unicode_prop_Dash_table,\n    unicode_prop_Deprecated_table,\n    unicode_prop_Diacritic_table,\n    unicode_prop_Extender_table,\n    unicode_prop_Hex_Digit_table,\n    unicode_prop_IDS_Unary_Operator_table,\n    unicode_prop_IDS_Binary_Operator_table,\n    unicode_prop_IDS_Trinary_Operator_table,\n    unicode_prop_Ideographic_table,\n    unicode_prop_Join_Control_table,\n    unicode_prop_Logical_Order_Exception_table,\n    unicode_prop_Modifier_Combining_Mark_table,\n    unicode_prop_Noncharacter_Code_Point_table,\n    unicode_prop_Pattern_Syntax_table,\n    unicode_prop_Pattern_White_Space_table,\n    unicode_prop_Quotation_Mark_table,\n    unicode_prop_Radical_table,\n    unicode_prop_Regional_Indicator_table,\n    unicode_prop_Sentence_Terminal_table,\n    unicode_prop_Soft_Dotted_table,\n    unicode_prop_Terminal_Punctuation_table,\n    unicode_prop_Unified_Ideograph_table,\n    unicode_prop_Variation_Selector_table,\n    unicode_prop_White_Space_table,\n    unicode_prop_Bidi_Mirrored_table,\n    unicode_prop_Emoji_table,\n    unicode_prop_Emoji_Component_table,\n    unicode_prop_Emoji_Modifier_table,\n    unicode_prop_Emoji_Modifier_Base_table,\n    unicode_prop_Emoji_Presentation_table,\n    unicode_prop_Extended_Pictographic_table,\n    unicode_prop_Default_Ignorable_Code_Point_table,\n    unicode_prop_ID_Start_table,\n    unicode_prop_Case_Ignorable_table,\n};\n\nstatic const uint16_t unicode_prop_len_table[] = {\n    countof(unicode_prop_Hyphen_table),\n    countof(unicode_prop_Other_Math_table),\n    countof(unicode_prop_Other_Alphabetic_table),\n    countof(unicode_prop_Other_Lowercase_table),\n    countof(unicode_prop_Other_Uppercase_table),\n    countof(unicode_prop_Other_Grapheme_Extend_table),\n    countof(unicode_prop_Other_Default_Ignorable_Code_Point_table),\n    countof(unicode_prop_Other_ID_Start_table),\n    countof(unicode_prop_Other_ID_Continue_table),\n    countof(unicode_prop_Prepended_Concatenation_Mark_table),\n    countof(unicode_prop_ID_Continue1_table),\n    countof(unicode_prop_XID_Start1_table),\n    countof(unicode_prop_XID_Continue1_table),\n    countof(unicode_prop_Changes_When_Titlecased1_table),\n    countof(unicode_prop_Changes_When_Casefolded1_table),\n    countof(unicode_prop_Changes_When_NFKC_Casefolded1_table),\n    countof(unicode_prop_Basic_Emoji1_table),\n    countof(unicode_prop_Basic_Emoji2_table),\n    countof(unicode_prop_RGI_Emoji_Modifier_Sequence_table),\n    countof(unicode_prop_RGI_Emoji_Flag_Sequence_table),\n    countof(unicode_prop_Emoji_Keycap_Sequence_table),\n    countof(unicode_prop_ASCII_Hex_Digit_table),\n    countof(unicode_prop_Bidi_Control_table),\n    countof(unicode_prop_Dash_table),\n    countof(unicode_prop_Deprecated_table),\n    countof(unicode_prop_Diacritic_table),\n    countof(unicode_prop_Extender_table),\n    countof(unicode_prop_Hex_Digit_table),\n    countof(unicode_prop_IDS_Unary_Operator_table),\n    countof(unicode_prop_IDS_Binary_Operator_table),\n    countof(unicode_prop_IDS_Trinary_Operator_table),\n    countof(unicode_prop_Ideographic_table),\n    countof(unicode_prop_Join_Control_table),\n    countof(unicode_prop_Logical_Order_Exception_table),\n    countof(unicode_prop_Modifier_Combining_Mark_table),\n    countof(unicode_prop_Noncharacter_Code_Point_table),\n    countof(unicode_prop_Pattern_Syntax_table),\n    countof(unicode_prop_Pattern_White_Space_table),\n    countof(unicode_prop_Quotation_Mark_table),\n    countof(unicode_prop_Radical_table),\n    countof(unicode_prop_Regional_Indicator_table),\n    countof(unicode_prop_Sentence_Terminal_table),\n    countof(unicode_prop_Soft_Dotted_table),\n    countof(unicode_prop_Terminal_Punctuation_table),\n    countof(unicode_prop_Unified_Ideograph_table),\n    countof(unicode_prop_Variation_Selector_table),\n    countof(unicode_prop_White_Space_table),\n    countof(unicode_prop_Bidi_Mirrored_table),\n    countof(unicode_prop_Emoji_table),\n    countof(unicode_prop_Emoji_Component_table),\n    countof(unicode_prop_Emoji_Modifier_table),\n    countof(unicode_prop_Emoji_Modifier_Base_table),\n    countof(unicode_prop_Emoji_Presentation_table),\n    countof(unicode_prop_Extended_Pictographic_table),\n    countof(unicode_prop_Default_Ignorable_Code_Point_table),\n    countof(unicode_prop_ID_Start_table),\n    countof(unicode_prop_Case_Ignorable_table),\n};\n\ntypedef enum {\n    UNICODE_SEQUENCE_PROP_Basic_Emoji,\n    UNICODE_SEQUENCE_PROP_Emoji_Keycap_Sequence,\n    UNICODE_SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence,\n    UNICODE_SEQUENCE_PROP_RGI_Emoji_Flag_Sequence,\n    UNICODE_SEQUENCE_PROP_RGI_Emoji_Tag_Sequence,\n    UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence,\n    UNICODE_SEQUENCE_PROP_RGI_Emoji,\n    UNICODE_SEQUENCE_PROP_COUNT,\n} UnicodeSequencePropertyEnum;\n\nstatic const char unicode_sequence_prop_name_table[] =\n    \"Basic_Emoji\"                 \"\\0\"\n    \"Emoji_Keycap_Sequence\"       \"\\0\"\n    \"RGI_Emoji_Modifier_Sequence\" \"\\0\"\n    \"RGI_Emoji_Flag_Sequence\"     \"\\0\"\n    \"RGI_Emoji_Tag_Sequence\"      \"\\0\"\n    \"RGI_Emoji_ZWJ_Sequence\"      \"\\0\"\n    \"RGI_Emoji\"                   \"\\0\"\n;\n\nstatic const uint8_t unicode_rgi_emoji_tag_sequence[18] = {\n    0x67, 0x62, 0x65, 0x6e, 0x67, 0x00, 0x67, 0x62,\n    0x73, 0x63, 0x74, 0x00, 0x67, 0x62, 0x77, 0x6c,\n    0x73, 0x00,\n};\n\nstatic const uint8_t unicode_rgi_emoji_zwj_sequence[2392] = {\n    0x02, 0xb8, 0x19, 0x40, 0x86, 0x02, 0xd1, 0x39,\n    0xb0, 0x19, 0x02, 0x26, 0x39, 0x42, 0x86, 0x02,\n    0xb4, 0x36, 0x42, 0x86, 0x03, 0x68, 0x54, 0x64,\n    0x87, 0x68, 0x54, 0x02, 0xdc, 0x39, 0x42, 0x86,\n    0x02, 0xd1, 0x39, 0x73, 0x13, 0x02, 0x39, 0x39,\n    0x40, 0x86, 0x02, 0x69, 0x34, 0xbd, 0x19, 0x03,\n    0xb6, 0x36, 0x40, 0x86, 0xa1, 0x87, 0x03, 0x68,\n    0x74, 0x1d, 0x19, 0x68, 0x74, 0x03, 0x68, 0x34,\n    0xbd, 0x19, 0xa1, 0x87, 0x02, 0xf1, 0x7a, 0xf2,\n    0x7a, 0x02, 0xca, 0x33, 0x42, 0x86, 0x02, 0x69,\n    0x34, 0xb0, 0x19, 0x04, 0x68, 0x14, 0x68, 0x14,\n    0x67, 0x14, 0x66, 0x14, 0x02, 0xf9, 0x26, 0x42,\n    0x86, 0x03, 0x69, 0x74, 0x1d, 0x19, 0x69, 0x74,\n    0x03, 0xd1, 0x19, 0xbc, 0x19, 0xa1, 0x87, 0x02,\n    0x3c, 0x19, 0x40, 0x86, 0x02, 0x68, 0x34, 0xeb,\n    0x13, 0x02, 0xc3, 0x33, 0xa1, 0x87, 0x02, 0x70,\n    0x34, 0x40, 0x86, 0x02, 0xd4, 0x39, 0x42, 0x86,\n    0x02, 0xcf, 0x39, 0x42, 0x86, 0x03, 0xd1, 0x79,\n    0xef, 0x1a, 0xd1, 0x79, 0x03, 0x68, 0x74, 0xef,\n    0x1a, 0x68, 0x74, 0x03, 0x69, 0x74, 0xef, 0x1a,\n    0x69, 0x74, 0x02, 0x47, 0x36, 0x40, 0x86, 0x03,\n    0x68, 0x74, 0x30, 0x14, 0x68, 0x74, 0x02, 0x39,\n    0x39, 0x42, 0x86, 0x04, 0xd1, 0x79, 0x64, 0x87,\n    0x8b, 0x14, 0xd1, 0x79, 0x03, 0x69, 0x74, 0x30,\n    0x14, 0x69, 0x74, 0x02, 0xd1, 0x39, 0x95, 0x86,\n    0x02, 0x68, 0x34, 0x93, 0x13, 0x02, 0x69, 0x34,\n    0xed, 0x13, 0x02, 0xda, 0x39, 0x40, 0x86, 0x03,\n    0x69, 0x34, 0xaf, 0x19, 0xa1, 0x87, 0x02, 0xd1,\n    0x39, 0x93, 0x13, 0x03, 0xce, 0x39, 0x42, 0x86,\n    0xa1, 0x87, 0x03, 0xd1, 0x79, 0x64, 0x87, 0xd1,\n    0x79, 0x03, 0xc3, 0x33, 0x42, 0x86, 0xa1, 0x87,\n    0x03, 0x69, 0x74, 0x1d, 0x19, 0x68, 0x74, 0x02,\n    0x69, 0x34, 0x92, 0x16, 0x02, 0xd1, 0x39, 0x96,\n    0x86, 0x04, 0x69, 0x14, 0x64, 0x87, 0x8b, 0x14,\n    0x68, 0x14, 0x02, 0x47, 0x36, 0x42, 0x86, 0x02,\n    0x68, 0x34, 0x7c, 0x13, 0x02, 0x86, 0x34, 0x42,\n    0x86, 0x02, 0xd1, 0x39, 0x7c, 0x13, 0x02, 0x69,\n    0x14, 0xa4, 0x13, 0x02, 0xda, 0x39, 0x42, 0x86,\n    0x02, 0x37, 0x39, 0x40, 0x86, 0x02, 0xd1, 0x39,\n    0x08, 0x87, 0x04, 0x68, 0x54, 0x64, 0x87, 0x8b,\n    0x14, 0x68, 0x54, 0x02, 0x4d, 0x36, 0x40, 0x86,\n    0x02, 0x68, 0x34, 0x2c, 0x15, 0x02, 0x69, 0x34,\n    0xaf, 0x19, 0x02, 0x6e, 0x34, 0x40, 0x86, 0x02,\n    0xcd, 0x39, 0x42, 0x86, 0x02, 0xd1, 0x39, 0x2c,\n    0x15, 0x02, 0x6f, 0x14, 0x40, 0x86, 0x03, 0xd1,\n    0x39, 0xbc, 0x19, 0xa1, 0x87, 0x02, 0x68, 0x34,\n    0xa8, 0x13, 0x02, 0x69, 0x34, 0x73, 0x13, 0x04,\n    0x69, 0x54, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x54,\n    0x02, 0x71, 0x34, 0x42, 0x86, 0x02, 0x45, 0x36,\n    0x40, 0x86, 0x02, 0xd1, 0x39, 0xa8, 0x13, 0x03,\n    0x69, 0x54, 0x64, 0x87, 0x68, 0x54, 0x03, 0x69,\n    0x54, 0x64, 0x87, 0x69, 0x54, 0x03, 0xce, 0x39,\n    0x40, 0x86, 0xa1, 0x87, 0x02, 0xd8, 0x39, 0x40,\n    0x86, 0x03, 0xc3, 0x33, 0x40, 0x86, 0xa1, 0x87,\n    0x02, 0x4d, 0x36, 0x42, 0x86, 0x02, 0xd1, 0x19,\n    0x92, 0x16, 0x02, 0xd1, 0x39, 0xeb, 0x13, 0x02,\n    0x68, 0x34, 0xbc, 0x14, 0x02, 0xd1, 0x39, 0xbc,\n    0x14, 0x02, 0x3d, 0x39, 0x40, 0x86, 0x02, 0xb8,\n    0x39, 0x42, 0x86, 0x02, 0xa3, 0x36, 0x40, 0x86,\n    0x02, 0x75, 0x35, 0x40, 0x86, 0x02, 0xd8, 0x39,\n    0x42, 0x86, 0x02, 0x69, 0x34, 0x93, 0x13, 0x02,\n    0x35, 0x39, 0x40, 0x86, 0x02, 0x4b, 0x36, 0x40,\n    0x86, 0x02, 0x3d, 0x39, 0x42, 0x86, 0x02, 0x38,\n    0x39, 0x42, 0x86, 0x02, 0xa3, 0x36, 0x42, 0x86,\n    0x03, 0x69, 0x14, 0x67, 0x14, 0x67, 0x14, 0x02,\n    0xb6, 0x36, 0x40, 0x86, 0x02, 0x69, 0x34, 0x7c,\n    0x13, 0x02, 0x75, 0x35, 0x42, 0x86, 0x02, 0xcc,\n    0x93, 0x40, 0x86, 0x02, 0x6f, 0x34, 0x42, 0x86,\n    0x02, 0xcc, 0x33, 0x40, 0x86, 0x03, 0xd1, 0x39,\n    0xbd, 0x19, 0xa1, 0x87, 0x02, 0x87, 0x34, 0x40,\n    0x86, 0x02, 0x82, 0x34, 0x40, 0x86, 0x02, 0x69,\n    0x14, 0x3e, 0x13, 0x02, 0xd6, 0x39, 0x40, 0x86,\n    0x02, 0x68, 0x14, 0xbd, 0x19, 0x02, 0x4b, 0x36,\n    0x42, 0x86, 0x02, 0x46, 0x36, 0x42, 0x86, 0x02,\n    0x69, 0x34, 0x2c, 0x15, 0x03, 0xb6, 0x36, 0x42,\n    0x86, 0xa1, 0x87, 0x02, 0xc4, 0x33, 0x40, 0x86,\n    0x02, 0x26, 0x19, 0x40, 0x86, 0x02, 0x69, 0x14,\n    0xb0, 0x19, 0x02, 0xde, 0x19, 0x42, 0x86, 0x02,\n    0x69, 0x34, 0xa8, 0x13, 0x02, 0xcc, 0x33, 0x42,\n    0x86, 0x02, 0x82, 0x34, 0x42, 0x86, 0x02, 0xd1,\n    0x19, 0x93, 0x13, 0x02, 0x81, 0x14, 0x42, 0x86,\n    0x03, 0xd1, 0x79, 0x30, 0x14, 0xd1, 0x79, 0x02,\n    0x68, 0x34, 0xbb, 0x14, 0x02, 0x69, 0x34, 0x95,\n    0x86, 0x02, 0xd1, 0x39, 0xbb, 0x14, 0x02, 0x69,\n    0x34, 0xeb, 0x13, 0x02, 0xd1, 0x39, 0x84, 0x13,\n    0x02, 0x69, 0x34, 0xbc, 0x14, 0x04, 0x69, 0x54,\n    0x64, 0x87, 0x8b, 0x14, 0x69, 0x54, 0x02, 0x26,\n    0x39, 0x40, 0x86, 0x02, 0xb4, 0x36, 0x40, 0x86,\n    0x02, 0x47, 0x16, 0x42, 0x86, 0x02, 0xdc, 0x39,\n    0x40, 0x86, 0x02, 0xca, 0x33, 0x40, 0x86, 0x02,\n    0xf9, 0x26, 0x40, 0x86, 0x02, 0x69, 0x34, 0x08,\n    0x87, 0x03, 0x69, 0x14, 0x69, 0x14, 0x66, 0x14,\n    0x03, 0xd1, 0x59, 0x1d, 0x19, 0xd1, 0x59, 0x02,\n    0xd4, 0x39, 0x40, 0x86, 0x02, 0xcf, 0x39, 0x40,\n    0x86, 0x02, 0x68, 0x34, 0xa4, 0x13, 0x02, 0xd1,\n    0x39, 0xa4, 0x13, 0x02, 0xd1, 0x19, 0xa8, 0x13,\n    0x02, 0xd7, 0x39, 0x42, 0x86, 0x03, 0x69, 0x34,\n    0xbc, 0x19, 0xa1, 0x87, 0x02, 0x68, 0x14, 0xb0,\n    0x19, 0x02, 0x3c, 0x39, 0x42, 0x86, 0x02, 0x68,\n    0x14, 0x73, 0x13, 0x04, 0x69, 0x14, 0x69, 0x14,\n    0x66, 0x14, 0x66, 0x14, 0x03, 0x68, 0x34, 0xaf,\n    0x19, 0xa1, 0x87, 0x02, 0x68, 0x34, 0x80, 0x16,\n    0x02, 0x73, 0x34, 0x42, 0x86, 0x02, 0xd1, 0x39,\n    0x80, 0x16, 0x02, 0x68, 0x34, 0xb0, 0x19, 0x02,\n    0x86, 0x34, 0x40, 0x86, 0x02, 0x38, 0x19, 0x42,\n    0x86, 0x02, 0x69, 0x34, 0xbb, 0x14, 0x02, 0xb5,\n    0x36, 0x42, 0x86, 0x02, 0xcd, 0x39, 0x40, 0x86,\n    0x02, 0x68, 0x34, 0x27, 0x15, 0x02, 0x68, 0x34,\n    0x95, 0x86, 0x03, 0x68, 0x14, 0x68, 0x14, 0x66,\n    0x14, 0x02, 0x71, 0x34, 0x40, 0x86, 0x02, 0xd1,\n    0x39, 0x27, 0x15, 0x02, 0x2e, 0x16, 0xa8, 0x14,\n    0x02, 0xc3, 0x33, 0x42, 0x86, 0x02, 0x69, 0x14,\n    0x66, 0x14, 0x02, 0x68, 0x34, 0x96, 0x86, 0x02,\n    0xd1, 0x39, 0x70, 0x1a, 0x03, 0x69, 0x14, 0x64,\n    0x87, 0x68, 0x14, 0x02, 0x69, 0x34, 0xa4, 0x13,\n    0x02, 0xb8, 0x39, 0x40, 0x86, 0x02, 0x68, 0x34,\n    0x3e, 0x13, 0x03, 0xd1, 0x19, 0xaf, 0x19, 0xa1,\n    0x87, 0x02, 0xd1, 0x39, 0x3e, 0x13, 0x02, 0x68,\n    0x34, 0xbd, 0x19, 0x02, 0xd1, 0x19, 0xbb, 0x14,\n    0x02, 0xd1, 0x19, 0x95, 0x86, 0x02, 0xdb, 0x39,\n    0x42, 0x86, 0x02, 0x38, 0x39, 0x40, 0x86, 0x02,\n    0x69, 0x34, 0x80, 0x16, 0x02, 0x69, 0x14, 0xeb,\n    0x13, 0x04, 0x68, 0x14, 0x69, 0x14, 0x67, 0x14,\n    0x67, 0x14, 0x02, 0x6f, 0x34, 0x40, 0x86, 0x02,\n    0x77, 0x34, 0x42, 0x86, 0x02, 0x46, 0x36, 0x40,\n    0x86, 0x02, 0x68, 0x34, 0x92, 0x16, 0x02, 0x4e,\n    0x36, 0x42, 0x86, 0x03, 0x69, 0x14, 0xbd, 0x19,\n    0xa1, 0x87, 0x02, 0xde, 0x19, 0x40, 0x86, 0x02,\n    0x69, 0x34, 0x27, 0x15, 0x03, 0xc3, 0x13, 0x40,\n    0x86, 0xa1, 0x87, 0x02, 0x81, 0x14, 0x40, 0x86,\n    0x03, 0xd1, 0x39, 0xaf, 0x19, 0xa1, 0x87, 0x02,\n    0x68, 0x34, 0xbc, 0x19, 0x02, 0xd1, 0x19, 0x80,\n    0x16, 0x02, 0xd9, 0x39, 0x42, 0x86, 0x02, 0xd1,\n    0x39, 0xbc, 0x19, 0x02, 0xdc, 0x19, 0x42, 0x86,\n    0x02, 0x68, 0x34, 0x73, 0x13, 0x02, 0x69, 0x34,\n    0x3e, 0x13, 0x02, 0x47, 0x16, 0x40, 0x86, 0x02,\n    0xd1, 0x39, 0xbd, 0x19, 0x02, 0x3e, 0x39, 0x42,\n    0x86, 0x02, 0x69, 0x14, 0x95, 0x86, 0x02, 0x68,\n    0x14, 0x96, 0x86, 0x03, 0x69, 0x34, 0xbd, 0x19,\n    0xa1, 0x87, 0x02, 0xd7, 0x39, 0x40, 0x86, 0x02,\n    0x45, 0x16, 0x42, 0x86, 0x02, 0x68, 0x34, 0xed,\n    0x13, 0x03, 0x68, 0x34, 0xbc, 0x19, 0xa1, 0x87,\n    0x02, 0xd1, 0x39, 0xed, 0x13, 0x02, 0x3c, 0x39,\n    0x40, 0x86, 0x02, 0xd1, 0x19, 0x70, 0x1a, 0x02,\n    0xd1, 0x39, 0x92, 0x16, 0x02, 0x73, 0x34, 0x40,\n    0x86, 0x02, 0x38, 0x19, 0x40, 0x86, 0x02, 0xb5,\n    0x36, 0x40, 0x86, 0x02, 0x68, 0x34, 0xaf, 0x19,\n    0x02, 0xd1, 0x39, 0xaf, 0x19, 0x02, 0x69, 0x34,\n    0xbc, 0x19, 0x02, 0xb6, 0x16, 0x42, 0x86, 0x02,\n    0x26, 0x14, 0x25, 0x15, 0x02, 0xc3, 0x33, 0x40,\n    0x86, 0x02, 0xdd, 0x39, 0x42, 0x86, 0x02, 0xcb,\n    0x93, 0x42, 0x86, 0x02, 0xcb, 0x33, 0x42, 0x86,\n    0x02, 0x81, 0x34, 0x42, 0x86, 0x02, 0xce, 0x39,\n    0xa1, 0x87, 0x02, 0xdb, 0x39, 0x40, 0x86, 0x02,\n    0x68, 0x34, 0x08, 0x87, 0x02, 0xd1, 0x19, 0xb0,\n    0x19, 0x02, 0x77, 0x34, 0x40, 0x86, 0x02, 0x4e,\n    0x36, 0x40, 0x86, 0x02, 0xce, 0x39, 0x42, 0x86,\n    0x02, 0x4e, 0x16, 0x42, 0x86, 0x02, 0xd9, 0x39,\n    0x40, 0x86, 0x02, 0xdc, 0x19, 0x40, 0x86, 0x02,\n    0x3e, 0x39, 0x40, 0x86, 0x02, 0xb9, 0x39, 0x42,\n    0x86, 0x02, 0xda, 0x19, 0x42, 0x86, 0x02, 0x42,\n    0x16, 0x94, 0x81, 0x02, 0x45, 0x16, 0x40, 0x86,\n    0x02, 0x69, 0x14, 0xbd, 0x19, 0x02, 0x70, 0x34,\n    0x42, 0x86, 0x02, 0xce, 0x19, 0xa1, 0x87, 0x02,\n    0xc3, 0x13, 0x42, 0x86, 0x02, 0x68, 0x14, 0x08,\n    0x87, 0x02, 0xd1, 0x19, 0x7c, 0x13, 0x02, 0x68,\n    0x14, 0x92, 0x16, 0x02, 0xb6, 0x16, 0x40, 0x86,\n    0x02, 0x37, 0x39, 0x42, 0x86, 0x03, 0xce, 0x19,\n    0x42, 0x86, 0xa1, 0x87, 0x03, 0x68, 0x14, 0x67,\n    0x14, 0x67, 0x14, 0x02, 0xdd, 0x39, 0x40, 0x86,\n    0x02, 0xcf, 0x19, 0x42, 0x86, 0x02, 0xd1, 0x19,\n    0x2c, 0x15, 0x02, 0x4b, 0x13, 0xe9, 0x17, 0x02,\n    0x68, 0x14, 0x67, 0x14, 0x02, 0xcb, 0x93, 0x40,\n    0x86, 0x02, 0x6e, 0x34, 0x42, 0x86, 0x02, 0xcb,\n    0x33, 0x40, 0x86, 0x02, 0x81, 0x34, 0x40, 0x86,\n    0x02, 0xb6, 0x36, 0xa1, 0x87, 0x02, 0x45, 0x36,\n    0x42, 0x86, 0x02, 0xb4, 0x16, 0x42, 0x86, 0x02,\n    0x69, 0x14, 0x73, 0x13, 0x04, 0x69, 0x14, 0x69,\n    0x14, 0x67, 0x14, 0x66, 0x14, 0x02, 0x35, 0x39,\n    0x42, 0x86, 0x02, 0x68, 0x14, 0x93, 0x13, 0x02,\n    0xb6, 0x36, 0x42, 0x86, 0x03, 0x68, 0x14, 0x69,\n    0x14, 0x66, 0x14, 0x02, 0xce, 0x39, 0x40, 0x86,\n    0x02, 0x4e, 0x16, 0x40, 0x86, 0x02, 0x87, 0x34,\n    0x42, 0x86, 0x02, 0x86, 0x14, 0x42, 0x86, 0x02,\n    0xd6, 0x39, 0x42, 0x86, 0x02, 0xc4, 0x33, 0x42,\n    0x86, 0x02, 0x69, 0x34, 0x96, 0x86, 0x02, 0xb9,\n    0x39, 0x40, 0x86, 0x02, 0x68, 0x14, 0xa8, 0x13,\n    0x02, 0xd1, 0x19, 0x84, 0x13, 0x02, 0xda, 0x19,\n    0x40, 0x86, 0x02, 0xd8, 0x19, 0x42, 0x86, 0x02,\n    0xc3, 0x13, 0x40, 0x86, 0x02, 0xb9, 0x19, 0x42,\n    0x86, 0x02, 0x3d, 0x19, 0x42, 0x86, 0x02, 0xcf,\n    0x19, 0x40, 0x86, 0x04, 0x68, 0x14, 0x68, 0x14,\n    0x67, 0x14, 0x67, 0x14, 0x03, 0xd1, 0x19, 0xd1,\n    0x19, 0xd2, 0x19, 0x02, 0x68, 0x14, 0xbb, 0x14,\n    0x02, 0x3b, 0x14, 0x44, 0x87, 0x02, 0xd1, 0x19,\n    0x27, 0x15, 0x02, 0xb4, 0x16, 0x40, 0x86, 0x02,\n    0xcd, 0x19, 0x42, 0x86, 0x02, 0xd3, 0x86, 0xa5,\n    0x14, 0x02, 0x70, 0x14, 0x42, 0x86, 0x03, 0xb6,\n    0x16, 0x42, 0x86, 0xa1, 0x87, 0x04, 0x69, 0x14,\n    0x64, 0x87, 0x8b, 0x14, 0x69, 0x14, 0x02, 0x36,\n    0x16, 0x2b, 0x93, 0x02, 0x68, 0x14, 0x80, 0x16,\n    0x02, 0x86, 0x14, 0x40, 0x86, 0x02, 0x08, 0x14,\n    0x1b, 0x0b, 0x02, 0xd1, 0x19, 0xbc, 0x19, 0x02,\n    0xca, 0x13, 0x42, 0x86, 0x02, 0x41, 0x94, 0xe8,\n    0x95, 0x02, 0xd8, 0x19, 0x40, 0x86, 0x02, 0xb9,\n    0x19, 0x40, 0x86, 0x02, 0xd1, 0x19, 0xed, 0x13,\n    0x02, 0xf9, 0x86, 0x42, 0x86, 0x03, 0xd1, 0x19,\n    0xbd, 0x19, 0xa1, 0x87, 0x02, 0x3d, 0x19, 0x40,\n    0x86, 0x02, 0xd6, 0x19, 0x42, 0x86, 0x03, 0x69,\n    0x14, 0x66, 0x14, 0x66, 0x14, 0x02, 0xd1, 0x19,\n    0xaf, 0x19, 0x03, 0x69, 0x14, 0x69, 0x14, 0x67,\n    0x14, 0x02, 0xcd, 0x19, 0x40, 0x86, 0x02, 0x70,\n    0x14, 0x40, 0x86, 0x03, 0x68, 0x14, 0xbc, 0x19,\n    0xa1, 0x87, 0x02, 0x6e, 0x14, 0x42, 0x86, 0x02,\n    0x69, 0x14, 0x92, 0x16, 0x03, 0x68, 0x14, 0x68,\n    0x14, 0x67, 0x14, 0x02, 0x69, 0x14, 0x67, 0x14,\n    0x02, 0x75, 0x95, 0x42, 0x86, 0x03, 0x69, 0x14,\n    0x64, 0x87, 0x69, 0x14, 0x02, 0xd1, 0x19, 0xbc,\n    0x14, 0x02, 0xdf, 0x19, 0x42, 0x86, 0x02, 0xca,\n    0x13, 0x40, 0x86, 0x02, 0x82, 0x14, 0x42, 0x86,\n    0x02, 0x69, 0x14, 0x93, 0x13, 0x02, 0x68, 0x14,\n    0x7c, 0x13, 0x02, 0xf9, 0x86, 0x40, 0x86, 0x02,\n    0xd6, 0x19, 0x40, 0x86, 0x02, 0x68, 0x14, 0x2c,\n    0x15, 0x02, 0x69, 0x14, 0xa8, 0x13, 0x02, 0xd4,\n    0x19, 0x42, 0x86, 0x04, 0x68, 0x14, 0x69, 0x14,\n    0x66, 0x14, 0x66, 0x14, 0x02, 0x77, 0x14, 0x42,\n    0x86, 0x02, 0x39, 0x19, 0x42, 0x86, 0x02, 0xd1,\n    0x19, 0xa4, 0x13, 0x02, 0x6e, 0x14, 0x40, 0x86,\n    0x03, 0xd1, 0x19, 0xd2, 0x19, 0xd2, 0x19, 0x02,\n    0x69, 0x14, 0xbb, 0x14, 0x02, 0xd1, 0x19, 0x96,\n    0x86, 0x02, 0x75, 0x95, 0x40, 0x86, 0x04, 0x68,\n    0x14, 0x64, 0x87, 0x8b, 0x14, 0x68, 0x14, 0x02,\n    0xd1, 0x19, 0x3e, 0x13, 0x02, 0xdf, 0x19, 0x40,\n    0x86, 0x02, 0x82, 0x14, 0x40, 0x86, 0x02, 0x44,\n    0x13, 0xeb, 0x17, 0x02, 0xdd, 0x19, 0x42, 0x86,\n    0x03, 0x68, 0x14, 0xaf, 0x19, 0xa1, 0x87, 0x02,\n    0x69, 0x14, 0x80, 0x16, 0x02, 0xa3, 0x16, 0x42,\n    0x86, 0x02, 0x69, 0x14, 0x96, 0x86, 0x02, 0x46,\n    0x16, 0x42, 0x86, 0x02, 0xb6, 0x16, 0xa1, 0x87,\n    0x02, 0x68, 0x14, 0x27, 0x15, 0x02, 0x26, 0x14,\n    0x1b, 0x0b, 0x02, 0xd4, 0x19, 0x40, 0x86, 0x02,\n    0x77, 0x14, 0x40, 0x86, 0x02, 0x39, 0x19, 0x40,\n    0x86, 0x02, 0x37, 0x19, 0x42, 0x86, 0x03, 0x69,\n    0x14, 0x67, 0x14, 0x66, 0x14, 0x03, 0xc3, 0x13,\n    0x42, 0x86, 0xa1, 0x87, 0x02, 0x68, 0x14, 0xbc,\n    0x19, 0x02, 0xd1, 0x19, 0xeb, 0x13, 0x04, 0x69,\n    0x14, 0x69, 0x14, 0x67, 0x14, 0x67, 0x14, 0x02,\n    0xd1, 0x19, 0x08, 0x87, 0x02, 0x68, 0x14, 0xed,\n    0x13, 0x03, 0x69, 0x14, 0xbc, 0x19, 0xa1, 0x87,\n    0x02, 0xdd, 0x19, 0x40, 0x86, 0x02, 0xc3, 0x13,\n    0xa1, 0x87, 0x03, 0x68, 0x14, 0x66, 0x14, 0x66,\n    0x14, 0x03, 0x68, 0x14, 0x69, 0x14, 0x67, 0x14,\n    0x02, 0xa3, 0x16, 0x40, 0x86, 0x02, 0xdb, 0x19,\n    0x42, 0x86, 0x02, 0x68, 0x14, 0xaf, 0x19, 0x02,\n    0x46, 0x16, 0x40, 0x86, 0x02, 0x35, 0x16, 0xab,\n    0x14, 0x02, 0x68, 0x14, 0x95, 0x86, 0x02, 0x42,\n    0x16, 0x95, 0x81, 0x02, 0xc4, 0x13, 0x42, 0x86,\n    0x02, 0x15, 0x14, 0xba, 0x19, 0x03, 0xd1, 0x19,\n    0x1d, 0x19, 0xd1, 0x19, 0x02, 0x69, 0x14, 0x08,\n    0x87, 0x02, 0x69, 0x14, 0x7c, 0x13, 0x02, 0x37,\n    0x19, 0x40, 0x86, 0x02, 0x73, 0x14, 0x42, 0x86,\n    0x02, 0x69, 0x14, 0x2c, 0x15, 0x02, 0xb5, 0x16,\n    0x42, 0x86, 0x02, 0x35, 0x19, 0x42, 0x86, 0x04,\n    0x68, 0x14, 0x69, 0x14, 0x67, 0x14, 0x66, 0x14,\n    0x02, 0x64, 0x87, 0x25, 0x15, 0x02, 0x64, 0x87,\n    0x79, 0x1a, 0x02, 0x68, 0x14, 0xbc, 0x14, 0x03,\n    0xce, 0x19, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x87,\n    0x14, 0x42, 0x86, 0x02, 0x4d, 0x16, 0x42, 0x86,\n    0x04, 0x68, 0x14, 0x68, 0x14, 0x66, 0x14, 0x66,\n    0x14, 0x02, 0xdb, 0x19, 0x40, 0x86, 0x02, 0xd9,\n    0x19, 0x42, 0x86, 0x02, 0xc4, 0x13, 0x40, 0x86,\n    0x02, 0xd1, 0x19, 0xbd, 0x19, 0x02, 0x68, 0x14,\n    0xa4, 0x13, 0x02, 0x3e, 0x19, 0x42, 0x86, 0x02,\n    0xf3, 0x93, 0xa7, 0x86, 0x03, 0x69, 0x14, 0xaf,\n    0x19, 0xa1, 0x87, 0x02, 0xf3, 0x93, 0x08, 0x13,\n    0x02, 0xd1, 0x19, 0xd2, 0x19, 0x02, 0x73, 0x14,\n    0x40, 0x86, 0x02, 0xb5, 0x16, 0x40, 0x86, 0x02,\n    0x35, 0x19, 0x40, 0x86, 0x02, 0x69, 0x14, 0x27,\n    0x15, 0x02, 0xce, 0x19, 0x42, 0x86, 0x02, 0x71,\n    0x14, 0x42, 0x86, 0x02, 0xd1, 0x19, 0x73, 0x13,\n    0x02, 0x68, 0x14, 0x3e, 0x13, 0x02, 0xf4, 0x13,\n    0x20, 0x86, 0x02, 0x87, 0x14, 0x40, 0x86, 0x03,\n    0xb6, 0x16, 0x40, 0x86, 0xa1, 0x87, 0x02, 0x4d,\n    0x16, 0x40, 0x86, 0x02, 0x69, 0x14, 0xbc, 0x19,\n    0x02, 0x4b, 0x16, 0x42, 0x86, 0x02, 0xd9, 0x19,\n    0x40, 0x86, 0x02, 0x3e, 0x19, 0x40, 0x86, 0x02,\n    0x69, 0x14, 0xed, 0x13, 0x02, 0xd7, 0x19, 0x42,\n    0x86, 0x02, 0xb8, 0x19, 0x42, 0x86, 0x03, 0x68,\n    0x14, 0x67, 0x14, 0x66, 0x14, 0x02, 0x3c, 0x19,\n    0x42, 0x86, 0x02, 0x68, 0x14, 0x66, 0x14, 0x03,\n    0x68, 0x14, 0x64, 0x87, 0x68, 0x14, 0x02, 0x69,\n    0x14, 0xaf, 0x19, 0x02, 0xce, 0x19, 0x40, 0x86,\n    0x02, 0x71, 0x14, 0x40, 0x86, 0x02, 0x68, 0x14,\n    0xeb, 0x13, 0x03, 0x68, 0x14, 0xbd, 0x19, 0xa1,\n    0x87, 0x02, 0x6f, 0x14, 0x42, 0x86, 0x04, 0xd1,\n    0x19, 0xd1, 0x19, 0xd2, 0x19, 0xd2, 0x19, 0x02,\n    0x69, 0x14, 0xbc, 0x14, 0x02, 0xcc, 0x93, 0x42,\n    0x86, 0x02, 0x4b, 0x16, 0x40, 0x86, 0x02, 0x26,\n    0x19, 0x42, 0x86, 0x02, 0xd7, 0x19, 0x40, 0x86,\n};\n\n#endif /* CONFIG_ALL_UNICODE */\n/* 71 tables / 36659 bytes, 5 index / 357 bytes */\n"
  },
  {
    "path": "libunicode.c",
    "content": "/*\n * Unicode utilities\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <string.h>\n#include <assert.h>\n\n#include \"cutils.h\"\n#include \"libunicode.h\"\n#include \"libunicode-table.h\"\n\nenum {\n    RUN_TYPE_U,\n    RUN_TYPE_L,\n    RUN_TYPE_UF,\n    RUN_TYPE_LF,\n    RUN_TYPE_UL,\n    RUN_TYPE_LSU,\n    RUN_TYPE_U2L_399_EXT2,\n    RUN_TYPE_UF_D20,\n    RUN_TYPE_UF_D1_EXT,\n    RUN_TYPE_U_EXT,\n    RUN_TYPE_LF_EXT,\n    RUN_TYPE_UF_EXT2,\n    RUN_TYPE_LF_EXT2,\n    RUN_TYPE_UF_EXT3,\n};\n\nstatic int lre_case_conv1(uint32_t c, int conv_type)\n{\n    uint32_t res[LRE_CC_RES_LEN_MAX];\n    lre_case_conv(res, c, conv_type);\n    return res[0];\n}\n\n/* case conversion using the table entry 'idx' with value 'v' */\nstatic int lre_case_conv_entry(uint32_t *res, uint32_t c, int conv_type, uint32_t idx, uint32_t v)\n{\n    uint32_t code, data, type, a, is_lower;\n    is_lower = (conv_type != 0);\n    type = (v >> (32 - 17 - 7 - 4)) & 0xf;\n    data = ((v & 0xf) << 8) | case_conv_table2[idx];\n    code = v >> (32 - 17);\n    switch(type) {\n    case RUN_TYPE_U:\n    case RUN_TYPE_L:\n    case RUN_TYPE_UF:\n    case RUN_TYPE_LF:\n        if (conv_type == (type & 1) ||\n            (type >= RUN_TYPE_UF && conv_type == 2)) {\n            c = c - code + (case_conv_table1[data] >> (32 - 17));\n        }\n        break;\n    case RUN_TYPE_UL:\n        a = c - code;\n        if ((a & 1) != (1 - is_lower))\n            break;\n        c = (a ^ 1) + code;\n        break;\n    case RUN_TYPE_LSU:\n        a = c - code;\n        if (a == 1) {\n            c += 2 * is_lower - 1;\n        } else if (a == (1 - is_lower) * 2) {\n            c += (2 * is_lower - 1) * 2;\n        }\n        break;\n    case RUN_TYPE_U2L_399_EXT2:\n        if (!is_lower) {\n            res[0] = c - code + case_conv_ext[data >> 6];\n            res[1] = 0x399;\n            return 2;\n        } else {\n            c = c - code + case_conv_ext[data & 0x3f];\n        }\n        break;\n    case RUN_TYPE_UF_D20:\n        if (conv_type == 1)\n            break;\n        c = data + (conv_type == 2) * 0x20;\n        break;\n    case RUN_TYPE_UF_D1_EXT:\n        if (conv_type == 1)\n            break;\n        c = case_conv_ext[data] + (conv_type == 2);\n        break;\n    case RUN_TYPE_U_EXT:\n    case RUN_TYPE_LF_EXT:\n        if (is_lower != (type - RUN_TYPE_U_EXT))\n            break;\n        c = case_conv_ext[data];\n        break;\n    case RUN_TYPE_LF_EXT2:\n        if (!is_lower)\n            break;\n        res[0] = c - code + case_conv_ext[data >> 6];\n        res[1] = case_conv_ext[data & 0x3f];\n        return 2;\n    case RUN_TYPE_UF_EXT2:\n        if (conv_type == 1)\n            break;\n        res[0] = c - code + case_conv_ext[data >> 6];\n        res[1] = case_conv_ext[data & 0x3f];\n        if (conv_type == 2) {\n            /* convert to lower */\n            res[0] = lre_case_conv1(res[0], 1);\n            res[1] = lre_case_conv1(res[1], 1);\n        }\n        return 2;\n    default:\n    case RUN_TYPE_UF_EXT3:\n        if (conv_type == 1)\n            break;\n        res[0] = case_conv_ext[data >> 8];\n        res[1] = case_conv_ext[(data >> 4) & 0xf];\n        res[2] = case_conv_ext[data & 0xf];\n        if (conv_type == 2) {\n            /* convert to lower */\n            res[0] = lre_case_conv1(res[0], 1);\n            res[1] = lre_case_conv1(res[1], 1);\n            res[2] = lre_case_conv1(res[2], 1);\n        }\n        return 3;\n    }\n    res[0] = c;\n    return 1;\n}\n\n/* conv_type:\n   0 = to upper\n   1 = to lower\n   2 = case folding (= to lower with modifications)\n*/\nint lre_case_conv(uint32_t *res, uint32_t c, int conv_type)\n{\n    if (c < 128) {\n        if (conv_type) {\n            if (c >= 'A' && c <= 'Z') {\n                c = c - 'A' + 'a';\n            }\n        } else {\n            if (c >= 'a' && c <= 'z') {\n                c = c - 'a' + 'A';\n            }\n        }\n    } else {\n        uint32_t v, code, len;\n        int idx, idx_min, idx_max;\n\n        idx_min = 0;\n        idx_max = countof(case_conv_table1) - 1;\n        while (idx_min <= idx_max) {\n            idx = (unsigned)(idx_max + idx_min) / 2;\n            v = case_conv_table1[idx];\n            code = v >> (32 - 17);\n            len = (v >> (32 - 17 - 7)) & 0x7f;\n            if (c < code) {\n                idx_max = idx - 1;\n            } else if (c >= code + len) {\n                idx_min = idx + 1;\n            } else {\n                return lre_case_conv_entry(res, c, conv_type, idx, v);\n            }\n        }\n    }\n    res[0] = c;\n    return 1;\n}\n\nstatic int lre_case_folding_entry(uint32_t c, uint32_t idx, uint32_t v, BOOL is_unicode)\n{\n    uint32_t res[LRE_CC_RES_LEN_MAX];\n    int len;\n\n    if (is_unicode) {\n        len = lre_case_conv_entry(res, c, 2, idx, v);\n        if (len == 1) {\n            c = res[0];\n        } else {\n            /* handle the few specific multi-character cases (see\n               unicode_gen.c:dump_case_folding_special_cases()) */\n            if (c == 0xfb06) {\n                c = 0xfb05;\n            } else if (c == 0x01fd3) {\n                c = 0x390;\n            } else if (c == 0x01fe3) {\n                c = 0x3b0;\n            }\n        }\n    } else {\n        if (likely(c < 128)) {\n            if (c >= 'a' && c <= 'z')\n                c = c - 'a' + 'A';\n        } else {\n            /* legacy regexp: to upper case if single char >= 128 */\n            len = lre_case_conv_entry(res, c, FALSE, idx, v);\n            if (len == 1 && res[0] >= 128)\n                c = res[0];\n        }\n    }\n    return c;\n}\n\n/* JS regexp specific rules for case folding */\nint lre_canonicalize(uint32_t c, BOOL is_unicode)\n{\n    if (c < 128) {\n        /* fast case */\n        if (is_unicode) {\n            if (c >= 'A' && c <= 'Z') {\n                c = c - 'A' + 'a';\n            }\n        } else {\n            if (c >= 'a' && c <= 'z') {\n                c = c - 'a' + 'A';\n            }\n        }\n    } else {\n        uint32_t v, code, len;\n        int idx, idx_min, idx_max;\n\n        idx_min = 0;\n        idx_max = countof(case_conv_table1) - 1;\n        while (idx_min <= idx_max) {\n            idx = (unsigned)(idx_max + idx_min) / 2;\n            v = case_conv_table1[idx];\n            code = v >> (32 - 17);\n            len = (v >> (32 - 17 - 7)) & 0x7f;\n            if (c < code) {\n                idx_max = idx - 1;\n            } else if (c >= code + len) {\n                idx_min = idx + 1;\n            } else {\n                return lre_case_folding_entry(c, idx, v, is_unicode);\n            }\n        }\n    }\n    return c;\n}\n\nstatic uint32_t get_le24(const uint8_t *ptr)\n{\n    return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16);\n}\n\n#define UNICODE_INDEX_BLOCK_LEN 32\n\n/* return -1 if not in table, otherwise the offset in the block */\nstatic int get_index_pos(uint32_t *pcode, uint32_t c,\n                         const uint8_t *index_table, int index_table_len)\n{\n    uint32_t code, v;\n    int idx_min, idx_max, idx;\n\n    idx_min = 0;\n    v = get_le24(index_table);\n    code = v & ((1 << 21) - 1);\n    if (c < code) {\n        *pcode = 0;\n        return 0;\n    }\n    idx_max = index_table_len - 1;\n    code = get_le24(index_table + idx_max * 3);\n    if (c >= code)\n        return -1;\n    /* invariant: tab[idx_min] <= c < tab2[idx_max] */\n    while ((idx_max - idx_min) > 1) {\n        idx = (idx_max + idx_min) / 2;\n        v = get_le24(index_table + idx * 3);\n        code = v & ((1 << 21) - 1);\n        if (c < code) {\n            idx_max = idx;\n        } else {\n            idx_min = idx;\n        }\n    }\n    v = get_le24(index_table + idx_min * 3);\n    *pcode = v & ((1 << 21) - 1);\n    return (idx_min + 1) * UNICODE_INDEX_BLOCK_LEN + (v >> 21);\n}\n\nstatic BOOL lre_is_in_table(uint32_t c, const uint8_t *table,\n                            const uint8_t *index_table, int index_table_len)\n{\n    uint32_t code, b, bit;\n    int pos;\n    const uint8_t *p;\n\n    pos = get_index_pos(&code, c, index_table, index_table_len);\n    if (pos < 0)\n        return FALSE; /* outside the table */\n    p = table + pos;\n    bit = 0;\n    /* Compressed run length encoding:\n       00..3F: 2 packed lengths: 3-bit + 3-bit\n       40..5F: 5-bits plus extra byte for length\n       60..7F: 5-bits plus 2 extra bytes for length\n       80..FF: 7-bit length\n       lengths must be incremented to get character count\n       Ranges alternate between false and true return value.\n     */\n    for(;;) {\n        b = *p++;\n        if (b < 64) {\n            code += (b >> 3) + 1;\n            if (c < code)\n                return bit;\n            bit ^= 1;\n            code += (b & 7) + 1;\n        } else if (b >= 0x80) {\n            code += b - 0x80 + 1;\n        } else if (b < 0x60) {\n            code += (((b - 0x40) << 8) | p[0]) + 1;\n            p++;\n        } else {\n            code += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1;\n            p += 2;\n        }\n        if (c < code)\n            return bit;\n        bit ^= 1;\n    }\n}\n\nBOOL lre_is_cased(uint32_t c)\n{\n    uint32_t v, code, len;\n    int idx, idx_min, idx_max;\n\n    idx_min = 0;\n    idx_max = countof(case_conv_table1) - 1;\n    while (idx_min <= idx_max) {\n        idx = (unsigned)(idx_max + idx_min) / 2;\n        v = case_conv_table1[idx];\n        code = v >> (32 - 17);\n        len = (v >> (32 - 17 - 7)) & 0x7f;\n        if (c < code) {\n            idx_max = idx - 1;\n        } else if (c >= code + len) {\n            idx_min = idx + 1;\n        } else {\n            return TRUE;\n        }\n    }\n    return lre_is_in_table(c, unicode_prop_Cased1_table,\n                           unicode_prop_Cased1_index,\n                           sizeof(unicode_prop_Cased1_index) / 3);\n}\n\nBOOL lre_is_case_ignorable(uint32_t c)\n{\n    return lre_is_in_table(c, unicode_prop_Case_Ignorable_table,\n                           unicode_prop_Case_Ignorable_index,\n                           sizeof(unicode_prop_Case_Ignorable_index) / 3);\n}\n\n/* character range */\n\nstatic __maybe_unused void cr_dump(CharRange *cr)\n{\n    int i;\n    for(i = 0; i < cr->len; i++)\n        printf(\"%d: 0x%04x\\n\", i, cr->points[i]);\n}\n\nstatic void *cr_default_realloc(void *opaque, void *ptr, size_t size)\n{\n    return realloc(ptr, size);\n}\n\nvoid cr_init(CharRange *cr, void *mem_opaque, DynBufReallocFunc *realloc_func)\n{\n    cr->len = cr->size = 0;\n    cr->points = NULL;\n    cr->mem_opaque = mem_opaque;\n    cr->realloc_func = realloc_func ? realloc_func : cr_default_realloc;\n}\n\nvoid cr_free(CharRange *cr)\n{\n    cr->realloc_func(cr->mem_opaque, cr->points, 0);\n}\n\nint cr_realloc(CharRange *cr, int size)\n{\n    int new_size;\n    uint32_t *new_buf;\n\n    if (size > cr->size) {\n        new_size = max_int(size, cr->size * 3 / 2);\n        new_buf = cr->realloc_func(cr->mem_opaque, cr->points,\n                                   new_size * sizeof(cr->points[0]));\n        if (!new_buf)\n            return -1;\n        cr->points = new_buf;\n        cr->size = new_size;\n    }\n    return 0;\n}\n\nint cr_copy(CharRange *cr, const CharRange *cr1)\n{\n    if (cr_realloc(cr, cr1->len))\n        return -1;\n    memcpy(cr->points, cr1->points, sizeof(cr->points[0]) * cr1->len);\n    cr->len = cr1->len;\n    return 0;\n}\n\n/* merge consecutive intervals and remove empty intervals */\nstatic void cr_compress(CharRange *cr)\n{\n    int i, j, k, len;\n    uint32_t *pt;\n\n    pt = cr->points;\n    len = cr->len;\n    i = 0;\n    j = 0;\n    k = 0;\n    while ((i + 1) < len) {\n        if (pt[i] == pt[i + 1]) {\n            /* empty interval */\n            i += 2;\n        } else {\n            j = i;\n            while ((j + 3) < len && pt[j + 1] == pt[j + 2])\n                j += 2;\n            /* just copy */\n            pt[k] = pt[i];\n            pt[k + 1] = pt[j + 1];\n            k += 2;\n            i = j + 2;\n        }\n    }\n    cr->len = k;\n}\n\n/* union or intersection */\nint cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,\n          const uint32_t *b_pt, int b_len, int op)\n{\n    int a_idx, b_idx, is_in;\n    uint32_t v;\n\n    a_idx = 0;\n    b_idx = 0;\n    for(;;) {\n        /* get one more point from a or b in increasing order */\n        if (a_idx < a_len && b_idx < b_len) {\n            if (a_pt[a_idx] < b_pt[b_idx]) {\n                goto a_add;\n            } else if (a_pt[a_idx] == b_pt[b_idx]) {\n                v = a_pt[a_idx];\n                a_idx++;\n                b_idx++;\n            } else {\n                goto b_add;\n            }\n        } else if (a_idx < a_len) {\n        a_add:\n            v = a_pt[a_idx++];\n        } else if (b_idx < b_len) {\n        b_add:\n            v = b_pt[b_idx++];\n        } else {\n            break;\n        }\n        /* add the point if the in/out status changes */\n        switch(op) {\n        case CR_OP_UNION:\n            is_in = (a_idx & 1) | (b_idx & 1);\n            break;\n        case CR_OP_INTER:\n            is_in = (a_idx & 1) & (b_idx & 1);\n            break;\n        case CR_OP_XOR:\n            is_in = (a_idx & 1) ^ (b_idx & 1);\n            break;\n        case CR_OP_SUB:\n            is_in = (a_idx & 1) & ((b_idx & 1) ^ 1);\n            break;\n        default:\n            abort();\n        }\n        if (is_in != (cr->len & 1)) {\n            if (cr_add_point(cr, v))\n                return -1;\n        }\n    }\n    cr_compress(cr);\n    return 0;\n}\n\nint cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op)\n{\n    CharRange a = *cr;\n    int ret;\n    cr->len = 0;\n    cr->size = 0;\n    cr->points = NULL;\n    ret = cr_op(cr, a.points, a.len, b_pt, b_len, op);\n    cr_free(&a);\n    return ret;\n}\n\nint cr_invert(CharRange *cr)\n{\n    int len;\n    len = cr->len;\n    if (cr_realloc(cr, len + 2))\n        return -1;\n    memmove(cr->points + 1, cr->points, len * sizeof(cr->points[0]));\n    cr->points[0] = 0;\n    cr->points[len + 1] = UINT32_MAX;\n    cr->len = len + 2;\n    cr_compress(cr);\n    return 0;\n}\n\n#define CASE_U (1 << 0)\n#define CASE_L (1 << 1)\n#define CASE_F (1 << 2)\n\n/* use the case conversion table to generate range of characters.\n   CASE_U: set char if modified by uppercasing,\n   CASE_L: set char if modified by lowercasing,\n   CASE_F: set char if modified by case folding,\n */\nstatic int unicode_case1(CharRange *cr, int case_mask)\n{\n#define MR(x) (1 << RUN_TYPE_ ## x)\n    const uint32_t tab_run_mask[3] = {\n        MR(U) | MR(UF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(UF_D20) |\n        MR(UF_D1_EXT) | MR(U_EXT) | MR(UF_EXT2) | MR(UF_EXT3),\n\n        MR(L) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2),\n\n        MR(UF) | MR(LF) | MR(UL) | MR(LSU) | MR(U2L_399_EXT2) | MR(LF_EXT) | MR(LF_EXT2) | MR(UF_D20) | MR(UF_D1_EXT) | MR(LF_EXT) | MR(UF_EXT2) | MR(UF_EXT3),\n    };\n#undef MR\n    uint32_t mask, v, code, type, len, i, idx;\n\n    if (case_mask == 0)\n        return 0;\n    mask = 0;\n    for(i = 0; i < 3; i++) {\n        if ((case_mask >> i) & 1)\n            mask |= tab_run_mask[i];\n    }\n    for(idx = 0; idx < countof(case_conv_table1); idx++) {\n        v = case_conv_table1[idx];\n        type = (v >> (32 - 17 - 7 - 4)) & 0xf;\n        code = v >> (32 - 17);\n        len = (v >> (32 - 17 - 7)) & 0x7f;\n        if ((mask >> type) & 1) {\n            //            printf(\"%d: type=%d %04x %04x\\n\", idx, type, code, code + len - 1);\n            switch(type) {\n            case RUN_TYPE_UL:\n                if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))\n                    goto def_case;\n                code += ((case_mask & CASE_U) != 0);\n                for(i = 0; i < len; i += 2) {\n                    if (cr_add_interval(cr, code + i, code + i + 1))\n                        return -1;\n                }\n                break;\n            case RUN_TYPE_LSU:\n                if ((case_mask & CASE_U) && (case_mask & (CASE_L | CASE_F)))\n                    goto def_case;\n                if (!(case_mask & CASE_U)) {\n                    if (cr_add_interval(cr, code, code + 1))\n                        return -1;\n                }\n                if (cr_add_interval(cr, code + 1, code + 2))\n                    return -1;\n                if (case_mask & CASE_U) {\n                    if (cr_add_interval(cr, code + 2, code + 3))\n                        return -1;\n                }\n                break;\n            default:\n            def_case:\n                if (cr_add_interval(cr, code, code + len))\n                    return -1;\n                break;\n            }\n        }\n    }\n    return 0;\n}\n\nstatic int point_cmp(const void *p1, const void *p2, void *arg)\n{\n    uint32_t v1 = *(uint32_t *)p1;\n    uint32_t v2 = *(uint32_t *)p2;\n    return (v1 > v2) - (v1 < v2);\n}\n\nstatic void cr_sort_and_remove_overlap(CharRange *cr)\n{\n    uint32_t start, end, start1, end1, i, j;\n\n    /* the resulting ranges are not necessarily sorted and may overlap */\n    rqsort(cr->points, cr->len / 2, sizeof(cr->points[0]) * 2, point_cmp, NULL);\n    j = 0;\n    for(i = 0; i < cr->len; ) {\n        start = cr->points[i];\n        end = cr->points[i + 1];\n        i += 2;\n        while (i < cr->len) {\n            start1 = cr->points[i];\n            end1 = cr->points[i + 1];\n            if (start1 > end) {\n                /* |------|\n                 *           |-------| */\n                break;\n            } else if (end1 <= end) {\n                /* |------|\n                 *    |--| */\n                i += 2;\n            } else {\n                /* |------|\n                 *     |-------| */\n                end = end1;\n                i += 2;\n            }\n        }\n        cr->points[j] = start;\n        cr->points[j + 1] = end;\n        j += 2;\n    }\n    cr->len = j;\n}\n\n/* canonicalize a character set using the JS regex case folding rules\n   (see lre_canonicalize()) */\nint cr_regexp_canonicalize(CharRange *cr, BOOL is_unicode)\n{\n    CharRange cr_inter, cr_mask, cr_result, cr_sub;\n    uint32_t v, code, len, i, idx, start, end, c, d_start, d_end, d;\n\n    cr_init(&cr_mask, cr->mem_opaque, cr->realloc_func);\n    cr_init(&cr_inter, cr->mem_opaque, cr->realloc_func);\n    cr_init(&cr_result, cr->mem_opaque, cr->realloc_func);\n    cr_init(&cr_sub, cr->mem_opaque, cr->realloc_func);\n\n    if (unicode_case1(&cr_mask, is_unicode ? CASE_F : CASE_U))\n        goto fail;\n    if (cr_op(&cr_inter, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))\n        goto fail;\n\n    if (cr_invert(&cr_mask))\n        goto fail;\n    if (cr_op(&cr_sub, cr_mask.points, cr_mask.len, cr->points, cr->len, CR_OP_INTER))\n        goto fail;\n\n    /* cr_inter = cr & cr_mask */\n    /* cr_sub = cr & ~cr_mask */\n\n    /* use the case conversion table to compute the result */\n    d_start = -1;\n    d_end = -1;\n    idx = 0;\n    v = case_conv_table1[idx];\n    code = v >> (32 - 17);\n    len = (v >> (32 - 17 - 7)) & 0x7f;\n    for(i = 0; i < cr_inter.len; i += 2) {\n        start = cr_inter.points[i];\n        end = cr_inter.points[i + 1];\n\n        for(c = start; c < end; c++) {\n            for(;;) {\n                if (c >= code && c < code + len)\n                    break;\n                idx++;\n                assert(idx < countof(case_conv_table1));\n                v = case_conv_table1[idx];\n                code = v >> (32 - 17);\n                len = (v >> (32 - 17 - 7)) & 0x7f;\n            }\n            d = lre_case_folding_entry(c, idx, v, is_unicode);\n            /* try to merge with the current interval */\n            if (d_start == -1) {\n                d_start = d;\n                d_end = d + 1;\n            } else if (d_end == d) {\n                d_end++;\n            } else {\n                cr_add_interval(&cr_result, d_start, d_end);\n                d_start = d;\n                d_end = d + 1;\n            }\n        }\n    }\n    if (d_start != -1) {\n        if (cr_add_interval(&cr_result, d_start, d_end))\n            goto fail;\n    }\n\n    /* the resulting ranges are not necessarily sorted and may overlap */\n    cr_sort_and_remove_overlap(&cr_result);\n\n    /* or with the character not affected by the case folding */\n    cr->len = 0;\n    if (cr_op(cr, cr_result.points, cr_result.len, cr_sub.points, cr_sub.len, CR_OP_UNION))\n        goto fail;\n\n    cr_free(&cr_inter);\n    cr_free(&cr_mask);\n    cr_free(&cr_result);\n    cr_free(&cr_sub);\n    return 0;\n fail:\n    cr_free(&cr_inter);\n    cr_free(&cr_mask);\n    cr_free(&cr_result);\n    cr_free(&cr_sub);\n    return -1;\n}\n\n#ifdef CONFIG_ALL_UNICODE\n\nBOOL lre_is_id_start(uint32_t c)\n{\n    return lre_is_in_table(c, unicode_prop_ID_Start_table,\n                           unicode_prop_ID_Start_index,\n                           sizeof(unicode_prop_ID_Start_index) / 3);\n}\n\nBOOL lre_is_id_continue(uint32_t c)\n{\n    return lre_is_id_start(c) ||\n        lre_is_in_table(c, unicode_prop_ID_Continue1_table,\n                        unicode_prop_ID_Continue1_index,\n                        sizeof(unicode_prop_ID_Continue1_index) / 3);\n}\n\n#define UNICODE_DECOMP_LEN_MAX 18\n\ntypedef enum {\n    DECOMP_TYPE_C1, /* 16 bit char */\n    DECOMP_TYPE_L1, /* 16 bit char table */\n    DECOMP_TYPE_L2,\n    DECOMP_TYPE_L3,\n    DECOMP_TYPE_L4,\n    DECOMP_TYPE_L5, /* XXX: not used */\n    DECOMP_TYPE_L6, /* XXX: could remove */\n    DECOMP_TYPE_L7, /* XXX: could remove */\n    DECOMP_TYPE_LL1, /* 18 bit char table */\n    DECOMP_TYPE_LL2,\n    DECOMP_TYPE_S1, /* 8 bit char table */\n    DECOMP_TYPE_S2,\n    DECOMP_TYPE_S3,\n    DECOMP_TYPE_S4,\n    DECOMP_TYPE_S5,\n    DECOMP_TYPE_I1, /* increment 16 bit char value */\n    DECOMP_TYPE_I2_0,\n    DECOMP_TYPE_I2_1,\n    DECOMP_TYPE_I3_1,\n    DECOMP_TYPE_I3_2,\n    DECOMP_TYPE_I4_1,\n    DECOMP_TYPE_I4_2,\n    DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */\n    DECOMP_TYPE_B2,\n    DECOMP_TYPE_B3,\n    DECOMP_TYPE_B4,\n    DECOMP_TYPE_B5,\n    DECOMP_TYPE_B6,\n    DECOMP_TYPE_B7,\n    DECOMP_TYPE_B8,\n    DECOMP_TYPE_B18,\n    DECOMP_TYPE_LS2,\n    DECOMP_TYPE_PAT3,\n    DECOMP_TYPE_S2_UL,\n    DECOMP_TYPE_LS2_UL,\n} DecompTypeEnum;\n\nstatic uint32_t unicode_get_short_code(uint32_t c)\n{\n    static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 };\n\n    if (c < 0x80)\n        return c;\n    else if (c < 0x80 + 0x50)\n        return c - 0x80 + 0x300;\n    else\n        return unicode_short_table[c - 0x80 - 0x50];\n}\n\nstatic uint32_t unicode_get_lower_simple(uint32_t c)\n{\n    if (c < 0x100 || (c >= 0x410 && c <= 0x42f))\n        c += 0x20;\n    else\n        c++;\n    return c;\n}\n\nstatic uint16_t unicode_get16(const uint8_t *p)\n{\n    return p[0] | (p[1] << 8);\n}\n\nstatic int unicode_decomp_entry(uint32_t *res, uint32_t c,\n                                int idx, uint32_t code, uint32_t len,\n                                uint32_t type)\n{\n    uint32_t c1;\n    int l, i, p;\n    const uint8_t *d;\n\n    if (type == DECOMP_TYPE_C1) {\n        res[0] = unicode_decomp_table2[idx];\n        return 1;\n    } else {\n        d = unicode_decomp_data + unicode_decomp_table2[idx];\n        switch(type) {\n        case DECOMP_TYPE_L1:\n        case DECOMP_TYPE_L2:\n        case DECOMP_TYPE_L3:\n        case DECOMP_TYPE_L4:\n        case DECOMP_TYPE_L5:\n        case DECOMP_TYPE_L6:\n        case DECOMP_TYPE_L7:\n            l = type - DECOMP_TYPE_L1 + 1;\n            d += (c - code) * l * 2;\n            for(i = 0; i < l; i++) {\n                if ((res[i] = unicode_get16(d + 2 * i)) == 0)\n                    return 0;\n            }\n            return l;\n        case DECOMP_TYPE_LL1:\n        case DECOMP_TYPE_LL2:\n            {\n                uint32_t k, p;\n                l = type - DECOMP_TYPE_LL1 + 1;\n                k = (c - code) * l;\n                p = len * l * 2;\n                for(i = 0; i < l; i++) {\n                    c1 = unicode_get16(d + 2 * k) |\n                        (((d[p + (k / 4)] >> ((k % 4) * 2)) & 3) << 16);\n                    if (!c1)\n                        return 0;\n                    res[i] = c1;\n                    k++;\n                }\n            }\n            return l;\n        case DECOMP_TYPE_S1:\n        case DECOMP_TYPE_S2:\n        case DECOMP_TYPE_S3:\n        case DECOMP_TYPE_S4:\n        case DECOMP_TYPE_S5:\n            l = type - DECOMP_TYPE_S1 + 1;\n            d += (c - code) * l;\n            for(i = 0; i < l; i++) {\n                if ((res[i] = unicode_get_short_code(d[i])) == 0)\n                    return 0;\n            }\n            return l;\n        case DECOMP_TYPE_I1:\n            l = 1;\n            p = 0;\n            goto decomp_type_i;\n        case DECOMP_TYPE_I2_0:\n        case DECOMP_TYPE_I2_1:\n        case DECOMP_TYPE_I3_1:\n        case DECOMP_TYPE_I3_2:\n        case DECOMP_TYPE_I4_1:\n        case DECOMP_TYPE_I4_2:\n            l = 2 + ((type - DECOMP_TYPE_I2_0) >> 1);\n            p = ((type - DECOMP_TYPE_I2_0) & 1) + (l > 2);\n        decomp_type_i:\n            for(i = 0; i < l; i++) {\n                c1 = unicode_get16(d + 2 * i);\n                if (i == p)\n                    c1 += c - code;\n                res[i] = c1;\n            }\n            return l;\n        case DECOMP_TYPE_B18:\n            l = 18;\n            goto decomp_type_b;\n        case DECOMP_TYPE_B1:\n        case DECOMP_TYPE_B2:\n        case DECOMP_TYPE_B3:\n        case DECOMP_TYPE_B4:\n        case DECOMP_TYPE_B5:\n        case DECOMP_TYPE_B6:\n        case DECOMP_TYPE_B7:\n        case DECOMP_TYPE_B8:\n            l = type - DECOMP_TYPE_B1 + 1;\n        decomp_type_b:\n            {\n                uint32_t c_min;\n                c_min = unicode_get16(d);\n                d += 2 + (c - code) * l;\n                for(i = 0; i < l; i++) {\n                    c1 = d[i];\n                    if (c1 == 0xff)\n                        c1 = 0x20;\n                    else\n                        c1 += c_min;\n                    res[i] = c1;\n                }\n            }\n            return l;\n        case DECOMP_TYPE_LS2:\n            d += (c - code) * 3;\n            if (!(res[0] = unicode_get16(d)))\n                return 0;\n            res[1] = unicode_get_short_code(d[2]);\n            return 2;\n        case DECOMP_TYPE_PAT3:\n            res[0] = unicode_get16(d);\n            res[2] = unicode_get16(d + 2);\n            d += 4 + (c - code) * 2;\n            res[1] = unicode_get16(d);\n            return 3;\n        case DECOMP_TYPE_S2_UL:\n        case DECOMP_TYPE_LS2_UL:\n            c1 = c - code;\n            if (type == DECOMP_TYPE_S2_UL) {\n                d += c1 & ~1;\n                c = unicode_get_short_code(*d);\n                d++;\n            } else {\n                d += (c1 >> 1) * 3;\n                c = unicode_get16(d);\n                d += 2;\n            }\n            if (c1 & 1)\n                c = unicode_get_lower_simple(c);\n            res[0] = c;\n            res[1] = unicode_get_short_code(*d);\n            return 2;\n        }\n    }\n    return 0;\n}\n\n\n/* return the length of the decomposition (length <=\n   UNICODE_DECOMP_LEN_MAX) or 0 if no decomposition */\nstatic int unicode_decomp_char(uint32_t *res, uint32_t c, BOOL is_compat1)\n{\n    uint32_t v, type, is_compat, code, len;\n    int idx_min, idx_max, idx;\n\n    idx_min = 0;\n    idx_max = countof(unicode_decomp_table1) - 1;\n    while (idx_min <= idx_max) {\n        idx = (idx_max + idx_min) / 2;\n        v = unicode_decomp_table1[idx];\n        code = v >> (32 - 18);\n        len = (v >> (32 - 18 - 7)) & 0x7f;\n        //        printf(\"idx=%d code=%05x len=%d\\n\", idx, code, len);\n        if (c < code) {\n            idx_max = idx - 1;\n        } else if (c >= code + len) {\n            idx_min = idx + 1;\n        } else {\n            is_compat = v & 1;\n            if (is_compat1 < is_compat)\n                break;\n            type = (v >> (32 - 18 - 7 - 6)) & 0x3f;\n            return unicode_decomp_entry(res, c, idx, code, len, type);\n        }\n    }\n    return 0;\n}\n\n/* return 0 if no pair found */\nstatic int unicode_compose_pair(uint32_t c0, uint32_t c1)\n{\n    uint32_t code, len, type, v, idx1, d_idx, d_offset, ch;\n    int idx_min, idx_max, idx, d;\n    uint32_t pair[2];\n\n    idx_min = 0;\n    idx_max = countof(unicode_comp_table) - 1;\n    while (idx_min <= idx_max) {\n        idx = (idx_max + idx_min) / 2;\n        idx1 = unicode_comp_table[idx];\n\n        /* idx1 represent an entry of the decomposition table */\n        d_idx = idx1 >> 6;\n        d_offset = idx1 & 0x3f;\n        v = unicode_decomp_table1[d_idx];\n        code = v >> (32 - 18);\n        len = (v >> (32 - 18 - 7)) & 0x7f;\n        type = (v >> (32 - 18 - 7 - 6)) & 0x3f;\n        ch = code + d_offset;\n        unicode_decomp_entry(pair, ch, d_idx, code, len, type);\n        d = c0 - pair[0];\n        if (d == 0)\n            d = c1 - pair[1];\n        if (d < 0) {\n            idx_max = idx - 1;\n        } else if (d > 0) {\n            idx_min = idx + 1;\n        } else {\n            return ch;\n        }\n    }\n    return 0;\n}\n\n/* return the combining class of character c (between 0 and 255) */\nstatic int unicode_get_cc(uint32_t c)\n{\n    uint32_t code, n, type, cc, c1, b;\n    int pos;\n    const uint8_t *p;\n\n    pos = get_index_pos(&code, c,\n                        unicode_cc_index, sizeof(unicode_cc_index) / 3);\n    if (pos < 0)\n        return 0;\n    p = unicode_cc_table + pos;\n    /* Compressed run length encoding:\n       - 2 high order bits are combining class type\n       -         0:0, 1:230, 2:extra byte linear progression, 3:extra byte\n       - 00..2F: range length (add 1)\n       - 30..37: 3-bit range-length + 1 extra byte\n       - 38..3F: 3-bit range-length + 2 extra byte\n     */\n    for(;;) {\n        b = *p++;\n        type = b >> 6;\n        n = b & 0x3f;\n        if (n < 48) {\n        } else if (n < 56) {\n            n = (n - 48) << 8;\n            n |= *p++;\n            n += 48;\n        } else {\n            n = (n - 56) << 8;\n            n |= *p++ << 8;\n            n |= *p++;\n            n += 48 + (1 << 11);\n        }\n        if (type <= 1)\n            p++;\n        c1 = code + n + 1;\n        if (c < c1) {\n            switch(type) {\n            case 0:\n                cc = p[-1];\n                break;\n            case 1:\n                cc = p[-1] + c - code;\n                break;\n            case 2:\n                cc = 0;\n                break;\n            default:\n            case 3:\n                cc = 230;\n                break;\n            }\n            return cc;\n        }\n        code = c1;\n    }\n}\n\nstatic void sort_cc(int *buf, int len)\n{\n    int i, j, k, cc, cc1, start, ch1;\n\n    for(i = 0; i < len; i++) {\n        cc = unicode_get_cc(buf[i]);\n        if (cc != 0) {\n            start = i;\n            j = i + 1;\n            while (j < len) {\n                ch1 = buf[j];\n                cc1 = unicode_get_cc(ch1);\n                if (cc1 == 0)\n                    break;\n                k = j - 1;\n                while (k >= start) {\n                    if (unicode_get_cc(buf[k]) <= cc1)\n                        break;\n                    buf[k + 1] = buf[k];\n                    k--;\n                }\n                buf[k + 1] = ch1;\n                j++;\n            }\n#if 0\n            printf(\"cc:\");\n            for(k = start; k < j; k++) {\n                printf(\" %3d\", unicode_get_cc(buf[k]));\n            }\n            printf(\"\\n\");\n#endif\n            i = j;\n        }\n    }\n}\n\nstatic void to_nfd_rec(DynBuf *dbuf,\n                       const int *src, int src_len, int is_compat)\n{\n    uint32_t c, v;\n    int i, l;\n    uint32_t res[UNICODE_DECOMP_LEN_MAX];\n\n    for(i = 0; i < src_len; i++) {\n        c = src[i];\n        if (c >= 0xac00 && c < 0xd7a4) {\n            /* Hangul decomposition */\n            c -= 0xac00;\n            dbuf_put_u32(dbuf, 0x1100 + c / 588);\n            dbuf_put_u32(dbuf, 0x1161 + (c % 588) / 28);\n            v = c % 28;\n            if (v != 0)\n                dbuf_put_u32(dbuf, 0x11a7 + v);\n        } else {\n            l = unicode_decomp_char(res, c, is_compat);\n            if (l) {\n                to_nfd_rec(dbuf, (int *)res, l, is_compat);\n            } else {\n                dbuf_put_u32(dbuf, c);\n            }\n        }\n    }\n}\n\n/* return 0 if not found */\nstatic int compose_pair(uint32_t c0, uint32_t c1)\n{\n    /* Hangul composition */\n    if (c0 >= 0x1100 && c0 < 0x1100 + 19 &&\n        c1 >= 0x1161 && c1 < 0x1161 + 21) {\n        return 0xac00 + (c0 - 0x1100) * 588 + (c1 - 0x1161) * 28;\n    } else if (c0 >= 0xac00 && c0 < 0xac00 + 11172 &&\n               (c0 - 0xac00) % 28 == 0 &&\n               c1 >= 0x11a7 && c1 < 0x11a7 + 28) {\n        return c0 + c1 - 0x11a7;\n    } else {\n        return unicode_compose_pair(c0, c1);\n    }\n}\n\nint unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,\n                      UnicodeNormalizationEnum n_type,\n                      void *opaque, DynBufReallocFunc *realloc_func)\n{\n    int *buf, buf_len, i, p, starter_pos, cc, last_cc, out_len;\n    BOOL is_compat;\n    DynBuf dbuf_s, *dbuf = &dbuf_s;\n\n    is_compat = n_type >> 1;\n\n    dbuf_init2(dbuf, opaque, realloc_func);\n    if (dbuf_claim(dbuf, sizeof(int) * src_len))\n        goto fail;\n\n    /* common case: latin1 is unaffected by NFC */\n    if (n_type == UNICODE_NFC) {\n        for(i = 0; i < src_len; i++) {\n            if (src[i] >= 0x100)\n                goto not_latin1;\n        }\n        buf = (int *)dbuf->buf;\n        memcpy(buf, src, src_len * sizeof(int));\n        *pdst = (uint32_t *)buf;\n        return src_len;\n    not_latin1: ;\n    }\n\n    to_nfd_rec(dbuf, (const int *)src, src_len, is_compat);\n    if (dbuf_error(dbuf)) {\n    fail:\n        *pdst = NULL;\n        return -1;\n    }\n    buf = (int *)dbuf->buf;\n    buf_len = dbuf->size / sizeof(int);\n\n    sort_cc(buf, buf_len);\n\n    if (buf_len <= 1 || (n_type & 1) != 0) {\n        /* NFD / NFKD */\n        *pdst = (uint32_t *)buf;\n        return buf_len;\n    }\n\n    i = 1;\n    out_len = 1;\n    while (i < buf_len) {\n        /* find the starter character and test if it is blocked from\n           the character at 'i' */\n        last_cc = unicode_get_cc(buf[i]);\n        starter_pos = out_len - 1;\n        while (starter_pos >= 0) {\n            cc = unicode_get_cc(buf[starter_pos]);\n            if (cc == 0)\n                break;\n            if (cc >= last_cc)\n                goto next;\n            last_cc = 256;\n            starter_pos--;\n        }\n        if (starter_pos >= 0 &&\n            (p = compose_pair(buf[starter_pos], buf[i])) != 0) {\n            buf[starter_pos] = p;\n            i++;\n        } else {\n        next:\n            buf[out_len++] = buf[i++];\n        }\n    }\n    *pdst = (uint32_t *)buf;\n    return out_len;\n}\n\n/* char ranges for various unicode properties */\n\nstatic int unicode_find_name(const char *name_table, const char *name)\n{\n    const char *p, *r;\n    int pos;\n    size_t name_len, len;\n\n    p = name_table;\n    pos = 0;\n    name_len = strlen(name);\n    while (*p) {\n        for(;;) {\n            r = strchr(p, ',');\n            if (!r)\n                len = strlen(p);\n            else\n                len = r - p;\n            if (len == name_len && !memcmp(p, name, name_len))\n                return pos;\n            p += len + 1;\n            if (!r)\n                break;\n        }\n        pos++;\n    }\n    return -1;\n}\n\n/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2\n   if not found */\nint unicode_script(CharRange *cr,\n                   const char *script_name, BOOL is_ext)\n{\n    int script_idx;\n    const uint8_t *p, *p_end;\n    uint32_t c, c1, b, n, v, v_len, i, type;\n    CharRange cr1_s, *cr1;\n    CharRange cr2_s, *cr2 = &cr2_s;\n    BOOL is_common;\n\n    script_idx = unicode_find_name(unicode_script_name_table, script_name);\n    if (script_idx < 0)\n        return -2;\n\n    is_common = (script_idx == UNICODE_SCRIPT_Common ||\n                 script_idx == UNICODE_SCRIPT_Inherited);\n    if (is_ext) {\n        cr1 = &cr1_s;\n        cr_init(cr1, cr->mem_opaque, cr->realloc_func);\n        cr_init(cr2, cr->mem_opaque, cr->realloc_func);\n    } else {\n        cr1 = cr;\n    }\n\n    p = unicode_script_table;\n    p_end = unicode_script_table + countof(unicode_script_table);\n    c = 0;\n    while (p < p_end) {\n        b = *p++;\n        type = b >> 7;\n        n = b & 0x7f;\n        if (n < 96) {\n        } else if (n < 112) {\n            n = (n - 96) << 8;\n            n |= *p++;\n            n += 96;\n        } else {\n            n = (n - 112) << 16;\n            n |= *p++ << 8;\n            n |= *p++;\n            n += 96 + (1 << 12);\n        }\n        c1 = c + n + 1;\n        if (type != 0) {\n            v = *p++;\n            if (v == script_idx || script_idx == UNICODE_SCRIPT_Unknown) {\n                if (cr_add_interval(cr1, c, c1))\n                    goto fail;\n            }\n        }\n        c = c1;\n    }\n    if (script_idx == UNICODE_SCRIPT_Unknown) {\n        /* Unknown is all the characters outside scripts */\n        if (cr_invert(cr1))\n            goto fail;\n    }\n\n    if (is_ext) {\n        /* add the script extensions */\n        p = unicode_script_ext_table;\n        p_end = unicode_script_ext_table + countof(unicode_script_ext_table);\n        c = 0;\n        while (p < p_end) {\n            b = *p++;\n            if (b < 128) {\n                n = b;\n            } else if (b < 128 + 64) {\n                n = (b - 128) << 8;\n                n |= *p++;\n                n += 128;\n            } else {\n                n = (b - 128 - 64) << 16;\n                n |= *p++ << 8;\n                n |= *p++;\n                n += 128 + (1 << 14);\n            }\n            c1 = c + n + 1;\n            v_len = *p++;\n            if (is_common) {\n                if (v_len != 0) {\n                    if (cr_add_interval(cr2, c, c1))\n                        goto fail;\n                }\n            } else {\n                for(i = 0; i < v_len; i++) {\n                    if (p[i] == script_idx) {\n                        if (cr_add_interval(cr2, c, c1))\n                            goto fail;\n                        break;\n                    }\n                }\n            }\n            p += v_len;\n            c = c1;\n        }\n        if (is_common) {\n            /* remove all the characters with script extensions */\n            if (cr_invert(cr2))\n                goto fail;\n            if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len,\n                      CR_OP_INTER))\n                goto fail;\n        } else {\n            if (cr_op(cr, cr1->points, cr1->len, cr2->points, cr2->len,\n                      CR_OP_UNION))\n                goto fail;\n        }\n        cr_free(cr1);\n        cr_free(cr2);\n    }\n    return 0;\n fail:\n    if (is_ext) {\n        cr_free(cr1);\n        cr_free(cr2);\n    }\n    goto fail;\n}\n\n#define M(id) (1U << UNICODE_GC_ ## id)\n\nstatic int unicode_general_category1(CharRange *cr, uint32_t gc_mask)\n{\n    const uint8_t *p, *p_end;\n    uint32_t c, c0, b, n, v;\n\n    p = unicode_gc_table;\n    p_end = unicode_gc_table + countof(unicode_gc_table);\n    c = 0;\n    /* Compressed range encoding:\n       initial byte:\n       bits 0..4: category number (special case 31)\n       bits 5..7: range length (add 1)\n       special case bits 5..7 == 7: read an extra byte\n       - 00..7F: range length (add 7 + 1)\n       - 80..BF: 6-bits plus extra byte for range length (add 7 + 128)\n       - C0..FF: 6-bits plus 2 extra bytes for range length (add 7 + 128 + 16384)\n     */\n    while (p < p_end) {\n        b = *p++;\n        n = b >> 5;\n        v = b & 0x1f;\n        if (n == 7) {\n            n = *p++;\n            if (n < 128) {\n                n += 7;\n            } else if (n < 128 + 64) {\n                n = (n - 128) << 8;\n                n |= *p++;\n                n += 7 + 128;\n            } else {\n                n = (n - 128 - 64) << 16;\n                n |= *p++ << 8;\n                n |= *p++;\n                n += 7 + 128 + (1 << 14);\n            }\n        }\n        c0 = c;\n        c += n + 1;\n        if (v == 31) {\n            /* run of Lu / Ll */\n            b = gc_mask & (M(Lu) | M(Ll));\n            if (b != 0) {\n                if (b == (M(Lu) | M(Ll))) {\n                    goto add_range;\n                } else {\n                    c0 += ((gc_mask & M(Ll)) != 0);\n                    for(; c0 < c; c0 += 2) {\n                        if (cr_add_interval(cr, c0, c0 + 1))\n                            return -1;\n                    }\n                }\n            }\n        } else if ((gc_mask >> v) & 1) {\n        add_range:\n            if (cr_add_interval(cr, c0, c))\n                return -1;\n        }\n    }\n    return 0;\n}\n\nstatic int unicode_prop1(CharRange *cr, int prop_idx)\n{\n    const uint8_t *p, *p_end;\n    uint32_t c, c0, b, bit;\n\n    p = unicode_prop_table[prop_idx];\n    p_end = p + unicode_prop_len_table[prop_idx];\n    c = 0;\n    bit = 0;\n    /* Compressed range encoding:\n       00..3F: 2 packed lengths: 3-bit + 3-bit\n       40..5F: 5-bits plus extra byte for length\n       60..7F: 5-bits plus 2 extra bytes for length\n       80..FF: 7-bit length\n       lengths must be incremented to get character count\n       Ranges alternate between false and true return value.\n     */\n    while (p < p_end) {\n        c0 = c;\n        b = *p++;\n        if (b < 64) {\n            c += (b >> 3) + 1;\n            if (bit)  {\n                if (cr_add_interval(cr, c0, c))\n                    return -1;\n            }\n            bit ^= 1;\n            c0 = c;\n            c += (b & 7) + 1;\n        } else if (b >= 0x80) {\n            c += b - 0x80 + 1;\n        } else if (b < 0x60) {\n            c += (((b - 0x40) << 8) | p[0]) + 1;\n            p++;\n        } else {\n            c += (((b - 0x60) << 16) | (p[0] << 8) | p[1]) + 1;\n            p += 2;\n        }\n        if (bit)  {\n            if (cr_add_interval(cr, c0, c))\n                return -1;\n        }\n        bit ^= 1;\n    }\n    return 0;\n}\n\ntypedef enum {\n    POP_GC,\n    POP_PROP,\n    POP_CASE,\n    POP_UNION,\n    POP_INTER,\n    POP_XOR,\n    POP_INVERT,\n    POP_END,\n} PropOPEnum;\n\n#define POP_STACK_LEN_MAX 4\n\nstatic int unicode_prop_ops(CharRange *cr, ...)\n{\n    va_list ap;\n    CharRange stack[POP_STACK_LEN_MAX];\n    int stack_len, op, ret, i;\n    uint32_t a;\n\n    va_start(ap, cr);\n    stack_len = 0;\n    for(;;) {\n        op = va_arg(ap, int);\n        switch(op) {\n        case POP_GC:\n            assert(stack_len < POP_STACK_LEN_MAX);\n            a = va_arg(ap, int);\n            cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);\n            if (unicode_general_category1(&stack[stack_len - 1], a))\n                goto fail;\n            break;\n        case POP_PROP:\n            assert(stack_len < POP_STACK_LEN_MAX);\n            a = va_arg(ap, int);\n            cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);\n            if (unicode_prop1(&stack[stack_len - 1], a))\n                goto fail;\n            break;\n        case POP_CASE:\n            assert(stack_len < POP_STACK_LEN_MAX);\n            a = va_arg(ap, int);\n            cr_init(&stack[stack_len++], cr->mem_opaque, cr->realloc_func);\n            if (unicode_case1(&stack[stack_len - 1], a))\n                goto fail;\n            break;\n        case POP_UNION:\n        case POP_INTER:\n        case POP_XOR:\n            {\n                CharRange *cr1, *cr2, *cr3;\n                assert(stack_len >= 2);\n                assert(stack_len < POP_STACK_LEN_MAX);\n                cr1 = &stack[stack_len - 2];\n                cr2 = &stack[stack_len - 1];\n                cr3 = &stack[stack_len++];\n                cr_init(cr3, cr->mem_opaque, cr->realloc_func);\n                /* CR_OP_XOR may be used here */\n                if (cr_op(cr3, cr1->points, cr1->len,\n                          cr2->points, cr2->len, op - POP_UNION + CR_OP_UNION))\n                    goto fail;\n                cr_free(cr1);\n                cr_free(cr2);\n                *cr1 = *cr3;\n                stack_len -= 2;\n            }\n            break;\n        case POP_INVERT:\n            assert(stack_len >= 1);\n            if (cr_invert(&stack[stack_len - 1]))\n                goto fail;\n            break;\n        case POP_END:\n            goto done;\n        default:\n            abort();\n        }\n    }\n done:\n    assert(stack_len == 1);\n    ret = cr_copy(cr, &stack[0]);\n    cr_free(&stack[0]);\n    return ret;\n fail:\n    for(i = 0; i < stack_len; i++)\n        cr_free(&stack[i]);\n    return -1;\n}\n\nstatic const uint32_t unicode_gc_mask_table[] = {\n    M(Lu) | M(Ll) | M(Lt), /* LC */\n    M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo), /* L */\n    M(Mn) | M(Mc) | M(Me), /* M */\n    M(Nd) | M(Nl) | M(No), /* N */\n    M(Sm) | M(Sc) | M(Sk) | M(So), /* S */\n    M(Pc) | M(Pd) | M(Ps) | M(Pe) | M(Pi) | M(Pf) | M(Po), /* P */\n    M(Zs) | M(Zl) | M(Zp), /* Z */\n    M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn), /* C */\n};\n\n/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2\n   if not found */\nint unicode_general_category(CharRange *cr, const char *gc_name)\n{\n    int gc_idx;\n    uint32_t gc_mask;\n\n    gc_idx = unicode_find_name(unicode_gc_name_table, gc_name);\n    if (gc_idx < 0)\n        return -2;\n    if (gc_idx <= UNICODE_GC_Co) {\n        gc_mask = (uint64_t)1 << gc_idx;\n    } else {\n        gc_mask = unicode_gc_mask_table[gc_idx - UNICODE_GC_LC];\n    }\n    return unicode_general_category1(cr, gc_mask);\n}\n\n\n/* 'cr' must be initialized and empty. Return 0 if OK, -1 if error, -2\n   if not found */\nint unicode_prop(CharRange *cr, const char *prop_name)\n{\n    int prop_idx, ret;\n\n    prop_idx = unicode_find_name(unicode_prop_name_table, prop_name);\n    if (prop_idx < 0)\n        return -2;\n    prop_idx += UNICODE_PROP_ASCII_Hex_Digit;\n\n    ret = 0;\n    switch(prop_idx) {\n    case UNICODE_PROP_ASCII:\n        if (cr_add_interval(cr, 0x00, 0x7f + 1))\n            return -1;\n        break;\n    case UNICODE_PROP_Any:\n        if (cr_add_interval(cr, 0x00000, 0x10ffff + 1))\n            return -1;\n        break;\n    case UNICODE_PROP_Assigned:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Cn),\n                               POP_INVERT,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Math:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Sm),\n                               POP_PROP, UNICODE_PROP_Other_Math,\n                               POP_UNION,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Lowercase:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Ll),\n                               POP_PROP, UNICODE_PROP_Other_Lowercase,\n                               POP_UNION,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Uppercase:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Lu),\n                               POP_PROP, UNICODE_PROP_Other_Uppercase,\n                               POP_UNION,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Cased:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Lu) | M(Ll) | M(Lt),\n                               POP_PROP, UNICODE_PROP_Other_Uppercase,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Other_Lowercase,\n                               POP_UNION,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Alphabetic:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),\n                               POP_PROP, UNICODE_PROP_Other_Uppercase,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Other_Lowercase,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Other_Alphabetic,\n                               POP_UNION,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Grapheme_Base:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Cc) | M(Cf) | M(Cs) | M(Co) | M(Cn) | M(Zl) | M(Zp) | M(Me) | M(Mn),\n                               POP_PROP, UNICODE_PROP_Other_Grapheme_Extend,\n                               POP_UNION,\n                               POP_INVERT,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Grapheme_Extend:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Me) | M(Mn),\n                               POP_PROP, UNICODE_PROP_Other_Grapheme_Extend,\n                               POP_UNION,\n                               POP_END);\n        break;\n    case UNICODE_PROP_XID_Start:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),\n                               POP_PROP, UNICODE_PROP_Other_ID_Start,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Pattern_Syntax,\n                               POP_PROP, UNICODE_PROP_Pattern_White_Space,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_XID_Start1,\n                               POP_UNION,\n                               POP_INVERT,\n                               POP_INTER,\n                               POP_END);\n        break;\n    case UNICODE_PROP_XID_Continue:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) |\n                               M(Mn) | M(Mc) | M(Nd) | M(Pc),\n                               POP_PROP, UNICODE_PROP_Other_ID_Start,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Other_ID_Continue,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Pattern_Syntax,\n                               POP_PROP, UNICODE_PROP_Pattern_White_Space,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_XID_Continue1,\n                               POP_UNION,\n                               POP_INVERT,\n                               POP_INTER,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Changes_When_Uppercased:\n        ret = unicode_case1(cr, CASE_U);\n        break;\n    case UNICODE_PROP_Changes_When_Lowercased:\n        ret = unicode_case1(cr, CASE_L);\n        break;\n    case UNICODE_PROP_Changes_When_Casemapped:\n        ret = unicode_case1(cr, CASE_U | CASE_L | CASE_F);\n        break;\n    case UNICODE_PROP_Changes_When_Titlecased:\n        ret = unicode_prop_ops(cr,\n                               POP_CASE, CASE_U,\n                               POP_PROP, UNICODE_PROP_Changes_When_Titlecased1,\n                               POP_XOR,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Changes_When_Casefolded:\n        ret = unicode_prop_ops(cr,\n                               POP_CASE, CASE_F,\n                               POP_PROP, UNICODE_PROP_Changes_When_Casefolded1,\n                               POP_XOR,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Changes_When_NFKC_Casefolded:\n        ret = unicode_prop_ops(cr,\n                               POP_CASE, CASE_F,\n                               POP_PROP, UNICODE_PROP_Changes_When_NFKC_Casefolded1,\n                               POP_XOR,\n                               POP_END);\n        break;\n#if 0\n    case UNICODE_PROP_ID_Start:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl),\n                               POP_PROP, UNICODE_PROP_Other_ID_Start,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Pattern_Syntax,\n                               POP_PROP, UNICODE_PROP_Pattern_White_Space,\n                               POP_UNION,\n                               POP_INVERT,\n                               POP_INTER,\n                               POP_END);\n        break;\n    case UNICODE_PROP_ID_Continue:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Lu) | M(Ll) | M(Lt) | M(Lm) | M(Lo) | M(Nl) |\n                               M(Mn) | M(Mc) | M(Nd) | M(Pc),\n                               POP_PROP, UNICODE_PROP_Other_ID_Start,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Other_ID_Continue,\n                               POP_UNION,\n                               POP_PROP, UNICODE_PROP_Pattern_Syntax,\n                               POP_PROP, UNICODE_PROP_Pattern_White_Space,\n                               POP_UNION,\n                               POP_INVERT,\n                               POP_INTER,\n                               POP_END);\n        break;\n    case UNICODE_PROP_Case_Ignorable:\n        ret = unicode_prop_ops(cr,\n                               POP_GC, M(Mn) | M(Cf) | M(Lm) | M(Sk),\n                               POP_PROP, UNICODE_PROP_Case_Ignorable1,\n                               POP_XOR,\n                               POP_END);\n        break;\n#else\n        /* we use the existing tables */\n    case UNICODE_PROP_ID_Continue:\n        ret = unicode_prop_ops(cr,\n                               POP_PROP, UNICODE_PROP_ID_Start,\n                               POP_PROP, UNICODE_PROP_ID_Continue1,\n                               POP_XOR,\n                               POP_END);\n        break;\n#endif\n    default:\n        if (prop_idx >= countof(unicode_prop_table))\n            return -2;\n        ret = unicode_prop1(cr, prop_idx);\n        break;\n    }\n    return ret;\n}\n\n#endif /* CONFIG_ALL_UNICODE */\n\n/*---- lre codepoint categorizing functions ----*/\n\n#define S  UNICODE_C_SPACE\n#define D  UNICODE_C_DIGIT\n#define X  UNICODE_C_XDIGIT\n#define U  UNICODE_C_UPPER\n#define L  UNICODE_C_LOWER\n#define _  UNICODE_C_UNDER\n#define d  UNICODE_C_DOLLAR\n\nuint8_t const lre_ctype_bits[256] = {\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, S, S, S, S, S, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n\n    S, 0, 0, 0, d, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    X|D, X|D, X|D, X|D, X|D, X|D, X|D, X|D,\n    X|D, X|D, 0, 0, 0, 0, 0, 0,\n\n    0, X|U, X|U, X|U, X|U, X|U, X|U, U,\n    U, U, U, U, U, U, U, U,\n    U, U, U, U, U, U, U, U,\n    U, U, U, 0, 0, 0, 0, _,\n\n    0, X|L, X|L, X|L, X|L, X|L, X|L, L,\n    L, L, L, L, L, L, L, L,\n    L, L, L, L, L, L, L, L,\n    L, L, L, 0, 0, 0, 0, 0,\n\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n\n    S, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n    0, 0, 0, 0, 0, 0, 0, 0,\n};\n\n#undef S\n#undef D\n#undef X\n#undef U\n#undef L\n#undef _\n#undef d\n\n/* code point ranges for Zs,Zl or Zp property */\nstatic const uint16_t char_range_s[] = {\n    10,\n    0x0009, 0x000D + 1,\n    0x0020, 0x0020 + 1,\n    0x00A0, 0x00A0 + 1,\n    0x1680, 0x1680 + 1,\n    0x2000, 0x200A + 1,\n    /* 2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;; */\n    /* 2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;; */\n    0x2028, 0x2029 + 1,\n    0x202F, 0x202F + 1,\n    0x205F, 0x205F + 1,\n    0x3000, 0x3000 + 1,\n    /* FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;; */\n    0xFEFF, 0xFEFF + 1,\n};\n\nBOOL lre_is_space_non_ascii(uint32_t c)\n{\n    size_t i, n;\n\n    n = countof(char_range_s);\n    for(i = 5; i < n; i += 2) {\n        uint32_t low = char_range_s[i];\n        uint32_t high = char_range_s[i + 1];\n        if (c < low)\n            return FALSE;\n        if (c < high)\n            return TRUE;\n    }\n    return FALSE;\n}\n\n#define SEQ_MAX_LEN 16\n\nstatic int unicode_sequence_prop1(int seq_prop_idx, UnicodeSequencePropCB *cb, void *opaque,\n                                  CharRange *cr)\n{\n    int i, c, j;\n    uint32_t seq[SEQ_MAX_LEN];\n    \n    switch(seq_prop_idx) {\n    case UNICODE_SEQUENCE_PROP_Basic_Emoji:\n        if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji1) < 0)\n            return -1;\n        for(i = 0; i < cr->len; i += 2) {\n            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {\n                seq[0] = c;\n                cb(opaque, seq, 1);\n            }\n        }\n\n        cr->len = 0;\n\n        if (unicode_prop1(cr, UNICODE_PROP_Basic_Emoji2) < 0)\n            return -1;\n        for(i = 0; i < cr->len; i += 2) {\n            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {\n                seq[0] = c;\n                seq[1] = 0xfe0f;\n                cb(opaque, seq, 2);\n            }\n        }\n\n        break;\n    case UNICODE_SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence:\n        if (unicode_prop1(cr, UNICODE_PROP_Emoji_Modifier_Base) < 0)\n            return -1;\n        for(i = 0; i < cr->len; i += 2) {\n            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {\n                for(j = 0; j < 5; j++) {\n                    seq[0] = c;\n                    seq[1] = 0x1f3fb + j;\n                    cb(opaque, seq, 2);\n                }\n            }\n        }\n        break;\n    case UNICODE_SEQUENCE_PROP_RGI_Emoji_Flag_Sequence:\n        if (unicode_prop1(cr, UNICODE_PROP_RGI_Emoji_Flag_Sequence) < 0)\n            return -1;\n        for(i = 0; i < cr->len; i += 2) {\n            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {\n                int c0, c1;\n                c0 = c / 26;\n                c1 = c % 26;\n                seq[0] = 0x1F1E6 + c0;\n                seq[1] = 0x1F1E6 + c1;\n                cb(opaque, seq, 2);\n            }\n        }\n        break;\n    case UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence:\n        {\n            int len, code, pres, k, mod, mod_count, mod_pos[2], hc_pos, n_mod, n_hc, mod1;\n            int mod_idx, hc_idx, i0, i1;\n            const uint8_t *tab = unicode_rgi_emoji_zwj_sequence;\n            \n            for(i = 0; i < countof(unicode_rgi_emoji_zwj_sequence);) {\n                len = tab[i++];\n                k = 0;\n                mod = 0;\n                mod_count = 0;\n                hc_pos = -1;\n                for(j = 0; j < len; j++) {\n                    code = tab[i++];\n                    code |= tab[i++] << 8;\n                    pres = code >> 15;\n                    mod1 = (code >> 13) & 3;\n                    code &= 0x1fff;\n                    if (code < 0x1000) {\n                        c = code + 0x2000;\n                    } else {\n                        c = 0x1f000 + (code - 0x1000);\n                    }\n                    if (c == 0x1f9b0)\n                        hc_pos = k;\n                    seq[k++] = c;\n                    if (mod1 != 0) {\n                        assert(mod_count < 2);\n                        mod = mod1;\n                        mod_pos[mod_count++] = k;\n                        seq[k++] = 0; /* will be filled later */\n                    }\n                    if (pres) {\n                        seq[k++] = 0xfe0f;\n                    }\n                    if (j < len - 1) {\n                        seq[k++] = 0x200d;\n                    }\n                }\n\n                /* genrate all the variants */\n                switch(mod) {\n                case 1:\n                    n_mod = 5;\n                    break;\n                case 2:\n                    n_mod = 25;\n                    break;\n                case 3:\n                    n_mod = 20;\n                    break;\n                default:\n                    n_mod = 1;\n                    break;\n                }\n                if (hc_pos >= 0)\n                    n_hc = 4;\n                else\n                    n_hc = 1;\n                for(hc_idx = 0; hc_idx < n_hc; hc_idx++) {\n                    for(mod_idx = 0; mod_idx < n_mod; mod_idx++) {\n                        if (hc_pos >= 0)\n                            seq[hc_pos] = 0x1f9b0 + hc_idx;\n                        \n                        switch(mod) {\n                        case 1:\n                            seq[mod_pos[0]] = 0x1f3fb + mod_idx;\n                            break;\n                        case 2:\n                        case 3:\n                            i0 = mod_idx / 5;\n                            i1 = mod_idx % 5;\n                            /* avoid identical values */\n                            if (mod == 3 && i0 >= i1)\n                                i0++;\n                            seq[mod_pos[0]] = 0x1f3fb + i0;\n                            seq[mod_pos[1]] = 0x1f3fb + i1;\n                            break;\n                        default:\n                            break;\n                        }\n#if 0\n                        for(j = 0; j < k; j++)\n                            printf(\" %04x\", seq[j]);\n                        printf(\"\\n\");\n#endif                \n                        cb(opaque, seq, k);\n                    }\n                }\n            }\n        }\n        break;\n    case UNICODE_SEQUENCE_PROP_RGI_Emoji_Tag_Sequence:\n        {\n            for(i = 0; i < countof(unicode_rgi_emoji_tag_sequence);) {\n                j = 0;\n                seq[j++] = 0x1F3F4;\n                for(;;) {\n                    c = unicode_rgi_emoji_tag_sequence[i++];\n                    if (c == 0x00)\n                        break;\n                    seq[j++] = 0xe0000 + c;\n                }\n                seq[j++] = 0xe007f;\n                cb(opaque, seq, j);\n            }\n        }\n        break;\n    case UNICODE_SEQUENCE_PROP_Emoji_Keycap_Sequence:\n        if (unicode_prop1(cr, UNICODE_PROP_Emoji_Keycap_Sequence) < 0)\n            return -1;\n        for(i = 0; i < cr->len; i += 2) {\n            for(c = cr->points[i]; c < cr->points[i + 1]; c++) {\n                seq[0] = c;\n                seq[1] = 0xfe0f;\n                seq[2] = 0x20e3;\n                cb(opaque, seq, 3);\n            }\n        }\n        break;\n    case UNICODE_SEQUENCE_PROP_RGI_Emoji:\n        /* all prevous sequences */\n        for(i = UNICODE_SEQUENCE_PROP_Basic_Emoji; i <= UNICODE_SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence; i++) {\n            int ret;\n            ret = unicode_sequence_prop1(i, cb, opaque, cr);\n            if (ret < 0)\n                return ret;\n            cr->len = 0;\n        }\n        break;\n    default:\n        return -2;\n    }\n    return 0;\n}\n\n/* build a unicode sequence property */\n/* return -2 if not found, -1 if other error. 'cr' is used as temporary memory. */\nint unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque,\n                          CharRange *cr)\n{\n    int seq_prop_idx;\n    seq_prop_idx = unicode_find_name(unicode_sequence_prop_name_table, prop_name);\n    if (seq_prop_idx < 0)\n        return -2;\n    return unicode_sequence_prop1(seq_prop_idx, cb, opaque, cr);\n}\n"
  },
  {
    "path": "libunicode.h",
    "content": "/*\n * Unicode utilities\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef LIBUNICODE_H\n#define LIBUNICODE_H\n\n#include <stdint.h>\n\n/* define it to include all the unicode tables (40KB larger) */\n#define CONFIG_ALL_UNICODE\n\n#define LRE_CC_RES_LEN_MAX 3\n\n/* char ranges */\n\ntypedef struct {\n    int len; /* in points, always even */\n    int size;\n    uint32_t *points; /* points sorted by increasing value */\n    void *mem_opaque;\n    void *(*realloc_func)(void *opaque, void *ptr, size_t size);\n} CharRange;\n\ntypedef enum {\n    CR_OP_UNION,\n    CR_OP_INTER,\n    CR_OP_XOR,\n    CR_OP_SUB,\n} CharRangeOpEnum;\n\nvoid cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));\nvoid cr_free(CharRange *cr);\nint cr_realloc(CharRange *cr, int size);\nint cr_copy(CharRange *cr, const CharRange *cr1);\n\nstatic inline int cr_add_point(CharRange *cr, uint32_t v)\n{\n    if (cr->len >= cr->size) {\n        if (cr_realloc(cr, cr->len + 1))\n            return -1;\n    }\n    cr->points[cr->len++] = v;\n    return 0;\n}\n\nstatic inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)\n{\n    if ((cr->len + 2) > cr->size) {\n        if (cr_realloc(cr, cr->len + 2))\n            return -1;\n    }\n    cr->points[cr->len++] = c1;\n    cr->points[cr->len++] = c2;\n    return 0;\n}\n\nint cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,\n          const uint32_t *b_pt, int b_len, int op);\nint cr_op1(CharRange *cr, const uint32_t *b_pt, int b_len, int op);\n\nstatic inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)\n{\n    uint32_t b_pt[2];\n    b_pt[0] = c1;\n    b_pt[1] = c2 + 1;\n    return cr_op1(cr, b_pt, 2, CR_OP_UNION);\n}\n\nint cr_invert(CharRange *cr);\n\nint cr_regexp_canonicalize(CharRange *cr, int is_unicode);\n\ntypedef enum {\n    UNICODE_NFC,\n    UNICODE_NFD,\n    UNICODE_NFKC,\n    UNICODE_NFKD,\n} UnicodeNormalizationEnum;\n\nint unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,\n                      UnicodeNormalizationEnum n_type,\n                      void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));\n\n/* Unicode character range functions */\n\nint unicode_script(CharRange *cr, const char *script_name, int is_ext);\nint unicode_general_category(CharRange *cr, const char *gc_name);\nint unicode_prop(CharRange *cr, const char *prop_name);\n\ntypedef void UnicodeSequencePropCB(void *opaque, const uint32_t *buf, int len);\nint unicode_sequence_prop(const char *prop_name, UnicodeSequencePropCB *cb, void *opaque,\n                          CharRange *cr);\n\nint lre_case_conv(uint32_t *res, uint32_t c, int conv_type);\nint lre_canonicalize(uint32_t c, int is_unicode);\n\n/* Code point type categories */\nenum {\n    UNICODE_C_SPACE  = (1 << 0),\n    UNICODE_C_DIGIT  = (1 << 1),\n    UNICODE_C_UPPER  = (1 << 2),\n    UNICODE_C_LOWER  = (1 << 3),\n    UNICODE_C_UNDER  = (1 << 4),\n    UNICODE_C_DOLLAR = (1 << 5),\n    UNICODE_C_XDIGIT = (1 << 6),\n};\nextern uint8_t const lre_ctype_bits[256];\n\n/* zero or non-zero return value */\nint lre_is_cased(uint32_t c);\nint lre_is_case_ignorable(uint32_t c);\nint lre_is_id_start(uint32_t c);\nint lre_is_id_continue(uint32_t c);\n\nstatic inline int lre_is_space_byte(uint8_t c) {\n    return lre_ctype_bits[c] & UNICODE_C_SPACE;\n}\n\nstatic inline int lre_is_id_start_byte(uint8_t c) {\n    return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |\n                                UNICODE_C_UNDER | UNICODE_C_DOLLAR);\n}\n\nstatic inline int lre_is_id_continue_byte(uint8_t c) {\n    return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |\n                                UNICODE_C_UNDER | UNICODE_C_DOLLAR |\n                                UNICODE_C_DIGIT);\n}\n\nstatic inline int lre_is_word_byte(uint8_t c) {\n    return lre_ctype_bits[c] & (UNICODE_C_UPPER | UNICODE_C_LOWER |\n                                UNICODE_C_UNDER | UNICODE_C_DIGIT);\n}\n\nint lre_is_space_non_ascii(uint32_t c);\n\nstatic inline int lre_is_space(uint32_t c) {\n    if (c < 256)\n        return lre_is_space_byte(c);\n    else\n        return lre_is_space_non_ascii(c);\n}\n\nstatic inline int lre_js_is_ident_first(uint32_t c) {\n    if (c < 128) {\n        return lre_is_id_start_byte(c);\n    } else {\n#ifdef CONFIG_ALL_UNICODE\n        return lre_is_id_start(c);\n#else\n        return !lre_is_space_non_ascii(c);\n#endif\n    }\n}\n\nstatic inline int lre_js_is_ident_next(uint32_t c) {\n    if (c < 128) {\n        return lre_is_id_continue_byte(c);\n    } else {\n        /* ZWNJ and ZWJ are accepted in identifiers */\n        if (c >= 0x200C && c <= 0x200D)\n            return TRUE;\n#ifdef CONFIG_ALL_UNICODE\n        return lre_is_id_continue(c);\n#else\n        return !lre_is_space_non_ascii(c);\n#endif\n    }\n}\n\n#endif /* LIBUNICODE_H */\n"
  },
  {
    "path": "list.h",
    "content": "/*\n * Linux klist like system\n *\n * Copyright (c) 2016-2017 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef LIST_H\n#define LIST_H\n\n#ifndef NULL\n#include <stddef.h>\n#endif\n\nstruct list_head {\n    struct list_head *prev;\n    struct list_head *next;\n};\n\n#define LIST_HEAD_INIT(el) { &(el), &(el) }\n\n/* return the pointer of type 'type *' containing 'el' as field 'member' */\n#define list_entry(el, type, member) container_of(el, type, member)\n\nstatic inline void init_list_head(struct list_head *head)\n{\n    head->prev = head;\n    head->next = head;\n}\n\n/* insert 'el' between 'prev' and 'next' */\nstatic inline void __list_add(struct list_head *el,\n                              struct list_head *prev, struct list_head *next)\n{\n    prev->next = el;\n    el->prev = prev;\n    el->next = next;\n    next->prev = el;\n}\n\n/* add 'el' at the head of the list 'head' (= after element head) */\nstatic inline void list_add(struct list_head *el, struct list_head *head)\n{\n    __list_add(el, head, head->next);\n}\n\n/* add 'el' at the end of the list 'head' (= before element head) */\nstatic inline void list_add_tail(struct list_head *el, struct list_head *head)\n{\n    __list_add(el, head->prev, head);\n}\n\nstatic inline void list_del(struct list_head *el)\n{\n    struct list_head *prev, *next;\n    prev = el->prev;\n    next = el->next;\n    prev->next = next;\n    next->prev = prev;\n    el->prev = NULL; /* fail safe */\n    el->next = NULL; /* fail safe */\n}\n\nstatic inline int list_empty(struct list_head *el)\n{\n    return el->next == el;\n}\n\n#define list_for_each(el, head) \\\n  for(el = (head)->next; el != (head); el = el->next)\n\n#define list_for_each_safe(el, el1, head)                \\\n    for(el = (head)->next, el1 = el->next; el != (head); \\\n        el = el1, el1 = el->next)\n\n#define list_for_each_prev(el, head) \\\n  for(el = (head)->prev; el != (head); el = el->prev)\n\n#define list_for_each_prev_safe(el, el1, head)           \\\n    for(el = (head)->prev, el1 = el->prev; el != (head); \\\n        el = el1, el1 = el->prev)\n\n#endif /* LIST_H */\n"
  },
  {
    "path": "qjs.c",
    "content": "/*\n * QuickJS stand alone interpreter\n *\n * Copyright (c) 2017-2021 Fabrice Bellard\n * Copyright (c) 2017-2021 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n#include <unistd.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <time.h>\n#if defined(__APPLE__)\n#include <malloc/malloc.h>\n#elif defined(__linux__) || defined(__GLIBC__)\n#include <malloc.h>\n#elif defined(__FreeBSD__)\n#include <malloc_np.h>\n#endif\n\n#include \"cutils.h\"\n#include \"quickjs-libc.h\"\n\nextern const uint8_t qjsc_repl[];\nextern const uint32_t qjsc_repl_size;\n\nstatic int eval_buf(JSContext *ctx, const void *buf, int buf_len,\n                    const char *filename, int eval_flags)\n{\n    JSValue val;\n    int ret;\n\n    if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) {\n        /* for the modules, we compile then run to be able to set\n           import.meta */\n        val = JS_Eval(ctx, buf, buf_len, filename,\n                      eval_flags | JS_EVAL_FLAG_COMPILE_ONLY);\n        if (!JS_IsException(val)) {\n            js_module_set_import_meta(ctx, val, TRUE, TRUE);\n            val = JS_EvalFunction(ctx, val);\n        }\n        val = js_std_await(ctx, val);\n    } else {\n        val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);\n    }\n    if (JS_IsException(val)) {\n        js_std_dump_error(ctx);\n        ret = -1;\n    } else {\n        ret = 0;\n    }\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic int eval_file(JSContext *ctx, const char *filename, int module, int strict)\n{\n    uint8_t *buf;\n    int ret, eval_flags;\n    size_t buf_len;\n\n    buf = js_load_file(ctx, &buf_len, filename);\n    if (!buf) {\n        perror(filename);\n        exit(1);\n    }\n\n    if (module < 0) {\n        module = (has_suffix(filename, \".mjs\") ||\n                  JS_DetectModule((const char *)buf, buf_len));\n    }\n    if (module) {\n        eval_flags = JS_EVAL_TYPE_MODULE;\n    } else {\n        eval_flags = JS_EVAL_TYPE_GLOBAL;\n        if (strict)\n            eval_flags |= JS_EVAL_FLAG_STRICT;\n    }\n    ret = eval_buf(ctx, buf, buf_len, filename, eval_flags);\n    js_free(ctx, buf);\n    return ret;\n}\n\n/* also used to initialize the worker context */\nstatic JSContext *JS_NewCustomContext(JSRuntime *rt)\n{\n    JSContext *ctx;\n    ctx = JS_NewContext(rt);\n    if (!ctx)\n        return NULL;\n    /* system modules */\n    js_init_module_std(ctx, \"std\");\n    js_init_module_os(ctx, \"os\");\n    return ctx;\n}\n\n#if defined(__APPLE__)\n#define MALLOC_OVERHEAD  0\n#else\n#define MALLOC_OVERHEAD  8\n#endif\n\nstruct trace_malloc_data {\n    uint8_t *base;\n};\n\nstatic inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr,\n                                                struct trace_malloc_data *dp)\n{\n    return ptr - dp->base;\n}\n\n/* default memory allocation functions with memory limitation */\nstatic size_t js_trace_malloc_usable_size(const void *ptr)\n{\n#if defined(__APPLE__)\n    return malloc_size(ptr);\n#elif defined(_WIN32)\n    return _msize((void *)ptr);\n#elif defined(EMSCRIPTEN)\n    return 0;\n#elif defined(__linux__) || defined(__GLIBC__)\n    return malloc_usable_size((void *)ptr);\n#else\n    /* change this to `return 0;` if compilation fails */\n    return malloc_usable_size((void *)ptr);\n#endif\n}\n\nstatic void\n#ifdef _WIN32\n/* mingw printf is used */\n__attribute__((format(gnu_printf, 2, 3)))\n#else\n__attribute__((format(printf, 2, 3)))\n#endif\n    js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...)\n{\n    va_list ap;\n    int c;\n\n    va_start(ap, fmt);\n    while ((c = *fmt++) != '\\0') {\n        if (c == '%') {\n            /* only handle %p and %zd */\n            if (*fmt == 'p') {\n                uint8_t *ptr = va_arg(ap, void *);\n                if (ptr == NULL) {\n                    printf(\"NULL\");\n                } else {\n                    printf(\"H%+06lld.%zd\",\n                           js_trace_malloc_ptr_offset(ptr, s->opaque),\n                           js_trace_malloc_usable_size(ptr));\n                }\n                fmt++;\n                continue;\n            }\n            if (fmt[0] == 'z' && fmt[1] == 'd') {\n                size_t sz = va_arg(ap, size_t);\n                printf(\"%zd\", sz);\n                fmt += 2;\n                continue;\n            }\n        }\n        putc(c, stdout);\n    }\n    va_end(ap);\n}\n\nstatic void js_trace_malloc_init(struct trace_malloc_data *s)\n{\n    free(s->base = malloc(8));\n}\n\nstatic void *js_trace_malloc(JSMallocState *s, size_t size)\n{\n    void *ptr;\n\n    /* Do not allocate zero bytes: behavior is platform dependent */\n    assert(size != 0);\n\n    if (unlikely(s->malloc_size + size > s->malloc_limit))\n        return NULL;\n    ptr = malloc(size);\n    js_trace_malloc_printf(s, \"A %zd -> %p\\n\", size, ptr);\n    if (ptr) {\n        s->malloc_count++;\n        s->malloc_size += js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD;\n    }\n    return ptr;\n}\n\nstatic void js_trace_free(JSMallocState *s, void *ptr)\n{\n    if (!ptr)\n        return;\n\n    js_trace_malloc_printf(s, \"F %p\\n\", ptr);\n    s->malloc_count--;\n    s->malloc_size -= js_trace_malloc_usable_size(ptr) + MALLOC_OVERHEAD;\n    free(ptr);\n}\n\nstatic void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size)\n{\n    size_t old_size;\n\n    if (!ptr) {\n        if (size == 0)\n            return NULL;\n        return js_trace_malloc(s, size);\n    }\n    old_size = js_trace_malloc_usable_size(ptr);\n    if (size == 0) {\n        js_trace_malloc_printf(s, \"R %zd %p\\n\", size, ptr);\n        s->malloc_count--;\n        s->malloc_size -= old_size + MALLOC_OVERHEAD;\n        free(ptr);\n        return NULL;\n    }\n    if (s->malloc_size + size - old_size > s->malloc_limit)\n        return NULL;\n\n    js_trace_malloc_printf(s, \"R %zd %p\", size, ptr);\n\n    ptr = realloc(ptr, size);\n    js_trace_malloc_printf(s, \" -> %p\\n\", ptr);\n    if (ptr) {\n        s->malloc_size += js_trace_malloc_usable_size(ptr) - old_size;\n    }\n    return ptr;\n}\n\nstatic const JSMallocFunctions trace_mf = {\n    js_trace_malloc,\n    js_trace_free,\n    js_trace_realloc,\n    js_trace_malloc_usable_size,\n};\n\nstatic size_t get_suffixed_size(const char *str)\n{\n    char *p;\n    size_t v;\n    v = (size_t)strtod(str, &p);\n    switch(*p) {\n    case 'G':\n        v <<= 30;\n        break;\n    case 'M':\n        v <<= 20;\n        break;\n    case 'k':\n    case 'K':\n        v <<= 10;\n        break;\n    default:\n        if (*p != '\\0') {\n            fprintf(stderr, \"qjs: invalid suffix: %s\\n\", p);\n            exit(1);\n        }\n        break;\n    }\n    return v;\n}\n\n#define PROG_NAME \"qjs\"\n\nvoid help(void)\n{\n    printf(\"QuickJS version \" CONFIG_VERSION \"\\n\"\n           \"usage: \" PROG_NAME \" [options] [file [args]]\\n\"\n           \"-h  --help         list options\\n\"\n           \"-e  --eval EXPR    evaluate EXPR\\n\"\n           \"-i  --interactive  go to interactive mode\\n\"\n           \"-m  --module       load as ES6 module (default=autodetect)\\n\"\n           \"    --script       load as ES6 script (default=autodetect)\\n\"\n           \"    --strict       force strict mode\\n\"\n           \"-I  --include file include an additional file\\n\"\n           \"    --std          make 'std' and 'os' available to the loaded script\\n\"\n           \"-T  --trace        trace memory allocation\\n\"\n           \"-d  --dump         dump the memory usage stats\\n\"\n           \"    --memory-limit n  limit the memory usage to 'n' bytes (SI suffixes allowed)\\n\"\n           \"    --stack-size n    limit the stack size to 'n' bytes (SI suffixes allowed)\\n\"\n           \"    --no-unhandled-rejection  ignore unhandled promise rejections\\n\"\n           \"-s                    strip all the debug info\\n\"\n           \"    --strip-source    strip the source code\\n\"\n           \"-q  --quit         just instantiate the interpreter and quit\\n\");\n    exit(1);\n}\n\nint main(int argc, char **argv)\n{\n    JSRuntime *rt;\n    JSContext *ctx;\n    struct trace_malloc_data trace_data = { NULL };\n    int optind;\n    char *expr = NULL;\n    int interactive = 0;\n    int dump_memory = 0;\n    int trace_memory = 0;\n    int empty_run = 0;\n    int module = -1;\n    int strict = 0;\n    int load_std = 0;\n    int dump_unhandled_promise_rejection = 1;\n    size_t memory_limit = 0;\n    char *include_list[32];\n    int i, include_count = 0;\n    int strip_flags = 0;\n    size_t stack_size = 0;\n\n    /* cannot use getopt because we want to pass the command line to\n       the script */\n    optind = 1;\n    while (optind < argc && *argv[optind] == '-') {\n        char *arg = argv[optind] + 1;\n        const char *longopt = \"\";\n        /* a single - is not an option, it also stops argument scanning */\n        if (!*arg)\n            break;\n        optind++;\n        if (*arg == '-') {\n            longopt = arg + 1;\n            arg += strlen(arg);\n            /* -- stops argument scanning */\n            if (!*longopt)\n                break;\n        }\n        for (; *arg || *longopt; longopt = \"\") {\n            char opt = *arg;\n            if (opt)\n                arg++;\n            if (opt == 'h' || opt == '?' || !strcmp(longopt, \"help\")) {\n                help();\n                continue;\n            }\n            if (opt == 'e' || !strcmp(longopt, \"eval\")) {\n                if (*arg) {\n                    expr = arg;\n                    break;\n                }\n                if (optind < argc) {\n                    expr = argv[optind++];\n                    break;\n                }\n                fprintf(stderr, \"qjs: missing expression for -e\\n\");\n                exit(2);\n            }\n            if (opt == 'I' || !strcmp(longopt, \"include\")) {\n                if (optind >= argc) {\n                    fprintf(stderr, \"expecting filename\");\n                    exit(1);\n                }\n                if (include_count >= countof(include_list)) {\n                    fprintf(stderr, \"too many included files\");\n                    exit(1);\n                }\n                include_list[include_count++] = argv[optind++];\n                continue;\n            }\n            if (opt == 'i' || !strcmp(longopt, \"interactive\")) {\n                interactive++;\n                continue;\n            }\n            if (opt == 'm' || !strcmp(longopt, \"module\")) {\n                module = 1;\n                continue;\n            }\n            if (!strcmp(longopt, \"script\")) {\n                module = 0;\n                continue;\n            }\n            if (!strcmp(longopt, \"strict\")) {\n                strict = 1;\n                continue;\n            }\n            if (opt == 'd' || !strcmp(longopt, \"dump\")) {\n                dump_memory++;\n                continue;\n            }\n            if (opt == 'T' || !strcmp(longopt, \"trace\")) {\n                trace_memory++;\n                continue;\n            }\n            if (!strcmp(longopt, \"std\")) {\n                load_std = 1;\n                continue;\n            }\n            if (!strcmp(longopt, \"no-unhandled-rejection\")) {\n                dump_unhandled_promise_rejection = 0;\n                continue;\n            }\n            if (opt == 'q' || !strcmp(longopt, \"quit\")) {\n                empty_run++;\n                continue;\n            }\n            if (!strcmp(longopt, \"memory-limit\")) {\n                if (optind >= argc) {\n                    fprintf(stderr, \"expecting memory limit\");\n                    exit(1);\n                }\n                memory_limit = get_suffixed_size(argv[optind++]);\n                continue;\n            }\n            if (!strcmp(longopt, \"stack-size\")) {\n                if (optind >= argc) {\n                    fprintf(stderr, \"expecting stack size\");\n                    exit(1);\n                }\n                stack_size = get_suffixed_size(argv[optind++]);\n                continue;\n            }\n            if (opt == 's') {\n                strip_flags = JS_STRIP_DEBUG;\n                continue;\n            }\n            if (!strcmp(longopt, \"strip-source\")) {\n                strip_flags = JS_STRIP_SOURCE;\n                continue;\n            }\n            if (opt) {\n                fprintf(stderr, \"qjs: unknown option '-%c'\\n\", opt);\n            } else {\n                fprintf(stderr, \"qjs: unknown option '--%s'\\n\", longopt);\n            }\n            help();\n        }\n    }\n\n    if (trace_memory) {\n        js_trace_malloc_init(&trace_data);\n        rt = JS_NewRuntime2(&trace_mf, &trace_data);\n    } else {\n        rt = JS_NewRuntime();\n    }\n    if (!rt) {\n        fprintf(stderr, \"qjs: cannot allocate JS runtime\\n\");\n        exit(2);\n    }\n    if (memory_limit != 0)\n        JS_SetMemoryLimit(rt, memory_limit);\n    if (stack_size != 0)\n        JS_SetMaxStackSize(rt, stack_size);\n    JS_SetStripInfo(rt, strip_flags);\n    js_std_set_worker_new_context_func(JS_NewCustomContext);\n    js_std_init_handlers(rt);\n    ctx = JS_NewCustomContext(rt);\n    if (!ctx) {\n        fprintf(stderr, \"qjs: cannot allocate JS context\\n\");\n        exit(2);\n    }\n\n    /* loader for ES6 modules */\n    JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);\n\n    if (dump_unhandled_promise_rejection) {\n        JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,\n                                          NULL);\n    }\n\n    if (!empty_run) {\n        js_std_add_helpers(ctx, argc - optind, argv + optind);\n\n        /* make 'std' and 'os' visible to non module code */\n        if (load_std) {\n            const char *str = \"import * as std from 'std';\\n\"\n                \"import * as os from 'os';\\n\"\n                \"globalThis.std = std;\\n\"\n                \"globalThis.os = os;\\n\";\n            eval_buf(ctx, str, strlen(str), \"<input>\", JS_EVAL_TYPE_MODULE);\n        }\n\n        for(i = 0; i < include_count; i++) {\n            if (eval_file(ctx, include_list[i], 0, strict))\n                goto fail;\n        }\n\n        if (expr) {\n            int eval_flags;\n            if (module > 0) {\n                eval_flags = JS_EVAL_TYPE_MODULE;\n            } else {\n                eval_flags = JS_EVAL_TYPE_GLOBAL;\n                if (strict)\n                    eval_flags |= JS_EVAL_FLAG_STRICT;\n            }\n            if (eval_buf(ctx, expr, strlen(expr), \"<cmdline>\", eval_flags))\n                goto fail;\n        } else\n        if (optind >= argc) {\n            /* interactive mode */\n            interactive = 1;\n        } else {\n            const char *filename;\n            filename = argv[optind];\n            if (eval_file(ctx, filename, module, strict))\n                goto fail;\n        }\n        if (interactive) {\n            JS_SetHostPromiseRejectionTracker(rt, NULL, NULL);\n            js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0);\n        }\n        js_std_loop(ctx);\n    }\n\n    if (dump_memory) {\n        JSMemoryUsage stats;\n        JS_ComputeMemoryUsage(rt, &stats);\n        JS_DumpMemoryUsage(stdout, &stats, rt);\n    }\n    js_std_free_handlers(rt);\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n\n    if (empty_run && dump_memory) {\n        clock_t t[5];\n        double best[5];\n        int i, j;\n        for (i = 0; i < 100; i++) {\n            t[0] = clock();\n            rt = JS_NewRuntime();\n            t[1] = clock();\n            ctx = JS_NewContext(rt);\n            t[2] = clock();\n            JS_FreeContext(ctx);\n            t[3] = clock();\n            JS_FreeRuntime(rt);\n            t[4] = clock();\n            for (j = 4; j > 0; j--) {\n                double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC;\n                if (i == 0 || best[j] > ms)\n                    best[j] = ms;\n            }\n        }\n        printf(\"\\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\\n\",\n               best[1] + best[2] + best[3] + best[4],\n               best[1], best[2], best[3], best[4]);\n    }\n    return 0;\n fail:\n    js_std_free_handlers(rt);\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n    return 1;\n}\n"
  },
  {
    "path": "qjsc.c",
    "content": "/*\n * QuickJS command line compiler\n *\n * Copyright (c) 2018-2021 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n#include <unistd.h>\n#include <errno.h>\n#if !defined(_WIN32)\n#include <sys/wait.h>\n#endif\n\n#include \"cutils.h\"\n#include \"quickjs-libc.h\"\n\ntypedef struct {\n    char *name;\n    char *short_name;\n    int flags;\n} namelist_entry_t;\n\ntypedef struct namelist_t {\n    namelist_entry_t *array;\n    int count;\n    int size;\n} namelist_t;\n\ntypedef struct {\n    const char *option_name;\n    const char *init_name;\n} FeatureEntry;\n\nstatic namelist_t cname_list;\nstatic namelist_t cmodule_list;\nstatic namelist_t init_module_list;\nstatic uint64_t feature_bitmap;\nstatic FILE *outfile;\nstatic BOOL byte_swap;\nstatic BOOL dynamic_export;\nstatic const char *c_ident_prefix = \"qjsc_\";\n\n#define FE_ALL (-1)\n\nstatic const FeatureEntry feature_list[] = {\n    { \"date\", \"Date\" },\n    { \"eval\", \"Eval\" },\n    { \"string-normalize\", \"StringNormalize\" },\n    { \"regexp\", \"RegExp\" },\n    { \"json\", \"JSON\" },\n    { \"proxy\", \"Proxy\" },\n    { \"map\", \"MapSet\" },\n    { \"typedarray\", \"TypedArrays\" },\n    { \"promise\", \"Promise\" },\n#define FE_MODULE_LOADER 9\n    { \"module-loader\", NULL },\n    { \"weakref\", \"WeakRef\" },\n};\n\nvoid namelist_add(namelist_t *lp, const char *name, const char *short_name,\n                  int flags)\n{\n    namelist_entry_t *e;\n    if (lp->count == lp->size) {\n        size_t newsize = lp->size + (lp->size >> 1) + 4;\n        namelist_entry_t *a =\n            realloc(lp->array, sizeof(lp->array[0]) * newsize);\n        /* XXX: check for realloc failure */\n        lp->array = a;\n        lp->size = newsize;\n    }\n    e =  &lp->array[lp->count++];\n    e->name = strdup(name);\n    if (short_name)\n        e->short_name = strdup(short_name);\n    else\n        e->short_name = NULL;\n    e->flags = flags;\n}\n\nvoid namelist_free(namelist_t *lp)\n{\n    while (lp->count > 0) {\n        namelist_entry_t *e = &lp->array[--lp->count];\n        free(e->name);\n        free(e->short_name);\n    }\n    free(lp->array);\n    lp->array = NULL;\n    lp->size = 0;\n}\n\nnamelist_entry_t *namelist_find(namelist_t *lp, const char *name)\n{\n    int i;\n    for(i = 0; i < lp->count; i++) {\n        namelist_entry_t *e = &lp->array[i];\n        if (!strcmp(e->name, name))\n            return e;\n    }\n    return NULL;\n}\n\nstatic void get_c_name(char *buf, size_t buf_size, const char *file)\n{\n    const char *p, *r;\n    size_t len, i;\n    int c;\n    char *q;\n\n    p = strrchr(file, '/');\n    if (!p)\n        p = file;\n    else\n        p++;\n    r = strrchr(p, '.');\n    if (!r)\n        len = strlen(p);\n    else\n        len = r - p;\n    pstrcpy(buf, buf_size, c_ident_prefix);\n    q = buf + strlen(buf);\n    for(i = 0; i < len; i++) {\n        c = p[i];\n        if (!((c >= '0' && c <= '9') ||\n              (c >= 'A' && c <= 'Z') ||\n              (c >= 'a' && c <= 'z'))) {\n            c = '_';\n        }\n        if ((q - buf) < buf_size - 1)\n            *q++ = c;\n    }\n    *q = '\\0';\n}\n\nstatic void dump_hex(FILE *f, const uint8_t *buf, size_t len)\n{\n    size_t i, col;\n    col = 0;\n    for(i = 0; i < len; i++) {\n        fprintf(f, \" 0x%02x,\", buf[i]);\n        if (++col == 8) {\n            fprintf(f, \"\\n\");\n            col = 0;\n        }\n    }\n    if (col != 0)\n        fprintf(f, \"\\n\");\n}\n\ntypedef enum {\n    CNAME_TYPE_SCRIPT,\n    CNAME_TYPE_MODULE,\n    CNAME_TYPE_JSON_MODULE,\n} CNameTypeEnum;\n\nstatic void output_object_code(JSContext *ctx,\n                               FILE *fo, JSValueConst obj, const char *c_name,\n                               CNameTypeEnum c_name_type)\n{\n    uint8_t *out_buf;\n    size_t out_buf_len;\n    int flags;\n\n    if (c_name_type == CNAME_TYPE_JSON_MODULE)\n        flags = 0;\n    else\n        flags = JS_WRITE_OBJ_BYTECODE;\n    if (byte_swap)\n        flags |= JS_WRITE_OBJ_BSWAP;\n    out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);\n    if (!out_buf) {\n        js_std_dump_error(ctx);\n        exit(1);\n    }\n\n    namelist_add(&cname_list, c_name, NULL, c_name_type);\n\n    fprintf(fo, \"const uint32_t %s_size = %u;\\n\\n\",\n            c_name, (unsigned int)out_buf_len);\n    fprintf(fo, \"const uint8_t %s[%u] = {\\n\",\n            c_name, (unsigned int)out_buf_len);\n    dump_hex(fo, out_buf, out_buf_len);\n    fprintf(fo, \"};\\n\\n\");\n\n    js_free(ctx, out_buf);\n}\n\nstatic int js_module_dummy_init(JSContext *ctx, JSModuleDef *m)\n{\n    /* should never be called when compiling JS code */\n    abort();\n}\n\nstatic void find_unique_cname(char *cname, size_t cname_size)\n{\n    char cname1[1024];\n    int suffix_num;\n    size_t len, max_len;\n    assert(cname_size >= 32);\n    /* find a C name not matching an existing module C name by\n       adding a numeric suffix */\n    len = strlen(cname);\n    max_len = cname_size - 16;\n    if (len > max_len)\n        cname[max_len] = '\\0';\n    suffix_num = 1;\n    for(;;) {\n        snprintf(cname1, sizeof(cname1), \"%s_%d\", cname, suffix_num);\n        if (!namelist_find(&cname_list, cname1))\n            break;\n        suffix_num++;\n    }\n    pstrcpy(cname, cname_size, cname1);\n}\n\nJSModuleDef *jsc_module_loader(JSContext *ctx,\n                               const char *module_name, void *opaque,\n                               JSValueConst attributes)\n{\n    JSModuleDef *m;\n    namelist_entry_t *e;\n\n    /* check if it is a declared C or system module */\n    e = namelist_find(&cmodule_list, module_name);\n    if (e) {\n        /* add in the static init module list */\n        namelist_add(&init_module_list, e->name, e->short_name, 0);\n        /* create a dummy module */\n        m = JS_NewCModule(ctx, module_name, js_module_dummy_init);\n    } else if (has_suffix(module_name, \".so\")) {\n        fprintf(stderr, \"Warning: binary module '%s' will be dynamically loaded\\n\", module_name);\n        /* create a dummy module */\n        m = JS_NewCModule(ctx, module_name, js_module_dummy_init);\n        /* the resulting executable will export its symbols for the\n           dynamic library */\n        dynamic_export = TRUE;\n    } else {\n        size_t buf_len;\n        uint8_t *buf;\n        char cname[1024];\n        int res;\n        \n        buf = js_load_file(ctx, &buf_len, module_name);\n        if (!buf) {\n            JS_ThrowReferenceError(ctx, \"could not load module filename '%s'\",\n                                   module_name);\n            return NULL;\n        }\n\n        res = js_module_test_json(ctx, attributes);\n        if (has_suffix(module_name, \".json\") || res > 0) {\n            /* compile as JSON or JSON5 depending on \"type\" */\n            JSValue val;\n            int flags;\n\n            if (res == 2)\n                flags = JS_PARSE_JSON_EXT;\n            else\n                flags = 0;\n            val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);\n            js_free(ctx, buf);\n            if (JS_IsException(val))\n                return NULL;\n            /* create a dummy module */\n            m = JS_NewCModule(ctx, module_name, js_module_dummy_init);\n            if (!m) {\n                JS_FreeValue(ctx, val);\n                return NULL;\n            }\n\n            get_c_name(cname, sizeof(cname), module_name);\n            if (namelist_find(&cname_list, cname)) {\n                find_unique_cname(cname, sizeof(cname));\n            }\n\n            /* output the module name */\n            fprintf(outfile, \"static const uint8_t %s_module_name[] = {\\n\",\n                    cname);\n            dump_hex(outfile, (const uint8_t *)module_name, strlen(module_name) + 1);\n            fprintf(outfile, \"};\\n\\n\");\n\n            output_object_code(ctx, outfile, val, cname, CNAME_TYPE_JSON_MODULE);\n            JS_FreeValue(ctx, val);\n        } else {\n            JSValue func_val;\n\n            /* compile the module */\n            func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,\n                               JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);\n            js_free(ctx, buf);\n            if (JS_IsException(func_val))\n                return NULL;\n            get_c_name(cname, sizeof(cname), module_name);\n            if (namelist_find(&cname_list, cname)) {\n                find_unique_cname(cname, sizeof(cname));\n            }\n            output_object_code(ctx, outfile, func_val, cname, CNAME_TYPE_MODULE);\n            \n            /* the module is already referenced, so we must free it */\n            m = JS_VALUE_GET_PTR(func_val);\n            JS_FreeValue(ctx, func_val);\n        }\n    }\n    return m;\n}\n\nstatic void compile_file(JSContext *ctx, FILE *fo,\n                         const char *filename,\n                         const char *c_name1,\n                         int module)\n{\n    uint8_t *buf;\n    char c_name[1024];\n    int eval_flags;\n    JSValue obj;\n    size_t buf_len;\n\n    buf = js_load_file(ctx, &buf_len, filename);\n    if (!buf) {\n        fprintf(stderr, \"Could not load '%s'\\n\", filename);\n        exit(1);\n    }\n    eval_flags = JS_EVAL_FLAG_COMPILE_ONLY;\n    if (module < 0) {\n        module = (has_suffix(filename, \".mjs\") ||\n                  JS_DetectModule((const char *)buf, buf_len));\n    }\n    if (module)\n        eval_flags |= JS_EVAL_TYPE_MODULE;\n    else\n        eval_flags |= JS_EVAL_TYPE_GLOBAL;\n    obj = JS_Eval(ctx, (const char *)buf, buf_len, filename, eval_flags);\n    if (JS_IsException(obj)) {\n        js_std_dump_error(ctx);\n        exit(1);\n    }\n    js_free(ctx, buf);\n    if (c_name1) {\n        pstrcpy(c_name, sizeof(c_name), c_name1);\n    } else {\n        get_c_name(c_name, sizeof(c_name), filename);\n        if (namelist_find(&cname_list, c_name)) {\n            find_unique_cname(c_name, sizeof(c_name));\n        }\n    }\n    output_object_code(ctx, fo, obj, c_name, CNAME_TYPE_SCRIPT);\n    JS_FreeValue(ctx, obj);\n}\n\nstatic const char main_c_template1[] =\n    \"int main(int argc, char **argv)\\n\"\n    \"{\\n\"\n    \"  JSRuntime *rt;\\n\"\n    \"  JSContext *ctx;\\n\"\n    \"  rt = JS_NewRuntime();\\n\"\n    \"  js_std_set_worker_new_context_func(JS_NewCustomContext);\\n\"\n    \"  js_std_init_handlers(rt);\\n\"\n    ;\n\nstatic const char main_c_template2[] =\n    \"  js_std_loop(ctx);\\n\"\n    \"  js_std_free_handlers(rt);\\n\"\n    \"  JS_FreeContext(ctx);\\n\"\n    \"  JS_FreeRuntime(rt);\\n\"\n    \"  return 0;\\n\"\n    \"}\\n\";\n\n#define PROG_NAME \"qjsc\"\n\nvoid help(void)\n{\n    printf(\"QuickJS Compiler version \" CONFIG_VERSION \"\\n\"\n           \"usage: \" PROG_NAME \" [options] [files]\\n\"\n           \"\\n\"\n           \"options are:\\n\"\n           \"-c          only output bytecode to a C file\\n\"\n           \"-e          output main() and bytecode to a C file (default = executable output)\\n\"\n           \"-o output   set the output filename\\n\"\n           \"-N cname    set the C name of the generated data\\n\"\n           \"-m          compile as Javascript module (default=autodetect)\\n\"\n           \"-D module_name         compile a dynamically loaded module or worker\\n\"\n           \"-M module_name[,cname] add initialization code for an external C module\\n\"\n           \"-x          byte swapped output\\n\"\n           \"-p prefix   set the prefix of the generated C names\\n\"\n           \"-S n        set the maximum stack size to 'n' bytes (default=%d)\\n\"\n           \"-s            strip all the debug info\\n\"\n           \"--keep-source keep the source code\\n\",\n           JS_DEFAULT_STACK_SIZE);\n#ifdef CONFIG_LTO\n    {\n        int i;\n        printf(\"-flto       use link time optimization\\n\");\n        printf(\"-fno-[\");\n        for(i = 0; i < countof(feature_list); i++) {\n            if (i != 0)\n                printf(\"|\");\n            printf(\"%s\", feature_list[i].option_name);\n        }\n        printf(\"]\\n\"\n               \"            disable selected language features (smaller code size)\\n\");\n    }\n#endif\n    exit(1);\n}\n\n#if defined(CONFIG_CC) && !defined(_WIN32)\n\nint exec_cmd(char **argv)\n{\n    int pid, status, ret;\n\n    pid = fork();\n    if (pid == 0) {\n        execvp(argv[0], argv);\n        exit(1);\n    }\n\n    for(;;) {\n        ret = waitpid(pid, &status, 0);\n        if (ret == pid && WIFEXITED(status))\n            break;\n    }\n    return WEXITSTATUS(status);\n}\n\nstatic int output_executable(const char *out_filename, const char *cfilename,\n                             BOOL use_lto, BOOL verbose, const char *exename)\n{\n    const char *argv[64];\n    const char **arg, *bn_suffix, *lto_suffix;\n    char libjsname[1024];\n    char exe_dir[1024], inc_dir[1024], lib_dir[1024], buf[1024], *p;\n    int ret;\n\n    /* get the directory of the executable */\n    pstrcpy(exe_dir, sizeof(exe_dir), exename);\n    p = strrchr(exe_dir, '/');\n    if (p) {\n        *p = '\\0';\n    } else {\n        pstrcpy(exe_dir, sizeof(exe_dir), \".\");\n    }\n\n    /* if 'quickjs.h' is present at the same path as the executable, we\n       use it as include and lib directory */\n    snprintf(buf, sizeof(buf), \"%s/quickjs.h\", exe_dir);\n    if (access(buf, R_OK) == 0) {\n        pstrcpy(inc_dir, sizeof(inc_dir), exe_dir);\n        pstrcpy(lib_dir, sizeof(lib_dir), exe_dir);\n    } else {\n        snprintf(inc_dir, sizeof(inc_dir), \"%s/include/quickjs\", CONFIG_PREFIX);\n        snprintf(lib_dir, sizeof(lib_dir), \"%s/lib/quickjs\", CONFIG_PREFIX);\n    }\n\n    lto_suffix = \"\";\n    bn_suffix = \"\";\n\n    arg = argv;\n    *arg++ = CONFIG_CC;\n    *arg++ = \"-O2\";\n#ifdef CONFIG_LTO\n    if (use_lto) {\n        *arg++ = \"-flto\";\n        lto_suffix = \".lto\";\n    }\n#endif\n    /* XXX: use the executable path to find the includes files and\n       libraries */\n    *arg++ = \"-D\";\n    *arg++ = \"_GNU_SOURCE\";\n    *arg++ = \"-I\";\n    *arg++ = inc_dir;\n    *arg++ = \"-o\";\n    *arg++ = out_filename;\n    if (dynamic_export)\n        *arg++ = \"-rdynamic\";\n    *arg++ = cfilename;\n    snprintf(libjsname, sizeof(libjsname), \"%s/libquickjs%s%s.a\",\n             lib_dir, bn_suffix, lto_suffix);\n    *arg++ = libjsname;\n    *arg++ = \"-lm\";\n    *arg++ = \"-ldl\";\n    *arg++ = \"-lpthread\";\n    *arg = NULL;\n\n    if (verbose) {\n        for(arg = argv; *arg != NULL; arg++)\n            printf(\"%s \", *arg);\n        printf(\"\\n\");\n    }\n\n    ret = exec_cmd((char **)argv);\n    unlink(cfilename);\n    return ret;\n}\n#else\nstatic int output_executable(const char *out_filename, const char *cfilename,\n                             BOOL use_lto, BOOL verbose, const char *exename)\n{\n    fprintf(stderr, \"Executable output is not supported for this target\\n\");\n    exit(1);\n    return 0;\n}\n#endif\n\nstatic size_t get_suffixed_size(const char *str)\n{\n    char *p;\n    size_t v;\n    v = (size_t)strtod(str, &p);\n    switch(*p) {\n    case 'G':\n        v <<= 30;\n        break;\n    case 'M':\n        v <<= 20;\n        break;\n    case 'k':\n    case 'K':\n        v <<= 10;\n        break;\n    default:\n        if (*p != '\\0') {\n            fprintf(stderr, \"qjs: invalid suffix: %s\\n\", p);\n            exit(1);\n        }\n        break;\n    }\n    return v;\n}\n\ntypedef enum {\n    OUTPUT_C,\n    OUTPUT_C_MAIN,\n    OUTPUT_EXECUTABLE,\n} OutputTypeEnum;\n\nstatic const char *get_short_optarg(int *poptind, int opt,\n                                    const char *arg, int argc, char **argv)\n{\n    const char *optarg;\n    if (*arg) {\n        optarg = arg;\n    } else if (*poptind < argc) {\n        optarg = argv[(*poptind)++];\n    } else {\n        fprintf(stderr, \"qjsc: expecting parameter for -%c\\n\", opt);\n        exit(1);\n    }\n    return optarg;\n}\n\nint main(int argc, char **argv)\n{\n    int i, verbose, strip_flags;\n    const char *out_filename, *cname;\n    char cfilename[1024];\n    FILE *fo;\n    JSRuntime *rt;\n    JSContext *ctx;\n    BOOL use_lto;\n    int module;\n    OutputTypeEnum output_type;\n    size_t stack_size;\n    namelist_t dynamic_module_list;\n\n    out_filename = NULL;\n    output_type = OUTPUT_EXECUTABLE;\n    cname = NULL;\n    feature_bitmap = FE_ALL;\n    module = -1;\n    byte_swap = FALSE;\n    verbose = 0;\n    strip_flags = JS_STRIP_SOURCE;\n    use_lto = FALSE;\n    stack_size = 0;\n    memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));\n\n    /* add system modules */\n    namelist_add(&cmodule_list, \"std\", \"std\", 0);\n    namelist_add(&cmodule_list, \"os\", \"os\", 0);\n\n    optind = 1;\n    while (optind < argc && *argv[optind] == '-') {\n        char *arg = argv[optind] + 1;\n        const char *longopt = \"\";\n        const char *optarg;\n        /* a single - is not an option, it also stops argument scanning */\n        if (!*arg)\n            break;\n        optind++;\n        if (*arg == '-') {\n            longopt = arg + 1;\n            arg += strlen(arg);\n            /* -- stops argument scanning */\n            if (!*longopt)\n                break;\n        }\n        for (; *arg || *longopt; longopt = \"\") {\n            char opt = *arg;\n            if (opt)\n                arg++;\n            if (opt == 'h' || opt == '?' || !strcmp(longopt, \"help\")) {\n                help();\n                continue;\n            }\n            if (opt == 'o') {\n                out_filename = get_short_optarg(&optind, opt, arg, argc, argv);\n                break;\n            }\n            if (opt == 'c') {\n                output_type = OUTPUT_C;\n                continue;\n            }\n            if (opt == 'e') {\n                output_type = OUTPUT_C_MAIN;\n                continue;\n            }\n            if (opt == 'N') {\n                cname = get_short_optarg(&optind, opt, arg, argc, argv);\n                break;\n            }\n            if (opt == 'f') {\n                const char *p;\n                optarg = get_short_optarg(&optind, opt, arg, argc, argv);\n                p = optarg;\n                if (!strcmp(p, \"lto\")) {\n                    use_lto = TRUE;\n                } else if (strstart(p, \"no-\", &p)) {\n                    use_lto = TRUE;\n                    for(i = 0; i < countof(feature_list); i++) {\n                        if (!strcmp(p, feature_list[i].option_name)) {\n                            feature_bitmap &= ~((uint64_t)1 << i);\n                            break;\n                        }\n                    }\n                    if (i == countof(feature_list))\n                        goto bad_feature;\n                } else {\n                bad_feature:\n                    fprintf(stderr, \"unsupported feature: %s\\n\", optarg);\n                    exit(1);\n                }\n                break;\n            }\n            if (opt == 'm') {\n                module = 1;\n                continue;\n            }\n            if (opt == 'M') {\n                char *p;\n                char path[1024];\n                char cname[1024];\n\n                optarg = get_short_optarg(&optind, opt, arg, argc, argv);\n                pstrcpy(path, sizeof(path), optarg);\n                p = strchr(path, ',');\n                if (p) {\n                    *p = '\\0';\n                    pstrcpy(cname, sizeof(cname), p + 1);\n                } else {\n                    get_c_name(cname, sizeof(cname), path);\n                }\n                namelist_add(&cmodule_list, path, cname, 0);\n                break;\n            }\n            if (opt == 'D') {\n                optarg = get_short_optarg(&optind, opt, arg, argc, argv);\n                namelist_add(&dynamic_module_list, optarg, NULL, 0);\n                break;\n            }\n            if (opt == 'x') {\n                byte_swap = 1;\n                continue;\n            }\n            if (opt == 'v') {\n                verbose++;\n                continue;\n            }\n            if (opt == 'p') {\n                c_ident_prefix = get_short_optarg(&optind, opt, arg, argc, argv);\n                break;\n            }\n            if (opt == 'S') {\n                optarg = get_short_optarg(&optind, opt, arg, argc, argv);\n                stack_size = get_suffixed_size(optarg);\n                break;\n            }\n            if (opt == 's') {\n                strip_flags = JS_STRIP_DEBUG;\n                continue;\n            }\n            if (!strcmp(longopt, \"keep-source\")) {\n                strip_flags = 0;\n                continue;\n            }\n            if (opt) {\n                fprintf(stderr, \"qjsc: unknown option '-%c'\\n\", opt);\n            } else {\n                fprintf(stderr, \"qjsc: unknown option '--%s'\\n\", longopt);\n            }\n            help();\n        }\n    }\n\n    if (optind >= argc)\n        help();\n\n    if (!out_filename) {\n        if (output_type == OUTPUT_EXECUTABLE) {\n            out_filename = \"a.out\";\n        } else {\n            out_filename = \"out.c\";\n        }\n    }\n\n    if (output_type == OUTPUT_EXECUTABLE) {\n#if defined(_WIN32) || defined(__ANDROID__)\n        /* XXX: find a /tmp directory ? */\n        snprintf(cfilename, sizeof(cfilename), \"out%d.c\", getpid());\n#else\n        snprintf(cfilename, sizeof(cfilename), \"/tmp/out%d.c\", getpid());\n#endif\n    } else {\n        pstrcpy(cfilename, sizeof(cfilename), out_filename);\n    }\n\n    fo = fopen(cfilename, \"w\");\n    if (!fo) {\n        perror(cfilename);\n        exit(1);\n    }\n    outfile = fo;\n\n    rt = JS_NewRuntime();\n    ctx = JS_NewContext(rt);\n\n    JS_SetStripInfo(rt, strip_flags);\n\n    /* loader for ES6 modules */\n    JS_SetModuleLoaderFunc2(rt, NULL, jsc_module_loader, NULL, NULL);\n\n    fprintf(fo, \"/* File generated automatically by the QuickJS compiler. */\\n\"\n            \"\\n\"\n            );\n\n    if (output_type != OUTPUT_C) {\n        fprintf(fo, \"#include \\\"quickjs-libc.h\\\"\\n\"\n                \"\\n\"\n                );\n    } else {\n        fprintf(fo, \"#include <inttypes.h>\\n\"\n                \"\\n\"\n                );\n    }\n\n    for(i = optind; i < argc; i++) {\n        const char *filename = argv[i];\n        compile_file(ctx, fo, filename, cname, module);\n        cname = NULL;\n    }\n\n    for(i = 0; i < dynamic_module_list.count; i++) {\n        if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL, JS_UNDEFINED)) {\n            fprintf(stderr, \"Could not load dynamic module '%s'\\n\",\n                    dynamic_module_list.array[i].name);\n            exit(1);\n        }\n    }\n\n    if (output_type != OUTPUT_C) {\n        fprintf(fo,\n                \"static JSContext *JS_NewCustomContext(JSRuntime *rt)\\n\"\n                \"{\\n\"\n                \"  JSContext *ctx = JS_NewContextRaw(rt);\\n\"\n                \"  if (!ctx)\\n\"\n                \"    return NULL;\\n\");\n        /* add the basic objects */\n        fprintf(fo, \"  JS_AddIntrinsicBaseObjects(ctx);\\n\");\n        for(i = 0; i < countof(feature_list); i++) {\n            if ((feature_bitmap & ((uint64_t)1 << i)) &&\n                feature_list[i].init_name) {\n                fprintf(fo, \"  JS_AddIntrinsic%s(ctx);\\n\",\n                        feature_list[i].init_name);\n            }\n        }\n        /* add the precompiled modules (XXX: could modify the module\n           loader instead) */\n        for(i = 0; i < init_module_list.count; i++) {\n            namelist_entry_t *e = &init_module_list.array[i];\n            /* initialize the static C modules */\n\n            fprintf(fo,\n                    \"  {\\n\"\n                    \"    extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\\n\"\n                    \"    js_init_module_%s(ctx, \\\"%s\\\");\\n\"\n                    \"  }\\n\",\n                    e->short_name, e->short_name, e->name);\n        }\n        for(i = 0; i < cname_list.count; i++) {\n            namelist_entry_t *e = &cname_list.array[i];\n            if (e->flags == CNAME_TYPE_MODULE) {\n                fprintf(fo, \"  js_std_eval_binary(ctx, %s, %s_size, 1);\\n\",\n                        e->name, e->name);\n            } else if (e->flags == CNAME_TYPE_JSON_MODULE) {\n                fprintf(fo, \"  js_std_eval_binary_json_module(ctx, %s, %s_size, (const char *)%s_module_name);\\n\",\n                        e->name, e->name, e->name);\n            }\n        }\n        fprintf(fo,\n                \"  return ctx;\\n\"\n                \"}\\n\\n\");\n\n        fputs(main_c_template1, fo);\n\n        if (stack_size != 0) {\n            fprintf(fo, \"  JS_SetMaxStackSize(rt, %u);\\n\",\n                    (unsigned int)stack_size);\n        }\n\n        /* add the module loader if necessary */\n        if (feature_bitmap & (1 << FE_MODULE_LOADER)) {\n            fprintf(fo, \"  JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);\\n\");\n        }\n\n        fprintf(fo,\n                \"  ctx = JS_NewCustomContext(rt);\\n\"\n                \"  js_std_add_helpers(ctx, argc, argv);\\n\");\n\n        for(i = 0; i < cname_list.count; i++) {\n            namelist_entry_t *e = &cname_list.array[i];\n            if (e->flags == CNAME_TYPE_SCRIPT) {\n                fprintf(fo, \"  js_std_eval_binary(ctx, %s, %s_size, 0);\\n\",\n                        e->name, e->name);\n            }\n        }\n        fputs(main_c_template2, fo);\n    }\n\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n\n    fclose(fo);\n\n    if (output_type == OUTPUT_EXECUTABLE) {\n        return output_executable(out_filename, cfilename, use_lto, verbose,\n                                 argv[0]);\n    }\n    namelist_free(&cname_list);\n    namelist_free(&cmodule_list);\n    namelist_free(&init_module_list);\n    return 0;\n}\n"
  },
  {
    "path": "quickjs-atom.h",
    "content": "/*\n * QuickJS atom definitions\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n * Copyright (c) 2017-2018 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifdef DEF\n\n/* Note: first atoms are considered as keywords in the parser */\nDEF(null, \"null\") /* must be first */\nDEF(false, \"false\")\nDEF(true, \"true\")\nDEF(if, \"if\")\nDEF(else, \"else\")\nDEF(return, \"return\")\nDEF(var, \"var\")\nDEF(this, \"this\")\nDEF(delete, \"delete\")\nDEF(void, \"void\")\nDEF(typeof, \"typeof\")\nDEF(new, \"new\")\nDEF(in, \"in\")\nDEF(instanceof, \"instanceof\")\nDEF(do, \"do\")\nDEF(while, \"while\")\nDEF(for, \"for\")\nDEF(break, \"break\")\nDEF(continue, \"continue\")\nDEF(switch, \"switch\")\nDEF(case, \"case\")\nDEF(default, \"default\")\nDEF(throw, \"throw\")\nDEF(try, \"try\")\nDEF(catch, \"catch\")\nDEF(finally, \"finally\")\nDEF(function, \"function\")\nDEF(debugger, \"debugger\")\nDEF(with, \"with\")\n/* FutureReservedWord */\nDEF(class, \"class\")\nDEF(const, \"const\")\nDEF(enum, \"enum\")\nDEF(export, \"export\")\nDEF(extends, \"extends\")\nDEF(import, \"import\")\nDEF(super, \"super\")\n/* FutureReservedWords when parsing strict mode code */\nDEF(implements, \"implements\")\nDEF(interface, \"interface\")\nDEF(let, \"let\")\nDEF(package, \"package\")\nDEF(private, \"private\")\nDEF(protected, \"protected\")\nDEF(public, \"public\")\nDEF(static, \"static\")\nDEF(yield, \"yield\")\nDEF(await, \"await\")\n\n/* empty string */\nDEF(empty_string, \"\")\n/* identifiers */\nDEF(keys, \"keys\")\nDEF(size, \"size\")\nDEF(length, \"length\")\nDEF(fileName, \"fileName\")\nDEF(lineNumber, \"lineNumber\")\nDEF(columnNumber, \"columnNumber\")\nDEF(message, \"message\")\nDEF(cause, \"cause\")\nDEF(errors, \"errors\")\nDEF(stack, \"stack\")\nDEF(name, \"name\")\nDEF(toString, \"toString\")\nDEF(toLocaleString, \"toLocaleString\")\nDEF(valueOf, \"valueOf\")\nDEF(eval, \"eval\")\nDEF(prototype, \"prototype\")\nDEF(constructor, \"constructor\")\nDEF(configurable, \"configurable\")\nDEF(writable, \"writable\")\nDEF(enumerable, \"enumerable\")\nDEF(value, \"value\")\nDEF(get, \"get\")\nDEF(set, \"set\")\nDEF(of, \"of\")\nDEF(__proto__, \"__proto__\")\nDEF(undefined, \"undefined\")\nDEF(number, \"number\")\nDEF(boolean, \"boolean\")\nDEF(string, \"string\")\nDEF(object, \"object\")\nDEF(symbol, \"symbol\")\nDEF(integer, \"integer\")\nDEF(unknown, \"unknown\")\nDEF(arguments, \"arguments\")\nDEF(callee, \"callee\")\nDEF(caller, \"caller\")\nDEF(_eval_, \"<eval>\")\nDEF(_ret_, \"<ret>\")\nDEF(_var_, \"<var>\")\nDEF(_arg_var_, \"<arg_var>\")\nDEF(_with_, \"<with>\")\nDEF(lastIndex, \"lastIndex\")\nDEF(target, \"target\")\nDEF(index, \"index\")\nDEF(input, \"input\")\nDEF(defineProperties, \"defineProperties\")\nDEF(apply, \"apply\")\nDEF(join, \"join\")\nDEF(concat, \"concat\")\nDEF(split, \"split\")\nDEF(construct, \"construct\")\nDEF(getPrototypeOf, \"getPrototypeOf\")\nDEF(setPrototypeOf, \"setPrototypeOf\")\nDEF(isExtensible, \"isExtensible\")\nDEF(preventExtensions, \"preventExtensions\")\nDEF(has, \"has\")\nDEF(deleteProperty, \"deleteProperty\")\nDEF(defineProperty, \"defineProperty\")\nDEF(getOwnPropertyDescriptor, \"getOwnPropertyDescriptor\")\nDEF(ownKeys, \"ownKeys\")\nDEF(add, \"add\")\nDEF(done, \"done\")\nDEF(next, \"next\")\nDEF(values, \"values\")\nDEF(source, \"source\")\nDEF(flags, \"flags\")\nDEF(global, \"global\")\nDEF(unicode, \"unicode\")\nDEF(raw, \"raw\")\nDEF(new_target, \"new.target\")\nDEF(this_active_func, \"this.active_func\")\nDEF(home_object, \"<home_object>\")\nDEF(computed_field, \"<computed_field>\")\nDEF(static_computed_field, \"<static_computed_field>\") /* must come after computed_fields */\nDEF(class_fields_init, \"<class_fields_init>\")\nDEF(brand, \"<brand>\")\nDEF(hash_constructor, \"#constructor\")\nDEF(as, \"as\")\nDEF(from, \"from\")\nDEF(meta, \"meta\")\nDEF(_default_, \"*default*\")\nDEF(_star_, \"*\")\nDEF(Module, \"Module\")\nDEF(then, \"then\")\nDEF(resolve, \"resolve\")\nDEF(reject, \"reject\")\nDEF(promise, \"promise\")\nDEF(proxy, \"proxy\")\nDEF(revoke, \"revoke\")\nDEF(async, \"async\")\nDEF(exec, \"exec\")\nDEF(groups, \"groups\")\nDEF(indices, \"indices\")\nDEF(status, \"status\")\nDEF(reason, \"reason\")\nDEF(globalThis, \"globalThis\")\nDEF(bigint, \"bigint\")\nDEF(minus_zero, \"-0\")\nDEF(Infinity, \"Infinity\")\nDEF(minus_Infinity, \"-Infinity\")\nDEF(NaN, \"NaN\")\nDEF(hasIndices, \"hasIndices\")\nDEF(ignoreCase, \"ignoreCase\")\nDEF(multiline, \"multiline\")\nDEF(dotAll, \"dotAll\")\nDEF(sticky, \"sticky\")\nDEF(unicodeSets, \"unicodeSets\")\n/* the following 3 atoms are only used with CONFIG_ATOMICS */\nDEF(not_equal, \"not-equal\")\nDEF(timed_out, \"timed-out\")\nDEF(ok, \"ok\")\n/* */\nDEF(toJSON, \"toJSON\")\nDEF(maxByteLength, \"maxByteLength\")\n/* class names */\nDEF(Object, \"Object\")\nDEF(Array, \"Array\")\nDEF(Error, \"Error\")\nDEF(Number, \"Number\")\nDEF(String, \"String\")\nDEF(Boolean, \"Boolean\")\nDEF(Symbol, \"Symbol\")\nDEF(Arguments, \"Arguments\")\nDEF(Math, \"Math\")\nDEF(JSON, \"JSON\")\nDEF(Date, \"Date\")\nDEF(Function, \"Function\")\nDEF(GeneratorFunction, \"GeneratorFunction\")\nDEF(ForInIterator, \"ForInIterator\")\nDEF(RegExp, \"RegExp\")\nDEF(ArrayBuffer, \"ArrayBuffer\")\nDEF(SharedArrayBuffer, \"SharedArrayBuffer\")\n/* must keep same order as class IDs for typed arrays */\nDEF(Uint8ClampedArray, \"Uint8ClampedArray\")\nDEF(Int8Array, \"Int8Array\")\nDEF(Uint8Array, \"Uint8Array\")\nDEF(Int16Array, \"Int16Array\")\nDEF(Uint16Array, \"Uint16Array\")\nDEF(Int32Array, \"Int32Array\")\nDEF(Uint32Array, \"Uint32Array\")\nDEF(BigInt64Array, \"BigInt64Array\")\nDEF(BigUint64Array, \"BigUint64Array\")\nDEF(Float16Array, \"Float16Array\")\nDEF(Float32Array, \"Float32Array\")\nDEF(Float64Array, \"Float64Array\")\nDEF(DataView, \"DataView\")\nDEF(BigInt, \"BigInt\")\nDEF(WeakRef, \"WeakRef\")\nDEF(FinalizationRegistry, \"FinalizationRegistry\")\nDEF(Map, \"Map\")\nDEF(Set, \"Set\") /* Map + 1 */\nDEF(WeakMap, \"WeakMap\") /* Map + 2 */\nDEF(WeakSet, \"WeakSet\") /* Map + 3 */\nDEF(Iterator, \"Iterator\")\nDEF(IteratorHelper, \"Iterator Helper\")\nDEF(IteratorConcat, \"Iterator Concat\")\nDEF(IteratorWrap, \"Iterator Wrap\")\nDEF(Map_Iterator, \"Map Iterator\")\nDEF(Set_Iterator, \"Set Iterator\")\nDEF(Array_Iterator, \"Array Iterator\")\nDEF(String_Iterator, \"String Iterator\")\nDEF(RegExp_String_Iterator, \"RegExp String Iterator\")\nDEF(Generator, \"Generator\")\nDEF(Proxy, \"Proxy\")\nDEF(Promise, \"Promise\")\nDEF(PromiseResolveFunction, \"PromiseResolveFunction\")\nDEF(PromiseRejectFunction, \"PromiseRejectFunction\")\nDEF(AsyncFunction, \"AsyncFunction\")\nDEF(AsyncFunctionResolve, \"AsyncFunctionResolve\")\nDEF(AsyncFunctionReject, \"AsyncFunctionReject\")\nDEF(AsyncGeneratorFunction, \"AsyncGeneratorFunction\")\nDEF(AsyncGenerator, \"AsyncGenerator\")\nDEF(EvalError, \"EvalError\")\nDEF(RangeError, \"RangeError\")\nDEF(ReferenceError, \"ReferenceError\")\nDEF(SyntaxError, \"SyntaxError\")\nDEF(TypeError, \"TypeError\")\nDEF(URIError, \"URIError\")\nDEF(InternalError, \"InternalError\")\nDEF(AggregateError, \"AggregateError\")\n/* private symbols */\nDEF(Private_brand, \"<brand>\")\n/* symbols */\nDEF(Symbol_toPrimitive, \"Symbol.toPrimitive\")\nDEF(Symbol_iterator, \"Symbol.iterator\")\nDEF(Symbol_match, \"Symbol.match\")\nDEF(Symbol_matchAll, \"Symbol.matchAll\")\nDEF(Symbol_replace, \"Symbol.replace\")\nDEF(Symbol_search, \"Symbol.search\")\nDEF(Symbol_split, \"Symbol.split\")\nDEF(Symbol_toStringTag, \"Symbol.toStringTag\")\nDEF(Symbol_isConcatSpreadable, \"Symbol.isConcatSpreadable\")\nDEF(Symbol_hasInstance, \"Symbol.hasInstance\")\nDEF(Symbol_species, \"Symbol.species\")\nDEF(Symbol_unscopables, \"Symbol.unscopables\")\nDEF(Symbol_asyncIterator, \"Symbol.asyncIterator\")\n\n#endif /* DEF */\n"
  },
  {
    "path": "quickjs-libc.c",
    "content": "/*\n * QuickJS C library\n *\n * Copyright (c) 2017-2021 Fabrice Bellard\n * Copyright (c) 2017-2021 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n#include <unistd.h>\n#include <errno.h>\n#include <fcntl.h>\n#include <sys/time.h>\n#include <time.h>\n#include <signal.h>\n#include <limits.h>\n#include <sys/stat.h>\n#include <dirent.h>\n#if defined(_WIN32)\n#include <windows.h>\n#include <conio.h>\n#include <utime.h>\n#else\n#include <dlfcn.h>\n#include <termios.h>\n#include <sys/ioctl.h>\n#include <sys/wait.h>\n\n#if defined(__FreeBSD__)\nextern char **environ;\n#endif\n\n#if defined(__APPLE__) || defined(__FreeBSD__)\ntypedef sig_t sighandler_t;\n#endif\n\n#if defined(__APPLE__)\n#if !defined(environ)\n#include <crt_externs.h>\n#define environ (*_NSGetEnviron())\n#endif\n#endif /* __APPLE__ */\n\n#endif\n\n/* enable the os.Worker API. It relies on POSIX threads */\n#define USE_WORKER\n\n#ifdef USE_WORKER\n#include <pthread.h>\n#include <stdatomic.h>\n#endif\n\n#include \"cutils.h\"\n#include \"list.h\"\n#include \"quickjs-libc.h\"\n\n#if !defined(PATH_MAX)\n#define PATH_MAX 4096\n#endif\n\n/* TODO:\n   - add socket calls\n*/\n\ntypedef struct {\n    struct list_head link;\n    int fd;\n    JSValue rw_func[2];\n} JSOSRWHandler;\n\ntypedef struct {\n    struct list_head link;\n    int sig_num;\n    JSValue func;\n} JSOSSignalHandler;\n\ntypedef struct {\n    struct list_head link;\n    int timer_id;\n    int64_t timeout;\n    JSValue func;\n} JSOSTimer;\n\ntypedef struct {\n    struct list_head link;\n    uint8_t *data;\n    size_t data_len;\n    /* list of SharedArrayBuffers, necessary to free the message */\n    uint8_t **sab_tab;\n    size_t sab_tab_len;\n} JSWorkerMessage;\n\ntypedef struct JSWaker {\n#ifdef _WIN32\n    HANDLE handle;\n#else\n    int read_fd;\n    int write_fd;\n#endif\n} JSWaker;\n\ntypedef struct {\n    int ref_count;\n#ifdef USE_WORKER\n    pthread_mutex_t mutex;\n#endif\n    struct list_head msg_queue; /* list of JSWorkerMessage.link */\n    JSWaker waker;\n} JSWorkerMessagePipe;\n\ntypedef struct {\n    struct list_head link;\n    JSWorkerMessagePipe *recv_pipe;\n    JSValue on_message_func;\n} JSWorkerMessageHandler;\n\ntypedef struct {\n    struct list_head link;\n    JSValue promise;\n    JSValue reason;\n} JSRejectedPromiseEntry;\n\ntypedef struct JSThreadState {\n    struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */\n    struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */\n    struct list_head os_timers; /* list of JSOSTimer.link */\n    struct list_head port_list; /* list of JSWorkerMessageHandler.link */\n    struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */\n    int eval_script_recurse; /* only used in the main thread */\n    int next_timer_id; /* for setTimeout() */\n    /* not used in the main thread */\n    JSWorkerMessagePipe *recv_pipe, *send_pipe;\n} JSThreadState;\n\nstatic uint64_t os_pending_signals;\nstatic int (*os_poll_func)(JSContext *ctx);\n\nstatic void js_std_dbuf_init(JSContext *ctx, DynBuf *s)\n{\n    dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);\n}\n\nstatic BOOL my_isdigit(int c)\n{\n    return (c >= '0' && c <= '9');\n}\n\n/* XXX: use 'o' and 'O' for object using JS_PrintValue() ? */\nstatic JSValue js_printf_internal(JSContext *ctx,\n                                  int argc, JSValueConst *argv, FILE *fp)\n{\n    char fmtbuf[32];\n    uint8_t cbuf[UTF8_CHAR_LEN_MAX+1];\n    JSValue res;\n    DynBuf dbuf;\n    const char *fmt_str = NULL;\n    const uint8_t *fmt, *fmt_end;\n    const uint8_t *p;\n    char *q;\n    int i, c, len, mod;\n    size_t fmt_len;\n    int32_t int32_arg;\n    int64_t int64_arg;\n    double double_arg;\n    const char *string_arg;\n    /* Use indirect call to dbuf_printf to prevent gcc warning */\n    int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf;\n\n    js_std_dbuf_init(ctx, &dbuf);\n\n    if (argc > 0) {\n        fmt_str = JS_ToCStringLen(ctx, &fmt_len, argv[0]);\n        if (!fmt_str)\n            goto fail;\n\n        i = 1;\n        fmt = (const uint8_t *)fmt_str;\n        fmt_end = fmt + fmt_len;\n        while (fmt < fmt_end) {\n            for (p = fmt; fmt < fmt_end && *fmt != '%'; fmt++)\n                continue;\n            dbuf_put(&dbuf, p, fmt - p);\n            if (fmt >= fmt_end)\n                break;\n            q = fmtbuf;\n            *q++ = *fmt++;  /* copy '%' */\n\n            /* flags */\n            for(;;) {\n                c = *fmt;\n                if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||\n                    c == '\\'') {\n                    if (q >= fmtbuf + sizeof(fmtbuf) - 1)\n                        goto invalid;\n                    *q++ = c;\n                    fmt++;\n                } else {\n                    break;\n                }\n            }\n            /* width */\n            if (*fmt == '*') {\n                if (i >= argc)\n                    goto missing;\n                if (JS_ToInt32(ctx, &int32_arg, argv[i++]))\n                    goto fail;\n                q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, \"%d\", int32_arg);\n                fmt++;\n            } else {\n                while (my_isdigit(*fmt)) {\n                    if (q >= fmtbuf + sizeof(fmtbuf) - 1)\n                        goto invalid;\n                    *q++ = *fmt++;\n                }\n            }\n            if (*fmt == '.') {\n                if (q >= fmtbuf + sizeof(fmtbuf) - 1)\n                    goto invalid;\n                *q++ = *fmt++;\n                if (*fmt == '*') {\n                    if (i >= argc)\n                        goto missing;\n                    if (JS_ToInt32(ctx, &int32_arg, argv[i++]))\n                        goto fail;\n                    q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, \"%d\", int32_arg);\n                    fmt++;\n                } else {\n                    while (my_isdigit(*fmt)) {\n                        if (q >= fmtbuf + sizeof(fmtbuf) - 1)\n                            goto invalid;\n                        *q++ = *fmt++;\n                    }\n                }\n            }\n\n            /* we only support the \"l\" modifier for 64 bit numbers */\n            mod = ' ';\n            if (*fmt == 'l') {\n                mod = *fmt++;\n            }\n\n            /* type */\n            c = *fmt++;\n            if (q >= fmtbuf + sizeof(fmtbuf) - 1)\n                goto invalid;\n            *q++ = c;\n            *q = '\\0';\n\n            switch (c) {\n            case 'c':\n                if (i >= argc)\n                    goto missing;\n                if (JS_IsString(argv[i])) {\n                    string_arg = JS_ToCString(ctx, argv[i++]);\n                    if (!string_arg)\n                        goto fail;\n                    int32_arg = unicode_from_utf8((const uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);\n                    JS_FreeCString(ctx, string_arg);\n                } else {\n                    if (JS_ToInt32(ctx, &int32_arg, argv[i++]))\n                        goto fail;\n                }\n                /* handle utf-8 encoding explicitly */\n                if ((unsigned)int32_arg > 0x10FFFF)\n                    int32_arg = 0xFFFD;\n                /* ignore conversion flags, width and precision */\n                len = unicode_to_utf8(cbuf, int32_arg);\n                dbuf_put(&dbuf, cbuf, len);\n                break;\n\n            case 'd':\n            case 'i':\n            case 'o':\n            case 'u':\n            case 'x':\n            case 'X':\n                if (i >= argc)\n                    goto missing;\n                if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))\n                    goto fail;\n                if (mod == 'l') {\n                    /* 64 bit number */\n#if defined(_WIN32)\n                    if (q >= fmtbuf + sizeof(fmtbuf) - 3)\n                        goto invalid;\n                    q[2] = q[-1];\n                    q[-1] = 'I';\n                    q[0] = '6';\n                    q[1] = '4';\n                    q[3] = '\\0';\n                    dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);\n#else\n                    if (q >= fmtbuf + sizeof(fmtbuf) - 2)\n                        goto invalid;\n                    q[1] = q[-1];\n                    q[-1] = q[0] = 'l';\n                    q[2] = '\\0';\n                    dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);\n#endif\n                } else {\n                    dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);\n                }\n                break;\n\n            case 's':\n                if (i >= argc)\n                    goto missing;\n                /* XXX: handle strings containing null characters */\n                string_arg = JS_ToCString(ctx, argv[i++]);\n                if (!string_arg)\n                    goto fail;\n                dbuf_printf_fun(&dbuf, fmtbuf, string_arg);\n                JS_FreeCString(ctx, string_arg);\n                break;\n\n            case 'e':\n            case 'f':\n            case 'g':\n            case 'a':\n            case 'E':\n            case 'F':\n            case 'G':\n            case 'A':\n                if (i >= argc)\n                    goto missing;\n                if (JS_ToFloat64(ctx, &double_arg, argv[i++]))\n                    goto fail;\n                dbuf_printf_fun(&dbuf, fmtbuf, double_arg);\n                break;\n\n            case '%':\n                dbuf_putc(&dbuf, '%');\n                break;\n\n            default:\n                /* XXX: should support an extension mechanism */\n            invalid:\n                JS_ThrowTypeError(ctx, \"invalid conversion specifier in format string\");\n                goto fail;\n            missing:\n                JS_ThrowReferenceError(ctx, \"missing argument for conversion specifier\");\n                goto fail;\n            }\n        }\n        JS_FreeCString(ctx, fmt_str);\n    }\n    if (dbuf.error) {\n        res = JS_ThrowOutOfMemory(ctx);\n    } else {\n        if (fp) {\n            len = fwrite(dbuf.buf, 1, dbuf.size, fp);\n            res = JS_NewInt32(ctx, len);\n        } else {\n            res = JS_NewStringLen(ctx, (char *)dbuf.buf, dbuf.size);\n        }\n    }\n    dbuf_free(&dbuf);\n    return res;\n\nfail:\n    JS_FreeCString(ctx, fmt_str);\n    dbuf_free(&dbuf);\n    return JS_EXCEPTION;\n}\n\nuint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename)\n{\n    FILE *f;\n    uint8_t *buf;\n    size_t buf_len;\n    long lret;\n\n    f = fopen(filename, \"rb\");\n    if (!f)\n        return NULL;\n    if (fseek(f, 0, SEEK_END) < 0)\n        goto fail;\n    lret = ftell(f);\n    if (lret < 0)\n        goto fail;\n    /* XXX: on Linux, ftell() return LONG_MAX for directories */\n    if (lret == LONG_MAX) {\n        errno = EISDIR;\n        goto fail;\n    }\n    buf_len = lret;\n    if (fseek(f, 0, SEEK_SET) < 0)\n        goto fail;\n    if (ctx)\n        buf = js_malloc(ctx, buf_len + 1);\n    else\n        buf = malloc(buf_len + 1);\n    if (!buf)\n        goto fail;\n    if (fread(buf, 1, buf_len, f) != buf_len) {\n        errno = EIO;\n        if (ctx)\n            js_free(ctx, buf);\n        else\n            free(buf);\n    fail:\n        fclose(f);\n        return NULL;\n    }\n    buf[buf_len] = '\\0';\n    fclose(f);\n    *pbuf_len = buf_len;\n    return buf;\n}\n\n/* load and evaluate a file */\nstatic JSValue js_loadScript(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    uint8_t *buf;\n    const char *filename;\n    JSValue ret;\n    size_t buf_len;\n\n    filename = JS_ToCString(ctx, argv[0]);\n    if (!filename)\n        return JS_EXCEPTION;\n    buf = js_load_file(ctx, &buf_len, filename);\n    if (!buf) {\n        JS_ThrowReferenceError(ctx, \"could not load '%s'\", filename);\n        JS_FreeCString(ctx, filename);\n        return JS_EXCEPTION;\n    }\n    ret = JS_Eval(ctx, (char *)buf, buf_len, filename,\n                  JS_EVAL_TYPE_GLOBAL);\n    js_free(ctx, buf);\n    JS_FreeCString(ctx, filename);\n    return ret;\n}\n\n/* load a file as a UTF-8 encoded string */\nstatic JSValue js_std_loadFile(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    uint8_t *buf;\n    const char *filename;\n    JSValue ret;\n    size_t buf_len;\n\n    filename = JS_ToCString(ctx, argv[0]);\n    if (!filename)\n        return JS_EXCEPTION;\n    buf = js_load_file(ctx, &buf_len, filename);\n    JS_FreeCString(ctx, filename);\n    if (!buf)\n        return JS_NULL;\n    ret = JS_NewStringLen(ctx, (char *)buf, buf_len);\n    js_free(ctx, buf);\n    return ret;\n}\n\ntypedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,\n                                        const char *module_name);\n\n\n#if defined(_WIN32)\nstatic JSModuleDef *js_module_loader_so(JSContext *ctx,\n                                        const char *module_name)\n{\n    JS_ThrowReferenceError(ctx, \"shared library modules are not supported yet\");\n    return NULL;\n}\n#else\nstatic JSModuleDef *js_module_loader_so(JSContext *ctx,\n                                        const char *module_name)\n{\n    JSModuleDef *m;\n    void *hd;\n    JSInitModuleFunc *init;\n    char *filename;\n\n    if (!strchr(module_name, '/')) {\n        /* must add a '/' so that the DLL is not searched in the\n           system library paths */\n        filename = js_malloc(ctx, strlen(module_name) + 2 + 1);\n        if (!filename)\n            return NULL;\n        strcpy(filename, \"./\");\n        strcpy(filename + 2, module_name);\n    } else {\n        filename = (char *)module_name;\n    }\n\n    /* C module */\n    hd = dlopen(filename, RTLD_NOW | RTLD_LOCAL);\n    if (filename != module_name)\n        js_free(ctx, filename);\n    if (!hd) {\n        JS_ThrowReferenceError(ctx, \"could not load module filename '%s' as shared library\",\n                               module_name);\n        goto fail;\n    }\n\n    init = dlsym(hd, \"js_init_module\");\n    if (!init) {\n        JS_ThrowReferenceError(ctx, \"could not load module filename '%s': js_init_module not found\",\n                               module_name);\n        goto fail;\n    }\n\n    m = init(ctx, module_name);\n    if (!m) {\n        JS_ThrowReferenceError(ctx, \"could not load module filename '%s': initialization error\",\n                               module_name);\n    fail:\n        if (hd)\n            dlclose(hd);\n        return NULL;\n    }\n    return m;\n}\n#endif /* !_WIN32 */\n\nint js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,\n                              JS_BOOL use_realpath, JS_BOOL is_main)\n{\n    JSModuleDef *m;\n    char buf[PATH_MAX + 16];\n    JSValue meta_obj;\n    JSAtom module_name_atom;\n    const char *module_name;\n\n    assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);\n    m = JS_VALUE_GET_PTR(func_val);\n\n    module_name_atom = JS_GetModuleName(ctx, m);\n    module_name = JS_AtomToCString(ctx, module_name_atom);\n    JS_FreeAtom(ctx, module_name_atom);\n    if (!module_name)\n        return -1;\n    if (!strchr(module_name, ':')) {\n        strcpy(buf, \"file://\");\n#if !defined(_WIN32)\n        /* realpath() cannot be used with modules compiled with qjsc\n           because the corresponding module source code is not\n           necessarily present */\n        if (use_realpath) {\n            char *res = realpath(module_name, buf + strlen(buf));\n            if (!res) {\n                JS_ThrowTypeError(ctx, \"realpath failure\");\n                JS_FreeCString(ctx, module_name);\n                return -1;\n            }\n        } else\n#endif\n        {\n            pstrcat(buf, sizeof(buf), module_name);\n        }\n    } else {\n        pstrcpy(buf, sizeof(buf), module_name);\n    }\n    JS_FreeCString(ctx, module_name);\n\n    meta_obj = JS_GetImportMeta(ctx, m);\n    if (JS_IsException(meta_obj))\n        return -1;\n    JS_DefinePropertyValueStr(ctx, meta_obj, \"url\",\n                              JS_NewString(ctx, buf),\n                              JS_PROP_C_W_E);\n    JS_DefinePropertyValueStr(ctx, meta_obj, \"main\",\n                              JS_NewBool(ctx, is_main),\n                              JS_PROP_C_W_E);\n    JS_FreeValue(ctx, meta_obj);\n    return 0;\n}\n\nstatic int json_module_init(JSContext *ctx, JSModuleDef *m)\n{\n    JSValue val;\n    val = JS_GetModulePrivateValue(ctx, m);\n    JS_SetModuleExport(ctx, m, \"default\", val);\n    return 0;\n}\n\nstatic JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val)\n{\n    JSModuleDef *m;\n    m = JS_NewCModule(ctx, module_name, json_module_init);\n    if (!m) {\n        JS_FreeValue(ctx, val);\n        return NULL;\n    }\n    /* only export the \"default\" symbol which will contain the JSON object */\n    JS_AddModuleExport(ctx, m, \"default\");\n    JS_SetModulePrivateValue(ctx, m, val);\n    return m;\n}\n\n/* in order to conform with the specification, only the keys should be\n   tested and not the associated values. */\nint js_module_check_attributes(JSContext *ctx, void *opaque,\n                               JSValueConst attributes)\n{\n    JSPropertyEnum *tab;\n    uint32_t i, len;\n    int ret;\n    const char *cstr;\n    size_t cstr_len;\n    \n    if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))\n        return -1;\n    ret = 0;\n    for(i = 0; i < len; i++) {\n        cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);\n        if (!cstr) {\n            ret = -1;\n            break;\n        }\n        if (!(cstr_len == 4 && !memcmp(cstr, \"type\", cstr_len))) {\n            JS_ThrowTypeError(ctx, \"import attribute '%s' is not supported\", cstr);\n            ret = -1;\n        }\n        JS_FreeCString(ctx, cstr);\n        if (ret)\n            break;\n    }\n    JS_FreePropertyEnum(ctx, tab, len);\n    return ret;\n}\n\n/* return > 0 if the attributes indicate a JSON module */\nint js_module_test_json(JSContext *ctx, JSValueConst attributes)\n{\n    JSValue str;\n    const char *cstr;\n    size_t len;\n    BOOL res;\n\n    if (JS_IsUndefined(attributes))\n        return FALSE;\n    str = JS_GetPropertyStr(ctx, attributes, \"type\");\n    if (!JS_IsString(str))\n        return FALSE;\n    cstr = JS_ToCStringLen(ctx, &len, str);\n    JS_FreeValue(ctx, str);\n    if (!cstr)\n        return FALSE;\n    /* XXX: raise an error if unknown type ? */\n    if (len == 4 && !memcmp(cstr, \"json\", len)) {\n        res = 1;\n    } else if (len == 5 && !memcmp(cstr, \"json5\", len)) {\n        res = 2;\n    } else {\n        res = 0;\n    }\n    JS_FreeCString(ctx, cstr);\n    return res;\n}\n\nJSModuleDef *js_module_loader(JSContext *ctx,\n                              const char *module_name, void *opaque,\n                              JSValueConst attributes)\n{\n    JSModuleDef *m;\n    int res;\n    \n    if (has_suffix(module_name, \".so\")) {\n        m = js_module_loader_so(ctx, module_name);\n    } else {\n        size_t buf_len;\n        uint8_t *buf;\n\n        buf = js_load_file(ctx, &buf_len, module_name);\n        if (!buf) {\n            JS_ThrowReferenceError(ctx, \"could not load module filename '%s'\",\n                                   module_name);\n            return NULL;\n        }\n        res = js_module_test_json(ctx, attributes);\n        if (has_suffix(module_name, \".json\") || res > 0) {\n            /* compile as JSON or JSON5 depending on \"type\" */\n            JSValue val;\n            int flags;\n            if (res == 2)\n                flags = JS_PARSE_JSON_EXT;\n            else\n                flags = 0;\n            val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);\n            js_free(ctx, buf);\n            if (JS_IsException(val))\n                return NULL;\n            m = create_json_module(ctx, module_name, val);\n            if (!m)\n                return NULL;\n        } else {\n            JSValue func_val;\n            /* compile the module */\n            func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,\n                               JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);\n            js_free(ctx, buf);\n            if (JS_IsException(func_val))\n                return NULL;\n            /* XXX: could propagate the exception */\n            js_module_set_import_meta(ctx, func_val, TRUE, FALSE);\n            /* the module is already referenced, so we must free it */\n            m = JS_VALUE_GET_PTR(func_val);\n            JS_FreeValue(ctx, func_val);\n        }\n    }\n    return m;\n}\n\nstatic JSValue js_std_exit(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    int status;\n    if (JS_ToInt32(ctx, &status, argv[0]))\n        status = -1;\n    exit(status);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_std_getenv(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    const char *name, *str;\n    name = JS_ToCString(ctx, argv[0]);\n    if (!name)\n        return JS_EXCEPTION;\n    str = getenv(name);\n    JS_FreeCString(ctx, name);\n    if (!str)\n        return JS_UNDEFINED;\n    else\n        return JS_NewString(ctx, str);\n}\n\n#if defined(_WIN32)\nstatic void setenv(const char *name, const char *value, int overwrite)\n{\n    char *str;\n    size_t name_len, value_len;\n    name_len = strlen(name);\n    value_len = strlen(value);\n    str = malloc(name_len + 1 + value_len + 1);\n    memcpy(str, name, name_len);\n    str[name_len] = '=';\n    memcpy(str + name_len + 1, value, value_len);\n    str[name_len + 1 + value_len] = '\\0';\n    _putenv(str);\n    free(str);\n}\n\nstatic void unsetenv(const char *name)\n{\n    setenv(name, \"\", TRUE);\n}\n#endif /* _WIN32 */\n\nstatic JSValue js_std_setenv(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    const char *name, *value;\n    name = JS_ToCString(ctx, argv[0]);\n    if (!name)\n        return JS_EXCEPTION;\n    value = JS_ToCString(ctx, argv[1]);\n    if (!value) {\n        JS_FreeCString(ctx, name);\n        return JS_EXCEPTION;\n    }\n    setenv(name, value, TRUE);\n    JS_FreeCString(ctx, name);\n    JS_FreeCString(ctx, value);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    const char *name;\n    name = JS_ToCString(ctx, argv[0]);\n    if (!name)\n        return JS_EXCEPTION;\n    unsetenv(name);\n    JS_FreeCString(ctx, name);\n    return JS_UNDEFINED;\n}\n\n/* return an object containing the list of the available environment\n   variables. */\nstatic JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    char **envp;\n    const char *name, *p, *value;\n    JSValue obj;\n    uint32_t idx;\n    size_t name_len;\n    JSAtom atom;\n    int ret;\n\n    obj = JS_NewObject(ctx);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    envp = environ;\n    for(idx = 0; envp[idx] != NULL; idx++) {\n        name = envp[idx];\n        p = strchr(name, '=');\n        name_len = p - name;\n        if (!p)\n            continue;\n        value = p + 1;\n        atom = JS_NewAtomLen(ctx, name, name_len);\n        if (atom == JS_ATOM_NULL)\n            goto fail;\n        ret = JS_DefinePropertyValue(ctx, obj, atom, JS_NewString(ctx, value),\n                                     JS_PROP_C_W_E);\n        JS_FreeAtom(ctx, atom);\n        if (ret < 0)\n            goto fail;\n    }\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,\n                         int argc, JSValueConst *argv)\n{\n    JS_RunGC(JS_GetRuntime(ctx));\n    return JS_UNDEFINED;\n}\n\nstatic int interrupt_handler(JSRuntime *rt, void *opaque)\n{\n    return (os_pending_signals >> SIGINT) & 1;\n}\n\nstatic int get_bool_option(JSContext *ctx, BOOL *pbool,\n                           JSValueConst obj,\n                           const char *option)\n{\n    JSValue val;\n    val = JS_GetPropertyStr(ctx, obj, option);\n    if (JS_IsException(val))\n        return -1;\n    if (!JS_IsUndefined(val)) {\n        *pbool = JS_ToBool(ctx, val);\n    }\n    JS_FreeValue(ctx, val);\n    return 0;\n}\n\nstatic JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    const char *str;\n    size_t len;\n    JSValue ret;\n    JSValueConst options_obj;\n    BOOL backtrace_barrier = FALSE;\n    BOOL is_async = FALSE;\n    int flags;\n\n    if (argc >= 2) {\n        options_obj = argv[1];\n        if (get_bool_option(ctx, &backtrace_barrier, options_obj,\n                            \"backtrace_barrier\"))\n            return JS_EXCEPTION;\n        if (get_bool_option(ctx, &is_async, options_obj,\n                            \"async\"))\n            return JS_EXCEPTION;\n    }\n\n    str = JS_ToCStringLen(ctx, &len, argv[0]);\n    if (!str)\n        return JS_EXCEPTION;\n    if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) {\n        /* install the interrupt handler */\n        JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);\n    }\n    flags = JS_EVAL_TYPE_GLOBAL;\n    if (backtrace_barrier)\n        flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;\n    if (is_async)\n        flags |= JS_EVAL_FLAG_ASYNC;\n    ret = JS_Eval(ctx, str, len, \"<evalScript>\", flags);\n    JS_FreeCString(ctx, str);\n    if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {\n        /* remove the interrupt handler */\n        JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL);\n        os_pending_signals &= ~((uint64_t)1 << SIGINT);\n        /* convert the uncatchable \"interrupted\" error into a normal error\n           so that it can be caught by the REPL */\n        if (JS_IsException(ret))\n            JS_SetUncatchableException(ctx, FALSE);\n    }\n    return ret;\n}\n\nstatic JSClassID js_std_file_class_id;\n\ntypedef struct {\n    FILE *f;\n    BOOL close_in_finalizer;\n    BOOL is_popen;\n} JSSTDFile;\n\nstatic void js_std_file_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id);\n    if (s) {\n        if (s->f && s->close_in_finalizer) {\n            if (s->is_popen)\n                pclose(s->f);\n            else\n                fclose(s->f);\n        }\n        js_free_rt(rt, s);\n    }\n}\n\nstatic ssize_t js_get_errno(ssize_t ret)\n{\n    if (ret == -1)\n        ret = -errno;\n    return ret;\n}\n\nstatic JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    int err;\n    if (JS_ToInt32(ctx, &err, argv[0]))\n        return JS_EXCEPTION;\n    return JS_NewString(ctx, strerror(err));\n}\n\nstatic JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue obj;\n    const char *str;\n    size_t len;\n\n    str = JS_ToCStringLen(ctx, &len, argv[0]);\n    if (!str)\n        return JS_EXCEPTION;\n    obj = JS_ParseJSON2(ctx, str, len, \"<input>\", JS_PARSE_JSON_EXT);\n    JS_FreeCString(ctx, str);\n    return obj;\n}\n\nstatic JSValue js_new_std_file(JSContext *ctx, FILE *f,\n                               BOOL close_in_finalizer,\n                               BOOL is_popen)\n{\n    JSSTDFile *s;\n    JSValue obj;\n    obj = JS_NewObjectClass(ctx, js_std_file_class_id);\n    if (JS_IsException(obj))\n        return obj;\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    s->close_in_finalizer = close_in_finalizer;\n    s->is_popen = is_popen;\n    s->f = f;\n    JS_SetOpaque(obj, s);\n    return obj;\n}\n\nstatic void js_set_error_object(JSContext *ctx, JSValue obj, int err)\n{\n    if (!JS_IsUndefined(obj)) {\n        JS_SetPropertyStr(ctx, obj, \"errno\", JS_NewInt32(ctx, err));\n    }\n}\n\nstatic JSValue js_std_open(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    const char *filename, *mode = NULL;\n    FILE *f;\n    int err;\n\n    filename = JS_ToCString(ctx, argv[0]);\n    if (!filename)\n        goto fail;\n    mode = JS_ToCString(ctx, argv[1]);\n    if (!mode)\n        goto fail;\n    if (mode[strspn(mode, \"rwa+b\")] != '\\0') {\n        JS_ThrowTypeError(ctx, \"invalid file mode\");\n        goto fail;\n    }\n\n    f = fopen(filename, mode);\n    if (!f)\n        err = errno;\n    else\n        err = 0;\n    if (argc >= 3)\n        js_set_error_object(ctx, argv[2], err);\n    JS_FreeCString(ctx, filename);\n    JS_FreeCString(ctx, mode);\n    if (!f)\n        return JS_NULL;\n    return js_new_std_file(ctx, f, TRUE, FALSE);\n fail:\n    JS_FreeCString(ctx, filename);\n    JS_FreeCString(ctx, mode);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    const char *filename, *mode = NULL;\n    FILE *f;\n    int err;\n\n    filename = JS_ToCString(ctx, argv[0]);\n    if (!filename)\n        goto fail;\n    mode = JS_ToCString(ctx, argv[1]);\n    if (!mode)\n        goto fail;\n    if (mode[strspn(mode, \"rw\")] != '\\0') {\n        JS_ThrowTypeError(ctx, \"invalid file mode\");\n        goto fail;\n    }\n\n    f = popen(filename, mode);\n    if (!f)\n        err = errno;\n    else\n        err = 0;\n    if (argc >= 3)\n        js_set_error_object(ctx, argv[2], err);\n    JS_FreeCString(ctx, filename);\n    JS_FreeCString(ctx, mode);\n    if (!f)\n        return JS_NULL;\n    return js_new_std_file(ctx, f, TRUE, TRUE);\n fail:\n    JS_FreeCString(ctx, filename);\n    JS_FreeCString(ctx, mode);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    const char *mode;\n    FILE *f;\n    int fd, err;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    mode = JS_ToCString(ctx, argv[1]);\n    if (!mode)\n        goto fail;\n    if (mode[strspn(mode, \"rwa+\")] != '\\0') {\n        JS_ThrowTypeError(ctx, \"invalid file mode\");\n        goto fail;\n    }\n\n    f = fdopen(fd, mode);\n    if (!f)\n        err = errno;\n    else\n        err = 0;\n    if (argc >= 3)\n        js_set_error_object(ctx, argv[2], err);\n    JS_FreeCString(ctx, mode);\n    if (!f)\n        return JS_NULL;\n    return js_new_std_file(ctx, f, TRUE, FALSE);\n fail:\n    JS_FreeCString(ctx, mode);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    FILE *f;\n    f = tmpfile();\n    if (argc >= 1)\n        js_set_error_object(ctx, argv[0], f ? 0 : errno);\n    if (!f)\n        return JS_NULL;\n    return js_new_std_file(ctx, f, TRUE, FALSE);\n}\n\nstatic JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv)\n{\n    return js_printf_internal(ctx, argc, argv, NULL);\n}\n\nstatic JSValue js_std_printf(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    return js_printf_internal(ctx, argc, argv, stdout);\n}\n\nstatic FILE *js_std_file_get(JSContext *ctx, JSValueConst obj)\n{\n    JSSTDFile *s = JS_GetOpaque2(ctx, obj, js_std_file_class_id);\n    if (!s)\n        return NULL;\n    if (!s->f) {\n        JS_ThrowTypeError(ctx, \"invalid file handle\");\n        return NULL;\n    }\n    return s->f;\n}\n\nstatic JSValue js_std_file_puts(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv, int magic)\n{\n    FILE *f;\n    int i;\n    const char *str;\n    size_t len;\n\n    if (magic == 0) {\n        f = stdout;\n    } else {\n        f = js_std_file_get(ctx, this_val);\n        if (!f)\n            return JS_EXCEPTION;\n    }\n\n    for(i = 0; i < argc; i++) {\n        str = JS_ToCStringLen(ctx, &len, argv[i]);\n        if (!str)\n            return JS_EXCEPTION;\n        fwrite(str, 1, len, f);\n        JS_FreeCString(ctx, str);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSSTDFile *s = JS_GetOpaque2(ctx, this_val, js_std_file_class_id);\n    int err;\n    if (!s)\n        return JS_EXCEPTION;\n    if (!s->f)\n        return JS_ThrowTypeError(ctx, \"invalid file handle\");\n    if (s->is_popen)\n        err = js_get_errno(pclose(s->f));\n    else\n        err = js_get_errno(fclose(s->f));\n    s->f = NULL;\n    return JS_NewInt32(ctx, err);\n}\n\nstatic JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    if (!f)\n        return JS_EXCEPTION;\n    return js_printf_internal(ctx, argc, argv, f);\n}\n\nstatic void js_print_value_write(void *opaque, const char *buf, size_t len)\n{\n    FILE *fo = opaque;\n    fwrite(buf, 1, len, fo);\n}\n\nstatic JSValue js_std_file_printObject(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JS_PrintValue(ctx, js_print_value_write, stdout, argv[0], NULL);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    if (!f)\n        return JS_EXCEPTION;\n    fflush(f);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_std_file_tell(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv, int is_bigint)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    int64_t pos;\n    if (!f)\n        return JS_EXCEPTION;\n#if defined(__linux__) || defined(__GLIBC__)\n    pos = ftello(f);\n#else\n    pos = ftell(f);\n#endif\n    if (is_bigint)\n        return JS_NewBigInt64(ctx, pos);\n    else\n        return JS_NewInt64(ctx, pos);\n}\n\nstatic JSValue js_std_file_seek(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    int64_t pos;\n    int whence, ret;\n    if (!f)\n        return JS_EXCEPTION;\n    if (JS_ToInt64Ext(ctx, &pos, argv[0]))\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &whence, argv[1]))\n        return JS_EXCEPTION;\n#if defined(__linux__) || defined(__GLIBC__)\n    ret = fseeko(f, pos, whence);\n#else\n    ret = fseek(f, pos, whence);\n#endif\n    if (ret < 0)\n        ret = -errno;\n    return JS_NewInt32(ctx, ret);\n}\n\nstatic JSValue js_std_file_eof(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    if (!f)\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, feof(f));\n}\n\nstatic JSValue js_std_file_error(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    if (!f)\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, ferror(f));\n}\n\nstatic JSValue js_std_file_clearerr(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    if (!f)\n        return JS_EXCEPTION;\n    clearerr(f);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_std_file_fileno(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    if (!f)\n        return JS_EXCEPTION;\n    return JS_NewInt32(ctx, fileno(f));\n}\n\nstatic JSValue js_std_file_read_write(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv, int magic)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    uint64_t pos, len;\n    size_t size, ret;\n    uint8_t *buf;\n\n    if (!f)\n        return JS_EXCEPTION;\n    if (JS_ToIndex(ctx, &pos, argv[1]))\n        return JS_EXCEPTION;\n    if (JS_ToIndex(ctx, &len, argv[2]))\n        return JS_EXCEPTION;\n    buf = JS_GetArrayBuffer(ctx, &size, argv[0]);\n    if (!buf)\n        return JS_EXCEPTION;\n    if (pos + len > size)\n        return JS_ThrowRangeError(ctx, \"read/write array buffer overflow\");\n    if (magic)\n        ret = fwrite(buf + pos, 1, len, f);\n    else\n        ret = fread(buf + pos, 1, len, f);\n    return JS_NewInt64(ctx, ret);\n}\n\n/* XXX: could use less memory and go faster */\nstatic JSValue js_std_file_getline(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    int c;\n    DynBuf dbuf;\n    JSValue obj;\n\n    if (!f)\n        return JS_EXCEPTION;\n\n    js_std_dbuf_init(ctx, &dbuf);\n    for(;;) {\n        c = fgetc(f);\n        if (c == EOF) {\n            if (dbuf.size == 0) {\n                /* EOF */\n                dbuf_free(&dbuf);\n                return JS_NULL;\n            } else {\n                break;\n            }\n        }\n        if (c == '\\n')\n            break;\n        if (dbuf_putc(&dbuf, c)) {\n            dbuf_free(&dbuf);\n            return JS_ThrowOutOfMemory(ctx);\n        }\n    }\n    obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);\n    dbuf_free(&dbuf);\n    return obj;\n}\n\n/* XXX: could use less memory and go faster */\nstatic JSValue js_std_file_readAsString(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    int c;\n    DynBuf dbuf;\n    JSValue obj;\n    uint64_t max_size64;\n    size_t max_size;\n    JSValueConst max_size_val;\n\n    if (!f)\n        return JS_EXCEPTION;\n\n    if (argc >= 1)\n        max_size_val = argv[0];\n    else\n        max_size_val = JS_UNDEFINED;\n    max_size = (size_t)-1;\n    if (!JS_IsUndefined(max_size_val)) {\n        if (JS_ToIndex(ctx, &max_size64, max_size_val))\n            return JS_EXCEPTION;\n        if (max_size64 < max_size)\n            max_size = max_size64;\n    }\n\n    js_std_dbuf_init(ctx, &dbuf);\n    while (max_size != 0) {\n        c = fgetc(f);\n        if (c == EOF)\n            break;\n        if (dbuf_putc(&dbuf, c)) {\n            dbuf_free(&dbuf);\n            return JS_EXCEPTION;\n        }\n        max_size--;\n    }\n    obj = JS_NewStringLen(ctx, (const char *)dbuf.buf, dbuf.size);\n    dbuf_free(&dbuf);\n    return obj;\n}\n\nstatic JSValue js_std_file_getByte(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    if (!f)\n        return JS_EXCEPTION;\n    return JS_NewInt32(ctx, fgetc(f));\n}\n\nstatic JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    FILE *f = js_std_file_get(ctx, this_val);\n    int c;\n    if (!f)\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &c, argv[0]))\n        return JS_EXCEPTION;\n    c = fputc(c, f);\n    return JS_NewInt32(ctx, c);\n}\n\n/* urlGet */\n\n#define URL_GET_PROGRAM \"curl -s -i --\"\n#define URL_GET_BUF_SIZE 4096\n\nstatic int http_get_header_line(FILE *f, char *buf, size_t buf_size,\n                                DynBuf *dbuf)\n{\n    int c;\n    char *p;\n\n    p = buf;\n    for(;;) {\n        c = fgetc(f);\n        if (c < 0)\n            return -1;\n        if ((p - buf) < buf_size - 1)\n            *p++ = c;\n        if (dbuf)\n            dbuf_putc(dbuf, c);\n        if (c == '\\n')\n            break;\n    }\n    *p = '\\0';\n    return 0;\n}\n\nstatic int http_get_status(const char *buf)\n{\n    const char *p = buf;\n    while (*p != ' ' && *p != '\\0')\n        p++;\n    if (*p != ' ')\n        return 0;\n    while (*p == ' ')\n        p++;\n    return atoi(p);\n}\n\nstatic JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    const char *url;\n    DynBuf cmd_buf;\n    DynBuf data_buf_s, *data_buf = &data_buf_s;\n    DynBuf header_buf_s, *header_buf = &header_buf_s;\n    char *buf;\n    size_t i, len;\n    int status;\n    JSValue response = JS_UNDEFINED, ret_obj;\n    JSValueConst options_obj;\n    FILE *f;\n    BOOL binary_flag, full_flag;\n\n    url = JS_ToCString(ctx, argv[0]);\n    if (!url)\n        return JS_EXCEPTION;\n\n    binary_flag = FALSE;\n    full_flag = FALSE;\n\n    if (argc >= 2) {\n        options_obj = argv[1];\n\n        if (get_bool_option(ctx, &binary_flag, options_obj, \"binary\"))\n            goto fail_obj;\n\n        if (get_bool_option(ctx, &full_flag, options_obj, \"full\")) {\n        fail_obj:\n            JS_FreeCString(ctx, url);\n            return JS_EXCEPTION;\n        }\n    }\n\n    js_std_dbuf_init(ctx, &cmd_buf);\n    dbuf_printf(&cmd_buf, \"%s '\", URL_GET_PROGRAM);\n    for(i = 0; url[i] != '\\0'; i++) {\n        unsigned char c = url[i];\n        switch (c) {\n        case '\\'':\n            /* shell single quoted string does not support \\' */\n            dbuf_putstr(&cmd_buf, \"'\\\\''\");\n            break;\n        case '[': case ']': case '{': case '}': case '\\\\':\n            /* prevent interpretation by curl as range or set specification */\n            dbuf_putc(&cmd_buf, '\\\\');\n            /* FALLTHROUGH */\n        default:\n            dbuf_putc(&cmd_buf, c);\n            break;\n        }\n    }\n    JS_FreeCString(ctx, url);\n    dbuf_putstr(&cmd_buf, \"'\");\n    dbuf_putc(&cmd_buf, '\\0');\n    if (dbuf_error(&cmd_buf)) {\n        dbuf_free(&cmd_buf);\n        return JS_EXCEPTION;\n    }\n    //    printf(\"%s\\n\", (char *)cmd_buf.buf);\n    f = popen((char *)cmd_buf.buf, \"r\");\n    dbuf_free(&cmd_buf);\n    if (!f) {\n        return JS_ThrowTypeError(ctx, \"could not start curl\");\n    }\n\n    js_std_dbuf_init(ctx, data_buf);\n    js_std_dbuf_init(ctx, header_buf);\n\n    buf = js_malloc(ctx, URL_GET_BUF_SIZE);\n    if (!buf)\n        goto fail;\n\n    /* get the HTTP status */\n    if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, NULL) < 0) {\n        status = 0;\n        goto bad_header;\n    }\n    status = http_get_status(buf);\n    if (!full_flag && !(status >= 200 && status <= 299)) {\n        goto bad_header;\n    }\n\n    /* wait until there is an empty line */\n    for(;;) {\n        if (http_get_header_line(f, buf, URL_GET_BUF_SIZE, header_buf) < 0) {\n        bad_header:\n            response = JS_NULL;\n            goto done;\n        }\n        if (!strcmp(buf, \"\\r\\n\"))\n            break;\n    }\n    if (dbuf_error(header_buf))\n        goto fail;\n    header_buf->size -= 2; /* remove the trailing CRLF */\n\n    /* download the data */\n    for(;;) {\n        len = fread(buf, 1, URL_GET_BUF_SIZE, f);\n        if (len == 0)\n            break;\n        dbuf_put(data_buf, (uint8_t *)buf, len);\n    }\n    if (dbuf_error(data_buf))\n        goto fail;\n    if (binary_flag) {\n        response = JS_NewArrayBufferCopy(ctx,\n                                         data_buf->buf, data_buf->size);\n    } else {\n        response = JS_NewStringLen(ctx, (char *)data_buf->buf, data_buf->size);\n    }\n    if (JS_IsException(response))\n        goto fail;\n done:\n    js_free(ctx, buf);\n    buf = NULL;\n    pclose(f);\n    f = NULL;\n    dbuf_free(data_buf);\n    data_buf = NULL;\n\n    if (full_flag) {\n        ret_obj = JS_NewObject(ctx);\n        if (JS_IsException(ret_obj))\n            goto fail;\n        JS_DefinePropertyValueStr(ctx, ret_obj, \"response\",\n                                  response,\n                                  JS_PROP_C_W_E);\n        if (!JS_IsNull(response)) {\n            JS_DefinePropertyValueStr(ctx, ret_obj, \"responseHeaders\",\n                                      JS_NewStringLen(ctx, (char *)header_buf->buf,\n                                                      header_buf->size),\n                                      JS_PROP_C_W_E);\n            JS_DefinePropertyValueStr(ctx, ret_obj, \"status\",\n                                      JS_NewInt32(ctx, status),\n                                      JS_PROP_C_W_E);\n        }\n    } else {\n        ret_obj = response;\n    }\n    dbuf_free(header_buf);\n    return ret_obj;\n fail:\n    if (f)\n        pclose(f);\n    js_free(ctx, buf);\n    if (data_buf)\n        dbuf_free(data_buf);\n    if (header_buf)\n        dbuf_free(header_buf);\n    JS_FreeValue(ctx, response);\n    return JS_EXCEPTION;\n}\n\nstatic JSClassDef js_std_file_class = {\n    \"FILE\",\n    .finalizer = js_std_file_finalizer,\n};\n\nstatic const JSCFunctionListEntry js_std_error_props[] = {\n    /* various errno values */\n#define DEF(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )\n    DEF(EINVAL),\n    DEF(EIO),\n    DEF(EACCES),\n    DEF(EEXIST),\n    DEF(ENOSPC),\n    DEF(ENOSYS),\n    DEF(EBUSY),\n    DEF(ENOENT),\n    DEF(EPERM),\n    DEF(EPIPE),\n    DEF(EBADF),\n#undef DEF\n};\n\nstatic const JSCFunctionListEntry js_std_funcs[] = {\n    JS_CFUNC_DEF(\"exit\", 1, js_std_exit ),\n    JS_CFUNC_DEF(\"gc\", 0, js_std_gc ),\n    JS_CFUNC_DEF(\"evalScript\", 1, js_evalScript ),\n    JS_CFUNC_DEF(\"loadScript\", 1, js_loadScript ),\n    JS_CFUNC_DEF(\"getenv\", 1, js_std_getenv ),\n    JS_CFUNC_DEF(\"setenv\", 1, js_std_setenv ),\n    JS_CFUNC_DEF(\"unsetenv\", 1, js_std_unsetenv ),\n    JS_CFUNC_DEF(\"getenviron\", 1, js_std_getenviron ),\n    JS_CFUNC_DEF(\"urlGet\", 1, js_std_urlGet ),\n    JS_CFUNC_DEF(\"loadFile\", 1, js_std_loadFile ),\n    JS_CFUNC_DEF(\"strerror\", 1, js_std_strerror ),\n    JS_CFUNC_DEF(\"parseExtJSON\", 1, js_std_parseExtJSON ),\n\n    /* FILE I/O */\n    JS_CFUNC_DEF(\"open\", 2, js_std_open ),\n    JS_CFUNC_DEF(\"popen\", 2, js_std_popen ),\n    JS_CFUNC_DEF(\"fdopen\", 2, js_std_fdopen ),\n    JS_CFUNC_DEF(\"tmpfile\", 0, js_std_tmpfile ),\n    JS_CFUNC_MAGIC_DEF(\"puts\", 1, js_std_file_puts, 0 ),\n    JS_CFUNC_DEF(\"printf\", 1, js_std_printf ),\n    JS_CFUNC_DEF(\"sprintf\", 1, js_std_sprintf ),\n    JS_PROP_INT32_DEF(\"SEEK_SET\", SEEK_SET, JS_PROP_CONFIGURABLE ),\n    JS_PROP_INT32_DEF(\"SEEK_CUR\", SEEK_CUR, JS_PROP_CONFIGURABLE ),\n    JS_PROP_INT32_DEF(\"SEEK_END\", SEEK_END, JS_PROP_CONFIGURABLE ),\n    JS_OBJECT_DEF(\"Error\", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),\n    JS_CFUNC_DEF(\"__printObject\", 1, js_std_file_printObject ),\n};\n\nstatic const JSCFunctionListEntry js_std_file_proto_funcs[] = {\n    JS_CFUNC_DEF(\"close\", 0, js_std_file_close ),\n    JS_CFUNC_MAGIC_DEF(\"puts\", 1, js_std_file_puts, 1 ),\n    JS_CFUNC_DEF(\"printf\", 1, js_std_file_printf ),\n    JS_CFUNC_DEF(\"flush\", 0, js_std_file_flush ),\n    JS_CFUNC_MAGIC_DEF(\"tell\", 0, js_std_file_tell, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"tello\", 0, js_std_file_tell, 1 ),\n    JS_CFUNC_DEF(\"seek\", 2, js_std_file_seek ),\n    JS_CFUNC_DEF(\"eof\", 0, js_std_file_eof ),\n    JS_CFUNC_DEF(\"fileno\", 0, js_std_file_fileno ),\n    JS_CFUNC_DEF(\"error\", 0, js_std_file_error ),\n    JS_CFUNC_DEF(\"clearerr\", 0, js_std_file_clearerr ),\n    JS_CFUNC_MAGIC_DEF(\"read\", 3, js_std_file_read_write, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"write\", 3, js_std_file_read_write, 1 ),\n    JS_CFUNC_DEF(\"getline\", 0, js_std_file_getline ),\n    JS_CFUNC_DEF(\"readAsString\", 0, js_std_file_readAsString ),\n    JS_CFUNC_DEF(\"getByte\", 0, js_std_file_getByte ),\n    JS_CFUNC_DEF(\"putByte\", 1, js_std_file_putByte ),\n    /* setvbuf, ...  */\n};\n\nstatic int js_std_init(JSContext *ctx, JSModuleDef *m)\n{\n    JSValue proto;\n\n    /* FILE class */\n    /* the class ID is created once */\n    JS_NewClassID(&js_std_file_class_id);\n    /* the class is created once per runtime */\n    JS_NewClass(JS_GetRuntime(ctx), js_std_file_class_id, &js_std_file_class);\n    proto = JS_NewObject(ctx);\n    JS_SetPropertyFunctionList(ctx, proto, js_std_file_proto_funcs,\n                               countof(js_std_file_proto_funcs));\n    JS_SetClassProto(ctx, js_std_file_class_id, proto);\n\n    JS_SetModuleExportList(ctx, m, js_std_funcs,\n                           countof(js_std_funcs));\n    JS_SetModuleExport(ctx, m, \"in\", js_new_std_file(ctx, stdin, FALSE, FALSE));\n    JS_SetModuleExport(ctx, m, \"out\", js_new_std_file(ctx, stdout, FALSE, FALSE));\n    JS_SetModuleExport(ctx, m, \"err\", js_new_std_file(ctx, stderr, FALSE, FALSE));\n    return 0;\n}\n\nJSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name)\n{\n    JSModuleDef *m;\n    m = JS_NewCModule(ctx, module_name, js_std_init);\n    if (!m)\n        return NULL;\n    JS_AddModuleExportList(ctx, m, js_std_funcs, countof(js_std_funcs));\n    JS_AddModuleExport(ctx, m, \"in\");\n    JS_AddModuleExport(ctx, m, \"out\");\n    JS_AddModuleExport(ctx, m, \"err\");\n    return m;\n}\n\n/**********************************************************/\n/* 'os' object */\n\nstatic JSValue js_os_open(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv)\n{\n    const char *filename;\n    int flags, mode, ret;\n\n    filename = JS_ToCString(ctx, argv[0]);\n    if (!filename)\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &flags, argv[1]))\n        goto fail;\n    if (argc >= 3 && !JS_IsUndefined(argv[2])) {\n        if (JS_ToInt32(ctx, &mode, argv[2])) {\n        fail:\n            JS_FreeCString(ctx, filename);\n            return JS_EXCEPTION;\n        }\n    } else {\n        mode = 0666;\n    }\n#if defined(_WIN32)\n    /* force binary mode by default */\n    if (!(flags & O_TEXT))\n        flags |= O_BINARY;\n#endif\n    ret = js_get_errno(open(filename, flags, mode));\n    JS_FreeCString(ctx, filename);\n    return JS_NewInt32(ctx, ret);\n}\n\nstatic JSValue js_os_close(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    int fd, ret;\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    ret = js_get_errno(close(fd));\n    return JS_NewInt32(ctx, ret);\n}\n\nstatic JSValue js_os_seek(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv)\n{\n    int fd, whence;\n    int64_t pos, ret;\n    BOOL is_bigint;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    is_bigint = JS_IsBigInt(ctx, argv[1]);\n    if (JS_ToInt64Ext(ctx, &pos, argv[1]))\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &whence, argv[2]))\n        return JS_EXCEPTION;\n    ret = lseek(fd, pos, whence);\n    if (ret == -1)\n        ret = -errno;\n    if (is_bigint)\n        return JS_NewBigInt64(ctx, ret);\n    else\n        return JS_NewInt64(ctx, ret);\n}\n\nstatic JSValue js_os_read_write(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv, int magic)\n{\n    int fd;\n    uint64_t pos, len;\n    size_t size;\n    ssize_t ret;\n    uint8_t *buf;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    if (JS_ToIndex(ctx, &pos, argv[2]))\n        return JS_EXCEPTION;\n    if (JS_ToIndex(ctx, &len, argv[3]))\n        return JS_EXCEPTION;\n    buf = JS_GetArrayBuffer(ctx, &size, argv[1]);\n    if (!buf)\n        return JS_EXCEPTION;\n    if (pos + len > size)\n        return JS_ThrowRangeError(ctx, \"read/write array buffer overflow\");\n    if (magic)\n        ret = js_get_errno(write(fd, buf + pos, len));\n    else\n        ret = js_get_errno(read(fd, buf + pos, len));\n    return JS_NewInt64(ctx, ret);\n}\n\nstatic JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    int fd;\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, isatty(fd));\n}\n\n#if defined(_WIN32)\nstatic JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    int fd;\n    HANDLE handle;\n    CONSOLE_SCREEN_BUFFER_INFO info;\n    JSValue obj;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    handle = (HANDLE)_get_osfhandle(fd);\n\n    if (!GetConsoleScreenBufferInfo(handle, &info))\n        return JS_NULL;\n    obj = JS_NewArray(ctx);\n    if (JS_IsException(obj))\n        return obj;\n    JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, info.dwSize.X), JS_PROP_C_W_E);\n    JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, info.dwSize.Y), JS_PROP_C_W_E);\n    return obj;\n}\n\n/* Windows 10 built-in VT100 emulation */\n#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004\n#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200\n\nstatic JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    int fd;\n    HANDLE handle;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    handle = (HANDLE)_get_osfhandle(fd);\n    SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT);\n    _setmode(fd, _O_BINARY);\n    if (fd == 0) {\n        handle = (HANDLE)_get_osfhandle(1); /* corresponding output */\n        SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING);\n    }\n    return JS_UNDEFINED;\n}\n#else\nstatic JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    int fd;\n    struct winsize ws;\n    JSValue obj;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    if (ioctl(fd, TIOCGWINSZ, &ws) == 0 &&\n        ws.ws_col >= 4 && ws.ws_row >= 4) {\n        obj = JS_NewArray(ctx);\n        if (JS_IsException(obj))\n            return obj;\n        JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ws.ws_col), JS_PROP_C_W_E);\n        JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, ws.ws_row), JS_PROP_C_W_E);\n        return obj;\n    } else {\n        return JS_NULL;\n    }\n}\n\nstatic struct termios oldtty;\n\nstatic void term_exit(void)\n{\n    tcsetattr(0, TCSANOW, &oldtty);\n}\n\n/* XXX: should add a way to go back to normal mode */\nstatic JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    struct termios tty;\n    int fd;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n\n    memset(&tty, 0, sizeof(tty));\n    tcgetattr(fd, &tty);\n    oldtty = tty;\n\n    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP\n                          |INLCR|IGNCR|ICRNL|IXON);\n    tty.c_oflag |= OPOST;\n    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);\n    tty.c_cflag &= ~(CSIZE|PARENB);\n    tty.c_cflag |= CS8;\n    tty.c_cc[VMIN] = 1;\n    tty.c_cc[VTIME] = 0;\n\n    tcsetattr(fd, TCSANOW, &tty);\n\n    atexit(term_exit);\n    return JS_UNDEFINED;\n}\n\n#endif /* !_WIN32 */\n\nstatic JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    const char *filename;\n    int ret;\n\n    filename = JS_ToCString(ctx, argv[0]);\n    if (!filename)\n        return JS_EXCEPTION;\n#if defined(_WIN32)\n    {\n        struct stat st;\n        if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) {\n            ret = rmdir(filename);\n        } else {\n            ret = unlink(filename);\n        }\n    }\n#else\n    ret = remove(filename);\n#endif\n    ret = js_get_errno(ret);\n    JS_FreeCString(ctx, filename);\n    return JS_NewInt32(ctx, ret);\n}\n\nstatic JSValue js_os_rename(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    const char *oldpath, *newpath;\n    int ret;\n\n    oldpath = JS_ToCString(ctx, argv[0]);\n    if (!oldpath)\n        return JS_EXCEPTION;\n    newpath = JS_ToCString(ctx, argv[1]);\n    if (!newpath) {\n        JS_FreeCString(ctx, oldpath);\n        return JS_EXCEPTION;\n    }\n    ret = js_get_errno(rename(oldpath, newpath));\n    JS_FreeCString(ctx, oldpath);\n    JS_FreeCString(ctx, newpath);\n    return JS_NewInt32(ctx, ret);\n}\n\nstatic BOOL is_main_thread(JSRuntime *rt)\n{\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    return !ts->recv_pipe;\n}\n\nstatic JSOSRWHandler *find_rh(JSThreadState *ts, int fd)\n{\n    JSOSRWHandler *rh;\n    struct list_head *el;\n\n    list_for_each(el, &ts->os_rw_handlers) {\n        rh = list_entry(el, JSOSRWHandler, link);\n        if (rh->fd == fd)\n            return rh;\n    }\n    return NULL;\n}\n\nstatic void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh)\n{\n    int i;\n    list_del(&rh->link);\n    for(i = 0; i < 2; i++) {\n        JS_FreeValueRT(rt, rh->rw_func[i]);\n    }\n    js_free_rt(rt, rh);\n}\n\nstatic JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv, int magic)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    JSOSRWHandler *rh;\n    int fd;\n    JSValueConst func;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    func = argv[1];\n    if (JS_IsNull(func)) {\n        rh = find_rh(ts, fd);\n        if (rh) {\n            JS_FreeValue(ctx, rh->rw_func[magic]);\n            rh->rw_func[magic] = JS_NULL;\n            if (JS_IsNull(rh->rw_func[0]) &&\n                JS_IsNull(rh->rw_func[1])) {\n                /* remove the entry */\n                free_rw_handler(JS_GetRuntime(ctx), rh);\n            }\n        }\n    } else {\n        if (!JS_IsFunction(ctx, func))\n            return JS_ThrowTypeError(ctx, \"not a function\");\n        rh = find_rh(ts, fd);\n        if (!rh) {\n            rh = js_mallocz(ctx, sizeof(*rh));\n            if (!rh)\n                return JS_EXCEPTION;\n            rh->fd = fd;\n            rh->rw_func[0] = JS_NULL;\n            rh->rw_func[1] = JS_NULL;\n            list_add_tail(&rh->link, &ts->os_rw_handlers);\n        }\n        JS_FreeValue(ctx, rh->rw_func[magic]);\n        rh->rw_func[magic] = JS_DupValue(ctx, func);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num)\n{\n    JSOSSignalHandler *sh;\n    struct list_head *el;\n    list_for_each(el, &ts->os_signal_handlers) {\n        sh = list_entry(el, JSOSSignalHandler, link);\n        if (sh->sig_num == sig_num)\n            return sh;\n    }\n    return NULL;\n}\n\nstatic void free_sh(JSRuntime *rt, JSOSSignalHandler *sh)\n{\n    list_del(&sh->link);\n    JS_FreeValueRT(rt, sh->func);\n    js_free_rt(rt, sh);\n}\n\nstatic void os_signal_handler(int sig_num)\n{\n    os_pending_signals |= ((uint64_t)1 << sig_num);\n}\n\n#if defined(_WIN32)\ntypedef void (*sighandler_t)(int sig_num);\n#endif\n\nstatic JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    JSOSSignalHandler *sh;\n    uint32_t sig_num;\n    JSValueConst func;\n    sighandler_t handler;\n\n    if (!is_main_thread(rt))\n        return JS_ThrowTypeError(ctx, \"signal handler can only be set in the main thread\");\n\n    if (JS_ToUint32(ctx, &sig_num, argv[0]))\n        return JS_EXCEPTION;\n    if (sig_num >= 64)\n        return JS_ThrowRangeError(ctx, \"invalid signal number\");\n    func = argv[1];\n    /* func = null: SIG_DFL, func = undefined, SIG_IGN */\n    if (JS_IsNull(func) || JS_IsUndefined(func)) {\n        sh = find_sh(ts, sig_num);\n        if (sh) {\n            free_sh(JS_GetRuntime(ctx), sh);\n        }\n        if (JS_IsNull(func))\n            handler = SIG_DFL;\n        else\n            handler = SIG_IGN;\n        signal(sig_num, handler);\n    } else {\n        if (!JS_IsFunction(ctx, func))\n            return JS_ThrowTypeError(ctx, \"not a function\");\n        sh = find_sh(ts, sig_num);\n        if (!sh) {\n            sh = js_mallocz(ctx, sizeof(*sh));\n            if (!sh)\n                return JS_EXCEPTION;\n            sh->sig_num = sig_num;\n            list_add_tail(&sh->link, &ts->os_signal_handlers);\n        }\n        JS_FreeValue(ctx, sh->func);\n        sh->func = JS_DupValue(ctx, func);\n        signal(sig_num, os_signal_handler);\n    }\n    return JS_UNDEFINED;\n}\n\n#if defined(__linux__) || defined(__APPLE__)\nstatic int64_t get_time_ms(void)\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC, &ts);\n    return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);\n}\n\nstatic int64_t get_time_ns(void)\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC, &ts);\n    return (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;\n}\n#else\n/* more portable, but does not work if the date is updated */\nstatic int64_t get_time_ms(void)\n{\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);\n}\n\nstatic int64_t get_time_ns(void)\n{\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return (int64_t)tv.tv_sec * 1000000000 + (tv.tv_usec * 1000);\n}\n#endif\n\nstatic JSValue js_os_now(JSContext *ctx, JSValue this_val,\n                         int argc, JSValue *argv)\n{\n    return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6);\n}\n\nstatic void free_timer(JSRuntime *rt, JSOSTimer *th)\n{\n    list_del(&th->link);\n    JS_FreeValueRT(rt, th->func);\n    js_free_rt(rt, th);\n}\n\nstatic JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    int64_t delay;\n    JSValueConst func;\n    JSOSTimer *th;\n\n    func = argv[0];\n    if (!JS_IsFunction(ctx, func))\n        return JS_ThrowTypeError(ctx, \"not a function\");\n    if (JS_ToInt64(ctx, &delay, argv[1]))\n        return JS_EXCEPTION;\n    th = js_mallocz(ctx, sizeof(*th));\n    if (!th)\n        return JS_EXCEPTION;\n    th->timer_id = ts->next_timer_id;\n    if (ts->next_timer_id == INT32_MAX)\n        ts->next_timer_id = 1;\n    else\n        ts->next_timer_id++;\n    th->timeout = get_time_ms() + delay;\n    th->func = JS_DupValue(ctx, func);\n    list_add_tail(&th->link, &ts->os_timers);\n    return JS_NewInt32(ctx, th->timer_id);\n}\n\nstatic JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)\n{\n    struct list_head *el;\n    if (timer_id <= 0)\n        return NULL;\n    list_for_each(el, &ts->os_timers) {\n        JSOSTimer *th = list_entry(el, JSOSTimer, link);\n        if (th->timer_id == timer_id)\n            return th;\n    }\n    return NULL;\n}\n\nstatic JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    JSOSTimer *th;\n    int timer_id;\n\n    if (JS_ToInt32(ctx, &timer_id, argv[0]))\n        return JS_EXCEPTION;\n    th = find_timer_by_id(ts, timer_id);\n    if (!th)\n        return JS_UNDEFINED;\n    free_timer(rt, th);\n    return JS_UNDEFINED;\n}\n\n/* return a promise */\nstatic JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    int64_t delay;\n    JSOSTimer *th;\n    JSValue promise, resolving_funcs[2];\n\n    if (JS_ToInt64(ctx, &delay, argv[0]))\n        return JS_EXCEPTION;\n    promise = JS_NewPromiseCapability(ctx, resolving_funcs);\n    if (JS_IsException(promise))\n        return JS_EXCEPTION;\n\n    th = js_mallocz(ctx, sizeof(*th));\n    if (!th) {\n        JS_FreeValue(ctx, promise);\n        JS_FreeValue(ctx, resolving_funcs[0]);\n        JS_FreeValue(ctx, resolving_funcs[1]);\n        return JS_EXCEPTION;\n    }\n    th->timer_id = -1;\n    th->timeout = get_time_ms() + delay;\n    th->func = JS_DupValue(ctx, resolving_funcs[0]);\n    list_add_tail(&th->link, &ts->os_timers);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    return promise;\n}\n\nstatic void call_handler(JSContext *ctx, JSValueConst func)\n{\n    JSValue ret, func1;\n    /* 'func' might be destroyed when calling itself (if it frees the\n       handler), so must take extra care */\n    func1 = JS_DupValue(ctx, func);\n    ret = JS_Call(ctx, func1, JS_UNDEFINED, 0, NULL);\n    JS_FreeValue(ctx, func1);\n    if (JS_IsException(ret))\n        js_std_dump_error(ctx);\n    JS_FreeValue(ctx, ret);\n}\n\n#ifdef USE_WORKER\n\n#ifdef _WIN32\n\nstatic int js_waker_init(JSWaker *w)\n{\n    w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);\n    return w->handle ? 0 : -1;\n}\n\nstatic void js_waker_signal(JSWaker *w)\n{\n    SetEvent(w->handle);\n}\n\nstatic void js_waker_clear(JSWaker *w)\n{\n    ResetEvent(w->handle);\n}\n\nstatic void js_waker_close(JSWaker *w)\n{\n    CloseHandle(w->handle);\n    w->handle = INVALID_HANDLE_VALUE;\n}\n\n#else // !_WIN32\n\nstatic int js_waker_init(JSWaker *w)\n{\n    int fds[2];\n\n    if (pipe(fds) < 0)\n        return -1;\n    w->read_fd = fds[0];\n    w->write_fd = fds[1];\n    return 0;\n}\n\nstatic void js_waker_signal(JSWaker *w)\n{\n    int ret;\n\n    for(;;) {\n        ret = write(w->write_fd, \"\", 1);\n        if (ret == 1)\n            break;\n        if (ret < 0 && (errno != EAGAIN || errno != EINTR))\n            break;\n    }\n}\n\nstatic void js_waker_clear(JSWaker *w)\n{\n    uint8_t buf[16];\n    int ret;\n\n    for(;;) {\n        ret = read(w->read_fd, buf, sizeof(buf));\n        if (ret >= 0)\n            break;\n        if (errno != EAGAIN && errno != EINTR)\n            break;\n    }\n}\n\nstatic void js_waker_close(JSWaker *w)\n{\n    close(w->read_fd);\n    close(w->write_fd);\n    w->read_fd = -1;\n    w->write_fd = -1;\n}\n\n#endif // _WIN32\n\nstatic void js_free_message(JSWorkerMessage *msg);\n\n/* return 1 if a message was handled, 0 if no message */\nstatic int handle_posted_message(JSRuntime *rt, JSContext *ctx,\n                                 JSWorkerMessageHandler *port)\n{\n    JSWorkerMessagePipe *ps = port->recv_pipe;\n    int ret;\n    struct list_head *el;\n    JSWorkerMessage *msg;\n    JSValue obj, data_obj, func, retval;\n\n    pthread_mutex_lock(&ps->mutex);\n    if (!list_empty(&ps->msg_queue)) {\n        el = ps->msg_queue.next;\n        msg = list_entry(el, JSWorkerMessage, link);\n\n        /* remove the message from the queue */\n        list_del(&msg->link);\n\n        if (list_empty(&ps->msg_queue))\n            js_waker_clear(&ps->waker);\n\n        pthread_mutex_unlock(&ps->mutex);\n\n        data_obj = JS_ReadObject(ctx, msg->data, msg->data_len,\n                                 JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE);\n\n        js_free_message(msg);\n\n        if (JS_IsException(data_obj))\n            goto fail;\n        obj = JS_NewObject(ctx);\n        if (JS_IsException(obj)) {\n            JS_FreeValue(ctx, data_obj);\n            goto fail;\n        }\n        JS_DefinePropertyValueStr(ctx, obj, \"data\", data_obj, JS_PROP_C_W_E);\n\n        /* 'func' might be destroyed when calling itself (if it frees the\n           handler), so must take extra care */\n        func = JS_DupValue(ctx, port->on_message_func);\n        retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj);\n        JS_FreeValue(ctx, obj);\n        JS_FreeValue(ctx, func);\n        if (JS_IsException(retval)) {\n        fail:\n            js_std_dump_error(ctx);\n        } else {\n            JS_FreeValue(ctx, retval);\n        }\n        ret = 1;\n    } else {\n        pthread_mutex_unlock(&ps->mutex);\n        ret = 0;\n    }\n    return ret;\n}\n#else\nstatic int handle_posted_message(JSRuntime *rt, JSContext *ctx,\n                                 JSWorkerMessageHandler *port)\n{\n    return 0;\n}\n#endif /* !USE_WORKER */\n\n#if defined(_WIN32)\n\nstatic int js_os_poll(JSContext *ctx)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    int min_delay, count;\n    int64_t cur_time, delay;\n    JSOSRWHandler *rh;\n    struct list_head *el;\n    HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64\n\n    /* XXX: handle signals if useful */\n\n    if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&\n        list_empty(&ts->port_list)) {\n        return -1; /* no more events */\n    }\n    \n    if (!list_empty(&ts->os_timers)) {\n        cur_time = get_time_ms();\n        min_delay = 10000;\n        list_for_each(el, &ts->os_timers) {\n            JSOSTimer *th = list_entry(el, JSOSTimer, link);\n            delay = th->timeout - cur_time;\n            if (delay <= 0) {\n                JSValue func;\n                /* the timer expired */\n                func = th->func;\n                th->func = JS_UNDEFINED;\n                free_timer(rt, th);\n                call_handler(ctx, func);\n                JS_FreeValue(ctx, func);\n                return 0;\n            } else if (delay < min_delay) {\n                min_delay = delay;\n            }\n        }\n    } else {\n        min_delay = -1;\n    }\n\n    count = 0;\n    list_for_each(el, &ts->os_rw_handlers) {\n        rh = list_entry(el, JSOSRWHandler, link);\n        if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {\n            handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin\n            if (count == (int)countof(handles))\n                break;\n        }\n    }\n\n    list_for_each(el, &ts->port_list) {\n        JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);\n        if (JS_IsNull(port->on_message_func))\n            continue;\n        handles[count++] = port->recv_pipe->waker.handle;\n        if (count == (int)countof(handles))\n            break;\n    }\n\n    if (count > 0) {\n        DWORD ret, timeout = INFINITE;\n        if (min_delay != -1)\n            timeout = min_delay;\n        ret = WaitForMultipleObjects(count, handles, FALSE, timeout);\n\n        if (ret < count) {\n            list_for_each(el, &ts->os_rw_handlers) {\n                rh = list_entry(el, JSOSRWHandler, link);\n                if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {\n                    call_handler(ctx, rh->rw_func[0]);\n                    /* must stop because the list may have been modified */\n                    goto done;\n                }\n            }\n\n            list_for_each(el, &ts->port_list) {\n                JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);\n                if (!JS_IsNull(port->on_message_func)) {\n                    JSWorkerMessagePipe *ps = port->recv_pipe;\n                    if (ps->waker.handle == handles[ret]) {\n                        if (handle_posted_message(rt, ctx, port))\n                            goto done;\n                    }\n                }\n            }\n        }\n    } else {\n        Sleep(min_delay);\n    }\n done:\n    return 0;\n}\n\n#else\n\nstatic int js_os_poll(JSContext *ctx)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    int ret, fd_max, min_delay;\n    int64_t cur_time, delay;\n    fd_set rfds, wfds;\n    JSOSRWHandler *rh;\n    struct list_head *el;\n    struct timeval tv, *tvp;\n\n    /* only check signals in the main thread */\n    if (!ts->recv_pipe &&\n        unlikely(os_pending_signals != 0)) {\n        JSOSSignalHandler *sh;\n        uint64_t mask;\n\n        list_for_each(el, &ts->os_signal_handlers) {\n            sh = list_entry(el, JSOSSignalHandler, link);\n            mask = (uint64_t)1 << sh->sig_num;\n            if (os_pending_signals & mask) {\n                os_pending_signals &= ~mask;\n                call_handler(ctx, sh->func);\n                return 0;\n            }\n        }\n    }\n\n    if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&\n        list_empty(&ts->port_list))\n        return -1; /* no more events */\n\n    if (!list_empty(&ts->os_timers)) {\n        cur_time = get_time_ms();\n        min_delay = 10000;\n        list_for_each(el, &ts->os_timers) {\n            JSOSTimer *th = list_entry(el, JSOSTimer, link);\n            delay = th->timeout - cur_time;\n            if (delay <= 0) {\n                JSValue func;\n                /* the timer expired */\n                func = th->func;\n                th->func = JS_UNDEFINED;\n                free_timer(rt, th);\n                call_handler(ctx, func);\n                JS_FreeValue(ctx, func);\n                return 0;\n            } else if (delay < min_delay) {\n                min_delay = delay;\n            }\n        }\n        tv.tv_sec = min_delay / 1000;\n        tv.tv_usec = (min_delay % 1000) * 1000;\n        tvp = &tv;\n    } else {\n        tvp = NULL;\n    }\n\n    FD_ZERO(&rfds);\n    FD_ZERO(&wfds);\n    fd_max = -1;\n    list_for_each(el, &ts->os_rw_handlers) {\n        rh = list_entry(el, JSOSRWHandler, link);\n        fd_max = max_int(fd_max, rh->fd);\n        if (!JS_IsNull(rh->rw_func[0]))\n            FD_SET(rh->fd, &rfds);\n        if (!JS_IsNull(rh->rw_func[1]))\n            FD_SET(rh->fd, &wfds);\n    }\n\n    list_for_each(el, &ts->port_list) {\n        JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);\n        if (!JS_IsNull(port->on_message_func)) {\n            JSWorkerMessagePipe *ps = port->recv_pipe;\n            fd_max = max_int(fd_max, ps->waker.read_fd);\n            FD_SET(ps->waker.read_fd, &rfds);\n        }\n    }\n\n    ret = select(fd_max + 1, &rfds, &wfds, NULL, tvp);\n    if (ret > 0) {\n        list_for_each(el, &ts->os_rw_handlers) {\n            rh = list_entry(el, JSOSRWHandler, link);\n            if (!JS_IsNull(rh->rw_func[0]) &&\n                FD_ISSET(rh->fd, &rfds)) {\n                call_handler(ctx, rh->rw_func[0]);\n                /* must stop because the list may have been modified */\n                goto done;\n            }\n            if (!JS_IsNull(rh->rw_func[1]) &&\n                FD_ISSET(rh->fd, &wfds)) {\n                call_handler(ctx, rh->rw_func[1]);\n                /* must stop because the list may have been modified */\n                goto done;\n            }\n        }\n\n        list_for_each(el, &ts->port_list) {\n            JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);\n            if (!JS_IsNull(port->on_message_func)) {\n                JSWorkerMessagePipe *ps = port->recv_pipe;\n                if (FD_ISSET(ps->waker.read_fd, &rfds)) {\n                    if (handle_posted_message(rt, ctx, port))\n                        goto done;\n                }\n            }\n        }\n    }\n done:\n    return 0;\n}\n#endif /* !_WIN32 */\n\nstatic JSValue make_obj_error(JSContext *ctx,\n                              JSValue obj,\n                              int err)\n{\n    JSValue arr;\n    if (JS_IsException(obj))\n        return obj;\n    arr = JS_NewArray(ctx);\n    if (JS_IsException(arr))\n        return JS_EXCEPTION;\n    JS_DefinePropertyValueUint32(ctx, arr, 0, obj,\n                                 JS_PROP_C_W_E);\n    JS_DefinePropertyValueUint32(ctx, arr, 1, JS_NewInt32(ctx, err),\n                                 JS_PROP_C_W_E);\n    return arr;\n}\n\nstatic JSValue make_string_error(JSContext *ctx,\n                                 const char *buf,\n                                 int err)\n{\n    return make_obj_error(ctx, JS_NewString(ctx, buf), err);\n}\n\n/* return [cwd, errorcode] */\nstatic JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    char buf[PATH_MAX];\n    int err;\n\n    if (!getcwd(buf, sizeof(buf))) {\n        buf[0] = '\\0';\n        err = errno;\n    } else {\n        err = 0;\n    }\n    return make_string_error(ctx, buf, err);\n}\n\nstatic JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    const char *target;\n    int err;\n\n    target = JS_ToCString(ctx, argv[0]);\n    if (!target)\n        return JS_EXCEPTION;\n    err = js_get_errno(chdir(target));\n    JS_FreeCString(ctx, target);\n    return JS_NewInt32(ctx, err);\n}\n\nstatic JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    int mode, ret;\n    const char *path;\n\n    if (argc >= 2) {\n        if (JS_ToInt32(ctx, &mode, argv[1]))\n            return JS_EXCEPTION;\n    } else {\n        mode = 0777;\n    }\n    path = JS_ToCString(ctx, argv[0]);\n    if (!path)\n        return JS_EXCEPTION;\n#if defined(_WIN32)\n    (void)mode;\n    ret = js_get_errno(mkdir(path));\n#else\n    ret = js_get_errno(mkdir(path, mode));\n#endif\n    JS_FreeCString(ctx, path);\n    return JS_NewInt32(ctx, ret);\n}\n\n/* return [array, errorcode] */\nstatic JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    const char *path;\n    DIR *f;\n    struct dirent *d;\n    JSValue obj;\n    int err;\n    uint32_t len;\n\n    path = JS_ToCString(ctx, argv[0]);\n    if (!path)\n        return JS_EXCEPTION;\n    obj = JS_NewArray(ctx);\n    if (JS_IsException(obj)) {\n        JS_FreeCString(ctx, path);\n        return JS_EXCEPTION;\n    }\n    f = opendir(path);\n    if (!f)\n        err = errno;\n    else\n        err = 0;\n    JS_FreeCString(ctx, path);\n    if (!f)\n        goto done;\n    len = 0;\n    for(;;) {\n        errno = 0;\n        d = readdir(f);\n        if (!d) {\n            err = errno;\n            break;\n        }\n        JS_DefinePropertyValueUint32(ctx, obj, len++,\n                                     JS_NewString(ctx, d->d_name),\n                                     JS_PROP_C_W_E);\n    }\n    closedir(f);\n done:\n    return make_obj_error(ctx, obj, err);\n}\n\n#if !defined(_WIN32)\nstatic int64_t timespec_to_ms(const struct timespec *tv)\n{\n    return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000);\n}\n#endif\n\n/* return [obj, errcode] */\nstatic JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv, int is_lstat)\n{\n    const char *path;\n    int err, res;\n    struct stat st;\n    JSValue obj;\n\n    path = JS_ToCString(ctx, argv[0]);\n    if (!path)\n        return JS_EXCEPTION;\n#if defined(_WIN32)\n    res = stat(path, &st);\n#else\n    if (is_lstat)\n        res = lstat(path, &st);\n    else\n        res = stat(path, &st);\n#endif\n    if (res < 0)\n        err = errno;\n    else\n        err = 0;\n    JS_FreeCString(ctx, path);\n    if (res < 0) {\n        obj = JS_NULL;\n    } else {\n        obj = JS_NewObject(ctx);\n        if (JS_IsException(obj))\n            return JS_EXCEPTION;\n        JS_DefinePropertyValueStr(ctx, obj, \"dev\",\n                                  JS_NewInt64(ctx, st.st_dev),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"ino\",\n                                  JS_NewInt64(ctx, st.st_ino),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"mode\",\n                                  JS_NewInt32(ctx, st.st_mode),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"nlink\",\n                                  JS_NewInt64(ctx, st.st_nlink),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"uid\",\n                                  JS_NewInt64(ctx, st.st_uid),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"gid\",\n                                  JS_NewInt64(ctx, st.st_gid),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"rdev\",\n                                  JS_NewInt64(ctx, st.st_rdev),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"size\",\n                                  JS_NewInt64(ctx, st.st_size),\n                                  JS_PROP_C_W_E);\n#if !defined(_WIN32)\n        JS_DefinePropertyValueStr(ctx, obj, \"blocks\",\n                                  JS_NewInt64(ctx, st.st_blocks),\n                                  JS_PROP_C_W_E);\n#endif\n#if defined(_WIN32)\n        JS_DefinePropertyValueStr(ctx, obj, \"atime\",\n                                  JS_NewInt64(ctx, (int64_t)st.st_atime * 1000),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"mtime\",\n                                  JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"ctime\",\n                                  JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000),\n                                  JS_PROP_C_W_E);\n#elif defined(__APPLE__)\n        JS_DefinePropertyValueStr(ctx, obj, \"atime\",\n                                  JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"mtime\",\n                                  JS_NewInt64(ctx, timespec_to_ms(&st.st_mtimespec)),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"ctime\",\n                                  JS_NewInt64(ctx, timespec_to_ms(&st.st_ctimespec)),\n                                  JS_PROP_C_W_E);\n#else\n        JS_DefinePropertyValueStr(ctx, obj, \"atime\",\n                                  JS_NewInt64(ctx, timespec_to_ms(&st.st_atim)),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"mtime\",\n                                  JS_NewInt64(ctx, timespec_to_ms(&st.st_mtim)),\n                                  JS_PROP_C_W_E);\n        JS_DefinePropertyValueStr(ctx, obj, \"ctime\",\n                                  JS_NewInt64(ctx, timespec_to_ms(&st.st_ctim)),\n                                  JS_PROP_C_W_E);\n#endif\n    }\n    return make_obj_error(ctx, obj, err);\n}\n\n#if !defined(_WIN32)\nstatic void ms_to_timeval(struct timeval *tv, uint64_t v)\n{\n    tv->tv_sec = v / 1000;\n    tv->tv_usec = (v % 1000) * 1000;\n}\n#endif\n\nstatic JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    const char *path;\n    int64_t atime, mtime;\n    int ret;\n\n    if (JS_ToInt64(ctx, &atime, argv[1]))\n        return JS_EXCEPTION;\n    if (JS_ToInt64(ctx, &mtime, argv[2]))\n        return JS_EXCEPTION;\n    path = JS_ToCString(ctx, argv[0]);\n    if (!path)\n        return JS_EXCEPTION;\n#if defined(_WIN32)\n    {\n        struct _utimbuf times;\n        times.actime = atime / 1000;\n        times.modtime = mtime / 1000;\n        ret = js_get_errno(_utime(path, &times));\n    }\n#else\n    {\n        struct timeval times[2];\n        ms_to_timeval(&times[0], atime);\n        ms_to_timeval(&times[1], mtime);\n        ret = js_get_errno(utimes(path, times));\n    }\n#endif\n    JS_FreeCString(ctx, path);\n    return JS_NewInt32(ctx, ret);\n}\n\n/* sleep(delay_ms) */\nstatic JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    int64_t delay;\n    int ret;\n\n    if (JS_ToInt64(ctx, &delay, argv[0]))\n        return JS_EXCEPTION;\n    if (delay < 0)\n        delay = 0;\n#if defined(_WIN32)\n    {\n        if (delay > INT32_MAX)\n            delay = INT32_MAX;\n        Sleep(delay);\n        ret = 0;\n    }\n#else\n    {\n        struct timespec ts;\n\n        ts.tv_sec = delay / 1000;\n        ts.tv_nsec = (delay % 1000) * 1000000;\n        ret = js_get_errno(nanosleep(&ts, NULL));\n    }\n#endif\n    return JS_NewInt32(ctx, ret);\n}\n\n#if defined(_WIN32)\nstatic char *realpath(const char *path, char *buf)\n{\n    if (!_fullpath(buf, path, PATH_MAX)) {\n        errno = ENOENT;\n        return NULL;\n    } else {\n        return buf;\n    }\n}\n#endif\n\n/* return [path, errorcode] */\nstatic JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    const char *path;\n    char buf[PATH_MAX], *res;\n    int err;\n\n    path = JS_ToCString(ctx, argv[0]);\n    if (!path)\n        return JS_EXCEPTION;\n    res = realpath(path, buf);\n    JS_FreeCString(ctx, path);\n    if (!res) {\n        buf[0] = '\\0';\n        err = errno;\n    } else {\n        err = 0;\n    }\n    return make_string_error(ctx, buf, err);\n}\n\n#if !defined(_WIN32)\nstatic JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    const char *target, *linkpath;\n    int err;\n\n    target = JS_ToCString(ctx, argv[0]);\n    if (!target)\n        return JS_EXCEPTION;\n    linkpath = JS_ToCString(ctx, argv[1]);\n    if (!linkpath) {\n        JS_FreeCString(ctx, target);\n        return JS_EXCEPTION;\n    }\n    err = js_get_errno(symlink(target, linkpath));\n    JS_FreeCString(ctx, target);\n    JS_FreeCString(ctx, linkpath);\n    return JS_NewInt32(ctx, err);\n}\n\n/* return [path, errorcode] */\nstatic JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    const char *path;\n    char buf[PATH_MAX];\n    int err;\n    ssize_t res;\n\n    path = JS_ToCString(ctx, argv[0]);\n    if (!path)\n        return JS_EXCEPTION;\n    res = readlink(path, buf, sizeof(buf) - 1);\n    if (res < 0) {\n        buf[0] = '\\0';\n        err = errno;\n    } else {\n        buf[res] = '\\0';\n        err = 0;\n    }\n    JS_FreeCString(ctx, path);\n    return make_string_error(ctx, buf, err);\n}\n\nstatic char **build_envp(JSContext *ctx, JSValueConst obj)\n{\n    uint32_t len, i;\n    JSPropertyEnum *tab;\n    char **envp, *pair;\n    const char *key, *str;\n    JSValue val;\n    size_t key_len, str_len;\n\n    if (JS_GetOwnPropertyNames(ctx, &tab, &len, obj,\n                               JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY) < 0)\n        return NULL;\n    envp = js_mallocz(ctx, sizeof(envp[0]) * ((size_t)len + 1));\n    if (!envp)\n        goto fail;\n    for(i = 0; i < len; i++) {\n        val = JS_GetProperty(ctx, obj, tab[i].atom);\n        if (JS_IsException(val))\n            goto fail;\n        str = JS_ToCString(ctx, val);\n        JS_FreeValue(ctx, val);\n        if (!str)\n            goto fail;\n        key = JS_AtomToCString(ctx, tab[i].atom);\n        if (!key) {\n            JS_FreeCString(ctx, str);\n            goto fail;\n        }\n        key_len = strlen(key);\n        str_len = strlen(str);\n        pair = js_malloc(ctx, key_len + str_len + 2);\n        if (!pair) {\n            JS_FreeCString(ctx, key);\n            JS_FreeCString(ctx, str);\n            goto fail;\n        }\n        memcpy(pair, key, key_len);\n        pair[key_len] = '=';\n        memcpy(pair + key_len + 1, str, str_len);\n        pair[key_len + 1 + str_len] = '\\0';\n        envp[i] = pair;\n        JS_FreeCString(ctx, key);\n        JS_FreeCString(ctx, str);\n    }\n done:\n    JS_FreePropertyEnum(ctx, tab, len);\n    return envp;\n fail:\n    if (envp) {\n        for(i = 0; i < len; i++)\n            js_free(ctx, envp[i]);\n        js_free(ctx, envp);\n        envp = NULL;\n    }\n    goto done;\n}\n\n/* execvpe is not available on non GNU systems */\nstatic int my_execvpe(const char *filename, char **argv, char **envp)\n{\n    char *path, *p, *p_next, *p1;\n    char buf[PATH_MAX];\n    size_t filename_len, path_len;\n    BOOL eacces_error;\n\n    filename_len = strlen(filename);\n    if (filename_len == 0) {\n        errno = ENOENT;\n        return -1;\n    }\n    if (strchr(filename, '/'))\n        return execve(filename, argv, envp);\n\n    path = getenv(\"PATH\");\n    if (!path)\n        path = (char *)\"/bin:/usr/bin\";\n    eacces_error = FALSE;\n    p = path;\n    for(p = path; p != NULL; p = p_next) {\n        p1 = strchr(p, ':');\n        if (!p1) {\n            p_next = NULL;\n            path_len = strlen(p);\n        } else {\n            p_next = p1 + 1;\n            path_len = p1 - p;\n        }\n        /* path too long */\n        if ((path_len + 1 + filename_len + 1) > PATH_MAX)\n            continue;\n        memcpy(buf, p, path_len);\n        buf[path_len] = '/';\n        memcpy(buf + path_len + 1, filename, filename_len);\n        buf[path_len + 1 + filename_len] = '\\0';\n\n        execve(buf, argv, envp);\n\n        switch(errno) {\n        case EACCES:\n            eacces_error = TRUE;\n            break;\n        case ENOENT:\n        case ENOTDIR:\n            break;\n        default:\n            return -1;\n        }\n    }\n    if (eacces_error)\n        errno = EACCES;\n    return -1;\n}\n\n/* exec(args[, options]) -> exitcode */\nstatic JSValue js_os_exec(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv)\n{\n    JSValueConst options, args = argv[0];\n    JSValue val, ret_val;\n    const char **exec_argv, *file = NULL, *str, *cwd = NULL;\n    char **envp = environ;\n    uint32_t exec_argc, i;\n    int ret, pid, status;\n    BOOL block_flag = TRUE, use_path = TRUE;\n    static const char *std_name[3] = { \"stdin\", \"stdout\", \"stderr\" };\n    int std_fds[3];\n    uint32_t uid = -1, gid = -1;\n\n    val = JS_GetPropertyStr(ctx, args, \"length\");\n    if (JS_IsException(val))\n        return JS_EXCEPTION;\n    ret = JS_ToUint32(ctx, &exec_argc, val);\n    JS_FreeValue(ctx, val);\n    if (ret)\n        return JS_EXCEPTION;\n    /* arbitrary limit to avoid overflow */\n    if (exec_argc < 1 || exec_argc > 65535) {\n        return JS_ThrowTypeError(ctx, \"invalid number of arguments\");\n    }\n    exec_argv = js_mallocz(ctx, sizeof(exec_argv[0]) * (exec_argc + 1));\n    if (!exec_argv)\n        return JS_EXCEPTION;\n    for(i = 0; i < exec_argc; i++) {\n        val = JS_GetPropertyUint32(ctx, args, i);\n        if (JS_IsException(val))\n            goto exception;\n        str = JS_ToCString(ctx, val);\n        JS_FreeValue(ctx, val);\n        if (!str)\n            goto exception;\n        exec_argv[i] = str;\n    }\n    exec_argv[exec_argc] = NULL;\n\n    for(i = 0; i < 3; i++)\n        std_fds[i] = i;\n\n    /* get the options, if any */\n    if (argc >= 2) {\n        options = argv[1];\n\n        if (get_bool_option(ctx, &block_flag, options, \"block\"))\n            goto exception;\n        if (get_bool_option(ctx, &use_path, options, \"usePath\"))\n            goto exception;\n\n        val = JS_GetPropertyStr(ctx, options, \"file\");\n        if (JS_IsException(val))\n            goto exception;\n        if (!JS_IsUndefined(val)) {\n            file = JS_ToCString(ctx, val);\n            JS_FreeValue(ctx, val);\n            if (!file)\n                goto exception;\n        }\n\n        val = JS_GetPropertyStr(ctx, options, \"cwd\");\n        if (JS_IsException(val))\n            goto exception;\n        if (!JS_IsUndefined(val)) {\n            cwd = JS_ToCString(ctx, val);\n            JS_FreeValue(ctx, val);\n            if (!cwd)\n                goto exception;\n        }\n\n        /* stdin/stdout/stderr handles */\n        for(i = 0; i < 3; i++) {\n            val = JS_GetPropertyStr(ctx, options, std_name[i]);\n            if (JS_IsException(val))\n                goto exception;\n            if (!JS_IsUndefined(val)) {\n                int fd;\n                ret = JS_ToInt32(ctx, &fd, val);\n                JS_FreeValue(ctx, val);\n                if (ret)\n                    goto exception;\n                std_fds[i] = fd;\n            }\n        }\n\n        val = JS_GetPropertyStr(ctx, options, \"env\");\n        if (JS_IsException(val))\n            goto exception;\n        if (!JS_IsUndefined(val)) {\n            envp = build_envp(ctx, val);\n            JS_FreeValue(ctx, val);\n            if (!envp)\n                goto exception;\n        }\n\n        val = JS_GetPropertyStr(ctx, options, \"uid\");\n        if (JS_IsException(val))\n            goto exception;\n        if (!JS_IsUndefined(val)) {\n            ret = JS_ToUint32(ctx, &uid, val);\n            JS_FreeValue(ctx, val);\n            if (ret)\n                goto exception;\n        }\n\n        val = JS_GetPropertyStr(ctx, options, \"gid\");\n        if (JS_IsException(val))\n            goto exception;\n        if (!JS_IsUndefined(val)) {\n            ret = JS_ToUint32(ctx, &gid, val);\n            JS_FreeValue(ctx, val);\n            if (ret)\n                goto exception;\n        }\n    }\n\n    pid = fork();\n    if (pid < 0) {\n        JS_ThrowTypeError(ctx, \"fork error\");\n        goto exception;\n    }\n    if (pid == 0) {\n        /* child */\n\n        /* remap the stdin/stdout/stderr handles if necessary */\n        for(i = 0; i < 3; i++) {\n            if (std_fds[i] != i) {\n                if (dup2(std_fds[i], i) < 0)\n                    _exit(127);\n            }\n        }\n#if defined(HAVE_CLOSEFROM)\n        /* closefrom() is available on many recent unix systems:\n           Linux with glibc 2.34+, Solaris 9+, FreeBSD 7.3+,\n           NetBSD 3.0+, OpenBSD 3.5+.\n           Linux with the musl libc and macOS don't have it.\n         */\n\n        closefrom(3);\n#else\n        {\n            /* Close the file handles manually, limit to 1024 to avoid\n               costly loop on linux Alpine where sysconf(_SC_OPEN_MAX)\n               returns a huge value 1048576.\n               Patch inspired by nicolas-duteil-nova. See also:\n               https://stackoverflow.com/questions/73229353/\n               https://stackoverflow.com/questions/899038/#918469\n             */\n            int fd_max = min_int(sysconf(_SC_OPEN_MAX), 1024);\n            for(i = 3; i < fd_max; i++)\n                close(i);\n        }\n#endif\n        if (cwd) {\n            if (chdir(cwd) < 0)\n                _exit(127);\n        }\n        if (uid != -1) {\n            if (setuid(uid) < 0)\n                _exit(127);\n        }\n        if (gid != -1) {\n            if (setgid(gid) < 0)\n                _exit(127);\n        }\n\n        if (!file)\n            file = exec_argv[0];\n        if (use_path)\n            ret = my_execvpe(file, (char **)exec_argv, envp);\n        else\n            ret = execve(file, (char **)exec_argv, envp);\n        _exit(127);\n    }\n    /* parent */\n    if (block_flag) {\n        for(;;) {\n            ret = waitpid(pid, &status, 0);\n            if (ret == pid) {\n                if (WIFEXITED(status)) {\n                    ret = WEXITSTATUS(status);\n                    break;\n                } else if (WIFSIGNALED(status)) {\n                    ret = -WTERMSIG(status);\n                    break;\n                }\n            }\n        }\n    } else {\n        ret = pid;\n    }\n    ret_val = JS_NewInt32(ctx, ret);\n done:\n    JS_FreeCString(ctx, file);\n    JS_FreeCString(ctx, cwd);\n    for(i = 0; i < exec_argc; i++)\n        JS_FreeCString(ctx, exec_argv[i]);\n    js_free(ctx, exec_argv);\n    if (envp != environ) {\n        char **p;\n        p = envp;\n        while (*p != NULL) {\n            js_free(ctx, *p);\n            p++;\n        }\n        js_free(ctx, envp);\n    }\n    return ret_val;\n exception:\n    ret_val = JS_EXCEPTION;\n    goto done;\n}\n\n/* getpid() -> pid */\nstatic JSValue js_os_getpid(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    return JS_NewInt32(ctx, getpid());\n}\n\n/* waitpid(pid, block) -> [pid, status] */\nstatic JSValue js_os_waitpid(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    int pid, status, options, ret;\n    JSValue obj;\n\n    if (JS_ToInt32(ctx, &pid, argv[0]))\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &options, argv[1]))\n        return JS_EXCEPTION;\n\n    ret = waitpid(pid, &status, options);\n    if (ret < 0) {\n        ret = -errno;\n        status = 0;\n    }\n\n    obj = JS_NewArray(ctx);\n    if (JS_IsException(obj))\n        return obj;\n    JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, ret),\n                                 JS_PROP_C_W_E);\n    JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, status),\n                                 JS_PROP_C_W_E);\n    return obj;\n}\n\n/* pipe() -> [read_fd, write_fd] or null if error */\nstatic JSValue js_os_pipe(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv)\n{\n    int pipe_fds[2], ret;\n    JSValue obj;\n\n    ret = pipe(pipe_fds);\n    if (ret < 0)\n        return JS_NULL;\n    obj = JS_NewArray(ctx);\n    if (JS_IsException(obj))\n        return obj;\n    JS_DefinePropertyValueUint32(ctx, obj, 0, JS_NewInt32(ctx, pipe_fds[0]),\n                                 JS_PROP_C_W_E);\n    JS_DefinePropertyValueUint32(ctx, obj, 1, JS_NewInt32(ctx, pipe_fds[1]),\n                                 JS_PROP_C_W_E);\n    return obj;\n}\n\n/* kill(pid, sig) */\nstatic JSValue js_os_kill(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv)\n{\n    int pid, sig, ret;\n\n    if (JS_ToInt32(ctx, &pid, argv[0]))\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &sig, argv[1]))\n        return JS_EXCEPTION;\n    ret = js_get_errno(kill(pid, sig));\n    return JS_NewInt32(ctx, ret);\n}\n\n/* dup(fd) */\nstatic JSValue js_os_dup(JSContext *ctx, JSValueConst this_val,\n                         int argc, JSValueConst *argv)\n{\n    int fd, ret;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    ret = js_get_errno(dup(fd));\n    return JS_NewInt32(ctx, ret);\n}\n\n/* dup2(fd) */\nstatic JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,\n                         int argc, JSValueConst *argv)\n{\n    int fd, fd2, ret;\n\n    if (JS_ToInt32(ctx, &fd, argv[0]))\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &fd2, argv[1]))\n        return JS_EXCEPTION;\n    ret = js_get_errno(dup2(fd, fd2));\n    return JS_NewInt32(ctx, ret);\n}\n\n#endif /* !_WIN32 */\n\n#ifdef USE_WORKER\n\n/* Worker */\n\ntypedef struct {\n    JSWorkerMessagePipe *recv_pipe;\n    JSWorkerMessagePipe *send_pipe;\n    JSWorkerMessageHandler *msg_handler;\n} JSWorkerData;\n\ntypedef struct {\n    char *filename; /* module filename */\n    char *basename; /* module base name */\n    JSWorkerMessagePipe *recv_pipe, *send_pipe;\n    int strip_flags;\n} WorkerFuncArgs;\n\ntypedef struct {\n    int ref_count;\n    uint64_t buf[0];\n} JSSABHeader;\n\nstatic JSClassID js_worker_class_id;\nstatic JSContext *(*js_worker_new_context_func)(JSRuntime *rt);\n\nstatic int atomic_add_int(int *ptr, int v)\n{\n    return atomic_fetch_add((_Atomic(uint32_t) *)ptr, v) + v;\n}\n\n/* shared array buffer allocator */\nstatic void *js_sab_alloc(void *opaque, size_t size)\n{\n    JSSABHeader *sab;\n    sab = malloc(sizeof(JSSABHeader) + size);\n    if (!sab)\n        return NULL;\n    sab->ref_count = 1;\n    return sab->buf;\n}\n\nstatic void js_sab_free(void *opaque, void *ptr)\n{\n    JSSABHeader *sab;\n    int ref_count;\n    sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));\n    ref_count = atomic_add_int(&sab->ref_count, -1);\n    assert(ref_count >= 0);\n    if (ref_count == 0) {\n        free(sab);\n    }\n}\n\nstatic void js_sab_dup(void *opaque, void *ptr)\n{\n    JSSABHeader *sab;\n    sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));\n    atomic_add_int(&sab->ref_count, 1);\n}\n\nstatic JSWorkerMessagePipe *js_new_message_pipe(void)\n{\n    JSWorkerMessagePipe *ps;\n\n    ps = malloc(sizeof(*ps));\n    if (!ps)\n        return NULL;\n    if (js_waker_init(&ps->waker)) {\n        free(ps);\n        return NULL;\n    }\n    ps->ref_count = 1;\n    init_list_head(&ps->msg_queue);\n    pthread_mutex_init(&ps->mutex, NULL);\n    return ps;\n}\n\nstatic JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps)\n{\n    atomic_add_int(&ps->ref_count, 1);\n    return ps;\n}\n\nstatic void js_free_message(JSWorkerMessage *msg)\n{\n    size_t i;\n    /* free the SAB */\n    for(i = 0; i < msg->sab_tab_len; i++) {\n        js_sab_free(NULL, msg->sab_tab[i]);\n    }\n    free(msg->sab_tab);\n    free(msg->data);\n    free(msg);\n}\n\nstatic void js_free_message_pipe(JSWorkerMessagePipe *ps)\n{\n    struct list_head *el, *el1;\n    JSWorkerMessage *msg;\n    int ref_count;\n\n    if (!ps)\n        return;\n\n    ref_count = atomic_add_int(&ps->ref_count, -1);\n    assert(ref_count >= 0);\n    if (ref_count == 0) {\n        list_for_each_safe(el, el1, &ps->msg_queue) {\n            msg = list_entry(el, JSWorkerMessage, link);\n            js_free_message(msg);\n        }\n        pthread_mutex_destroy(&ps->mutex);\n        js_waker_close(&ps->waker);\n        free(ps);\n    }\n}\n\nstatic void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port)\n{\n    if (port) {\n        js_free_message_pipe(port->recv_pipe);\n        JS_FreeValueRT(rt, port->on_message_func);\n        if (port->link.prev)\n            list_del(&port->link);\n        js_free_rt(rt, port);\n    }\n}\n\nstatic void js_worker_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id);\n    if (worker) {\n        js_free_message_pipe(worker->recv_pipe);\n        js_free_message_pipe(worker->send_pipe);\n        js_free_port(rt, worker->msg_handler);\n        js_free_rt(rt, worker);\n    }\n}\n\nstatic void js_worker_mark(JSRuntime *rt, JSValueConst val,\n                           JS_MarkFunc *mark_func)\n{\n    JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id);\n    if (worker) {\n        JSWorkerMessageHandler *port = worker->msg_handler;\n        if (port) {\n            JS_MarkValue(rt, port->on_message_func, mark_func);\n        }\n    }\n}\n\nstatic JSClassDef js_worker_class = {\n    \"Worker\",\n    .finalizer = js_worker_finalizer,\n    .gc_mark = js_worker_mark,\n};\n\nstatic void *worker_func(void *opaque)\n{\n    WorkerFuncArgs *args = opaque;\n    JSRuntime *rt;\n    JSThreadState *ts;\n    JSContext *ctx;\n    JSValue val;\n\n    rt = JS_NewRuntime();\n    if (rt == NULL) {\n        fprintf(stderr, \"JS_NewRuntime failure\");\n        exit(1);\n    }\n    JS_SetStripInfo(rt, args->strip_flags);\n    js_std_init_handlers(rt);\n\n    JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);\n\n    /* set the pipe to communicate with the parent */\n    ts = JS_GetRuntimeOpaque(rt);\n    ts->recv_pipe = args->recv_pipe;\n    ts->send_pipe = args->send_pipe;\n\n    /* function pointer to avoid linking the whole JS_NewContext() if\n       not needed */\n    ctx = js_worker_new_context_func(rt);\n    if (ctx == NULL) {\n        fprintf(stderr, \"JS_NewContext failure\");\n    }\n\n    JS_SetCanBlock(rt, TRUE);\n\n    js_std_add_helpers(ctx, -1, NULL);\n\n    val = JS_LoadModule(ctx, args->basename, args->filename);\n    free(args->filename);\n    free(args->basename);\n    free(args);\n    val = js_std_await(ctx, val);\n    if (JS_IsException(val))\n        js_std_dump_error(ctx);\n    JS_FreeValue(ctx, val);\n\n    js_std_loop(ctx);\n\n    JS_FreeContext(ctx);\n    js_std_free_handlers(rt);\n    JS_FreeRuntime(rt);\n    return NULL;\n}\n\nstatic JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target,\n                                       JSWorkerMessagePipe *recv_pipe,\n                                       JSWorkerMessagePipe *send_pipe)\n{\n    JSValue obj = JS_UNDEFINED, proto;\n    JSWorkerData *s;\n\n    /* create the object */\n    if (JS_IsUndefined(new_target)) {\n        proto = JS_GetClassProto(ctx, js_worker_class_id);\n    } else {\n        proto = JS_GetPropertyStr(ctx, new_target, \"prototype\");\n        if (JS_IsException(proto))\n            goto fail;\n    }\n    obj = JS_NewObjectProtoClass(ctx, proto, js_worker_class_id);\n    JS_FreeValue(ctx, proto);\n    if (JS_IsException(obj))\n        goto fail;\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s)\n        goto fail;\n    s->recv_pipe = js_dup_message_pipe(recv_pipe);\n    s->send_pipe = js_dup_message_pipe(send_pipe);\n\n    JS_SetOpaque(obj, s);\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,\n                              int argc, JSValueConst *argv)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    WorkerFuncArgs *args = NULL;\n    pthread_t tid;\n    pthread_attr_t attr;\n    JSValue obj = JS_UNDEFINED;\n    int ret;\n    const char *filename = NULL, *basename;\n    JSAtom basename_atom;\n\n    /* XXX: in order to avoid problems with resource liberation, we\n       don't support creating workers inside workers */\n    if (!is_main_thread(rt))\n        return JS_ThrowTypeError(ctx, \"cannot create a worker inside a worker\");\n\n    /* base name, assuming the calling function is a normal JS\n       function */\n    basename_atom = JS_GetScriptOrModuleName(ctx, 1);\n    if (basename_atom == JS_ATOM_NULL) {\n        return JS_ThrowTypeError(ctx, \"could not determine calling script or module name\");\n    }\n    basename = JS_AtomToCString(ctx, basename_atom);\n    JS_FreeAtom(ctx, basename_atom);\n    if (!basename)\n        goto fail;\n\n    /* module name */\n    filename = JS_ToCString(ctx, argv[0]);\n    if (!filename)\n        goto fail;\n\n    args = malloc(sizeof(*args));\n    if (!args)\n        goto oom_fail;\n    memset(args, 0, sizeof(*args));\n    args->filename = strdup(filename);\n    args->basename = strdup(basename);\n\n    /* ports */\n    args->recv_pipe = js_new_message_pipe();\n    if (!args->recv_pipe)\n        goto oom_fail;\n    args->send_pipe = js_new_message_pipe();\n    if (!args->send_pipe)\n        goto oom_fail;\n\n    args->strip_flags = JS_GetStripInfo(rt);\n    \n    obj = js_worker_ctor_internal(ctx, new_target,\n                                  args->send_pipe, args->recv_pipe);\n    if (JS_IsException(obj))\n        goto fail;\n\n    pthread_attr_init(&attr);\n    /* no join at the end */\n    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);\n    ret = pthread_create(&tid, &attr, worker_func, args);\n    pthread_attr_destroy(&attr);\n    if (ret != 0) {\n        JS_ThrowTypeError(ctx, \"could not create worker\");\n        goto fail;\n    }\n    JS_FreeCString(ctx, basename);\n    JS_FreeCString(ctx, filename);\n    return obj;\n oom_fail:\n    JS_ThrowOutOfMemory(ctx);\n fail:\n    JS_FreeCString(ctx, basename);\n    JS_FreeCString(ctx, filename);\n    if (args) {\n        free(args->filename);\n        free(args->basename);\n        js_free_message_pipe(args->recv_pipe);\n        js_free_message_pipe(args->send_pipe);\n        free(args);\n    }\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);\n    JSWorkerMessagePipe *ps;\n    size_t data_len, sab_tab_len, i;\n    uint8_t *data;\n    JSWorkerMessage *msg;\n    uint8_t **sab_tab;\n\n    if (!worker)\n        return JS_EXCEPTION;\n\n    data = JS_WriteObject2(ctx, &data_len, argv[0],\n                           JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE,\n                           &sab_tab, &sab_tab_len);\n    if (!data)\n        return JS_EXCEPTION;\n\n    msg = malloc(sizeof(*msg));\n    if (!msg)\n        goto fail;\n    msg->data = NULL;\n    msg->sab_tab = NULL;\n\n    /* must reallocate because the allocator may be different */\n    msg->data = malloc(data_len);\n    if (!msg->data)\n        goto fail;\n    memcpy(msg->data, data, data_len);\n    msg->data_len = data_len;\n\n    if (sab_tab_len > 0) {\n        msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len);\n        if (!msg->sab_tab)\n            goto fail;\n        memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len);\n    }\n    msg->sab_tab_len = sab_tab_len;\n\n    js_free(ctx, data);\n    js_free(ctx, sab_tab);\n\n    /* increment the SAB reference counts */\n    for(i = 0; i < msg->sab_tab_len; i++) {\n        js_sab_dup(NULL, msg->sab_tab[i]);\n    }\n\n    ps = worker->send_pipe;\n    pthread_mutex_lock(&ps->mutex);\n    /* indicate that data is present */\n    if (list_empty(&ps->msg_queue))\n        js_waker_signal(&ps->waker);\n    list_add_tail(&msg->link, &ps->msg_queue);\n    pthread_mutex_unlock(&ps->mutex);\n    return JS_UNDEFINED;\n fail:\n    if (msg) {\n        free(msg->data);\n        free(msg->sab_tab);\n        free(msg);\n    }\n    js_free(ctx, data);\n    js_free(ctx, sab_tab);\n    return JS_EXCEPTION;\n\n}\n\nstatic JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,\n                                   JSValueConst func)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);\n    JSWorkerMessageHandler *port;\n\n    if (!worker)\n        return JS_EXCEPTION;\n\n    port = worker->msg_handler;\n    if (JS_IsNull(func)) {\n        if (port) {\n            js_free_port(rt, port);\n            worker->msg_handler = NULL;\n        }\n    } else {\n        if (!JS_IsFunction(ctx, func))\n            return JS_ThrowTypeError(ctx, \"not a function\");\n        if (!port) {\n            port = js_mallocz(ctx, sizeof(*port));\n            if (!port)\n                return JS_EXCEPTION;\n            port->recv_pipe = js_dup_message_pipe(worker->recv_pipe);\n            port->on_message_func = JS_NULL;\n            list_add_tail(&port->link, &ts->port_list);\n            worker->msg_handler = port;\n        }\n        JS_FreeValue(ctx, port->on_message_func);\n        port->on_message_func = JS_DupValue(ctx, func);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val)\n{\n    JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);\n    JSWorkerMessageHandler *port;\n    if (!worker)\n        return JS_EXCEPTION;\n    port = worker->msg_handler;\n    if (port) {\n        return JS_DupValue(ctx, port->on_message_func);\n    } else {\n        return JS_NULL;\n    }\n}\n\nstatic const JSCFunctionListEntry js_worker_proto_funcs[] = {\n    JS_CFUNC_DEF(\"postMessage\", 1, js_worker_postMessage ),\n    JS_CGETSET_DEF(\"onmessage\", js_worker_get_onmessage, js_worker_set_onmessage ),\n};\n\n#endif /* USE_WORKER */\n\nvoid js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt))\n{\n#ifdef USE_WORKER\n    js_worker_new_context_func = func;\n#endif\n}\n\n#if defined(_WIN32)\n#define OS_PLATFORM \"win32\"\n#elif defined(__APPLE__)\n#define OS_PLATFORM \"darwin\"\n#elif defined(EMSCRIPTEN)\n#define OS_PLATFORM \"js\"\n#else\n#define OS_PLATFORM \"linux\"\n#endif\n\n#define OS_FLAG(x) JS_PROP_INT32_DEF(#x, x, JS_PROP_CONFIGURABLE )\n\nstatic const JSCFunctionListEntry js_os_funcs[] = {\n    JS_CFUNC_DEF(\"open\", 2, js_os_open ),\n    OS_FLAG(O_RDONLY),\n    OS_FLAG(O_WRONLY),\n    OS_FLAG(O_RDWR),\n    OS_FLAG(O_APPEND),\n    OS_FLAG(O_CREAT),\n    OS_FLAG(O_EXCL),\n    OS_FLAG(O_TRUNC),\n#if defined(_WIN32)\n    OS_FLAG(O_BINARY),\n    OS_FLAG(O_TEXT),\n#endif\n    JS_CFUNC_DEF(\"close\", 1, js_os_close ),\n    JS_CFUNC_DEF(\"seek\", 3, js_os_seek ),\n    JS_CFUNC_MAGIC_DEF(\"read\", 4, js_os_read_write, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"write\", 4, js_os_read_write, 1 ),\n    JS_CFUNC_DEF(\"isatty\", 1, js_os_isatty ),\n    JS_CFUNC_DEF(\"ttyGetWinSize\", 1, js_os_ttyGetWinSize ),\n    JS_CFUNC_DEF(\"ttySetRaw\", 1, js_os_ttySetRaw ),\n    JS_CFUNC_DEF(\"remove\", 1, js_os_remove ),\n    JS_CFUNC_DEF(\"rename\", 2, js_os_rename ),\n    JS_CFUNC_MAGIC_DEF(\"setReadHandler\", 2, js_os_setReadHandler, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"setWriteHandler\", 2, js_os_setReadHandler, 1 ),\n    JS_CFUNC_DEF(\"signal\", 2, js_os_signal ),\n    OS_FLAG(SIGINT),\n    OS_FLAG(SIGABRT),\n    OS_FLAG(SIGFPE),\n    OS_FLAG(SIGILL),\n    OS_FLAG(SIGSEGV),\n    OS_FLAG(SIGTERM),\n#if !defined(_WIN32)\n    OS_FLAG(SIGQUIT),\n    OS_FLAG(SIGPIPE),\n    OS_FLAG(SIGALRM),\n    OS_FLAG(SIGUSR1),\n    OS_FLAG(SIGUSR2),\n    OS_FLAG(SIGCHLD),\n    OS_FLAG(SIGCONT),\n    OS_FLAG(SIGSTOP),\n    OS_FLAG(SIGTSTP),\n    OS_FLAG(SIGTTIN),\n    OS_FLAG(SIGTTOU),\n#endif\n    JS_CFUNC_DEF(\"now\", 0, js_os_now ),\n    JS_CFUNC_DEF(\"setTimeout\", 2, js_os_setTimeout ),\n    JS_CFUNC_DEF(\"clearTimeout\", 1, js_os_clearTimeout ),\n    JS_CFUNC_DEF(\"sleepAsync\", 1, js_os_sleepAsync ),\n    JS_PROP_STRING_DEF(\"platform\", OS_PLATFORM, 0 ),\n    JS_CFUNC_DEF(\"getcwd\", 0, js_os_getcwd ),\n    JS_CFUNC_DEF(\"chdir\", 0, js_os_chdir ),\n    JS_CFUNC_DEF(\"mkdir\", 1, js_os_mkdir ),\n    JS_CFUNC_DEF(\"readdir\", 1, js_os_readdir ),\n    /* st_mode constants */\n    OS_FLAG(S_IFMT),\n    OS_FLAG(S_IFIFO),\n    OS_FLAG(S_IFCHR),\n    OS_FLAG(S_IFDIR),\n    OS_FLAG(S_IFBLK),\n    OS_FLAG(S_IFREG),\n#if !defined(_WIN32)\n    OS_FLAG(S_IFSOCK),\n    OS_FLAG(S_IFLNK),\n    OS_FLAG(S_ISGID),\n    OS_FLAG(S_ISUID),\n#endif\n    JS_CFUNC_MAGIC_DEF(\"stat\", 1, js_os_stat, 0 ),\n    JS_CFUNC_DEF(\"utimes\", 3, js_os_utimes ),\n    JS_CFUNC_DEF(\"sleep\", 1, js_os_sleep ),\n    JS_CFUNC_DEF(\"realpath\", 1, js_os_realpath ),\n#if !defined(_WIN32)\n    JS_CFUNC_MAGIC_DEF(\"lstat\", 1, js_os_stat, 1 ),\n    JS_CFUNC_DEF(\"symlink\", 2, js_os_symlink ),\n    JS_CFUNC_DEF(\"readlink\", 1, js_os_readlink ),\n    JS_CFUNC_DEF(\"exec\", 1, js_os_exec ),\n    JS_CFUNC_DEF(\"getpid\", 0, js_os_getpid ),\n    JS_CFUNC_DEF(\"waitpid\", 2, js_os_waitpid ),\n    OS_FLAG(WNOHANG),\n    JS_CFUNC_DEF(\"pipe\", 0, js_os_pipe ),\n    JS_CFUNC_DEF(\"kill\", 2, js_os_kill ),\n    JS_CFUNC_DEF(\"dup\", 1, js_os_dup ),\n    JS_CFUNC_DEF(\"dup2\", 2, js_os_dup2 ),\n#endif\n};\n\nstatic int js_os_init(JSContext *ctx, JSModuleDef *m)\n{\n    os_poll_func = js_os_poll;\n\n#ifdef USE_WORKER\n    {\n        JSRuntime *rt = JS_GetRuntime(ctx);\n        JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n        JSValue proto, obj;\n        /* Worker class */\n        JS_NewClassID(&js_worker_class_id);\n        JS_NewClass(JS_GetRuntime(ctx), js_worker_class_id, &js_worker_class);\n        proto = JS_NewObject(ctx);\n        JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs));\n\n        obj = JS_NewCFunction2(ctx, js_worker_ctor, \"Worker\", 1,\n                               JS_CFUNC_constructor, 0);\n        JS_SetConstructor(ctx, obj, proto);\n\n        JS_SetClassProto(ctx, js_worker_class_id, proto);\n\n        /* set 'Worker.parent' if necessary */\n        if (ts->recv_pipe && ts->send_pipe) {\n            JS_DefinePropertyValueStr(ctx, obj, \"parent\",\n                                      js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe),\n                                      JS_PROP_C_W_E);\n        }\n\n        JS_SetModuleExport(ctx, m, \"Worker\", obj);\n    }\n#endif /* USE_WORKER */\n\n    return JS_SetModuleExportList(ctx, m, js_os_funcs,\n                                  countof(js_os_funcs));\n}\n\nJSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)\n{\n    JSModuleDef *m;\n    m = JS_NewCModule(ctx, module_name, js_os_init);\n    if (!m)\n        return NULL;\n    JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));\n#ifdef USE_WORKER\n    JS_AddModuleExport(ctx, m, \"Worker\");\n#endif\n    return m;\n}\n\n/**********************************************************/\n\nstatic JSValue js_print(JSContext *ctx, JSValueConst this_val,\n                        int argc, JSValueConst *argv)\n{\n    int i;\n    JSValueConst v;\n    \n    for(i = 0; i < argc; i++) {\n        if (i != 0)\n            putchar(' ');\n        v = argv[i];\n        if (JS_IsString(v)) {\n            const char *str;\n            size_t len;\n            str = JS_ToCStringLen(ctx, &len, v);\n            if (!str)\n                return JS_EXCEPTION;\n            fwrite(str, 1, len, stdout);\n            JS_FreeCString(ctx, str);\n        } else {\n            JS_PrintValue(ctx, js_print_value_write, stdout, v, NULL);\n        }\n    }\n    putchar('\\n');\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_console_log(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSValue ret;\n    ret = js_print(ctx, this_val, argc, argv);\n    fflush(stdout);\n    return ret;\n}\n\nvoid js_std_add_helpers(JSContext *ctx, int argc, char **argv)\n{\n    JSValue global_obj, console, args, performance;\n    int i;\n\n    /* XXX: should these global definitions be enumerable? */\n    global_obj = JS_GetGlobalObject(ctx);\n\n    console = JS_NewObject(ctx);\n    JS_SetPropertyStr(ctx, console, \"log\",\n                      JS_NewCFunction(ctx, js_console_log, \"log\", 1));\n    JS_SetPropertyStr(ctx, global_obj, \"console\", console);\n\n    performance = JS_NewObject(ctx);\n    JS_SetPropertyStr(ctx, performance, \"now\",\n                      JS_NewCFunction(ctx, js_os_now, \"now\", 0));\n    JS_SetPropertyStr(ctx, global_obj, \"performance\", performance);\n\n    /* same methods as the mozilla JS shell */\n    if (argc >= 0) {\n        args = JS_NewArray(ctx);\n        for(i = 0; i < argc; i++) {\n            JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i]));\n        }\n        JS_SetPropertyStr(ctx, global_obj, \"scriptArgs\", args);\n    }\n\n    JS_SetPropertyStr(ctx, global_obj, \"print\",\n                      JS_NewCFunction(ctx, js_print, \"print\", 1));\n    JS_SetPropertyStr(ctx, global_obj, \"__loadScript\",\n                      JS_NewCFunction(ctx, js_loadScript, \"__loadScript\", 1));\n\n    JS_FreeValue(ctx, global_obj);\n}\n\nvoid js_std_init_handlers(JSRuntime *rt)\n{\n    JSThreadState *ts;\n\n    ts = malloc(sizeof(*ts));\n    if (!ts) {\n        fprintf(stderr, \"Could not allocate memory for the worker\");\n        exit(1);\n    }\n    memset(ts, 0, sizeof(*ts));\n    init_list_head(&ts->os_rw_handlers);\n    init_list_head(&ts->os_signal_handlers);\n    init_list_head(&ts->os_timers);\n    init_list_head(&ts->port_list);\n    init_list_head(&ts->rejected_promise_list);\n    ts->next_timer_id = 1;\n\n    JS_SetRuntimeOpaque(rt, ts);\n\n#ifdef USE_WORKER\n    /* set the SharedArrayBuffer memory handlers */\n    {\n        JSSharedArrayBufferFunctions sf;\n        memset(&sf, 0, sizeof(sf));\n        sf.sab_alloc = js_sab_alloc;\n        sf.sab_free = js_sab_free;\n        sf.sab_dup = js_sab_dup;\n        JS_SetSharedArrayBufferFunctions(rt, &sf);\n    }\n#endif\n}\n\nvoid js_std_free_handlers(JSRuntime *rt)\n{\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    struct list_head *el, *el1;\n\n    list_for_each_safe(el, el1, &ts->os_rw_handlers) {\n        JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link);\n        free_rw_handler(rt, rh);\n    }\n\n    list_for_each_safe(el, el1, &ts->os_signal_handlers) {\n        JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link);\n        free_sh(rt, sh);\n    }\n\n    list_for_each_safe(el, el1, &ts->os_timers) {\n        JSOSTimer *th = list_entry(el, JSOSTimer, link);\n        free_timer(rt, th);\n    }\n\n    list_for_each_safe(el, el1, &ts->rejected_promise_list) {\n        JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);\n        JS_FreeValueRT(rt, rp->promise);\n        JS_FreeValueRT(rt, rp->reason);\n        free(rp);\n    }\n\n#ifdef USE_WORKER\n    js_free_message_pipe(ts->recv_pipe);\n    js_free_message_pipe(ts->send_pipe);\n\n    list_for_each_safe(el, el1, &ts->port_list) {\n        JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);\n        /* unlink the message ports. They are freed by the Worker object */\n        port->link.prev = NULL;\n        port->link.next = NULL;\n    }\n#endif\n\n    free(ts);\n    JS_SetRuntimeOpaque(rt, NULL); /* fail safe */\n}\n\nstatic void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val)\n{\n    JS_PrintValue(ctx, js_print_value_write, stderr, exception_val, NULL);\n    fputc('\\n', stderr);\n}\n\nvoid js_std_dump_error(JSContext *ctx)\n{\n    JSValue exception_val;\n\n    exception_val = JS_GetException(ctx);\n    js_std_dump_error1(ctx, exception_val);\n    JS_FreeValue(ctx, exception_val);\n}\n\nstatic JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts,\n                                                     JSValueConst promise)\n{\n    struct list_head *el;\n\n    list_for_each(el, &ts->rejected_promise_list) {\n        JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);\n        if (JS_SameValue(ctx, rp->promise, promise))\n            return rp;\n    }\n    return NULL;\n}\n\nvoid js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,\n                                      JSValueConst reason,\n                                      BOOL is_handled, void *opaque)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    JSRejectedPromiseEntry *rp;\n\n    if (!is_handled) {\n        /* add a new entry if needed */\n        rp = find_rejected_promise(ctx, ts, promise);\n        if (!rp) {\n            rp = malloc(sizeof(*rp));\n            if (rp) {\n                rp->promise = JS_DupValue(ctx, promise);\n                rp->reason = JS_DupValue(ctx, reason);\n                list_add_tail(&rp->link, &ts->rejected_promise_list);\n            }\n        }\n    } else {\n        /* the rejection is handled, so the entry can be removed if present */\n        rp = find_rejected_promise(ctx, ts, promise);\n        if (rp) {\n            JS_FreeValue(ctx, rp->promise);\n            JS_FreeValue(ctx, rp->reason);\n            list_del(&rp->link);\n            free(rp);\n        }\n    }\n}\n\n/* check if there are pending promise rejections. It must be done\n   asynchrously in case a rejected promise is handled later. Currently\n   we do it once the application is about to sleep. It could be done\n   more often if needed. */\nstatic void js_std_promise_rejection_check(JSContext *ctx)\n{\n    JSRuntime *rt = JS_GetRuntime(ctx);\n    JSThreadState *ts = JS_GetRuntimeOpaque(rt);\n    struct list_head *el;\n\n    if (unlikely(!list_empty(&ts->rejected_promise_list))) {\n        list_for_each(el, &ts->rejected_promise_list) {\n            JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);\n            fprintf(stderr, \"Possibly unhandled promise rejection: \");\n            js_std_dump_error1(ctx, rp->reason);\n        }\n        exit(1);\n    }\n}\n\n/* main loop which calls the user JS callbacks */\nvoid js_std_loop(JSContext *ctx)\n{\n    int err;\n\n    for(;;) {\n        /* execute the pending jobs */\n        for(;;) {\n            err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);\n            if (err <= 0) {\n                if (err < 0)\n                    js_std_dump_error(ctx);\n                break;\n            }\n        }\n\n        js_std_promise_rejection_check(ctx);\n        \n        if (!os_poll_func || os_poll_func(ctx))\n            break;\n    }\n}\n\n/* Wait for a promise and execute pending jobs while waiting for\n   it. Return the promise result or JS_EXCEPTION in case of promise\n   rejection. */\nJSValue js_std_await(JSContext *ctx, JSValue obj)\n{\n    JSValue ret;\n    int state;\n\n    for(;;) {\n        state = JS_PromiseState(ctx, obj);\n        if (state == JS_PROMISE_FULFILLED) {\n            ret = JS_PromiseResult(ctx, obj);\n            JS_FreeValue(ctx, obj);\n            break;\n        } else if (state == JS_PROMISE_REJECTED) {\n            ret = JS_Throw(ctx, JS_PromiseResult(ctx, obj));\n            JS_FreeValue(ctx, obj);\n            break;\n        } else if (state == JS_PROMISE_PENDING) {\n            int err;\n            err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);\n            if (err < 0) {\n                js_std_dump_error(ctx);\n            }\n            if (err == 0) {\n                js_std_promise_rejection_check(ctx);\n\n                if (os_poll_func)\n                    os_poll_func(ctx);\n            }\n        } else {\n            /* not a promise */\n            ret = obj;\n            break;\n        }\n    }\n    return ret;\n}\n\nvoid js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,\n                        int load_only)\n{\n    JSValue obj, val;\n    obj = JS_ReadObject(ctx, buf, buf_len, JS_READ_OBJ_BYTECODE);\n    if (JS_IsException(obj))\n        goto exception;\n    if (load_only) {\n        if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {\n            js_module_set_import_meta(ctx, obj, FALSE, FALSE);\n        }\n        JS_FreeValue(ctx, obj);\n    } else {\n        if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {\n            if (JS_ResolveModule(ctx, obj) < 0) {\n                JS_FreeValue(ctx, obj);\n                goto exception;\n            }\n            js_module_set_import_meta(ctx, obj, FALSE, TRUE);\n            val = JS_EvalFunction(ctx, obj);\n            val = js_std_await(ctx, val);\n        } else {\n            val = JS_EvalFunction(ctx, obj);\n        }\n        if (JS_IsException(val)) {\n        exception:\n            js_std_dump_error(ctx);\n            exit(1);\n        }\n        JS_FreeValue(ctx, val);\n    }\n}\n\nvoid js_std_eval_binary_json_module(JSContext *ctx,\n                                    const uint8_t *buf, size_t buf_len,\n                                    const char *module_name)\n{\n    JSValue obj;\n    JSModuleDef *m;\n    \n    obj = JS_ReadObject(ctx, buf, buf_len, 0);\n    if (JS_IsException(obj))\n        goto exception;\n    m = create_json_module(ctx, module_name, obj);\n    if (!m) {\n    exception:\n        js_std_dump_error(ctx);\n        exit(1);\n    }\n}\n\n"
  },
  {
    "path": "quickjs-libc.h",
    "content": "/*\n * QuickJS C library\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef QUICKJS_LIBC_H\n#define QUICKJS_LIBC_H\n\n#include <stdio.h>\n#include <stdlib.h>\n\n#include \"quickjs.h\"\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nJSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);\nJSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);\nvoid js_std_add_helpers(JSContext *ctx, int argc, char **argv);\nvoid js_std_loop(JSContext *ctx);\nJSValue js_std_await(JSContext *ctx, JSValue obj);\nvoid js_std_init_handlers(JSRuntime *rt);\nvoid js_std_free_handlers(JSRuntime *rt);\nvoid js_std_dump_error(JSContext *ctx);\nuint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);\nint js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,\n                              JS_BOOL use_realpath, JS_BOOL is_main);\nint js_module_test_json(JSContext *ctx, JSValueConst attributes);\nint js_module_check_attributes(JSContext *ctx, void *opaque, JSValueConst attributes);\nJSModuleDef *js_module_loader(JSContext *ctx,\n                              const char *module_name, void *opaque,\n                              JSValueConst attributes);\nvoid js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,\n                        int flags);\nvoid js_std_eval_binary_json_module(JSContext *ctx,\n                                    const uint8_t *buf, size_t buf_len,\n                                    const char *module_name);\nvoid js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,\n                                      JSValueConst reason,\n                                      JS_BOOL is_handled, void *opaque);\nvoid js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));\n\n#ifdef __cplusplus\n} /* extern \"C\" { */\n#endif\n\n#endif /* QUICKJS_LIBC_H */\n"
  },
  {
    "path": "quickjs-opcode.h",
    "content": "/*\n * QuickJS opcode definitions\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n * Copyright (c) 2017-2018 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\n#ifdef FMT\nFMT(none)\nFMT(none_int)\nFMT(none_loc)\nFMT(none_arg)\nFMT(none_var_ref)\nFMT(u8)\nFMT(i8)\nFMT(loc8)\nFMT(const8)\nFMT(label8)\nFMT(u16)\nFMT(i16)\nFMT(label16)\nFMT(npop)\nFMT(npopx)\nFMT(npop_u16)\nFMT(loc)\nFMT(arg)\nFMT(var_ref)\nFMT(u32)\nFMT(i32)\nFMT(const)\nFMT(label)\nFMT(atom)\nFMT(atom_u8)\nFMT(atom_u16)\nFMT(atom_label_u8)\nFMT(atom_label_u16)\nFMT(label_u16)\n#undef FMT\n#endif /* FMT */\n\n#ifdef DEF\n\n#ifndef def\n#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)\n#endif\n\nDEF(invalid, 1, 0, 0, none) /* never emitted */\n\n/* push values */\nDEF(       push_i32, 5, 0, 1, i32)\nDEF(     push_const, 5, 0, 1, const)\nDEF(       fclosure, 5, 0, 1, const) /* must follow push_const */\nDEF(push_atom_value, 5, 0, 1, atom)\nDEF( private_symbol, 5, 0, 1, atom)\nDEF(      undefined, 1, 0, 1, none)\nDEF(           null, 1, 0, 1, none)\nDEF(      push_this, 1, 0, 1, none) /* only used at the start of a function */\nDEF(     push_false, 1, 0, 1, none)\nDEF(      push_true, 1, 0, 1, none)\nDEF(         object, 1, 0, 1, none)\nDEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */\nDEF(           rest, 3, 0, 1, u16) /* only used at the start of a function */\n\nDEF(           drop, 1, 1, 0, none) /* a -> */\nDEF(            nip, 1, 2, 1, none) /* a b -> b */\nDEF(           nip1, 1, 3, 2, none) /* a b c -> b c */\nDEF(            dup, 1, 1, 2, none) /* a -> a a */\nDEF(           dup1, 1, 2, 3, none) /* a b -> a a b */\nDEF(           dup2, 1, 2, 4, none) /* a b -> a b a b */\nDEF(           dup3, 1, 3, 6, none) /* a b c -> a b c a b c */\nDEF(        insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */\nDEF(        insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */\nDEF(        insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */\nDEF(          perm3, 1, 3, 3, none) /* obj a b -> a obj b */\nDEF(          perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */\nDEF(          perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */\nDEF(           swap, 1, 2, 2, none) /* a b -> b a */\nDEF(          swap2, 1, 4, 4, none) /* a b c d -> c d a b */\nDEF(          rot3l, 1, 3, 3, none) /* x a b -> a b x */\nDEF(          rot3r, 1, 3, 3, none) /* a b x -> x a b */\nDEF(          rot4l, 1, 4, 4, none) /* x a b c -> a b c x */\nDEF(          rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */\n\nDEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */\nDEF(           call, 3, 1, 1, npop) /* arguments are not counted in n_pop */\nDEF(      tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */\nDEF(    call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */\nDEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */\nDEF(     array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */\nDEF(          apply, 3, 3, 1, u16)\nDEF(         return, 1, 1, 0, none)\nDEF(   return_undef, 1, 0, 0, none)\nDEF(check_ctor_return, 1, 1, 2, none)\nDEF(     check_ctor, 1, 0, 0, none)\nDEF(      init_ctor, 1, 0, 1, none)\nDEF(    check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */\nDEF(      add_brand, 1, 2, 0, none) /* this_obj home_obj -> */\nDEF(   return_async, 1, 1, 0, none)\nDEF(          throw, 1, 1, 0, none)\nDEF(    throw_error, 6, 0, 0, atom_u8)\nDEF(           eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */\nDEF(     apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */\nDEF(         regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a\n                                       bytecode string */\nDEF(      get_super, 1, 1, 1, none)\nDEF(         import, 1, 2, 1, none) /* dynamic module import */\n\nDEF(  get_var_undef, 3, 0, 1, var_ref) /* push undefined if the variable does not exist */\nDEF(        get_var, 3, 0, 1, var_ref) /* throw an exception if the variable does not exist */\nDEF(        put_var, 3, 1, 0, var_ref) /* must come after get_var */\nDEF(   put_var_init, 3, 1, 0, var_ref) /* must come after put_var. Used to initialize a global lexical variable */\n\nDEF(  get_ref_value, 1, 2, 3, none)\nDEF(  put_ref_value, 1, 3, 0, none)\n\nDEF(      get_field, 5, 1, 1, atom)\nDEF(     get_field2, 5, 1, 2, atom)\nDEF(      put_field, 5, 2, 0, atom)\nDEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */\nDEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */\nDEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */\nDEF(   get_array_el, 1, 2, 1, none)\nDEF(  get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */\nDEF(  get_array_el3, 1, 2, 3, none) /* obj prop -> obj prop1 value */\nDEF(   put_array_el, 1, 3, 0, none)\nDEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */\nDEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */\nDEF(   define_field, 5, 2, 1, atom)\nDEF(       set_name, 5, 1, 1, atom)\nDEF(set_name_computed, 1, 2, 2, none)\nDEF(      set_proto, 1, 2, 1, none)\nDEF(set_home_object, 1, 2, 2, none)\nDEF(define_array_el, 1, 3, 2, none)\nDEF(         append, 1, 3, 2, none) /* append enumerated object, update length */\nDEF(copy_data_properties, 2, 3, 3, u8)\nDEF(  define_method, 6, 2, 1, atom_u8)\nDEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */\nDEF(   define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */\nDEF(   define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */\n\nDEF(        get_loc, 3, 0, 1, loc)\nDEF(        put_loc, 3, 1, 0, loc) /* must come after get_loc */\nDEF(        set_loc, 3, 1, 1, loc) /* must come after put_loc */\nDEF(        get_arg, 3, 0, 1, arg)\nDEF(        put_arg, 3, 1, 0, arg) /* must come after get_arg */\nDEF(        set_arg, 3, 1, 1, arg) /* must come after put_arg */\nDEF(    get_var_ref, 3, 0, 1, var_ref)\nDEF(    put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */\nDEF(    set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */\nDEF(set_loc_uninitialized, 3, 0, 0, loc)\nDEF(  get_loc_check, 3, 0, 1, loc)\nDEF(  put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */\nDEF(  set_loc_check, 3, 1, 1, loc) /* must come after put_loc_check */\nDEF(  put_loc_check_init, 3, 1, 0, loc)\nDEF(get_loc_checkthis, 3, 0, 1, loc)\nDEF(get_var_ref_check, 3, 0, 1, var_ref)\nDEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */\nDEF(put_var_ref_check_init, 3, 1, 0, var_ref)\nDEF(      close_loc, 3, 0, 0, loc)\nDEF(       if_false, 5, 1, 0, label)\nDEF(        if_true, 5, 1, 0, label) /* must come after if_false */\nDEF(           goto, 5, 0, 0, label) /* must come after if_true */\nDEF(          catch, 5, 0, 1, label)\nDEF(          gosub, 5, 0, 0, label) /* used to execute the finally block */\nDEF(            ret, 1, 1, 0, none) /* used to return from the finally block */\nDEF(      nip_catch, 1, 2, 1, none) /* catch ... a -> a */\n\nDEF(      to_object, 1, 1, 1, none)\n//DEF(      to_string, 1, 1, 1, none)\nDEF(     to_propkey, 1, 1, 1, none)\n\nDEF(   with_get_var, 10, 1, 0, atom_label_u8)     /* must be in the same order as scope_xxx */\nDEF(   with_put_var, 10, 2, 1, atom_label_u8)     /* must be in the same order as scope_xxx */\nDEF(with_delete_var, 10, 1, 0, atom_label_u8)     /* must be in the same order as scope_xxx */\nDEF(  with_make_ref, 10, 1, 0, atom_label_u8)     /* must be in the same order as scope_xxx */\nDEF(   with_get_ref, 10, 1, 0, atom_label_u8)     /* must be in the same order as scope_xxx */\n\nDEF(   make_loc_ref, 7, 0, 2, atom_u16)\nDEF(   make_arg_ref, 7, 0, 2, atom_u16)\nDEF(make_var_ref_ref, 7, 0, 2, atom_u16)\nDEF(   make_var_ref, 5, 0, 2, atom)\n\nDEF(   for_in_start, 1, 1, 1, none)\nDEF(   for_of_start, 1, 1, 3, none)\nDEF(for_await_of_start, 1, 1, 3, none)\nDEF(    for_in_next, 1, 1, 3, none)\nDEF(    for_of_next, 2, 3, 5, u8)\nDEF(for_await_of_next, 1, 3, 4, none) /* iter next catch_offset -> iter next catch_offset obj */\nDEF(iterator_check_object, 1, 1, 1, none)\nDEF(iterator_get_value_done, 1, 2, 3, none) /* catch_offset obj -> catch_offset value done */\nDEF( iterator_close, 1, 3, 0, none)\nDEF(  iterator_next, 1, 4, 4, none)\nDEF(  iterator_call, 2, 4, 5, u8)\nDEF(  initial_yield, 1, 0, 0, none)\nDEF(          yield, 1, 1, 2, none)\nDEF(     yield_star, 1, 1, 2, none)\nDEF(async_yield_star, 1, 1, 2, none)\nDEF(          await, 1, 1, 1, none)\n\n/* arithmetic/logic operations */\nDEF(            neg, 1, 1, 1, none)\nDEF(           plus, 1, 1, 1, none)\nDEF(            dec, 1, 1, 1, none)\nDEF(            inc, 1, 1, 1, none)\nDEF(       post_dec, 1, 1, 2, none)\nDEF(       post_inc, 1, 1, 2, none)\nDEF(        dec_loc, 2, 0, 0, loc8)\nDEF(        inc_loc, 2, 0, 0, loc8)\nDEF(        add_loc, 2, 1, 0, loc8)\nDEF(            not, 1, 1, 1, none)\nDEF(           lnot, 1, 1, 1, none)\nDEF(         typeof, 1, 1, 1, none)\nDEF(         delete, 1, 2, 1, none)\nDEF(     delete_var, 5, 0, 1, atom)\n\nDEF(            mul, 1, 2, 1, none)\nDEF(            div, 1, 2, 1, none)\nDEF(            mod, 1, 2, 1, none)\nDEF(            add, 1, 2, 1, none)\nDEF(            sub, 1, 2, 1, none)\nDEF(            pow, 1, 2, 1, none)\nDEF(            shl, 1, 2, 1, none)\nDEF(            sar, 1, 2, 1, none)\nDEF(            shr, 1, 2, 1, none)\nDEF(             lt, 1, 2, 1, none)\nDEF(            lte, 1, 2, 1, none)\nDEF(             gt, 1, 2, 1, none)\nDEF(            gte, 1, 2, 1, none)\nDEF(     instanceof, 1, 2, 1, none)\nDEF(             in, 1, 2, 1, none)\nDEF(             eq, 1, 2, 1, none)\nDEF(            neq, 1, 2, 1, none)\nDEF(      strict_eq, 1, 2, 1, none)\nDEF(     strict_neq, 1, 2, 1, none)\nDEF(            and, 1, 2, 1, none)\nDEF(            xor, 1, 2, 1, none)\nDEF(             or, 1, 2, 1, none)\nDEF(is_undefined_or_null, 1, 1, 1, none)\nDEF(     private_in, 1, 2, 1, none)\nDEF(push_bigint_i32, 5, 0, 1, i32)\n/* must be the last non short and non temporary opcode */\nDEF(            nop, 1, 0, 0, none)\n\n/* temporary opcodes: never emitted in the final bytecode */\n\ndef(    enter_scope, 3, 0, 0, u16)  /* emitted in phase 1, removed in phase 2 */\ndef(    leave_scope, 3, 0, 0, u16)  /* emitted in phase 1, removed in phase 2 */\n\ndef(          label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */\n\n/* the following opcodes must be in the same order as the 'with_x' and\n   get_var_undef, get_var and put_var opcodes */\ndef(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */\ndef(  scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */\ndef(  scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */\ndef(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */\ndef( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */\ndef(  scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */\ndef(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */\ndef(scope_get_var_checkthis, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2, only used to return 'this' in derived class constructors */\ndef(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */\ndef(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */\ndef(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */\ndef(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */\ndef(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */\ndef(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */\ndef( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */\n\ndef(       line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */\n\n#if SHORT_OPCODES\nDEF(    push_minus1, 1, 0, 1, none_int)\nDEF(         push_0, 1, 0, 1, none_int)\nDEF(         push_1, 1, 0, 1, none_int)\nDEF(         push_2, 1, 0, 1, none_int)\nDEF(         push_3, 1, 0, 1, none_int)\nDEF(         push_4, 1, 0, 1, none_int)\nDEF(         push_5, 1, 0, 1, none_int)\nDEF(         push_6, 1, 0, 1, none_int)\nDEF(         push_7, 1, 0, 1, none_int)\nDEF(        push_i8, 2, 0, 1, i8)\nDEF(       push_i16, 3, 0, 1, i16)\nDEF(    push_const8, 2, 0, 1, const8)\nDEF(      fclosure8, 2, 0, 1, const8) /* must follow push_const8 */\nDEF(push_empty_string, 1, 0, 1, none)\n\nDEF(       get_loc8, 2, 0, 1, loc8)\nDEF(       put_loc8, 2, 1, 0, loc8)\nDEF(       set_loc8, 2, 1, 1, loc8)\n\nDEF(       get_loc0, 1, 0, 1, none_loc)\nDEF(       get_loc1, 1, 0, 1, none_loc)\nDEF(       get_loc2, 1, 0, 1, none_loc)\nDEF(       get_loc3, 1, 0, 1, none_loc)\nDEF(       put_loc0, 1, 1, 0, none_loc)\nDEF(       put_loc1, 1, 1, 0, none_loc)\nDEF(       put_loc2, 1, 1, 0, none_loc)\nDEF(       put_loc3, 1, 1, 0, none_loc)\nDEF(       set_loc0, 1, 1, 1, none_loc)\nDEF(       set_loc1, 1, 1, 1, none_loc)\nDEF(       set_loc2, 1, 1, 1, none_loc)\nDEF(       set_loc3, 1, 1, 1, none_loc)\nDEF(       get_arg0, 1, 0, 1, none_arg)\nDEF(       get_arg1, 1, 0, 1, none_arg)\nDEF(       get_arg2, 1, 0, 1, none_arg)\nDEF(       get_arg3, 1, 0, 1, none_arg)\nDEF(       put_arg0, 1, 1, 0, none_arg)\nDEF(       put_arg1, 1, 1, 0, none_arg)\nDEF(       put_arg2, 1, 1, 0, none_arg)\nDEF(       put_arg3, 1, 1, 0, none_arg)\nDEF(       set_arg0, 1, 1, 1, none_arg)\nDEF(       set_arg1, 1, 1, 1, none_arg)\nDEF(       set_arg2, 1, 1, 1, none_arg)\nDEF(       set_arg3, 1, 1, 1, none_arg)\nDEF(   get_var_ref0, 1, 0, 1, none_var_ref)\nDEF(   get_var_ref1, 1, 0, 1, none_var_ref)\nDEF(   get_var_ref2, 1, 0, 1, none_var_ref)\nDEF(   get_var_ref3, 1, 0, 1, none_var_ref)\nDEF(   put_var_ref0, 1, 1, 0, none_var_ref)\nDEF(   put_var_ref1, 1, 1, 0, none_var_ref)\nDEF(   put_var_ref2, 1, 1, 0, none_var_ref)\nDEF(   put_var_ref3, 1, 1, 0, none_var_ref)\nDEF(   set_var_ref0, 1, 1, 1, none_var_ref)\nDEF(   set_var_ref1, 1, 1, 1, none_var_ref)\nDEF(   set_var_ref2, 1, 1, 1, none_var_ref)\nDEF(   set_var_ref3, 1, 1, 1, none_var_ref)\n\nDEF(     get_length, 1, 1, 1, none)\n\nDEF(      if_false8, 2, 1, 0, label8)\nDEF(       if_true8, 2, 1, 0, label8) /* must come after if_false8 */\nDEF(          goto8, 2, 0, 0, label8) /* must come after if_true8 */\nDEF(         goto16, 3, 0, 0, label16)\n\nDEF(          call0, 1, 1, 1, npopx)\nDEF(          call1, 1, 1, 1, npopx)\nDEF(          call2, 1, 1, 1, npopx)\nDEF(          call3, 1, 1, 1, npopx)\n\nDEF(   is_undefined, 1, 1, 1, none)\nDEF(        is_null, 1, 1, 1, none)\nDEF(typeof_is_undefined, 1, 1, 1, none)\nDEF( typeof_is_function, 1, 1, 1, none)\n#endif\n\n#undef DEF\n#undef def\n#endif  /* DEF */\n"
  },
  {
    "path": "quickjs.c",
    "content": "/*\n * QuickJS Javascript Engine\n *\n * Copyright (c) 2017-2025 Fabrice Bellard\n * Copyright (c) 2017-2025 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n#include <sys/time.h>\n#include <time.h>\n#include <fenv.h>\n#include <math.h>\n#if defined(__APPLE__)\n#include <malloc/malloc.h>\n#elif defined(__linux__) || defined(__GLIBC__)\n#include <malloc.h>\n#elif defined(__FreeBSD__)\n#include <malloc_np.h>\n#endif\n\n#include \"cutils.h\"\n#include \"list.h\"\n#include \"quickjs.h\"\n#include \"libregexp.h\"\n#include \"libunicode.h\"\n#include \"dtoa.h\"\n\n#define OPTIMIZE         1\n#define SHORT_OPCODES    1\n#if defined(EMSCRIPTEN)\n#define DIRECT_DISPATCH  0\n#else\n#define DIRECT_DISPATCH  1\n#endif\n\n#if defined(__APPLE__)\n#define MALLOC_OVERHEAD  0\n#else\n#define MALLOC_OVERHEAD  8\n#endif\n\n#if !defined(_WIN32)\n/* define it if printf uses the RNDN rounding mode instead of RNDNA */\n#define CONFIG_PRINTF_RNDN\n#endif\n\n/* define to include Atomics.* operations which depend on the OS\n   threads */\n#if !defined(EMSCRIPTEN)\n#define CONFIG_ATOMICS\n#endif\n\n#if !defined(EMSCRIPTEN)\n/* enable stack limitation */\n#define CONFIG_STACK_CHECK\n#endif\n\n\n/* dump object free */\n//#define DUMP_FREE\n//#define DUMP_CLOSURE\n/* dump the bytecode of the compiled functions: combination of bits\n   1: dump pass 3 final byte code\n   2: dump pass 2 code\n   4: dump pass 1 code\n   8: dump stdlib functions\n  16: dump bytecode in hex\n  32: dump line number table\n  64: dump compute_stack_size\n */\n//#define DUMP_BYTECODE  (1)\n/* dump the occurence of the automatic GC */\n//#define DUMP_GC\n/* dump objects freed by the garbage collector */\n//#define DUMP_GC_FREE\n/* dump objects leaking when freeing the runtime */\n//#define DUMP_LEAKS  1\n/* dump memory usage before running the garbage collector */\n//#define DUMP_MEM\n//#define DUMP_OBJECTS    /* dump objects in JS_FreeContext */\n//#define DUMP_ATOMS      /* dump atoms in JS_FreeContext */\n//#define DUMP_SHAPES     /* dump shapes in JS_FreeContext */\n//#define DUMP_MODULE_RESOLVE\n//#define DUMP_MODULE_EXEC\n//#define DUMP_PROMISE\n//#define DUMP_READ_OBJECT\n//#define DUMP_ROPE_REBALANCE\n\n/* test the GC by forcing it before each object allocation */\n//#define FORCE_GC_AT_MALLOC\n\n#ifdef CONFIG_ATOMICS\n#include <pthread.h>\n#include <stdatomic.h>\n#include <errno.h>\n#endif\n\nenum {\n    /* classid tag        */    /* union usage   | properties */\n    JS_CLASS_OBJECT = 1,        /* must be first */\n    JS_CLASS_ARRAY,             /* u.array       | length */\n    JS_CLASS_ERROR,\n    JS_CLASS_NUMBER,            /* u.object_data */\n    JS_CLASS_STRING,            /* u.object_data */\n    JS_CLASS_BOOLEAN,           /* u.object_data */\n    JS_CLASS_SYMBOL,            /* u.object_data */\n    JS_CLASS_ARGUMENTS,         /* u.array       | length */\n    JS_CLASS_MAPPED_ARGUMENTS,  /* u.array       | length */\n    JS_CLASS_DATE,              /* u.object_data */\n    JS_CLASS_MODULE_NS,\n    JS_CLASS_C_FUNCTION,        /* u.cfunc */\n    JS_CLASS_BYTECODE_FUNCTION, /* u.func */\n    JS_CLASS_BOUND_FUNCTION,    /* u.bound_function */\n    JS_CLASS_C_FUNCTION_DATA,   /* u.c_function_data_record */\n    JS_CLASS_GENERATOR_FUNCTION, /* u.func */\n    JS_CLASS_FOR_IN_ITERATOR,   /* u.for_in_iterator */\n    JS_CLASS_REGEXP,            /* u.regexp */\n    JS_CLASS_ARRAY_BUFFER,      /* u.array_buffer */\n    JS_CLASS_SHARED_ARRAY_BUFFER, /* u.array_buffer */\n    JS_CLASS_UINT8C_ARRAY,      /* u.array (typed_array) */\n    JS_CLASS_INT8_ARRAY,        /* u.array (typed_array) */\n    JS_CLASS_UINT8_ARRAY,       /* u.array (typed_array) */\n    JS_CLASS_INT16_ARRAY,       /* u.array (typed_array) */\n    JS_CLASS_UINT16_ARRAY,      /* u.array (typed_array) */\n    JS_CLASS_INT32_ARRAY,       /* u.array (typed_array) */\n    JS_CLASS_UINT32_ARRAY,      /* u.array (typed_array) */\n    JS_CLASS_BIG_INT64_ARRAY,   /* u.array (typed_array) */\n    JS_CLASS_BIG_UINT64_ARRAY,  /* u.array (typed_array) */\n    JS_CLASS_FLOAT16_ARRAY,     /* u.array (typed_array) */\n    JS_CLASS_FLOAT32_ARRAY,     /* u.array (typed_array) */\n    JS_CLASS_FLOAT64_ARRAY,     /* u.array (typed_array) */\n    JS_CLASS_DATAVIEW,          /* u.typed_array */\n    JS_CLASS_BIG_INT,           /* u.object_data */\n    JS_CLASS_MAP,               /* u.map_state */\n    JS_CLASS_SET,               /* u.map_state */\n    JS_CLASS_WEAKMAP,           /* u.map_state */\n    JS_CLASS_WEAKSET,           /* u.map_state */\n    JS_CLASS_ITERATOR,          /* u.map_iterator_data */\n    JS_CLASS_ITERATOR_CONCAT,   /* u.iterator_concat_data */\n    JS_CLASS_ITERATOR_HELPER,   /* u.iterator_helper_data */\n    JS_CLASS_ITERATOR_WRAP,     /* u.iterator_wrap_data */\n    JS_CLASS_MAP_ITERATOR,      /* u.map_iterator_data */\n    JS_CLASS_SET_ITERATOR,      /* u.map_iterator_data */\n    JS_CLASS_ARRAY_ITERATOR,    /* u.array_iterator_data */\n    JS_CLASS_STRING_ITERATOR,   /* u.array_iterator_data */\n    JS_CLASS_REGEXP_STRING_ITERATOR,   /* u.regexp_string_iterator_data */\n    JS_CLASS_GENERATOR,         /* u.generator_data */\n    JS_CLASS_GLOBAL_OBJECT,     /* u.global_object */\n    JS_CLASS_PROXY,             /* u.proxy_data */\n    JS_CLASS_PROMISE,           /* u.promise_data */\n    JS_CLASS_PROMISE_RESOLVE_FUNCTION,  /* u.promise_function_data */\n    JS_CLASS_PROMISE_REJECT_FUNCTION,   /* u.promise_function_data */\n    JS_CLASS_ASYNC_FUNCTION,            /* u.func */\n    JS_CLASS_ASYNC_FUNCTION_RESOLVE,    /* u.async_function_data */\n    JS_CLASS_ASYNC_FUNCTION_REJECT,     /* u.async_function_data */\n    JS_CLASS_ASYNC_FROM_SYNC_ITERATOR,  /* u.async_from_sync_iterator_data */\n    JS_CLASS_ASYNC_GENERATOR_FUNCTION,  /* u.func */\n    JS_CLASS_ASYNC_GENERATOR,   /* u.async_generator_data */\n    JS_CLASS_WEAK_REF,\n    JS_CLASS_FINALIZATION_REGISTRY,\n    \n    JS_CLASS_INIT_COUNT, /* last entry for predefined classes */\n};\n\n/* number of typed array types */\n#define JS_TYPED_ARRAY_COUNT  (JS_CLASS_FLOAT64_ARRAY - JS_CLASS_UINT8C_ARRAY + 1)\nstatic uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT];\n#define typed_array_size_log2(classid)  (typed_array_size_log2[(classid)- JS_CLASS_UINT8C_ARRAY])\n\ntypedef enum JSErrorEnum {\n    JS_EVAL_ERROR,\n    JS_RANGE_ERROR,\n    JS_REFERENCE_ERROR,\n    JS_SYNTAX_ERROR,\n    JS_TYPE_ERROR,\n    JS_URI_ERROR,\n    JS_INTERNAL_ERROR,\n    JS_AGGREGATE_ERROR,\n\n    JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */\n} JSErrorEnum;\n\n/* the variable and scope indexes must fit on 16 bits. The (-1) and\n   ARG_SCOPE_END values are reserved. */\n#define JS_MAX_LOCAL_VARS 65534\n#define JS_STACK_SIZE_MAX 65534\n#define JS_STRING_LEN_MAX ((1 << 30) - 1)\n\n/* strings <= this length are not concatenated using ropes. if too\n   small, the rope memory overhead becomes high. */\n#define JS_STRING_ROPE_SHORT_LEN  512\n/* specific threshold for initial rope use */\n#define JS_STRING_ROPE_SHORT2_LEN 8192\n/* rope depth at which we rebalance */\n#define JS_STRING_ROPE_MAX_DEPTH 60\n\n#define __exception __attribute__((warn_unused_result))\n\ntypedef struct JSShape JSShape;\ntypedef struct JSString JSString;\ntypedef struct JSString JSAtomStruct;\ntypedef struct JSObject JSObject;\n\n#define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v))\n#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v))\n#define JS_VALUE_GET_STRING_ROPE(v) ((JSStringRope *)JS_VALUE_GET_PTR(v))\n\ntypedef enum {\n    JS_GC_PHASE_NONE,\n    JS_GC_PHASE_DECREF,\n    JS_GC_PHASE_REMOVE_CYCLES,\n} JSGCPhaseEnum;\n\ntypedef enum OPCodeEnum OPCodeEnum;\n\nstruct JSRuntime {\n    JSMallocFunctions mf;\n    JSMallocState malloc_state;\n    const char *rt_info;\n\n    int atom_hash_size; /* power of two */\n    int atom_count;\n    int atom_size;\n    int atom_count_resize; /* resize hash table at this count */\n    uint32_t *atom_hash;\n    JSAtomStruct **atom_array;\n    int atom_free_index; /* 0 = none */\n\n    int class_count;    /* size of class_array */\n    JSClass *class_array;\n\n    struct list_head context_list; /* list of JSContext.link */\n    /* list of JSGCObjectHeader.link. List of allocated GC objects (used\n       by the garbage collector) */\n    struct list_head gc_obj_list;\n    /* list of JSGCObjectHeader.link. Used during JS_FreeValueRT() */\n    struct list_head gc_zero_ref_count_list;\n    struct list_head tmp_obj_list; /* used during GC */\n    JSGCPhaseEnum gc_phase : 8;\n    size_t malloc_gc_threshold;\n    struct list_head weakref_list; /* list of JSWeakRefHeader.link */\n#ifdef DUMP_LEAKS\n    struct list_head string_list; /* list of JSString.link */\n#endif\n    /* stack limitation */\n    uintptr_t stack_size; /* in bytes, 0 if no limit */\n    uintptr_t stack_top;\n    uintptr_t stack_limit; /* lower stack limit */\n\n    JSValue current_exception;\n    /* true if the current exception cannot be catched */\n    BOOL current_exception_is_uncatchable : 8;\n    /* true if inside an out of memory error, to avoid recursing */\n    BOOL in_out_of_memory : 8;\n\n    struct JSStackFrame *current_stack_frame;\n\n    JSInterruptHandler *interrupt_handler;\n    void *interrupt_opaque;\n\n    JSHostPromiseRejectionTracker *host_promise_rejection_tracker;\n    void *host_promise_rejection_tracker_opaque;\n\n    struct list_head job_list; /* list of JSJobEntry.link */\n\n    JSModuleNormalizeFunc *module_normalize_func;\n    BOOL module_loader_has_attr;\n    union {\n        JSModuleLoaderFunc *module_loader_func;\n        JSModuleLoaderFunc2 *module_loader_func2;\n    } u;\n    JSModuleCheckSupportedImportAttributes *module_check_attrs;\n    void *module_loader_opaque;\n    /* timestamp for internal use in module evaluation */\n    int64_t module_async_evaluation_next_timestamp;\n\n    BOOL can_block : 8; /* TRUE if Atomics.wait can block */\n    /* used to allocate, free and clone SharedArrayBuffers */\n    JSSharedArrayBufferFunctions sab_funcs;\n    /* see JS_SetStripInfo() */\n    uint8_t strip_flags;\n    \n    /* Shape hash table */\n    int shape_hash_bits;\n    int shape_hash_size;\n    int shape_hash_count; /* number of hashed shapes */\n    JSShape **shape_hash;\n    void *user_opaque;\n};\n\nstruct JSClass {\n    uint32_t class_id; /* 0 means free entry */\n    JSAtom class_name;\n    JSClassFinalizer *finalizer;\n    JSClassGCMark *gc_mark;\n    JSClassCall *call;\n    /* pointers for exotic behavior, can be NULL if none are present */\n    const JSClassExoticMethods *exotic;\n};\n\n#define JS_MODE_STRICT (1 << 0)\n#define JS_MODE_ASYNC  (1 << 2) /* async function */\n#define JS_MODE_BACKTRACE_BARRIER (1 << 3) /* stop backtrace before this frame */\n\ntypedef struct JSStackFrame {\n    struct JSStackFrame *prev_frame; /* NULL if first stack frame */\n    JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */\n    JSValue *arg_buf; /* arguments */\n    JSValue *var_buf; /* variables */\n    struct JSVarRef **var_refs; /* references to arguments or local variables */ \n    const uint8_t *cur_pc; /* only used in bytecode functions : PC of the\n                        instruction after the call */\n    int arg_count;\n    int js_mode; /* not supported for C functions */\n    /* only used in generators. Current stack pointer value. NULL if\n       the function is running. */\n    JSValue *cur_sp;\n} JSStackFrame;\n\ntypedef enum {\n    JS_GC_OBJ_TYPE_JS_OBJECT,\n    JS_GC_OBJ_TYPE_FUNCTION_BYTECODE,\n    JS_GC_OBJ_TYPE_SHAPE,\n    JS_GC_OBJ_TYPE_VAR_REF,\n    JS_GC_OBJ_TYPE_ASYNC_FUNCTION,\n    JS_GC_OBJ_TYPE_JS_CONTEXT,\n    JS_GC_OBJ_TYPE_MODULE,\n} JSGCObjectTypeEnum;\n\n/* header for GC objects. GC objects are C data structures with a\n   reference count that can reference other GC objects. JS Objects are\n   a particular type of GC object. */\nstruct JSGCObjectHeader {\n    int ref_count; /* must come first, 32-bit */\n    JSGCObjectTypeEnum gc_obj_type : 4;\n    uint8_t mark : 1; /* used by the GC */\n    uint8_t dummy0: 3;\n    uint8_t dummy1; /* not used by the GC */\n    uint16_t dummy2; /* not used by the GC */\n    struct list_head link;\n};\n\ntypedef enum {\n    JS_WEAKREF_TYPE_MAP,\n    JS_WEAKREF_TYPE_WEAKREF,\n    JS_WEAKREF_TYPE_FINREC,\n} JSWeakRefHeaderTypeEnum;\n\ntypedef struct {\n    struct list_head link;\n    JSWeakRefHeaderTypeEnum weakref_type;\n} JSWeakRefHeader;\n\ntypedef struct JSVarRef {\n    union {\n        JSGCObjectHeader header; /* must come first */\n        struct {\n            int __gc_ref_count; /* corresponds to header.ref_count */\n            uint8_t __gc_mark; /* corresponds to header.mark/gc_obj_type */\n            uint8_t is_detached;\n            uint8_t is_lexical; /* only used with global variables */\n            uint8_t is_const; /* only used with global variables */\n        };\n    };\n    JSValue *pvalue; /* pointer to the value, either on the stack or\n                        to 'value' */\n    union {\n        JSValue value; /* used when is_detached = TRUE */\n        struct {\n            uint16_t var_ref_idx; /* index in JSStackFrame.var_refs[] */\n            JSStackFrame *stack_frame;\n        }; /* used when is_detached = FALSE */\n    };\n} JSVarRef;\n\n/* bigint */\n\n#if JS_LIMB_BITS == 32\n\ntypedef int32_t js_slimb_t;\ntypedef uint32_t js_limb_t;\ntypedef int64_t js_sdlimb_t;\ntypedef uint64_t js_dlimb_t;\n\n#define JS_LIMB_DIGITS 9\n\n#else\n\ntypedef __int128 int128_t;\ntypedef unsigned __int128 uint128_t;\ntypedef int64_t js_slimb_t;\ntypedef uint64_t js_limb_t;\ntypedef int128_t js_sdlimb_t;\ntypedef uint128_t js_dlimb_t;\n\n#define JS_LIMB_DIGITS 19\n\n#endif\n\ntypedef struct JSBigInt {\n    JSRefCountHeader header; /* must come first, 32-bit */\n    uint32_t len; /* number of limbs, >= 1 */\n    js_limb_t tab[]; /* two's complement representation, always\n                        normalized so that 'len' is the minimum\n                        possible length >= 1 */\n} JSBigInt;\n\n/* this bigint structure can hold a 64 bit integer */\ntypedef struct {\n    js_limb_t big_int_buf[sizeof(JSBigInt) / sizeof(js_limb_t)]; /* for JSBigInt */\n    /* must come just after */\n    js_limb_t tab[(64 + JS_LIMB_BITS - 1) / JS_LIMB_BITS];\n} JSBigIntBuf;\n    \ntypedef enum {\n    JS_AUTOINIT_ID_PROTOTYPE,\n    JS_AUTOINIT_ID_MODULE_NS,\n    JS_AUTOINIT_ID_PROP,\n} JSAutoInitIDEnum;\n\n/* must be large enough to have a negligible runtime cost and small\n   enough to call the interrupt callback often. */\n#define JS_INTERRUPT_COUNTER_INIT 10000\n\nstruct JSContext {\n    JSGCObjectHeader header; /* must come first */\n    JSRuntime *rt;\n    struct list_head link;\n\n    uint16_t binary_object_count;\n    int binary_object_size;\n    \n    JSShape *array_shape;   /* initial shape for Array objects */\n    JSShape *arguments_shape;  /* shape for arguments objects */\n    JSShape *mapped_arguments_shape;  /* shape for mapped arguments objects */\n    JSShape *regexp_shape;  /* shape for regexp objects */\n    JSShape *regexp_result_shape;  /* shape for regexp result objects */\n\n    JSValue *class_proto;\n    JSValue function_proto;\n    JSValue function_ctor;\n    JSValue array_ctor;\n    JSValue regexp_ctor;\n    JSValue promise_ctor;\n    JSValue native_error_proto[JS_NATIVE_ERROR_COUNT];\n    JSValue iterator_ctor;\n    JSValue async_iterator_proto;\n    JSValue array_proto_values;\n    JSValue throw_type_error;\n    JSValue eval_obj;\n\n    JSValue global_obj; /* global object */\n    JSValue global_var_obj; /* contains the global let/const definitions */\n\n    uint64_t random_state;\n\n    /* when the counter reaches zero, JSRutime.interrupt_handler is called */\n    int interrupt_counter;\n\n    struct list_head loaded_modules; /* list of JSModuleDef.link */\n\n    /* if NULL, RegExp compilation is not supported */\n    JSValue (*compile_regexp)(JSContext *ctx, JSValueConst pattern,\n                              JSValueConst flags);\n    /* if NULL, eval is not supported */\n    JSValue (*eval_internal)(JSContext *ctx, JSValueConst this_obj,\n                             const char *input, size_t input_len,\n                             const char *filename, int flags, int scope_idx);\n    void *user_opaque;\n};\n\ntypedef union JSFloat64Union {\n    double d;\n    uint64_t u64;\n    uint32_t u32[2];\n} JSFloat64Union;\n\nenum {\n    JS_ATOM_TYPE_STRING = 1,\n    JS_ATOM_TYPE_GLOBAL_SYMBOL,\n    JS_ATOM_TYPE_SYMBOL,\n    JS_ATOM_TYPE_PRIVATE,\n};\n\ntypedef enum {\n    JS_ATOM_KIND_STRING,\n    JS_ATOM_KIND_SYMBOL,\n    JS_ATOM_KIND_PRIVATE,\n} JSAtomKindEnum;\n\n#define JS_ATOM_HASH_MASK  ((1 << 30) - 1)\n#define JS_ATOM_HASH_PRIVATE JS_ATOM_HASH_MASK\n\nstruct JSString {\n    JSRefCountHeader header; /* must come first, 32-bit */\n    uint32_t len : 31;\n    uint8_t is_wide_char : 1; /* 0 = 8 bits, 1 = 16 bits characters */\n    /* for JS_ATOM_TYPE_SYMBOL: hash = weakref_count, atom_type = 3,\n       for JS_ATOM_TYPE_PRIVATE: hash = JS_ATOM_HASH_PRIVATE, atom_type = 3\n       XXX: could change encoding to have one more bit in hash */\n    uint32_t hash : 30;\n    uint8_t atom_type : 2; /* != 0 if atom, JS_ATOM_TYPE_x */\n    uint32_t hash_next; /* atom_index for JS_ATOM_TYPE_SYMBOL */\n#ifdef DUMP_LEAKS\n    struct list_head link; /* string list */\n#endif\n    union {\n        uint8_t str8[0]; /* 8 bit strings will get an extra null terminator */\n        uint16_t str16[0];\n    } u;\n};\n\ntypedef struct JSStringRope {\n    JSRefCountHeader header; /* must come first, 32-bit */\n    uint32_t len;\n    uint8_t is_wide_char; /* 0 = 8 bits, 1 = 16 bits characters */\n    uint8_t depth; /* max depth of the rope tree */\n    /* XXX: could reduce memory usage by using a direct pointer with\n       bit 0 to select rope or string */\n    JSValue left;\n    JSValue right; /* might be the empty string */\n} JSStringRope;\n\ntypedef enum {\n    JS_CLOSURE_LOCAL, /* 'var_idx' is the index of a local variable in the parent function */\n    JS_CLOSURE_ARG, /* 'var_idx' is the index of a argument variable in the parent function */\n    JS_CLOSURE_REF, /* 'var_idx' is the index of a closure variable in the parent function */\n    JS_CLOSURE_GLOBAL_REF, /* 'var_idx' in the index of a closure\n                              variable in the parent function\n                              referencing a global variable */\n    JS_CLOSURE_GLOBAL_DECL, /* global variable declaration (eval code only) */\n    JS_CLOSURE_GLOBAL, /* global variable (eval code only) */\n    JS_CLOSURE_MODULE_DECL, /* definition of a module variable (eval code only) */\n    JS_CLOSURE_MODULE_IMPORT, /* definition of a module import (eval code only) */ \n} JSClosureTypeEnum;\n\ntypedef struct JSClosureVar {\n    JSClosureTypeEnum closure_type : 3;\n    uint8_t is_lexical : 1; /* lexical variable */\n    uint8_t is_const : 1; /* const variable (is_lexical = 1 if is_const = 1 */\n    uint8_t var_kind : 4; /* see JSVarKindEnum */\n    uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the\n                    parent function. otherwise: index to a closure\n                    variable of the parent function */\n    JSAtom var_name;\n} JSClosureVar;\n\n#define ARG_SCOPE_INDEX 1\n#define ARG_SCOPE_END (-2)\n\ntypedef enum {\n    /* XXX: add more variable kinds here instead of using bit fields */\n    JS_VAR_NORMAL,\n    JS_VAR_FUNCTION_DECL, /* lexical var with function declaration */\n    JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator\n                                 function declaration */\n    JS_VAR_CATCH,\n    JS_VAR_FUNCTION_NAME, /* function expression name */\n    JS_VAR_PRIVATE_FIELD,\n    JS_VAR_PRIVATE_METHOD,\n    JS_VAR_PRIVATE_GETTER,\n    JS_VAR_PRIVATE_SETTER, /* must come after JS_VAR_PRIVATE_GETTER */\n    JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */\n    JS_VAR_GLOBAL_FUNCTION_DECL, /* global function definition, only in JSVarDef */\n} JSVarKindEnum;\n\ntypedef struct JSBytecodeVarDef {\n    JSAtom var_name;\n    /* index into JSFunctionBytecode.vars of the next variable in the same or\n       enclosing lexical scope\n    */\n    int scope_next; /* XXX: store on 16 bits */\n    uint8_t is_const : 1;\n    uint8_t is_lexical : 1;\n    uint8_t is_captured : 1; /* XXX: could remove and use a var_ref_idx value */\n    uint8_t has_scope: 1; /* true if JSVarDef.scope_level != 0 */\n    uint8_t var_kind : 4; /* see JSVarKindEnum */\n    /* If is_captured = TRUE, provides, the index of the corresponding\n       JSVarRef on stack. It would be more compact to have a separate\n       table with the corresponding inverted table but it requires\n       more modifications in the code. */\n    uint16_t var_ref_idx;\n} JSBytecodeVarDef;\n\n/* for the encoding of the pc2line table */\n#define PC2LINE_BASE     (-1)\n#define PC2LINE_RANGE    5\n#define PC2LINE_OP_FIRST 1\n#define PC2LINE_DIFF_PC_MAX ((255 - PC2LINE_OP_FIRST) / PC2LINE_RANGE)\n\ntypedef enum JSFunctionKindEnum {\n    JS_FUNC_NORMAL = 0,\n    JS_FUNC_GENERATOR = (1 << 0),\n    JS_FUNC_ASYNC = (1 << 1),\n    JS_FUNC_ASYNC_GENERATOR = (JS_FUNC_GENERATOR | JS_FUNC_ASYNC),\n} JSFunctionKindEnum;\n\ntypedef struct JSFunctionBytecode {\n    JSGCObjectHeader header; /* must come first */\n    uint8_t js_mode;\n    uint8_t has_prototype : 1; /* true if a prototype field is necessary */\n    uint8_t has_simple_parameter_list : 1;\n    uint8_t is_derived_class_constructor : 1;\n    /* true if home_object needs to be initialized */\n    uint8_t need_home_object : 1;\n    uint8_t func_kind : 2;\n    uint8_t new_target_allowed : 1;\n    uint8_t super_call_allowed : 1;\n    uint8_t super_allowed : 1;\n    uint8_t arguments_allowed : 1;\n    uint8_t has_debug : 1;\n    uint8_t read_only_bytecode : 1;\n    uint8_t is_direct_or_indirect_eval : 1; /* used by JS_GetScriptOrModuleName() */\n    /* XXX: 10 bits available */\n    uint8_t *byte_code_buf; /* (self pointer) */\n    int byte_code_len;\n    JSAtom func_name;\n    JSBytecodeVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */\n    JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */\n    uint16_t arg_count;\n    uint16_t var_count;\n    uint16_t defined_arg_count; /* for length function property */\n    uint16_t stack_size; /* maximum stack size */\n    uint16_t var_ref_count; /* number of local variable references */\n    JSContext *realm; /* function realm */\n    JSValue *cpool; /* constant pool (self pointer) */\n    int cpool_count;\n    int closure_var_count;\n    struct {\n        /* debug info, move to separate structure to save memory? */\n        JSAtom filename;\n        int source_len; \n        int pc2line_len;\n        uint8_t *pc2line_buf;\n        char *source;\n    } debug;\n} JSFunctionBytecode;\n\ntypedef struct JSBoundFunction {\n    JSValue func_obj;\n    JSValue this_val;\n    int argc;\n    JSValue argv[0];\n} JSBoundFunction;\n\ntypedef enum JSIteratorKindEnum {\n    JS_ITERATOR_KIND_KEY,\n    JS_ITERATOR_KIND_VALUE,\n    JS_ITERATOR_KIND_KEY_AND_VALUE,\n} JSIteratorKindEnum;\n\ntypedef struct JSForInIterator {\n    JSValue obj;\n    uint32_t idx;\n    uint32_t atom_count;\n    uint8_t in_prototype_chain;\n    uint8_t is_array;\n    JSPropertyEnum *tab_atom; /* is_array = FALSE */\n} JSForInIterator;\n\ntypedef struct JSRegExp {\n    JSString *pattern;\n    JSString *bytecode; /* also contains the flags */\n} JSRegExp;\n\ntypedef struct JSProxyData {\n    JSValue target;\n    JSValue handler;\n    uint8_t is_func;\n    uint8_t is_revoked;\n} JSProxyData;\n\ntypedef struct JSArrayBuffer {\n    int byte_length; /* 0 if detached */\n    int max_byte_length; /* -1 if not resizable; >= byte_length otherwise */\n    uint8_t detached;\n    uint8_t shared; /* if shared, the array buffer cannot be detached */\n    uint8_t *data; /* NULL if detached */\n    struct list_head array_list;\n    void *opaque;\n    JSFreeArrayBufferDataFunc *free_func;\n} JSArrayBuffer;\n\ntypedef struct JSTypedArray {\n    struct list_head link; /* link to arraybuffer */\n    JSObject *obj; /* back pointer to the TypedArray/DataView object */\n    JSObject *buffer; /* based array buffer */\n    uint32_t offset; /* byte offset in the array buffer */\n    uint32_t length; /* byte length in the array buffer */\n    BOOL track_rab; /* auto-track length of backing array buffer */\n} JSTypedArray;\n\ntypedef struct JSGlobalObject {\n    JSValue uninitialized_vars; /* hidden object containing the list of uninitialized variables */\n} JSGlobalObject;\n\ntypedef struct JSAsyncFunctionState {\n    JSGCObjectHeader header;\n    JSValue this_val; /* 'this' argument */\n    int argc; /* number of function arguments */\n    BOOL throw_flag; /* used to throw an exception in JS_CallInternal() */\n    BOOL is_completed; /* TRUE if the function has returned. The stack\n                          frame is no longer valid */\n    JSValue resolving_funcs[2]; /* only used in JS async functions */\n    JSStackFrame frame;\n    /* arg_buf, var_buf, stack_buf and var_refs follow */\n} JSAsyncFunctionState;\n\ntypedef enum {\n   /* binary operators */\n   JS_OVOP_ADD,\n   JS_OVOP_SUB,\n   JS_OVOP_MUL,\n   JS_OVOP_DIV,\n   JS_OVOP_MOD,\n   JS_OVOP_POW,\n   JS_OVOP_OR,\n   JS_OVOP_AND,\n   JS_OVOP_XOR,\n   JS_OVOP_SHL,\n   JS_OVOP_SAR,\n   JS_OVOP_SHR,\n   JS_OVOP_EQ,\n   JS_OVOP_LESS,\n\n   JS_OVOP_BINARY_COUNT,\n   /* unary operators */\n   JS_OVOP_POS = JS_OVOP_BINARY_COUNT,\n   JS_OVOP_NEG,\n   JS_OVOP_INC,\n   JS_OVOP_DEC,\n   JS_OVOP_NOT,\n\n   JS_OVOP_COUNT,\n} JSOverloadableOperatorEnum;\n\ntypedef struct {\n    uint32_t operator_index;\n    JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */\n} JSBinaryOperatorDefEntry;\n\ntypedef struct {\n    int count;\n    JSBinaryOperatorDefEntry *tab;\n} JSBinaryOperatorDef;\n\ntypedef struct {\n    uint32_t operator_counter;\n    BOOL is_primitive; /* OperatorSet for a primitive type */\n    /* NULL if no operator is defined */\n    JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */\n    JSBinaryOperatorDef left;\n    JSBinaryOperatorDef right;\n} JSOperatorSetData;\n\ntypedef struct JSReqModuleEntry {\n    JSAtom module_name;\n    JSModuleDef *module; /* used using resolution */\n    JSValue attributes; /* JS_UNDEFINED or an object contains the attributes as key/value */\n} JSReqModuleEntry;\n\ntypedef enum JSExportTypeEnum {\n    JS_EXPORT_TYPE_LOCAL,\n    JS_EXPORT_TYPE_INDIRECT,\n} JSExportTypeEnum;\n\ntypedef struct JSExportEntry {\n    union {\n        struct {\n            int var_idx; /* closure variable index */\n            JSVarRef *var_ref; /* if != NULL, reference to the variable */\n        } local; /* for local export */\n        int req_module_idx; /* module for indirect export */\n    } u;\n    JSExportTypeEnum export_type;\n    JSAtom local_name; /* '*' if export ns from. not used for local\n                          export after compilation */\n    JSAtom export_name; /* exported variable name */\n} JSExportEntry;\n\ntypedef struct JSStarExportEntry {\n    int req_module_idx; /* in req_module_entries */\n} JSStarExportEntry;\n\ntypedef struct JSImportEntry {\n    int var_idx; /* closure variable index */\n    BOOL is_star; /* import_name = '*' is a valid import name, so need a flag */\n    JSAtom import_name;\n    int req_module_idx; /* in req_module_entries */\n} JSImportEntry;\n\ntypedef enum {\n    JS_MODULE_STATUS_UNLINKED,\n    JS_MODULE_STATUS_LINKING,\n    JS_MODULE_STATUS_LINKED,\n    JS_MODULE_STATUS_EVALUATING,\n    JS_MODULE_STATUS_EVALUATING_ASYNC,\n    JS_MODULE_STATUS_EVALUATED,\n} JSModuleStatus;\n\nstruct JSModuleDef {\n    JSGCObjectHeader header; /* must come first */\n    JSAtom module_name;\n    struct list_head link;\n\n    JSReqModuleEntry *req_module_entries;\n    int req_module_entries_count;\n    int req_module_entries_size;\n\n    JSExportEntry *export_entries;\n    int export_entries_count;\n    int export_entries_size;\n\n    JSStarExportEntry *star_export_entries;\n    int star_export_entries_count;\n    int star_export_entries_size;\n\n    JSImportEntry *import_entries;\n    int import_entries_count;\n    int import_entries_size;\n\n    JSValue module_ns;\n    JSValue func_obj; /* only used for JS modules */\n    JSModuleInitFunc *init_func; /* only used for C modules */\n    BOOL has_tla : 8; /* true if func_obj contains await */\n    BOOL resolved : 8;\n    BOOL func_created : 8;\n    JSModuleStatus status : 8;\n    /* temp use during js_module_link() & js_module_evaluate() */\n    int dfs_index, dfs_ancestor_index;\n    JSModuleDef *stack_prev;\n    /* temp use during js_module_evaluate() */\n    JSModuleDef **async_parent_modules;\n    int async_parent_modules_count;\n    int async_parent_modules_size;\n    int pending_async_dependencies;\n    BOOL async_evaluation; /* true: async_evaluation_timestamp corresponds to [[AsyncEvaluationOrder]] \n                              false: [[AsyncEvaluationOrder]] is UNSET or DONE */\n    int64_t async_evaluation_timestamp;\n    JSModuleDef *cycle_root;\n    JSValue promise; /* corresponds to spec field: capability */\n    JSValue resolving_funcs[2]; /* corresponds to spec field: capability */\n\n    /* true if evaluation yielded an exception. It is saved in\n       eval_exception */\n    BOOL eval_has_exception : 8;\n    JSValue eval_exception;\n    JSValue meta_obj; /* for import.meta */\n    JSValue private_value; /* private value for C modules */\n};\n\ntypedef struct JSJobEntry {\n    struct list_head link;\n    JSContext *realm;\n    JSJobFunc *job_func;\n    int argc;\n    JSValue argv[0];\n} JSJobEntry;\n\ntypedef struct JSProperty {\n    union {\n        JSValue value;      /* JS_PROP_NORMAL */\n        struct {            /* JS_PROP_GETSET */\n            JSObject *getter; /* NULL if undefined */\n            JSObject *setter; /* NULL if undefined */\n        } getset;\n        JSVarRef *var_ref;  /* JS_PROP_VARREF */\n        struct {            /* JS_PROP_AUTOINIT */\n            /* in order to use only 2 pointers, we compress the realm\n               and the init function pointer */\n            uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)\n                                       in the 2 low bits */\n            void *opaque;\n        } init;\n    } u;\n} JSProperty;\n\n#define JS_PROP_INITIAL_SIZE 2\n#define JS_PROP_INITIAL_HASH_SIZE 4 /* must be a power of two */\n\ntypedef struct JSShapeProperty {\n    uint32_t hash_next : 26; /* 0 if last in list */\n    uint32_t flags : 6;   /* JS_PROP_XXX */\n    JSAtom atom; /* JS_ATOM_NULL = free property entry */\n} JSShapeProperty;\n\nstruct JSShape {\n    /* hash table of size hash_mask + 1 before the start of the\n       structure (see prop_hash_end()). */\n    JSGCObjectHeader header;\n    /* true if the shape is inserted in the shape hash table. If not,\n       JSShape.hash is not valid */\n    uint8_t is_hashed;\n    uint32_t hash; /* current hash value */\n    uint32_t prop_hash_mask;\n    int prop_size; /* allocated properties */\n    int prop_count; /* include deleted properties */\n    int deleted_prop_count;\n    JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */\n    JSObject *proto;\n    JSShapeProperty prop[0]; /* prop_size elements */\n};\n\nstruct JSObject {\n    union {\n        JSGCObjectHeader header;\n        struct {\n            int __gc_ref_count; /* corresponds to header.ref_count */\n            uint8_t __gc_mark : 7; /* corresponds to header.mark/gc_obj_type */\n            /* TRUE if the array prototype is \"normal\":\n               - no small index properties which are get/set or non writable\n               - its prototype is Object.prototype\n               - Object.prototype has no small index properties which are get/set or non writable\n               - the prototype of Object.prototype is null (always true as it is immutable)\n            */\n            uint8_t is_std_array_prototype : 1;\n\n            uint8_t extensible : 1;\n            uint8_t free_mark : 1; /* only used when freeing objects with cycles */\n            uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */\n            uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_MAPPED_ARGUMENTS and typed arrays) */\n            uint8_t is_constructor : 1; /* TRUE if object is a constructor function */\n            uint8_t has_immutable_prototype : 1; /* cannot modify the prototype */\n            uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */\n            uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */\n            uint16_t class_id; /* see JS_CLASS_x */\n        };\n    };\n    /* count the number of weak references to this object. The object\n       structure is freed only if header.ref_count = 0 and\n       weakref_count = 0 */\n    uint32_t weakref_count; \n    JSShape *shape; /* prototype and property names + flag */\n    JSProperty *prop; /* array of properties */\n    union {\n        void *opaque;\n        struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */\n        struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */\n        struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */\n        struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */\n        struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */\n        struct JSMapState *map_state;   /* JS_CLASS_MAP..JS_CLASS_WEAKSET */\n        struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */\n        struct JSArrayIteratorData *array_iterator_data; /* JS_CLASS_ARRAY_ITERATOR, JS_CLASS_STRING_ITERATOR */\n        struct JSRegExpStringIteratorData *regexp_string_iterator_data; /* JS_CLASS_REGEXP_STRING_ITERATOR */\n        struct JSGeneratorData *generator_data; /* JS_CLASS_GENERATOR */\n        struct JSIteratorConcatData *iterator_concat_data; /* JS_CLASS_ITERATOR_CONCAT */\n        struct JSIteratorHelperData *iterator_helper_data; /* JS_CLASS_ITERATOR_HELPER */\n        struct JSIteratorWrapData *iterator_wrap_data; /* JS_CLASS_ITERATOR_WRAP */\n        struct JSProxyData *proxy_data; /* JS_CLASS_PROXY */\n        struct JSPromiseData *promise_data; /* JS_CLASS_PROMISE */\n        struct JSPromiseFunctionData *promise_function_data; /* JS_CLASS_PROMISE_RESOLVE_FUNCTION, JS_CLASS_PROMISE_REJECT_FUNCTION */\n        struct JSAsyncFunctionState *async_function_data; /* JS_CLASS_ASYNC_FUNCTION_RESOLVE, JS_CLASS_ASYNC_FUNCTION_REJECT */\n        struct JSAsyncFromSyncIteratorData *async_from_sync_iterator_data; /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */\n        struct JSAsyncGeneratorData *async_generator_data; /* JS_CLASS_ASYNC_GENERATOR */\n        struct { /* JS_CLASS_BYTECODE_FUNCTION: 12/24 bytes */\n            /* also used by JS_CLASS_GENERATOR_FUNCTION, JS_CLASS_ASYNC_FUNCTION and JS_CLASS_ASYNC_GENERATOR_FUNCTION */\n            struct JSFunctionBytecode *function_bytecode;\n            JSVarRef **var_refs;\n            JSObject *home_object; /* for 'super' access */\n        } func;\n        struct { /* JS_CLASS_C_FUNCTION: 12/20 bytes */\n            JSContext *realm;\n            JSCFunctionType c_function;\n            uint8_t length;\n            uint8_t cproto;\n            int16_t magic;\n        } cfunc;\n        /* array part for fast arrays and typed arrays */\n        struct { /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS, JS_CLASS_MAPPED_ARGUMENTS, JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */\n            union {\n                uint32_t size;          /* JS_CLASS_ARRAY */\n                struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */\n            } u1;\n            union {\n                JSValue *values;        /* JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS */\n                JSVarRef **var_refs;     /* JS_CLASS_MAPPED_ARGUMENTS */\n                void *ptr;              /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_FLOAT64_ARRAY */\n                int8_t *int8_ptr;       /* JS_CLASS_INT8_ARRAY */\n                uint8_t *uint8_ptr;     /* JS_CLASS_UINT8_ARRAY, JS_CLASS_UINT8C_ARRAY */\n                int16_t *int16_ptr;     /* JS_CLASS_INT16_ARRAY */\n                uint16_t *uint16_ptr;   /* JS_CLASS_UINT16_ARRAY */\n                int32_t *int32_ptr;     /* JS_CLASS_INT32_ARRAY */\n                uint32_t *uint32_ptr;   /* JS_CLASS_UINT32_ARRAY */\n                int64_t *int64_ptr;     /* JS_CLASS_INT64_ARRAY */\n                uint64_t *uint64_ptr;   /* JS_CLASS_UINT64_ARRAY */\n                uint16_t *fp16_ptr;     /* JS_CLASS_FLOAT16_ARRAY */\n                float *float_ptr;       /* JS_CLASS_FLOAT32_ARRAY */\n                double *double_ptr;     /* JS_CLASS_FLOAT64_ARRAY */\n            } u;\n            uint32_t count; /* <= 2^31-1. 0 for a detached typed array */\n        } array;    /* 12/20 bytes */\n        JSRegExp regexp;    /* JS_CLASS_REGEXP: 8/16 bytes */\n        JSValue object_data;    /* for JS_SetObjectData(): 8/16/16 bytes */\n        JSGlobalObject global_object;\n    } u;\n};\n\ntypedef struct JSMapRecord {\n    int ref_count; /* used during enumeration to avoid freeing the record */\n    BOOL empty : 8; /* TRUE if the record is deleted */\n    struct list_head link;\n    struct JSMapRecord *hash_next;\n    JSValue key;\n    JSValue value;\n} JSMapRecord;\n\ntypedef struct JSMapState {\n    BOOL is_weak; /* TRUE if WeakSet/WeakMap */\n    struct list_head records; /* list of JSMapRecord.link */\n    uint32_t record_count;\n    JSMapRecord **hash_table;\n    int hash_bits;\n    uint32_t hash_size; /* = 2 ^ hash_bits */\n    uint32_t record_count_threshold; /* count at which a hash table\n                                        resize is needed */\n    JSWeakRefHeader weakref_header; /* only used if is_weak = TRUE */\n} JSMapState;\n\nenum {\n    __JS_ATOM_NULL = JS_ATOM_NULL,\n#define DEF(name, str) JS_ATOM_ ## name,\n#include \"quickjs-atom.h\"\n#undef DEF\n    JS_ATOM_END,\n};\n#define JS_ATOM_LAST_KEYWORD JS_ATOM_super\n#define JS_ATOM_LAST_STRICT_KEYWORD JS_ATOM_yield\n\nstatic const char js_atom_init[] =\n#define DEF(name, str) str \"\\0\"\n#include \"quickjs-atom.h\"\n#undef DEF\n;\n\ntypedef enum OPCodeFormat {\n#define FMT(f) OP_FMT_ ## f,\n#define DEF(id, size, n_pop, n_push, f)\n#include \"quickjs-opcode.h\"\n#undef DEF\n#undef FMT\n} OPCodeFormat;\n\nenum OPCodeEnum {\n#define FMT(f)\n#define DEF(id, size, n_pop, n_push, f) OP_ ## id,\n#define def(id, size, n_pop, n_push, f)\n#include \"quickjs-opcode.h\"\n#undef def\n#undef DEF\n#undef FMT\n    OP_COUNT, /* excluding temporary opcodes */\n    /* temporary opcodes : overlap with the short opcodes */\n    OP_TEMP_START = OP_nop + 1,\n    OP___dummy = OP_TEMP_START - 1,\n#define FMT(f)\n#define DEF(id, size, n_pop, n_push, f)\n#define def(id, size, n_pop, n_push, f) OP_ ## id,\n#include \"quickjs-opcode.h\"\n#undef def\n#undef DEF\n#undef FMT\n    OP_TEMP_END,\n};\n\nstatic int JS_InitAtoms(JSRuntime *rt);\nstatic JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,\n                               int atom_type);\nstatic void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p);\nstatic void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b);\nstatic JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,\n                                  JSValueConst this_obj,\n                                  int argc, JSValueConst *argv, int flags);\nstatic JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,\n                                      JSValueConst this_obj,\n                                      int argc, JSValueConst *argv, int flags);\nstatic JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,\n                               JSValueConst this_obj, JSValueConst new_target,\n                               int argc, JSValue *argv, int flags);\nstatic JSValue JS_CallConstructorInternal(JSContext *ctx,\n                                          JSValueConst func_obj,\n                                          JSValueConst new_target,\n                                          int argc, JSValue *argv, int flags);\nstatic JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,\n                           int argc, JSValueConst *argv);\nstatic JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,\n                             int argc, JSValueConst *argv);\nstatic __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,\n                                            JSValue val, BOOL is_array_ctor);\nstatic JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,\n                             JSValueConst val, int flags, int scope_idx);\nJSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);\nstatic __maybe_unused void JS_DumpAtoms(JSRuntime *rt);\nstatic __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p);\nstatic __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt);\nstatic __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p);\nstatic __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p);\nstatic __maybe_unused void JS_DumpAtom(JSContext *ctx, const char *str, JSAtom atom);\nstatic __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val);\nstatic __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val);\nstatic __maybe_unused void JS_DumpShapes(JSRuntime *rt);\nstatic void js_dump_value_write(void *opaque, const char *buf, size_t len);\nstatic JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv, int magic);\nstatic void js_array_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_array_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);\nstatic void js_mapped_arguments_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_mapped_arguments_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);\nstatic void js_object_data_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_object_data_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);\nstatic void js_c_function_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_c_function_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);\nstatic void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_bound_function_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_bound_function_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_regexp_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_array_buffer_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_typed_array_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_typed_array_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_proxy_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_proxy_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_map_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_map_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_map_iterator_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_array_iterator_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_iterator_concat_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_iterator_concat_mark(JSRuntime *rt, JSValueConst val,\n                                    JS_MarkFunc *mark_func);\nstatic void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val,\n                                    JS_MarkFunc *mark_func);\nstatic void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val,\n                                  JS_MarkFunc *mark_func);\nstatic void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_generator_finalizer(JSRuntime *rt, JSValue obj);\nstatic void js_generator_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_global_object_finalizer(JSRuntime *rt, JSValue obj);\nstatic void js_global_object_mark(JSRuntime *rt, JSValueConst val,\n                                  JS_MarkFunc *mark_func);\nstatic void js_promise_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_promise_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\nstatic void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func);\n\n#define HINT_STRING  0\n#define HINT_NUMBER  1\n#define HINT_NONE    2\n#define HINT_FORCE_ORDINARY (1 << 4) // don't try Symbol.toPrimitive\nstatic JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint);\nstatic JSValue JS_ToStringFree(JSContext *ctx, JSValue val);\nstatic int JS_ToBoolFree(JSContext *ctx, JSValue val);\nstatic int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);\nstatic int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val);\nstatic int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val);\nstatic JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len);\nstatic JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,\n                                 JSValueConst flags);\nstatic JSValue JS_NewRegexp(JSContext *ctx, JSValue pattern, JSValue bc);\nstatic void gc_decref(JSRuntime *rt);\nstatic int JS_NewClass1(JSRuntime *rt, JSClassID class_id,\n                        const JSClassDef *class_def, JSAtom name);\n\ntypedef enum JSStrictEqModeEnum {\n    JS_EQ_STRICT,\n    JS_EQ_SAME_VALUE,\n    JS_EQ_SAME_VALUE_ZERO,\n} JSStrictEqModeEnum;\n\nstatic BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,\n                          JSStrictEqModeEnum eq_mode);\nstatic BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2);\nstatic BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2);\nstatic BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2);\nstatic JSValue JS_ToObject(JSContext *ctx, JSValueConst val);\nstatic JSValue JS_ToObjectFree(JSContext *ctx, JSValue val);\nstatic JSProperty *add_property(JSContext *ctx,\n                                JSObject *p, JSAtom prop, int prop_flags);\nstatic void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags);\nstatic int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);\nJSValue JS_ThrowOutOfMemory(JSContext *ctx);\nstatic JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);\n\nstatic int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, int throw_exception);\nstatic int JS_CreateProperty(JSContext *ctx, JSObject *p,\n                             JSAtom prop, JSValueConst val,\n                             JSValueConst getter, JSValueConst setter,\n                             int flags);\nstatic int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,\n                            int pos2, int len);\nstatic JSValue js_array_buffer_constructor3(JSContext *ctx,\n                                            JSValueConst new_target,\n                                            uint64_t len, uint64_t *max_len,\n                                            JSClassID class_id,\n                                            uint8_t *buf,\n                                            JSFreeArrayBufferDataFunc *free_func,\n                                            void *opaque, BOOL alloc_flag);\nstatic void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr);\nstatic JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);\nstatic BOOL array_buffer_is_resizable(const JSArrayBuffer *abuf);\nstatic JSValue js_typed_array_constructor(JSContext *ctx,\n                                          JSValueConst this_val,\n                                          int argc, JSValueConst *argv,\n                                          int classid);\nstatic JSValue js_typed_array_constructor_ta(JSContext *ctx,\n                                             JSValueConst new_target,\n                                             JSValueConst src_obj,\n                                             int classid, uint32_t len);\nstatic BOOL typed_array_is_oob(JSObject *p);\nstatic int js_typed_array_get_length_unsafe(JSContext *ctx, JSValueConst obj);\nstatic JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);\nstatic JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx);\nstatic JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical);\nstatic JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,\n                             BOOL is_arg);\nstatic void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);\nstatic void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s);\nstatic JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,\n                                          JSValueConst this_obj,\n                                          int argc, JSValueConst *argv,\n                                          int flags);\nstatic void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,\n                                           JS_MarkFunc *mark_func);\nstatic JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,\n                               const char *input, size_t input_len,\n                               const char *filename, int flags, int scope_idx);\nstatic void js_free_module_def(JSRuntime *rt, JSModuleDef *m);\nstatic void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,\n                               JS_MarkFunc *mark_func);\nstatic JSValue js_import_meta(JSContext *ctx);\nstatic JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options);\nstatic void free_var_ref(JSRuntime *rt, JSVarRef *var_ref);\nstatic JSValue js_new_promise_capability(JSContext *ctx,\n                                         JSValue *resolving_funcs,\n                                         JSValueConst ctor);\nstatic __exception int perform_promise_then(JSContext *ctx,\n                                            JSValueConst promise,\n                                            JSValueConst *resolve_reject,\n                                            JSValueConst *cap_resolving_funcs);\nstatic JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv, int magic);\nstatic JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv);\nstatic BOOL js_string_eq(JSContext *ctx,\n                         const JSString *p1, const JSString *p2);\nstatic int js_string_compare(JSContext *ctx,\n                             const JSString *p1, const JSString *p2);\nstatic JSValue JS_ToNumber(JSContext *ctx, JSValueConst val);\nstatic int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,\n                               JSValue prop, JSValue val, int flags);\nstatic int JS_NumberIsInteger(JSContext *ctx, JSValueConst val);\nstatic BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val);\nstatic JSValue JS_ToNumberFree(JSContext *ctx, JSValue val);\nstatic int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,\n                                     JSObject *p, JSAtom prop);\nstatic void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc);\nstatic int JS_AddIntrinsicBasicObjects(JSContext *ctx);\nstatic void js_free_shape(JSRuntime *rt, JSShape *sh);\nstatic void js_free_shape_null(JSRuntime *rt, JSShape *sh);\nstatic int js_shape_prepare_update(JSContext *ctx, JSObject *p,\n                                   JSShapeProperty **pprs);\nstatic int init_shape_hash(JSRuntime *rt);\nstatic __exception int js_get_length32(JSContext *ctx, uint32_t *pres,\n                                       JSValueConst obj);\nstatic __exception int js_get_length64(JSContext *ctx, int64_t *pres,\n                                       JSValueConst obj);\nstatic void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len);\nstatic JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,\n                               JSValueConst array_arg);\nstatic BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,\n                              JSValue **arrpp, uint32_t *countp);\nstatic JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,\n                                              JSValueConst sync_iter);\nstatic void js_c_function_data_finalizer(JSRuntime *rt, JSValue val);\nstatic void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,\n                                    JS_MarkFunc *mark_func);\nstatic JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,\n                                       JSValueConst this_val,\n                                       int argc, JSValueConst *argv, int flags);\nstatic JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val);\nstatic void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,\n                          JSGCObjectTypeEnum type);\nstatic void remove_gc_object(JSGCObjectHeader *h);\nstatic JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);\nstatic JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,\n                                 void *opaque);\nstatic JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,\n                                               JSAtom atom, void *opaque);\nstatic JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv, int is_map);\nstatic void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh);\nstatic void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);\nstatic void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh);\nstatic void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects);\nstatic JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,\n                                      JSValueConst obj, JSValueConst method);\nstatic int js_string_find_invalid_codepoint(JSString *p);\nstatic JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv);\nstatic JSValue get_date_string(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv, int magic);\nstatic JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv);\nstatic JSVarRef *js_global_object_find_uninitialized_var(JSContext *ctx, JSObject *p,\n                                                         JSAtom atom, BOOL is_lexical);\n\nstatic const JSClassExoticMethods js_arguments_exotic_methods;\nstatic const JSClassExoticMethods js_string_exotic_methods;\nstatic const JSClassExoticMethods js_proxy_exotic_methods;\nstatic const JSClassExoticMethods js_module_ns_exotic_methods;\nstatic JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;\n\nstatic void js_trigger_gc(JSRuntime *rt, size_t size)\n{\n    BOOL force_gc;\n#ifdef FORCE_GC_AT_MALLOC\n    force_gc = TRUE;\n#else\n    force_gc = ((rt->malloc_state.malloc_size + size) >\n                rt->malloc_gc_threshold);\n#endif\n    if (force_gc) {\n#ifdef DUMP_GC\n        printf(\"GC: size=%\" PRIu64 \"\\n\",\n               (uint64_t)rt->malloc_state.malloc_size);\n#endif\n        JS_RunGC(rt);\n        rt->malloc_gc_threshold = rt->malloc_state.malloc_size +\n            (rt->malloc_state.malloc_size >> 1);\n    }\n}\n\nstatic size_t js_malloc_usable_size_unknown(const void *ptr)\n{\n    return 0;\n}\n\nvoid *js_malloc_rt(JSRuntime *rt, size_t size)\n{\n    return rt->mf.js_malloc(&rt->malloc_state, size);\n}\n\nvoid js_free_rt(JSRuntime *rt, void *ptr)\n{\n    rt->mf.js_free(&rt->malloc_state, ptr);\n}\n\nvoid *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size)\n{\n    return rt->mf.js_realloc(&rt->malloc_state, ptr, size);\n}\n\nsize_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr)\n{\n    return rt->mf.js_malloc_usable_size(ptr);\n}\n\nvoid *js_mallocz_rt(JSRuntime *rt, size_t size)\n{\n    void *ptr;\n    ptr = js_malloc_rt(rt, size);\n    if (!ptr)\n        return NULL;\n    return memset(ptr, 0, size);\n}\n\n/* Throw out of memory in case of error */\nvoid *js_malloc(JSContext *ctx, size_t size)\n{\n    void *ptr;\n    ptr = js_malloc_rt(ctx->rt, size);\n    if (unlikely(!ptr)) {\n        JS_ThrowOutOfMemory(ctx);\n        return NULL;\n    }\n    return ptr;\n}\n\n/* Throw out of memory in case of error */\nvoid *js_mallocz(JSContext *ctx, size_t size)\n{\n    void *ptr;\n    ptr = js_mallocz_rt(ctx->rt, size);\n    if (unlikely(!ptr)) {\n        JS_ThrowOutOfMemory(ctx);\n        return NULL;\n    }\n    return ptr;\n}\n\nvoid js_free(JSContext *ctx, void *ptr)\n{\n    js_free_rt(ctx->rt, ptr);\n}\n\n/* Throw out of memory in case of error */\nvoid *js_realloc(JSContext *ctx, void *ptr, size_t size)\n{\n    void *ret;\n    ret = js_realloc_rt(ctx->rt, ptr, size);\n    if (unlikely(!ret && size != 0)) {\n        JS_ThrowOutOfMemory(ctx);\n        return NULL;\n    }\n    return ret;\n}\n\n/* store extra allocated size in *pslack if successful */\nvoid *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack)\n{\n    void *ret;\n    ret = js_realloc_rt(ctx->rt, ptr, size);\n    if (unlikely(!ret && size != 0)) {\n        JS_ThrowOutOfMemory(ctx);\n        return NULL;\n    }\n    if (pslack) {\n        size_t new_size = js_malloc_usable_size_rt(ctx->rt, ret);\n        *pslack = (new_size > size) ? new_size - size : 0;\n    }\n    return ret;\n}\n\nsize_t js_malloc_usable_size(JSContext *ctx, const void *ptr)\n{\n    return js_malloc_usable_size_rt(ctx->rt, ptr);\n}\n\n/* Throw out of memory exception in case of error */\nchar *js_strndup(JSContext *ctx, const char *s, size_t n)\n{\n    char *ptr;\n    ptr = js_malloc(ctx, n + 1);\n    if (ptr) {\n        memcpy(ptr, s, n);\n        ptr[n] = '\\0';\n    }\n    return ptr;\n}\n\nchar *js_strdup(JSContext *ctx, const char *str)\n{\n    return js_strndup(ctx, str, strlen(str));\n}\n\nstatic no_inline int js_realloc_array(JSContext *ctx, void **parray,\n                                      int elem_size, int *psize, int req_size)\n{\n    int new_size;\n    size_t slack;\n    void *new_array;\n    /* XXX: potential arithmetic overflow */\n    new_size = max_int(req_size, *psize * 3 / 2);\n    new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);\n    if (!new_array)\n        return -1;\n    new_size += slack / elem_size;\n    *psize = new_size;\n    *parray = new_array;\n    return 0;\n}\n\n/* resize the array and update its size if req_size > *psize */\nstatic inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,\n                                  int *psize, int req_size)\n{\n    if (unlikely(req_size > *psize))\n        return js_realloc_array(ctx, parray, elem_size, psize, req_size);\n    else\n        return 0;\n}\n\nstatic inline void js_dbuf_init(JSContext *ctx, DynBuf *s)\n{\n    dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt);\n}\n\nstatic void *js_realloc_bytecode_rt(void *opaque, void *ptr, size_t size)\n{\n    JSRuntime *rt = opaque;\n    if (size > (INT32_MAX / 2)) {\n        /* the bytecode cannot be larger than 2G. Leave some slack to \n           avoid some overflows. */\n        return NULL;\n    } else {\n        return rt->mf.js_realloc(&rt->malloc_state, ptr, size);\n    }\n}\n\nstatic inline void js_dbuf_bytecode_init(JSContext *ctx, DynBuf *s)\n{\n    dbuf_init2(s, ctx->rt, js_realloc_bytecode_rt);\n}\n\nstatic inline int is_digit(int c) {\n    return c >= '0' && c <= '9';\n}\n\nstatic inline int string_get(const JSString *p, int idx) {\n    return p->is_wide_char ? p->u.str16[idx] : p->u.str8[idx];\n}\n\ntypedef struct JSClassShortDef {\n    JSAtom class_name;\n    JSClassFinalizer *finalizer;\n    JSClassGCMark *gc_mark;\n} JSClassShortDef;\n\nstatic JSClassShortDef const js_std_class_def[] = {\n    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_OBJECT */\n    { JS_ATOM_Array, js_array_finalizer, js_array_mark },       /* JS_CLASS_ARRAY */\n    { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */\n    { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */\n    { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */\n    { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */\n    { JS_ATOM_Symbol, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_SYMBOL */\n    { JS_ATOM_Arguments, js_array_finalizer, js_array_mark },   /* JS_CLASS_ARGUMENTS */\n    { JS_ATOM_Arguments, js_mapped_arguments_finalizer, js_mapped_arguments_mark }, /* JS_CLASS_MAPPED_ARGUMENTS */\n    { JS_ATOM_Date, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_DATE */\n    { JS_ATOM_Object, NULL, NULL },                             /* JS_CLASS_MODULE_NS */\n    { JS_ATOM_Function, js_c_function_finalizer, js_c_function_mark }, /* JS_CLASS_C_FUNCTION */\n    { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */\n    { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */\n    { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */\n    { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_GENERATOR_FUNCTION */\n    { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark },      /* JS_CLASS_FOR_IN_ITERATOR */\n    { JS_ATOM_RegExp, js_regexp_finalizer, NULL },                              /* JS_CLASS_REGEXP */\n    { JS_ATOM_ArrayBuffer, js_array_buffer_finalizer, NULL },                   /* JS_CLASS_ARRAY_BUFFER */\n    { JS_ATOM_SharedArrayBuffer, js_array_buffer_finalizer, NULL },             /* JS_CLASS_SHARED_ARRAY_BUFFER */\n    { JS_ATOM_Uint8ClampedArray, js_typed_array_finalizer, js_typed_array_mark }, /* JS_CLASS_UINT8C_ARRAY */\n    { JS_ATOM_Int8Array, js_typed_array_finalizer, js_typed_array_mark },       /* JS_CLASS_INT8_ARRAY */\n    { JS_ATOM_Uint8Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_UINT8_ARRAY */\n    { JS_ATOM_Int16Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT16_ARRAY */\n    { JS_ATOM_Uint16Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT16_ARRAY */\n    { JS_ATOM_Int32Array, js_typed_array_finalizer, js_typed_array_mark },      /* JS_CLASS_INT32_ARRAY */\n    { JS_ATOM_Uint32Array, js_typed_array_finalizer, js_typed_array_mark },     /* JS_CLASS_UINT32_ARRAY */\n    { JS_ATOM_BigInt64Array, js_typed_array_finalizer, js_typed_array_mark },   /* JS_CLASS_BIG_INT64_ARRAY */\n    { JS_ATOM_BigUint64Array, js_typed_array_finalizer, js_typed_array_mark },  /* JS_CLASS_BIG_UINT64_ARRAY */\n    { JS_ATOM_Float16Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT16_ARRAY */\n    { JS_ATOM_Float32Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT32_ARRAY */\n    { JS_ATOM_Float64Array, js_typed_array_finalizer, js_typed_array_mark },    /* JS_CLASS_FLOAT64_ARRAY */\n    { JS_ATOM_DataView, js_typed_array_finalizer, js_typed_array_mark },        /* JS_CLASS_DATAVIEW */\n    { JS_ATOM_BigInt, js_object_data_finalizer, js_object_data_mark },      /* JS_CLASS_BIG_INT */\n    { JS_ATOM_Map, js_map_finalizer, js_map_mark },             /* JS_CLASS_MAP */\n    { JS_ATOM_Set, js_map_finalizer, js_map_mark },             /* JS_CLASS_SET */\n    { JS_ATOM_WeakMap, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKMAP */\n    { JS_ATOM_WeakSet, js_map_finalizer, js_map_mark },         /* JS_CLASS_WEAKSET */\n    { JS_ATOM_Iterator, NULL, NULL },                           /* JS_CLASS_ITERATOR */\n    { JS_ATOM_IteratorConcat, js_iterator_concat_finalizer, js_iterator_concat_mark }, /* JS_CLASS_ITERATOR_CONCAT */\n    { JS_ATOM_IteratorHelper, js_iterator_helper_finalizer, js_iterator_helper_mark }, /* JS_CLASS_ITERATOR_HELPER */\n    { JS_ATOM_IteratorWrap, js_iterator_wrap_finalizer, js_iterator_wrap_mark }, /* JS_CLASS_ITERATOR_WRAP */\n    { JS_ATOM_Map_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_MAP_ITERATOR */\n    { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */\n    { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */\n    { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */\n    { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */\n    { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */\n    { JS_ATOM_Object, js_global_object_finalizer, js_global_object_mark }, /* JS_CLASS_GLOBAL_OBJECT */\n};\n\nstatic int init_class_range(JSRuntime *rt, JSClassShortDef const *tab,\n                            int start, int count)\n{\n    JSClassDef cm_s, *cm = &cm_s;\n    int i, class_id;\n\n    for(i = 0; i < count; i++) {\n        class_id = i + start;\n        memset(cm, 0, sizeof(*cm));\n        cm->finalizer = tab[i].finalizer;\n        cm->gc_mark = tab[i].gc_mark;\n        if (JS_NewClass1(rt, class_id, cm, tab[i].class_name) < 0)\n            return -1;\n    }\n    return 0;\n}\n\n#if !defined(CONFIG_STACK_CHECK)\n/* no stack limitation */\nstatic inline uintptr_t js_get_stack_pointer(void)\n{\n    return 0;\n}\n\nstatic inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)\n{\n    return FALSE;\n}\n#else\n/* Note: OS and CPU dependent */\nstatic inline uintptr_t js_get_stack_pointer(void)\n{\n    return (uintptr_t)__builtin_frame_address(0);\n}\n\nstatic inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)\n{\n    uintptr_t sp;\n    sp = js_get_stack_pointer() - alloca_size;\n    return unlikely(sp < rt->stack_limit);\n}\n#endif\n\nJSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)\n{\n    JSRuntime *rt;\n    JSMallocState ms;\n\n    memset(&ms, 0, sizeof(ms));\n    ms.opaque = opaque;\n    ms.malloc_limit = -1;\n\n    rt = mf->js_malloc(&ms, sizeof(JSRuntime));\n    if (!rt)\n        return NULL;\n    memset(rt, 0, sizeof(*rt));\n    rt->mf = *mf;\n    if (!rt->mf.js_malloc_usable_size) {\n        /* use dummy function if none provided */\n        rt->mf.js_malloc_usable_size = js_malloc_usable_size_unknown;\n    }\n    rt->malloc_state = ms;\n    rt->malloc_gc_threshold = 256 * 1024;\n\n    init_list_head(&rt->context_list);\n    init_list_head(&rt->gc_obj_list);\n    init_list_head(&rt->gc_zero_ref_count_list);\n    rt->gc_phase = JS_GC_PHASE_NONE;\n    init_list_head(&rt->weakref_list);\n\n#ifdef DUMP_LEAKS\n    init_list_head(&rt->string_list);\n#endif\n    init_list_head(&rt->job_list);\n\n    if (JS_InitAtoms(rt))\n        goto fail;\n\n    /* create the object, array and function classes */\n    if (init_class_range(rt, js_std_class_def, JS_CLASS_OBJECT,\n                         countof(js_std_class_def)) < 0)\n        goto fail;\n    rt->class_array[JS_CLASS_ARGUMENTS].exotic = &js_arguments_exotic_methods;\n    rt->class_array[JS_CLASS_MAPPED_ARGUMENTS].exotic = &js_arguments_exotic_methods;\n    rt->class_array[JS_CLASS_STRING].exotic = &js_string_exotic_methods;\n    rt->class_array[JS_CLASS_MODULE_NS].exotic = &js_module_ns_exotic_methods;\n\n    rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;\n    rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_c_function_data_call;\n    rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;\n    rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_generator_function_call;\n    if (init_shape_hash(rt))\n        goto fail;\n\n    rt->stack_size = JS_DEFAULT_STACK_SIZE;\n    JS_UpdateStackTop(rt);\n\n    rt->current_exception = JS_UNINITIALIZED;\n\n    return rt;\n fail:\n    JS_FreeRuntime(rt);\n    return NULL;\n}\n\nvoid *JS_GetRuntimeOpaque(JSRuntime *rt)\n{\n    return rt->user_opaque;\n}\n\nvoid JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)\n{\n    rt->user_opaque = opaque;\n}\n\n/* default memory allocation functions with memory limitation */\nstatic size_t js_def_malloc_usable_size(const void *ptr)\n{\n#if defined(__APPLE__)\n    return malloc_size(ptr);\n#elif defined(_WIN32)\n    return _msize((void *)ptr);\n#elif defined(EMSCRIPTEN)\n    return 0;\n#elif defined(__linux__) || defined(__GLIBC__)\n    return malloc_usable_size((void *)ptr);\n#else\n    /* change this to `return 0;` if compilation fails */\n    return malloc_usable_size((void *)ptr);\n#endif\n}\n\nstatic void *js_def_malloc(JSMallocState *s, size_t size)\n{\n    void *ptr;\n\n    /* Do not allocate zero bytes: behavior is platform dependent */\n    assert(size != 0);\n\n    if (unlikely(s->malloc_size + size > s->malloc_limit))\n        return NULL;\n\n    ptr = malloc(size);\n    if (!ptr)\n        return NULL;\n\n    s->malloc_count++;\n    s->malloc_size += js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;\n    return ptr;\n}\n\nstatic void js_def_free(JSMallocState *s, void *ptr)\n{\n    if (!ptr)\n        return;\n\n    s->malloc_count--;\n    s->malloc_size -= js_def_malloc_usable_size(ptr) + MALLOC_OVERHEAD;\n    free(ptr);\n}\n\nstatic void *js_def_realloc(JSMallocState *s, void *ptr, size_t size)\n{\n    size_t old_size;\n\n    if (!ptr) {\n        if (size == 0)\n            return NULL;\n        return js_def_malloc(s, size);\n    }\n    old_size = js_def_malloc_usable_size(ptr);\n    if (size == 0) {\n        s->malloc_count--;\n        s->malloc_size -= old_size + MALLOC_OVERHEAD;\n        free(ptr);\n        return NULL;\n    }\n    if (s->malloc_size + size - old_size > s->malloc_limit)\n        return NULL;\n\n    ptr = realloc(ptr, size);\n    if (!ptr)\n        return NULL;\n\n    s->malloc_size += js_def_malloc_usable_size(ptr) - old_size;\n    return ptr;\n}\n\nstatic const JSMallocFunctions def_malloc_funcs = {\n    js_def_malloc,\n    js_def_free,\n    js_def_realloc,\n    js_def_malloc_usable_size,\n};\n\nJSRuntime *JS_NewRuntime(void)\n{\n    return JS_NewRuntime2(&def_malloc_funcs, NULL);\n}\n\nvoid JS_SetMemoryLimit(JSRuntime *rt, size_t limit)\n{\n    rt->malloc_state.malloc_limit = limit;\n}\n\n/* use -1 to disable automatic GC */\nvoid JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold)\n{\n    rt->malloc_gc_threshold = gc_threshold;\n}\n\n#define malloc(s) malloc_is_forbidden(s)\n#define free(p) free_is_forbidden(p)\n#define realloc(p,s) realloc_is_forbidden(p,s)\n\nvoid JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque)\n{\n    rt->interrupt_handler = cb;\n    rt->interrupt_opaque = opaque;\n}\n\nvoid JS_SetCanBlock(JSRuntime *rt, BOOL can_block)\n{\n    rt->can_block = can_block;\n}\n\nvoid JS_SetSharedArrayBufferFunctions(JSRuntime *rt,\n                                      const JSSharedArrayBufferFunctions *sf)\n{\n    rt->sab_funcs = *sf;\n}\n\nvoid JS_SetStripInfo(JSRuntime *rt, int flags)\n{\n    rt->strip_flags = flags;\n}\n\nint JS_GetStripInfo(JSRuntime *rt)\n{\n    return rt->strip_flags;\n}\n\n/* return 0 if OK, < 0 if exception */\nint JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,\n                  int argc, JSValueConst *argv)\n{\n    JSRuntime *rt = ctx->rt;\n    JSJobEntry *e;\n    int i;\n\n    e = js_malloc(ctx, sizeof(*e) + argc * sizeof(JSValue));\n    if (!e)\n        return -1;\n    e->realm = JS_DupContext(ctx);\n    e->job_func = job_func;\n    e->argc = argc;\n    for(i = 0; i < argc; i++) {\n        e->argv[i] = JS_DupValue(ctx, argv[i]);\n    }\n    list_add_tail(&e->link, &rt->job_list);\n    return 0;\n}\n\nBOOL JS_IsJobPending(JSRuntime *rt)\n{\n    return !list_empty(&rt->job_list);\n}\n\n/* return < 0 if exception, 0 if no job pending, 1 if a job was\n   executed successfully. The context of the job is stored in '*pctx'\n   if pctx != NULL. It may be NULL if the context was already\n   destroyed or if no job was pending. The 'pctx' parameter is now\n   absolete. */\nint JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx)\n{\n    JSContext *ctx;\n    JSJobEntry *e;\n    JSValue res;\n    int i, ret;\n\n    if (list_empty(&rt->job_list)) {\n        if (pctx)\n            *pctx = NULL;\n        return 0;\n    }\n\n    /* get the first pending job and execute it */\n    e = list_entry(rt->job_list.next, JSJobEntry, link);\n    list_del(&e->link);\n    ctx = e->realm;\n    res = e->job_func(ctx, e->argc, (JSValueConst *)e->argv);\n    for(i = 0; i < e->argc; i++)\n        JS_FreeValue(ctx, e->argv[i]);\n    if (JS_IsException(res))\n        ret = -1;\n    else\n        ret = 1;\n    JS_FreeValue(ctx, res);\n    js_free(ctx, e);\n    if (pctx) {\n        if (ctx->header.ref_count > 1)\n            *pctx = ctx;\n        else\n            *pctx = NULL;\n    }\n    JS_FreeContext(ctx);\n    return ret;\n}\n\nstatic inline uint32_t atom_get_free(const JSAtomStruct *p)\n{\n    return (uintptr_t)p >> 1;\n}\n\nstatic inline BOOL atom_is_free(const JSAtomStruct *p)\n{\n    return (uintptr_t)p & 1;\n}\n\nstatic inline JSAtomStruct *atom_set_free(uint32_t v)\n{\n    return (JSAtomStruct *)(((uintptr_t)v << 1) | 1);\n}\n\n/* Note: the string contents are uninitialized */\nstatic JSString *js_alloc_string_rt(JSRuntime *rt, int max_len, int is_wide_char)\n{\n    JSString *str;\n    str = js_malloc_rt(rt, sizeof(JSString) + (max_len << is_wide_char) + 1 - is_wide_char);\n    if (unlikely(!str))\n        return NULL;\n    str->header.ref_count = 1;\n    str->is_wide_char = is_wide_char;\n    str->len = max_len;\n    str->atom_type = 0;\n    str->hash = 0;          /* optional but costless */\n    str->hash_next = 0;     /* optional */\n#ifdef DUMP_LEAKS\n    list_add_tail(&str->link, &rt->string_list);\n#endif\n    return str;\n}\n\nstatic JSString *js_alloc_string(JSContext *ctx, int max_len, int is_wide_char)\n{\n    JSString *p;\n    p = js_alloc_string_rt(ctx->rt, max_len, is_wide_char);\n    if (unlikely(!p)) {\n        JS_ThrowOutOfMemory(ctx);\n        return NULL;\n    }\n    return p;\n}\n\n/* same as JS_FreeValueRT() but faster */\nstatic inline void js_free_string(JSRuntime *rt, JSString *str)\n{\n    if (--str->header.ref_count <= 0) {\n        if (str->atom_type) {\n            JS_FreeAtomStruct(rt, str);\n        } else {\n#ifdef DUMP_LEAKS\n            list_del(&str->link);\n#endif\n            js_free_rt(rt, str);\n        }\n    }\n}\n\nvoid JS_SetRuntimeInfo(JSRuntime *rt, const char *s)\n{\n    if (rt)\n        rt->rt_info = s;\n}\n\nvoid JS_FreeRuntime(JSRuntime *rt)\n{\n    struct list_head *el, *el1;\n    int i;\n\n    JS_FreeValueRT(rt, rt->current_exception);\n\n    list_for_each_safe(el, el1, &rt->job_list) {\n        JSJobEntry *e = list_entry(el, JSJobEntry, link);\n        for(i = 0; i < e->argc; i++)\n            JS_FreeValueRT(rt, e->argv[i]);\n        JS_FreeContext(e->realm);\n        js_free_rt(rt, e);\n    }\n    init_list_head(&rt->job_list);\n\n    /* don't remove the weak objects to avoid create new jobs with\n       FinalizationRegistry */\n    JS_RunGCInternal(rt, FALSE);\n\n#ifdef DUMP_LEAKS\n    /* leaking objects */\n    {\n        BOOL header_done;\n        JSGCObjectHeader *p;\n        int count;\n\n        /* remove the internal refcounts to display only the object\n           referenced externally */\n        list_for_each(el, &rt->gc_obj_list) {\n            p = list_entry(el, JSGCObjectHeader, link);\n            p->mark = 0;\n        }\n        gc_decref(rt);\n\n        header_done = FALSE;\n        list_for_each(el, &rt->gc_obj_list) {\n            p = list_entry(el, JSGCObjectHeader, link);\n            if (p->ref_count != 0) {\n                if (!header_done) {\n                    printf(\"Object leaks:\\n\");\n                    JS_DumpObjectHeader(rt);\n                    header_done = TRUE;\n                }\n                JS_DumpGCObject(rt, p);\n            }\n        }\n\n        count = 0;\n        list_for_each(el, &rt->gc_obj_list) {\n            p = list_entry(el, JSGCObjectHeader, link);\n            if (p->ref_count == 0) {\n                count++;\n            }\n        }\n        if (count != 0)\n            printf(\"Secondary object leaks: %d\\n\", count);\n    }\n#endif\n    assert(list_empty(&rt->gc_obj_list));\n    assert(list_empty(&rt->weakref_list));\n\n    /* free the classes */\n    for(i = 0; i < rt->class_count; i++) {\n        JSClass *cl = &rt->class_array[i];\n        if (cl->class_id != 0) {\n            JS_FreeAtomRT(rt, cl->class_name);\n        }\n    }\n    js_free_rt(rt, rt->class_array);\n\n#ifdef DUMP_LEAKS\n    /* only the atoms defined in JS_InitAtoms() should be left */\n    {\n        BOOL header_done = FALSE;\n\n        for(i = 0; i < rt->atom_size; i++) {\n            JSAtomStruct *p = rt->atom_array[i];\n            if (!atom_is_free(p) /* && p->str*/) {\n                if (i >= JS_ATOM_END || p->header.ref_count != 1) {\n                    if (!header_done) {\n                        header_done = TRUE;\n                        if (rt->rt_info) {\n                            printf(\"%s:1: atom leakage:\", rt->rt_info);\n                        } else {\n                            printf(\"Atom leaks:\\n\"\n                                   \"    %6s %6s %s\\n\",\n                                   \"ID\", \"REFCNT\", \"NAME\");\n                        }\n                    }\n                    if (rt->rt_info) {\n                        printf(\" \");\n                    } else {\n                        printf(\"    %6u %6u \", i, p->header.ref_count);\n                    }\n                    switch (p->atom_type) {\n                    case JS_ATOM_TYPE_STRING:\n                        JS_DumpString(rt, p);\n                        break;\n                    case JS_ATOM_TYPE_GLOBAL_SYMBOL:\n                        printf(\"Symbol.for(\");\n                        JS_DumpString(rt, p);\n                        printf(\")\");\n                        break;\n                    case JS_ATOM_TYPE_SYMBOL:\n                        if (p->hash != JS_ATOM_HASH_PRIVATE) {\n                            printf(\"Symbol(\");\n                            JS_DumpString(rt, p);\n                            printf(\")\");\n                        } else {\n                            printf(\"Private(\");\n                            JS_DumpString(rt, p);\n                            printf(\")\");\n                        }\n                        break;\n                    }\n                    if (rt->rt_info) {\n                        printf(\":%u\", p->header.ref_count);\n                    } else {\n                        printf(\"\\n\");\n                    }\n                }\n            }\n        }\n        if (rt->rt_info && header_done)\n            printf(\"\\n\");\n    }\n#endif\n\n    /* free the atoms */\n    for(i = 0; i < rt->atom_size; i++) {\n        JSAtomStruct *p = rt->atom_array[i];\n        if (!atom_is_free(p)) {\n#ifdef DUMP_LEAKS\n            list_del(&p->link);\n#endif\n            js_free_rt(rt, p);\n        }\n    }\n    js_free_rt(rt, rt->atom_array);\n    js_free_rt(rt, rt->atom_hash);\n    js_free_rt(rt, rt->shape_hash);\n#ifdef DUMP_LEAKS\n    if (!list_empty(&rt->string_list)) {\n        if (rt->rt_info) {\n            printf(\"%s:1: string leakage:\", rt->rt_info);\n        } else {\n            printf(\"String leaks:\\n\"\n                   \"    %6s %s\\n\",\n                   \"REFCNT\", \"VALUE\");\n        }\n        list_for_each_safe(el, el1, &rt->string_list) {\n            JSString *str = list_entry(el, JSString, link);\n            if (rt->rt_info) {\n                printf(\" \");\n            } else {\n                printf(\"    %6u \", str->header.ref_count);\n            }\n            JS_DumpString(rt, str);\n            if (rt->rt_info) {\n                printf(\":%u\", str->header.ref_count);\n            } else {\n                printf(\"\\n\");\n            }\n            list_del(&str->link);\n            js_free_rt(rt, str);\n        }\n        if (rt->rt_info)\n            printf(\"\\n\");\n    }\n    {\n        JSMallocState *s = &rt->malloc_state;\n        if (s->malloc_count > 1) {\n            if (rt->rt_info)\n                printf(\"%s:1: \", rt->rt_info);\n            printf(\"Memory leak: %\"PRIu64\" bytes lost in %\"PRIu64\" block%s\\n\",\n                   (uint64_t)(s->malloc_size - sizeof(JSRuntime)),\n                   (uint64_t)(s->malloc_count - 1), &\"s\"[s->malloc_count == 2]);\n        }\n    }\n#endif\n\n    {\n        JSMallocState ms = rt->malloc_state;\n        rt->mf.js_free(&ms, rt);\n    }\n}\n\nJSContext *JS_NewContextRaw(JSRuntime *rt)\n{\n    JSContext *ctx;\n    int i;\n\n    ctx = js_mallocz_rt(rt, sizeof(JSContext));\n    if (!ctx)\n        return NULL;\n    ctx->header.ref_count = 1;\n    add_gc_object(rt, &ctx->header, JS_GC_OBJ_TYPE_JS_CONTEXT);\n\n    ctx->class_proto = js_malloc_rt(rt, sizeof(ctx->class_proto[0]) *\n                                    rt->class_count);\n    if (!ctx->class_proto) {\n        js_free_rt(rt, ctx);\n        return NULL;\n    }\n    ctx->rt = rt;\n    list_add_tail(&ctx->link, &rt->context_list);\n    for(i = 0; i < rt->class_count; i++)\n        ctx->class_proto[i] = JS_NULL;\n    ctx->array_ctor = JS_NULL;\n    ctx->iterator_ctor = JS_NULL;\n    ctx->regexp_ctor = JS_NULL;\n    ctx->promise_ctor = JS_NULL;\n    init_list_head(&ctx->loaded_modules);\n\n    if (JS_AddIntrinsicBasicObjects(ctx)) {\n        JS_FreeContext(ctx);\n        return NULL;\n    }\n    return ctx;\n}\n\nJSContext *JS_NewContext(JSRuntime *rt)\n{\n    JSContext *ctx;\n\n    ctx = JS_NewContextRaw(rt);\n    if (!ctx)\n        return NULL;\n\n    if (JS_AddIntrinsicBaseObjects(ctx) ||\n        JS_AddIntrinsicDate(ctx) ||\n        JS_AddIntrinsicEval(ctx) ||\n        JS_AddIntrinsicStringNormalize(ctx) ||\n        JS_AddIntrinsicRegExp(ctx) ||\n        JS_AddIntrinsicJSON(ctx) ||\n        JS_AddIntrinsicProxy(ctx) ||\n        JS_AddIntrinsicMapSet(ctx) ||\n        JS_AddIntrinsicTypedArrays(ctx) ||\n        JS_AddIntrinsicPromise(ctx) ||\n        JS_AddIntrinsicWeakRef(ctx)) {\n        JS_FreeContext(ctx);\n        return NULL;\n    }\n    return ctx;\n}\n\nvoid *JS_GetContextOpaque(JSContext *ctx)\n{\n    return ctx->user_opaque;\n}\n\nvoid JS_SetContextOpaque(JSContext *ctx, void *opaque)\n{\n    ctx->user_opaque = opaque;\n}\n\n/* set the new value and free the old value after (freeing the value\n   can reallocate the object data) */\nstatic inline void set_value(JSContext *ctx, JSValue *pval, JSValue new_val)\n{\n    JSValue old_val;\n    old_val = *pval;\n    *pval = new_val;\n    JS_FreeValue(ctx, old_val);\n}\n\nvoid JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj)\n{\n    JSRuntime *rt = ctx->rt;\n    assert(class_id < rt->class_count);\n    set_value(ctx, &ctx->class_proto[class_id], obj);\n}\n\nJSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id)\n{\n    JSRuntime *rt = ctx->rt;\n    assert(class_id < rt->class_count);\n    return JS_DupValue(ctx, ctx->class_proto[class_id]);\n}\n\ntypedef enum JSFreeModuleEnum {\n    JS_FREE_MODULE_ALL,\n    JS_FREE_MODULE_NOT_RESOLVED,\n} JSFreeModuleEnum;\n\n/* XXX: would be more efficient with separate module lists */\nstatic void js_free_modules(JSContext *ctx, JSFreeModuleEnum flag)\n{\n    struct list_head *el, *el1;\n    list_for_each_safe(el, el1, &ctx->loaded_modules) {\n        JSModuleDef *m = list_entry(el, JSModuleDef, link);\n        if (flag == JS_FREE_MODULE_ALL ||\n            (flag == JS_FREE_MODULE_NOT_RESOLVED && !m->resolved)) {\n            /* warning: the module may be referenced elsewhere. It\n               could be simpler to use an array instead of a list for\n               'ctx->loaded_modules' */\n            list_del(&m->link);\n            m->link.prev = NULL;\n            m->link.next = NULL;\n            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));\n        }\n    }\n}\n\nJSContext *JS_DupContext(JSContext *ctx)\n{\n    ctx->header.ref_count++;\n    return ctx;\n}\n\n/* used by the GC */\nstatic void JS_MarkContext(JSRuntime *rt, JSContext *ctx,\n                           JS_MarkFunc *mark_func)\n{\n    int i;\n    struct list_head *el;\n\n    list_for_each(el, &ctx->loaded_modules) {\n        JSModuleDef *m = list_entry(el, JSModuleDef, link);\n        JS_MarkValue(rt, JS_MKPTR(JS_TAG_MODULE, m), mark_func);\n    }\n\n    JS_MarkValue(rt, ctx->global_obj, mark_func);\n    JS_MarkValue(rt, ctx->global_var_obj, mark_func);\n\n    JS_MarkValue(rt, ctx->throw_type_error, mark_func);\n    JS_MarkValue(rt, ctx->eval_obj, mark_func);\n\n    JS_MarkValue(rt, ctx->array_proto_values, mark_func);\n    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {\n        JS_MarkValue(rt, ctx->native_error_proto[i], mark_func);\n    }\n    for(i = 0; i < rt->class_count; i++) {\n        JS_MarkValue(rt, ctx->class_proto[i], mark_func);\n    }\n    JS_MarkValue(rt, ctx->iterator_ctor, mark_func);\n    JS_MarkValue(rt, ctx->async_iterator_proto, mark_func);\n    JS_MarkValue(rt, ctx->promise_ctor, mark_func);\n    JS_MarkValue(rt, ctx->array_ctor, mark_func);\n    JS_MarkValue(rt, ctx->regexp_ctor, mark_func);\n    JS_MarkValue(rt, ctx->function_ctor, mark_func);\n    JS_MarkValue(rt, ctx->function_proto, mark_func);\n\n    if (ctx->array_shape)\n        mark_func(rt, &ctx->array_shape->header);\n\n    if (ctx->arguments_shape)\n        mark_func(rt, &ctx->arguments_shape->header);\n\n    if (ctx->mapped_arguments_shape)\n        mark_func(rt, &ctx->mapped_arguments_shape->header);\n\n    if (ctx->regexp_shape)\n        mark_func(rt, &ctx->regexp_shape->header);\n\n    if (ctx->regexp_result_shape)\n        mark_func(rt, &ctx->regexp_result_shape->header);\n}\n\nvoid JS_FreeContext(JSContext *ctx)\n{\n    JSRuntime *rt = ctx->rt;\n    int i;\n\n    if (--ctx->header.ref_count > 0)\n        return;\n    assert(ctx->header.ref_count == 0);\n\n#ifdef DUMP_ATOMS\n    JS_DumpAtoms(ctx->rt);\n#endif\n#ifdef DUMP_SHAPES\n    JS_DumpShapes(ctx->rt);\n#endif\n#ifdef DUMP_OBJECTS\n    {\n        struct list_head *el;\n        JSGCObjectHeader *p;\n        printf(\"JSObjects: {\\n\");\n        JS_DumpObjectHeader(ctx->rt);\n        list_for_each(el, &rt->gc_obj_list) {\n            p = list_entry(el, JSGCObjectHeader, link);\n            JS_DumpGCObject(rt, p);\n        }\n        printf(\"}\\n\");\n    }\n#endif\n#ifdef DUMP_MEM\n    {\n        JSMemoryUsage stats;\n        JS_ComputeMemoryUsage(rt, &stats);\n        JS_DumpMemoryUsage(stdout, &stats, rt);\n    }\n#endif\n\n    js_free_modules(ctx, JS_FREE_MODULE_ALL);\n\n    JS_FreeValue(ctx, ctx->global_obj);\n    JS_FreeValue(ctx, ctx->global_var_obj);\n\n    JS_FreeValue(ctx, ctx->throw_type_error);\n    JS_FreeValue(ctx, ctx->eval_obj);\n\n    JS_FreeValue(ctx, ctx->array_proto_values);\n    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {\n        JS_FreeValue(ctx, ctx->native_error_proto[i]);\n    }\n    for(i = 0; i < rt->class_count; i++) {\n        JS_FreeValue(ctx, ctx->class_proto[i]);\n    }\n    js_free_rt(rt, ctx->class_proto);\n    JS_FreeValue(ctx, ctx->iterator_ctor);\n    JS_FreeValue(ctx, ctx->async_iterator_proto);\n    JS_FreeValue(ctx, ctx->promise_ctor);\n    JS_FreeValue(ctx, ctx->array_ctor);\n    JS_FreeValue(ctx, ctx->regexp_ctor);\n    JS_FreeValue(ctx, ctx->function_ctor);\n    JS_FreeValue(ctx, ctx->function_proto);\n\n    js_free_shape_null(ctx->rt, ctx->array_shape);\n    js_free_shape_null(ctx->rt, ctx->arguments_shape);\n    js_free_shape_null(ctx->rt, ctx->mapped_arguments_shape);\n    js_free_shape_null(ctx->rt, ctx->regexp_shape);\n    js_free_shape_null(ctx->rt, ctx->regexp_result_shape);\n\n    list_del(&ctx->link);\n    remove_gc_object(&ctx->header);\n    js_free_rt(ctx->rt, ctx);\n}\n\nJSRuntime *JS_GetRuntime(JSContext *ctx)\n{\n    return ctx->rt;\n}\n\nstatic void update_stack_limit(JSRuntime *rt)\n{\n    if (rt->stack_size == 0) {\n        rt->stack_limit = 0; /* no limit */\n    } else {\n        rt->stack_limit = rt->stack_top - rt->stack_size;\n    }\n}\n\nvoid JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)\n{\n    rt->stack_size = stack_size;\n    update_stack_limit(rt);\n}\n\nvoid JS_UpdateStackTop(JSRuntime *rt)\n{\n    rt->stack_top = js_get_stack_pointer();\n    update_stack_limit(rt);\n}\n\nstatic inline BOOL is_strict_mode(JSContext *ctx)\n{\n    JSStackFrame *sf = ctx->rt->current_stack_frame;\n    return (sf && (sf->js_mode & JS_MODE_STRICT));\n}\n\n/* JSAtom support */\n\n#define JS_ATOM_TAG_INT (1U << 31)\n#define JS_ATOM_MAX_INT (JS_ATOM_TAG_INT - 1)\n#define JS_ATOM_MAX     ((1U << 30) - 1)\n\n/* return the max count from the hash size */\n#define JS_ATOM_COUNT_RESIZE(n) ((n) * 2)\n\nstatic inline BOOL __JS_AtomIsConst(JSAtom v)\n{\n#if defined(DUMP_LEAKS) && DUMP_LEAKS > 1\n        return (int32_t)v <= 0;\n#else\n        return (int32_t)v < JS_ATOM_END;\n#endif\n}\n\nstatic inline BOOL __JS_AtomIsTaggedInt(JSAtom v)\n{\n    return (v & JS_ATOM_TAG_INT) != 0;\n}\n\nstatic inline JSAtom __JS_AtomFromUInt32(uint32_t v)\n{\n    return v | JS_ATOM_TAG_INT;\n}\n\nstatic inline uint32_t __JS_AtomToUInt32(JSAtom atom)\n{\n    return atom & ~JS_ATOM_TAG_INT;\n}\n\nstatic inline int is_num(int c)\n{\n    return c >= '0' && c <= '9';\n}\n\n/* return TRUE if the string is a number n with 0 <= n <= 2^32-1 */\nstatic inline BOOL is_num_string(uint32_t *pval, const JSString *p)\n{\n    uint32_t n;\n    uint64_t n64;\n    int c, i, len;\n\n    len = p->len;\n    if (len == 0 || len > 10)\n        return FALSE;\n    c = string_get(p, 0);\n    if (is_num(c)) {\n        if (c == '0') {\n            if (len != 1)\n                return FALSE;\n            n = 0;\n        } else {\n            n = c - '0';\n            for(i = 1; i < len; i++) {\n                c = string_get(p, i);\n                if (!is_num(c))\n                    return FALSE;\n                n64 = (uint64_t)n * 10 + (c - '0');\n                if ((n64 >> 32) != 0)\n                    return FALSE;\n                n = n64;\n            }\n        }\n        *pval = n;\n        return TRUE;\n    } else {\n        return FALSE;\n    }\n}\n\n/* XXX: could use faster version ? */\nstatic inline uint32_t hash_string8(const uint8_t *str, size_t len, uint32_t h)\n{\n    size_t i;\n\n    for(i = 0; i < len; i++)\n        h = h * 263 + str[i];\n    return h;\n}\n\nstatic inline uint32_t hash_string16(const uint16_t *str,\n                                     size_t len, uint32_t h)\n{\n    size_t i;\n\n    for(i = 0; i < len; i++)\n        h = h * 263 + str[i];\n    return h;\n}\n\nstatic uint32_t hash_string(const JSString *str, uint32_t h)\n{\n    if (str->is_wide_char)\n        h = hash_string16(str->u.str16, str->len, h);\n    else\n        h = hash_string8(str->u.str8, str->len, h);\n    return h;\n}\n\nstatic uint32_t hash_string_rope(JSValueConst val, uint32_t h)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {\n        return hash_string(JS_VALUE_GET_STRING(val), h);\n    } else {\n        JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);\n        h = hash_string_rope(r->left, h);\n        return hash_string_rope(r->right, h);\n    }\n}\n\nstatic __maybe_unused void JS_DumpChar(FILE *fo, int c, int sep)\n{\n    if (c == sep || c == '\\\\') {\n        fputc('\\\\', fo);\n        fputc(c, fo);\n    } else if (c >= ' ' && c <= 126) {\n        fputc(c, fo);\n    } else if (c == '\\n') {\n        fputc('\\\\', fo);\n        fputc('n', fo);\n    } else {\n        fprintf(fo, \"\\\\u%04x\", c);\n    }\n}\n\nstatic __maybe_unused void JS_DumpString(JSRuntime *rt, const JSString *p)\n{\n    int i, sep;\n\n    if (p == NULL) {\n        printf(\"<null>\");\n        return;\n    }\n    printf(\"%d\", p->header.ref_count);\n    sep = (p->header.ref_count == 1) ? '\\\"' : '\\'';\n    putchar(sep);\n    for(i = 0; i < p->len; i++) {\n        JS_DumpChar(stdout, string_get(p, i), sep);\n    }\n    putchar(sep);\n}\n\nstatic __maybe_unused void JS_DumpAtoms(JSRuntime *rt)\n{\n    JSAtomStruct *p;\n    int h, i;\n    /* This only dumps hashed atoms, not JS_ATOM_TYPE_SYMBOL atoms */\n    printf(\"JSAtom count=%d size=%d hash_size=%d:\\n\",\n           rt->atom_count, rt->atom_size, rt->atom_hash_size);\n    printf(\"JSAtom hash table: {\\n\");\n    for(i = 0; i < rt->atom_hash_size; i++) {\n        h = rt->atom_hash[i];\n        if (h) {\n            printf(\"  %d:\", i);\n            while (h) {\n                p = rt->atom_array[h];\n                printf(\" \");\n                JS_DumpString(rt, p);\n                h = p->hash_next;\n            }\n            printf(\"\\n\");\n        }\n    }\n    printf(\"}\\n\");\n    printf(\"JSAtom table: {\\n\");\n    for(i = 0; i < rt->atom_size; i++) {\n        p = rt->atom_array[i];\n        if (!atom_is_free(p)) {\n            printf(\"  %d: { %d %08x \", i, p->atom_type, p->hash);\n            if (!(p->len == 0 && p->is_wide_char != 0))\n                JS_DumpString(rt, p);\n            printf(\" %d }\\n\", p->hash_next);\n        }\n    }\n    printf(\"}\\n\");\n}\n\nstatic int JS_ResizeAtomHash(JSRuntime *rt, int new_hash_size)\n{\n    JSAtomStruct *p;\n    uint32_t new_hash_mask, h, i, hash_next1, j, *new_hash;\n\n    assert((new_hash_size & (new_hash_size - 1)) == 0); /* power of two */\n    new_hash_mask = new_hash_size - 1;\n    new_hash = js_mallocz_rt(rt, sizeof(rt->atom_hash[0]) * new_hash_size);\n    if (!new_hash)\n        return -1;\n    for(i = 0; i < rt->atom_hash_size; i++) {\n        h = rt->atom_hash[i];\n        while (h != 0) {\n            p = rt->atom_array[h];\n            hash_next1 = p->hash_next;\n            /* add in new hash table */\n            j = p->hash & new_hash_mask;\n            p->hash_next = new_hash[j];\n            new_hash[j] = h;\n            h = hash_next1;\n        }\n    }\n    js_free_rt(rt, rt->atom_hash);\n    rt->atom_hash = new_hash;\n    rt->atom_hash_size = new_hash_size;\n    rt->atom_count_resize = JS_ATOM_COUNT_RESIZE(new_hash_size);\n    //    JS_DumpAtoms(rt);\n    return 0;\n}\n\nstatic int JS_InitAtoms(JSRuntime *rt)\n{\n    int i, len, atom_type;\n    const char *p;\n\n    rt->atom_hash_size = 0;\n    rt->atom_hash = NULL;\n    rt->atom_count = 0;\n    rt->atom_size = 0;\n    rt->atom_free_index = 0;\n    if (JS_ResizeAtomHash(rt, 512))     /* there are at least 504 predefined atoms */\n        return -1;\n\n    p = js_atom_init;\n    for(i = 1; i < JS_ATOM_END; i++) {\n        if (i == JS_ATOM_Private_brand)\n            atom_type = JS_ATOM_TYPE_PRIVATE;\n        else if (i >= JS_ATOM_Symbol_toPrimitive)\n            atom_type = JS_ATOM_TYPE_SYMBOL;\n        else\n            atom_type = JS_ATOM_TYPE_STRING;\n        len = strlen(p);\n        if (__JS_NewAtomInit(rt, p, len, atom_type) == JS_ATOM_NULL)\n            return -1;\n        p = p + len + 1;\n    }\n    return 0;\n}\n\nstatic JSAtom JS_DupAtomRT(JSRuntime *rt, JSAtom v)\n{\n    JSAtomStruct *p;\n\n    if (!__JS_AtomIsConst(v)) {\n        p = rt->atom_array[v];\n        p->header.ref_count++;\n    }\n    return v;\n}\n\nJSAtom JS_DupAtom(JSContext *ctx, JSAtom v)\n{\n    JSRuntime *rt;\n    JSAtomStruct *p;\n\n    if (!__JS_AtomIsConst(v)) {\n        rt = ctx->rt;\n        p = rt->atom_array[v];\n        p->header.ref_count++;\n    }\n    return v;\n}\n\nstatic JSAtomKindEnum JS_AtomGetKind(JSContext *ctx, JSAtom v)\n{\n    JSRuntime *rt;\n    JSAtomStruct *p;\n\n    rt = ctx->rt;\n    if (__JS_AtomIsTaggedInt(v))\n        return JS_ATOM_KIND_STRING;\n    p = rt->atom_array[v];\n    switch(p->atom_type) {\n    case JS_ATOM_TYPE_STRING:\n        return JS_ATOM_KIND_STRING;\n    case JS_ATOM_TYPE_GLOBAL_SYMBOL:\n        return JS_ATOM_KIND_SYMBOL;\n    case JS_ATOM_TYPE_SYMBOL:\n        if (p->hash == JS_ATOM_HASH_PRIVATE)\n            return JS_ATOM_KIND_PRIVATE;\n        else\n            return JS_ATOM_KIND_SYMBOL;\n    default:\n        abort();\n    }\n}\n\nstatic BOOL JS_AtomIsString(JSContext *ctx, JSAtom v)\n{\n    return JS_AtomGetKind(ctx, v) == JS_ATOM_KIND_STRING;\n}\n\nstatic JSAtom js_get_atom_index(JSRuntime *rt, JSAtomStruct *p)\n{\n    uint32_t i = p->hash_next;  /* atom_index */\n    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {\n        JSAtomStruct *p1;\n\n        i = rt->atom_hash[p->hash & (rt->atom_hash_size - 1)];\n        p1 = rt->atom_array[i];\n        while (p1 != p) {\n            assert(i != 0);\n            i = p1->hash_next;\n            p1 = rt->atom_array[i];\n        }\n    }\n    return i;\n}\n\n/* string case (internal). Return JS_ATOM_NULL if error. 'str' is\n   freed. */\nstatic JSAtom __JS_NewAtom(JSRuntime *rt, JSString *str, int atom_type)\n{\n    uint32_t h, h1, i;\n    JSAtomStruct *p;\n    int len;\n\n#if 0\n    printf(\"__JS_NewAtom: \");  JS_DumpString(rt, str); printf(\"\\n\");\n#endif\n    if (atom_type < JS_ATOM_TYPE_SYMBOL) {\n        /* str is not NULL */\n        if (str->atom_type == atom_type) {\n            /* str is the atom, return its index */\n            i = js_get_atom_index(rt, str);\n            /* reduce string refcount and increase atom's unless constant */\n            if (__JS_AtomIsConst(i))\n                str->header.ref_count--;\n            return i;\n        }\n        /* try and locate an already registered atom */\n        len = str->len;\n        h = hash_string(str, atom_type);\n        h &= JS_ATOM_HASH_MASK;\n        h1 = h & (rt->atom_hash_size - 1);\n        i = rt->atom_hash[h1];\n        while (i != 0) {\n            p = rt->atom_array[i];\n            if (p->hash == h &&\n                p->atom_type == atom_type &&\n                p->len == len &&\n                js_string_memcmp(p, 0, str, 0, len) == 0) {\n                if (!__JS_AtomIsConst(i))\n                    p->header.ref_count++;\n                goto done;\n            }\n            i = p->hash_next;\n        }\n    } else {\n        h1 = 0; /* avoid warning */\n        if (atom_type == JS_ATOM_TYPE_SYMBOL) {\n            h = 0;\n        } else {\n            h = JS_ATOM_HASH_PRIVATE;\n            atom_type = JS_ATOM_TYPE_SYMBOL;\n        }\n    }\n\n    if (rt->atom_free_index == 0) {\n        /* allow new atom entries */\n        uint32_t new_size, start;\n        JSAtomStruct **new_array;\n\n        /* alloc new with size progression 3/2:\n           4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599 2398 3597 5395 8092\n           preallocating space for predefined atoms (at least 504).\n         */\n        new_size = max_int(711, rt->atom_size * 3 / 2);\n        if (new_size > JS_ATOM_MAX)\n            goto fail;\n        /* XXX: should use realloc2 to use slack space */\n        new_array = js_realloc_rt(rt, rt->atom_array, sizeof(*new_array) * new_size);\n        if (!new_array)\n            goto fail;\n        /* Note: the atom 0 is not used */\n        start = rt->atom_size;\n        if (start == 0) {\n            /* JS_ATOM_NULL entry */\n            p = js_mallocz_rt(rt, sizeof(JSAtomStruct));\n            if (!p) {\n                js_free_rt(rt, new_array);\n                goto fail;\n            }\n            p->header.ref_count = 1;  /* not refcounted */\n            p->atom_type = JS_ATOM_TYPE_SYMBOL;\n#ifdef DUMP_LEAKS\n            list_add_tail(&p->link, &rt->string_list);\n#endif\n            new_array[0] = p;\n            rt->atom_count++;\n            start = 1;\n        }\n        rt->atom_size = new_size;\n        rt->atom_array = new_array;\n        rt->atom_free_index = start;\n        for(i = start; i < new_size; i++) {\n            uint32_t next;\n            if (i == (new_size - 1))\n                next = 0;\n            else\n                next = i + 1;\n            rt->atom_array[i] = atom_set_free(next);\n        }\n    }\n\n    if (str) {\n        if (str->atom_type == 0) {\n            p = str;\n            p->atom_type = atom_type;\n        } else {\n            p = js_malloc_rt(rt, sizeof(JSString) +\n                             (str->len << str->is_wide_char) +\n                             1 - str->is_wide_char);\n            if (unlikely(!p))\n                goto fail;\n            p->header.ref_count = 1;\n            p->is_wide_char = str->is_wide_char;\n            p->len = str->len;\n#ifdef DUMP_LEAKS\n            list_add_tail(&p->link, &rt->string_list);\n#endif\n            memcpy(p->u.str8, str->u.str8, (str->len << str->is_wide_char) +\n                   1 - str->is_wide_char);\n            js_free_string(rt, str);\n        }\n    } else {\n        p = js_malloc_rt(rt, sizeof(JSAtomStruct)); /* empty wide string */\n        if (!p)\n            return JS_ATOM_NULL;\n        p->header.ref_count = 1;\n        p->is_wide_char = 1;    /* Hack to represent NULL as a JSString */\n        p->len = 0;\n#ifdef DUMP_LEAKS\n        list_add_tail(&p->link, &rt->string_list);\n#endif\n    }\n\n    /* use an already free entry */\n    i = rt->atom_free_index;\n    rt->atom_free_index = atom_get_free(rt->atom_array[i]);\n    rt->atom_array[i] = p;\n\n    p->hash = h;\n    p->hash_next = i;   /* atom_index */\n    p->atom_type = atom_type;\n\n    rt->atom_count++;\n\n    if (atom_type != JS_ATOM_TYPE_SYMBOL) {\n        p->hash_next = rt->atom_hash[h1];\n        rt->atom_hash[h1] = i;\n        if (unlikely(rt->atom_count >= rt->atom_count_resize))\n            JS_ResizeAtomHash(rt, rt->atom_hash_size * 2);\n    }\n\n    //    JS_DumpAtoms(rt);\n    return i;\n\n fail:\n    i = JS_ATOM_NULL;\n done:\n    if (str)\n        js_free_string(rt, str);\n    return i;\n}\n\n/* only works with zero terminated 8 bit strings */\nstatic JSAtom __JS_NewAtomInit(JSRuntime *rt, const char *str, int len,\n                               int atom_type)\n{\n    JSString *p;\n    p = js_alloc_string_rt(rt, len, 0);\n    if (!p)\n        return JS_ATOM_NULL;\n    memcpy(p->u.str8, str, len);\n    p->u.str8[len] = '\\0';\n    return __JS_NewAtom(rt, p, atom_type);\n}\n\n/* Warning: str must be ASCII only */\nstatic JSAtom __JS_FindAtom(JSRuntime *rt, const char *str, size_t len,\n                            int atom_type)\n{\n    uint32_t h, h1, i;\n    JSAtomStruct *p;\n\n    h = hash_string8((const uint8_t *)str, len, JS_ATOM_TYPE_STRING);\n    h &= JS_ATOM_HASH_MASK;\n    h1 = h & (rt->atom_hash_size - 1);\n    i = rt->atom_hash[h1];\n    while (i != 0) {\n        p = rt->atom_array[i];\n        if (p->hash == h &&\n            p->atom_type == JS_ATOM_TYPE_STRING &&\n            p->len == len &&\n            p->is_wide_char == 0 &&\n            memcmp(p->u.str8, str, len) == 0) {\n            if (!__JS_AtomIsConst(i))\n                p->header.ref_count++;\n            return i;\n        }\n        i = p->hash_next;\n    }\n    return JS_ATOM_NULL;\n}\n\nstatic void JS_FreeAtomStruct(JSRuntime *rt, JSAtomStruct *p)\n{\n#if 0   /* JS_ATOM_NULL is not refcounted: __JS_AtomIsConst() includes 0 */\n    if (unlikely(i == JS_ATOM_NULL)) {\n        p->header.ref_count = INT32_MAX / 2;\n        return;\n    }\n#endif\n    uint32_t i = p->hash_next;  /* atom_index */\n    if (p->atom_type != JS_ATOM_TYPE_SYMBOL) {\n        JSAtomStruct *p0, *p1;\n        uint32_t h0;\n\n        h0 = p->hash & (rt->atom_hash_size - 1);\n        i = rt->atom_hash[h0];\n        p1 = rt->atom_array[i];\n        if (p1 == p) {\n            rt->atom_hash[h0] = p1->hash_next;\n        } else {\n            for(;;) {\n                assert(i != 0);\n                p0 = p1;\n                i = p1->hash_next;\n                p1 = rt->atom_array[i];\n                if (p1 == p) {\n                    p0->hash_next = p1->hash_next;\n                    break;\n                }\n            }\n        }\n    }\n    /* insert in free atom list */\n    rt->atom_array[i] = atom_set_free(rt->atom_free_index);\n    rt->atom_free_index = i;\n    /* free the string structure */\n#ifdef DUMP_LEAKS\n    list_del(&p->link);\n#endif\n    if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&\n        p->hash != JS_ATOM_HASH_PRIVATE && p->hash != 0) {\n        /* live weak references are still present on this object: keep\n           it */\n    } else {\n        js_free_rt(rt, p);\n    }\n    rt->atom_count--;\n    assert(rt->atom_count >= 0);\n}\n\nstatic void __JS_FreeAtom(JSRuntime *rt, uint32_t i)\n{\n    JSAtomStruct *p;\n\n    p = rt->atom_array[i];\n    if (--p->header.ref_count > 0)\n        return;\n    JS_FreeAtomStruct(rt, p);\n}\n\n/* Warning: 'p' is freed */\nstatic JSAtom JS_NewAtomStr(JSContext *ctx, JSString *p)\n{\n    JSRuntime *rt = ctx->rt;\n    uint32_t n;\n    if (is_num_string(&n, p)) {\n        if (n <= JS_ATOM_MAX_INT) {\n            js_free_string(rt, p);\n            return __JS_AtomFromUInt32(n);\n        }\n    }\n    /* XXX: should generate an exception */\n    return __JS_NewAtom(rt, p, JS_ATOM_TYPE_STRING);\n}\n\n/* XXX: optimize */\nstatic size_t count_ascii(const uint8_t *buf, size_t len)\n{\n    const uint8_t *p, *p_end;\n    p = buf;\n    p_end = buf + len;\n    while (p < p_end && *p < 128)\n        p++;\n    return p - buf;\n}\n\n/* str is UTF-8 encoded */\nJSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len)\n{\n    JSValue val;\n\n    if (len == 0 ||\n        (!is_digit(*str) &&\n         count_ascii((const uint8_t *)str, len) == len)) {\n        JSAtom atom = __JS_FindAtom(ctx->rt, str, len, JS_ATOM_TYPE_STRING);\n        if (atom)\n            return atom;\n    }\n    val = JS_NewStringLen(ctx, str, len);\n    if (JS_IsException(val))\n        return JS_ATOM_NULL;\n    return JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(val));\n}\n\nJSAtom JS_NewAtom(JSContext *ctx, const char *str)\n{\n    return JS_NewAtomLen(ctx, str, strlen(str));\n}\n\nJSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n)\n{\n    if (n <= JS_ATOM_MAX_INT) {\n        return __JS_AtomFromUInt32(n);\n    } else {\n        char buf[11];\n        JSValue val;\n        size_t len;\n        len = u32toa(buf, n);\n        val = js_new_string8_len(ctx, buf, len);\n        if (JS_IsException(val))\n            return JS_ATOM_NULL;\n        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),\n                            JS_ATOM_TYPE_STRING);\n    }\n}\n\nstatic JSAtom JS_NewAtomInt64(JSContext *ctx, int64_t n)\n{\n    if ((uint64_t)n <= JS_ATOM_MAX_INT) {\n        return __JS_AtomFromUInt32((uint32_t)n);\n    } else {\n        char buf[24];\n        JSValue val;\n        size_t len;\n        len = i64toa(buf, n);\n        val = js_new_string8_len(ctx, buf, len);\n        if (JS_IsException(val))\n            return JS_ATOM_NULL;\n        return __JS_NewAtom(ctx->rt, JS_VALUE_GET_STRING(val),\n                            JS_ATOM_TYPE_STRING);\n    }\n}\n\n/* 'p' is freed */\nstatic JSValue JS_NewSymbol(JSContext *ctx, JSString *p, int atom_type)\n{\n    JSRuntime *rt = ctx->rt;\n    JSAtom atom;\n    atom = __JS_NewAtom(rt, p, atom_type);\n    if (atom == JS_ATOM_NULL)\n        return JS_ThrowOutOfMemory(ctx);\n    return JS_MKPTR(JS_TAG_SYMBOL, rt->atom_array[atom]);\n}\n\n/* descr must be a non-numeric string atom */\nstatic JSValue JS_NewSymbolFromAtom(JSContext *ctx, JSAtom descr,\n                                    int atom_type)\n{\n    JSRuntime *rt = ctx->rt;\n    JSString *p;\n\n    assert(!__JS_AtomIsTaggedInt(descr));\n    assert(descr < rt->atom_size);\n    p = rt->atom_array[descr];\n    JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));\n    return JS_NewSymbol(ctx, p, atom_type);\n}\n\n#define ATOM_GET_STR_BUF_SIZE 64\n\n/* Should only be used for debug. */\nstatic const char *JS_AtomGetStrRT(JSRuntime *rt, char *buf, int buf_size,\n                                   JSAtom atom)\n{\n    if (__JS_AtomIsTaggedInt(atom)) {\n        snprintf(buf, buf_size, \"%u\", __JS_AtomToUInt32(atom));\n    } else {\n        JSAtomStruct *p;\n        assert(atom < rt->atom_size);\n        if (atom == JS_ATOM_NULL) {\n            snprintf(buf, buf_size, \"<null>\");\n        } else {\n            int i, c;\n            char *q;\n            JSString *str;\n\n            q = buf;\n            p = rt->atom_array[atom];\n            assert(!atom_is_free(p));\n            str = p;\n            if (str) {\n                if (!str->is_wide_char) {\n                    /* special case ASCII strings */\n                    c = 0;\n                    for(i = 0; i < str->len; i++) {\n                        c |= str->u.str8[i];\n                    }\n                    if (c < 0x80)\n                        return (const char *)str->u.str8;\n                }\n                for(i = 0; i < str->len; i++) {\n                    c = string_get(str, i);\n                    if ((q - buf) >= buf_size - UTF8_CHAR_LEN_MAX)\n                        break;\n                    if (c < 128) {\n                        *q++ = c;\n                    } else {\n                        q += unicode_to_utf8((uint8_t *)q, c);\n                    }\n                }\n            }\n            *q = '\\0';\n        }\n    }\n    return buf;\n}\n\nstatic const char *JS_AtomGetStr(JSContext *ctx, char *buf, int buf_size, JSAtom atom)\n{\n    return JS_AtomGetStrRT(ctx->rt, buf, buf_size, atom);\n}\n\nstatic JSValue __JS_AtomToValue(JSContext *ctx, JSAtom atom, BOOL force_string)\n{\n    char buf[ATOM_GET_STR_BUF_SIZE];\n\n    if (__JS_AtomIsTaggedInt(atom)) {\n        size_t len = u32toa(buf, __JS_AtomToUInt32(atom));\n        return js_new_string8_len(ctx, buf, len);\n    } else {\n        JSRuntime *rt = ctx->rt;\n        JSAtomStruct *p;\n        assert(atom < rt->atom_size);\n        p = rt->atom_array[atom];\n        if (p->atom_type == JS_ATOM_TYPE_STRING) {\n            goto ret_string;\n        } else if (force_string) {\n            if (p->len == 0 && p->is_wide_char != 0) {\n                /* no description string */\n                p = rt->atom_array[JS_ATOM_empty_string];\n            }\n        ret_string:\n            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));\n        } else {\n            return JS_DupValue(ctx, JS_MKPTR(JS_TAG_SYMBOL, p));\n        }\n    }\n}\n\nJSValue JS_AtomToValue(JSContext *ctx, JSAtom atom)\n{\n    return __JS_AtomToValue(ctx, atom, FALSE);\n}\n\nJSValue JS_AtomToString(JSContext *ctx, JSAtom atom)\n{\n    return __JS_AtomToValue(ctx, atom, TRUE);\n}\n\n/* return TRUE if the atom is an array index (i.e. 0 <= index <=\n   2^32-2 and return its value */\nstatic BOOL JS_AtomIsArrayIndex(JSContext *ctx, uint32_t *pval, JSAtom atom)\n{\n    if (__JS_AtomIsTaggedInt(atom)) {\n        *pval = __JS_AtomToUInt32(atom);\n        return TRUE;\n    } else {\n        JSRuntime *rt = ctx->rt;\n        JSAtomStruct *p;\n        uint32_t val;\n\n        assert(atom < rt->atom_size);\n        p = rt->atom_array[atom];\n        if (p->atom_type == JS_ATOM_TYPE_STRING &&\n            is_num_string(&val, p) && val != -1) {\n            *pval = val;\n            return TRUE;\n        } else {\n            *pval = 0;\n            return FALSE;\n        }\n    }\n}\n\n/* This test must be fast if atom is not a numeric index (e.g. a\n   method name). Return JS_UNDEFINED if not a numeric\n   index. JS_EXCEPTION can also be returned. */\nstatic JSValue JS_AtomIsNumericIndex1(JSContext *ctx, JSAtom atom)\n{\n    JSRuntime *rt = ctx->rt;\n    JSAtomStruct *p1;\n    JSString *p;\n    int c, ret;\n    JSValue num, str;\n\n    if (__JS_AtomIsTaggedInt(atom))\n        return JS_NewInt32(ctx, __JS_AtomToUInt32(atom));\n    assert(atom < rt->atom_size);\n    p1 = rt->atom_array[atom];\n    if (p1->atom_type != JS_ATOM_TYPE_STRING)\n        return JS_UNDEFINED;\n    switch(atom) {\n    case JS_ATOM_minus_zero:\n        return __JS_NewFloat64(ctx, -0.0);\n    case JS_ATOM_Infinity:\n        return __JS_NewFloat64(ctx, INFINITY);\n    case JS_ATOM_minus_Infinity:\n        return __JS_NewFloat64(ctx, -INFINITY);\n    case JS_ATOM_NaN:\n        return __JS_NewFloat64(ctx, NAN);\n    default:\n        break;\n    }\n    p = p1;\n    if (p->len == 0)\n        return JS_UNDEFINED;\n    c = string_get(p, 0);\n    if (!is_num(c) && c != '-')\n        return JS_UNDEFINED;\n    /* this is ECMA CanonicalNumericIndexString primitive */\n    num = JS_ToNumber(ctx, JS_MKPTR(JS_TAG_STRING, p));\n    if (JS_IsException(num))\n        return num;\n    str = JS_ToString(ctx, num);\n    if (JS_IsException(str)) {\n        JS_FreeValue(ctx, num);\n        return str;\n    }\n    ret = js_string_eq(ctx, p, JS_VALUE_GET_STRING(str));\n    JS_FreeValue(ctx, str);\n    if (ret) {\n        return num;\n    } else {\n        JS_FreeValue(ctx, num);\n        return JS_UNDEFINED;\n    }\n}\n\n/* return -1 if exception or TRUE/FALSE */\nstatic int JS_AtomIsNumericIndex(JSContext *ctx, JSAtom atom)\n{\n    JSValue num;\n    num = JS_AtomIsNumericIndex1(ctx, atom);\n    if (likely(JS_IsUndefined(num)))\n        return FALSE;\n    if (JS_IsException(num))\n        return -1;\n    JS_FreeValue(ctx, num);\n    return TRUE;\n}\n\nvoid JS_FreeAtom(JSContext *ctx, JSAtom v)\n{\n    if (!__JS_AtomIsConst(v))\n        __JS_FreeAtom(ctx->rt, v);\n}\n\nvoid JS_FreeAtomRT(JSRuntime *rt, JSAtom v)\n{\n    if (!__JS_AtomIsConst(v))\n        __JS_FreeAtom(rt, v);\n}\n\n/* return TRUE if 'v' is a symbol with a string description */\nstatic BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v)\n{\n    JSRuntime *rt;\n    JSAtomStruct *p;\n\n    rt = ctx->rt;\n    if (__JS_AtomIsTaggedInt(v))\n        return FALSE;\n    p = rt->atom_array[v];\n    return (((p->atom_type == JS_ATOM_TYPE_SYMBOL &&\n              p->hash != JS_ATOM_HASH_PRIVATE) ||\n             p->atom_type == JS_ATOM_TYPE_GLOBAL_SYMBOL) &&\n            !(p->len == 0 && p->is_wide_char != 0));\n}\n\n/* free with JS_FreeCString() */\nconst char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom)\n{\n    JSValue str;\n    const char *cstr;\n\n    str = JS_AtomToString(ctx, atom);\n    if (JS_IsException(str)) {\n        if (plen)\n            *plen = 0;\n        return NULL;\n    }\n    cstr = JS_ToCStringLen(ctx, plen, str);\n    JS_FreeValue(ctx, str);\n    return cstr;\n}\n\n/* return a string atom containing name concatenated with str1 */\nstatic JSAtom js_atom_concat_str(JSContext *ctx, JSAtom name, const char *str1)\n{\n    JSValue str;\n    JSAtom atom;\n    const char *cstr;\n    char *cstr2;\n    size_t len, len1;\n\n    str = JS_AtomToString(ctx, name);\n    if (JS_IsException(str))\n        return JS_ATOM_NULL;\n    cstr = JS_ToCStringLen(ctx, &len, str);\n    if (!cstr)\n        goto fail;\n    len1 = strlen(str1);\n    cstr2 = js_malloc(ctx, len + len1 + 1);\n    if (!cstr2)\n        goto fail;\n    memcpy(cstr2, cstr, len);\n    memcpy(cstr2 + len, str1, len1);\n    cstr2[len + len1] = '\\0';\n    atom = JS_NewAtomLen(ctx, cstr2, len + len1);\n    js_free(ctx, cstr2);\n    JS_FreeCString(ctx, cstr);\n    JS_FreeValue(ctx, str);\n    return atom;\n fail:\n    JS_FreeCString(ctx, cstr);\n    JS_FreeValue(ctx, str);\n    return JS_ATOM_NULL;\n}\n\nstatic JSAtom js_atom_concat_num(JSContext *ctx, JSAtom name, uint32_t n)\n{\n    char buf[16];\n    size_t len;\n    len = u32toa(buf, n);\n    buf[len] = '\\0';\n    return js_atom_concat_str(ctx, name, buf);\n}\n\nstatic inline BOOL JS_IsEmptyString(JSValueConst v)\n{\n    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING && JS_VALUE_GET_STRING(v)->len == 0;\n}\n\n/* JSClass support */\n\n#ifdef CONFIG_ATOMICS\nstatic pthread_mutex_t js_class_id_mutex = PTHREAD_MUTEX_INITIALIZER;\n#endif\n\n/* a new class ID is allocated if *pclass_id != 0 */\nJSClassID JS_NewClassID(JSClassID *pclass_id)\n{\n    JSClassID class_id;\n#ifdef CONFIG_ATOMICS\n    pthread_mutex_lock(&js_class_id_mutex);\n#endif\n    class_id = *pclass_id;\n    if (class_id == 0) {\n        class_id = js_class_id_alloc++;\n        *pclass_id = class_id;\n    }\n#ifdef CONFIG_ATOMICS\n    pthread_mutex_unlock(&js_class_id_mutex);\n#endif\n    return class_id;\n}\n\nJSClassID JS_GetClassID(JSValue v)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(v) != JS_TAG_OBJECT)\n        return JS_INVALID_CLASS_ID;\n    p = JS_VALUE_GET_OBJ(v);\n    return p->class_id;\n}\n\nBOOL JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id)\n{\n    return (class_id < rt->class_count &&\n            rt->class_array[class_id].class_id != 0);\n}\n\n/* create a new object internal class. Return -1 if error, 0 if\n   OK. The finalizer can be NULL if none is needed. */\nstatic int JS_NewClass1(JSRuntime *rt, JSClassID class_id,\n                        const JSClassDef *class_def, JSAtom name)\n{\n    int new_size, i;\n    JSClass *cl, *new_class_array;\n    struct list_head *el;\n\n    if (class_id >= (1 << 16))\n        return -1;\n    if (class_id < rt->class_count &&\n        rt->class_array[class_id].class_id != 0)\n        return -1;\n\n    if (class_id >= rt->class_count) {\n        new_size = max_int(JS_CLASS_INIT_COUNT,\n                           max_int(class_id + 1, rt->class_count * 3 / 2));\n\n        /* reallocate the context class prototype array, if any */\n        list_for_each(el, &rt->context_list) {\n            JSContext *ctx = list_entry(el, JSContext, link);\n            JSValue *new_tab;\n            new_tab = js_realloc_rt(rt, ctx->class_proto,\n                                    sizeof(ctx->class_proto[0]) * new_size);\n            if (!new_tab)\n                return -1;\n            for(i = rt->class_count; i < new_size; i++)\n                new_tab[i] = JS_NULL;\n            ctx->class_proto = new_tab;\n        }\n        /* reallocate the class array */\n        new_class_array = js_realloc_rt(rt, rt->class_array,\n                                        sizeof(JSClass) * new_size);\n        if (!new_class_array)\n            return -1;\n        memset(new_class_array + rt->class_count, 0,\n               (new_size - rt->class_count) * sizeof(JSClass));\n        rt->class_array = new_class_array;\n        rt->class_count = new_size;\n    }\n    cl = &rt->class_array[class_id];\n    cl->class_id = class_id;\n    cl->class_name = JS_DupAtomRT(rt, name);\n    cl->finalizer = class_def->finalizer;\n    cl->gc_mark = class_def->gc_mark;\n    cl->call = class_def->call;\n    cl->exotic = class_def->exotic;\n    return 0;\n}\n\nint JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def)\n{\n    int ret, len;\n    JSAtom name;\n\n    len = strlen(class_def->class_name);\n    name = __JS_FindAtom(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);\n    if (name == JS_ATOM_NULL) {\n        name = __JS_NewAtomInit(rt, class_def->class_name, len, JS_ATOM_TYPE_STRING);\n        if (name == JS_ATOM_NULL)\n            return -1;\n    }\n    ret = JS_NewClass1(rt, class_id, class_def, name);\n    JS_FreeAtomRT(rt, name);\n    return ret;\n}\n\nstatic JSValue js_new_string8_len(JSContext *ctx, const char *buf, int len)\n{\n    JSString *str;\n\n    if (len <= 0) {\n        return JS_AtomToString(ctx, JS_ATOM_empty_string);\n    }\n    str = js_alloc_string(ctx, len, 0);\n    if (!str)\n        return JS_EXCEPTION;\n    memcpy(str->u.str8, buf, len);\n    str->u.str8[len] = '\\0';\n    return JS_MKPTR(JS_TAG_STRING, str);\n}\n\nstatic JSValue js_new_string8(JSContext *ctx, const char *buf)\n{\n    return js_new_string8_len(ctx, buf, strlen(buf));\n}\n\nstatic JSValue js_new_string16_len(JSContext *ctx, const uint16_t *buf, int len)\n{\n    JSString *str;\n    str = js_alloc_string(ctx, len, 1);\n    if (!str)\n        return JS_EXCEPTION;\n    memcpy(str->u.str16, buf, len * 2);\n    return JS_MKPTR(JS_TAG_STRING, str);\n}\n\nstatic JSValue js_new_string_char(JSContext *ctx, uint16_t c)\n{\n    if (c < 0x100) {\n        uint8_t ch8 = c;\n        return js_new_string8_len(ctx, (const char *)&ch8, 1);\n    } else {\n        uint16_t ch16 = c;\n        return js_new_string16_len(ctx, &ch16, 1);\n    }\n}\n\nstatic JSValue js_sub_string(JSContext *ctx, JSString *p, int start, int end)\n{\n    int len = end - start;\n    if (start == 0 && end == p->len) {\n        return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));\n    }\n    if (p->is_wide_char && len > 0) {\n        JSString *str;\n        int i;\n        uint16_t c = 0;\n        for (i = start; i < end; i++) {\n            c |= p->u.str16[i];\n        }\n        if (c > 0xFF)\n            return js_new_string16_len(ctx, p->u.str16 + start, len);\n\n        str = js_alloc_string(ctx, len, 0);\n        if (!str)\n            return JS_EXCEPTION;\n        for (i = 0; i < len; i++) {\n            str->u.str8[i] = p->u.str16[start + i];\n        }\n        str->u.str8[len] = '\\0';\n        return JS_MKPTR(JS_TAG_STRING, str);\n    } else {\n        return js_new_string8_len(ctx, (const char *)(p->u.str8 + start), len);\n    }\n}\n\ntypedef struct StringBuffer {\n    JSContext *ctx;\n    JSString *str;\n    int len;\n    int size;\n    int is_wide_char;\n    int error_status;\n} StringBuffer;\n\n/* It is valid to call string_buffer_end() and all string_buffer functions even\n   if string_buffer_init() or another string_buffer function returns an error.\n   If the error_status is set, string_buffer_end() returns JS_EXCEPTION.\n */\nstatic int string_buffer_init2(JSContext *ctx, StringBuffer *s, int size,\n                               int is_wide)\n{\n    s->ctx = ctx;\n    s->size = size;\n    s->len = 0;\n    s->is_wide_char = is_wide;\n    s->error_status = 0;\n    s->str = js_alloc_string(ctx, size, is_wide);\n    if (unlikely(!s->str)) {\n        s->size = 0;\n        return s->error_status = -1;\n    }\n#ifdef DUMP_LEAKS\n    /* the StringBuffer may reallocate the JSString, only link it at the end */\n    list_del(&s->str->link);\n#endif\n    return 0;\n}\n\nstatic inline int string_buffer_init(JSContext *ctx, StringBuffer *s, int size)\n{\n    return string_buffer_init2(ctx, s, size, 0);\n}\n\nstatic void string_buffer_free(StringBuffer *s)\n{\n    js_free(s->ctx, s->str);\n    s->str = NULL;\n}\n\nstatic int string_buffer_set_error(StringBuffer *s)\n{\n    js_free(s->ctx, s->str);\n    s->str = NULL;\n    s->size = 0;\n    s->len = 0;\n    return s->error_status = -1;\n}\n\nstatic no_inline int string_buffer_widen(StringBuffer *s, int size)\n{\n    JSString *str;\n    size_t slack;\n    int i;\n\n    if (s->error_status)\n        return -1;\n\n    str = js_realloc2(s->ctx, s->str, sizeof(JSString) + (size << 1), &slack);\n    if (!str)\n        return string_buffer_set_error(s);\n    size += slack >> 1;\n    for(i = s->len; i-- > 0;) {\n        str->u.str16[i] = str->u.str8[i];\n    }\n    s->is_wide_char = 1;\n    s->size = size;\n    s->str = str;\n    return 0;\n}\n\nstatic no_inline int string_buffer_realloc(StringBuffer *s, int new_len, int c)\n{\n    JSString *new_str;\n    int new_size;\n    size_t new_size_bytes, slack;\n\n    if (s->error_status)\n        return -1;\n\n    if (new_len > JS_STRING_LEN_MAX) {\n        JS_ThrowInternalError(s->ctx, \"string too long\");\n        return string_buffer_set_error(s);\n    }\n    new_size = min_int(max_int(new_len, s->size * 3 / 2), JS_STRING_LEN_MAX);\n    if (!s->is_wide_char && c >= 0x100) {\n        return string_buffer_widen(s, new_size);\n    }\n    new_size_bytes = sizeof(JSString) + (new_size << s->is_wide_char) + 1 - s->is_wide_char;\n    new_str = js_realloc2(s->ctx, s->str, new_size_bytes, &slack);\n    if (!new_str)\n        return string_buffer_set_error(s);\n    new_size = min_int(new_size + (slack >> s->is_wide_char), JS_STRING_LEN_MAX);\n    s->size = new_size;\n    s->str = new_str;\n    return 0;\n}\n\nstatic no_inline int string_buffer_putc16_slow(StringBuffer *s, uint32_t c)\n{\n    if (unlikely(s->len >= s->size)) {\n        if (string_buffer_realloc(s, s->len + 1, c))\n            return -1;\n    }\n    if (s->is_wide_char) {\n        s->str->u.str16[s->len++] = c;\n    } else if (c < 0x100) {\n        s->str->u.str8[s->len++] = c;\n    } else {\n        if (string_buffer_widen(s, s->size))\n            return -1;\n        s->str->u.str16[s->len++] = c;\n    }\n    return 0;\n}\n\n/* 0 <= c <= 0xff */\nstatic int string_buffer_putc8(StringBuffer *s, uint32_t c)\n{\n    if (unlikely(s->len >= s->size)) {\n        if (string_buffer_realloc(s, s->len + 1, c))\n            return -1;\n    }\n    if (s->is_wide_char) {\n        s->str->u.str16[s->len++] = c;\n    } else {\n        s->str->u.str8[s->len++] = c;\n    }\n    return 0;\n}\n\n/* 0 <= c <= 0xffff */\nstatic int string_buffer_putc16(StringBuffer *s, uint32_t c)\n{\n    if (likely(s->len < s->size)) {\n        if (s->is_wide_char) {\n            s->str->u.str16[s->len++] = c;\n            return 0;\n        } else if (c < 0x100) {\n            s->str->u.str8[s->len++] = c;\n            return 0;\n        }\n    }\n    return string_buffer_putc16_slow(s, c);\n}\n\nstatic int string_buffer_putc_slow(StringBuffer *s, uint32_t c)\n{\n    if (unlikely(c >= 0x10000)) {\n        /* surrogate pair */\n        if (string_buffer_putc16(s, get_hi_surrogate(c)))\n            return -1;\n        c = get_lo_surrogate(c);\n    }\n    return string_buffer_putc16(s, c);\n}\n\n/* 0 <= c <= 0x10ffff */\nstatic inline int string_buffer_putc(StringBuffer *s, uint32_t c)\n{\n    if (likely(s->len < s->size)) {\n        if (s->is_wide_char) {\n            if (c < 0x10000) {\n                s->str->u.str16[s->len++] = c;\n                return 0;\n            } else if (likely((s->len + 1) < s->size)) {\n                s->str->u.str16[s->len++] = get_hi_surrogate(c);\n                s->str->u.str16[s->len++] = get_lo_surrogate(c);\n                return 0;\n            }\n        } else if (c < 0x100) {\n            s->str->u.str8[s->len++] = c;\n            return 0;\n        }\n    }\n    return string_buffer_putc_slow(s, c);\n}\n\nstatic int string_getc(const JSString *p, int *pidx)\n{\n    int idx, c, c1;\n    idx = *pidx;\n    if (p->is_wide_char) {\n        c = p->u.str16[idx++];\n        if (is_hi_surrogate(c) && idx < p->len) {\n            c1 = p->u.str16[idx];\n            if (is_lo_surrogate(c1)) {\n                c = from_surrogate(c, c1);\n                idx++;\n            }\n        }\n    } else {\n        c = p->u.str8[idx++];\n    }\n    *pidx = idx;\n    return c;\n}\n\nstatic int string_buffer_write8(StringBuffer *s, const uint8_t *p, int len)\n{\n    int i;\n\n    if (s->len + len > s->size) {\n        if (string_buffer_realloc(s, s->len + len, 0))\n            return -1;\n    }\n    if (s->is_wide_char) {\n        for (i = 0; i < len; i++) {\n            s->str->u.str16[s->len + i] = p[i];\n        }\n        s->len += len;\n    } else {\n        memcpy(&s->str->u.str8[s->len], p, len);\n        s->len += len;\n    }\n    return 0;\n}\n\nstatic int string_buffer_write16(StringBuffer *s, const uint16_t *p, int len)\n{\n    int c = 0, i;\n\n    for (i = 0; i < len; i++) {\n        c |= p[i];\n    }\n    if (s->len + len > s->size) {\n        if (string_buffer_realloc(s, s->len + len, c))\n            return -1;\n    } else if (!s->is_wide_char && c >= 0x100) {\n        if (string_buffer_widen(s, s->size))\n            return -1;\n    }\n    if (s->is_wide_char) {\n        memcpy(&s->str->u.str16[s->len], p, len << 1);\n        s->len += len;\n    } else {\n        for (i = 0; i < len; i++) {\n            s->str->u.str8[s->len + i] = p[i];\n        }\n        s->len += len;\n    }\n    return 0;\n}\n\n/* appending an ASCII string */\nstatic int string_buffer_puts8(StringBuffer *s, const char *str)\n{\n    return string_buffer_write8(s, (const uint8_t *)str, strlen(str));\n}\n\nstatic int string_buffer_concat(StringBuffer *s, const JSString *p,\n                                uint32_t from, uint32_t to)\n{\n    if (to <= from)\n        return 0;\n    if (p->is_wide_char)\n        return string_buffer_write16(s, p->u.str16 + from, to - from);\n    else\n        return string_buffer_write8(s, p->u.str8 + from, to - from);\n}\n\nstatic int string_buffer_concat_value(StringBuffer *s, JSValueConst v)\n{\n    JSString *p;\n    JSValue v1;\n    int res;\n\n    if (s->error_status) {\n        /* prevent exception overload */\n        return -1;\n    }\n    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {\n        if (JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE) {\n            JSStringRope *r = JS_VALUE_GET_STRING_ROPE(v);\n            /* recursion is acceptable because the rope depth is bounded */\n            if (string_buffer_concat_value(s, r->left))\n                return -1;\n            return string_buffer_concat_value(s, r->right);\n        } else {\n            v1 = JS_ToString(s->ctx, v);\n            if (JS_IsException(v1))\n                return string_buffer_set_error(s);\n            p = JS_VALUE_GET_STRING(v1);\n            res = string_buffer_concat(s, p, 0, p->len);\n            JS_FreeValue(s->ctx, v1);\n            return res;\n        }\n    }\n    p = JS_VALUE_GET_STRING(v);\n    return string_buffer_concat(s, p, 0, p->len);\n}\n\nstatic int string_buffer_concat_value_free(StringBuffer *s, JSValue v)\n{\n    JSString *p;\n    int res;\n\n    if (s->error_status) {\n        /* prevent exception overload */\n        JS_FreeValue(s->ctx, v);\n        return -1;\n    }\n    if (unlikely(JS_VALUE_GET_TAG(v) != JS_TAG_STRING)) {\n        v = JS_ToStringFree(s->ctx, v);\n        if (JS_IsException(v))\n            return string_buffer_set_error(s);\n    }\n    p = JS_VALUE_GET_STRING(v);\n    res = string_buffer_concat(s, p, 0, p->len);\n    JS_FreeValue(s->ctx, v);\n    return res;\n}\n\nstatic int string_buffer_fill(StringBuffer *s, int c, int count)\n{\n    /* XXX: optimize */\n    if (s->len + count > s->size) {\n        if (string_buffer_realloc(s, s->len + count, c))\n            return -1;\n    }\n    while (count-- > 0) {\n        if (string_buffer_putc16(s, c))\n            return -1;\n    }\n    return 0;\n}\n\nstatic JSValue string_buffer_end(StringBuffer *s)\n{\n    JSString *str;\n    str = s->str;\n    if (s->error_status)\n        return JS_EXCEPTION;\n    if (s->len == 0) {\n        js_free(s->ctx, str);\n        s->str = NULL;\n        return JS_AtomToString(s->ctx, JS_ATOM_empty_string);\n    }\n    if (s->len < s->size) {\n        /* smaller size so js_realloc should not fail, but OK if it does */\n        /* XXX: should add some slack to avoid unnecessary calls */\n        /* XXX: might need to use malloc+free to ensure smaller size */\n        str = js_realloc_rt(s->ctx->rt, str, sizeof(JSString) +\n                            (s->len << s->is_wide_char) + 1 - s->is_wide_char);\n        if (str == NULL)\n            str = s->str;\n        s->str = str;\n    }\n    if (!s->is_wide_char)\n        str->u.str8[s->len] = 0;\n#ifdef DUMP_LEAKS\n    list_add_tail(&str->link, &s->ctx->rt->string_list);\n#endif\n    str->is_wide_char = s->is_wide_char;\n    str->len = s->len;\n    s->str = NULL;\n    return JS_MKPTR(JS_TAG_STRING, str);\n}\n\n/* create a string from a UTF-8 buffer */\nJSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len)\n{\n    const uint8_t *p, *p_end, *p_start, *p_next;\n    uint32_t c;\n    StringBuffer b_s, *b = &b_s;\n    size_t len1;\n\n    p_start = (const uint8_t *)buf;\n    p_end = p_start + buf_len;\n    len1 = count_ascii(p_start, buf_len);\n    p = p_start + len1;\n    if (len1 > JS_STRING_LEN_MAX)\n        return JS_ThrowInternalError(ctx, \"string too long\");\n    if (p == p_end) {\n        /* ASCII string */\n        return js_new_string8_len(ctx, buf, buf_len);\n    } else {\n        if (string_buffer_init(ctx, b, buf_len))\n            goto fail;\n        string_buffer_write8(b, p_start, len1);\n        while (p < p_end) {\n            if (*p < 128) {\n                string_buffer_putc8(b, *p++);\n            } else {\n                /* parse utf-8 sequence, return 0xFFFFFFFF for error */\n                c = unicode_from_utf8(p, p_end - p, &p_next);\n                if (c < 0x10000) {\n                    p = p_next;\n                } else if (c <= 0x10FFFF) {\n                    p = p_next;\n                    /* surrogate pair */\n                    string_buffer_putc16(b, get_hi_surrogate(c));\n                    c = get_lo_surrogate(c);\n                } else {\n                    /* invalid char */\n                    c = 0xfffd;\n                    /* skip the invalid chars */\n                    /* XXX: seems incorrect. Why not just use c = *p++; ? */\n                    while (p < p_end && (*p >= 0x80 && *p < 0xc0))\n                        p++;\n                    if (p < p_end) {\n                        p++;\n                        while (p < p_end && (*p >= 0x80 && *p < 0xc0))\n                            p++;\n                    }\n                }\n                string_buffer_putc16(b, c);\n            }\n        }\n    }\n    return string_buffer_end(b);\n\n fail:\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ConcatString3(JSContext *ctx, const char *str1,\n                                JSValue str2, const char *str3)\n{\n    StringBuffer b_s, *b = &b_s;\n    int len1, len3;\n    JSString *p;\n\n    if (unlikely(JS_VALUE_GET_TAG(str2) != JS_TAG_STRING)) {\n        str2 = JS_ToStringFree(ctx, str2);\n        if (JS_IsException(str2))\n            goto fail;\n    }\n    p = JS_VALUE_GET_STRING(str2);\n    len1 = strlen(str1);\n    len3 = strlen(str3);\n\n    if (string_buffer_init2(ctx, b, len1 + p->len + len3, p->is_wide_char))\n        goto fail;\n\n    string_buffer_write8(b, (const uint8_t *)str1, len1);\n    string_buffer_concat(b, p, 0, p->len);\n    string_buffer_write8(b, (const uint8_t *)str3, len3);\n\n    JS_FreeValue(ctx, str2);\n    return string_buffer_end(b);\n\n fail:\n    JS_FreeValue(ctx, str2);\n    return JS_EXCEPTION;\n}\n\nJSValue JS_NewAtomString(JSContext *ctx, const char *str)\n{\n    JSAtom atom = JS_NewAtom(ctx, str);\n    if (atom == JS_ATOM_NULL)\n        return JS_EXCEPTION;\n    JSValue val = JS_AtomToString(ctx, atom);\n    JS_FreeAtom(ctx, atom);\n    return val;\n}\n\n/* return (NULL, 0) if exception. */\n/* return pointer into a JSString with a live ref_count */\n/* cesu8 determines if non-BMP1 codepoints are encoded as 1 or 2 utf-8 sequences */\nconst char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, BOOL cesu8)\n{\n    JSValue val;\n    JSString *str, *str_new;\n    int pos, len, c, c1;\n    uint8_t *q;\n\n    if (JS_VALUE_GET_TAG(val1) != JS_TAG_STRING) {\n        val = JS_ToString(ctx, val1);\n        if (JS_IsException(val))\n            goto fail;\n    } else {\n        val = JS_DupValue(ctx, val1);\n    }\n\n    str = JS_VALUE_GET_STRING(val);\n    len = str->len;\n    if (!str->is_wide_char) {\n        const uint8_t *src = str->u.str8;\n        int count;\n\n        /* count the number of non-ASCII characters */\n        /* Scanning the whole string is required for ASCII strings,\n           and computing the number of non-ASCII bytes is less expensive\n           than testing each byte, hence this method is faster for ASCII\n           strings, which is the most common case.\n         */\n        count = 0;\n        for (pos = 0; pos < len; pos++) {\n            count += src[pos] >> 7;\n        }\n        if (count == 0) {\n            if (plen)\n                *plen = len;\n            return (const char *)src;\n        }\n        str_new = js_alloc_string(ctx, len + count, 0);\n        if (!str_new)\n            goto fail;\n        q = str_new->u.str8;\n        for (pos = 0; pos < len; pos++) {\n            c = src[pos];\n            if (c < 0x80) {\n                *q++ = c;\n            } else {\n                *q++ = (c >> 6) | 0xc0;\n                *q++ = (c & 0x3f) | 0x80;\n            }\n        }\n    } else {\n        const uint16_t *src = str->u.str16;\n        /* Allocate 3 bytes per 16 bit code point. Surrogate pairs may\n           produce 4 bytes but use 2 code points.\n         */\n        str_new = js_alloc_string(ctx, len * 3, 0);\n        if (!str_new)\n            goto fail;\n        q = str_new->u.str8;\n        pos = 0;\n        while (pos < len) {\n            c = src[pos++];\n            if (c < 0x80) {\n                *q++ = c;\n            } else {\n                if (is_hi_surrogate(c)) {\n                    if (pos < len && !cesu8) {\n                        c1 = src[pos];\n                        if (is_lo_surrogate(c1)) {\n                            pos++;\n                            c = from_surrogate(c, c1);\n                        } else {\n                            /* Keep unmatched surrogate code points */\n                            /* c = 0xfffd; */ /* error */\n                        }\n                    } else {\n                        /* Keep unmatched surrogate code points */\n                        /* c = 0xfffd; */ /* error */\n                    }\n                }\n                q += unicode_to_utf8(q, c);\n            }\n        }\n    }\n\n    *q = '\\0';\n    str_new->len = q - str_new->u.str8;\n    JS_FreeValue(ctx, val);\n    if (plen)\n        *plen = str_new->len;\n    return (const char *)str_new->u.str8;\n fail:\n    if (plen)\n        *plen = 0;\n    return NULL;\n}\n\nvoid JS_FreeCString(JSContext *ctx, const char *ptr)\n{\n    JSString *p;\n    if (!ptr)\n        return;\n    /* purposely removing constness */\n    p = container_of(ptr, JSString, u);\n    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, p));\n}\n\nstatic int memcmp16_8(const uint16_t *src1, const uint8_t *src2, int len)\n{\n    int c, i;\n    for(i = 0; i < len; i++) {\n        c = src1[i] - src2[i];\n        if (c != 0)\n            return c;\n    }\n    return 0;\n}\n\nstatic int memcmp16(const uint16_t *src1, const uint16_t *src2, int len)\n{\n    int c, i;\n    for(i = 0; i < len; i++) {\n        c = src1[i] - src2[i];\n        if (c != 0)\n            return c;\n    }\n    return 0;\n}\n\nstatic int js_string_memcmp(const JSString *p1, int pos1, const JSString *p2,\n                            int pos2, int len)\n{\n    int res;\n\n    if (likely(!p1->is_wide_char)) {\n        if (likely(!p2->is_wide_char))\n            res = memcmp(p1->u.str8 + pos1, p2->u.str8 + pos2, len);\n        else\n            res = -memcmp16_8(p2->u.str16 + pos2, p1->u.str8 + pos1, len);\n    } else {\n        if (!p2->is_wide_char)\n            res = memcmp16_8(p1->u.str16 + pos1, p2->u.str8 + pos2, len);\n        else\n            res = memcmp16(p1->u.str16 + pos1, p2->u.str16 + pos2, len);\n    }\n    return res;\n}\n\nstatic BOOL js_string_eq(JSContext *ctx,\n                         const JSString *p1, const JSString *p2)\n{\n    if (p1->len != p2->len)\n        return FALSE;\n    if (p1 == p2)\n        return TRUE;\n    return js_string_memcmp(p1, 0, p2, 0, p1->len) == 0;\n}\n\n/* return < 0, 0 or > 0 */\nstatic int js_string_compare(JSContext *ctx,\n                             const JSString *p1, const JSString *p2)\n{\n    int res, len;\n    len = min_int(p1->len, p2->len);\n    res = js_string_memcmp(p1, 0, p2, 0, len);\n    if (res == 0) {\n        if (p1->len == p2->len)\n            res = 0;\n        else if (p1->len < p2->len)\n            res = -1;\n        else\n            res = 1;\n    }\n    return res;\n}\n\nstatic void copy_str16(uint16_t *dst, const JSString *p, int offset, int len)\n{\n    if (p->is_wide_char) {\n        memcpy(dst, p->u.str16 + offset, len * 2);\n    } else {\n        const uint8_t *src1 = p->u.str8 + offset;\n        int i;\n\n        for(i = 0; i < len; i++)\n            dst[i] = src1[i];\n    }\n}\n\nstatic JSValue JS_ConcatString1(JSContext *ctx,\n                                const JSString *p1, const JSString *p2)\n{\n    JSString *p;\n    uint32_t len;\n    int is_wide_char;\n\n    len = p1->len + p2->len;\n    if (len > JS_STRING_LEN_MAX)\n        return JS_ThrowInternalError(ctx, \"string too long\");\n    is_wide_char = p1->is_wide_char | p2->is_wide_char;\n    p = js_alloc_string(ctx, len, is_wide_char);\n    if (!p)\n        return JS_EXCEPTION;\n    if (!is_wide_char) {\n        memcpy(p->u.str8, p1->u.str8, p1->len);\n        memcpy(p->u.str8 + p1->len, p2->u.str8, p2->len);\n        p->u.str8[len] = '\\0';\n    } else {\n        copy_str16(p->u.str16, p1, 0, p1->len);\n        copy_str16(p->u.str16 + p1->len, p2, 0, p2->len);\n    }\n    return JS_MKPTR(JS_TAG_STRING, p);\n}\n\nstatic BOOL JS_ConcatStringInPlace(JSContext *ctx, JSString *p1, JSValueConst op2) {\n    if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {\n        JSString *p2 = JS_VALUE_GET_STRING(op2);\n        size_t size1;\n\n        if (p2->len == 0)\n            return TRUE;\n        if (p1->header.ref_count != 1)\n            return FALSE;\n        size1 = js_malloc_usable_size(ctx, p1);\n        if (p1->is_wide_char) {\n            if (size1 >= sizeof(*p1) + ((p1->len + p2->len) << 1)) {\n                if (p2->is_wide_char) {\n                    memcpy(p1->u.str16 + p1->len, p2->u.str16, p2->len << 1);\n                    p1->len += p2->len;\n                    return TRUE;\n                } else {\n                    size_t i;\n                    for (i = 0; i < p2->len; i++) {\n                        p1->u.str16[p1->len++] = p2->u.str8[i];\n                    }\n                    return TRUE;\n                }\n            }\n        } else if (!p2->is_wide_char) {\n            if (size1 >= sizeof(*p1) + p1->len + p2->len + 1) {\n                memcpy(p1->u.str8 + p1->len, p2->u.str8, p2->len);\n                p1->len += p2->len;\n                p1->u.str8[p1->len] = '\\0';\n                return TRUE;\n            }\n        }\n    }\n    return FALSE;\n}\n\nstatic JSValue JS_ConcatString2(JSContext *ctx, JSValue op1, JSValue op2)\n{\n    JSValue ret;\n    JSString *p1, *p2;\n    p1 = JS_VALUE_GET_STRING(op1);\n    if (JS_ConcatStringInPlace(ctx, p1, op2)) {\n        JS_FreeValue(ctx, op2);\n        return op1;\n    }\n    p2 = JS_VALUE_GET_STRING(op2);\n    ret = JS_ConcatString1(ctx, p1, p2);\n    JS_FreeValue(ctx, op1);\n    JS_FreeValue(ctx, op2);\n    return ret;\n}\n\n/* Return the character at position 'idx'. 'val' must be a string or rope */\nstatic int string_rope_get(JSValueConst val, uint32_t idx)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {\n        return string_get(JS_VALUE_GET_STRING(val), idx);\n    } else {\n        JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);\n        uint32_t len;\n        if (JS_VALUE_GET_TAG(r->left) == JS_TAG_STRING)\n            len = JS_VALUE_GET_STRING(r->left)->len;\n        else\n            len = JS_VALUE_GET_STRING_ROPE(r->left)->len;\n        if (idx < len)\n            return string_rope_get(r->left, idx);\n        else\n            return string_rope_get(r->right, idx - len);\n    }\n}\n\ntypedef struct {\n    JSValueConst stack[JS_STRING_ROPE_MAX_DEPTH];\n    int stack_len;\n} JSStringRopeIter;\n\nstatic void string_rope_iter_init(JSStringRopeIter *s, JSValueConst val)\n{\n    s->stack_len = 0;\n    s->stack[s->stack_len++] = val;\n}\n\n/* iterate thru a rope and return the strings in order */\nstatic JSString *string_rope_iter_next(JSStringRopeIter *s)\n{\n    JSValueConst val;\n    JSStringRope *r;\n\n    if (s->stack_len == 0)\n        return NULL;\n    val = s->stack[--s->stack_len];\n    for(;;) {\n        if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)\n            return JS_VALUE_GET_STRING(val);\n        r = JS_VALUE_GET_STRING_ROPE(val);\n        assert(s->stack_len < JS_STRING_ROPE_MAX_DEPTH);\n        s->stack[s->stack_len++] = r->right;\n        val = r->left;\n    }\n}\n\nstatic uint32_t string_rope_get_len(JSValueConst val)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING)\n        return JS_VALUE_GET_STRING(val)->len;\n    else\n        return JS_VALUE_GET_STRING_ROPE(val)->len;\n}\n\nstatic int js_string_rope_compare(JSContext *ctx, JSValueConst op1,\n                                  JSValueConst op2, BOOL eq_only)\n{\n    uint32_t len1, len2, len, pos1, pos2, l;\n    int res;\n    JSStringRopeIter it1, it2;\n    JSString *p1, *p2;\n    \n    len1 = string_rope_get_len(op1);\n    len2 = string_rope_get_len(op2);\n    /* no need to go further for equality test if\n       different length */\n    if (eq_only && len1 != len2)\n        return 1; \n    len = min_uint32(len1, len2);\n    string_rope_iter_init(&it1, op1);\n    string_rope_iter_init(&it2, op2);\n    p1 = string_rope_iter_next(&it1);\n    p2 = string_rope_iter_next(&it2);\n    pos1 = 0;\n    pos2 = 0;\n    while (len != 0) {\n        l = min_uint32(p1->len - pos1, p2->len - pos2);\n        l = min_uint32(l, len);\n        res = js_string_memcmp(p1, pos1, p2, pos2, l);\n        if (res != 0)\n            return res;\n        len -= l;\n        pos1 += l;\n        if (pos1 >= p1->len) {\n            p1 = string_rope_iter_next(&it1);\n            pos1 = 0;\n        }\n        pos2 += l;\n        if (pos2 >= p2->len) {\n            p2 = string_rope_iter_next(&it2);\n            pos2 = 0;\n        }\n    }\n\n    if (len1 == len2)\n        res = 0;\n    else if (len1 < len2)\n        res = -1;\n    else\n        res = 1;\n    return res;\n}\n\n/* 'rope' must be a rope. return a string and modify the rope so that\n   it won't need to be linearized again. */\nstatic JSValue js_linearize_string_rope(JSContext *ctx, JSValue rope)\n{\n    StringBuffer b_s, *b = &b_s;\n    JSStringRope *r;\n    JSValue ret;\n    \n    r = JS_VALUE_GET_STRING_ROPE(rope);\n\n    /* check whether it is already linearized */\n    if (JS_VALUE_GET_TAG(r->right) == JS_TAG_STRING &&\n        JS_VALUE_GET_STRING(r->right)->len == 0) {\n        ret = JS_DupValue(ctx, r->left);\n        JS_FreeValue(ctx, rope);\n        return ret;\n    }\n    if (string_buffer_init2(ctx, b, r->len, r->is_wide_char))\n        goto fail;\n    if (string_buffer_concat_value(b, rope))\n        goto fail;\n    ret = string_buffer_end(b);\n    if (r->header.ref_count > 1) {\n        /* update the rope so that it won't need to be linearized again */\n        JS_FreeValue(ctx, r->left);\n        JS_FreeValue(ctx, r->right);\n        r->left = JS_DupValue(ctx, ret);\n        r->right = JS_AtomToString(ctx, JS_ATOM_empty_string);\n    }\n    JS_FreeValue(ctx, rope);\n    return ret;\n fail:\n    JS_FreeValue(ctx, rope);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope);\n\n/* op1 and op2 must be strings or string ropes */\nstatic JSValue js_new_string_rope(JSContext *ctx, JSValue op1, JSValue op2)\n{\n    uint32_t len;\n    int is_wide_char, depth;\n    JSStringRope *r;\n    JSValue res;\n    \n    if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {\n        JSString *p1 = JS_VALUE_GET_STRING(op1);\n        len = p1->len;\n        is_wide_char = p1->is_wide_char;\n        depth = 0;\n    } else {\n        JSStringRope *r1 = JS_VALUE_GET_STRING_ROPE(op1);\n        len = r1->len;\n        is_wide_char = r1->is_wide_char;\n        depth = r1->depth;\n    }\n\n    if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {\n        JSString *p2 = JS_VALUE_GET_STRING(op2);\n        len += p2->len;\n        is_wide_char |= p2->is_wide_char;\n    } else {\n        JSStringRope *r2 = JS_VALUE_GET_STRING_ROPE(op2);\n        len += r2->len;\n        is_wide_char |= r2->is_wide_char;\n        depth = max_int(depth, r2->depth);\n    }\n    if (len > JS_STRING_LEN_MAX) {\n        JS_ThrowInternalError(ctx, \"string too long\");\n        goto fail;\n    }\n    r = js_malloc(ctx, sizeof(*r));\n    if (!r)\n        goto fail;\n    r->header.ref_count = 1;\n    r->len = len;\n    r->is_wide_char = is_wide_char;\n    r->depth = depth + 1;\n    r->left = op1;\n    r->right = op2;\n    res = JS_MKPTR(JS_TAG_STRING_ROPE, r);\n    if (r->depth > JS_STRING_ROPE_MAX_DEPTH) {\n        JSValue res2;\n#ifdef DUMP_ROPE_REBALANCE\n        printf(\"rebalance: initial depth=%d\\n\", r->depth);\n#endif\n        res2 = js_rebalancee_string_rope(ctx, res);\n#ifdef DUMP_ROPE_REBALANCE\n        if (JS_VALUE_GET_TAG(res2) == JS_TAG_STRING_ROPE) \n            printf(\"rebalance: final depth=%d\\n\", JS_VALUE_GET_STRING_ROPE(res2)->depth);\n#endif\n        JS_FreeValue(ctx, res);\n        return res2;\n    } else {\n        return res;\n    }\n fail:\n    JS_FreeValue(ctx, op1);\n    JS_FreeValue(ctx, op2);\n    return JS_EXCEPTION;\n}\n\n#define ROPE_N_BUCKETS 44\n\n/* Fibonacii numbers starting from F_2 */\nstatic const uint32_t rope_bucket_len[ROPE_N_BUCKETS] = {\n          1,          2,          3,          5,\n          8,         13,         21,         34,\n         55,         89,        144,        233,\n        377,        610,        987,       1597,\n       2584,       4181,       6765,      10946,\n      17711,      28657,      46368,      75025,\n     121393,     196418,     317811,     514229,\n     832040,    1346269,    2178309,    3524578,\n    5702887,    9227465,   14930352,   24157817,\n   39088169,   63245986,  102334155,  165580141,\n  267914296,  433494437,  701408733, 1134903170, /* > JS_STRING_LEN_MAX */\n};\n\nstatic int js_rebalancee_string_rope_rec(JSContext *ctx, JSValue *buckets,\n                                          JSValueConst val)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {\n        JSString *p = JS_VALUE_GET_STRING(val);\n        uint32_t len, i;\n        JSValue a, b;\n        \n        len = p->len;\n        if (len == 0)\n            return 0; /* nothing to do */\n        /* find the bucket i so that rope_bucket_len[i] <= len <\n           rope_bucket_len[i + 1] and concatenate the ropes in the\n           buckets before */\n        a = JS_NULL;\n        i = 0;\n        while (len >= rope_bucket_len[i + 1]) {\n            b = buckets[i];\n            if (!JS_IsNull(b)) {\n                buckets[i] = JS_NULL;\n                if (JS_IsNull(a)) {\n                    a = b;\n                } else {\n                    a = js_new_string_rope(ctx, b, a);\n                    if (JS_IsException(a))\n                        return -1;\n                }\n            }\n            i++;\n        }\n        if (!JS_IsNull(a)) {\n            a = js_new_string_rope(ctx, a, JS_DupValue(ctx, val));\n            if (JS_IsException(a))\n                return -1;\n        } else {\n            a = JS_DupValue(ctx, val);\n        }\n        while (!JS_IsNull(buckets[i])) {\n            a = js_new_string_rope(ctx, buckets[i], a);\n            buckets[i] = JS_NULL;\n            if (JS_IsException(a))\n                return -1;\n            i++;\n        }\n        buckets[i] = a;\n    } else {\n        JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);\n        js_rebalancee_string_rope_rec(ctx, buckets, r->left);\n        js_rebalancee_string_rope_rec(ctx, buckets, r->right);\n    }\n    return 0;\n}\n\n/* Return a new rope which is balanced. Algorithm from \"Ropes: an\n   Alternative to Strings\", Hans-J. Boehm, Russ Atkinson and Michael\n   Plass. */\nstatic JSValue js_rebalancee_string_rope(JSContext *ctx, JSValueConst rope)\n{\n    JSValue buckets[ROPE_N_BUCKETS], a, b;\n    int i;\n    \n    for(i = 0; i < ROPE_N_BUCKETS; i++)\n        buckets[i] = JS_NULL;\n    if (js_rebalancee_string_rope_rec(ctx, buckets, rope))\n        goto fail;\n    a = JS_NULL;\n    for(i = 0; i < ROPE_N_BUCKETS; i++) {\n        b = buckets[i];\n        if (!JS_IsNull(b)) {\n            buckets[i] = JS_NULL;\n            if (JS_IsNull(a)) {\n                a = b;\n            } else {\n                a = js_new_string_rope(ctx, b, a);\n                if (JS_IsException(a))\n                    goto fail;\n            }\n        }\n    }\n    /* fail safe */\n    if (JS_IsNull(a))\n        return JS_AtomToString(ctx, JS_ATOM_empty_string);\n    else\n        return a;\n fail:\n    for(i = 0; i < ROPE_N_BUCKETS; i++) {\n        JS_FreeValue(ctx, buckets[i]);\n    }\n    return JS_EXCEPTION;\n}\n\n/* op1 and op2 are converted to strings. For convenience, op1 or op2 =\n   JS_EXCEPTION are accepted and return JS_EXCEPTION.  */\nstatic JSValue JS_ConcatString(JSContext *ctx, JSValue op1, JSValue op2)\n{\n    JSString *p1, *p2;\n\n    if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_STRING &&\n                 JS_VALUE_GET_TAG(op1) != JS_TAG_STRING_ROPE)) {\n        op1 = JS_ToStringFree(ctx, op1);\n        if (JS_IsException(op1)) {\n            JS_FreeValue(ctx, op2);\n            return JS_EXCEPTION;\n        }\n    }\n    if (unlikely(JS_VALUE_GET_TAG(op2) != JS_TAG_STRING &&\n                 JS_VALUE_GET_TAG(op2) != JS_TAG_STRING_ROPE)) {\n        op2 = JS_ToStringFree(ctx, op2);\n        if (JS_IsException(op2)) {\n            JS_FreeValue(ctx, op1);\n            return JS_EXCEPTION;\n        }\n    }\n\n    /* normal concatenation for short strings */\n    if (JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {\n        p2 = JS_VALUE_GET_STRING(op2);\n        if (p2->len == 0) {\n            JS_FreeValue(ctx, op2);\n            return op1;\n        }\n        if (p2->len <= JS_STRING_ROPE_SHORT_LEN) {\n            if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {\n                p1 = JS_VALUE_GET_STRING(op1);\n                if (p1->len <= JS_STRING_ROPE_SHORT2_LEN) {\n                    return JS_ConcatString2(ctx, op1, op2);\n                } else {\n                    return js_new_string_rope(ctx, op1, op2);\n                }\n            } else {\n                JSStringRope *r1;\n                r1 = JS_VALUE_GET_STRING_ROPE(op1);\n                if (JS_VALUE_GET_TAG(r1->right) == JS_TAG_STRING &&\n                    JS_VALUE_GET_STRING(r1->right)->len <= JS_STRING_ROPE_SHORT_LEN) {\n                    JSValue val, ret;\n                    val = JS_ConcatString2(ctx, JS_DupValue(ctx, r1->right), op2);\n                    if (JS_IsException(val)) {\n                        JS_FreeValue(ctx, op1);\n                        return JS_EXCEPTION;\n                    }\n                    ret = js_new_string_rope(ctx, JS_DupValue(ctx, r1->left), val);\n                    JS_FreeValue(ctx, op1);\n                    return ret;\n                }\n            }\n        }\n    } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_STRING) {\n        JSStringRope *r2;\n        p1 = JS_VALUE_GET_STRING(op1);\n        if (p1->len == 0) {\n            JS_FreeValue(ctx, op1);\n            return op2;\n        }\n        r2 = JS_VALUE_GET_STRING_ROPE(op2);\n        if (JS_VALUE_GET_TAG(r2->left) == JS_TAG_STRING &&\n            JS_VALUE_GET_STRING(r2->left)->len <= JS_STRING_ROPE_SHORT_LEN) {\n            JSValue val, ret;\n            val = JS_ConcatString2(ctx, op1, JS_DupValue(ctx, r2->left));\n            if (JS_IsException(val)) {\n                JS_FreeValue(ctx, op2);\n                return JS_EXCEPTION;\n            }\n            ret = js_new_string_rope(ctx, val, JS_DupValue(ctx, r2->right));\n            JS_FreeValue(ctx, op2);\n            return ret;\n        }\n    }\n    return js_new_string_rope(ctx, op1, op2);\n}\n\n/* Shape support */\n\nstatic inline size_t get_shape_size(size_t hash_size, size_t prop_size)\n{\n    return hash_size * sizeof(uint32_t) + sizeof(JSShape) +\n        prop_size * sizeof(JSShapeProperty);\n}\n\nstatic inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size)\n{\n    return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size);\n}\n\nstatic inline uint32_t *prop_hash_end(JSShape *sh)\n{\n    return (uint32_t *)sh;\n}\n\nstatic inline void *get_alloc_from_shape(JSShape *sh)\n{\n    return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1);\n}\n\nstatic inline JSShapeProperty *get_shape_prop(JSShape *sh)\n{\n    return sh->prop;\n}\n\nstatic int init_shape_hash(JSRuntime *rt)\n{\n    rt->shape_hash_bits = 4;   /* 16 shapes */\n    rt->shape_hash_size = 1 << rt->shape_hash_bits;\n    rt->shape_hash_count = 0;\n    rt->shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *\n                                   rt->shape_hash_size);\n    if (!rt->shape_hash)\n        return -1;\n    return 0;\n}\n\n/* same magic hash multiplier as the Linux kernel */\nstatic uint32_t shape_hash(uint32_t h, uint32_t val)\n{\n    return (h + val) * 0x9e370001;\n}\n\n/* truncate the shape hash to 'hash_bits' bits */\nstatic uint32_t get_shape_hash(uint32_t h, int hash_bits)\n{\n    return h >> (32 - hash_bits);\n}\n\nstatic uint32_t shape_initial_hash(JSObject *proto)\n{\n    uint32_t h;\n    h = shape_hash(1, (uintptr_t)proto);\n    if (sizeof(proto) > 4)\n        h = shape_hash(h, (uint64_t)(uintptr_t)proto >> 32);\n    return h;\n}\n\nstatic int resize_shape_hash(JSRuntime *rt, int new_shape_hash_bits)\n{\n    int new_shape_hash_size, i;\n    uint32_t h;\n    JSShape **new_shape_hash, *sh, *sh_next;\n\n    new_shape_hash_size = 1 << new_shape_hash_bits;\n    new_shape_hash = js_mallocz_rt(rt, sizeof(rt->shape_hash[0]) *\n                                   new_shape_hash_size);\n    if (!new_shape_hash)\n        return -1;\n    for(i = 0; i < rt->shape_hash_size; i++) {\n        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh_next) {\n            sh_next = sh->shape_hash_next;\n            h = get_shape_hash(sh->hash, new_shape_hash_bits);\n            sh->shape_hash_next = new_shape_hash[h];\n            new_shape_hash[h] = sh;\n        }\n    }\n    js_free_rt(rt, rt->shape_hash);\n    rt->shape_hash_bits = new_shape_hash_bits;\n    rt->shape_hash_size = new_shape_hash_size;\n    rt->shape_hash = new_shape_hash;\n    return 0;\n}\n\nstatic void js_shape_hash_link(JSRuntime *rt, JSShape *sh)\n{\n    uint32_t h;\n    h = get_shape_hash(sh->hash, rt->shape_hash_bits);\n    sh->shape_hash_next = rt->shape_hash[h];\n    rt->shape_hash[h] = sh;\n    rt->shape_hash_count++;\n}\n\nstatic void js_shape_hash_unlink(JSRuntime *rt, JSShape *sh)\n{\n    uint32_t h;\n    JSShape **psh;\n\n    h = get_shape_hash(sh->hash, rt->shape_hash_bits);\n    psh = &rt->shape_hash[h];\n    while (*psh != sh)\n        psh = &(*psh)->shape_hash_next;\n    *psh = sh->shape_hash_next;\n    rt->shape_hash_count--;\n}\n\n/* create a new empty shape with prototype 'proto'. It is not hashed */\nstatic inline JSShape *js_new_shape_nohash(JSContext *ctx, JSObject *proto,\n                                           int hash_size, int prop_size)\n{\n    JSRuntime *rt = ctx->rt;\n    void *sh_alloc;\n    JSShape *sh;\n\n    sh_alloc = js_malloc(ctx, get_shape_size(hash_size, prop_size));\n    if (!sh_alloc)\n        return NULL;\n    sh = get_shape_from_alloc(sh_alloc, hash_size);\n    sh->header.ref_count = 1;\n    add_gc_object(rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);\n    if (proto)\n        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto));\n    sh->proto = proto;\n    memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) *\n           hash_size);\n    sh->prop_hash_mask = hash_size - 1;\n    sh->prop_size = prop_size;\n    sh->prop_count = 0;\n    sh->deleted_prop_count = 0;\n    sh->is_hashed = FALSE;\n    return sh;\n}\n\n/* create a new empty shape with prototype 'proto' */\nstatic no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto,\n                                        int hash_size, int prop_size)\n{\n    JSRuntime *rt = ctx->rt;\n    JSShape *sh;\n\n    /* resize the shape hash table if necessary */\n    if (2 * (rt->shape_hash_count + 1) > rt->shape_hash_size) {\n        resize_shape_hash(rt, rt->shape_hash_bits + 1);\n    }\n\n    sh = js_new_shape_nohash(ctx, proto, hash_size, prop_size);\n    if (!sh)\n        return NULL;\n    \n    /* insert in the hash table */\n    sh->hash = shape_initial_hash(proto);\n    sh->is_hashed = TRUE;\n    js_shape_hash_link(ctx->rt, sh);\n    return sh;\n}\n\nstatic JSShape *js_new_shape(JSContext *ctx, JSObject *proto)\n{\n    return js_new_shape2(ctx, proto, JS_PROP_INITIAL_HASH_SIZE,\n                         JS_PROP_INITIAL_SIZE);\n}\n\n/* The shape is cloned. The new shape is not inserted in the shape\n   hash table */\nstatic JSShape *js_clone_shape(JSContext *ctx, JSShape *sh1)\n{\n    JSShape *sh;\n    void *sh_alloc, *sh_alloc1;\n    size_t size;\n    JSShapeProperty *pr;\n    uint32_t i, hash_size;\n\n    hash_size = sh1->prop_hash_mask + 1;\n    size = get_shape_size(hash_size, sh1->prop_size);\n    sh_alloc = js_malloc(ctx, size);\n    if (!sh_alloc)\n        return NULL;\n    sh_alloc1 = get_alloc_from_shape(sh1);\n    memcpy(sh_alloc, sh_alloc1, size);\n    sh = get_shape_from_alloc(sh_alloc, hash_size);\n    sh->header.ref_count = 1;\n    add_gc_object(ctx->rt, &sh->header, JS_GC_OBJ_TYPE_SHAPE);\n    sh->is_hashed = FALSE;\n    if (sh->proto) {\n        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));\n    }\n    for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {\n        JS_DupAtom(ctx, pr->atom);\n    }\n    return sh;\n}\n\nstatic JSShape *js_dup_shape(JSShape *sh)\n{\n    sh->header.ref_count++;\n    return sh;\n}\n\nstatic void js_free_shape0(JSRuntime *rt, JSShape *sh)\n{\n    uint32_t i;\n    JSShapeProperty *pr;\n\n    assert(sh->header.ref_count == 0);\n    if (sh->is_hashed)\n        js_shape_hash_unlink(rt, sh);\n    if (sh->proto != NULL) {\n        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, sh->proto));\n    }\n    pr = get_shape_prop(sh);\n    for(i = 0; i < sh->prop_count; i++) {\n        JS_FreeAtomRT(rt, pr->atom);\n        pr++;\n    }\n    remove_gc_object(&sh->header);\n    js_free_rt(rt, get_alloc_from_shape(sh));\n}\n\nstatic void js_free_shape(JSRuntime *rt, JSShape *sh)\n{\n    if (unlikely(--sh->header.ref_count <= 0)) {\n        js_free_shape0(rt, sh);\n    }\n}\n\nstatic void js_free_shape_null(JSRuntime *rt, JSShape *sh)\n{\n    if (sh)\n        js_free_shape(rt, sh);\n}\n\n/* make space to hold at least 'count' properties */\nstatic no_inline int resize_properties(JSContext *ctx, JSShape **psh,\n                                       JSObject *p, uint32_t count)\n{\n    JSShape *sh;\n    uint32_t new_size, new_hash_size, new_hash_mask, i;\n    JSShapeProperty *pr;\n    void *sh_alloc;\n    intptr_t h;\n    JSShape *old_sh;\n\n    sh = *psh;\n    new_size = max_int(count, sh->prop_size * 3 / 2);\n    /* Reallocate prop array first to avoid crash or size inconsistency\n       in case of memory allocation failure */\n    if (p) {\n        JSProperty *new_prop;\n        new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);\n        if (unlikely(!new_prop))\n            return -1;\n        p->prop = new_prop;\n    }\n    new_hash_size = sh->prop_hash_mask + 1;\n    while (new_hash_size < new_size)\n        new_hash_size = 2 * new_hash_size;\n    /* resize the property shapes. Using js_realloc() is not possible in\n       case the GC runs during the allocation */\n    old_sh = sh;\n    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));\n    if (!sh_alloc)\n        return -1;\n    sh = get_shape_from_alloc(sh_alloc, new_hash_size);\n    list_del(&old_sh->header.link);\n    /* copy all the shape properties */\n    memcpy(sh, old_sh,\n           sizeof(JSShape) + sizeof(sh->prop[0]) * old_sh->prop_count);\n    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);\n\n    if (new_hash_size != (sh->prop_hash_mask + 1)) {\n        /* resize the hash table and the properties */\n        new_hash_mask = new_hash_size - 1;\n        sh->prop_hash_mask = new_hash_mask;\n        memset(prop_hash_end(sh) - new_hash_size, 0,\n               sizeof(prop_hash_end(sh)[0]) * new_hash_size);\n        for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) {\n            if (pr->atom != JS_ATOM_NULL) {\n                h = ((uintptr_t)pr->atom & new_hash_mask);\n                pr->hash_next = prop_hash_end(sh)[-h - 1];\n                prop_hash_end(sh)[-h - 1] = i + 1;\n            }\n        }\n    } else {\n        /* just copy the previous hash table */\n        memcpy(prop_hash_end(sh) - new_hash_size, prop_hash_end(old_sh) - new_hash_size,\n               sizeof(prop_hash_end(sh)[0]) * new_hash_size);\n    }\n    js_free(ctx, get_alloc_from_shape(old_sh));\n    *psh = sh;\n    sh->prop_size = new_size;\n    return 0;\n}\n\n/* remove the deleted properties. */\nstatic int compact_properties(JSContext *ctx, JSObject *p)\n{\n    JSShape *sh, *old_sh;\n    void *sh_alloc;\n    intptr_t h;\n    uint32_t new_hash_size, i, j, new_hash_mask, new_size;\n    JSShapeProperty *old_pr, *pr;\n    JSProperty *prop, *new_prop;\n\n    sh = p->shape;\n    assert(!sh->is_hashed);\n\n    new_size = max_int(JS_PROP_INITIAL_SIZE,\n                       sh->prop_count - sh->deleted_prop_count);\n    assert(new_size <= sh->prop_size);\n\n    new_hash_size = sh->prop_hash_mask + 1;\n    while ((new_hash_size / 2) >= new_size)\n        new_hash_size = new_hash_size / 2;\n    new_hash_mask = new_hash_size - 1;\n\n    /* resize the hash table and the properties */\n    old_sh = sh;\n    sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));\n    if (!sh_alloc)\n        return -1;\n    sh = get_shape_from_alloc(sh_alloc, new_hash_size);\n    list_del(&old_sh->header.link);\n    memcpy(sh, old_sh, sizeof(JSShape));\n    list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);\n\n    memset(prop_hash_end(sh) - new_hash_size, 0,\n           sizeof(prop_hash_end(sh)[0]) * new_hash_size);\n\n    j = 0;\n    old_pr = old_sh->prop;\n    pr = sh->prop;\n    prop = p->prop;\n    for(i = 0; i < sh->prop_count; i++) {\n        if (old_pr->atom != JS_ATOM_NULL) {\n            pr->atom = old_pr->atom;\n            pr->flags = old_pr->flags;\n            h = ((uintptr_t)old_pr->atom & new_hash_mask);\n            pr->hash_next = prop_hash_end(sh)[-h - 1];\n            prop_hash_end(sh)[-h - 1] = j + 1;\n            prop[j] = prop[i];\n            j++;\n            pr++;\n        }\n        old_pr++;\n    }\n    assert(j == (sh->prop_count - sh->deleted_prop_count));\n    sh->prop_hash_mask = new_hash_mask;\n    sh->prop_size = new_size;\n    sh->deleted_prop_count = 0;\n    sh->prop_count = j;\n\n    p->shape = sh;\n    js_free(ctx, get_alloc_from_shape(old_sh));\n\n    /* reduce the size of the object properties */\n    new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);\n    if (new_prop)\n        p->prop = new_prop;\n    return 0;\n}\n\nstatic int add_shape_property(JSContext *ctx, JSShape **psh,\n                              JSObject *p, JSAtom atom, int prop_flags)\n{\n    JSRuntime *rt = ctx->rt;\n    JSShape *sh = *psh;\n    JSShapeProperty *pr, *prop;\n    uint32_t hash_mask, new_shape_hash = 0;\n    intptr_t h;\n\n    /* update the shape hash */\n    if (sh->is_hashed) {\n        js_shape_hash_unlink(rt, sh);\n        new_shape_hash = shape_hash(shape_hash(sh->hash, atom), prop_flags);\n    }\n\n    if (unlikely(sh->prop_count >= sh->prop_size)) {\n        if (resize_properties(ctx, psh, p, sh->prop_count + 1)) {\n            /* in case of error, reinsert in the hash table.\n               sh is still valid if resize_properties() failed */\n            if (sh->is_hashed)\n                js_shape_hash_link(rt, sh);\n            return -1;\n        }\n        sh = *psh;\n    }\n    if (sh->is_hashed) {\n        sh->hash = new_shape_hash;\n        js_shape_hash_link(rt, sh);\n    }\n    /* Initialize the new shape property.\n       The object property at p->prop[sh->prop_count] is uninitialized */\n    prop = get_shape_prop(sh);\n    pr = &prop[sh->prop_count++];\n    pr->atom = JS_DupAtom(ctx, atom);\n    pr->flags = prop_flags;\n    /* add in hash table */\n    hash_mask = sh->prop_hash_mask;\n    h = atom & hash_mask;\n    pr->hash_next = prop_hash_end(sh)[-h - 1];\n    prop_hash_end(sh)[-h - 1] = sh->prop_count;\n    return 0;\n}\n\n/* find a hashed empty shape matching the prototype. Return NULL if\n   not found */\nstatic JSShape *find_hashed_shape_proto(JSRuntime *rt, JSObject *proto)\n{\n    JSShape *sh1;\n    uint32_t h, h1;\n\n    h = shape_initial_hash(proto);\n    h1 = get_shape_hash(h, rt->shape_hash_bits);\n    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {\n        if (sh1->hash == h &&\n            sh1->proto == proto &&\n            sh1->prop_count == 0) {\n            return sh1;\n        }\n    }\n    return NULL;\n}\n\n/* find a hashed shape matching sh + (prop, prop_flags). Return NULL if\n   not found */\nstatic JSShape *find_hashed_shape_prop(JSRuntime *rt, JSShape *sh,\n                                       JSAtom atom, int prop_flags)\n{\n    JSShape *sh1;\n    uint32_t h, h1, i, n;\n\n    h = sh->hash;\n    h = shape_hash(h, atom);\n    h = shape_hash(h, prop_flags);\n    h1 = get_shape_hash(h, rt->shape_hash_bits);\n    for(sh1 = rt->shape_hash[h1]; sh1 != NULL; sh1 = sh1->shape_hash_next) {\n        /* we test the hash first so that the rest is done only if the\n           shapes really match */\n        if (sh1->hash == h &&\n            sh1->proto == sh->proto &&\n            sh1->prop_count == ((n = sh->prop_count) + 1)) {\n            for(i = 0; i < n; i++) {\n                if (unlikely(sh1->prop[i].atom != sh->prop[i].atom) ||\n                    unlikely(sh1->prop[i].flags != sh->prop[i].flags))\n                    goto next;\n            }\n            if (unlikely(sh1->prop[n].atom != atom) ||\n                unlikely(sh1->prop[n].flags != prop_flags))\n                goto next;\n            return sh1;\n        }\n    next: ;\n    }\n    return NULL;\n}\n\nstatic __maybe_unused void JS_DumpShape(JSRuntime *rt, int i, JSShape *sh)\n{\n    char atom_buf[ATOM_GET_STR_BUF_SIZE];\n    int j;\n\n    /* XXX: should output readable class prototype */\n    printf(\"%5d %3d%c %14p %5d %5d\", i,\n           sh->header.ref_count, \" *\"[sh->is_hashed],\n           (void *)sh->proto, sh->prop_size, sh->prop_count);\n    for(j = 0; j < sh->prop_count; j++) {\n        printf(\" %s\", JS_AtomGetStrRT(rt, atom_buf, sizeof(atom_buf),\n                                      sh->prop[j].atom));\n    }\n    printf(\"\\n\");\n}\n\nstatic __maybe_unused void JS_DumpShapes(JSRuntime *rt)\n{\n    int i;\n    JSShape *sh;\n    struct list_head *el;\n    JSObject *p;\n    JSGCObjectHeader *gp;\n\n    printf(\"JSShapes: {\\n\");\n    printf(\"%5s %4s %14s %5s %5s %s\\n\", \"SLOT\", \"REFS\", \"PROTO\", \"SIZE\", \"COUNT\", \"PROPS\");\n    for(i = 0; i < rt->shape_hash_size; i++) {\n        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {\n            JS_DumpShape(rt, i, sh);\n            assert(sh->is_hashed);\n        }\n    }\n    /* dump non-hashed shapes */\n    list_for_each(el, &rt->gc_obj_list) {\n        gp = list_entry(el, JSGCObjectHeader, link);\n        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {\n            p = (JSObject *)gp;\n            if (!p->shape->is_hashed) {\n                JS_DumpShape(rt, -1, p->shape);\n            }\n        }\n    }\n    printf(\"}\\n\");\n}\n\n/* 'props[]' is used to initialized the object properties. The number\n   of elements depends on the shape. */\nstatic JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID class_id,\n                                     JSProperty *props)\n{\n    JSObject *p;\n    int i;\n    \n    js_trigger_gc(ctx->rt, sizeof(JSObject));\n    p = js_malloc(ctx, sizeof(JSObject));\n    if (unlikely(!p))\n        goto fail;\n    p->class_id = class_id;\n    p->is_std_array_prototype = 0;\n    p->extensible = TRUE;\n    p->free_mark = 0;\n    p->is_exotic = 0;\n    p->fast_array = 0;\n    p->is_constructor = 0;\n    p->has_immutable_prototype = 0;\n    p->tmp_mark = 0;\n    p->is_HTMLDDA = 0;\n    p->weakref_count = 0;\n    p->u.opaque = NULL;\n    p->shape = sh;\n    p->prop = js_malloc(ctx, sizeof(JSProperty) * sh->prop_size);\n    if (unlikely(!p->prop)) {\n        js_free(ctx, p);\n    fail:\n        if (props) {\n            JSShapeProperty *prs = get_shape_prop(sh);\n            for(i = 0; i < sh->prop_count; i++) {\n                free_property(ctx->rt, &props[i], prs->flags);\n                prs++;\n            }\n        }\n        js_free_shape(ctx->rt, sh);\n        return JS_EXCEPTION;\n    }\n\n    switch(class_id) {\n    case JS_CLASS_OBJECT:\n        break;\n    case JS_CLASS_ARRAY:\n        {\n            JSProperty *pr;\n            p->is_exotic = 1;\n            p->fast_array = 1;\n            p->u.array.u.values = NULL;\n            p->u.array.count = 0;\n            p->u.array.u1.size = 0;\n            if (!props) {\n                /* XXX: remove */\n                /* the length property is always the first one */\n                if (likely(sh == ctx->array_shape)) {\n                    pr = &p->prop[0];\n                } else {\n                    /* only used for the first array */\n                    /* cannot fail */\n                    pr = add_property(ctx, p, JS_ATOM_length,\n                                      JS_PROP_WRITABLE | JS_PROP_LENGTH);\n                }\n                pr->u.value = JS_NewInt32(ctx, 0);\n            }\n        }\n        break;\n    case JS_CLASS_C_FUNCTION:\n        p->prop[0].u.value = JS_UNDEFINED;\n        break;\n    case JS_CLASS_ARGUMENTS:\n    case JS_CLASS_MAPPED_ARGUMENTS:\n    case JS_CLASS_UINT8C_ARRAY:\n    case JS_CLASS_INT8_ARRAY:\n    case JS_CLASS_UINT8_ARRAY:\n    case JS_CLASS_INT16_ARRAY:\n    case JS_CLASS_UINT16_ARRAY:\n    case JS_CLASS_INT32_ARRAY:\n    case JS_CLASS_UINT32_ARRAY:\n    case JS_CLASS_BIG_INT64_ARRAY:\n    case JS_CLASS_BIG_UINT64_ARRAY:\n    case JS_CLASS_FLOAT16_ARRAY:\n    case JS_CLASS_FLOAT32_ARRAY:\n    case JS_CLASS_FLOAT64_ARRAY:\n        p->is_exotic = 1;\n        p->fast_array = 1;\n        p->u.array.u.ptr = NULL;\n        p->u.array.count = 0;\n        break;\n    case JS_CLASS_DATAVIEW:\n        p->u.array.u.ptr = NULL;\n        p->u.array.count = 0;\n        break;\n    case JS_CLASS_NUMBER:\n    case JS_CLASS_STRING:\n    case JS_CLASS_BOOLEAN:\n    case JS_CLASS_SYMBOL:\n    case JS_CLASS_DATE:\n    case JS_CLASS_BIG_INT:\n        p->u.object_data = JS_UNDEFINED;\n        goto set_exotic;\n    case JS_CLASS_REGEXP:\n        p->u.regexp.pattern = NULL;\n        p->u.regexp.bytecode = NULL;\n        break;\n    case JS_CLASS_GLOBAL_OBJECT:\n        p->u.global_object.uninitialized_vars = JS_UNDEFINED;\n        break;\n    default:\n    set_exotic:\n        if (ctx->rt->class_array[class_id].exotic) {\n            p->is_exotic = 1;\n        }\n        break;\n    }\n    p->header.ref_count = 1;\n    add_gc_object(ctx->rt, &p->header, JS_GC_OBJ_TYPE_JS_OBJECT);\n    if (props) {\n        for(i = 0; i < sh->prop_count; i++)\n            p->prop[i] = props[i];\n    }\n    return JS_MKPTR(JS_TAG_OBJECT, p);\n}\n\nstatic JSObject *get_proto_obj(JSValueConst proto_val)\n{\n    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT)\n        return NULL;\n    else\n        return JS_VALUE_GET_OBJ(proto_val);\n}\n\n/* WARNING: proto must be an object or JS_NULL */\nJSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto_val,\n                               JSClassID class_id)\n{\n    JSShape *sh;\n    JSObject *proto;\n\n    proto = get_proto_obj(proto_val);\n    sh = find_hashed_shape_proto(ctx->rt, proto);\n    if (likely(sh)) {\n        sh = js_dup_shape(sh);\n    } else {\n        sh = js_new_shape(ctx, proto);\n        if (!sh)\n            return JS_EXCEPTION;\n    }\n    return JS_NewObjectFromShape(ctx, sh, class_id, NULL);\n}\n\n/* WARNING: the shape is not hashed. It is used for objects where\n   factorizing the shape is not relevant (prototypes, constructors) */\nstatic JSValue JS_NewObjectProtoClassAlloc(JSContext *ctx, JSValueConst proto_val,\n                                           JSClassID class_id, int n_alloc_props)\n{\n    JSShape *sh;\n    JSObject *proto;\n    int hash_size, hash_bits;\n    \n    if (n_alloc_props <= JS_PROP_INITIAL_SIZE) {\n        n_alloc_props = JS_PROP_INITIAL_SIZE;\n        hash_size = JS_PROP_INITIAL_HASH_SIZE;\n    } else {\n        hash_bits = 32 - clz32(n_alloc_props - 1); /* ceil(log2(radix)) */\n        hash_size = 1 << hash_bits;\n    }\n    proto = get_proto_obj(proto_val);\n    sh = js_new_shape_nohash(ctx, proto, hash_size, n_alloc_props);\n    if (!sh)\n        return JS_EXCEPTION;\n    return JS_NewObjectFromShape(ctx, sh, class_id, NULL);\n}\n\n#if 0\nstatic JSValue JS_GetObjectData(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        p = JS_VALUE_GET_OBJ(obj);\n        switch(p->class_id) {\n        case JS_CLASS_NUMBER:\n        case JS_CLASS_STRING:\n        case JS_CLASS_BOOLEAN:\n        case JS_CLASS_SYMBOL:\n        case JS_CLASS_DATE:\n        case JS_CLASS_BIG_INT:\n            return JS_DupValue(ctx, p->u.object_data);\n        }\n    }\n    return JS_UNDEFINED;\n}\n#endif\n\nstatic int JS_SetObjectData(JSContext *ctx, JSValueConst obj, JSValue val)\n{\n    JSObject *p;\n\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        p = JS_VALUE_GET_OBJ(obj);\n        switch(p->class_id) {\n        case JS_CLASS_NUMBER:\n        case JS_CLASS_STRING:\n        case JS_CLASS_BOOLEAN:\n        case JS_CLASS_SYMBOL:\n        case JS_CLASS_DATE:\n        case JS_CLASS_BIG_INT:\n            JS_FreeValue(ctx, p->u.object_data);\n            p->u.object_data = val; /* for JS_CLASS_STRING, 'val' must\n                                       be JS_TAG_STRING (and not a\n                                       rope) */\n            return 0;\n        }\n    }\n    JS_FreeValue(ctx, val);\n    if (!JS_IsException(obj))\n        JS_ThrowTypeError(ctx, \"invalid object type\");\n    return -1;\n}\n\nJSValue JS_NewObjectClass(JSContext *ctx, int class_id)\n{\n    return JS_NewObjectProtoClass(ctx, ctx->class_proto[class_id], class_id);\n}\n\nJSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto)\n{\n    return JS_NewObjectProtoClass(ctx, proto, JS_CLASS_OBJECT);\n}\n\nJSValue JS_NewArray(JSContext *ctx)\n{\n    return JS_NewObjectFromShape(ctx, js_dup_shape(ctx->array_shape),\n                                 JS_CLASS_ARRAY, NULL);\n}\n\nJSValue JS_NewObject(JSContext *ctx)\n{\n    /* inline JS_NewObjectClass(ctx, JS_CLASS_OBJECT); */\n    return JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_OBJECT], JS_CLASS_OBJECT);\n}\n\nstatic void js_function_set_properties(JSContext *ctx, JSValueConst func_obj,\n                                       JSAtom name, int len)\n{\n    /* ES6 feature non compatible with ES5.1: length is configurable */\n    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, JS_NewInt32(ctx, len),\n                           JS_PROP_CONFIGURABLE);\n    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name,\n                           JS_AtomToString(ctx, name), JS_PROP_CONFIGURABLE);\n}\n\nstatic BOOL js_class_has_bytecode(JSClassID class_id)\n{\n    return (class_id == JS_CLASS_BYTECODE_FUNCTION ||\n            class_id == JS_CLASS_GENERATOR_FUNCTION ||\n            class_id == JS_CLASS_ASYNC_FUNCTION ||\n            class_id == JS_CLASS_ASYNC_GENERATOR_FUNCTION);\n}\n\n/* return NULL without exception if not a function or no bytecode */\nstatic JSFunctionBytecode *JS_GetFunctionBytecode(JSValueConst val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)\n        return NULL;\n    p = JS_VALUE_GET_OBJ(val);\n    if (!js_class_has_bytecode(p->class_id))\n        return NULL;\n    return p->u.func.function_bytecode;\n}\n\nstatic void js_method_set_home_object(JSContext *ctx, JSValueConst func_obj,\n                                      JSValueConst home_obj)\n{\n    JSObject *p, *p1;\n    JSFunctionBytecode *b;\n\n    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)\n        return;\n    p = JS_VALUE_GET_OBJ(func_obj);\n    if (!js_class_has_bytecode(p->class_id))\n        return;\n    b = p->u.func.function_bytecode;\n    if (b->need_home_object) {\n        p1 = p->u.func.home_object;\n        if (p1) {\n            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));\n        }\n        if (JS_VALUE_GET_TAG(home_obj) == JS_TAG_OBJECT)\n            p1 = JS_VALUE_GET_OBJ(JS_DupValue(ctx, home_obj));\n        else\n            p1 = NULL;\n        p->u.func.home_object = p1;\n    }\n}\n\nstatic JSValue js_get_function_name(JSContext *ctx, JSAtom name)\n{\n    JSValue name_str;\n\n    name_str = JS_AtomToString(ctx, name);\n    if (JS_AtomSymbolHasDescription(ctx, name)) {\n        name_str = JS_ConcatString3(ctx, \"[\", name_str, \"]\");\n    }\n    return name_str;\n}\n\n/* Modify the name of a method according to the atom and\n   'flags'. 'flags' is a bitmask of JS_PROP_HAS_GET and\n   JS_PROP_HAS_SET. Also set the home object of the method.\n   Return < 0 if exception. */\nstatic int js_method_set_properties(JSContext *ctx, JSValueConst func_obj,\n                                    JSAtom name, int flags, JSValueConst home_obj)\n{\n    JSValue name_str;\n\n    name_str = js_get_function_name(ctx, name);\n    if (flags & JS_PROP_HAS_GET) {\n        name_str = JS_ConcatString3(ctx, \"get \", name_str, \"\");\n    } else if (flags & JS_PROP_HAS_SET) {\n        name_str = JS_ConcatString3(ctx, \"set \", name_str, \"\");\n    }\n    if (JS_IsException(name_str))\n        return -1;\n    if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name_str,\n                               JS_PROP_CONFIGURABLE) < 0)\n        return -1;\n    js_method_set_home_object(ctx, func_obj, home_obj);\n    return 0;\n}\n\n/* Note: at least 'length' arguments will be readable in 'argv' */\nstatic JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func,\n                                const char *name,\n                                int length, JSCFunctionEnum cproto, int magic,\n                                JSValueConst proto_val, int n_fields)\n{\n    JSValue func_obj;\n    JSObject *p;\n    JSAtom name_atom;\n\n    if (n_fields > 0) {\n        func_obj = JS_NewObjectProtoClassAlloc(ctx, proto_val, JS_CLASS_C_FUNCTION, n_fields);\n    } else {\n        func_obj = JS_NewObjectProtoClass(ctx, proto_val, JS_CLASS_C_FUNCTION);\n    }\n    if (JS_IsException(func_obj))\n        return func_obj;\n    p = JS_VALUE_GET_OBJ(func_obj);\n    p->u.cfunc.realm = JS_DupContext(ctx);\n    p->u.cfunc.c_function.generic = func;\n    p->u.cfunc.length = length;\n    p->u.cfunc.cproto = cproto;\n    p->u.cfunc.magic = magic;\n    p->is_constructor = (cproto == JS_CFUNC_constructor ||\n                         cproto == JS_CFUNC_constructor_magic ||\n                         cproto == JS_CFUNC_constructor_or_func ||\n                         cproto == JS_CFUNC_constructor_or_func_magic);\n    if (!name)\n        name = \"\";\n    name_atom = JS_NewAtom(ctx, name);\n    if (name_atom == JS_ATOM_NULL) {\n        JS_FreeValue(ctx, func_obj);\n        return JS_EXCEPTION;\n    }\n    js_function_set_properties(ctx, func_obj, name_atom, length);\n    JS_FreeAtom(ctx, name_atom);\n    return func_obj;\n}\n\n/* Note: at least 'length' arguments will be readable in 'argv' */\nJSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,\n                         const char *name,\n                         int length, JSCFunctionEnum cproto, int magic)\n{\n    return JS_NewCFunction3(ctx, func, name, length, cproto, magic,\n                            ctx->function_proto, 0);\n}\n\ntypedef struct JSCFunctionDataRecord {\n    JSCFunctionData *func;\n    uint8_t length;\n    uint8_t data_len;\n    uint16_t magic;\n    JSValue data[0];\n} JSCFunctionDataRecord;\n\nstatic void js_c_function_data_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);\n    int i;\n\n    if (s) {\n        for(i = 0; i < s->data_len; i++) {\n            JS_FreeValueRT(rt, s->data[i]);\n        }\n        js_free_rt(rt, s);\n    }\n}\n\nstatic void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,\n                                    JS_MarkFunc *mark_func)\n{\n    JSCFunctionDataRecord *s = JS_GetOpaque(val, JS_CLASS_C_FUNCTION_DATA);\n    int i;\n\n    if (s) {\n        for(i = 0; i < s->data_len; i++) {\n            JS_MarkValue(rt, s->data[i], mark_func);\n        }\n    }\n}\n\nstatic JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj,\n                                       JSValueConst this_val,\n                                       int argc, JSValueConst *argv, int flags)\n{\n    JSCFunctionDataRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_FUNCTION_DATA);\n    JSValueConst *arg_buf;\n    int i;\n\n    /* XXX: could add the function on the stack for debug */\n    if (unlikely(argc < s->length)) {\n        arg_buf = alloca(sizeof(arg_buf[0]) * s->length);\n        for(i = 0; i < argc; i++)\n            arg_buf[i] = argv[i];\n        for(i = argc; i < s->length; i++)\n            arg_buf[i] = JS_UNDEFINED;\n    } else {\n        arg_buf = argv;\n    }\n\n    return s->func(ctx, this_val, argc, arg_buf, s->magic, s->data);\n}\n\nJSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,\n                            int length, int magic, int data_len,\n                            JSValueConst *data)\n{\n    JSCFunctionDataRecord *s;\n    JSValue func_obj;\n    int i;\n\n    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,\n                                      JS_CLASS_C_FUNCTION_DATA);\n    if (JS_IsException(func_obj))\n        return func_obj;\n    s = js_malloc(ctx, sizeof(*s) + data_len * sizeof(JSValue));\n    if (!s) {\n        JS_FreeValue(ctx, func_obj);\n        return JS_EXCEPTION;\n    }\n    s->func = func;\n    s->length = length;\n    s->data_len = data_len;\n    s->magic = magic;\n    for(i = 0; i < data_len; i++)\n        s->data[i] = JS_DupValue(ctx, data[i]);\n    JS_SetOpaque(func_obj, s);\n    js_function_set_properties(ctx, func_obj,\n                               JS_ATOM_empty_string, length);\n    return func_obj;\n}\n\nstatic JSContext *js_autoinit_get_realm(JSProperty *pr)\n{\n    return (JSContext *)(pr->u.init.realm_and_id & ~3);\n}\n\nstatic JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)\n{\n    return pr->u.init.realm_and_id & 3;\n}\n\nstatic void js_autoinit_free(JSRuntime *rt, JSProperty *pr)\n{\n    JS_FreeContext(js_autoinit_get_realm(pr));\n}\n\nstatic void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,\n                             JS_MarkFunc *mark_func)\n{\n    mark_func(rt, &js_autoinit_get_realm(pr)->header);\n}\n\nstatic void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)\n{\n    if (unlikely(prop_flags & JS_PROP_TMASK)) {\n        if ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n            if (pr->u.getset.getter)\n                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));\n            if (pr->u.getset.setter)\n                JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));\n        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n            free_var_ref(rt, pr->u.var_ref);\n        } else if ((prop_flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n            js_autoinit_free(rt, pr);\n        }\n    } else {\n        JS_FreeValueRT(rt, pr->u.value);\n    }\n}\n\nstatic force_inline JSShapeProperty *find_own_property1(JSObject *p,\n                                                        JSAtom atom)\n{\n    JSShape *sh;\n    JSShapeProperty *pr, *prop;\n    intptr_t h;\n    sh = p->shape;\n    h = (uintptr_t)atom & sh->prop_hash_mask;\n    h = prop_hash_end(sh)[-h - 1];\n    prop = get_shape_prop(sh);\n    while (h) {\n        pr = &prop[h - 1];\n        if (likely(pr->atom == atom)) {\n            return pr;\n        }\n        h = pr->hash_next;\n    }\n    return NULL;\n}\n\nstatic force_inline JSShapeProperty *find_own_property(JSProperty **ppr,\n                                                       JSObject *p,\n                                                       JSAtom atom)\n{\n    JSShape *sh;\n    JSShapeProperty *pr, *prop;\n    intptr_t h;\n    sh = p->shape;\n    h = (uintptr_t)atom & sh->prop_hash_mask;\n    h = prop_hash_end(sh)[-h - 1];\n    prop = get_shape_prop(sh);\n    while (h) {\n        pr = &prop[h - 1];\n        if (likely(pr->atom == atom)) {\n            *ppr = &p->prop[h - 1];\n            /* the compiler should be able to assume that pr != NULL here */\n            return pr;\n        }\n        h = pr->hash_next;\n    }\n    *ppr = NULL;\n    return NULL;\n}\n\n/* indicate that the object may be part of a function prototype cycle */\nstatic void set_cycle_flag(JSContext *ctx, JSValueConst obj)\n{\n}\n\nstatic void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)\n{\n    if (var_ref) {\n        assert(var_ref->header.ref_count > 0);\n        if (--var_ref->header.ref_count == 0) {\n            if (var_ref->is_detached) {\n                JS_FreeValueRT(rt, var_ref->value);\n            } else {\n                JSStackFrame *sf = var_ref->stack_frame;\n                assert(sf->var_refs[var_ref->var_ref_idx] == var_ref);\n                sf->var_refs[var_ref->var_ref_idx] = NULL;\n                if (sf->js_mode & JS_MODE_ASYNC) {\n                    JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);\n                    async_func_free(rt, async_func);\n                }\n            }\n            remove_gc_object(&var_ref->header);\n            js_free_rt(rt, var_ref);\n        }\n    }\n}\n\nstatic void js_array_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    int i;\n\n    for(i = 0; i < p->u.array.count; i++) {\n        JS_FreeValueRT(rt, p->u.array.u.values[i]);\n    }\n    js_free_rt(rt, p->u.array.u.values);\n}\n\nstatic void js_array_mark(JSRuntime *rt, JSValueConst val,\n                          JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    int i;\n\n    for(i = 0; i < p->u.array.count; i++) {\n        JS_MarkValue(rt, p->u.array.u.values[i], mark_func);\n    }\n}\n\nstatic void js_object_data_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JS_FreeValueRT(rt, p->u.object_data);\n    p->u.object_data = JS_UNDEFINED;\n}\n\nstatic void js_object_data_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JS_MarkValue(rt, p->u.object_data, mark_func);\n}\n\nstatic void js_c_function_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n\n    if (p->u.cfunc.realm)\n        JS_FreeContext(p->u.cfunc.realm);\n}\n\nstatic void js_c_function_mark(JSRuntime *rt, JSValueConst val,\n                               JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n\n    if (p->u.cfunc.realm)\n        mark_func(rt, &p->u.cfunc.realm->header);\n}\n\nstatic void js_bytecode_function_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p1, *p = JS_VALUE_GET_OBJ(val);\n    JSFunctionBytecode *b;\n    JSVarRef **var_refs;\n    int i;\n\n    p1 = p->u.func.home_object;\n    if (p1) {\n        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, p1));\n    }\n    b = p->u.func.function_bytecode;\n    if (b) {\n        var_refs = p->u.func.var_refs;\n        if (var_refs) {\n            for(i = 0; i < b->closure_var_count; i++)\n                free_var_ref(rt, var_refs[i]);\n            js_free_rt(rt, var_refs);\n        }\n        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b));\n    }\n}\n\nstatic void js_bytecode_function_mark(JSRuntime *rt, JSValueConst val,\n                                      JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSVarRef **var_refs = p->u.func.var_refs;\n    JSFunctionBytecode *b = p->u.func.function_bytecode;\n    int i;\n\n    if (p->u.func.home_object) {\n        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object),\n                     mark_func);\n    }\n    if (b) {\n        if (var_refs) {\n            for(i = 0; i < b->closure_var_count; i++) {\n                JSVarRef *var_ref = var_refs[i];\n                if (var_ref) {\n                    mark_func(rt, &var_ref->header);\n                }\n            }\n        }\n        /* must mark the function bytecode because template objects may be\n           part of a cycle */\n        JS_MarkValue(rt, JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b), mark_func);\n    }\n}\n\nstatic void js_bound_function_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSBoundFunction *bf = p->u.bound_function;\n    int i;\n\n    JS_FreeValueRT(rt, bf->func_obj);\n    JS_FreeValueRT(rt, bf->this_val);\n    for(i = 0; i < bf->argc; i++) {\n        JS_FreeValueRT(rt, bf->argv[i]);\n    }\n    js_free_rt(rt, bf);\n}\n\nstatic void js_bound_function_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSBoundFunction *bf = p->u.bound_function;\n    int i;\n\n    JS_MarkValue(rt, bf->func_obj, mark_func);\n    JS_MarkValue(rt, bf->this_val, mark_func);\n    for(i = 0; i < bf->argc; i++)\n        JS_MarkValue(rt, bf->argv[i], mark_func);\n}\n\nstatic void js_for_in_iterator_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSForInIterator *it = p->u.for_in_iterator;\n    int i;\n\n    JS_FreeValueRT(rt, it->obj);\n    if (!it->is_array) {\n        for(i = 0; i < it->atom_count; i++) {\n            JS_FreeAtomRT(rt, it->tab_atom[i].atom);\n        }\n        js_free_rt(rt, it->tab_atom);\n    }\n    js_free_rt(rt, it);\n}\n\nstatic void js_for_in_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSForInIterator *it = p->u.for_in_iterator;\n    JS_MarkValue(rt, it->obj, mark_func);\n}\n\nstatic void free_object(JSRuntime *rt, JSObject *p)\n{\n    int i;\n    JSClassFinalizer *finalizer;\n    JSShape *sh;\n    JSShapeProperty *pr;\n\n    p->free_mark = 1; /* used to tell the object is invalid when\n                         freeing cycles */\n    /* free all the fields */\n    sh = p->shape;\n    pr = get_shape_prop(sh);\n    for(i = 0; i < sh->prop_count; i++) {\n        free_property(rt, &p->prop[i], pr->flags);\n        pr++;\n    }\n    js_free_rt(rt, p->prop);\n    /* as an optimization we destroy the shape immediately without\n       putting it in gc_zero_ref_count_list */\n    js_free_shape(rt, sh);\n\n    /* fail safe */\n    p->shape = NULL;\n    p->prop = NULL;\n\n    finalizer = rt->class_array[p->class_id].finalizer;\n    if (finalizer)\n        (*finalizer)(rt, JS_MKPTR(JS_TAG_OBJECT, p));\n\n    /* fail safe */\n    p->class_id = 0;\n    p->u.opaque = NULL;\n    p->u.func.var_refs = NULL;\n    p->u.func.home_object = NULL;\n\n    remove_gc_object(&p->header);\n    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES) {\n        if (p->header.ref_count == 0 && p->weakref_count == 0) {\n            js_free_rt(rt, p);\n        } else {\n            /* keep the object structure because there are may be\n               references to it */\n            list_add_tail(&p->header.link, &rt->gc_zero_ref_count_list);\n        }\n    } else {\n        /* keep the object structure in case there are weak references to it */\n        if (p->weakref_count == 0) {\n            js_free_rt(rt, p);\n        } else {\n            p->header.mark = 0; /* reset the mark so that the weakref can be freed */\n        }\n    }\n}\n\nstatic void free_gc_object(JSRuntime *rt, JSGCObjectHeader *gp)\n{\n    switch(gp->gc_obj_type) {\n    case JS_GC_OBJ_TYPE_JS_OBJECT:\n        free_object(rt, (JSObject *)gp);\n        break;\n    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:\n        free_function_bytecode(rt, (JSFunctionBytecode *)gp);\n        break;\n    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:\n        __async_func_free(rt, (JSAsyncFunctionState *)gp);\n        break;\n    case JS_GC_OBJ_TYPE_MODULE:\n        js_free_module_def(rt, (JSModuleDef *)gp);\n        break;\n    default:\n        abort();\n    }\n}\n\nstatic void free_zero_refcount(JSRuntime *rt)\n{\n    struct list_head *el;\n    JSGCObjectHeader *p;\n\n    rt->gc_phase = JS_GC_PHASE_DECREF;\n    for(;;) {\n        el = rt->gc_zero_ref_count_list.next;\n        if (el == &rt->gc_zero_ref_count_list)\n            break;\n        p = list_entry(el, JSGCObjectHeader, link);\n        assert(p->ref_count == 0);\n        free_gc_object(rt, p);\n    }\n    rt->gc_phase = JS_GC_PHASE_NONE;\n}\n\n/* called with the ref_count of 'v' reaches zero. */\nvoid __JS_FreeValueRT(JSRuntime *rt, JSValue v)\n{\n    uint32_t tag = JS_VALUE_GET_TAG(v);\n\n#ifdef DUMP_FREE\n    {\n        printf(\"Freeing \");\n        if (tag == JS_TAG_OBJECT) {\n            JS_DumpObject(rt, JS_VALUE_GET_OBJ(v));\n        } else {\n            JS_DumpValueShort(rt, v);\n            printf(\"\\n\");\n        }\n    }\n#endif\n\n    switch(tag) {\n    case JS_TAG_STRING:\n        {\n            JSString *p = JS_VALUE_GET_STRING(v);\n            if (p->atom_type) {\n                JS_FreeAtomStruct(rt, p);\n            } else {\n#ifdef DUMP_LEAKS\n                list_del(&p->link);\n#endif\n                js_free_rt(rt, p);\n            }\n        }\n        break;\n    case JS_TAG_STRING_ROPE:\n        /* Note: recursion is acceptable because the rope depth is bounded */\n        {\n            JSStringRope *p = JS_VALUE_GET_STRING_ROPE(v);\n            JS_FreeValueRT(rt, p->left);\n            JS_FreeValueRT(rt, p->right);\n            js_free_rt(rt, p);\n        }\n        break;\n    case JS_TAG_OBJECT:\n    case JS_TAG_FUNCTION_BYTECODE:\n    case JS_TAG_MODULE:\n        {\n            JSGCObjectHeader *p = JS_VALUE_GET_PTR(v);\n            if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {\n                list_del(&p->link);\n                list_add(&p->link, &rt->gc_zero_ref_count_list);\n                p->mark = 1; /* indicate that the object is about to be freed */\n                if (rt->gc_phase == JS_GC_PHASE_NONE) {\n                    free_zero_refcount(rt);\n                }\n            }\n        }\n        break;\n    case JS_TAG_BIG_INT:\n        {\n            JSBigInt *p = JS_VALUE_GET_PTR(v);\n            js_free_rt(rt, p);\n        }\n        break;\n    case JS_TAG_SYMBOL:\n        {\n            JSAtomStruct *p = JS_VALUE_GET_PTR(v);\n            JS_FreeAtomStruct(rt, p);\n        }\n        break;\n    default:\n        abort();\n    }\n}\n\nvoid __JS_FreeValue(JSContext *ctx, JSValue v)\n{\n    __JS_FreeValueRT(ctx->rt, v);\n}\n\n/* garbage collection */\n\nstatic void gc_remove_weak_objects(JSRuntime *rt)\n{\n    struct list_head *el;\n\n    /* add the freed objects to rt->gc_zero_ref_count_list so that\n       rt->weakref_list is not modified while we traverse it */\n    rt->gc_phase = JS_GC_PHASE_DECREF; \n        \n    list_for_each(el, &rt->weakref_list) {\n        JSWeakRefHeader *wh = list_entry(el, JSWeakRefHeader, link);\n        switch(wh->weakref_type) {\n        case JS_WEAKREF_TYPE_MAP:\n            map_delete_weakrefs(rt, wh);\n            break;\n        case JS_WEAKREF_TYPE_WEAKREF:\n            weakref_delete_weakref(rt, wh);\n            break;\n        case JS_WEAKREF_TYPE_FINREC:\n            finrec_delete_weakref(rt, wh);\n            break;\n        default:\n            abort();\n        }\n    }\n\n    rt->gc_phase = JS_GC_PHASE_NONE;\n    /* free the freed objects here. */\n    free_zero_refcount(rt);\n}\n\nstatic void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,\n                          JSGCObjectTypeEnum type)\n{\n    h->mark = 0;\n    h->gc_obj_type = type;\n    list_add_tail(&h->link, &rt->gc_obj_list);\n}\n\nstatic void remove_gc_object(JSGCObjectHeader *h)\n{\n    list_del(&h->link);\n}\n\nvoid JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)\n{\n    if (JS_VALUE_HAS_REF_COUNT(val)) {\n        switch(JS_VALUE_GET_TAG(val)) {\n        case JS_TAG_OBJECT:\n        case JS_TAG_FUNCTION_BYTECODE:\n        case JS_TAG_MODULE:\n            mark_func(rt, JS_VALUE_GET_PTR(val));\n            break;\n        default:\n            break;\n        }\n    }\n}\n\nstatic void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,\n                          JS_MarkFunc *mark_func)\n{\n    switch(gp->gc_obj_type) {\n    case JS_GC_OBJ_TYPE_JS_OBJECT:\n        {\n            JSObject *p = (JSObject *)gp;\n            JSShapeProperty *prs;\n            JSShape *sh;\n            int i;\n            sh = p->shape;\n            mark_func(rt, &sh->header);\n            /* mark all the fields */\n            prs = get_shape_prop(sh);\n            for(i = 0; i < sh->prop_count; i++) {\n                JSProperty *pr = &p->prop[i];\n                if (prs->atom != JS_ATOM_NULL) {\n                    if (prs->flags & JS_PROP_TMASK) {\n                        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                            if (pr->u.getset.getter)\n                                mark_func(rt, &pr->u.getset.getter->header);\n                            if (pr->u.getset.setter)\n                                mark_func(rt, &pr->u.getset.setter->header);\n                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n                            /* Note: the tag does not matter\n                               provided it is a GC object */\n                            mark_func(rt, &pr->u.var_ref->header);\n                        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n                            js_autoinit_mark(rt, pr, mark_func);\n                        }\n                    } else {\n                        JS_MarkValue(rt, pr->u.value, mark_func);\n                    }\n                }\n                prs++;\n            }\n\n            if (p->class_id != JS_CLASS_OBJECT) {\n                JSClassGCMark *gc_mark;\n                gc_mark = rt->class_array[p->class_id].gc_mark;\n                if (gc_mark)\n                    gc_mark(rt, JS_MKPTR(JS_TAG_OBJECT, p), mark_func);\n            }\n        }\n        break;\n    case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:\n        /* the template objects can be part of a cycle */\n        {\n            JSFunctionBytecode *b = (JSFunctionBytecode *)gp;\n            int i;\n            for(i = 0; i < b->cpool_count; i++) {\n                JS_MarkValue(rt, b->cpool[i], mark_func);\n            }\n            if (b->realm)\n                mark_func(rt, &b->realm->header);\n        }\n        break;\n    case JS_GC_OBJ_TYPE_VAR_REF:\n        {\n            JSVarRef *var_ref = (JSVarRef *)gp;\n            if (var_ref->is_detached) {\n                JS_MarkValue(rt, *var_ref->pvalue, mark_func);\n            } else {\n                JSStackFrame *sf = var_ref->stack_frame;\n                if (sf->js_mode & JS_MODE_ASYNC) {\n                    JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);\n                    mark_func(rt, &async_func->header);\n                }\n            }\n        }\n        break;\n    case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:\n        {\n            JSAsyncFunctionState *s = (JSAsyncFunctionState *)gp;\n            JSStackFrame *sf = &s->frame;\n            JSValue *sp;\n\n            if (!s->is_completed) {\n                JS_MarkValue(rt, sf->cur_func, mark_func);\n                JS_MarkValue(rt, s->this_val, mark_func);\n                /* sf->cur_sp = NULL if the function is running */\n                if (sf->cur_sp) {\n                    /* if the function is running, cur_sp is not known so we\n                       cannot mark the stack. Marking the variables is not needed\n                       because a running function cannot be part of a removable\n                       cycle */\n                    for(sp = sf->arg_buf; sp < sf->cur_sp; sp++)\n                        JS_MarkValue(rt, *sp, mark_func);\n                }\n            }\n            JS_MarkValue(rt, s->resolving_funcs[0], mark_func);\n            JS_MarkValue(rt, s->resolving_funcs[1], mark_func);\n        }\n        break;\n    case JS_GC_OBJ_TYPE_SHAPE:\n        {\n            JSShape *sh = (JSShape *)gp;\n            if (sh->proto != NULL) {\n                mark_func(rt, &sh->proto->header);\n            }\n        }\n        break;\n    case JS_GC_OBJ_TYPE_JS_CONTEXT:\n        {\n            JSContext *ctx = (JSContext *)gp;\n            JS_MarkContext(rt, ctx, mark_func);\n        }\n        break;\n    case JS_GC_OBJ_TYPE_MODULE:\n        {\n            JSModuleDef *m = (JSModuleDef *)gp;\n            js_mark_module_def(rt, m, mark_func);\n        }\n        break;\n    default:\n        abort();\n    }\n}\n\nstatic void gc_decref_child(JSRuntime *rt, JSGCObjectHeader *p)\n{\n    assert(p->ref_count > 0);\n    p->ref_count--;\n    if (p->ref_count == 0 && p->mark == 1) {\n        list_del(&p->link);\n        list_add_tail(&p->link, &rt->tmp_obj_list);\n    }\n}\n\nstatic void gc_decref(JSRuntime *rt)\n{\n    struct list_head *el, *el1;\n    JSGCObjectHeader *p;\n\n    init_list_head(&rt->tmp_obj_list);\n\n    /* decrement the refcount of all the children of all the GC\n       objects and move the GC objects with zero refcount to\n       tmp_obj_list */\n    list_for_each_safe(el, el1, &rt->gc_obj_list) {\n        p = list_entry(el, JSGCObjectHeader, link);\n        assert(p->mark == 0);\n        mark_children(rt, p, gc_decref_child);\n        p->mark = 1;\n        if (p->ref_count == 0) {\n            list_del(&p->link);\n            list_add_tail(&p->link, &rt->tmp_obj_list);\n        }\n    }\n}\n\nstatic void gc_scan_incref_child(JSRuntime *rt, JSGCObjectHeader *p)\n{\n    p->ref_count++;\n    if (p->ref_count == 1) {\n        /* ref_count was 0: remove from tmp_obj_list and add at the\n           end of gc_obj_list */\n        list_del(&p->link);\n        list_add_tail(&p->link, &rt->gc_obj_list);\n        p->mark = 0; /* reset the mark for the next GC call */\n    }\n}\n\nstatic void gc_scan_incref_child2(JSRuntime *rt, JSGCObjectHeader *p)\n{\n    p->ref_count++;\n}\n\nstatic void gc_scan(JSRuntime *rt)\n{\n    struct list_head *el;\n    JSGCObjectHeader *p;\n\n    /* keep the objects with a refcount > 0 and their children. */\n    list_for_each(el, &rt->gc_obj_list) {\n        p = list_entry(el, JSGCObjectHeader, link);\n        assert(p->ref_count > 0);\n        p->mark = 0; /* reset the mark for the next GC call */\n        mark_children(rt, p, gc_scan_incref_child);\n    }\n\n    /* restore the refcount of the objects to be deleted. */\n    list_for_each(el, &rt->tmp_obj_list) {\n        p = list_entry(el, JSGCObjectHeader, link);\n        mark_children(rt, p, gc_scan_incref_child2);\n    }\n}\n\nstatic void gc_free_cycles(JSRuntime *rt)\n{\n    struct list_head *el, *el1;\n    JSGCObjectHeader *p;\n#ifdef DUMP_GC_FREE\n    BOOL header_done = FALSE;\n#endif\n\n    rt->gc_phase = JS_GC_PHASE_REMOVE_CYCLES;\n\n    for(;;) {\n        el = rt->tmp_obj_list.next;\n        if (el == &rt->tmp_obj_list)\n            break;\n        p = list_entry(el, JSGCObjectHeader, link);\n        /* Only need to free the GC object associated with JS values\n           or async functions. The rest will be automatically removed\n           because they must be referenced by them. */\n        switch(p->gc_obj_type) {\n        case JS_GC_OBJ_TYPE_JS_OBJECT:\n        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:\n        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:\n        case JS_GC_OBJ_TYPE_MODULE:\n#ifdef DUMP_GC_FREE\n            if (!header_done) {\n                printf(\"Freeing cycles:\\n\");\n                JS_DumpObjectHeader(rt);\n                header_done = TRUE;\n            }\n            JS_DumpGCObject(rt, p);\n#endif\n            free_gc_object(rt, p);\n            break;\n        default:\n            list_del(&p->link);\n            list_add_tail(&p->link, &rt->gc_zero_ref_count_list);\n            break;\n        }\n    }\n    rt->gc_phase = JS_GC_PHASE_NONE;\n\n    list_for_each_safe(el, el1, &rt->gc_zero_ref_count_list) {\n        p = list_entry(el, JSGCObjectHeader, link);\n        assert(p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT ||\n               p->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ||\n               p->gc_obj_type == JS_GC_OBJ_TYPE_ASYNC_FUNCTION ||\n               p->gc_obj_type == JS_GC_OBJ_TYPE_MODULE);\n        if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT &&\n            ((JSObject *)p)->weakref_count != 0) {\n            /* keep the object because there are weak references to it */\n            p->mark = 0;\n        } else {\n            js_free_rt(rt, p);\n        }\n    }\n\n    init_list_head(&rt->gc_zero_ref_count_list);\n}\n\nstatic void JS_RunGCInternal(JSRuntime *rt, BOOL remove_weak_objects)\n{\n    if (remove_weak_objects) {\n        /* free the weakly referenced object or symbol structures, delete\n           the associated Map/Set entries and queue the finalization\n           registry callbacks. */\n        gc_remove_weak_objects(rt);\n    }\n    \n    /* decrement the reference of the children of each object. mark =\n       1 after this pass. */\n    gc_decref(rt);\n\n    /* keep the GC objects with a non zero refcount and their childs */\n    gc_scan(rt);\n\n    /* free the GC objects in a cycle */\n    gc_free_cycles(rt);\n}\n\nvoid JS_RunGC(JSRuntime *rt)\n{\n    JS_RunGCInternal(rt, TRUE);\n}\n\n/* Return false if not an object or if the object has already been\n   freed (zombie objects are visible in finalizers when freeing\n   cycles). */\nBOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj)\n{\n    JSObject *p;\n    if (!JS_IsObject(obj))\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    return !p->free_mark;\n}\n\n/* Compute memory used by various object types */\n/* XXX: poor man's approach to handling multiply referenced objects */\ntypedef struct JSMemoryUsage_helper {\n    double memory_used_count;\n    double str_count;\n    double str_size;\n    int64_t js_func_count;\n    double js_func_size;\n    int64_t js_func_code_size;\n    int64_t js_func_pc2line_count;\n    int64_t js_func_pc2line_size;\n} JSMemoryUsage_helper;\n\nstatic void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp);\n\nstatic void compute_jsstring_size(JSString *str, JSMemoryUsage_helper *hp)\n{\n    if (!str->atom_type) {  /* atoms are handled separately */\n        double s_ref_count = str->header.ref_count;\n        hp->str_count += 1 / s_ref_count;\n        hp->str_size += ((sizeof(*str) + (str->len << str->is_wide_char) +\n                          1 - str->is_wide_char) / s_ref_count);\n    }\n}\n\nstatic void compute_bytecode_size(JSFunctionBytecode *b, JSMemoryUsage_helper *hp)\n{\n    int memory_used_count, js_func_size, i;\n\n    memory_used_count = 0;\n    js_func_size = offsetof(JSFunctionBytecode, debug);\n    if (b->vardefs) {\n        js_func_size += (b->arg_count + b->var_count) * sizeof(*b->vardefs);\n    }\n    if (b->cpool) {\n        js_func_size += b->cpool_count * sizeof(*b->cpool);\n        for (i = 0; i < b->cpool_count; i++) {\n            JSValueConst val = b->cpool[i];\n            compute_value_size(val, hp);\n        }\n    }\n    if (b->closure_var) {\n        js_func_size += b->closure_var_count * sizeof(*b->closure_var);\n    }\n    if (!b->read_only_bytecode && b->byte_code_buf) {\n        hp->js_func_code_size += b->byte_code_len;\n    }\n    if (b->has_debug) {\n        js_func_size += sizeof(*b) - offsetof(JSFunctionBytecode, debug);\n        if (b->debug.source) {\n            memory_used_count++;\n            js_func_size += b->debug.source_len + 1;\n        }\n        if (b->debug.pc2line_len) {\n            memory_used_count++;\n            hp->js_func_pc2line_count += 1;\n            hp->js_func_pc2line_size += b->debug.pc2line_len;\n        }\n    }\n    hp->js_func_size += js_func_size;\n    hp->js_func_count += 1;\n    hp->memory_used_count += memory_used_count;\n}\n\nstatic void compute_value_size(JSValueConst val, JSMemoryUsage_helper *hp)\n{\n    switch(JS_VALUE_GET_TAG(val)) {\n    case JS_TAG_STRING:\n        compute_jsstring_size(JS_VALUE_GET_STRING(val), hp);\n        break;\n    case JS_TAG_BIG_INT:\n        /* should track JSBigInt usage */\n        break;\n    }\n}\n\nvoid JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)\n{\n    struct list_head *el, *el1;\n    int i;\n    JSMemoryUsage_helper mem = { 0 }, *hp = &mem;\n\n    memset(s, 0, sizeof(*s));\n    s->malloc_count = rt->malloc_state.malloc_count;\n    s->malloc_size = rt->malloc_state.malloc_size;\n    s->malloc_limit = rt->malloc_state.malloc_limit;\n\n    s->memory_used_count = 2; /* rt + rt->class_array */\n    s->memory_used_size = sizeof(JSRuntime) + sizeof(JSValue) * rt->class_count;\n\n    list_for_each(el, &rt->context_list) {\n        JSContext *ctx = list_entry(el, JSContext, link);\n        JSShape *sh = ctx->array_shape;\n        s->memory_used_count += 2; /* ctx + ctx->class_proto */\n        s->memory_used_size += sizeof(JSContext) +\n            sizeof(JSValue) * rt->class_count;\n        s->binary_object_count += ctx->binary_object_count;\n        s->binary_object_size += ctx->binary_object_size;\n\n        /* the hashed shapes are counted separately */\n        if (sh && !sh->is_hashed) {\n            int hash_size = sh->prop_hash_mask + 1;\n            s->shape_count++;\n            s->shape_size += get_shape_size(hash_size, sh->prop_size);\n        }\n        list_for_each(el1, &ctx->loaded_modules) {\n            JSModuleDef *m = list_entry(el1, JSModuleDef, link);\n            s->memory_used_count += 1;\n            s->memory_used_size += sizeof(*m);\n            if (m->req_module_entries) {\n                s->memory_used_count += 1;\n                s->memory_used_size += m->req_module_entries_count * sizeof(*m->req_module_entries);\n            }\n            if (m->export_entries) {\n                s->memory_used_count += 1;\n                s->memory_used_size += m->export_entries_count * sizeof(*m->export_entries);\n                for (i = 0; i < m->export_entries_count; i++) {\n                    JSExportEntry *me = &m->export_entries[i];\n                    if (me->export_type == JS_EXPORT_TYPE_LOCAL && me->u.local.var_ref) {\n                        /* potential multiple count */\n                        s->memory_used_count += 1;\n                        compute_value_size(me->u.local.var_ref->value, hp);\n                    }\n                }\n            }\n            if (m->star_export_entries) {\n                s->memory_used_count += 1;\n                s->memory_used_size += m->star_export_entries_count * sizeof(*m->star_export_entries);\n            }\n            if (m->import_entries) {\n                s->memory_used_count += 1;\n                s->memory_used_size += m->import_entries_count * sizeof(*m->import_entries);\n            }\n            compute_value_size(m->module_ns, hp);\n            compute_value_size(m->func_obj, hp);\n        }\n    }\n\n    list_for_each(el, &rt->gc_obj_list) {\n        JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);\n        JSObject *p;\n        JSShape *sh;\n        JSShapeProperty *prs;\n\n        /* XXX: could count the other GC object types too */\n        if (gp->gc_obj_type == JS_GC_OBJ_TYPE_FUNCTION_BYTECODE) {\n            compute_bytecode_size((JSFunctionBytecode *)gp, hp);\n            continue;\n        } else if (gp->gc_obj_type != JS_GC_OBJ_TYPE_JS_OBJECT) {\n            continue;\n        }\n        p = (JSObject *)gp;\n        sh = p->shape;\n        s->obj_count++;\n        if (p->prop) {\n            s->memory_used_count++;\n            s->prop_size += sh->prop_size * sizeof(*p->prop);\n            s->prop_count += sh->prop_count;\n            prs = get_shape_prop(sh);\n            for(i = 0; i < sh->prop_count; i++) {\n                JSProperty *pr = &p->prop[i];\n                if (prs->atom != JS_ATOM_NULL && !(prs->flags & JS_PROP_TMASK)) {\n                    compute_value_size(pr->u.value, hp);\n                }\n                prs++;\n            }\n        }\n        /* the hashed shapes are counted separately */\n        if (!sh->is_hashed) {\n            int hash_size = sh->prop_hash_mask + 1;\n            s->shape_count++;\n            s->shape_size += get_shape_size(hash_size, sh->prop_size);\n        }\n\n        switch(p->class_id) {\n        case JS_CLASS_ARRAY:             /* u.array | length */\n        case JS_CLASS_ARGUMENTS:         /* u.array | length */\n            s->array_count++;\n            if (p->fast_array) {\n                s->fast_array_count++;\n                if (p->u.array.u.values) {\n                    s->memory_used_count++;\n                    s->memory_used_size += p->u.array.count *\n                        sizeof(*p->u.array.u.values);\n                    s->fast_array_elements += p->u.array.count;\n                    for (i = 0; i < p->u.array.count; i++) {\n                        compute_value_size(p->u.array.u.values[i], hp);\n                    }\n                }\n            }\n            break;\n        case JS_CLASS_MAPPED_ARGUMENTS:         /* u.array | length */\n            if (p->fast_array) {\n                s->fast_array_count++;\n                if (p->u.array.u.values) {\n                    s->memory_used_count++;\n                    s->memory_used_size += p->u.array.count *\n                        sizeof(*p->u.array.u.var_refs);\n                    s->fast_array_elements += p->u.array.count;\n                    for (i = 0; i < p->u.array.count; i++) {\n                        compute_value_size(*p->u.array.u.var_refs[i]->pvalue, hp);\n                    }\n                }\n            }\n            break;\n        case JS_CLASS_NUMBER:            /* u.object_data */\n        case JS_CLASS_STRING:            /* u.object_data */\n        case JS_CLASS_BOOLEAN:           /* u.object_data */\n        case JS_CLASS_SYMBOL:            /* u.object_data */\n        case JS_CLASS_DATE:              /* u.object_data */\n        case JS_CLASS_BIG_INT:           /* u.object_data */\n            compute_value_size(p->u.object_data, hp);\n            break;\n        case JS_CLASS_C_FUNCTION:        /* u.cfunc */\n            s->c_func_count++;\n            break;\n        case JS_CLASS_BYTECODE_FUNCTION: /* u.func */\n            {\n                JSFunctionBytecode *b = p->u.func.function_bytecode;\n                JSVarRef **var_refs = p->u.func.var_refs;\n                /* home_object: object will be accounted for in list scan */\n                if (var_refs) {\n                    s->memory_used_count++;\n                    s->js_func_size += b->closure_var_count * sizeof(*var_refs);\n                    for (i = 0; i < b->closure_var_count; i++) {\n                        if (var_refs[i]) {\n                            double ref_count = var_refs[i]->header.ref_count;\n                            s->memory_used_count += 1 / ref_count;\n                            s->js_func_size += sizeof(*var_refs[i]) / ref_count;\n                            /* handle non object closed values */\n                            if (var_refs[i]->pvalue == &var_refs[i]->value) {\n                                /* potential multiple count */\n                                compute_value_size(var_refs[i]->value, hp);\n                            }\n                        }\n                    }\n                }\n            }\n            break;\n        case JS_CLASS_BOUND_FUNCTION:    /* u.bound_function */\n            {\n                JSBoundFunction *bf = p->u.bound_function;\n                /* func_obj and this_val are objects */\n                for (i = 0; i < bf->argc; i++) {\n                    compute_value_size(bf->argv[i], hp);\n                }\n                s->memory_used_count += 1;\n                s->memory_used_size += sizeof(*bf) + bf->argc * sizeof(*bf->argv);\n            }\n            break;\n        case JS_CLASS_C_FUNCTION_DATA:   /* u.c_function_data_record */\n            {\n                JSCFunctionDataRecord *fd = p->u.c_function_data_record;\n                if (fd) {\n                    for (i = 0; i < fd->data_len; i++) {\n                        compute_value_size(fd->data[i], hp);\n                    }\n                    s->memory_used_count += 1;\n                    s->memory_used_size += sizeof(*fd) + fd->data_len * sizeof(*fd->data);\n                }\n            }\n            break;\n        case JS_CLASS_REGEXP:            /* u.regexp */\n            compute_jsstring_size(p->u.regexp.pattern, hp);\n            compute_jsstring_size(p->u.regexp.bytecode, hp);\n            break;\n\n        case JS_CLASS_FOR_IN_ITERATOR:   /* u.for_in_iterator */\n            {\n                JSForInIterator *it = p->u.for_in_iterator;\n                if (it) {\n                    compute_value_size(it->obj, hp);\n                    s->memory_used_count += 1;\n                    s->memory_used_size += sizeof(*it);\n                }\n            }\n            break;\n        case JS_CLASS_ARRAY_BUFFER:      /* u.array_buffer */\n        case JS_CLASS_SHARED_ARRAY_BUFFER: /* u.array_buffer */\n            {\n                JSArrayBuffer *abuf = p->u.array_buffer;\n                if (abuf) {\n                    s->memory_used_count += 1;\n                    s->memory_used_size += sizeof(*abuf);\n                    if (abuf->data) {\n                        s->memory_used_count += 1;\n                        s->memory_used_size += abuf->byte_length;\n                    }\n                }\n            }\n            break;\n        case JS_CLASS_GENERATOR:         /* u.generator_data */\n        case JS_CLASS_UINT8C_ARRAY:      /* u.typed_array / u.array */\n        case JS_CLASS_INT8_ARRAY:        /* u.typed_array / u.array */\n        case JS_CLASS_UINT8_ARRAY:       /* u.typed_array / u.array */\n        case JS_CLASS_INT16_ARRAY:       /* u.typed_array / u.array */\n        case JS_CLASS_UINT16_ARRAY:      /* u.typed_array / u.array */\n        case JS_CLASS_INT32_ARRAY:       /* u.typed_array / u.array */\n        case JS_CLASS_UINT32_ARRAY:      /* u.typed_array / u.array */\n        case JS_CLASS_BIG_INT64_ARRAY:   /* u.typed_array / u.array */\n        case JS_CLASS_BIG_UINT64_ARRAY:  /* u.typed_array / u.array */\n        case JS_CLASS_FLOAT16_ARRAY:     /* u.typed_array / u.array */\n        case JS_CLASS_FLOAT32_ARRAY:     /* u.typed_array / u.array */\n        case JS_CLASS_FLOAT64_ARRAY:     /* u.typed_array / u.array */\n        case JS_CLASS_DATAVIEW:          /* u.typed_array */\n        case JS_CLASS_MAP:               /* u.map_state */\n        case JS_CLASS_SET:               /* u.map_state */\n        case JS_CLASS_WEAKMAP:           /* u.map_state */\n        case JS_CLASS_WEAKSET:           /* u.map_state */\n        case JS_CLASS_MAP_ITERATOR:      /* u.map_iterator_data */\n        case JS_CLASS_SET_ITERATOR:      /* u.map_iterator_data */\n        case JS_CLASS_ARRAY_ITERATOR:    /* u.array_iterator_data */\n        case JS_CLASS_STRING_ITERATOR:   /* u.array_iterator_data */\n        case JS_CLASS_PROXY:             /* u.proxy_data */\n        case JS_CLASS_PROMISE:           /* u.promise_data */\n        case JS_CLASS_PROMISE_RESOLVE_FUNCTION:  /* u.promise_function_data */\n        case JS_CLASS_PROMISE_REJECT_FUNCTION:   /* u.promise_function_data */\n        case JS_CLASS_ASYNC_FUNCTION_RESOLVE:    /* u.async_function_data */\n        case JS_CLASS_ASYNC_FUNCTION_REJECT:     /* u.async_function_data */\n        case JS_CLASS_ASYNC_FROM_SYNC_ITERATOR:  /* u.async_from_sync_iterator_data */\n        case JS_CLASS_ASYNC_GENERATOR:   /* u.async_generator_data */\n            /* TODO */\n        default:\n            /* XXX: class definition should have an opaque block size */\n            if (p->u.opaque) {\n                s->memory_used_count += 1;\n            }\n            break;\n        }\n    }\n    s->obj_size += s->obj_count * sizeof(JSObject);\n\n    /* hashed shapes */\n    s->memory_used_count++; /* rt->shape_hash */\n    s->memory_used_size += sizeof(rt->shape_hash[0]) * rt->shape_hash_size;\n    for(i = 0; i < rt->shape_hash_size; i++) {\n        JSShape *sh;\n        for(sh = rt->shape_hash[i]; sh != NULL; sh = sh->shape_hash_next) {\n            int hash_size = sh->prop_hash_mask + 1;\n            s->shape_count++;\n            s->shape_size += get_shape_size(hash_size, sh->prop_size);\n        }\n    }\n\n    /* atoms */\n    s->memory_used_count += 2; /* rt->atom_array, rt->atom_hash */\n    s->atom_count = rt->atom_count;\n    s->atom_size = sizeof(rt->atom_array[0]) * rt->atom_size +\n        sizeof(rt->atom_hash[0]) * rt->atom_hash_size;\n    for(i = 0; i < rt->atom_size; i++) {\n        JSAtomStruct *p = rt->atom_array[i];\n        if (!atom_is_free(p)) {\n            s->atom_size += (sizeof(*p) + (p->len << p->is_wide_char) +\n                             1 - p->is_wide_char);\n        }\n    }\n    s->str_count = round(mem.str_count);\n    s->str_size = round(mem.str_size);\n    s->js_func_count = mem.js_func_count;\n    s->js_func_size = round(mem.js_func_size);\n    s->js_func_code_size = mem.js_func_code_size;\n    s->js_func_pc2line_count = mem.js_func_pc2line_count;\n    s->js_func_pc2line_size = mem.js_func_pc2line_size;\n    s->memory_used_count += round(mem.memory_used_count) +\n        s->atom_count + s->str_count +\n        s->obj_count + s->shape_count +\n        s->js_func_count + s->js_func_pc2line_count;\n    s->memory_used_size += s->atom_size + s->str_size +\n        s->obj_size + s->prop_size + s->shape_size +\n        s->js_func_size + s->js_func_code_size + s->js_func_pc2line_size;\n}\n\nvoid JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt)\n{\n    fprintf(fp, \"QuickJS memory usage -- \" CONFIG_VERSION \" version, %d-bit, malloc limit: %\"PRId64\"\\n\\n\",\n            (int)sizeof(void *) * 8, s->malloc_limit);\n#if 1\n    if (rt) {\n        static const struct {\n            const char *name;\n            size_t size;\n        } object_types[] = {\n            { \"JSRuntime\", sizeof(JSRuntime) },\n            { \"JSContext\", sizeof(JSContext) },\n            { \"JSObject\", sizeof(JSObject) },\n            { \"JSString\", sizeof(JSString) },\n            { \"JSFunctionBytecode\", sizeof(JSFunctionBytecode) },\n        };\n        int i, usage_size_ok = 0;\n        for(i = 0; i < countof(object_types); i++) {\n            unsigned int size = object_types[i].size;\n            void *p = js_malloc_rt(rt, size);\n            if (p) {\n                unsigned int size1 = js_malloc_usable_size_rt(rt, p);\n                if (size1 >= size) {\n                    usage_size_ok = 1;\n                    fprintf(fp, \"  %3u + %-2u  %s\\n\",\n                            size, size1 - size, object_types[i].name);\n                }\n                js_free_rt(rt, p);\n            }\n        }\n        if (!usage_size_ok) {\n            fprintf(fp, \"  malloc_usable_size unavailable\\n\");\n        }\n        {\n            int obj_classes[JS_CLASS_INIT_COUNT + 1] = { 0 };\n            int class_id;\n            struct list_head *el;\n            list_for_each(el, &rt->gc_obj_list) {\n                JSGCObjectHeader *gp = list_entry(el, JSGCObjectHeader, link);\n                JSObject *p;\n                if (gp->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {\n                    p = (JSObject *)gp;\n                    obj_classes[min_uint32(p->class_id, JS_CLASS_INIT_COUNT)]++;\n                }\n            }\n            fprintf(fp, \"\\n\" \"JSObject classes\\n\");\n            if (obj_classes[0])\n                fprintf(fp, \"  %5d  %2.0d %s\\n\", obj_classes[0], 0, \"none\");\n            for (class_id = 1; class_id < JS_CLASS_INIT_COUNT; class_id++) {\n                if (obj_classes[class_id] && class_id < rt->class_count) {\n                    char buf[ATOM_GET_STR_BUF_SIZE];\n                    fprintf(fp, \"  %5d  %2.0d %s\\n\", obj_classes[class_id], class_id,\n                            JS_AtomGetStrRT(rt, buf, sizeof(buf), rt->class_array[class_id].class_name));\n                }\n            }\n            if (obj_classes[JS_CLASS_INIT_COUNT])\n                fprintf(fp, \"  %5d  %2.0d %s\\n\", obj_classes[JS_CLASS_INIT_COUNT], 0, \"other\");\n        }\n        fprintf(fp, \"\\n\");\n    }\n#endif\n    fprintf(fp, \"%-20s %8s %8s\\n\", \"NAME\", \"COUNT\", \"SIZE\");\n\n    if (s->malloc_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per block)\\n\",\n                \"memory allocated\", s->malloc_count, s->malloc_size,\n                (double)s->malloc_size / s->malloc_count);\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%d overhead, %0.1f average slack)\\n\",\n                \"memory used\", s->memory_used_count, s->memory_used_size,\n                MALLOC_OVERHEAD, ((double)(s->malloc_size - s->memory_used_size) /\n                                  s->memory_used_count));\n    }\n    if (s->atom_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per atom)\\n\",\n                \"atoms\", s->atom_count, s->atom_size,\n                (double)s->atom_size / s->atom_count);\n    }\n    if (s->str_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per string)\\n\",\n                \"strings\", s->str_count, s->str_size,\n                (double)s->str_size / s->str_count);\n    }\n    if (s->obj_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per object)\\n\",\n                \"objects\", s->obj_count, s->obj_size,\n                (double)s->obj_size / s->obj_count);\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per object)\\n\",\n                \"  properties\", s->prop_count, s->prop_size,\n                (double)s->prop_count / s->obj_count);\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per shape)\\n\",\n                \"  shapes\", s->shape_count, s->shape_size,\n                (double)s->shape_size / s->shape_count);\n    }\n    if (s->js_func_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"\\n\",\n                \"bytecode functions\", s->js_func_count, s->js_func_size);\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per function)\\n\",\n                \"  bytecode\", s->js_func_count, s->js_func_code_size,\n                (double)s->js_func_code_size / s->js_func_count);\n        if (s->js_func_pc2line_count) {\n            fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per function)\\n\",\n                    \"  pc2line\", s->js_func_pc2line_count,\n                    s->js_func_pc2line_size,\n                    (double)s->js_func_pc2line_size / s->js_func_pc2line_count);\n        }\n    }\n    if (s->c_func_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\"\\n\", \"C functions\", s->c_func_count);\n    }\n    if (s->array_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\"\\n\", \"arrays\", s->array_count);\n        if (s->fast_array_count) {\n            fprintf(fp, \"%-20s %8\"PRId64\"\\n\", \"  fast arrays\", s->fast_array_count);\n            fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"  (%0.1f per fast array)\\n\",\n                    \"  elements\", s->fast_array_elements,\n                    s->fast_array_elements * (int)sizeof(JSValue),\n                    (double)s->fast_array_elements / s->fast_array_count);\n        }\n    }\n    if (s->binary_object_count) {\n        fprintf(fp, \"%-20s %8\"PRId64\" %8\"PRId64\"\\n\",\n                \"binary objects\", s->binary_object_count, s->binary_object_size);\n    }\n}\n\nJSValue JS_GetGlobalObject(JSContext *ctx)\n{\n    return JS_DupValue(ctx, ctx->global_obj);\n}\n\n/* WARNING: obj is freed */\nJSValue JS_Throw(JSContext *ctx, JSValue obj)\n{\n    JSRuntime *rt = ctx->rt;\n    JS_FreeValue(ctx, rt->current_exception);\n    rt->current_exception = obj;\n    rt->current_exception_is_uncatchable = FALSE;\n    return JS_EXCEPTION;\n}\n\n/* return the pending exception (cannot be called twice). */\nJSValue JS_GetException(JSContext *ctx)\n{\n    JSValue val;\n    JSRuntime *rt = ctx->rt;\n    val = rt->current_exception;\n    rt->current_exception = JS_UNINITIALIZED;\n    return val;\n}\n\nJS_BOOL JS_HasException(JSContext *ctx)\n{\n    return !JS_IsUninitialized(ctx->rt->current_exception);\n}\n\nstatic void dbuf_put_leb128(DynBuf *s, uint32_t v)\n{\n    uint32_t a;\n    for(;;) {\n        a = v & 0x7f;\n        v >>= 7;\n        if (v != 0) {\n            dbuf_putc(s, a | 0x80);\n        } else {\n            dbuf_putc(s, a);\n            break;\n        }\n    }\n}\n\nstatic void dbuf_put_sleb128(DynBuf *s, int32_t v1)\n{\n    uint32_t v = v1;\n    dbuf_put_leb128(s, (2 * v) ^ -(v >> 31));\n}\n\nstatic int get_leb128(uint32_t *pval, const uint8_t *buf,\n                      const uint8_t *buf_end)\n{\n    const uint8_t *ptr = buf;\n    uint32_t v, a, i;\n    v = 0;\n    for(i = 0; i < 5; i++) {\n        if (unlikely(ptr >= buf_end))\n            break;\n        a = *ptr++;\n        v |= (a & 0x7f) << (i * 7);\n        if (!(a & 0x80)) {\n            *pval = v;\n            return ptr - buf;\n        }\n    }\n    *pval = 0;\n    return -1;\n}\n\nstatic int get_sleb128(int32_t *pval, const uint8_t *buf,\n                       const uint8_t *buf_end)\n{\n    int ret;\n    uint32_t val;\n    ret = get_leb128(&val, buf, buf_end);\n    if (ret < 0) {\n        *pval = 0;\n        return -1;\n    }\n    *pval = (val >> 1) ^ -(val & 1);\n    return ret;\n}\n\n/* use pc_value = -1 to get the position of the function definition */\nstatic int find_line_num(JSContext *ctx, JSFunctionBytecode *b,\n                         uint32_t pc_value, int *pcol_num)\n{\n    const uint8_t *p_end, *p;\n    int new_line_num, line_num, pc, v, ret, new_col_num, col_num;\n    uint32_t val;\n    unsigned int op;\n\n    if (!b->has_debug || !b->debug.pc2line_buf)\n        goto fail; /* function was stripped */\n\n    p = b->debug.pc2line_buf;\n    p_end = p + b->debug.pc2line_len;\n\n    /* get the function line and column numbers */\n    ret = get_leb128(&val, p, p_end);\n    if (ret < 0)\n        goto fail;\n    p += ret;\n    line_num = val + 1;\n\n    ret = get_leb128(&val, p, p_end);\n    if (ret < 0)\n        goto fail;\n    p += ret;\n    col_num = val + 1;\n\n    if (pc_value != -1) {\n        pc = 0;\n        while (p < p_end) {\n            op = *p++;\n            if (op == 0) {\n                ret = get_leb128(&val, p, p_end);\n                if (ret < 0)\n                    goto fail;\n                pc += val;\n                p += ret;\n                ret = get_sleb128(&v, p, p_end);\n                if (ret < 0)\n                    goto fail;\n                p += ret;\n                new_line_num = line_num + v;\n            } else {\n                op -= PC2LINE_OP_FIRST;\n                pc += (op / PC2LINE_RANGE);\n                new_line_num = line_num + (op % PC2LINE_RANGE) + PC2LINE_BASE;\n            }\n            ret = get_sleb128(&v, p, p_end);\n            if (ret < 0)\n                goto fail;\n            p += ret;\n            new_col_num = col_num + v;\n            \n            if (pc_value < pc)\n                goto done;\n            line_num = new_line_num;\n            col_num = new_col_num;\n        }\n    }\n done:\n    *pcol_num = col_num;\n    return line_num;\n fail:\n    *pcol_num = 0;\n    return 0;\n}\n\n/* return a string property without executing arbitrary JS code (used\n   when dumping the stack trace or in debug print). */\nstatic const char *get_prop_string(JSContext *ctx, JSValueConst obj, JSAtom prop)\n{\n    JSObject *p;\n    JSProperty *pr;\n    JSShapeProperty *prs;\n    JSValueConst val;\n\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return NULL;\n    p = JS_VALUE_GET_OBJ(obj);\n    prs = find_own_property(&pr, p, prop);\n    if (!prs) {\n        /* we look at one level in the prototype to handle the 'name'\n           field of the Error objects */\n        p = p->shape->proto;\n        if (!p)\n            return NULL;\n        prs = find_own_property(&pr, p, prop);\n        if (!prs)\n            return NULL;\n    }\n    \n    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)\n        return NULL;\n    val = pr->u.value;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)\n        return NULL;\n    return JS_ToCString(ctx, val);\n}\n\n#define JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL (1 << 0)\n\n/* if filename != NULL, an additional level is added with the filename\n   and line number information (used for parse error). */\nstatic void build_backtrace(JSContext *ctx, JSValueConst error_obj,\n                            const char *filename, int line_num, int col_num,\n                            int backtrace_flags)\n{\n    JSStackFrame *sf;\n    JSValue str;\n    DynBuf dbuf;\n    const char *func_name_str;\n    const char *str1;\n    JSObject *p;\n\n    if (!JS_IsObject(error_obj))\n        return; /* protection in the out of memory case */\n    \n    js_dbuf_init(ctx, &dbuf);\n    if (filename) {\n        dbuf_printf(&dbuf, \"    at %s\", filename);\n        if (line_num != -1)\n            dbuf_printf(&dbuf, \":%d:%d\", line_num, col_num);\n        dbuf_putc(&dbuf, '\\n');\n        str = JS_NewString(ctx, filename);\n        if (JS_IsException(str))\n            return;\n        /* Note: SpiderMonkey does that, could update once there is a standard */\n        if (JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, str,\n                                   JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||\n            JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, JS_NewInt32(ctx, line_num),\n                                   JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0 ||\n            JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, JS_NewInt32(ctx, col_num),\n                                   JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0) {\n            return;\n        }\n    }\n    for(sf = ctx->rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {\n        if (sf->js_mode & JS_MODE_BACKTRACE_BARRIER)\n            break;\n        if (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) {\n            backtrace_flags &= ~JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL;\n            continue;\n        }\n        func_name_str = get_prop_string(ctx, sf->cur_func, JS_ATOM_name);\n        if (!func_name_str || func_name_str[0] == '\\0')\n            str1 = \"<anonymous>\";\n        else\n            str1 = func_name_str;\n        dbuf_printf(&dbuf, \"    at %s\", str1);\n        JS_FreeCString(ctx, func_name_str);\n\n        p = JS_VALUE_GET_OBJ(sf->cur_func);\n        if (js_class_has_bytecode(p->class_id)) {\n            JSFunctionBytecode *b;\n            const char *atom_str;\n            int line_num1, col_num1;\n\n            b = p->u.func.function_bytecode;\n            if (b->has_debug) {\n                line_num1 = find_line_num(ctx, b,\n                                          sf->cur_pc - b->byte_code_buf - 1, &col_num1);\n                atom_str = JS_AtomToCString(ctx, b->debug.filename);\n                dbuf_printf(&dbuf, \" (%s\",\n                            atom_str ? atom_str : \"<null>\");\n                JS_FreeCString(ctx, atom_str);\n                if (line_num1 != 0)\n                    dbuf_printf(&dbuf, \":%d:%d\", line_num1, col_num1);\n                dbuf_putc(&dbuf, ')');\n            }\n        } else {\n            dbuf_printf(&dbuf, \" (native)\");\n        }\n        dbuf_putc(&dbuf, '\\n');\n    }\n    dbuf_putc(&dbuf, '\\0');\n    if (dbuf_error(&dbuf))\n        str = JS_NULL;\n    else\n        str = JS_NewString(ctx, (char *)dbuf.buf);\n    dbuf_free(&dbuf);\n    JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str,\n                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n}\n\n/* Note: it is important that no exception is returned by this function */\nstatic BOOL is_backtrace_needed(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (p->class_id != JS_CLASS_ERROR)\n        return FALSE;\n    if (find_own_property1(p, JS_ATOM_stack))\n        return FALSE;\n    return TRUE;\n}\n\nJSValue JS_NewError(JSContext *ctx)\n{\n    return JS_NewObjectClass(ctx, JS_CLASS_ERROR);\n}\n\nstatic JSValue JS_ThrowError2(JSContext *ctx, JSErrorEnum error_num,\n                              const char *fmt, va_list ap, BOOL add_backtrace)\n{\n    char buf[256];\n    JSValue obj, ret;\n\n    vsnprintf(buf, sizeof(buf), fmt, ap);\n    obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[error_num],\n                                 JS_CLASS_ERROR);\n    if (unlikely(JS_IsException(obj))) {\n        /* out of memory: throw JS_NULL to avoid recursing */\n        obj = JS_NULL;\n    } else {\n        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,\n                               JS_NewString(ctx, buf),\n                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n        if (add_backtrace) {\n            build_backtrace(ctx, obj, NULL, 0, 0, 0);\n        }\n    }\n    ret = JS_Throw(ctx, obj);\n    return ret;\n}\n\nstatic JSValue JS_ThrowError(JSContext *ctx, JSErrorEnum error_num,\n                             const char *fmt, va_list ap)\n{\n    JSRuntime *rt = ctx->rt;\n    JSStackFrame *sf;\n    BOOL add_backtrace;\n\n    /* the backtrace is added later if called from a bytecode function */\n    sf = rt->current_stack_frame;\n    add_backtrace = !rt->in_out_of_memory &&\n        (!sf || (JS_GetFunctionBytecode(sf->cur_func) == NULL));\n    return JS_ThrowError2(ctx, error_num, fmt, ap, add_backtrace);\n}\n\nJSValue __attribute__((format(printf, 2, 3))) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...)\n{\n    JSValue val;\n    va_list ap;\n\n    va_start(ap, fmt);\n    val = JS_ThrowError(ctx, JS_SYNTAX_ERROR, fmt, ap);\n    va_end(ap);\n    return val;\n}\n\nJSValue __attribute__((format(printf, 2, 3))) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...)\n{\n    JSValue val;\n    va_list ap;\n\n    va_start(ap, fmt);\n    val = JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);\n    va_end(ap);\n    return val;\n}\n\nstatic int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSContext *ctx, int flags, const char *fmt, ...)\n{\n    va_list ap;\n\n    if ((flags & JS_PROP_THROW) ||\n        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {\n        va_start(ap, fmt);\n        JS_ThrowError(ctx, JS_TYPE_ERROR, fmt, ap);\n        va_end(ap);\n        return -1;\n    } else {\n        return FALSE;\n    }\n}\n\n/* never use it directly */\nstatic JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)\n{\n    char buf[ATOM_GET_STR_BUF_SIZE];\n    return JS_ThrowTypeError(ctx, fmt,\n                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));\n}\n\n/* never use it directly */\nstatic JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)\n{\n    char buf[ATOM_GET_STR_BUF_SIZE];\n    return JS_ThrowSyntaxError(ctx, fmt,\n                             JS_AtomGetStr(ctx, buf, sizeof(buf), atom));\n}\n\n/* %s is replaced by 'atom'. The macro is used so that gcc can check\n    the format string. */\n#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, \"\")\n#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, \"\")\n\nstatic int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)\n{\n    if ((flags & JS_PROP_THROW) ||\n        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {\n        JS_ThrowTypeErrorAtom(ctx, \"'%s' is read-only\", atom);\n        return -1;\n    } else {\n        return FALSE;\n    }\n}\n\nJSValue __attribute__((format(printf, 2, 3))) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...)\n{\n    JSValue val;\n    va_list ap;\n\n    va_start(ap, fmt);\n    val = JS_ThrowError(ctx, JS_REFERENCE_ERROR, fmt, ap);\n    va_end(ap);\n    return val;\n}\n\nJSValue __attribute__((format(printf, 2, 3))) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...)\n{\n    JSValue val;\n    va_list ap;\n\n    va_start(ap, fmt);\n    val = JS_ThrowError(ctx, JS_RANGE_ERROR, fmt, ap);\n    va_end(ap);\n    return val;\n}\n\nJSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...)\n{\n    JSValue val;\n    va_list ap;\n\n    va_start(ap, fmt);\n    val = JS_ThrowError(ctx, JS_INTERNAL_ERROR, fmt, ap);\n    va_end(ap);\n    return val;\n}\n\nJSValue JS_ThrowOutOfMemory(JSContext *ctx)\n{\n    JSRuntime *rt = ctx->rt;\n    if (!rt->in_out_of_memory) {\n        rt->in_out_of_memory = TRUE;\n        JS_ThrowInternalError(ctx, \"out of memory\");\n        rt->in_out_of_memory = FALSE;\n    }\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ThrowStackOverflow(JSContext *ctx)\n{\n    return JS_ThrowInternalError(ctx, \"stack overflow\");\n}\n\nstatic JSValue JS_ThrowTypeErrorNotAnObject(JSContext *ctx)\n{\n    return JS_ThrowTypeError(ctx, \"not an object\");\n}\n\nstatic JSValue JS_ThrowTypeErrorNotAConstructor(JSContext *ctx,\n                                                JSValueConst func_obj)\n{\n    const char *name;\n    if (!JS_IsFunction(ctx, func_obj))\n        goto fail;\n    name = get_prop_string(ctx, func_obj, JS_ATOM_name);\n    if (!name) {\n    fail:\n        return JS_ThrowTypeError(ctx, \"not a constructor\");\n    }\n    JS_ThrowTypeError(ctx, \"%s is not a constructor\", name);\n    JS_FreeCString(ctx, name);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx)\n{\n    return JS_ThrowTypeError(ctx, \"not a symbol\");\n}\n\nstatic JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)\n{\n    char buf[ATOM_GET_STR_BUF_SIZE];\n    return JS_ThrowReferenceError(ctx, \"'%s' is not defined\",\n                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));\n}\n\nstatic JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)\n{\n    char buf[ATOM_GET_STR_BUF_SIZE];\n    return JS_ThrowReferenceError(ctx, \"%s is not initialized\",\n                                  name == JS_ATOM_NULL ? \"lexical variable\" :\n                                  JS_AtomGetStr(ctx, buf, sizeof(buf), name));\n}\n\nstatic JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,\n                                                    JSFunctionBytecode *b,\n                                                    int idx, BOOL is_ref)\n{\n    JSAtom atom = JS_ATOM_NULL;\n    if (is_ref) {\n        atom = b->closure_var[idx].var_name;\n    } else {\n        /* not present if the function is stripped and contains no eval() */\n        if (b->vardefs)\n            atom = b->vardefs[b->arg_count + idx].var_name;\n    }\n    return JS_ThrowReferenceErrorUninitialized(ctx, atom);\n}\n\nstatic JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)\n{\n    JSRuntime *rt = ctx->rt;\n    JSAtom name;\n    name = rt->class_array[class_id].class_name;\n    return JS_ThrowTypeErrorAtom(ctx, \"%s object expected\", name);\n}\n\nstatic void JS_ThrowInterrupted(JSContext *ctx)\n{\n    JS_ThrowInternalError(ctx, \"interrupted\");\n    JS_SetUncatchableException(ctx, TRUE);\n}\n\nstatic no_inline __exception int __js_poll_interrupts(JSContext *ctx)\n{\n    JSRuntime *rt = ctx->rt;\n    ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;\n    if (rt->interrupt_handler) {\n        if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {\n            JS_ThrowInterrupted(ctx);\n            return -1;\n        }\n    }\n    return 0;\n}\n\nstatic inline __exception int js_poll_interrupts(JSContext *ctx)\n{\n    if (unlikely(--ctx->interrupt_counter <= 0)) {\n        return __js_poll_interrupts(ctx);\n    } else {\n        return 0;\n    }\n}\n\nstatic void JS_SetImmutablePrototype(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return;\n    p = JS_VALUE_GET_OBJ(obj);\n    p->has_immutable_prototype = TRUE;\n}\n\n/* Return -1 (exception) or TRUE/FALSE. 'throw_flag' = FALSE indicates\n   that it is called from Reflect.setPrototypeOf(). */\nstatic int JS_SetPrototypeInternal(JSContext *ctx, JSValueConst obj,\n                                   JSValueConst proto_val,\n                                   BOOL throw_flag)\n{\n    JSObject *proto, *p, *p1;\n    JSShape *sh;\n\n    if (throw_flag) {\n        if (JS_VALUE_GET_TAG(obj) == JS_TAG_NULL ||\n            JS_VALUE_GET_TAG(obj) == JS_TAG_UNDEFINED)\n            goto not_obj;\n    } else {\n        if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n            goto not_obj;\n    }\n    p = JS_VALUE_GET_OBJ(obj);\n    if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_OBJECT) {\n        if (JS_VALUE_GET_TAG(proto_val) != JS_TAG_NULL) {\n        not_obj:\n            JS_ThrowTypeErrorNotAnObject(ctx);\n            return -1;\n        }\n        proto = NULL;\n    } else {\n        proto = JS_VALUE_GET_OBJ(proto_val);\n    }\n\n    if (throw_flag && JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return TRUE;\n\n    if (unlikely(p->is_exotic)) {\n        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n        int ret;\n        if (em && em->set_prototype) {\n            ret = em->set_prototype(ctx, obj, proto_val);\n            if (ret == 0 && throw_flag) {\n                JS_ThrowTypeError(ctx, \"proxy: bad prototype\");\n                return -1;\n            } else {\n                return ret;\n            }\n        }\n    }\n\n    sh = p->shape;\n    if (sh->proto == proto)\n        return TRUE;\n    if (unlikely(p->has_immutable_prototype)) {\n        if (throw_flag) {\n            JS_ThrowTypeError(ctx, \"prototype is immutable\");\n            return -1;\n        } else {\n            return FALSE;\n        }\n    }\n    if (unlikely(!p->extensible)) {\n        if (throw_flag) {\n            JS_ThrowTypeError(ctx, \"object is not extensible\");\n            return -1;\n        } else {\n            return FALSE;\n        }\n    }\n    if (proto) {\n        /* check if there is a cycle */\n        p1 = proto;\n        do {\n            if (p1 == p) {\n                if (throw_flag) {\n                    JS_ThrowTypeError(ctx, \"circular prototype chain\");\n                    return -1;\n                } else {\n                    return FALSE;\n                }\n            }\n            /* Note: for Proxy objects, proto is NULL */\n            p1 = p1->shape->proto;\n        } while (p1 != NULL);\n        JS_DupValue(ctx, proto_val);\n    }\n\n    if (js_shape_prepare_update(ctx, p, NULL))\n        return -1;\n    sh = p->shape;\n    if (sh->proto)\n        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, sh->proto));\n    sh->proto = proto;\n    p->is_std_array_prototype = FALSE; \n    return TRUE;\n}\n\n/* return -1 (exception) or TRUE/FALSE */\nint JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val)\n{\n    return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);\n}\n\n/* Only works for primitive types, otherwise return JS_NULL. */\nstatic JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)\n{\n    switch(JS_VALUE_GET_NORM_TAG(val)) {\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        val = ctx->class_proto[JS_CLASS_BIG_INT];\n        break;\n    case JS_TAG_INT:\n    case JS_TAG_FLOAT64:\n        val = ctx->class_proto[JS_CLASS_NUMBER];\n        break;\n    case JS_TAG_BOOL:\n        val = ctx->class_proto[JS_CLASS_BOOLEAN];\n        break;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        val = ctx->class_proto[JS_CLASS_STRING];\n        break;\n    case JS_TAG_SYMBOL:\n        val = ctx->class_proto[JS_CLASS_SYMBOL];\n        break;\n    case JS_TAG_OBJECT:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n    default:\n        val = JS_NULL;\n        break;\n    }\n    return val;\n}\n\n/* Return an Object, JS_NULL or JS_EXCEPTION in case of exotic object. */\nJSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)\n{\n    JSValue val;\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        JSObject *p;\n        p = JS_VALUE_GET_OBJ(obj);\n        if (unlikely(p->is_exotic)) {\n            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n            if (em && em->get_prototype) {\n                return em->get_prototype(ctx, obj);\n            }\n        }\n        p = p->shape->proto;\n        if (!p)\n            val = JS_NULL;\n        else\n            val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n    } else {\n        val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));\n    }\n    return val;\n}\n\nstatic JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)\n{\n    JSValue obj1;\n    obj1 = JS_GetPrototype(ctx, obj);\n    JS_FreeValue(ctx, obj);\n    return obj1;\n}\n\n/* return TRUE, FALSE or (-1) in case of exception */\nstatic int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,\n                                   JSValueConst obj)\n{\n    JSValue obj_proto;\n    JSObject *proto;\n    const JSObject *p, *proto1;\n    BOOL ret;\n\n    if (!JS_IsFunction(ctx, obj))\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (p->class_id == JS_CLASS_BOUND_FUNCTION) {\n        JSBoundFunction *s = p->u.bound_function;\n        return JS_IsInstanceOf(ctx, val, s->func_obj);\n    }\n\n    /* Only explicitly boxed values are instances of constructors */\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)\n        return FALSE;\n    obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);\n    if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {\n        if (!JS_IsException(obj_proto))\n            JS_ThrowTypeError(ctx, \"operand 'prototype' property is not an object\");\n        ret = -1;\n        goto done;\n    }\n    proto = JS_VALUE_GET_OBJ(obj_proto);\n    p = JS_VALUE_GET_OBJ(val);\n    for(;;) {\n        proto1 = p->shape->proto;\n        if (!proto1) {\n            /* slow case if exotic object in the prototype chain */\n            if (unlikely(p->is_exotic && !p->fast_array)) {\n                JSValue obj1;\n                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));\n                for(;;) {\n                    obj1 = JS_GetPrototypeFree(ctx, obj1);\n                    if (JS_IsException(obj1)) {\n                        ret = -1;\n                        break;\n                    }\n                    if (JS_IsNull(obj1)) {\n                        ret = FALSE;\n                        break;\n                    }\n                    if (proto == JS_VALUE_GET_OBJ(obj1)) {\n                        JS_FreeValue(ctx, obj1);\n                        ret = TRUE;\n                        break;\n                    }\n                    /* must check for timeout to avoid infinite loop */\n                    if (js_poll_interrupts(ctx)) {\n                        JS_FreeValue(ctx, obj1);\n                        ret = -1;\n                        break;\n                    }\n                }\n            } else {\n                ret = FALSE;\n            }\n            break;\n        }\n        p = proto1;\n        if (proto == p) {\n            ret = TRUE;\n            break;\n        }\n    }\ndone:\n    JS_FreeValue(ctx, obj_proto);\n    return ret;\n}\n\n/* return TRUE, FALSE or (-1) in case of exception */\nint JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)\n{\n    JSValue method;\n\n    if (!JS_IsObject(obj))\n        goto fail;\n    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);\n    if (JS_IsException(method))\n        return -1;\n    if (!JS_IsNull(method) && !JS_IsUndefined(method)) {\n        JSValue ret;\n        ret = JS_CallFree(ctx, method, obj, 1, &val);\n        return JS_ToBoolFree(ctx, ret);\n    }\n\n    /* legacy case */\n    if (!JS_IsFunction(ctx, obj)) {\n    fail:\n        JS_ThrowTypeError(ctx, \"invalid 'instanceof' right operand\");\n        return -1;\n    }\n    return JS_OrdinaryIsInstanceOf(ctx, val, obj);\n}\n\n/* return the value associated to the autoinit property or an exception */\ntypedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);\n\nstatic JSAutoInitFunc *js_autoinit_func_table[] = {\n    js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */\n    js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */\n    JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */\n};\n\n/* warning: 'prs' is reallocated after it */\nstatic int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,\n                               JSProperty *pr, JSShapeProperty *prs)\n{\n    JSValue val;\n    JSContext *realm;\n    JSAutoInitFunc *func;\n    JSAutoInitIDEnum id;\n    \n    if (js_shape_prepare_update(ctx, p, &prs))\n        return -1;\n\n    realm = js_autoinit_get_realm(pr);\n    id = js_autoinit_get_id(pr);\n    func = js_autoinit_func_table[id];\n    /* 'func' shall not modify the object properties 'pr' */\n    val = func(realm, p, prop, pr->u.init.opaque);\n    js_autoinit_free(ctx->rt, pr);\n    prs->flags &= ~JS_PROP_TMASK;\n    pr->u.value = JS_UNDEFINED;\n    if (JS_IsException(val))\n        return -1;\n    if (id == JS_AUTOINIT_ID_MODULE_NS &&\n        JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {\n        /* WARNING: a varref is returned as a string  ! */\n        prs->flags |= JS_PROP_VARREF;\n        pr->u.var_ref = JS_VALUE_GET_PTR(val);\n        pr->u.var_ref->header.ref_count++;\n    } else if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {\n        JSVarRef *var_ref;\n        /* in the global object we use references */\n        var_ref = js_create_var_ref(ctx, FALSE);\n        if (!var_ref)\n            return -1;\n        prs->flags |= JS_PROP_VARREF;\n        pr->u.var_ref = var_ref;\n        var_ref->value = val; \n        var_ref->is_const = !(prs->flags & JS_PROP_WRITABLE);\n    } else {\n        pr->u.value = val;\n    }\n    return 0;\n}\n\nJSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,\n                               JSAtom prop, JSValueConst this_obj,\n                               BOOL throw_ref_error)\n{\n    JSObject *p;\n    JSProperty *pr;\n    JSShapeProperty *prs;\n    uint32_t tag;\n\n    tag = JS_VALUE_GET_TAG(obj);\n    if (unlikely(tag != JS_TAG_OBJECT)) {\n        switch(tag) {\n        case JS_TAG_NULL:\n            return JS_ThrowTypeErrorAtom(ctx, \"cannot read property '%s' of null\", prop);\n        case JS_TAG_UNDEFINED:\n            return JS_ThrowTypeErrorAtom(ctx, \"cannot read property '%s' of undefined\", prop);\n        case JS_TAG_EXCEPTION:\n            return JS_EXCEPTION;\n        case JS_TAG_STRING:\n            {\n                JSString *p1 = JS_VALUE_GET_STRING(obj);\n                if (__JS_AtomIsTaggedInt(prop)) {\n                    uint32_t idx;\n                    idx = __JS_AtomToUInt32(prop);\n                    if (idx < p1->len) {\n                        return js_new_string_char(ctx, string_get(p1, idx));\n                    }\n                } else if (prop == JS_ATOM_length) {\n                    return JS_NewInt32(ctx, p1->len);\n                }\n            }\n            break;\n        case JS_TAG_STRING_ROPE:\n            {\n                JSStringRope *p1 = JS_VALUE_GET_STRING_ROPE(obj);\n                if (__JS_AtomIsTaggedInt(prop)) {\n                    uint32_t idx;\n                    idx = __JS_AtomToUInt32(prop);\n                    if (idx < p1->len) {\n                        return js_new_string_char(ctx, string_rope_get(obj, idx));\n                    }\n                } else if (prop == JS_ATOM_length) {\n                    return JS_NewInt32(ctx, p1->len);\n                }\n            }\n            break;\n        default:\n            break;\n        }\n        /* cannot raise an exception */\n        p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));\n        if (!p)\n            return JS_UNDEFINED;\n    } else {\n        p = JS_VALUE_GET_OBJ(obj);\n    }\n\n    for(;;) {\n        prs = find_own_property(&pr, p, prop);\n        if (prs) {\n            /* found */\n            if (unlikely(prs->flags & JS_PROP_TMASK)) {\n                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                    if (unlikely(!pr->u.getset.getter)) {\n                        return JS_UNDEFINED;\n                    } else {\n                        JSValue func = JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter);\n                        /* Note: the field could be removed in the getter */\n                        func = JS_DupValue(ctx, func);\n                        return JS_CallFree(ctx, func, this_obj, 0, NULL);\n                    }\n                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n                    JSValue val = *pr->u.var_ref->pvalue;\n                    if (unlikely(JS_IsUninitialized(val)))\n                        return JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);\n                    return JS_DupValue(ctx, val);\n                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n                    /* Instantiate property and retry */\n                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))\n                        return JS_EXCEPTION;\n                    continue;\n                }\n            } else {\n                return JS_DupValue(ctx, pr->u.value);\n            }\n        }\n        if (unlikely(p->is_exotic)) {\n            /* exotic behaviors */\n            if (p->fast_array) {\n                if (__JS_AtomIsTaggedInt(prop)) {\n                    uint32_t idx = __JS_AtomToUInt32(prop);\n                    if (idx < p->u.array.count) {\n                        /* we avoid duplicating the code */\n                        return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);\n                    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                               p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n                        return JS_UNDEFINED;\n                    }\n                } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                           p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n                    int ret;\n                    ret = JS_AtomIsNumericIndex(ctx, prop);\n                    if (ret != 0) {\n                        if (ret < 0)\n                            return JS_EXCEPTION;\n                        return JS_UNDEFINED;\n                    }\n                }\n            } else {\n                const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n                if (em) {\n                    if (em->get_property) {\n                        JSValue obj1, retval;\n                        /* XXX: should pass throw_ref_error */\n                        /* Note: if 'p' is a prototype, it can be\n                           freed in the called function */\n                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n                        retval = em->get_property(ctx, obj1, prop, this_obj);\n                        JS_FreeValue(ctx, obj1);\n                        return retval;\n                    }\n                    if (em->get_own_property) {\n                        JSPropertyDescriptor desc;\n                        int ret;\n                        JSValue obj1;\n\n                        /* Note: if 'p' is a prototype, it can be\n                           freed in the called function */\n                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n                        ret = em->get_own_property(ctx, &desc, obj1, prop);\n                        JS_FreeValue(ctx, obj1);\n                        if (ret < 0)\n                            return JS_EXCEPTION;\n                        if (ret) {\n                            if (desc.flags & JS_PROP_GETSET) {\n                                JS_FreeValue(ctx, desc.setter);\n                                return JS_CallFree(ctx, desc.getter, this_obj, 0, NULL);\n                            } else {\n                                return desc.value;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        p = p->shape->proto;\n        if (!p)\n            break;\n    }\n    if (unlikely(throw_ref_error)) {\n        return JS_ThrowReferenceErrorNotDefined(ctx, prop);\n    } else {\n        return JS_UNDEFINED;\n    }\n}\n\nstatic JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)\n{\n    return JS_ThrowTypeErrorAtom(ctx, \"private class field '%s' does not exist\",\n                                 atom);\n}\n\n/* Private fields can be added even on non extensible objects or\n   Proxies */\nstatic int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj,\n                                 JSValueConst name, JSValue val)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSAtom prop;\n\n    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        goto fail;\n    }\n    /* safety check */\n    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {\n        JS_ThrowTypeErrorNotASymbol(ctx);\n        goto fail;\n    }\n    prop = js_symbol_to_atom(ctx, (JSValue)name);\n    p = JS_VALUE_GET_OBJ(obj);\n    prs = find_own_property(&pr, p, prop);\n    if (prs) {\n        JS_ThrowTypeErrorAtom(ctx, \"private class field '%s' already exists\",\n                              prop);\n        goto fail;\n    }\n    pr = add_property(ctx, p, prop, JS_PROP_C_W_E);\n    if (unlikely(!pr)) {\n    fail:\n        JS_FreeValue(ctx, val);\n        return -1;\n    }\n    pr->u.value = val;\n    return 0;\n}\n\nstatic JSValue JS_GetPrivateField(JSContext *ctx, JSValueConst obj,\n                                  JSValueConst name)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSAtom prop;\n\n    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    /* safety check */\n    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL))\n        return JS_ThrowTypeErrorNotASymbol(ctx);\n    prop = js_symbol_to_atom(ctx, (JSValue)name);\n    p = JS_VALUE_GET_OBJ(obj);\n    prs = find_own_property(&pr, p, prop);\n    if (!prs) {\n        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);\n        return JS_EXCEPTION;\n    }\n    return JS_DupValue(ctx, pr->u.value);\n}\n\nstatic int JS_SetPrivateField(JSContext *ctx, JSValueConst obj,\n                              JSValueConst name, JSValue val)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSAtom prop;\n\n    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        goto fail;\n    }\n    /* safety check */\n    if (unlikely(JS_VALUE_GET_TAG(name) != JS_TAG_SYMBOL)) {\n        JS_ThrowTypeErrorNotASymbol(ctx);\n        goto fail;\n    }\n    prop = js_symbol_to_atom(ctx, (JSValue)name);\n    p = JS_VALUE_GET_OBJ(obj);\n    prs = find_own_property(&pr, p, prop);\n    if (!prs) {\n        JS_ThrowTypeErrorPrivateNotFound(ctx, prop);\n    fail:\n        JS_FreeValue(ctx, val);\n        return -1;\n    }\n    set_value(ctx, &pr->u.value, val);\n    return 0;\n}\n\n/* add a private brand field to 'home_obj' if not already present and\n   if obj is != null add a private brand to it */\nstatic int JS_AddBrand(JSContext *ctx, JSValueConst obj, JSValueConst home_obj)\n{\n    JSObject *p, *p1;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSValue brand;\n    JSAtom brand_atom;\n\n    if (unlikely(JS_VALUE_GET_TAG(home_obj) != JS_TAG_OBJECT)) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        return -1;\n    }\n    p = JS_VALUE_GET_OBJ(home_obj);\n    prs = find_own_property(&pr, p, JS_ATOM_Private_brand);\n    if (!prs) {\n        /* if the brand is not present, add it */\n        brand = JS_NewSymbolFromAtom(ctx, JS_ATOM_brand, JS_ATOM_TYPE_PRIVATE);\n        if (JS_IsException(brand))\n            return -1;\n        pr = add_property(ctx, p, JS_ATOM_Private_brand, JS_PROP_C_W_E);\n        if (!pr) {\n            JS_FreeValue(ctx, brand);\n            return -1;\n        }\n        pr->u.value = JS_DupValue(ctx, brand);\n    } else {\n        brand = JS_DupValue(ctx, pr->u.value);\n    }\n    brand_atom = js_symbol_to_atom(ctx, brand);\n\n    if (JS_IsObject(obj)) {\n        p1 = JS_VALUE_GET_OBJ(obj);\n        prs = find_own_property(&pr, p1, brand_atom);\n        if (unlikely(prs)) {\n            JS_FreeAtom(ctx, brand_atom);\n            JS_ThrowTypeError(ctx, \"private method is already present\");\n            return -1;\n        }\n        pr = add_property(ctx, p1, brand_atom, JS_PROP_C_W_E);\n        JS_FreeAtom(ctx, brand_atom);\n        if (!pr)\n            return -1;\n        pr->u.value = JS_UNDEFINED;\n    } else {\n        JS_FreeAtom(ctx, brand_atom);\n    }\n    return 0;\n}\n\n/* return a boolean telling if the brand of the home object of 'func'\n   is present on 'obj' or -1 in case of exception */\nstatic int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)\n{\n    JSObject *p, *p1, *home_obj;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSValueConst brand;\n\n    /* get the home object of 'func' */\n    if (unlikely(JS_VALUE_GET_TAG(func) != JS_TAG_OBJECT))\n        goto not_obj;\n    p1 = JS_VALUE_GET_OBJ(func);\n    if (!js_class_has_bytecode(p1->class_id))\n        goto not_obj;\n    home_obj = p1->u.func.home_object;\n    if (!home_obj)\n        goto not_obj;\n    prs = find_own_property(&pr, home_obj, JS_ATOM_Private_brand);\n    if (!prs) {\n        JS_ThrowTypeError(ctx, \"expecting <brand> private field\");\n        return -1;\n    }\n    brand = pr->u.value;\n    /* safety check */\n    if (unlikely(JS_VALUE_GET_TAG(brand) != JS_TAG_SYMBOL))\n        goto not_obj;\n\n    /* get the brand array of 'obj' */\n    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)) {\n    not_obj:\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        return -1;\n    }\n    p = JS_VALUE_GET_OBJ(obj);\n    prs = find_own_property(&pr, p, js_symbol_to_atom(ctx, (JSValue)brand));\n    return (prs != NULL);\n}\n\nstatic uint32_t js_string_obj_get_length(JSContext *ctx,\n                                         JSValueConst obj)\n{\n    JSObject *p;\n    uint32_t len = 0;\n\n    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */\n    p = JS_VALUE_GET_OBJ(obj);\n    if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {\n        JSString *p1 = JS_VALUE_GET_STRING(p->u.object_data);\n        len = p1->len;\n    }\n    return len;\n}\n\nstatic int num_keys_cmp(const void *p1, const void *p2, void *opaque)\n{\n    JSContext *ctx = opaque;\n    JSAtom atom1 = ((const JSPropertyEnum *)p1)->atom;\n    JSAtom atom2 = ((const JSPropertyEnum *)p2)->atom;\n    uint32_t v1, v2;\n    BOOL atom1_is_integer, atom2_is_integer;\n\n    atom1_is_integer = JS_AtomIsArrayIndex(ctx, &v1, atom1);\n    atom2_is_integer = JS_AtomIsArrayIndex(ctx, &v2, atom2);\n    assert(atom1_is_integer && atom2_is_integer);\n    if (v1 < v2)\n        return -1;\n    else if (v1 == v2)\n        return 0;\n    else\n        return 1;\n}\n\nvoid JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len)\n{\n    uint32_t i;\n    if (tab) {\n        for(i = 0; i < len; i++)\n            JS_FreeAtom(ctx, tab[i].atom);\n        js_free(ctx, tab);\n    }\n}\n\n/* return < 0 in case if exception, 0 if OK. ptab and its atoms must\n   be freed by the user. */\nstatic int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,\n                                                      JSPropertyEnum **ptab,\n                                                      uint32_t *plen,\n                                                      JSObject *p, int flags)\n{\n    int i, j;\n    JSShape *sh;\n    JSShapeProperty *prs;\n    JSPropertyEnum *tab_atom, *tab_exotic;\n    JSAtom atom;\n    uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;\n    uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;\n    BOOL is_enumerable, num_sorted;\n    uint32_t num_key;\n    JSAtomKindEnum kind;\n\n    /* clear pointer for consistency in case of failure */\n    *ptab = NULL;\n    *plen = 0;\n\n    /* compute the number of returned properties */\n    num_keys_count = 0;\n    str_keys_count = 0;\n    sym_keys_count = 0;\n    exotic_keys_count = 0;\n    exotic_count = 0;\n    tab_exotic = NULL;\n    sh = p->shape;\n    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {\n        atom = prs->atom;\n        if (atom != JS_ATOM_NULL) {\n            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);\n            kind = JS_AtomGetKind(ctx, atom);\n            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&\n                ((flags >> kind) & 1) != 0) {\n                /* need to raise an exception in case of the module\n                   name space (implicit GetOwnProperty) */\n                if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) &&\n                    (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY))) {\n                    JSVarRef *var_ref = p->prop[i].u.var_ref;\n                    if (unlikely(JS_IsUninitialized(*var_ref->pvalue))) {\n                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);\n                        return -1;\n                    }\n                }\n                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {\n                    num_keys_count++;\n                } else if (kind == JS_ATOM_KIND_STRING) {\n                    str_keys_count++;\n                } else {\n                    sym_keys_count++;\n                }\n            }\n        }\n    }\n\n    if (p->is_exotic) {\n        if (p->fast_array) {\n            if (flags & JS_GPN_STRING_MASK) {\n                num_keys_count += p->u.array.count;\n            }\n        } else if (p->class_id == JS_CLASS_STRING) {\n            if (flags & JS_GPN_STRING_MASK) {\n                num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n            }\n        } else {\n            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n            if (em && em->get_own_property_names) {\n                if (em->get_own_property_names(ctx, &tab_exotic, &exotic_count,\n                                               JS_MKPTR(JS_TAG_OBJECT, p)))\n                    return -1;\n                for(i = 0; i < exotic_count; i++) {\n                    atom = tab_exotic[i].atom;\n                    kind = JS_AtomGetKind(ctx, atom);\n                    if (((flags >> kind) & 1) != 0) {\n                        is_enumerable = FALSE;\n                        if (flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) {\n                            JSPropertyDescriptor desc;\n                            int res;\n                            /* set the \"is_enumerable\" field if necessary */\n                            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);\n                            if (res < 0) {\n                                JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);\n                                return -1;\n                            }\n                            if (res) {\n                                is_enumerable =\n                                    ((desc.flags & JS_PROP_ENUMERABLE) != 0);\n                                js_free_desc(ctx, &desc);\n                            }\n                            tab_exotic[i].is_enumerable = is_enumerable;\n                        }\n                        if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {\n                            exotic_keys_count++;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /* fill them */\n\n    atom_count = num_keys_count + str_keys_count;\n    if (atom_count < str_keys_count)\n        goto add_overflow;\n    atom_count += sym_keys_count;\n    if (atom_count < sym_keys_count)\n        goto add_overflow;\n    atom_count += exotic_keys_count;\n    if (atom_count < exotic_keys_count || atom_count > INT32_MAX) {\n    add_overflow:\n        JS_ThrowOutOfMemory(ctx);\n        JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);\n        return -1;\n    }\n    /* XXX: need generic way to test for js_malloc(ctx, a * b) overflow */\n    \n    /* avoid allocating 0 bytes */\n    tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));\n    if (!tab_atom) {\n        JS_FreePropertyEnum(ctx, tab_exotic, exotic_count);\n        return -1;\n    }\n\n    num_index = 0;\n    str_index = num_keys_count;\n    sym_index = str_index + str_keys_count;\n\n    num_sorted = TRUE;\n    sh = p->shape;\n    for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {\n        atom = prs->atom;\n        if (atom != JS_ATOM_NULL) {\n            is_enumerable = ((prs->flags & JS_PROP_ENUMERABLE) != 0);\n            kind = JS_AtomGetKind(ctx, atom);\n            if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&\n                ((flags >> kind) & 1) != 0) {\n                if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {\n                    j = num_index++;\n                    num_sorted = FALSE;\n                } else if (kind == JS_ATOM_KIND_STRING) {\n                    j = str_index++;\n                } else {\n                    j = sym_index++;\n                }\n                tab_atom[j].atom = JS_DupAtom(ctx, atom);\n                tab_atom[j].is_enumerable = is_enumerable;\n            }\n        }\n    }\n\n    if (p->is_exotic) {\n        int len;\n        if (p->fast_array) {\n            if (flags & JS_GPN_STRING_MASK) {\n                len = p->u.array.count;\n                goto add_array_keys;\n            }\n        } else if (p->class_id == JS_CLASS_STRING) {\n            if (flags & JS_GPN_STRING_MASK) {\n                len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n            add_array_keys:\n                for(i = 0; i < len; i++) {\n                    tab_atom[num_index].atom = __JS_AtomFromUInt32(i);\n                    if (tab_atom[num_index].atom == JS_ATOM_NULL) {\n                        JS_FreePropertyEnum(ctx, tab_atom, num_index);\n                        return -1;\n                    }\n                    tab_atom[num_index].is_enumerable = TRUE;\n                    num_index++;\n                }\n            }\n        } else {\n            /* Note: exotic keys are not reordered and comes after the object own properties. */\n            for(i = 0; i < exotic_count; i++) {\n                atom = tab_exotic[i].atom;\n                is_enumerable = tab_exotic[i].is_enumerable;\n                kind = JS_AtomGetKind(ctx, atom);\n                if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&\n                    ((flags >> kind) & 1) != 0) {\n                    tab_atom[sym_index].atom = atom;\n                    tab_atom[sym_index].is_enumerable = is_enumerable;\n                    sym_index++;\n                } else {\n                    JS_FreeAtom(ctx, atom);\n                }\n            }\n            js_free(ctx, tab_exotic);\n        }\n    }\n\n    assert(num_index == num_keys_count);\n    assert(str_index == num_keys_count + str_keys_count);\n    assert(sym_index == atom_count);\n\n    if (num_keys_count != 0 && !num_sorted) {\n        rqsort(tab_atom, num_keys_count, sizeof(tab_atom[0]), num_keys_cmp,\n               ctx);\n    }\n    *ptab = tab_atom;\n    *plen = atom_count;\n    return 0;\n}\n\nint JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,\n                           uint32_t *plen, JSValueConst obj, int flags)\n{\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        return -1;\n    }\n    return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,\n                                          JS_VALUE_GET_OBJ(obj), flags);\n}\n\n/* Return -1 if exception,\n   FALSE if the property does not exist, TRUE if it exists. If TRUE is\n   returned, the property descriptor 'desc' is filled present. */\nstatic int JS_GetOwnPropertyInternal(JSContext *ctx, JSPropertyDescriptor *desc,\n                                     JSObject *p, JSAtom prop)\n{\n    JSShapeProperty *prs;\n    JSProperty *pr;\n\nretry:\n    prs = find_own_property(&pr, p, prop);\n    if (prs) {\n        if (desc) {\n            desc->flags = prs->flags & JS_PROP_C_W_E;\n            desc->getter = JS_UNDEFINED;\n            desc->setter = JS_UNDEFINED;\n            desc->value = JS_UNDEFINED;\n            if (unlikely(prs->flags & JS_PROP_TMASK)) {\n                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                    desc->flags |= JS_PROP_GETSET;\n                    if (pr->u.getset.getter)\n                        desc->getter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));\n                    if (pr->u.getset.setter)\n                        desc->setter = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));\n                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n                    JSValue val = *pr->u.var_ref->pvalue;\n                    if (unlikely(JS_IsUninitialized(val))) {\n                        JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);\n                        return -1;\n                    }\n                    desc->value = JS_DupValue(ctx, val);\n                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n                    /* Instantiate property and retry */\n                    if (JS_AutoInitProperty(ctx, p, prop, pr, prs))\n                        return -1;\n                    goto retry;\n                }\n            } else {\n                desc->value = JS_DupValue(ctx, pr->u.value);\n            }\n        } else {\n            /* for consistency, send the exception even if desc is NULL */\n            if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF)) {\n                if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {\n                    JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);\n                    return -1;\n                }\n            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n                /* nothing to do: delay instantiation until actual value and/or attributes are read */\n            }\n        }\n        return TRUE;\n    }\n    if (p->is_exotic) {\n        if (p->fast_array) {\n            /* specific case for fast arrays */\n            if (__JS_AtomIsTaggedInt(prop)) {\n                uint32_t idx;\n                idx = __JS_AtomToUInt32(prop);\n                if (idx < p->u.array.count) {\n                    if (desc) {\n                        desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |\n                            JS_PROP_CONFIGURABLE;\n                        desc->getter = JS_UNDEFINED;\n                        desc->setter = JS_UNDEFINED;\n                        desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);\n                    }\n                    return TRUE;\n                }\n            }\n        } else {\n            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n            if (em && em->get_own_property) {\n                return em->get_own_property(ctx, desc,\n                                            JS_MKPTR(JS_TAG_OBJECT, p), prop);\n            }\n        }\n    }\n    return FALSE;\n}\n\nint JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,\n                      JSValueConst obj, JSAtom prop)\n{\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        return -1;\n    }\n    return JS_GetOwnPropertyInternal(ctx, desc, JS_VALUE_GET_OBJ(obj), prop);\n}\n\n/* return -1 if exception (exotic object only) or TRUE/FALSE */\nint JS_IsExtensible(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n\n    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (unlikely(p->is_exotic)) {\n        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n        if (em && em->is_extensible) {\n            return em->is_extensible(ctx, obj);\n        }\n    }\n    return p->extensible;\n}\n\n/* return -1 if exception (exotic object only) or TRUE/FALSE */\nint JS_PreventExtensions(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n\n    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (unlikely(p->is_exotic)) {\n        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n            JSTypedArray *ta;\n            JSArrayBuffer *abuf;\n            /* resizable type arrays return FALSE */\n            ta = p->u.typed_array;\n            abuf = ta->buffer->u.array_buffer;\n            if (ta->track_rab ||\n                (array_buffer_is_resizable(abuf) && !abuf->shared))\n                return FALSE;\n        } else {\n            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n            if (em && em->prevent_extensions) {\n                return em->prevent_extensions(ctx, obj);\n            }\n        }\n    }\n    p->extensible = FALSE;\n    return TRUE;\n}\n\n/* return -1 if exception otherwise TRUE or FALSE */\nint JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)\n{\n    JSObject *p;\n    int ret;\n    JSValue obj1;\n\n    if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    for(;;) {\n        if (p->is_exotic) {\n            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n            if (em && em->has_property) {\n                /* has_property can free the prototype */\n                obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n                ret = em->has_property(ctx, obj1, prop);\n                JS_FreeValue(ctx, obj1);\n                return ret;\n            }\n        }\n        /* JS_GetOwnPropertyInternal can free the prototype */\n        JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n        ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);\n        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n        if (ret != 0)\n            return ret;\n        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n            p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n            ret = JS_AtomIsNumericIndex(ctx, prop);\n            if (ret != 0) {\n                if (ret < 0)\n                    return -1;\n                return FALSE;\n            }\n        }\n        p = p->shape->proto;\n        if (!p)\n            break;\n    }\n    return FALSE;\n}\n\n/* val must be a symbol */\nstatic JSAtom js_symbol_to_atom(JSContext *ctx, JSValue val)\n{\n    JSAtomStruct *p = JS_VALUE_GET_PTR(val);\n    return js_get_atom_index(ctx->rt, p);\n}\n\n/* return JS_ATOM_NULL in case of exception */\nJSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val)\n{\n    JSAtom atom;\n    uint32_t tag;\n    tag = JS_VALUE_GET_TAG(val);\n    if (tag == JS_TAG_INT &&\n        (uint32_t)JS_VALUE_GET_INT(val) <= JS_ATOM_MAX_INT) {\n        /* fast path for integer values */\n        atom = __JS_AtomFromUInt32(JS_VALUE_GET_INT(val));\n    } else if (tag == JS_TAG_SYMBOL) {\n        JSAtomStruct *p = JS_VALUE_GET_PTR(val);\n        atom = JS_DupAtom(ctx, js_get_atom_index(ctx->rt, p));\n    } else {\n        JSValue str;\n        str = JS_ToPropertyKey(ctx, val);\n        if (JS_IsException(str))\n            return JS_ATOM_NULL;\n        if (JS_VALUE_GET_TAG(str) == JS_TAG_SYMBOL) {\n            atom = js_symbol_to_atom(ctx, str);\n        } else {\n            atom = JS_NewAtomStr(ctx, JS_VALUE_GET_STRING(str));\n        }\n    }\n    return atom;\n}\n\nstatic JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,\n                                   JSValue prop)\n{\n    JSAtom atom;\n    JSValue ret;\n\n    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&\n               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {\n        JSObject *p;\n        uint32_t idx;\n        /* fast path for array access */\n        p = JS_VALUE_GET_OBJ(this_obj);\n        idx = JS_VALUE_GET_INT(prop);\n        switch(p->class_id) {\n        case JS_CLASS_ARRAY:\n        case JS_CLASS_ARGUMENTS:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_DupValue(ctx, p->u.array.u.values[idx]);\n        case JS_CLASS_MAPPED_ARGUMENTS:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_DupValue(ctx, *p->u.array.u.var_refs[idx]->pvalue);\n        case JS_CLASS_INT8_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewInt32(ctx, p->u.array.u.int8_ptr[idx]);\n        case JS_CLASS_UINT8C_ARRAY:\n        case JS_CLASS_UINT8_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewInt32(ctx, p->u.array.u.uint8_ptr[idx]);\n        case JS_CLASS_INT16_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewInt32(ctx, p->u.array.u.int16_ptr[idx]);\n        case JS_CLASS_UINT16_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewInt32(ctx, p->u.array.u.uint16_ptr[idx]);\n        case JS_CLASS_INT32_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewInt32(ctx, p->u.array.u.int32_ptr[idx]);\n        case JS_CLASS_UINT32_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewUint32(ctx, p->u.array.u.uint32_ptr[idx]);\n        case JS_CLASS_BIG_INT64_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewBigInt64(ctx, p->u.array.u.int64_ptr[idx]);\n        case JS_CLASS_BIG_UINT64_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return JS_NewBigUint64(ctx, p->u.array.u.uint64_ptr[idx]);\n        case JS_CLASS_FLOAT16_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return __JS_NewFloat64(ctx, fromfp16(p->u.array.u.fp16_ptr[idx]));\n        case JS_CLASS_FLOAT32_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return __JS_NewFloat64(ctx, p->u.array.u.float_ptr[idx]);\n        case JS_CLASS_FLOAT64_ARRAY:\n            if (unlikely(idx >= p->u.array.count)) goto slow_path;\n            return __JS_NewFloat64(ctx, p->u.array.u.double_ptr[idx]);\n        default:\n            goto slow_path;\n        }\n    } else {\n    slow_path:\n        /* ToObject() must be done before ToPropertyKey() */\n        if (JS_IsNull(this_obj) || JS_IsUndefined(this_obj)) {\n            JS_FreeValue(ctx, prop);\n            return JS_ThrowTypeError(ctx, \"cannot read property of %s\", JS_IsNull(this_obj) ? \"null\" : \"undefined\");\n        }\n        atom = JS_ValueToAtom(ctx, prop);\n        JS_FreeValue(ctx, prop);\n        if (unlikely(atom == JS_ATOM_NULL))\n            return JS_EXCEPTION;\n        ret = JS_GetProperty(ctx, this_obj, atom);\n        JS_FreeAtom(ctx, atom);\n        return ret;\n    }\n}\n\nJSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,\n                             uint32_t idx)\n{\n    return JS_GetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx));\n}\n\n/* Check if an object has a generalized numeric property. Return value:\n   -1 for exception,\n   TRUE if property exists, stored into *pval,\n   FALSE if proprty does not exist.\n */\nstatic int JS_TryGetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, JSValue *pval)\n{\n    JSValue val = JS_UNDEFINED;\n    JSAtom prop;\n    int present;\n\n    if (likely((uint64_t)idx <= JS_ATOM_MAX_INT)) {\n        /* fast path */\n        present = JS_HasProperty(ctx, obj, __JS_AtomFromUInt32(idx));\n        if (present > 0) {\n            val = JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));\n            if (unlikely(JS_IsException(val)))\n                present = -1;\n        }\n    } else {\n        prop = JS_NewAtomInt64(ctx, idx);\n        present = -1;\n        if (likely(prop != JS_ATOM_NULL)) {\n            present = JS_HasProperty(ctx, obj, prop);\n            if (present > 0) {\n                val = JS_GetProperty(ctx, obj, prop);\n                if (unlikely(JS_IsException(val)))\n                    present = -1;\n            }\n            JS_FreeAtom(ctx, prop);\n        }\n    }\n    *pval = val;\n    return present;\n}\n\nstatic JSValue JS_GetPropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx)\n{\n    JSAtom prop;\n    JSValue val;\n\n    if ((uint64_t)idx <= INT32_MAX) {\n        /* fast path for fast arrays */\n        return JS_GetPropertyValue(ctx, obj, JS_NewInt32(ctx, idx));\n    }\n    prop = JS_NewAtomInt64(ctx, idx);\n    if (prop == JS_ATOM_NULL)\n        return JS_EXCEPTION;\n\n    val = JS_GetProperty(ctx, obj, prop);\n    JS_FreeAtom(ctx, prop);\n    return val;\n}\n\nJSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,\n                          const char *prop)\n{\n    JSAtom atom;\n    JSValue ret;\n    atom = JS_NewAtom(ctx, prop);\n    if (atom == JS_ATOM_NULL)\n        return JS_EXCEPTION;\n    ret = JS_GetProperty(ctx, this_obj, atom);\n    JS_FreeAtom(ctx, atom);\n    return ret;\n}\n\n/* Note: the property value is not initialized. Return NULL if memory\n   error. */\nstatic JSProperty *add_property(JSContext *ctx,\n                                JSObject *p, JSAtom prop, int prop_flags)\n{\n    JSShape *sh, *new_sh;\n\n    if (unlikely(__JS_AtomIsTaggedInt(prop))) {\n        /* update is_std_array_prototype */\n        if (unlikely(p->is_std_array_prototype)) {\n            p->is_std_array_prototype = FALSE;\n        } else if (unlikely(p->has_immutable_prototype)) {\n            struct list_head *el;\n            \n            /* modifying Object.prototype : reset the corresponding is_std_array_prototype */\n            list_for_each(el, &ctx->rt->context_list) {\n                JSContext *ctx1 = list_entry(el, JSContext, link);\n                if (JS_IsObject(ctx1->class_proto[JS_CLASS_OBJECT]) && \n                    JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_OBJECT]) == p) {\n                    if (JS_IsObject(ctx1->class_proto[JS_CLASS_ARRAY])) {\n                        JSObject *p1 = JS_VALUE_GET_OBJ(ctx1->class_proto[JS_CLASS_ARRAY]);\n                        p1->is_std_array_prototype = FALSE;\n                    }\n                    break;\n                }\n            }\n        }\n    }\n    sh = p->shape;\n    if (sh->is_hashed) {\n        /* try to find an existing shape */\n        new_sh = find_hashed_shape_prop(ctx->rt, sh, prop, prop_flags);\n        if (new_sh) {\n            /* matching shape found: use it */\n            /*  the property array may need to be resized */\n            if (new_sh->prop_size != sh->prop_size) {\n                JSProperty *new_prop;\n                new_prop = js_realloc(ctx, p->prop, sizeof(p->prop[0]) *\n                                      new_sh->prop_size);\n                if (!new_prop)\n                    return NULL;\n                p->prop = new_prop;\n            }\n            p->shape = js_dup_shape(new_sh);\n            js_free_shape(ctx->rt, sh);\n            return &p->prop[new_sh->prop_count - 1];\n        } else if (sh->header.ref_count != 1) {\n            /* if the shape is shared, clone it */\n            new_sh = js_clone_shape(ctx, sh);\n            if (!new_sh)\n                return NULL;\n            /* hash the cloned shape */\n            new_sh->is_hashed = TRUE;\n            js_shape_hash_link(ctx->rt, new_sh);\n            js_free_shape(ctx->rt, p->shape);\n            p->shape = new_sh;\n        }\n    }\n    assert(p->shape->header.ref_count == 1);\n    if (add_shape_property(ctx, &p->shape, p, prop, prop_flags))\n        return NULL;\n    return &p->prop[p->shape->prop_count - 1];\n}\n\n/* can be called on JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS or\n   JS_CLASS_MAPPED_ARGUMENTS objects. return < 0 if memory alloc\n   error. */\nstatic no_inline __exception int convert_fast_array_to_array(JSContext *ctx,\n                                                             JSObject *p)\n{\n    JSProperty *pr;\n    JSShape *sh;\n    uint32_t i, len, new_count;\n\n    if (js_shape_prepare_update(ctx, p, NULL))\n        return -1;\n    len = p->u.array.count;\n    /* resize the properties once to simplify the error handling */\n    sh = p->shape;\n    new_count = sh->prop_count + len;\n    if (new_count > sh->prop_size) {\n        if (resize_properties(ctx, &p->shape, p, new_count))\n            return -1;\n    }\n\n    if (p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {\n        JSVarRef **tab = p->u.array.u.var_refs;\n        for(i = 0; i < len; i++) {\n            /* add_property cannot fail here but\n               __JS_AtomFromUInt32(i) fails for i > INT32_MAX */\n            pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E | JS_PROP_VARREF);\n            pr->u.var_ref = *tab++;\n        }\n    } else {\n        JSValue *tab = p->u.array.u.values;\n        for(i = 0; i < len; i++) {\n            /* add_property cannot fail here but\n               __JS_AtomFromUInt32(i) fails for i > INT32_MAX */\n            pr = add_property(ctx, p, __JS_AtomFromUInt32(i), JS_PROP_C_W_E);\n            pr->u.value = *tab++;\n        }\n    }\n    js_free(ctx, p->u.array.u.values);\n    p->u.array.count = 0;\n    p->u.array.u.values = NULL; /* fail safe */\n    p->u.array.u1.size = 0;\n    p->fast_array = 0;\n    p->is_std_array_prototype = FALSE;\n    return 0;\n}\n\nstatic int remove_global_object_property(JSContext *ctx, JSObject *p,\n                                         JSShapeProperty *prs, JSProperty *pr)\n{\n    JSVarRef *var_ref;\n    JSObject *p1;\n    JSProperty *pr1;\n    \n    var_ref = pr->u.var_ref;\n    if (var_ref->header.ref_count == 1)\n        return 0;\n    p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);\n    pr1 = add_property(ctx, p1, prs->atom, JS_PROP_C_W_E | JS_PROP_VARREF);\n    if (!pr1)\n        return -1;\n    pr1->u.var_ref = var_ref;\n    var_ref->header.ref_count++;\n    JS_FreeValue(ctx, var_ref->value);\n    var_ref->is_lexical = FALSE;\n    var_ref->is_const = FALSE;\n    var_ref->value = JS_UNINITIALIZED;\n    return 0;\n}\n\nstatic int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)\n{\n    JSShape *sh;\n    JSShapeProperty *pr, *lpr, *prop;\n    JSProperty *pr1;\n    uint32_t lpr_idx;\n    intptr_t h, h1;\n\n redo:\n    sh = p->shape;\n    h1 = atom & sh->prop_hash_mask;\n    h = prop_hash_end(sh)[-h1 - 1];\n    prop = get_shape_prop(sh);\n    lpr = NULL;\n    lpr_idx = 0;   /* prevent warning */\n    while (h != 0) {\n        pr = &prop[h - 1];\n        if (likely(pr->atom == atom)) {\n            /* found ! */\n            if (!(pr->flags & JS_PROP_CONFIGURABLE))\n                return FALSE;\n            /* realloc the shape if needed */\n            if (lpr)\n                lpr_idx = lpr - get_shape_prop(sh);\n            if (js_shape_prepare_update(ctx, p, &pr))\n                return -1;\n            sh = p->shape;\n            /* remove property */\n            if (lpr) {\n                lpr = get_shape_prop(sh) + lpr_idx;\n                lpr->hash_next = pr->hash_next;\n            } else {\n                prop_hash_end(sh)[-h1 - 1] = pr->hash_next;\n            }\n            sh->deleted_prop_count++;\n            /* free the entry */\n            pr1 = &p->prop[h - 1];\n            if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {\n                if ((pr->flags & JS_PROP_TMASK) == JS_PROP_VARREF)\n                    if (remove_global_object_property(ctx, p, pr, pr1))\n                        return -1;\n            }\n            free_property(ctx->rt, pr1, pr->flags);\n            JS_FreeAtom(ctx, pr->atom);\n            /* put default values */\n            pr->flags = 0;\n            pr->atom = JS_ATOM_NULL;\n            pr1->u.value = JS_UNDEFINED;\n\n            /* compact the properties if too many deleted properties */\n            if (sh->deleted_prop_count >= 8 &&\n                sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {\n                compact_properties(ctx, p);\n            }\n            return TRUE;\n        }\n        lpr = pr;\n        h = pr->hash_next;\n    }\n\n    if (p->is_exotic) {\n        if (p->fast_array) {\n            uint32_t idx;\n            if (JS_AtomIsArrayIndex(ctx, &idx, atom) &&\n                idx < p->u.array.count) {\n                if (p->class_id == JS_CLASS_ARRAY ||\n                    p->class_id == JS_CLASS_ARGUMENTS ||\n                    p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {\n                    /* Special case deleting the last element of a fast Array */\n                    if (idx == p->u.array.count - 1) {\n                        if (p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {\n                            free_var_ref(ctx->rt, p->u.array.u.var_refs[idx]);\n                        } else {\n                            JS_FreeValue(ctx, p->u.array.u.values[idx]);\n                        }\n                        p->u.array.count = idx;\n                        return TRUE;\n                    }\n                    if (convert_fast_array_to_array(ctx, p))\n                        return -1;\n                    goto redo;\n                } else {\n                    return FALSE;\n                }\n            }\n        } else {\n            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n            if (em && em->delete_property) {\n                return em->delete_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), atom);\n            }\n        }\n    }\n    /* not found */\n    return TRUE;\n}\n\nstatic int call_setter(JSContext *ctx, JSObject *setter,\n                       JSValueConst this_obj, JSValue val, int flags)\n{\n    JSValue ret, func;\n    if (likely(setter)) {\n        func = JS_MKPTR(JS_TAG_OBJECT, setter);\n        /* Note: the field could be removed in the setter */\n        func = JS_DupValue(ctx, func);\n        ret = JS_CallFree(ctx, func, this_obj, 1, (JSValueConst *)&val);\n        JS_FreeValue(ctx, val);\n        if (JS_IsException(ret))\n            return -1;\n        JS_FreeValue(ctx, ret);\n        return TRUE;\n    } else {\n        JS_FreeValue(ctx, val);\n        if ((flags & JS_PROP_THROW) ||\n            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {\n            JS_ThrowTypeError(ctx, \"no setter for property\");\n            return -1;\n        }\n        return FALSE;\n    }\n}\n\n/* set the array length and remove the array elements if necessary. */\nstatic int set_array_length(JSContext *ctx, JSObject *p, JSValue val,\n                            int flags)\n{\n    uint32_t len, idx, cur_len;\n    int i, ret;\n\n    /* Note: this call can reallocate the properties of 'p' */\n    ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);\n    if (ret)\n        return -1;\n    /* JS_ToArrayLengthFree() must be done before the read-only test */\n    if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))\n        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);\n\n    if (likely(p->fast_array)) {\n        uint32_t old_len = p->u.array.count;\n        if (len < old_len) {\n            for(i = len; i < old_len; i++) {\n                JS_FreeValue(ctx, p->u.array.u.values[i]);\n            }\n            p->u.array.count = len;\n        }\n        p->prop[0].u.value = JS_NewUint32(ctx, len);\n    } else {\n        /* Note: length is always a uint32 because the object is an\n           array */\n        JS_ToUint32(ctx, &cur_len, p->prop[0].u.value);\n        if (len < cur_len) {\n            uint32_t d;\n            JSShape *sh;\n            JSShapeProperty *pr;\n\n            d = cur_len - len;\n            sh = p->shape;\n            if (d <= sh->prop_count) {\n                JSAtom atom;\n\n                /* faster to iterate */\n                while (cur_len > len) {\n                    atom = JS_NewAtomUInt32(ctx, cur_len - 1);\n                    ret = delete_property(ctx, p, atom);\n                    JS_FreeAtom(ctx, atom);\n                    if (unlikely(!ret)) {\n                        /* unlikely case: property is not\n                           configurable */\n                        break;\n                    }\n                    cur_len--;\n                }\n            } else {\n                /* faster to iterate thru all the properties. Need two\n                   passes in case one of the property is not\n                   configurable */\n                cur_len = len;\n                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;\n                    i++, pr++) {\n                    if (pr->atom != JS_ATOM_NULL &&\n                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {\n                        if (idx >= cur_len &&\n                            !(pr->flags & JS_PROP_CONFIGURABLE)) {\n                            cur_len = idx + 1;\n                        }\n                    }\n                }\n\n                for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count;\n                    i++, pr++) {\n                    if (pr->atom != JS_ATOM_NULL &&\n                        JS_AtomIsArrayIndex(ctx, &idx, pr->atom)) {\n                        if (idx >= cur_len) {\n                            /* remove the property */\n                            delete_property(ctx, p, pr->atom);\n                            /* WARNING: the shape may have been modified */\n                            sh = p->shape;\n                            pr = get_shape_prop(sh) + i;\n                        }\n                    }\n                }\n            }\n        } else {\n            cur_len = len;\n        }\n        set_value(ctx, &p->prop[0].u.value, JS_NewUint32(ctx, cur_len));\n        if (unlikely(cur_len > len)) {\n            return JS_ThrowTypeErrorOrFalse(ctx, flags, \"not configurable\");\n        }\n    }\n    return TRUE;\n}\n\n/* return -1 if exception */\nstatic int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)\n{\n    uint32_t new_size;\n    size_t slack;\n    JSValue *new_array_prop;\n    /* XXX: potential arithmetic overflow */\n    new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);\n    new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);\n    if (!new_array_prop)\n        return -1;\n    new_size += slack / sizeof(*new_array_prop);\n    p->u.array.u.values = new_array_prop;\n    p->u.array.u1.size = new_size;\n    return 0;\n}\n\n/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =\n   TRUE and p->extensible = TRUE */\nstatic inline int add_fast_array_element(JSContext *ctx, JSObject *p,\n                                         JSValue val, int flags)\n{\n    uint32_t new_len, array_len;\n    /* extend the array by one */\n    /* XXX: convert to slow array if new_len > 2^31-1 elements */\n    new_len = p->u.array.count + 1;\n    /* update the length if necessary. We assume that if the length is\n       not an integer, then if it >= 2^31.  */\n    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {\n        array_len = JS_VALUE_GET_INT(p->prop[0].u.value);\n        if (new_len > array_len) {\n            if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {\n                JS_FreeValue(ctx, val);\n                return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);\n            }\n            p->prop[0].u.value = JS_NewInt32(ctx, new_len);\n        }\n    }\n    if (unlikely(new_len > p->u.array.u1.size)) {\n        if (expand_fast_array(ctx, p, new_len)) {\n            JS_FreeValue(ctx, val);\n            return -1;\n        }\n    }\n    p->u.array.u.values[new_len - 1] = val;\n    p->u.array.count = new_len;\n    return TRUE;\n}\n\n/* Allocate a new fast array. Its 'length' property is set to zero. It\n   maximum size is 2^31-1 elements. For convenience, 'len' is a 64 bit\n   integer. WARNING: the content of the array is not initialized. */\nstatic JSValue js_allocate_fast_array(JSContext *ctx, int64_t len)\n{\n    JSValue arr;\n    JSObject *p;\n\n    if (len > INT32_MAX)\n        return JS_ThrowRangeError(ctx, \"invalid array length\");\n    arr = JS_NewArray(ctx);\n    if (JS_IsException(arr))\n        return arr;\n    if (len > 0) {\n        p = JS_VALUE_GET_OBJ(arr);\n        if (expand_fast_array(ctx, p, len) < 0) {\n            JS_FreeValue(ctx, arr);\n            return JS_EXCEPTION;\n        }\n        p->u.array.count = len;\n    }\n    return arr;\n}\n\nstatic JSValue js_create_array(JSContext *ctx, int len, JSValueConst *tab)\n{\n    JSValue obj;\n    JSObject *p;\n    int i;\n\n    obj = JS_NewArray(ctx);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    if (len > 0) {\n        p = JS_VALUE_GET_OBJ(obj);\n        if (expand_fast_array(ctx, p, len) < 0) {\n            JS_FreeValue(ctx, obj);\n            return JS_EXCEPTION;\n        }\n        p->u.array.count = len;\n        for(i = 0; i < len; i++) \n            p->u.array.u.values[i] = JS_DupValue(ctx, tab[i]);\n        /* update the 'length' field */\n        set_value(ctx, &p->prop[0].u.value, JS_NewInt32(ctx, len));\n    }\n    return obj;\n}\n\nstatic JSValue js_create_array_free(JSContext *ctx, int len, JSValue *tab)\n{\n    JSValue obj;\n    JSObject *p;\n    int i;\n\n    obj = JS_NewArray(ctx);\n    if (JS_IsException(obj))\n        goto fail;\n    if (len > 0) {\n        p = JS_VALUE_GET_OBJ(obj);\n        if (expand_fast_array(ctx, p, len) < 0) {\n            JS_FreeValue(ctx, obj);\n        fail:\n            for(i = 0; i < len; i++)\n                JS_FreeValue(ctx, tab[i]);\n            return JS_EXCEPTION;\n        }\n        p->u.array.count = len;\n        for(i = 0; i < len; i++) \n            p->u.array.u.values[i] = tab[i];\n        /* update the 'length' field */\n        set_value(ctx, &p->prop[0].u.value, JS_NewInt32(ctx, len));\n    }\n    return obj;\n}\n\nstatic void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)\n{\n    JS_FreeValue(ctx, desc->getter);\n    JS_FreeValue(ctx, desc->setter);\n    JS_FreeValue(ctx, desc->value);\n}\n\n/* return -1 in case of exception or TRUE or FALSE. Warning: 'val' is\n   freed by the function. 'flags' is a bitmask of JS_PROP_THROW and\n   JS_PROP_THROW_STRICT. 'this_obj' is the receiver. If obj !=\n   this_obj, then obj must be an object (Reflect.set case). */\nint JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,\n                           JSAtom prop, JSValue val, JSValueConst this_obj, int flags)\n{\n    JSObject *p, *p1;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    uint32_t tag;\n    JSPropertyDescriptor desc;\n    int ret;\n#if 0\n    printf(\"JS_SetPropertyInternal: \"); print_atom(ctx, prop); printf(\"\\n\");\n#endif\n    tag = JS_VALUE_GET_TAG(this_obj);\n    if (unlikely(tag != JS_TAG_OBJECT)) {\n        if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n            p = NULL;\n            p1 = JS_VALUE_GET_OBJ(obj);\n            goto prototype_lookup;\n        } else {\n            switch(tag) {\n            case JS_TAG_NULL:\n                JS_FreeValue(ctx, val);\n                JS_ThrowTypeErrorAtom(ctx, \"cannot set property '%s' of null\", prop);\n                return -1;\n            case JS_TAG_UNDEFINED:\n                JS_FreeValue(ctx, val);\n                JS_ThrowTypeErrorAtom(ctx, \"cannot set property '%s' of undefined\", prop);\n                return -1;\n            default:\n                /* even on a primitive type we can have setters on the prototype */\n                p = NULL;\n                p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));\n                goto prototype_lookup;\n            }\n        }\n    } else {\n        p = JS_VALUE_GET_OBJ(this_obj);\n        p1 = JS_VALUE_GET_OBJ(obj);\n        if (unlikely(p != p1))\n            goto retry2;\n    }\n\n    /* fast path if obj == this_obj */\n retry:\n    prs = find_own_property(&pr, p1, prop);\n    if (prs) {\n        if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |\n                                  JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {\n            /* fast case */\n            set_value(ctx, &pr->u.value, val);\n            return TRUE;\n        } else if (prs->flags & JS_PROP_LENGTH) {\n            assert(p->class_id == JS_CLASS_ARRAY);\n            assert(prop == JS_ATOM_length);\n            return set_array_length(ctx, p, val, flags);\n        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n            return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);\n        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n            /* XXX: already use var_ref->is_const. Cannot simplify use the\n               writable flag for JS_CLASS_MODULE_NS. */\n            if (p->class_id == JS_CLASS_MODULE_NS || pr->u.var_ref->is_const)\n                goto read_only_prop;\n            set_value(ctx, pr->u.var_ref->pvalue, val);\n            return TRUE;\n        } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n            /* Instantiate property and retry (potentially useless) */\n            if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {\n                JS_FreeValue(ctx, val);\n                return -1;\n            }\n            goto retry;\n        } else {\n            goto read_only_prop;\n        }\n    }\n\n    for(;;) {\n        if (p1->is_exotic) {\n            if (p1->fast_array) {\n                if (__JS_AtomIsTaggedInt(prop)) {\n                    uint32_t idx = __JS_AtomToUInt32(prop);\n                    if (idx < p1->u.array.count) {\n                        if (unlikely(p == p1))\n                            return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val, flags);\n                        else\n                            break;\n                    } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                               p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n                        goto typed_array_oob;\n                    }\n                } else if (p1->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                           p1->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n                    ret = JS_AtomIsNumericIndex(ctx, prop);\n                    if (ret != 0) {\n                        if (ret < 0) {\n                            JS_FreeValue(ctx, val);\n                            return -1;\n                        }\n                    typed_array_oob:\n                        if (p == p1) {\n                            /* must convert the argument even if out of bound access */\n                            if (p1->class_id == JS_CLASS_BIG_INT64_ARRAY ||\n                                p1->class_id == JS_CLASS_BIG_UINT64_ARRAY) {\n                                int64_t v;\n                                if (JS_ToBigInt64Free(ctx, &v, val))\n                                    return -1;\n                            } else {\n                                val = JS_ToNumberFree(ctx, val);\n                                JS_FreeValue(ctx, val);\n                                if (JS_IsException(val))\n                                    return -1;\n                            }\n                        } else {\n                            JS_FreeValue(ctx, val);\n                        }\n                        return TRUE;\n                    }\n                }\n            } else {\n                const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;\n                if (em) {\n                    JSValue obj1;\n                    if (em->set_property) {\n                        /* set_property can free the prototype */\n                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));\n                        ret = em->set_property(ctx, obj1, prop,\n                                               val, this_obj, flags);\n                        JS_FreeValue(ctx, obj1);\n                        JS_FreeValue(ctx, val);\n                        return ret;\n                    }\n                    if (em->get_own_property) {\n                        /* get_own_property can free the prototype */\n                        obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));\n                        ret = em->get_own_property(ctx, &desc,\n                                                   obj1, prop);\n                        JS_FreeValue(ctx, obj1);\n                        if (ret < 0) {\n                            JS_FreeValue(ctx, val);\n                            return ret;\n                        }\n                        if (ret) {\n                            if (desc.flags & JS_PROP_GETSET) {\n                                JSObject *setter;\n                                if (JS_IsUndefined(desc.setter))\n                                    setter = NULL;\n                                else\n                                    setter = JS_VALUE_GET_OBJ(desc.setter);\n                                ret = call_setter(ctx, setter, this_obj, val, flags);\n                                JS_FreeValue(ctx, desc.getter);\n                                JS_FreeValue(ctx, desc.setter);\n                                return ret;\n                            } else {\n                                JS_FreeValue(ctx, desc.value);\n                                if (!(desc.flags & JS_PROP_WRITABLE))\n                                    goto read_only_prop;\n                                if (likely(p == p1)) {\n                                    ret = JS_DefineProperty(ctx, this_obj, prop, val,\n                                                            JS_UNDEFINED, JS_UNDEFINED,\n                                                            JS_PROP_HAS_VALUE);\n                                    JS_FreeValue(ctx, val);\n                                    return ret;\n                                } else {\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        p1 = p1->shape->proto;\n    prototype_lookup:\n        if (!p1)\n            break;\n\n    retry2:\n        prs = find_own_property(&pr, p1, prop);\n        if (prs) {\n            if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);\n            } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n                /* Instantiate property and retry (potentially useless) */\n                if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))\n                    return -1;\n                goto retry2;\n            } else if (!(prs->flags & JS_PROP_WRITABLE)) {\n                goto read_only_prop;\n            } else {\n                break;\n            }\n        }\n    }\n\n    if (unlikely(!p)) {\n        JS_FreeValue(ctx, val);\n        return JS_ThrowTypeErrorOrFalse(ctx, flags, \"not an object\");\n    }\n\n    if (unlikely(!p->extensible)) {\n        JS_FreeValue(ctx, val);\n        return JS_ThrowTypeErrorOrFalse(ctx, flags, \"object is not extensible\");\n    }\n\n    if (likely(p == JS_VALUE_GET_OBJ(obj))) {\n        if (p->is_exotic) {\n            if (p->class_id == JS_CLASS_ARRAY && p->fast_array &&\n                __JS_AtomIsTaggedInt(prop)) {\n                uint32_t idx = __JS_AtomToUInt32(prop);\n                if (idx == p->u.array.count) {\n                    /* fast case */\n                    return add_fast_array_element(ctx, p, val, flags);\n                } else {\n                    goto generic_create_prop;\n                }\n            } else {\n                goto generic_create_prop;\n            }\n        } else {\n            if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT))\n                goto generic_create_prop;\n            pr = add_property(ctx, p, prop, JS_PROP_C_W_E);\n            if (unlikely(!pr)) {\n                JS_FreeValue(ctx, val);\n                return -1;\n            }\n            pr->u.value = val;\n            return TRUE;\n        }\n    } else {\n        /* generic case: modify the property in this_obj if it already exists */\n        ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);\n        if (ret < 0) {\n            JS_FreeValue(ctx, val);\n            return ret;\n        }\n        if (ret) {\n            if (desc.flags & JS_PROP_GETSET) {\n                JS_FreeValue(ctx, desc.getter);\n                JS_FreeValue(ctx, desc.setter);\n                JS_FreeValue(ctx, val);\n                return JS_ThrowTypeErrorOrFalse(ctx, flags, \"setter is forbidden\");\n            } else {\n                JS_FreeValue(ctx, desc.value);\n                if (!(desc.flags & JS_PROP_WRITABLE) ||\n                    p->class_id == JS_CLASS_MODULE_NS) {\n                read_only_prop:\n                    JS_FreeValue(ctx, val);\n                    return JS_ThrowTypeErrorReadOnly(ctx, flags, prop);\n                }\n            }\n            ret = JS_DefineProperty(ctx, this_obj, prop, val,\n                                    JS_UNDEFINED, JS_UNDEFINED,\n                                    JS_PROP_HAS_VALUE);\n            JS_FreeValue(ctx, val);\n            return ret;\n        } else {\n        generic_create_prop:\n            ret = JS_CreateProperty(ctx, p, prop, val, JS_UNDEFINED, JS_UNDEFINED,\n                                    flags |\n                                    JS_PROP_HAS_VALUE |\n                                    JS_PROP_HAS_ENUMERABLE |\n                                    JS_PROP_HAS_WRITABLE |\n                                    JS_PROP_HAS_CONFIGURABLE |\n                                    JS_PROP_C_W_E);\n            JS_FreeValue(ctx, val);\n            return ret;\n        }\n    }\n}\n\n/* return true if an element can be added to a fast array without further tests */\nstatic force_inline BOOL can_extend_fast_array(JSObject *p)\n{\n    JSObject *proto;\n    if (!p->extensible)\n        return FALSE;\n    proto = p->shape->proto;\n    if (!proto)\n        return TRUE;\n    return proto->is_std_array_prototype;\n}\n\n/* flags can be JS_PROP_THROW or JS_PROP_THROW_STRICT */\nstatic int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,\n                               JSValue prop, JSValue val, int flags)\n{\n    if (likely(JS_VALUE_GET_TAG(this_obj) == JS_TAG_OBJECT &&\n               JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {\n        JSObject *p;\n        uint32_t idx;\n        double d;\n        int32_t v;\n\n        /* fast path for array access */\n        p = JS_VALUE_GET_OBJ(this_obj);\n        idx = JS_VALUE_GET_INT(prop);\n        switch(p->class_id) {\n        case JS_CLASS_ARRAY:\n            if (unlikely(idx >= (uint32_t)p->u.array.count)) {\n                /* fast path to add an element to the array */\n                if (unlikely(idx != (uint32_t)p->u.array.count ||\n                             !p->fast_array ||\n                             !can_extend_fast_array(p))) {\n                    goto slow_path;\n                }\n                /* add element */\n                return add_fast_array_element(ctx, p, val, flags);\n            }\n            set_value(ctx, &p->u.array.u.values[idx], val);\n            break;\n        case JS_CLASS_ARGUMENTS:\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto slow_path;\n            set_value(ctx, &p->u.array.u.values[idx], val);\n            break;\n        case JS_CLASS_MAPPED_ARGUMENTS:\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto slow_path;\n            set_value(ctx, p->u.array.u.var_refs[idx]->pvalue, val);\n            break;\n        case JS_CLASS_UINT8C_ARRAY:\n            if (JS_ToUint8ClampFree(ctx, &v, val))\n                return -1;\n            /* Note: the conversion can detach the typed array, so the\n               array bound check must be done after */\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto ta_out_of_bound;\n            p->u.array.u.uint8_ptr[idx] = v;\n            break;\n        case JS_CLASS_INT8_ARRAY:\n        case JS_CLASS_UINT8_ARRAY:\n            if (JS_ToInt32Free(ctx, &v, val))\n                return -1;\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto ta_out_of_bound;\n            p->u.array.u.uint8_ptr[idx] = v;\n            break;\n        case JS_CLASS_INT16_ARRAY:\n        case JS_CLASS_UINT16_ARRAY:\n            if (JS_ToInt32Free(ctx, &v, val))\n                return -1;\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto ta_out_of_bound;\n            p->u.array.u.uint16_ptr[idx] = v;\n            break;\n        case JS_CLASS_INT32_ARRAY:\n        case JS_CLASS_UINT32_ARRAY:\n            if (JS_ToInt32Free(ctx, &v, val))\n                return -1;\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto ta_out_of_bound;\n            p->u.array.u.uint32_ptr[idx] = v;\n            break;\n        case JS_CLASS_BIG_INT64_ARRAY:\n        case JS_CLASS_BIG_UINT64_ARRAY:\n            /* XXX: need specific conversion function */\n            {\n                int64_t v;\n                if (JS_ToBigInt64Free(ctx, &v, val))\n                    return -1;\n                if (unlikely(idx >= (uint32_t)p->u.array.count))\n                    goto ta_out_of_bound;\n                p->u.array.u.uint64_ptr[idx] = v;\n            }\n            break;\n        case JS_CLASS_FLOAT16_ARRAY:\n            if (JS_ToFloat64Free(ctx, &d, val))\n                return -1;\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto ta_out_of_bound;\n            p->u.array.u.fp16_ptr[idx] = tofp16(d);\n            break;\n        case JS_CLASS_FLOAT32_ARRAY:\n            if (JS_ToFloat64Free(ctx, &d, val))\n                return -1;\n            if (unlikely(idx >= (uint32_t)p->u.array.count))\n                goto ta_out_of_bound;\n            p->u.array.u.float_ptr[idx] = d;\n            break;\n        case JS_CLASS_FLOAT64_ARRAY:\n            if (JS_ToFloat64Free(ctx, &d, val))\n                return -1;\n            if (unlikely(idx >= (uint32_t)p->u.array.count)) {\n            ta_out_of_bound:\n                return TRUE;\n            }\n            p->u.array.u.double_ptr[idx] = d;\n            break;\n        default:\n            goto slow_path;\n        }\n        return TRUE;\n    } else {\n        JSAtom atom;\n        int ret;\n    slow_path:\n        atom = JS_ValueToAtom(ctx, prop);\n        JS_FreeValue(ctx, prop);\n        if (unlikely(atom == JS_ATOM_NULL)) {\n            JS_FreeValue(ctx, val);\n            return -1;\n        }\n        ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags);\n        JS_FreeAtom(ctx, atom);\n        return ret;\n    }\n}\n\nint JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,\n                         uint32_t idx, JSValue val)\n{\n    return JS_SetPropertyValue(ctx, this_obj, JS_NewUint32(ctx, idx), val,\n                               JS_PROP_THROW);\n}\n\nint JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,\n                        int64_t idx, JSValue val)\n{\n    JSAtom prop;\n    int res;\n\n    if ((uint64_t)idx <= INT32_MAX) {\n        /* fast path for fast arrays */\n        return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), val,\n                                   JS_PROP_THROW);\n    }\n    prop = JS_NewAtomInt64(ctx, idx);\n    if (prop == JS_ATOM_NULL) {\n        JS_FreeValue(ctx, val);\n        return -1;\n    }\n    res = JS_SetProperty(ctx, this_obj, prop, val);\n    JS_FreeAtom(ctx, prop);\n    return res;\n}\n\nint JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,\n                      const char *prop, JSValue val)\n{\n    JSAtom atom;\n    int ret;\n    atom = JS_NewAtom(ctx, prop);\n    if (atom == JS_ATOM_NULL) {\n        JS_FreeValue(ctx, val);\n        return -1;\n    }\n    ret = JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, JS_PROP_THROW);\n    JS_FreeAtom(ctx, atom);\n    return ret;\n}\n\n/* compute the property flags. For each flag: (JS_PROP_HAS_x forces\n   it, otherwise def_flags is used)\n   Note: makes assumption about the bit pattern of the flags\n*/\nstatic int get_prop_flags(int flags, int def_flags)\n{\n    int mask;\n    mask = (flags >> JS_PROP_HAS_SHIFT) & JS_PROP_C_W_E;\n    return (flags & mask) | (def_flags & ~mask);\n}\n\nstatic int JS_CreateProperty(JSContext *ctx, JSObject *p,\n                             JSAtom prop, JSValueConst val,\n                             JSValueConst getter, JSValueConst setter,\n                             int flags)\n{\n    JSProperty *pr;\n    int ret, prop_flags;\n    JSVarRef *var_ref;\n    JSObject *delete_obj;\n    \n    /* add a new property or modify an existing exotic one */\n    if (p->is_exotic) {\n        if (p->class_id == JS_CLASS_ARRAY) {\n            uint32_t idx, len;\n\n            if (p->fast_array) {\n                if (__JS_AtomIsTaggedInt(prop)) {\n                    idx = __JS_AtomToUInt32(prop);\n                    if (idx == p->u.array.count) {\n                        if (!p->extensible)\n                            goto not_extensible;\n                        if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET))\n                            goto convert_to_array;\n                        prop_flags = get_prop_flags(flags, 0);\n                        if (prop_flags != JS_PROP_C_W_E)\n                            goto convert_to_array;\n                        return add_fast_array_element(ctx, p,\n                                                      JS_DupValue(ctx, val), flags);\n                    } else {\n                        goto convert_to_array;\n                    }\n                } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {\n                    /* convert the fast array to normal array */\n                convert_to_array:\n                    if (convert_fast_array_to_array(ctx, p))\n                        return -1;\n                    goto generic_array;\n                }\n            } else if (JS_AtomIsArrayIndex(ctx, &idx, prop)) {\n                JSProperty *plen;\n                JSShapeProperty *pslen;\n            generic_array:\n                /* update the length field */\n                plen = &p->prop[0];\n                JS_ToUint32(ctx, &len, plen->u.value);\n                if ((idx + 1) > len) {\n                    pslen = get_shape_prop(p->shape);\n                    if (unlikely(!(pslen->flags & JS_PROP_WRITABLE)))\n                        return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);\n                    /* XXX: should update the length after defining\n                       the property */\n                    len = idx + 1;\n                    set_value(ctx, &plen->u.value, JS_NewUint32(ctx, len));\n                }\n            }\n        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n            ret = JS_AtomIsNumericIndex(ctx, prop);\n            if (ret != 0) {\n                if (ret < 0)\n                    return -1;\n                return JS_ThrowTypeErrorOrFalse(ctx, flags, \"cannot create numeric index in typed array\");\n            }\n        } else if (!(flags & JS_PROP_NO_EXOTIC)) {\n            const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n            if (em) {\n                if (em->define_own_property) {\n                    return em->define_own_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),\n                                                   prop, val, getter, setter, flags);\n                }\n                ret = JS_IsExtensible(ctx, JS_MKPTR(JS_TAG_OBJECT, p));\n                if (ret < 0)\n                    return -1;\n                if (!ret)\n                    goto not_extensible;\n            }\n        }\n    }\n\n    if (!p->extensible) {\n    not_extensible:\n        return JS_ThrowTypeErrorOrFalse(ctx, flags, \"object is not extensible\");\n    }\n\n    var_ref = NULL;\n    delete_obj = NULL;\n    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {\n        prop_flags = (flags & (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |\n            JS_PROP_GETSET;\n    } else {\n        prop_flags = flags & JS_PROP_C_W_E;\n        if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {\n            JSObject *p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);\n            JSShapeProperty *prs1;\n            JSProperty *pr1;\n            prs1 = find_own_property(&pr1, p1, prop);\n            if (prs1) {\n                delete_obj = p1;\n                var_ref = pr1->u.var_ref;\n                var_ref->header.ref_count++;\n            } else {\n                var_ref = js_create_var_ref(ctx, FALSE);\n                if (!var_ref)\n                    return -1;\n            }\n            var_ref->is_const = !(prop_flags & JS_PROP_WRITABLE);\n            prop_flags |= JS_PROP_VARREF;\n        }\n    }\n    pr = add_property(ctx, p, prop, prop_flags);\n    if (unlikely(!pr)) {\n        if (var_ref)\n            free_var_ref(ctx->rt, var_ref);\n        return -1;\n    }\n    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {\n        pr->u.getset.getter = NULL;\n        if ((flags & JS_PROP_HAS_GET) && JS_IsFunction(ctx, getter)) {\n            pr->u.getset.getter =\n                JS_VALUE_GET_OBJ(JS_DupValue(ctx, getter));\n        }\n        pr->u.getset.setter = NULL;\n        if ((flags & JS_PROP_HAS_SET) && JS_IsFunction(ctx, setter)) {\n            pr->u.getset.setter =\n                JS_VALUE_GET_OBJ(JS_DupValue(ctx, setter));\n        }\n    } else if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {\n        if (delete_obj)\n            delete_property(ctx, delete_obj, prop);\n        pr->u.var_ref = var_ref;\n        if (flags & JS_PROP_HAS_VALUE) {\n            *var_ref->pvalue = JS_DupValue(ctx, val);\n        } else {\n            *var_ref->pvalue = JS_UNDEFINED;\n        }\n    } else {\n        if (flags & JS_PROP_HAS_VALUE) {\n            pr->u.value = JS_DupValue(ctx, val);\n        } else {\n            pr->u.value = JS_UNDEFINED;\n        }\n    }\n    return TRUE;\n}\n\n/* return FALSE if not OK */\nstatic BOOL check_define_prop_flags(int prop_flags, int flags)\n{\n    BOOL has_accessor, is_getset;\n\n    if (!(prop_flags & JS_PROP_CONFIGURABLE)) {\n        if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) ==\n            (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) {\n            return FALSE;\n        }\n        if ((flags & JS_PROP_HAS_ENUMERABLE) &&\n            (flags & JS_PROP_ENUMERABLE) != (prop_flags & JS_PROP_ENUMERABLE))\n            return FALSE;\n        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |\n                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {\n            has_accessor = ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) != 0);\n            is_getset = ((prop_flags & JS_PROP_TMASK) == JS_PROP_GETSET);\n            if (has_accessor != is_getset)\n                return FALSE;\n            if (!is_getset && !(prop_flags & JS_PROP_WRITABLE)) {\n                /* not writable: cannot set the writable bit */\n                if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==\n                    (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))\n                    return FALSE;\n            }\n        }\n    }\n    return TRUE;\n}\n\n/* ensure that the shape can be safely modified */\nstatic int js_shape_prepare_update(JSContext *ctx, JSObject *p,\n                                   JSShapeProperty **pprs)\n{\n    JSShape *sh;\n    uint32_t idx = 0;    /* prevent warning */\n\n    sh = p->shape;\n    if (sh->is_hashed) {\n        if (sh->header.ref_count != 1) {\n            if (pprs)\n                idx = *pprs - get_shape_prop(sh);\n            /* clone the shape (the resulting one is no longer hashed) */\n            sh = js_clone_shape(ctx, sh);\n            if (!sh)\n                return -1;\n            js_free_shape(ctx->rt, p->shape);\n            p->shape = sh;\n            if (pprs)\n                *pprs = get_shape_prop(sh) + idx;\n        } else {\n            js_shape_hash_unlink(ctx->rt, sh);\n            sh->is_hashed = FALSE;\n        }\n    }\n    return 0;\n}\n\nstatic int js_update_property_flags(JSContext *ctx, JSObject *p,\n                                    JSShapeProperty **pprs, int flags)\n{\n    if (flags != (*pprs)->flags) {\n        if (js_shape_prepare_update(ctx, p, pprs))\n            return -1;\n        (*pprs)->flags = flags;\n    }\n    return 0;\n}\n\n/* allowed flags:\n   JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE\n   JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE,\n   JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE,\n   JS_PROP_THROW, JS_PROP_NO_EXOTIC.\n   If JS_PROP_THROW is set, return an exception instead of FALSE.\n   if JS_PROP_NO_EXOTIC is set, do not call the exotic\n   define_own_property callback.\n   return -1 (exception), FALSE or TRUE.\n*/\nint JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,\n                      JSAtom prop, JSValueConst val,\n                      JSValueConst getter, JSValueConst setter, int flags)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    int mask, res;\n\n    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        return -1;\n    }\n    p = JS_VALUE_GET_OBJ(this_obj);\n\n redo_prop_update:\n    prs = find_own_property(&pr, p, prop);\n    if (prs) {\n        /* the range of the Array length property is always tested before */\n        if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {\n            uint32_t array_length;\n            if (JS_ToArrayLengthFree(ctx, &array_length,\n                                     JS_DupValue(ctx, val), FALSE)) {\n                return -1;\n            }\n            /* this code relies on the fact that Uint32 are never allocated */\n            val = (JSValueConst)JS_NewUint32(ctx, array_length);\n            /* prs may have been modified */\n            prs = find_own_property(&pr, p, prop);\n            assert(prs != NULL);\n        }\n        /* property already exists */\n        if (!check_define_prop_flags(prs->flags, flags)) {\n        not_configurable:\n            return JS_ThrowTypeErrorOrFalse(ctx, flags, \"property is not configurable\");\n        }\n\n        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n            /* Instantiate property and retry */\n            if (JS_AutoInitProperty(ctx, p, prop, pr, prs))\n                return -1;\n            goto redo_prop_update;\n        }\n\n        if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |\n                     JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {\n            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {\n                JSObject *new_getter, *new_setter;\n\n                if (JS_IsFunction(ctx, getter)) {\n                    new_getter = JS_VALUE_GET_OBJ(getter);\n                } else {\n                    new_getter = NULL;\n                }\n                if (JS_IsFunction(ctx, setter)) {\n                    new_setter = JS_VALUE_GET_OBJ(setter);\n                } else {\n                    new_setter = NULL;\n                }\n\n                if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET) {\n                    if (js_shape_prepare_update(ctx, p, &prs))\n                        return -1;\n                    /* convert to getset */\n                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n                        if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {\n                            if (remove_global_object_property(ctx, p, prs, pr))\n                                return -1;\n                        }\n                        free_var_ref(ctx->rt, pr->u.var_ref);\n                    } else {\n                        JS_FreeValue(ctx, pr->u.value);\n                    }\n                    prs->flags = (prs->flags &\n                                  (JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE)) |\n                        JS_PROP_GETSET;\n                    pr->u.getset.getter = NULL;\n                    pr->u.getset.setter = NULL;\n                } else {\n                    if (!(prs->flags & JS_PROP_CONFIGURABLE)) {\n                        if ((flags & JS_PROP_HAS_GET) &&\n                            new_getter != pr->u.getset.getter) {\n                            goto not_configurable;\n                        }\n                        if ((flags & JS_PROP_HAS_SET) &&\n                            new_setter != pr->u.getset.setter) {\n                            goto not_configurable;\n                        }\n                    }\n                }\n                if (flags & JS_PROP_HAS_GET) {\n                    if (pr->u.getset.getter)\n                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));\n                    if (new_getter)\n                        JS_DupValue(ctx, getter);\n                    pr->u.getset.getter = new_getter;\n                }\n                if (flags & JS_PROP_HAS_SET) {\n                    if (pr->u.getset.setter)\n                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));\n                    if (new_setter)\n                        JS_DupValue(ctx, setter);\n                    pr->u.getset.setter = new_setter;\n                }\n            } else {\n                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                    /* convert to data descriptor */\n                    JSVarRef *var_ref;\n                    if (unlikely(p->class_id == JS_CLASS_GLOBAL_OBJECT)) {\n                        var_ref = js_global_object_find_uninitialized_var(ctx, p, prop, FALSE);\n                        if (!var_ref)\n                            return -1;\n                    } else {\n                        var_ref = NULL;\n                    }\n                    if (js_shape_prepare_update(ctx, p, &prs)) {\n                        if (var_ref)\n                            free_var_ref(ctx->rt, var_ref);\n                        return -1;\n                    }\n                    if (pr->u.getset.getter)\n                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter));\n                    if (pr->u.getset.setter)\n                        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.setter));\n                    if (var_ref) {\n                        prs->flags = (prs->flags & ~JS_PROP_TMASK) |\n                            JS_PROP_VARREF | JS_PROP_WRITABLE;\n                        pr->u.var_ref = var_ref;\n                    } else {\n                        prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);\n                        pr->u.value = JS_UNDEFINED;\n                    }\n                } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n                    /* Note: JS_PROP_VARREF is always writable */\n                } else {\n                    if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&\n                        (flags & JS_PROP_HAS_VALUE)) {\n                        if (!js_same_value(ctx, val, pr->u.value)) {\n                            goto not_configurable;\n                        } else {\n                            return TRUE;\n                        }\n                    }\n                }\n                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n                    if (flags & JS_PROP_HAS_VALUE) {\n                        if (p->class_id == JS_CLASS_MODULE_NS) {\n                            /* JS_PROP_WRITABLE is always true for variable\n                               references, but they are write protected in module name\n                               spaces. */\n                            if (!js_same_value(ctx, val, *pr->u.var_ref->pvalue))\n                                goto not_configurable;\n                        } else {\n                            /* update the reference */\n                            set_value(ctx, pr->u.var_ref->pvalue,\n                                      JS_DupValue(ctx, val));\n                        }\n                    }\n                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {\n                        JSValue val1;\n                        if (p->class_id == JS_CLASS_MODULE_NS) {\n                            return JS_ThrowTypeErrorOrFalse(ctx, flags, \"module namespace properties have writable = false\");\n                        }\n                        if (js_shape_prepare_update(ctx, p, &prs))\n                            return -1;\n                        if (p->class_id == JS_CLASS_GLOBAL_OBJECT) {\n                            pr->u.var_ref->is_const = TRUE; /* mark as read-only */\n                            prs->flags &= ~JS_PROP_WRITABLE;\n                        } else {\n                            /* if writable is set to false, no longer a\n                               reference (for mapped arguments) */\n                            val1 = JS_DupValue(ctx, *pr->u.var_ref->pvalue);\n                            free_var_ref(ctx->rt, pr->u.var_ref);\n                            pr->u.value = val1;\n                            prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);\n                        }\n                    }\n                } else if (prs->flags & JS_PROP_LENGTH) {\n                    if (flags & JS_PROP_HAS_VALUE) {\n                        /* Note: no JS code is executable because\n                           'val' is guaranted to be a Uint32 */\n                        res = set_array_length(ctx, p, JS_DupValue(ctx, val),\n                                               flags);\n                    } else {\n                        res = TRUE;\n                    }\n                    /* still need to reset the writable flag if\n                       needed.  The JS_PROP_LENGTH is kept because the\n                       Uint32 test is still done if the length\n                       property is read-only. */\n                    if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==\n                        JS_PROP_HAS_WRITABLE) {\n                        prs = get_shape_prop(p->shape);\n                        if (js_update_property_flags(ctx, p, &prs,\n                                                     prs->flags & ~JS_PROP_WRITABLE))\n                            return -1;\n                    }\n                    return res;\n                } else {\n                    if (flags & JS_PROP_HAS_VALUE) {\n                        JS_FreeValue(ctx, pr->u.value);\n                        pr->u.value = JS_DupValue(ctx, val);\n                    }\n                    if (flags & JS_PROP_HAS_WRITABLE) {\n                        if (js_update_property_flags(ctx, p, &prs,\n                                                     (prs->flags & ~JS_PROP_WRITABLE) |\n                                                     (flags & JS_PROP_WRITABLE)))\n                            return -1;\n                    }\n                }\n            }\n        }\n        mask = 0;\n        if (flags & JS_PROP_HAS_CONFIGURABLE)\n            mask |= JS_PROP_CONFIGURABLE;\n        if (flags & JS_PROP_HAS_ENUMERABLE)\n            mask |= JS_PROP_ENUMERABLE;\n        if (js_update_property_flags(ctx, p, &prs,\n                                     (prs->flags & ~mask) | (flags & mask)))\n            return -1;\n        return TRUE;\n    }\n\n    /* handle modification of fast array elements */\n    if (p->fast_array) {\n        uint32_t idx;\n        uint32_t prop_flags;\n        if (p->class_id == JS_CLASS_ARRAY) {\n            if (__JS_AtomIsTaggedInt(prop)) {\n                idx = __JS_AtomToUInt32(prop);\n                if (idx < p->u.array.count) {\n                    prop_flags = get_prop_flags(flags, JS_PROP_C_W_E);\n                    if (prop_flags != JS_PROP_C_W_E)\n                        goto convert_to_slow_array;\n                    if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {\n                    convert_to_slow_array:\n                        if (convert_fast_array_to_array(ctx, p))\n                            return -1;\n                        else\n                            goto redo_prop_update;\n                    }\n                    if (flags & JS_PROP_HAS_VALUE) {\n                        set_value(ctx, &p->u.array.u.values[idx], JS_DupValue(ctx, val));\n                    }\n                    return TRUE;\n                }\n            }\n        } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                   p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n            JSValue num;\n            int ret;\n\n            if (!__JS_AtomIsTaggedInt(prop)) {\n                /* slow path with to handle all numeric indexes */\n                num = JS_AtomIsNumericIndex1(ctx, prop);\n                if (JS_IsUndefined(num))\n                    goto typed_array_done;\n                if (JS_IsException(num))\n                    return -1;\n                ret = JS_NumberIsInteger(ctx, num);\n                if (ret < 0) {\n                    JS_FreeValue(ctx, num);\n                    return -1;\n                }\n                if (!ret) {\n                    JS_FreeValue(ctx, num);\n                    return JS_ThrowTypeErrorOrFalse(ctx, flags, \"non integer index in typed array\");\n                }\n                ret = JS_NumberIsNegativeOrMinusZero(ctx, num);\n                JS_FreeValue(ctx, num);\n                if (ret) {\n                    return JS_ThrowTypeErrorOrFalse(ctx, flags, \"negative index in typed array\");\n                }\n                if (!__JS_AtomIsTaggedInt(prop))\n                    goto typed_array_oob;\n            }\n            idx = __JS_AtomToUInt32(prop);\n            /* if the typed array is detached, p->u.array.count = 0 */\n            if (idx >= p->u.array.count) {\n            typed_array_oob:\n                return JS_ThrowTypeErrorOrFalse(ctx, flags, \"out-of-bound index in typed array\");\n            }\n            prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n            if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||\n                prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {\n                return JS_ThrowTypeErrorOrFalse(ctx, flags, \"invalid descriptor flags\");\n            }\n            if (flags & JS_PROP_HAS_VALUE) {\n                return JS_SetPropertyValue(ctx, this_obj, JS_NewInt32(ctx, idx), JS_DupValue(ctx, val), flags);\n            }\n            return TRUE;\n        typed_array_done: ;\n        }\n    }\n\n    return JS_CreateProperty(ctx, p, prop, val, getter, setter, flags);\n}\n\nstatic int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj,\n                                     JSAtom prop, JSAutoInitIDEnum id,\n                                     void *opaque, int flags)\n{\n    JSObject *p;\n    JSProperty *pr;\n\n    if (JS_VALUE_GET_TAG(this_obj) != JS_TAG_OBJECT)\n        return FALSE;\n\n    p = JS_VALUE_GET_OBJ(this_obj);\n\n    if (find_own_property(&pr, p, prop)) {\n        /* property already exists */\n        abort();\n        return FALSE;\n    }\n\n    /* Specialized CreateProperty */\n    pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);\n    if (unlikely(!pr))\n        return -1;\n    pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);\n    assert((pr->u.init.realm_and_id & 3) == 0);\n    assert(id <= 3);\n    pr->u.init.realm_and_id |= id;\n    pr->u.init.opaque = opaque;\n    return TRUE;\n}\n\n/* shortcut to add or redefine a new property value */\nint JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,\n                           JSAtom prop, JSValue val, int flags)\n{\n    int ret;\n    ret = JS_DefineProperty(ctx, this_obj, prop, val, JS_UNDEFINED, JS_UNDEFINED,\n                            flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nint JS_DefinePropertyValueValue(JSContext *ctx, JSValueConst this_obj,\n                                JSValue prop, JSValue val, int flags)\n{\n    JSAtom atom;\n    int ret;\n    atom = JS_ValueToAtom(ctx, prop);\n    JS_FreeValue(ctx, prop);\n    if (unlikely(atom == JS_ATOM_NULL)) {\n        JS_FreeValue(ctx, val);\n        return -1;\n    }\n    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);\n    JS_FreeAtom(ctx, atom);\n    return ret;\n}\n\nint JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,\n                                 uint32_t idx, JSValue val, int flags)\n{\n    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewUint32(ctx, idx),\n                                       val, flags);\n}\n\nint JS_DefinePropertyValueInt64(JSContext *ctx, JSValueConst this_obj,\n                                int64_t idx, JSValue val, int flags)\n{\n    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),\n                                       val, flags);\n}\n\nint JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,\n                              const char *prop, JSValue val, int flags)\n{\n    JSAtom atom;\n    int ret;\n    atom = JS_NewAtom(ctx, prop);\n    if (atom == JS_ATOM_NULL) {\n        JS_FreeValue(ctx, val);\n        return -1;\n    }\n    ret = JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);\n    JS_FreeAtom(ctx, atom);\n    return ret;\n}\n\n/* shortcut to add getter & setter */\nint JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,\n                            JSAtom prop, JSValue getter, JSValue setter,\n                            int flags)\n{\n    int ret;\n    ret = JS_DefineProperty(ctx, this_obj, prop, JS_UNDEFINED, getter, setter,\n                            flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET |\n                            JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);\n    JS_FreeValue(ctx, getter);\n    JS_FreeValue(ctx, setter);\n    return ret;\n}\n\nstatic int JS_CreateDataPropertyUint32(JSContext *ctx, JSValueConst this_obj,\n                                       int64_t idx, JSValue val, int flags)\n{\n    return JS_DefinePropertyValueValue(ctx, this_obj, JS_NewInt64(ctx, idx),\n                                       val, flags | JS_PROP_CONFIGURABLE |\n                                       JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);\n}\n\n\n/* return TRUE if 'obj' has a non empty 'name' string */\nstatic BOOL js_object_has_name(JSContext *ctx, JSValueConst obj)\n{\n    JSProperty *pr;\n    JSShapeProperty *prs;\n    JSValueConst val;\n    JSString *p;\n\n    prs = find_own_property(&pr, JS_VALUE_GET_OBJ(obj), JS_ATOM_name);\n    if (!prs)\n        return FALSE;\n    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)\n        return TRUE;\n    val = pr->u.value;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)\n        return TRUE;\n    p = JS_VALUE_GET_STRING(val);\n    return (p->len != 0);\n}\n\nstatic int JS_DefineObjectName(JSContext *ctx, JSValueConst obj,\n                               JSAtom name, int flags)\n{\n    if (name != JS_ATOM_NULL\n    &&  JS_IsObject(obj)\n    &&  !js_object_has_name(ctx, obj)\n    &&  JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, JS_AtomToString(ctx, name), flags) < 0) {\n        return -1;\n    }\n    return 0;\n}\n\nstatic int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj,\n                                       JSValueConst str, int flags)\n{\n    if (JS_IsObject(obj) &&\n        !js_object_has_name(ctx, obj)) {\n        JSAtom prop;\n        JSValue name_str;\n        prop = JS_ValueToAtom(ctx, str);\n        if (prop == JS_ATOM_NULL)\n            return -1;\n        name_str = js_get_function_name(ctx, prop);\n        JS_FreeAtom(ctx, prop);\n        if (JS_IsException(name_str))\n            return -1;\n        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_name, name_str, flags) < 0)\n            return -1;\n    }\n    return 0;\n}\n\n#define DEFINE_GLOBAL_LEX_VAR (1 << 7)\n#define DEFINE_GLOBAL_FUNC_VAR (1 << 6)\n\nstatic JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)\n{\n    return JS_ThrowSyntaxErrorAtom(ctx, \"redeclaration of '%s'\", prop);\n}\n\n/* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */\n/* XXX: could support exotic global object. */\nstatic int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n\n    p = JS_VALUE_GET_OBJ(ctx->global_obj);\n    prs = find_own_property1(p, prop);\n    /* XXX: should handle JS_PROP_AUTOINIT */\n    if (flags & DEFINE_GLOBAL_LEX_VAR) {\n        if (prs && !(prs->flags & JS_PROP_CONFIGURABLE))\n            goto fail_redeclaration;\n    } else {\n        if (!prs && !p->extensible)\n            goto define_error;\n        if (flags & DEFINE_GLOBAL_FUNC_VAR) {\n            if (prs) {\n                if (!(prs->flags & JS_PROP_CONFIGURABLE) &&\n                    ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET ||\n                     ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=\n                      (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {\n                define_error:\n                    JS_ThrowTypeErrorAtom(ctx, \"cannot define variable '%s'\",\n                                          prop);\n                    return -1;\n                }\n            }\n        }\n    }\n    /* check if there already is a lexical declaration */\n    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);\n    prs = find_own_property1(p, prop);\n    if (prs) {\n    fail_redeclaration:\n        JS_ThrowSyntaxErrorVarRedeclaration(ctx, prop);\n        return -1;\n    }\n    return 0;\n}\n\n/* construct a reference to a global variable */\nstatic int JS_GetGlobalVarRef(JSContext *ctx, JSAtom prop, JSValue *sp)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n\n    /* no exotic behavior is possible in global_var_obj */\n    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);\n    prs = find_own_property(&pr, p, prop);\n    if (prs) {\n        /* XXX: conformance: do these tests in\n           OP_put_var_ref/OP_get_var_ref ? */\n        if (unlikely(JS_IsUninitialized(*pr->u.var_ref->pvalue))) {\n            JS_ThrowReferenceErrorUninitialized(ctx, prs->atom);\n            return -1;\n        }\n        if (unlikely(!(prs->flags & JS_PROP_WRITABLE))) {\n            return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);\n        }\n        sp[0] = JS_DupValue(ctx, ctx->global_var_obj);\n    } else {\n        int ret;\n        ret = JS_HasProperty(ctx, ctx->global_obj, prop);\n        if (ret < 0)\n            return -1;\n        if (ret) {\n            sp[0] = JS_DupValue(ctx, ctx->global_obj);\n        } else {\n            sp[0] = JS_UNDEFINED;\n        }\n    }\n    sp[1] = JS_AtomToValue(ctx, prop);\n    return 0;\n}\n\n/* return -1, FALSE or TRUE */\nstatic int JS_DeleteGlobalVar(JSContext *ctx, JSAtom prop)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    int ret;\n\n    /* 9.1.1.4.7 DeleteBinding ( N ) */\n    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);\n    prs = find_own_property(&pr, p, prop);\n    if (prs)\n        return FALSE; /* lexical variables cannot be deleted */\n    ret = JS_HasProperty(ctx, ctx->global_obj, prop);\n    if (ret < 0)\n        return -1;\n    if (ret) {\n        return JS_DeleteProperty(ctx, ctx->global_obj, prop, 0);\n    } else {\n        return TRUE;\n    }\n}\n\n/* return -1, FALSE or TRUE. return FALSE if not configurable or\n   invalid object. return -1 in case of exception.\n   flags can be 0, JS_PROP_THROW or JS_PROP_THROW_STRICT */\nint JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags)\n{\n    JSValue obj1;\n    JSObject *p;\n    int res;\n\n    obj1 = JS_ToObject(ctx, obj);\n    if (JS_IsException(obj1))\n        return -1;\n    p = JS_VALUE_GET_OBJ(obj1);\n    res = delete_property(ctx, p, prop);\n    JS_FreeValue(ctx, obj1);\n    if (res != FALSE)\n        return res;\n    if ((flags & JS_PROP_THROW) ||\n        ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {\n        JS_ThrowTypeError(ctx, \"could not delete property\");\n        return -1;\n    }\n    return FALSE;\n}\n\nint JS_DeletePropertyInt64(JSContext *ctx, JSValueConst obj, int64_t idx, int flags)\n{\n    JSAtom prop;\n    int res;\n\n    if ((uint64_t)idx <= JS_ATOM_MAX_INT) {\n        /* fast path for fast arrays */\n        return JS_DeleteProperty(ctx, obj, __JS_AtomFromUInt32(idx), flags);\n    }\n    prop = JS_NewAtomInt64(ctx, idx);\n    if (prop == JS_ATOM_NULL)\n        return -1;\n    res = JS_DeleteProperty(ctx, obj, prop, flags);\n    JS_FreeAtom(ctx, prop);\n    return res;\n}\n\nBOOL JS_IsFunction(JSContext *ctx, JSValueConst val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(val);\n    switch(p->class_id) {\n    case JS_CLASS_BYTECODE_FUNCTION:\n        return TRUE;\n    case JS_CLASS_PROXY:\n        return p->u.proxy_data->is_func;\n    default:\n        return (ctx->rt->class_array[p->class_id].call != NULL);\n    }\n}\n\nBOOL JS_IsCFunction(JSContext *ctx, JSValueConst val, JSCFunction *func, int magic)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(val);\n    if (p->class_id == JS_CLASS_C_FUNCTION)\n        return (p->u.cfunc.c_function.generic == func && p->u.cfunc.magic == magic);\n    else\n        return FALSE;\n}\n\nBOOL JS_IsConstructor(JSContext *ctx, JSValueConst val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(val);\n    return p->is_constructor;\n}\n\nBOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, BOOL val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(func_obj);\n    p->is_constructor = val;\n    return TRUE;\n}\n\nBOOL JS_IsError(JSContext *ctx, JSValueConst val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(val);\n    return (p->class_id == JS_CLASS_ERROR);\n}\n\n/* must be called after JS_Throw() */\nvoid JS_SetUncatchableException(JSContext *ctx, BOOL flag)\n{\n    ctx->rt->current_exception_is_uncatchable = flag;\n}\n\nvoid JS_SetOpaque(JSValue obj, void *opaque)\n{\n   JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        p = JS_VALUE_GET_OBJ(obj);\n        p->u.opaque = opaque;\n    }\n}\n\n/* return NULL if not an object of class class_id */\nvoid *JS_GetOpaque(JSValueConst obj, JSClassID class_id)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return NULL;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (p->class_id != class_id)\n        return NULL;\n    return p->u.opaque;\n}\n\nvoid *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)\n{\n    void *p = JS_GetOpaque(obj, class_id);\n    if (unlikely(!p)) {\n        JS_ThrowTypeErrorInvalidClass(ctx, class_id);\n    }\n    return p;\n}\n\nvoid *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {\n        *class_id = 0;\n        return NULL;\n    }\n    p = JS_VALUE_GET_OBJ(obj);\n    *class_id = p->class_id;\n    return p->u.opaque;\n}\n\nstatic JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)\n{\n    int i;\n    BOOL force_ordinary;\n\n    JSAtom method_name;\n    JSValue method, ret;\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)\n        return val;\n    force_ordinary = hint & HINT_FORCE_ORDINARY;\n    hint &= ~HINT_FORCE_ORDINARY;\n    if (!force_ordinary) {\n        method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);\n        if (JS_IsException(method))\n            goto exception;\n        /* ECMA says *If exoticToPrim is not undefined* but tests in\n           test262 use null as a non callable converter */\n        if (!JS_IsUndefined(method) && !JS_IsNull(method)) {\n            JSAtom atom;\n            JSValue arg;\n            switch(hint) {\n            case HINT_STRING:\n                atom = JS_ATOM_string;\n                break;\n            case HINT_NUMBER:\n                atom = JS_ATOM_number;\n                break;\n            default:\n            case HINT_NONE:\n                atom = JS_ATOM_default;\n                break;\n            }\n            arg = JS_AtomToString(ctx, atom);\n            ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);\n            JS_FreeValue(ctx, arg);\n            if (JS_IsException(ret))\n                goto exception;\n            JS_FreeValue(ctx, val);\n            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT)\n                return ret;\n            JS_FreeValue(ctx, ret);\n            return JS_ThrowTypeError(ctx, \"toPrimitive\");\n        }\n    }\n    if (hint != HINT_STRING)\n        hint = HINT_NUMBER;\n    for(i = 0; i < 2; i++) {\n        if ((i ^ hint) == 0) {\n            method_name = JS_ATOM_toString;\n        } else {\n            method_name = JS_ATOM_valueOf;\n        }\n        method = JS_GetProperty(ctx, val, method_name);\n        if (JS_IsException(method))\n            goto exception;\n        if (JS_IsFunction(ctx, method)) {\n            ret = JS_CallFree(ctx, method, val, 0, NULL);\n            if (JS_IsException(ret))\n                goto exception;\n            if (JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {\n                JS_FreeValue(ctx, val);\n                return ret;\n            }\n            JS_FreeValue(ctx, ret);\n        } else {\n            JS_FreeValue(ctx, method);\n        }\n    }\n    JS_ThrowTypeError(ctx, \"toPrimitive\");\nexception:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint)\n{\n    return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint);\n}\n\nvoid JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return;\n    p = JS_VALUE_GET_OBJ(obj);\n    p->is_HTMLDDA = TRUE;\n}\n\nstatic inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    return p->is_HTMLDDA;\n}\n\nstatic int JS_ToBoolFree(JSContext *ctx, JSValue val)\n{\n    uint32_t tag = JS_VALUE_GET_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n        return JS_VALUE_GET_INT(val) != 0;\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        return JS_VALUE_GET_INT(val);\n    case JS_TAG_EXCEPTION:\n        return -1;\n    case JS_TAG_STRING:\n        {\n            BOOL ret = JS_VALUE_GET_STRING(val)->len != 0;\n            JS_FreeValue(ctx, val);\n            return ret;\n        }\n    case JS_TAG_STRING_ROPE:\n        {\n            BOOL ret = JS_VALUE_GET_STRING_ROPE(val)->len != 0;\n            JS_FreeValue(ctx, val);\n            return ret;\n        }\n    case JS_TAG_SHORT_BIG_INT:\n        return JS_VALUE_GET_SHORT_BIG_INT(val) != 0;\n    case JS_TAG_BIG_INT:\n        {\n            JSBigInt *p = JS_VALUE_GET_PTR(val);\n            BOOL ret;\n            int i;\n            \n            /* fail safe: we assume it is not necessarily\n               normalized. Beginning from the MSB ensures that the\n               test is fast. */\n            ret = FALSE;\n            for(i = p->len - 1; i >= 0; i--) {\n                if (p->tab[i] != 0) {\n                    ret = TRUE;\n                    break;\n                }\n            }\n            JS_FreeValue(ctx, val);\n            return ret;\n        }\n    case JS_TAG_OBJECT:\n        {\n            JSObject *p = JS_VALUE_GET_OBJ(val);\n            BOOL ret;\n            ret = !p->is_HTMLDDA;\n            JS_FreeValue(ctx, val);\n            return ret;\n        }\n        break;\n    default:\n        if (JS_TAG_IS_FLOAT64(tag)) {\n            double d = JS_VALUE_GET_FLOAT64(val);\n            return !isnan(d) && d != 0;\n        } else {\n            JS_FreeValue(ctx, val);\n            return TRUE;\n        }\n    }\n}\n\nint JS_ToBool(JSContext *ctx, JSValueConst val)\n{\n    return JS_ToBoolFree(ctx, JS_DupValue(ctx, val));\n}\n\nstatic int skip_spaces(const char *pc)\n{\n    const uint8_t *p, *p_next, *p_start;\n    uint32_t c;\n\n    p = p_start = (const uint8_t *)pc;\n    for (;;) {\n        c = *p;\n        if (c < 128) {\n            if (!((c >= 0x09 && c <= 0x0d) || (c == 0x20)))\n                break;\n            p++;\n        } else {\n            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);\n            if (!lre_is_space(c))\n                break;\n            p = p_next;\n        }\n    }\n    return p - p_start;\n}\n\nstatic inline int to_digit(int c)\n{\n    if (c >= '0' && c <= '9')\n        return c - '0';\n    else if (c >= 'A' && c <= 'Z')\n        return c - 'A' + 10;\n    else if (c >= 'a' && c <= 'z')\n        return c - 'a' + 10;\n    else\n        return 36;\n}\n\n/* bigint support */\n\n#define JS_BIGINT_MAX_SIZE ((1024 * 1024) / JS_LIMB_BITS) /* in limbs */\n\n/* it is currently assumed that JS_SHORT_BIG_INT_BITS = JS_LIMB_BITS */\n#if JS_SHORT_BIG_INT_BITS == 32\n#define JS_SHORT_BIG_INT_MIN INT32_MIN\n#define JS_SHORT_BIG_INT_MAX INT32_MAX\n#elif JS_SHORT_BIG_INT_BITS == 64\n#define JS_SHORT_BIG_INT_MIN INT64_MIN\n#define JS_SHORT_BIG_INT_MAX INT64_MAX\n#else\n#error unsupported\n#endif\n\n#define ADDC(res, carry_out, op1, op2, carry_in)        \\\ndo {                                                    \\\n    js_limb_t __v, __a, __k, __k1;                      \\\n    __v = (op1);                                        \\\n    __a = __v + (op2);                                  \\\n    __k1 = __a < __v;                                   \\\n    __k = (carry_in);                                   \\\n    __a = __a + __k;                                    \\\n    carry_out = (__a < __k) | __k1;                     \\\n    res = __a;                                          \\\n} while (0)\n\n#if JS_LIMB_BITS == 32\n/* a != 0 */\nstatic inline js_limb_t js_limb_clz(js_limb_t a)\n{\n    return clz32(a);\n}\n#else\nstatic inline js_limb_t js_limb_clz(js_limb_t a)\n{\n    return clz64(a);\n}\n#endif\n\n/* handle a = 0 too */\nstatic inline js_limb_t js_limb_safe_clz(js_limb_t a)\n{\n    if (a == 0)\n        return JS_LIMB_BITS;\n    else\n        return js_limb_clz(a);\n}\n\nstatic js_limb_t mp_add(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,\n                     js_limb_t n, js_limb_t carry)\n{\n    int i;\n    for(i = 0;i < n; i++) {\n        ADDC(res[i], carry, op1[i], op2[i], carry);\n    }\n    return carry;\n}\n\nstatic js_limb_t mp_sub(js_limb_t *res, const js_limb_t *op1, const js_limb_t *op2,\n                        int n, js_limb_t carry)\n{\n    int i;\n    js_limb_t k, a, v, k1;\n\n    k = carry;\n    for(i=0;i<n;i++) {\n        v = op1[i];\n        a = v - op2[i];\n        k1 = a > v;\n        v = a - k;\n        k = (v > a) | k1;\n        res[i] = v;\n    }\n    return k;\n}\n\n/* compute 0 - op2. carry = 0 or 1. */\nstatic js_limb_t mp_neg(js_limb_t *res, const js_limb_t *op2, int n)\n{\n    int i;\n    js_limb_t v, carry;\n\n    carry = 1;\n    for(i=0;i<n;i++) {\n        v = ~op2[i] + carry;\n        carry = v < carry;\n        res[i] = v;\n    }\n    return carry;\n}\n\n/* tabr[] = taba[] * b + l. Return the high carry */\nstatic js_limb_t mp_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,\n                      js_limb_t b, js_limb_t l)\n{\n    js_limb_t i;\n    js_dlimb_t t;\n\n    for(i = 0; i < n; i++) {\n        t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l;\n        tabr[i] = t;\n        l = t >> JS_LIMB_BITS;\n    }\n    return l;\n}\n\nstatic js_limb_t mp_div1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,\n                      js_limb_t b, js_limb_t r)\n{\n    js_slimb_t i;\n    js_dlimb_t a1;\n    for(i = n - 1; i >= 0; i--) {\n        a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];\n        tabr[i] = a1 / b;\n        r = a1 % b;\n    }\n    return r;\n}\n\n/* tabr[] += taba[] * b, return the high word. */\nstatic js_limb_t mp_add_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,\n                          js_limb_t b)\n{\n    js_limb_t i, l;\n    js_dlimb_t t;\n\n    l = 0;\n    for(i = 0; i < n; i++) {\n        t = (js_dlimb_t)taba[i] * (js_dlimb_t)b + l + tabr[i];\n        tabr[i] = t;\n        l = t >> JS_LIMB_BITS;\n    }\n    return l;\n}\n\n/* size of the result : op1_size + op2_size. */\nstatic void mp_mul_basecase(js_limb_t *result,\n                            const js_limb_t *op1, js_limb_t op1_size,\n                            const js_limb_t *op2, js_limb_t op2_size)\n{\n    int i;\n    js_limb_t r;\n    \n    result[op1_size] = mp_mul1(result, op1, op1_size, op2[0], 0);\n    for(i=1;i<op2_size;i++) {\n        r = mp_add_mul1(result + i, op1, op1_size, op2[i]);\n        result[i + op1_size] = r;\n    }\n}\n\n/* tabr[] -= taba[] * b. Return the value to substract to the high\n   word. */\nstatic js_limb_t mp_sub_mul1(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,\n                          js_limb_t b)\n{\n    js_limb_t i, l;\n    js_dlimb_t t;\n\n    l = 0;\n    for(i = 0; i < n; i++) {\n        t = tabr[i] - (js_dlimb_t)taba[i] * (js_dlimb_t)b - l;\n        tabr[i] = t;\n        l = -(t >> JS_LIMB_BITS);\n    }\n    return l;\n}\n\n/* WARNING: d must be >= 2^(JS_LIMB_BITS-1) */\nstatic inline js_limb_t udiv1norm_init(js_limb_t d)\n{\n    js_limb_t a0, a1;\n    a1 = -d - 1;\n    a0 = -1;\n    return (((js_dlimb_t)a1 << JS_LIMB_BITS) | a0) / d;\n}\n\n/* return the quotient and the remainder in '*pr'of 'a1*2^JS_LIMB_BITS+a0\n   / d' with 0 <= a1 < d. */\nstatic inline js_limb_t udiv1norm(js_limb_t *pr, js_limb_t a1, js_limb_t a0,\n                                js_limb_t d, js_limb_t d_inv)\n{\n    js_limb_t n1m, n_adj, q, r, ah;\n    js_dlimb_t a;\n    n1m = ((js_slimb_t)a0 >> (JS_LIMB_BITS - 1));\n    n_adj = a0 + (n1m & d);\n    a = (js_dlimb_t)d_inv * (a1 - n1m) + n_adj;\n    q = (a >> JS_LIMB_BITS) + a1;\n    /* compute a - q * r and update q so that the remainder is\\\n       between 0 and d - 1 */\n    a = ((js_dlimb_t)a1 << JS_LIMB_BITS) | a0;\n    a = a - (js_dlimb_t)q * d - d;\n    ah = a >> JS_LIMB_BITS;\n    q += 1 + ah;\n    r = (js_limb_t)a + (ah & d);\n    *pr = r;\n    return q;\n}\n\n#define UDIV1NORM_THRESHOLD 3\n\n/* b must be >= 1 << (JS_LIMB_BITS - 1) */\nstatic js_limb_t mp_div1norm(js_limb_t *tabr, const js_limb_t *taba, js_limb_t n,\n                          js_limb_t b, js_limb_t r)\n{\n    js_slimb_t i;\n\n    if (n >= UDIV1NORM_THRESHOLD) {\n        js_limb_t b_inv;\n        b_inv = udiv1norm_init(b);\n        for(i = n - 1; i >= 0; i--) {\n            tabr[i] = udiv1norm(&r, r, taba[i], b, b_inv);\n        }\n    } else {\n        js_dlimb_t a1;\n        for(i = n - 1; i >= 0; i--) {\n            a1 = ((js_dlimb_t)r << JS_LIMB_BITS) | taba[i];\n            tabr[i] = a1 / b;\n            r = a1 % b;\n        }\n    }\n    return r;\n}\n\n/* base case division: divides taba[0..na-1] by tabb[0..nb-1]. tabb[nb\n   - 1] must be >= 1 << (JS_LIMB_BITS - 1). na - nb must be >= 0. 'taba'\n   is modified and contains the remainder (nb limbs). tabq[0..na-nb]\n   contains the quotient with tabq[na - nb] <= 1. */\nstatic void mp_divnorm(js_limb_t *tabq, js_limb_t *taba, js_limb_t na,\n                       const js_limb_t *tabb, js_limb_t nb)\n{\n    js_limb_t r, a, c, q, v, b1, b1_inv, n, dummy_r;\n    int i, j;\n\n    b1 = tabb[nb - 1];\n    if (nb == 1) {\n        taba[0] = mp_div1norm(tabq, taba, na, b1, 0);\n        return;\n    }\n    n = na - nb;\n\n    if (n >= UDIV1NORM_THRESHOLD)\n        b1_inv = udiv1norm_init(b1);\n    else\n        b1_inv = 0;\n\n    /* first iteration: the quotient is only 0 or 1 */\n    q = 1;\n    for(j = nb - 1; j >= 0; j--) {\n        if (taba[n + j] != tabb[j]) {\n            if (taba[n + j] < tabb[j])\n                q = 0;\n            break;\n        }\n    }\n    tabq[n] = q;\n    if (q) {\n        mp_sub(taba + n, taba + n, tabb, nb, 0);\n    }\n\n    for(i = n - 1; i >= 0; i--) {\n        if (unlikely(taba[i + nb] >= b1)) {\n            q = -1;\n        } else if (b1_inv) {\n            q = udiv1norm(&dummy_r, taba[i + nb], taba[i + nb - 1], b1, b1_inv);\n        } else {\n            js_dlimb_t al;\n            al = ((js_dlimb_t)taba[i + nb] << JS_LIMB_BITS) | taba[i + nb - 1];\n            q = al / b1;\n            r = al % b1;\n        }\n        r = mp_sub_mul1(taba + i, tabb, nb, q);\n\n        v = taba[i + nb];\n        a = v - r;\n        c = (a > v);\n        taba[i + nb] = a;\n\n        if (c != 0) {\n            /* negative result */\n            for(;;) {\n                q--;\n                c = mp_add(taba + i, taba + i, tabb, nb, 0);\n                /* propagate carry and test if positive result */\n                if (c != 0) {\n                    if (++taba[i + nb] == 0) {\n                        break;\n                    }\n                }\n            }\n        }\n        tabq[i] = q;\n    }\n}\n\n/* 1 <= shift <= JS_LIMB_BITS - 1 */\nstatic js_limb_t mp_shl(js_limb_t *tabr, const js_limb_t *taba, int n,\n                        int shift)\n{\n    int i;\n    js_limb_t l, v;\n    l = 0;\n    for(i = 0; i < n; i++) {\n        v = taba[i];\n        tabr[i] = (v << shift) | l;\n        l = v >> (JS_LIMB_BITS - shift);\n    }\n    return l;\n}\n\n/* r = (a + high*B^n) >> shift. Return the remainder r (0 <= r < 2^shift). \n   1 <= shift <= LIMB_BITS - 1 */\nstatic js_limb_t mp_shr(js_limb_t *tab_r, const js_limb_t *tab, int n,\n                        int shift, js_limb_t high)\n{\n    int i;\n    js_limb_t l, a;\n\n    l = high;\n    for(i = n - 1; i >= 0; i--) {\n        a = tab[i];\n        tab_r[i] = (a >> shift) | (l << (JS_LIMB_BITS - shift));\n        l = a;\n    }\n    return l & (((js_limb_t)1 << shift) - 1);\n}\n\nstatic JSBigInt *js_bigint_new(JSContext *ctx, int len)\n{\n    JSBigInt *r;\n    if (len > JS_BIGINT_MAX_SIZE) {\n        JS_ThrowRangeError(ctx, \"BigInt is too large to allocate\");\n        return NULL;\n    }\n    r = js_malloc(ctx, sizeof(JSBigInt) + len * sizeof(js_limb_t));\n    if (!r)\n        return NULL;\n    r->header.ref_count = 1;\n    r->len = len;\n    return r;\n}\n\nstatic JSBigInt *js_bigint_set_si(JSBigIntBuf *buf, js_slimb_t a)\n{\n    JSBigInt *r = (JSBigInt *)buf->big_int_buf;\n    r->header.ref_count = 0; /* fail safe */\n    r->len = 1;\n    r->tab[0] = a;\n    return r;\n}\n\nstatic JSBigInt *js_bigint_set_si64(JSBigIntBuf *buf, int64_t a)\n{\n#if JS_LIMB_BITS == 64\n    return js_bigint_set_si(buf, a);\n#else\n    JSBigInt *r = (JSBigInt *)buf->big_int_buf;\n    r->header.ref_count = 0; /* fail safe */\n    if (a >= INT32_MIN && a <= INT32_MAX) {\n        r->len = 1;\n        r->tab[0] = a;\n    } else {\n        r->len = 2;\n        r->tab[0] = a;\n        r->tab[1] = a >> JS_LIMB_BITS;\n    }\n    return r;\n#endif\n}\n\n/* val must be a short big int */\nstatic JSBigInt *js_bigint_set_short(JSBigIntBuf *buf, JSValueConst val)\n{\n    return js_bigint_set_si(buf, JS_VALUE_GET_SHORT_BIG_INT(val));\n}\n\nstatic __maybe_unused void js_bigint_dump1(JSContext *ctx, const char *str,\n                                           const js_limb_t *tab, int len)\n{\n    int i;\n    printf(\"%s: \", str);\n    for(i = len - 1; i >= 0; i--) {\n#if JS_LIMB_BITS == 32\n        printf(\" %08x\", tab[i]);\n#else\n        printf(\" %016\" PRIx64, tab[i]);\n#endif\n    }\n    printf(\"\\n\");\n}\n\nstatic __maybe_unused void js_bigint_dump(JSContext *ctx, const char *str,\n                                          const JSBigInt *p)\n{\n    js_bigint_dump1(ctx, str, p->tab, p->len);\n}\n\nstatic JSBigInt *js_bigint_new_si(JSContext *ctx, js_slimb_t a)\n{\n    JSBigInt *r;\n    r = js_bigint_new(ctx, 1);\n    if (!r)\n        return NULL;\n    r->tab[0] = a;\n    return r;\n}\n\nstatic JSBigInt *js_bigint_new_si64(JSContext *ctx, int64_t a)\n{\n#if JS_LIMB_BITS == 64\n    return js_bigint_new_si(ctx, a);\n#else\n    if (a >= INT32_MIN && a <= INT32_MAX) {\n        return js_bigint_new_si(ctx, a);\n    } else {\n        JSBigInt *r;\n        r = js_bigint_new(ctx, 2);\n        if (!r)\n            return NULL;\n        r->tab[0] = a;\n        r->tab[1] = a >> 32;\n        return r;\n    }\n#endif\n}\n\nstatic JSBigInt *js_bigint_new_ui64(JSContext *ctx, uint64_t a)\n{\n    if (a <= INT64_MAX) {\n        return js_bigint_new_si64(ctx, a);\n    } else {\n        JSBigInt *r;\n        r = js_bigint_new(ctx, (65 + JS_LIMB_BITS - 1) / JS_LIMB_BITS);\n        if (!r)\n            return NULL;\n#if JS_LIMB_BITS == 64\n        r->tab[0] = a;\n        r->tab[1] = 0;\n#else\n        r->tab[0] = a;\n        r->tab[1] = a >> 32;\n        r->tab[2] = 0;\n#endif\n        return r;\n    }\n}\n\nstatic JSBigInt *js_bigint_new_di(JSContext *ctx, js_sdlimb_t a)\n{\n    JSBigInt *r;\n    if (a == (js_slimb_t)a) {\n        r = js_bigint_new(ctx, 1);\n        if (!r)\n            return NULL;\n        r->tab[0] = a;\n    } else {\n        r = js_bigint_new(ctx, 2);\n        if (!r)\n            return NULL;\n        r->tab[0] = a;\n        r->tab[1] = a >> JS_LIMB_BITS;\n    }\n    return r;\n}\n\n/* Remove redundant high order limbs. Warning: 'a' may be\n   reallocated. Can never fail.\n*/\nstatic JSBigInt *js_bigint_normalize1(JSContext *ctx, JSBigInt *a, int l)\n{\n    js_limb_t v;\n\n    assert(a->header.ref_count == 1);\n    while (l > 1) {\n        v = a->tab[l - 1];\n        if ((v != 0 && v != -1) ||\n            (v & 1) != (a->tab[l - 2] >> (JS_LIMB_BITS - 1))) {\n            break;\n        }\n        l--;\n    }\n    if (l != a->len) {\n        JSBigInt *a1;\n        /* realloc to reduce the size */\n        a->len = l;\n        a1 = js_realloc(ctx, a, sizeof(JSBigInt) + l * sizeof(js_limb_t));\n        if (a1)\n            a = a1;\n    }\n    return a;\n}\n\nstatic JSBigInt *js_bigint_normalize(JSContext *ctx, JSBigInt *a)\n{\n    return js_bigint_normalize1(ctx, a, a->len);\n}\n\n/* return 0 or 1 depending on the sign */\nstatic inline int js_bigint_sign(const JSBigInt *a)\n{\n    return a->tab[a->len - 1] >> (JS_LIMB_BITS - 1);\n}\n\nstatic js_slimb_t js_bigint_get_si_sat(const JSBigInt *a)\n{\n    if (a->len == 1) {\n        return a->tab[0];\n    } else {\n#if JS_LIMB_BITS == 32\n        if (js_bigint_sign(a))\n            return INT32_MIN;\n        else\n            return INT32_MAX;\n#else\n        if (js_bigint_sign(a))\n            return INT64_MIN;\n        else\n            return INT64_MAX;\n#endif\n    }\n}\n\n/* add the op1 limb */\nstatic JSBigInt *js_bigint_extend(JSContext *ctx, JSBigInt *r,\n                                  js_limb_t op1)\n{\n    int n2 = r->len;\n    if ((op1 != 0 && op1 != -1) ||\n        (op1 & 1) != r->tab[n2 - 1] >> (JS_LIMB_BITS - 1)) {\n        JSBigInt *r1;\n        r1 = js_realloc(ctx, r,\n                        sizeof(JSBigInt) + (n2 + 1) * sizeof(js_limb_t));\n        if (!r1) {\n            js_free(ctx, r);\n            return NULL;\n        }\n        r = r1;\n        r->len = n2 + 1;\n        r->tab[n2] = op1;\n    } else {\n        /* otherwise still need to normalize the result */\n        r = js_bigint_normalize(ctx, r);\n    }\n    return r;\n}\n\n/* return NULL in case of error. Compute a + b (b_neg = 0) or a - b\n   (b_neg = 1) */\n/* XXX: optimize */\nstatic JSBigInt *js_bigint_add(JSContext *ctx, const JSBigInt *a,\n                               const JSBigInt *b, int b_neg)\n{\n    JSBigInt *r;\n    int n1, n2, i;\n    js_limb_t carry, op1, op2, a_sign, b_sign;\n    \n    n2 = max_int(a->len, b->len);\n    n1 = min_int(a->len, b->len);\n    r = js_bigint_new(ctx, n2);\n    if (!r)\n        return NULL;\n    /* XXX: optimize */\n    /* common part */\n    carry = b_neg;\n    for(i = 0; i < n1; i++) {\n        op1 = a->tab[i];\n        op2 = b->tab[i] ^ (-b_neg);\n        ADDC(r->tab[i], carry, op1, op2, carry);\n    }\n    a_sign = -js_bigint_sign(a);\n    b_sign = (-js_bigint_sign(b)) ^ (-b_neg);\n    /* part with sign extension of one operand  */\n    if (a->len > b->len) {\n        for(i = n1; i < n2; i++) {\n            op1 = a->tab[i];\n            ADDC(r->tab[i], carry, op1, b_sign, carry);\n        }\n    } else if (a->len < b->len) {\n        for(i = n1; i < n2; i++) {\n            op2 = b->tab[i] ^ (-b_neg);\n            ADDC(r->tab[i], carry, a_sign, op2, carry);\n        }\n    }\n\n    /* part with sign extension for both operands. Extend the result\n       if necessary */\n    return js_bigint_extend(ctx, r, a_sign + b_sign + carry);\n}\n\n/* XXX: optimize */\nstatic JSBigInt *js_bigint_neg(JSContext *ctx, const JSBigInt *a)\n{\n    JSBigIntBuf buf;\n    JSBigInt *b;\n    b = js_bigint_set_si(&buf, 0);\n    return js_bigint_add(ctx, b, a, 1);\n}\n\nstatic JSBigInt *js_bigint_mul(JSContext *ctx, const JSBigInt *a,\n                               const JSBigInt *b)\n{\n    JSBigInt *r;\n    \n    r = js_bigint_new(ctx, a->len + b->len);\n    if (!r)\n        return NULL;\n    mp_mul_basecase(r->tab, a->tab, a->len, b->tab, b->len);\n    /* correct the result if negative operands (no overflow is\n       possible) */\n    if (js_bigint_sign(a))\n        mp_sub(r->tab + a->len, r->tab + a->len, b->tab, b->len, 0);\n    if (js_bigint_sign(b))\n        mp_sub(r->tab + b->len, r->tab + b->len, a->tab, a->len, 0);\n    return js_bigint_normalize(ctx, r);\n}\n\n/* return the division or the remainder. 'b' must be != 0. return NULL\n   in case of exception (division by zero or memory error) */\nstatic JSBigInt *js_bigint_divrem(JSContext *ctx, const JSBigInt *a,\n                                  const JSBigInt *b, BOOL is_rem)\n{\n    JSBigInt *r, *q;\n    js_limb_t *tabb, h;\n    int na, nb, a_sign, b_sign, shift;\n    \n    if (b->len == 1 && b->tab[0] == 0) {\n        JS_ThrowRangeError(ctx, \"BigInt division by zero\");\n        return NULL;\n    }\n    \n    a_sign = js_bigint_sign(a);\n    b_sign = js_bigint_sign(b);\n    na = a->len;\n    nb = b->len;\n\n    r = js_bigint_new(ctx, na + 2); \n    if (!r)\n        return NULL;\n    if (a_sign) {\n        mp_neg(r->tab, a->tab, na);\n    } else {\n        memcpy(r->tab, a->tab, na * sizeof(a->tab[0]));\n    }\n    /* normalize */\n    while (na > 1 && r->tab[na - 1] == 0)\n        na--;\n\n    tabb = js_malloc(ctx, nb * sizeof(tabb[0]));\n    if (!tabb) {\n        js_free(ctx, r);\n        return NULL;\n    }\n    if (b_sign) {\n        mp_neg(tabb, b->tab, nb);\n    } else {\n        memcpy(tabb, b->tab, nb * sizeof(tabb[0]));\n    }\n    /* normalize */\n    while (nb > 1 && tabb[nb - 1] == 0)\n        nb--;\n\n    /* trivial case if 'a' is small */\n    if (na < nb) {\n        js_free(ctx, r);\n        js_free(ctx, tabb);\n        if (is_rem) {\n            /* r = a */\n            r = js_bigint_new(ctx, a->len);\n            if (!r)\n                return NULL;\n            memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0])); \n            return r;\n        } else {\n            /* q = 0 */\n            return js_bigint_new_si(ctx, 0);\n        }\n    }\n\n    /* normalize 'b' */\n    shift = js_limb_clz(tabb[nb - 1]);\n    if (shift != 0) {\n        mp_shl(tabb, tabb, nb, shift);\n        h = mp_shl(r->tab, r->tab, na, shift);\n        if (h != 0)\n            r->tab[na++] = h;\n    }\n\n    q = js_bigint_new(ctx, na - nb + 2); /* one more limb for the sign */\n    if (!q) {\n        js_free(ctx, r);\n        js_free(ctx, tabb);\n        return NULL;\n    }\n\n    //    js_bigint_dump1(ctx, \"a\", r->tab, na);\n    //    js_bigint_dump1(ctx, \"b\", tabb, nb);\n    mp_divnorm(q->tab, r->tab, na, tabb, nb);\n    js_free(ctx, tabb);\n\n    if (is_rem) {\n        js_free(ctx, q);\n        if (shift != 0)\n            mp_shr(r->tab, r->tab, nb, shift, 0);\n        r->tab[nb++] = 0;\n        if (a_sign)\n            mp_neg(r->tab, r->tab, nb);\n        r = js_bigint_normalize1(ctx, r, nb);\n        return r;\n    } else {\n        js_free(ctx, r);\n        q->tab[na - nb + 1] = 0;\n        if (a_sign ^ b_sign) {\n            mp_neg(q->tab, q->tab, q->len);\n        }\n        q = js_bigint_normalize(ctx, q);\n        return q;\n    }\n}\n\n/* and, or, xor */\nstatic JSBigInt *js_bigint_logic(JSContext *ctx, const JSBigInt *a,\n                                 const JSBigInt *b, OPCodeEnum op)\n{\n    JSBigInt *r;\n    js_limb_t b_sign;\n    int a_len, b_len, i;\n\n    if (a->len < b->len) {\n        const JSBigInt *tmp;\n        tmp = a;\n        a = b;\n        b = tmp;\n    }\n    /* a_len >= b_len */\n    a_len = a->len;\n    b_len = b->len;\n    b_sign = -js_bigint_sign(b);\n\n    r = js_bigint_new(ctx, a_len);\n    if (!r)\n        return NULL;\n    switch(op) {\n    case OP_or:\n        for(i = 0; i < b_len; i++) {\n            r->tab[i] = a->tab[i] | b->tab[i];\n        }\n        for(i = b_len; i < a_len; i++) {\n            r->tab[i] = a->tab[i] | b_sign;\n        }\n        break;\n    case OP_and:\n        for(i = 0; i < b_len; i++) {\n            r->tab[i] = a->tab[i] & b->tab[i];\n        }\n        for(i = b_len; i < a_len; i++) {\n            r->tab[i] = a->tab[i] & b_sign;\n        }\n        break;\n    case OP_xor:\n        for(i = 0; i < b_len; i++) {\n            r->tab[i] = a->tab[i] ^ b->tab[i];\n        }\n        for(i = b_len; i < a_len; i++) {\n            r->tab[i] = a->tab[i] ^ b_sign;\n        }\n        break;\n    default:\n        abort();\n    }\n    return js_bigint_normalize(ctx, r);\n}\n\nstatic JSBigInt *js_bigint_not(JSContext *ctx, const JSBigInt *a)\n{\n    JSBigInt *r;\n    int i;\n    \n    r = js_bigint_new(ctx, a->len);\n    if (!r)\n        return NULL;\n    for(i = 0; i < a->len; i++) {\n        r->tab[i] = ~a->tab[i];\n    }\n    /* no normalization is needed */\n    return r;\n}\n\nstatic JSBigInt *js_bigint_shl(JSContext *ctx, const JSBigInt *a,\n                               unsigned int shift1)\n{\n    int d, i, shift;\n    JSBigInt *r;\n    js_limb_t l;\n\n    if (a->len == 1 && a->tab[0] == 0)\n        return js_bigint_new_si(ctx, 0); /* zero case */\n    d = shift1 / JS_LIMB_BITS;\n    shift = shift1 % JS_LIMB_BITS;\n    r = js_bigint_new(ctx, a->len + d);\n    if (!r)\n        return NULL;\n    for(i = 0; i < d; i++)\n        r->tab[i] = 0;\n    if (shift == 0) {\n        for(i = 0; i < a->len; i++) {\n            r->tab[i + d] = a->tab[i];\n        }\n    } else {\n        l = mp_shl(r->tab + d, a->tab, a->len, shift);\n        if (js_bigint_sign(a))\n            l |= (js_limb_t)(-1) << shift;\n        r = js_bigint_extend(ctx, r, l);\n    }\n    return r;\n}\n\nstatic JSBigInt *js_bigint_shr(JSContext *ctx, const JSBigInt *a,\n                               unsigned int shift1)\n{\n    int d, i, shift, a_sign, n1;\n    JSBigInt *r;\n\n    d = shift1 / JS_LIMB_BITS;\n    shift = shift1 % JS_LIMB_BITS;\n    a_sign = js_bigint_sign(a);\n    if (d >= a->len)\n        return js_bigint_new_si(ctx, -a_sign);\n    n1 = a->len - d;\n    r = js_bigint_new(ctx, n1);\n    if (!r)\n        return NULL;\n    if (shift == 0) {\n        for(i = 0; i < n1; i++) {\n            r->tab[i] = a->tab[i + d];\n        }\n        /* no normalization is needed */\n    } else {\n        mp_shr(r->tab, a->tab + d, n1, shift, -a_sign);\n        r = js_bigint_normalize(ctx, r);\n    }\n    return r;\n}\n\nstatic JSBigInt *js_bigint_pow(JSContext *ctx, const JSBigInt *a, JSBigInt *b)\n{\n    uint32_t e;\n    int n_bits, i;\n    JSBigInt *r, *r1;\n    \n    /* b must be >= 0 */\n    if (js_bigint_sign(b)) {\n        JS_ThrowRangeError(ctx, \"BigInt negative exponent\");\n        return NULL;\n    }\n    if (b->len == 1 && b->tab[0] == 0) {\n        /* a^0 = 1 */\n        return js_bigint_new_si(ctx, 1);\n    } else if (a->len == 1) {\n        js_limb_t v;\n        BOOL is_neg;\n\n        v = a->tab[0];\n        if (v <= 1)\n            return js_bigint_new_si(ctx, v);\n        else if (v == -1)\n            return js_bigint_new_si(ctx, 1 - 2 * (b->tab[0] & 1));\n        is_neg = (js_slimb_t)v < 0;\n        if (is_neg)\n            v = -v;\n        if ((v & (v - 1)) == 0) {\n            uint64_t e1;\n            int n;\n            /* v = 2^n */\n            n = JS_LIMB_BITS - 1 - js_limb_clz(v);\n            if (b->len > 1)\n                goto overflow;\n            if (b->tab[0] > INT32_MAX)\n                goto overflow;\n            e = b->tab[0];\n            e1 = (uint64_t)e * n;\n            if (e1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS)\n                goto overflow;\n            e = e1;\n            if (is_neg)\n                is_neg = b->tab[0] & 1;\n            r = js_bigint_new(ctx,\n                              (e + JS_LIMB_BITS + 1 - is_neg) / JS_LIMB_BITS);\n            if (!r)\n                return NULL;\n            memset(r->tab, 0, sizeof(r->tab[0]) * r->len);\n            r->tab[e / JS_LIMB_BITS] =\n                (js_limb_t)(1 - 2 * is_neg) << (e % JS_LIMB_BITS);\n            return r;\n        }\n    }\n    if (b->len > 1)\n        goto overflow;\n    if (b->tab[0] > INT32_MAX)\n        goto overflow;\n    e = b->tab[0];\n    n_bits = 32 - clz32(e);\n\n    r = js_bigint_new(ctx, a->len);\n    if (!r)\n        return NULL;\n    memcpy(r->tab, a->tab, a->len * sizeof(a->tab[0]));\n    for(i = n_bits - 2; i >= 0; i--) {\n        r1 = js_bigint_mul(ctx, r, r);\n        if (!r1)\n            return NULL;\n        js_free(ctx, r);\n        r = r1;\n        if ((e >> i) & 1) {\n            r1 = js_bigint_mul(ctx, r, a);\n            if (!r1)\n                return NULL;\n            js_free(ctx, r);\n            r = r1;\n        }\n    }\n    return r;\n overflow:\n    JS_ThrowRangeError(ctx, \"BigInt is too large\");\n    return NULL;\n}\n\n/* return (mant, exp) so that abs(a) ~ mant*2^(exp - (limb_bits -\n   1). a must be != 0. */\nstatic uint64_t js_bigint_get_mant_exp(JSContext *ctx,\n                                       int *pexp, const JSBigInt *a)\n{\n    js_limb_t t[4 - JS_LIMB_BITS / 32], carry, v, low_bits;\n    int n1, n2, sgn, shift, i, j, e;\n    uint64_t a1, a0;\n\n    n2 = 4 - JS_LIMB_BITS / 32;\n    n1 = a->len - n2;\n    sgn = js_bigint_sign(a);\n\n    /* low_bits != 0 if there are a non zero low bit in abs(a) */\n    low_bits = 0;\n    carry = sgn;\n    for(i = 0; i < n1; i++) {\n        v = (a->tab[i] ^ (-sgn)) + carry;\n        carry = v < carry;\n        low_bits |= v;\n    }\n    /* get the n2 high limbs of abs(a) */\n    for(j = 0; j < n2; j++) {\n        i = j + n1;\n        if (i < 0) {\n            v = 0;\n        } else {\n            v = (a->tab[i] ^ (-sgn)) + carry;\n            carry = v < carry;\n        }\n        t[j] = v;\n    }\n    \n#if JS_LIMB_BITS == 32\n    a1 = ((uint64_t)t[2] << 32) | t[1];\n    a0 = (uint64_t)t[0] << 32;\n#else\n    a1 = t[1];\n    a0 = t[0];\n#endif\n    a0 |= (low_bits != 0);\n    /* normalize */\n    if (a1 == 0) {\n        /* JS_LIMB_BITS = 64 bit only */\n        shift = 64;\n        a1 = a0;\n        a0 = 0;\n    } else {\n        shift = clz64(a1);\n        if (shift != 0) {\n            a1 = (a1 << shift) | (a0 >> (64 - shift));\n            a0 <<= shift;\n        }\n    }\n    a1 |= (a0 != 0); /* keep the bits for the final rounding */\n    /* compute the exponent */\n    e = a->len * JS_LIMB_BITS - shift - 1;\n    *pexp = e;\n    return a1;\n}\n\n/* shift left with round to nearest, ties to even. n >= 1 */\nstatic uint64_t shr_rndn(uint64_t a, int n)\n{\n    uint64_t addend = ((a >> n) & 1) + ((1 << (n - 1)) - 1);\n    return (a + addend) >> n;\n}\n\n/* convert to float64 with round to nearest, ties to even. Return\n   +/-infinity if too large. */\nstatic double js_bigint_to_float64(JSContext *ctx, const JSBigInt *a)\n{\n    int sgn, e;\n    uint64_t mant;\n\n    if (a->len == 1) {\n        /* fast case, including zero */\n        return (double)(js_slimb_t)a->tab[0];\n    }\n\n    sgn = js_bigint_sign(a);\n    mant = js_bigint_get_mant_exp(ctx, &e, a);\n    if (e > 1023) {\n        /* overflow: return infinity */\n        mant = 0;\n        e = 1024;\n    } else {\n        mant = (mant >> 1) | (mant & 1); /* avoid overflow in rounding */\n        mant = shr_rndn(mant, 10);\n        /* rounding can cause an overflow */\n        if (mant >= ((uint64_t)1 << 53)) {\n            mant >>= 1;\n            e++;\n        }\n        mant &= (((uint64_t)1 << 52) - 1);\n    }\n    return uint64_as_float64(((uint64_t)sgn << 63) |\n                             ((uint64_t)(e + 1023) << 52) |\n                             mant);\n}\n\n/* return (1, NULL) if not an integer, (2, NULL) if NaN or Infinity,\n   (0, n) if an integer, (0, NULL) in case of memory error */\nstatic JSBigInt *js_bigint_from_float64(JSContext *ctx, int *pres, double a1)\n{\n    uint64_t a = float64_as_uint64(a1);\n    int sgn, e, shift;\n    uint64_t mant;\n    JSBigIntBuf buf;\n    JSBigInt *r;\n    \n    sgn = a >> 63;\n    e = (a >> 52) & ((1 << 11) - 1);\n    mant = a & (((uint64_t)1 << 52) - 1);\n    if (e == 2047) {\n        /* NaN, Infinity */\n        *pres = 2;\n        return NULL;\n    }\n    if (e == 0 && mant == 0) {\n        /* zero */\n        *pres = 0;\n        return js_bigint_new_si(ctx, 0);\n    }\n    e -= 1023;\n    /* 0 < a < 1 : not an integer */\n    if (e < 0)\n        goto not_an_integer;\n    mant |= (uint64_t)1 << 52;\n    if (e < 52) {\n        shift = 52 - e;\n        /* check that there is no fractional part */\n        if (mant & (((uint64_t)1 << shift) - 1)) {\n        not_an_integer:\n            *pres = 1;\n            return NULL;\n        }\n        mant >>= shift;\n        e = 0;\n    } else {\n        e -= 52;\n    }\n    if (sgn)\n        mant = -mant;\n    /* the integer is mant*2^e */\n    r = js_bigint_set_si64(&buf, (int64_t)mant);\n    *pres = 0;\n    return js_bigint_shl(ctx, r, e);\n}\n\n/* return -1, 0, 1 or (2) (unordered) */\nstatic int js_bigint_float64_cmp(JSContext *ctx, const JSBigInt *a,\n                                 double b)\n{\n    int b_sign, a_sign, e, f;\n    uint64_t mant, b1, a_mant;\n    \n    b1 = float64_as_uint64(b);\n    b_sign = b1 >> 63;\n    e = (b1 >> 52) & ((1 << 11) - 1);\n    mant = b1 & (((uint64_t)1 << 52) - 1);\n    a_sign = js_bigint_sign(a);\n    if (e == 2047) {\n        if (mant != 0) {\n            /* NaN */\n            return 2;\n        } else {\n            /* +/- infinity */\n            return 2 * b_sign - 1;\n        }\n    } else if (e == 0 && mant == 0) {\n        /* b = +/-0 */\n        if (a->len == 1 && a->tab[0] == 0)\n            return 0;\n        else\n            return 1 - 2 * a_sign;\n    } else if (a->len == 1 && a->tab[0] == 0) {\n        /* a = 0, b != 0 */\n        return 2 * b_sign - 1;\n    } else if (a_sign != b_sign) {\n        return 1 - 2 * a_sign;\n    } else {\n        e -= 1023;\n        /* Note: handling denormals is not necessary because we\n           compare to integers hence f >= 0 */\n        /* compute f so that 2^f <= abs(a) < 2^(f+1) */\n        a_mant = js_bigint_get_mant_exp(ctx, &f, a);\n        if (f != e) {\n            if (f < e)\n                return -1;\n            else\n                return 1;\n        } else {\n            mant = (mant | ((uint64_t)1 << 52)) << 11; /* align to a_mant */\n            if (a_mant < mant)\n                return 2 * a_sign - 1;\n            else if (a_mant > mant)\n                return 1 - 2 * a_sign;\n            else\n                return 0;\n        }\n    }\n}\n\n/* return -1, 0 or 1 */\nstatic int js_bigint_cmp(JSContext *ctx, const JSBigInt *a,\n                         const JSBigInt *b)\n{\n    int a_sign, b_sign, res, i;\n    a_sign = js_bigint_sign(a);\n    b_sign = js_bigint_sign(b);\n    if (a_sign != b_sign) {\n        res = 1 - 2 * a_sign;\n    } else {\n        /* we assume the numbers are normalized */\n        if (a->len != b->len) {\n            if (a->len < b->len)\n                res = 2 * a_sign - 1;\n            else\n                res = 1 - 2 * a_sign;\n        } else {\n            res = 0;\n            for(i = a->len -1; i >= 0; i--) {\n                if (a->tab[i] != b->tab[i]) {\n                    if (a->tab[i] < b->tab[i])\n                        res = -1;\n                    else\n                        res = 1;\n                    break;\n                }\n            }\n        }\n    }\n    return res;\n}\n\n/* contains 10^i */\nstatic const js_limb_t js_pow_dec[JS_LIMB_DIGITS + 1] = {\n    1U,\n    10U,\n    100U,\n    1000U,\n    10000U,\n    100000U,\n    1000000U,\n    10000000U,\n    100000000U,\n    1000000000U,\n#if JS_LIMB_BITS == 64\n    10000000000U,\n    100000000000U,\n    1000000000000U,\n    10000000000000U,\n    100000000000000U,\n    1000000000000000U,\n    10000000000000000U,\n    100000000000000000U,\n    1000000000000000000U,\n    10000000000000000000U,\n#endif\n};\n\n/* syntax: [-]digits in base radix. Return NULL if memory error. radix\n   = 10, 2, 8 or 16. */\nstatic JSBigInt *js_bigint_from_string(JSContext *ctx,\n                                       const char *str, int radix)\n{\n    const char *p = str;\n    size_t n_digits1;\n    int is_neg, n_digits, n_limbs, len, log2_radix, n_bits, i;\n    JSBigInt *r;\n    js_limb_t v, c, h;\n    \n    is_neg = 0;\n    if (*p == '-') {\n        is_neg = 1;\n        p++;\n    }\n    while (*p == '0')\n        p++;\n    n_digits1 = strlen(p);\n    /* the real check for overflox is done js_bigint_new(). Here\n       we just avoid integer overflow */\n    if (n_digits1 > JS_BIGINT_MAX_SIZE * JS_LIMB_BITS) {\n        JS_ThrowRangeError(ctx, \"BigInt is too large to allocate\");\n        return NULL;\n    }\n    n_digits = n_digits1;\n    log2_radix = 32 - clz32(radix - 1); /* ceil(log2(radix)) */\n    /* compute the maximum number of limbs */\n    if (radix == 10) {\n        n_bits = (n_digits * 27 + 7) / 8; /* >= ceil(n_digits * log2(10)) */\n    } else {\n        n_bits = n_digits * log2_radix;\n    }\n    /* we add one extra bit for the sign */\n    n_limbs = max_int(1, n_bits / JS_LIMB_BITS + 1);\n    r = js_bigint_new(ctx, n_limbs);\n    if (!r)\n        return NULL;\n    if (radix == 10) {\n        int digits_per_limb = JS_LIMB_DIGITS;\n        len = 1;\n        r->tab[0] = 0;\n        for(;;) {\n            /* XXX: slow */\n            v = 0;\n            for(i = 0; i < digits_per_limb; i++) {\n                c = to_digit(*p);\n                if (c >= radix)\n                    break;\n                p++;\n                v = v * 10 + c;\n            }\n            if (i == 0)\n                break;\n            if (len == 1 && r->tab[0] == 0) {\n                r->tab[0] = v;\n            } else {\n                h = mp_mul1(r->tab, r->tab, len, js_pow_dec[i], v);\n                if (h != 0) {\n                    r->tab[len++] = h;\n                }\n            }\n        }\n        /* add one extra limb to have the correct sign*/\n        if ((r->tab[len - 1] >> (JS_LIMB_BITS - 1)) != 0)\n            r->tab[len++] = 0;\n        r->len = len;\n    } else {\n        unsigned int bit_pos, shift, pos;\n        \n        /* power of two base: no multiplication is needed */\n        r->len = n_limbs;\n        memset(r->tab, 0, sizeof(r->tab[0]) * n_limbs);\n        for(i = 0; i < n_digits; i++) {\n            c = to_digit(p[n_digits - 1 - i]);\n            assert(c < radix);\n            bit_pos = i * log2_radix;\n            shift = bit_pos & (JS_LIMB_BITS - 1);\n            pos = bit_pos / JS_LIMB_BITS;\n            r->tab[pos] |= c << shift;\n            /* if log2_radix does not divide JS_LIMB_BITS, needed an\n               additional op */\n            if (shift + log2_radix > JS_LIMB_BITS) {\n                r->tab[pos + 1] |= c >> (JS_LIMB_BITS - shift);\n            }\n        }\n    }\n    r = js_bigint_normalize(ctx, r);\n    /* XXX: could do it in place */\n    if (is_neg) {\n        JSBigInt *r1;\n        r1 = js_bigint_neg(ctx, r);\n        js_free(ctx, r);\n        r = r1;\n    }\n    return r;\n}\n\n/* 2 <= base <= 36 */\nstatic char const digits[36] = \"0123456789abcdefghijklmnopqrstuvwxyz\";\n\n/* special version going backwards */\n/* XXX: use dtoa.c */\nstatic char *js_u64toa(char *q, int64_t n, unsigned int base)\n{\n    int digit;\n    if (base == 10) {\n        /* division by known base uses multiplication */\n        do {\n            digit = (uint64_t)n % 10;\n            n = (uint64_t)n / 10;\n            *--q = '0' + digit;\n        } while (n != 0);\n    } else {\n        do {\n            digit = (uint64_t)n % base;\n            n = (uint64_t)n / base;\n            *--q = digits[digit];\n        } while (n != 0);\n    }\n    return q;\n}\n\n/* len >= 1. 2 <= radix <= 36 */\nstatic char *limb_to_a(char *q, js_limb_t n, unsigned int radix, int len)\n{\n    int digit, i;\n\n    if (radix == 10) {\n        /* specific case with constant divisor */\n        /* XXX: optimize */\n        for(i = 0; i < len; i++) {\n            digit = (js_limb_t)n % 10;\n            n = (js_limb_t)n / 10;\n            *--q = digit + '0';\n        }\n    } else {\n        for(i = 0; i < len; i++) {\n            digit = (js_limb_t)n % radix;\n            n = (js_limb_t)n / radix;\n            *--q = digits[digit];\n        }\n    }\n    return q;\n}\n\n#define JS_RADIX_MAX 36\n\nstatic const uint8_t digits_per_limb_table[JS_RADIX_MAX - 1] = {\n#if JS_LIMB_BITS == 32\n32,20,16,13,12,11,10,10, 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,\n#else\n64,40,32,27,24,22,21,20,19,18,17,17,16,16,16,15,15,15,14,14,14,14,13,13,13,13,13,13,13,12,12,12,12,12,12,\n#endif\n};\n\nstatic const js_limb_t radix_base_table[JS_RADIX_MAX - 1] = {\n#if JS_LIMB_BITS == 32\n 0x00000000, 0xcfd41b91, 0x00000000, 0x48c27395,\n 0x81bf1000, 0x75db9c97, 0x40000000, 0xcfd41b91,\n 0x3b9aca00, 0x8c8b6d2b, 0x19a10000, 0x309f1021,\n 0x57f6c100, 0x98c29b81, 0x00000000, 0x18754571,\n 0x247dbc80, 0x3547667b, 0x4c4b4000, 0x6b5a6e1d,\n 0x94ace180, 0xcaf18367, 0x0b640000, 0x0e8d4a51,\n 0x1269ae40, 0x17179149, 0x1cb91000, 0x23744899,\n 0x2b73a840, 0x34e63b41, 0x40000000, 0x4cfa3cc1,\n 0x5c13d840, 0x6d91b519, 0x81bf1000,\n#else\n 0x0000000000000000, 0xa8b8b452291fe821, 0x0000000000000000, 0x6765c793fa10079d,\n 0x41c21cb8e1000000, 0x3642798750226111, 0x8000000000000000, 0xa8b8b452291fe821,\n 0x8ac7230489e80000, 0x4d28cb56c33fa539, 0x1eca170c00000000, 0x780c7372621bd74d,\n 0x1e39a5057d810000, 0x5b27ac993df97701, 0x0000000000000000, 0x27b95e997e21d9f1,\n 0x5da0e1e53c5c8000, 0xd2ae3299c1c4aedb, 0x16bcc41e90000000, 0x2d04b7fdd9c0ef49,\n 0x5658597bcaa24000, 0xa0e2073737609371, 0x0c29e98000000000, 0x14adf4b7320334b9,\n 0x226ed36478bfa000, 0x383d9170b85ff80b, 0x5a3c23e39c000000, 0x8e65137388122bcd,\n 0xdd41bb36d259e000, 0x0aee5720ee830681, 0x1000000000000000, 0x172588ad4f5f0981,\n 0x211e44f7d02c1000, 0x2ee56725f06e5c71, 0x41c21cb8e1000000,\n#endif\n};\n\nstatic JSValue js_bigint_to_string1(JSContext *ctx, JSValueConst val, int radix)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {\n        char buf[66];\n        int len;\n        len = i64toa_radix(buf, JS_VALUE_GET_SHORT_BIG_INT(val), radix);\n        return js_new_string8_len(ctx, buf, len);\n    } else {\n        JSBigInt *r, *tmp = NULL;\n        char *buf, *q, *buf_end;\n        int is_neg, n_bits, log2_radix, n_digits;\n        BOOL is_binary_radix;\n        JSValue res;\n        \n        assert(JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT);\n        r = JS_VALUE_GET_PTR(val);\n        if (r->len == 1 && r->tab[0] == 0) {\n            /* '0' case */\n            return js_new_string8_len(ctx, \"0\", 1);\n        }\n        is_binary_radix = ((radix & (radix - 1)) == 0);\n        is_neg = js_bigint_sign(r);\n        if (is_neg) {\n            tmp = js_bigint_neg(ctx, r);\n            if (!tmp)\n                return JS_EXCEPTION;\n            r = tmp;\n        } else if (!is_binary_radix) {\n            /* need to modify 'r' */\n            tmp = js_bigint_new(ctx, r->len);\n            if (!tmp)\n                return JS_EXCEPTION;\n            memcpy(tmp->tab, r->tab, r->len * sizeof(r->tab[0]));\n            r = tmp;\n        }\n        log2_radix = 31 - clz32(radix); /* floor(log2(radix)) */\n        n_bits = r->len * JS_LIMB_BITS - js_limb_safe_clz(r->tab[r->len - 1]);\n        /* n_digits is exact only if radix is a power of\n           two. Otherwise it is >= the exact number of digits */\n        n_digits = (n_bits + log2_radix - 1) / log2_radix;\n        /* XXX: could directly build the JSString */\n        buf = js_malloc(ctx, n_digits + is_neg + 1);\n        if (!buf) {\n            js_free(ctx, tmp);\n            return JS_EXCEPTION;\n        }\n        q = buf + n_digits + is_neg + 1;\n        *--q = '\\0';\n        buf_end = q;\n        if (!is_binary_radix) {\n            int len;\n            js_limb_t radix_base, v;\n            radix_base = radix_base_table[radix - 2];\n            len = r->len;\n            for(;;) {\n                /* remove leading zero limbs */\n                while (len > 1 && r->tab[len - 1] == 0)\n                    len--;\n                if (len == 1 && r->tab[0] < radix_base) {\n                    v = r->tab[0];\n                    if (v != 0) {\n                        q = js_u64toa(q, v, radix);\n                    }\n                    break;\n                } else {\n                    v = mp_div1(r->tab, r->tab, len, radix_base, 0);\n                    q = limb_to_a(q, v, radix, digits_per_limb_table[radix - 2]);\n                }\n            }\n        } else {\n            int i, shift;\n            unsigned int bit_pos, pos, c;\n\n            /* radix is a power of two */\n            for(i = 0; i < n_digits; i++) {\n                bit_pos = i * log2_radix;\n                pos = bit_pos / JS_LIMB_BITS;\n                shift = bit_pos % JS_LIMB_BITS;\n                c = r->tab[pos] >> shift;\n                if ((shift + log2_radix) > JS_LIMB_BITS &&\n                    (pos + 1) < r->len) {\n                    c |= r->tab[pos + 1] << (JS_LIMB_BITS - shift);\n                }\n                c &= (radix - 1);\n                *--q = digits[c];\n            }\n        }\n        if (is_neg)\n            *--q = '-';\n        js_free(ctx, tmp);\n        res = js_new_string8_len(ctx, q, buf_end - q);\n        js_free(ctx, buf);\n        return res;\n    }\n}\n\n/* if possible transform a BigInt to short big and free it, otherwise\n   return a normal bigint */\nstatic JSValue JS_CompactBigInt(JSContext *ctx, JSBigInt *p)\n{\n    JSValue res;\n    if (p->len == 1) {\n        res = __JS_NewShortBigInt(ctx, (js_slimb_t)p->tab[0]);\n        js_free(ctx, p);\n        return res;\n    } else {\n        return JS_MKPTR(JS_TAG_BIG_INT, p);\n    }\n}\n\n#define ATOD_INT_ONLY        (1 << 0)\n/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */\n#define ATOD_ACCEPT_BIN_OCT  (1 << 2)\n/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */\n#define ATOD_ACCEPT_LEGACY_OCTAL  (1 << 4)\n/* accept _ between digits as a digit separator */\n#define ATOD_ACCEPT_UNDERSCORES  (1 << 5)\n/* allow a suffix to override the type */\n#define ATOD_ACCEPT_SUFFIX    (1 << 6)\n/* default type */\n#define ATOD_TYPE_MASK        (3 << 7)\n#define ATOD_TYPE_FLOAT64     (0 << 7)\n#define ATOD_TYPE_BIG_INT     (1 << 7)\n/* accept -0x1 */\n#define ATOD_ACCEPT_PREFIX_AFTER_SIGN (1 << 10)\n\n/* return an exception in case of memory error. Return JS_NAN if\n   invalid syntax */\n/* XXX: directly use js_atod() */\nstatic JSValue js_atof(JSContext *ctx, const char *str, const char **pp,\n                       int radix, int flags)\n{\n    const char *p, *p_start;\n    int sep, is_neg;\n    BOOL is_float, has_legacy_octal;\n    int atod_type = flags & ATOD_TYPE_MASK;\n    char buf1[64], *buf;\n    int i, j, len;\n    BOOL buf_allocated = FALSE;\n    JSValue val;\n    JSATODTempMem atod_mem;\n    \n    /* optional separator between digits */\n    sep = (flags & ATOD_ACCEPT_UNDERSCORES) ? '_' : 256;\n    has_legacy_octal = FALSE;\n\n    p = str;\n    p_start = p;\n    is_neg = 0;\n    if (p[0] == '+') {\n        p++;\n        p_start++;\n        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))\n            goto no_radix_prefix;\n    } else if (p[0] == '-') {\n        p++;\n        p_start++;\n        is_neg = 1;\n        if (!(flags & ATOD_ACCEPT_PREFIX_AFTER_SIGN))\n            goto no_radix_prefix;\n    }\n    if (p[0] == '0') {\n        if ((p[1] == 'x' || p[1] == 'X') &&\n            (radix == 0 || radix == 16)) {\n            p += 2;\n            radix = 16;\n        } else if ((p[1] == 'o' || p[1] == 'O') &&\n                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {\n            p += 2;\n            radix = 8;\n        } else if ((p[1] == 'b' || p[1] == 'B') &&\n                   radix == 0 && (flags & ATOD_ACCEPT_BIN_OCT)) {\n            p += 2;\n            radix = 2;\n        } else if ((p[1] >= '0' && p[1] <= '9') &&\n                   radix == 0 && (flags & ATOD_ACCEPT_LEGACY_OCTAL)) {\n            int i;\n            has_legacy_octal = TRUE;\n            sep = 256;\n            for (i = 1; (p[i] >= '0' && p[i] <= '7'); i++)\n                continue;\n            if (p[i] == '8' || p[i] == '9')\n                goto no_prefix;\n            p += 1;\n            radix = 8;\n        } else {\n            goto no_prefix;\n        }\n        /* there must be a digit after the prefix */\n        if (to_digit((uint8_t)*p) >= radix)\n            goto fail;\n    no_prefix: ;\n    } else {\n no_radix_prefix:\n        if (!(flags & ATOD_INT_ONLY) &&\n            (atod_type == ATOD_TYPE_FLOAT64) &&\n            strstart(p, \"Infinity\", &p)) {\n            double d = 1.0 / 0.0;\n            if (is_neg)\n                d = -d;\n            val = JS_NewFloat64(ctx, d);\n            goto done;\n        }\n    }\n    if (radix == 0)\n        radix = 10;\n    is_float = FALSE;\n    p_start = p;\n    while (to_digit((uint8_t)*p) < radix\n           ||  (*p == sep && (radix != 10 ||\n                              p != p_start + 1 || p[-1] != '0') &&\n                to_digit((uint8_t)p[1]) < radix)) {\n        p++;\n    }\n    if (!(flags & ATOD_INT_ONLY)) {\n        if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {\n            is_float = TRUE;\n            p++;\n            if (*p == sep)\n                goto fail;\n            while (to_digit((uint8_t)*p) < radix ||\n                   (*p == sep && to_digit((uint8_t)p[1]) < radix))\n                p++;\n        }\n        if (p > p_start &&\n            (((*p == 'e' || *p == 'E') && radix == 10) ||\n             ((*p == 'p' || *p == 'P') && (radix == 2 || radix == 8 || radix == 16)))) {\n            const char *p1 = p + 1;\n            is_float = TRUE;\n            if (*p1 == '+') {\n                p1++;\n            } else if (*p1 == '-') {\n                p1++;\n            }\n            if (is_digit((uint8_t)*p1)) {\n                p = p1 + 1;\n                while (is_digit((uint8_t)*p) || (*p == sep && is_digit((uint8_t)p[1])))\n                    p++;\n            }\n        }\n    }\n    if (p == p_start)\n        goto fail;\n\n    buf = buf1;\n    buf_allocated = FALSE;\n    len = p - p_start;\n    if (unlikely((len + 2) > sizeof(buf1))) {\n        buf = js_malloc_rt(ctx->rt, len + 2); /* no exception raised */\n        if (!buf)\n            goto mem_error;\n        buf_allocated = TRUE;\n    }\n    /* remove the separators and the radix prefixes */\n    j = 0;\n    if (is_neg)\n        buf[j++] = '-';\n    for (i = 0; i < len; i++) {\n        if (p_start[i] != '_')\n            buf[j++] = p_start[i];\n    }\n    buf[j] = '\\0';\n\n    if (flags & ATOD_ACCEPT_SUFFIX) {\n        if (*p == 'n') {\n            p++;\n            atod_type = ATOD_TYPE_BIG_INT;\n        } else {\n            if (is_float && radix != 10)\n                goto fail;\n        }\n    } else {\n        if (atod_type == ATOD_TYPE_FLOAT64) {\n            if (is_float && radix != 10)\n                goto fail;\n        }\n    }\n\n    switch(atod_type) {\n    case ATOD_TYPE_FLOAT64:\n        {\n            double d;\n            d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY,\n                        &atod_mem);\n            /* return int or float64 */\n            val = JS_NewFloat64(ctx, d);\n        }\n        break;\n    case ATOD_TYPE_BIG_INT:\n        {\n            JSBigInt *r;\n            if (has_legacy_octal || is_float)\n                goto fail;\n            r = js_bigint_from_string(ctx, buf, radix);\n            if (!r) {\n                val = JS_EXCEPTION;\n                goto done;\n            }\n            val = JS_CompactBigInt(ctx, r);\n        }\n        break;\n    default:\n        abort();\n    }\n\ndone:\n    if (buf_allocated)\n        js_free_rt(ctx->rt, buf);\n    if (pp)\n        *pp = p;\n    return val;\n fail:\n    val = JS_NAN;\n    goto done;\n mem_error:\n    val = JS_ThrowOutOfMemory(ctx);\n    goto done;\n}\n\ntypedef enum JSToNumberHintEnum {\n    TON_FLAG_NUMBER,\n    TON_FLAG_NUMERIC,\n} JSToNumberHintEnum;\n\nstatic JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,\n                                   JSToNumberHintEnum flag)\n{\n    uint32_t tag;\n    JSValue ret;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_BIG_INT:\n    case JS_TAG_SHORT_BIG_INT:\n        if (flag != TON_FLAG_NUMERIC) {\n            JS_FreeValue(ctx, val);\n            return JS_ThrowTypeError(ctx, \"cannot convert bigint to number\");\n        }\n        ret = val;\n        break;\n    case JS_TAG_FLOAT64:\n    case JS_TAG_INT:\n    case JS_TAG_EXCEPTION:\n        ret = val;\n        break;\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));\n        break;\n    case JS_TAG_UNDEFINED:\n        ret = JS_NAN;\n        break;\n    case JS_TAG_OBJECT:\n        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);\n        if (JS_IsException(val))\n            return JS_EXCEPTION;\n        goto redo;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        {\n            const char *str;\n            const char *p;\n            size_t len;\n\n            str = JS_ToCStringLen(ctx, &len, val);\n            JS_FreeValue(ctx, val);\n            if (!str)\n                return JS_EXCEPTION;\n            p = str;\n            p += skip_spaces(p);\n            if ((p - str) == len) {\n                ret = JS_NewInt32(ctx, 0);\n            } else {\n                int flags = ATOD_ACCEPT_BIN_OCT;\n                ret = js_atof(ctx, p, &p, 0, flags);\n                if (!JS_IsException(ret)) {\n                    p += skip_spaces(p);\n                    if ((p - str) != len) {\n                        JS_FreeValue(ctx, ret);\n                        ret = JS_NAN;\n                    }\n                }\n            }\n            JS_FreeCString(ctx, str);\n        }\n        break;\n    case JS_TAG_SYMBOL:\n        JS_FreeValue(ctx, val);\n        return JS_ThrowTypeError(ctx, \"cannot convert symbol to number\");\n    default:\n        JS_FreeValue(ctx, val);\n        ret = JS_NAN;\n        break;\n    }\n    return ret;\n}\n\nstatic JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)\n{\n    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);\n}\n\nstatic JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)\n{\n    return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);\n}\n\nstatic JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)\n{\n    return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));\n}\n\nstatic __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,\n                                          JSValue val)\n{\n    double d;\n    uint32_t tag;\n    \n    val = JS_ToNumberFree(ctx, val);\n    if (JS_IsException(val))\n        goto fail;\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n        d = JS_VALUE_GET_INT(val);\n        break;\n    case JS_TAG_FLOAT64:\n        d = JS_VALUE_GET_FLOAT64(val);\n        break;\n    default:\n        abort();\n    }\n    *pres = d;\n    return 0;\n fail:\n    *pres = JS_FLOAT64_NAN;\n    return -1;\n}\n\nstatic inline int JS_ToFloat64Free(JSContext *ctx, double *pres, JSValue val)\n{\n    uint32_t tag;\n\n    tag = JS_VALUE_GET_TAG(val);\n    if (tag <= JS_TAG_NULL) {\n        *pres = JS_VALUE_GET_INT(val);\n        return 0;\n    } else if (JS_TAG_IS_FLOAT64(tag)) {\n        *pres = JS_VALUE_GET_FLOAT64(val);\n        return 0;\n    } else {\n        return __JS_ToFloat64Free(ctx, pres, val);\n    }\n}\n\nint JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val)\n{\n    return JS_ToFloat64Free(ctx, pres, JS_DupValue(ctx, val));\n}\n\nstatic JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)\n{\n    return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));\n}\n\n/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */\nstatic __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)\n{\n    uint32_t tag;\n    JSValue ret;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        ret = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));\n        break;\n    case JS_TAG_FLOAT64:\n        {\n            double d = JS_VALUE_GET_FLOAT64(val);\n            if (isnan(d)) {\n                ret = JS_NewInt32(ctx, 0);\n            } else {\n                /* convert -0 to +0 */\n                d = trunc(d) + 0.0;\n                ret = JS_NewFloat64(ctx, d);\n            }\n        }\n        break;\n    default:\n        val = JS_ToNumberFree(ctx, val);\n        if (JS_IsException(val))\n            return val;\n        goto redo;\n    }\n    return ret;\n}\n\n/* Note: the integer value is satured to 32 bits */\nstatic int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)\n{\n    uint32_t tag;\n    int ret;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        ret = JS_VALUE_GET_INT(val);\n        break;\n    case JS_TAG_EXCEPTION:\n        *pres = 0;\n        return -1;\n    case JS_TAG_FLOAT64:\n        {\n            double d = JS_VALUE_GET_FLOAT64(val);\n            if (isnan(d)) {\n                ret = 0;\n            } else {\n                if (d < INT32_MIN)\n                    ret = INT32_MIN;\n                else if (d > INT32_MAX)\n                    ret = INT32_MAX;\n                else\n                    ret = (int)d;\n            }\n        }\n        break;\n    default:\n        val = JS_ToNumberFree(ctx, val);\n        if (JS_IsException(val)) {\n            *pres = 0;\n            return -1;\n        }\n        goto redo;\n    }\n    *pres = ret;\n    return 0;\n}\n\nint JS_ToInt32Sat(JSContext *ctx, int *pres, JSValueConst val)\n{\n    return JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));\n}\n\nint JS_ToInt32Clamp(JSContext *ctx, int *pres, JSValueConst val,\n                    int min, int max, int min_offset)\n{\n    int res = JS_ToInt32SatFree(ctx, pres, JS_DupValue(ctx, val));\n    if (res == 0) {\n        if (*pres < min) {\n            *pres += min_offset;\n            if (*pres < min)\n                *pres = min;\n        } else {\n            if (*pres > max)\n                *pres = max;\n        }\n    }\n    return res;\n}\n\nstatic int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)\n{\n    uint32_t tag;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        *pres = JS_VALUE_GET_INT(val);\n        return 0;\n    case JS_TAG_EXCEPTION:\n        *pres = 0;\n        return -1;\n    case JS_TAG_FLOAT64:\n        {\n            double d = JS_VALUE_GET_FLOAT64(val);\n            if (isnan(d)) {\n                *pres = 0;\n            } else {\n                if (d < INT64_MIN)\n                    *pres = INT64_MIN;\n                else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */\n                    *pres = INT64_MAX;\n                else\n                    *pres = (int64_t)d;\n            }\n        }\n        return 0;\n    default:\n        val = JS_ToNumberFree(ctx, val);\n        if (JS_IsException(val)) {\n            *pres = 0;\n            return -1;\n        }\n        goto redo;\n    }\n}\n\nint JS_ToInt64Sat(JSContext *ctx, int64_t *pres, JSValueConst val)\n{\n    return JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));\n}\n\nint JS_ToInt64Clamp(JSContext *ctx, int64_t *pres, JSValueConst val,\n                    int64_t min, int64_t max, int64_t neg_offset)\n{\n    int res = JS_ToInt64SatFree(ctx, pres, JS_DupValue(ctx, val));\n    if (res == 0) {\n        if (*pres < 0)\n            *pres += neg_offset;\n        if (*pres < min)\n            *pres = min;\n        else if (*pres > max)\n            *pres = max;\n    }\n    return res;\n}\n\n/* Same as JS_ToInt32Free() but with a 64 bit result. Return (<0, 0)\n   in case of exception */\nstatic int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)\n{\n    uint32_t tag;\n    int64_t ret;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        ret = JS_VALUE_GET_INT(val);\n        break;\n    case JS_TAG_FLOAT64:\n        {\n            JSFloat64Union u;\n            double d;\n            int e;\n            d = JS_VALUE_GET_FLOAT64(val);\n            u.d = d;\n            /* we avoid doing fmod(x, 2^64) */\n            e = (u.u64 >> 52) & 0x7ff;\n            if (likely(e <= (1023 + 62))) {\n                /* fast case */\n                ret = (int64_t)d;\n            } else if (e <= (1023 + 62 + 53)) {\n                uint64_t v;\n                /* remainder modulo 2^64 */\n                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);\n                ret = v << ((e - 1023) - 52);\n                /* take the sign into account */\n                if (u.u64 >> 63)\n                    ret = -ret;\n            } else {\n                ret = 0; /* also handles NaN and +inf */\n            }\n        }\n        break;\n    default:\n        val = JS_ToNumberFree(ctx, val);\n        if (JS_IsException(val)) {\n            *pres = 0;\n            return -1;\n        }\n        goto redo;\n    }\n    *pres = ret;\n    return 0;\n}\n\nint JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)\n{\n    return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));\n}\n\nint JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)\n{\n    if (JS_IsBigInt(ctx, val))\n        return JS_ToBigInt64(ctx, pres, val);\n    else\n        return JS_ToInt64(ctx, pres, val);\n}\n\n/* return (<0, 0) in case of exception */\nstatic int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)\n{\n    uint32_t tag;\n    int32_t ret;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        ret = JS_VALUE_GET_INT(val);\n        break;\n    case JS_TAG_FLOAT64:\n        {\n            JSFloat64Union u;\n            double d;\n            int e;\n            d = JS_VALUE_GET_FLOAT64(val);\n            u.d = d;\n            /* we avoid doing fmod(x, 2^32) */\n            e = (u.u64 >> 52) & 0x7ff;\n            if (likely(e <= (1023 + 30))) {\n                /* fast case */\n                ret = (int32_t)d;\n            } else if (e <= (1023 + 30 + 53)) {\n                uint64_t v;\n                /* remainder modulo 2^32 */\n                v = (u.u64 & (((uint64_t)1 << 52) - 1)) | ((uint64_t)1 << 52);\n                v = v << ((e - 1023) - 52 + 32);\n                ret = v >> 32;\n                /* take the sign into account */\n                if (u.u64 >> 63)\n                    ret = -ret;\n            } else {\n                ret = 0; /* also handles NaN and +inf */\n            }\n        }\n        break;\n    default:\n        val = JS_ToNumberFree(ctx, val);\n        if (JS_IsException(val)) {\n            *pres = 0;\n            return -1;\n        }\n        goto redo;\n    }\n    *pres = ret;\n    return 0;\n}\n\nint JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val)\n{\n    return JS_ToInt32Free(ctx, pres, JS_DupValue(ctx, val));\n}\n\nstatic inline int JS_ToUint32Free(JSContext *ctx, uint32_t *pres, JSValue val)\n{\n    return JS_ToInt32Free(ctx, (int32_t *)pres, val);\n}\n\nstatic int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)\n{\n    uint32_t tag;\n    int res;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        res = JS_VALUE_GET_INT(val);\n        res = max_int(0, min_int(255, res));\n        break;\n    case JS_TAG_FLOAT64:\n        {\n            double d = JS_VALUE_GET_FLOAT64(val);\n            if (isnan(d)) {\n                res = 0;\n            } else {\n                if (d < 0)\n                    res = 0;\n                else if (d > 255)\n                    res = 255;\n                else\n                    res = lrint(d);\n            }\n        }\n        break;\n    default:\n        val = JS_ToNumberFree(ctx, val);\n        if (JS_IsException(val)) {\n            *pres = 0;\n            return -1;\n        }\n        goto redo;\n    }\n    *pres = res;\n    return 0;\n}\n\nstatic __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,\n                                            JSValue val, BOOL is_array_ctor)\n{\n    uint32_t tag, len;\n\n    tag = JS_VALUE_GET_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n        {\n            int v;\n            v = JS_VALUE_GET_INT(val);\n            if (v < 0)\n                goto fail;\n            len = v;\n        }\n        break;\n    default:\n        if (JS_TAG_IS_FLOAT64(tag)) {\n            double d;\n            d = JS_VALUE_GET_FLOAT64(val);\n            if (!(d >= 0 && d <= UINT32_MAX))\n                goto fail;\n            len = (uint32_t)d;\n            if (len != d)\n                goto fail;\n        } else {\n            uint32_t len1;\n\n            if (is_array_ctor) {\n                val = JS_ToNumberFree(ctx, val);\n                if (JS_IsException(val))\n                    return -1;\n                /* cannot recurse because val is a number */\n                if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))\n                    return -1;\n            } else {\n                /* legacy behavior: must do the conversion twice and compare */\n                if (JS_ToUint32(ctx, &len, val)) {\n                    JS_FreeValue(ctx, val);\n                    return -1;\n                }\n                val = JS_ToNumberFree(ctx, val);\n                if (JS_IsException(val))\n                    return -1;\n                /* cannot recurse because val is a number */\n                if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))\n                    return -1;\n                if (len1 != len) {\n                fail:\n                    JS_ThrowRangeError(ctx, \"invalid array length\");\n                    return -1;\n                }\n            }\n        }\n        break;\n    }\n    *plen = len;\n    return 0;\n}\n\n#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)\n\nstatic BOOL is_safe_integer(double d)\n{\n    return isfinite(d) && floor(d) == d &&\n        fabs(d) <= (double)MAX_SAFE_INTEGER;\n}\n\nint JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)\n{\n    int64_t v;\n    if (JS_ToInt64Sat(ctx, &v, val))\n        return -1;\n    if (v < 0 || v > MAX_SAFE_INTEGER) {\n        JS_ThrowRangeError(ctx, \"invalid array index\");\n        *plen = 0;\n        return -1;\n    }\n    *plen = v;\n    return 0;\n}\n\n/* convert a value to a length between 0 and MAX_SAFE_INTEGER.\n   return -1 for exception */\nstatic __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,\n                                       JSValue val)\n{\n    int res = JS_ToInt64Clamp(ctx, plen, val, 0, MAX_SAFE_INTEGER, 0);\n    JS_FreeValue(ctx, val);\n    return res;\n}\n\n/* Note: can return an exception */\nstatic int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)\n{\n    double d;\n    if (!JS_IsNumber(val))\n        return FALSE;\n    if (unlikely(JS_ToFloat64(ctx, &d, val)))\n        return -1;\n    return isfinite(d) && floor(d) == d;\n}\n\nstatic BOOL JS_NumberIsNegativeOrMinusZero(JSContext *ctx, JSValueConst val)\n{\n    uint32_t tag;\n\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n        {\n            int v;\n            v = JS_VALUE_GET_INT(val);\n            return (v < 0);\n        }\n    case JS_TAG_FLOAT64:\n        {\n            JSFloat64Union u;\n            u.d = JS_VALUE_GET_FLOAT64(val);\n            return (u.u64 >> 63);\n        }\n    case JS_TAG_SHORT_BIG_INT:\n        return (JS_VALUE_GET_SHORT_BIG_INT(val) < 0);\n    case JS_TAG_BIG_INT:\n        {\n            JSBigInt *p = JS_VALUE_GET_PTR(val);\n            return js_bigint_sign(p);\n        }\n    default:\n        return FALSE;\n    }\n}\n\nstatic JSValue js_bigint_to_string(JSContext *ctx, JSValueConst val)\n{\n    return js_bigint_to_string1(ctx, val, 10);\n}\n\nstatic JSValue js_dtoa2(JSContext *ctx,\n                        double d, int radix, int n_digits, int flags)\n{\n    char static_buf[128], *buf, *tmp_buf;\n    int len, len_max;\n    JSValue res;\n    JSDTOATempMem dtoa_mem;\n    len_max = js_dtoa_max_len(d, radix, n_digits, flags);\n    \n    /* longer buffer may be used if radix != 10 */\n    if (len_max > sizeof(static_buf) - 1) {\n        tmp_buf = js_malloc(ctx, len_max + 1);\n        if (!tmp_buf)\n            return JS_EXCEPTION;\n        buf = tmp_buf;\n    } else {\n        tmp_buf = NULL;\n        buf = static_buf;\n    }\n    len = js_dtoa(buf, d, radix, n_digits, flags, &dtoa_mem);\n    res = js_new_string8_len(ctx, buf, len);\n    js_free(ctx, tmp_buf);\n    return res;\n}\n\nstatic JSValue JS_ToStringInternal(JSContext *ctx, JSValueConst val, BOOL is_ToPropertyKey)\n{\n    uint32_t tag;\n    char buf[32];\n\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_STRING:\n        return JS_DupValue(ctx, val);\n    case JS_TAG_STRING_ROPE:\n        return js_linearize_string_rope(ctx, JS_DupValue(ctx, val));\n    case JS_TAG_INT:\n        {\n            size_t len;\n            len = i32toa(buf, JS_VALUE_GET_INT(val));\n            return js_new_string8_len(ctx, buf, len);\n        }\n        break;\n    case JS_TAG_BOOL:\n        return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?\n                          JS_ATOM_true : JS_ATOM_false);\n    case JS_TAG_NULL:\n        return JS_AtomToString(ctx, JS_ATOM_null);\n    case JS_TAG_UNDEFINED:\n        return JS_AtomToString(ctx, JS_ATOM_undefined);\n    case JS_TAG_EXCEPTION:\n        return JS_EXCEPTION;\n    case JS_TAG_OBJECT:\n        {\n            JSValue val1, ret;\n            val1 = JS_ToPrimitive(ctx, val, HINT_STRING);\n            if (JS_IsException(val1))\n                return val1;\n            ret = JS_ToStringInternal(ctx, val1, is_ToPropertyKey);\n            JS_FreeValue(ctx, val1);\n            return ret;\n        }\n        break;\n    case JS_TAG_FUNCTION_BYTECODE:\n        return js_new_string8(ctx, \"[function bytecode]\");\n    case JS_TAG_SYMBOL:\n        if (is_ToPropertyKey) {\n            return JS_DupValue(ctx, val);\n        } else {\n            return JS_ThrowTypeError(ctx, \"cannot convert symbol to string\");\n        }\n    case JS_TAG_FLOAT64:\n        return js_dtoa2(ctx, JS_VALUE_GET_FLOAT64(val), 10, 0,\n                        JS_DTOA_FORMAT_FREE);\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        return js_bigint_to_string(ctx, val);\n    default:\n        return js_new_string8(ctx, \"[unsupported type]\");\n    }\n}\n\nJSValue JS_ToString(JSContext *ctx, JSValueConst val)\n{\n    return JS_ToStringInternal(ctx, val, FALSE);\n}\n\nstatic JSValue JS_ToStringFree(JSContext *ctx, JSValue val)\n{\n    JSValue ret;\n    ret = JS_ToString(ctx, val);\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic JSValue JS_ToLocaleStringFree(JSContext *ctx, JSValue val)\n{\n    if (JS_IsUndefined(val) || JS_IsNull(val))\n        return JS_ToStringFree(ctx, val);\n    return JS_InvokeFree(ctx, val, JS_ATOM_toLocaleString, 0, NULL);\n}\n\nJSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val)\n{\n    return JS_ToStringInternal(ctx, val, TRUE);\n}\n\nstatic JSValue JS_ToStringCheckObject(JSContext *ctx, JSValueConst val)\n{\n    uint32_t tag = JS_VALUE_GET_TAG(val);\n    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)\n        return JS_ThrowTypeError(ctx, \"null or undefined are forbidden\");\n    return JS_ToString(ctx, val);\n}\n\n#define JS_PRINT_MAX_DEPTH 8\n\ntypedef struct {\n    JSRuntime *rt;\n    JSContext *ctx; /* may be NULL */\n    JSPrintValueOptions options;\n    JSPrintValueWrite *write_func;\n    void *write_opaque;\n    int level;\n    JSObject *print_stack[JS_PRINT_MAX_DEPTH]; /* level values */\n} JSPrintValueState;\n\nstatic void js_print_value(JSPrintValueState *s, JSValueConst val);\n\nstatic void js_putc(JSPrintValueState *s, char c)\n{\n    s->write_func(s->write_opaque, &c, 1);\n}\n\nstatic void js_puts(JSPrintValueState *s, const char *str)\n{\n    s->write_func(s->write_opaque, str, strlen(str));\n}\n\nstatic void __attribute__((format(printf, 2, 3))) js_printf(JSPrintValueState *s, const char *fmt, ...)\n{\n    va_list ap;\n    char buf[256];\n    \n    va_start(ap, fmt);\n    vsnprintf(buf, sizeof(buf), fmt, ap);\n    va_end(ap);\n    s->write_func(s->write_opaque, buf, strlen(buf));\n}\n\nstatic void js_print_float64(JSPrintValueState *s, double d)\n{\n    JSDTOATempMem dtoa_mem;\n    char buf[32];\n    int len;\n    len = js_dtoa(buf, d, 10, 0, JS_DTOA_FORMAT_FREE | JS_DTOA_MINUS_ZERO, &dtoa_mem);\n    s->write_func(s->write_opaque, buf, len);\n}\n\nstatic uint32_t js_string_get_length(JSValueConst val)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {\n        JSString *p = JS_VALUE_GET_STRING(val);\n        return p->len;\n    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {\n        JSStringRope *r = JS_VALUE_GET_PTR(val);\n        return r->len;\n    } else {\n        return 0;\n    }\n}\n\n/* pretty print the first 'len' characters of 'p' */\nstatic void js_print_string1(JSPrintValueState *s, JSString *p, int len, int sep)\n{\n    uint8_t buf[UTF8_CHAR_LEN_MAX];\n    int l, i, c, c1;\n\n    for(i = 0; i < len; i++) {\n        c = string_get(p, i);\n        switch(c) {\n        case '\\t':\n            c = 't';\n            goto quote;\n        case '\\r':\n            c = 'r';\n            goto quote;\n        case '\\n':\n            c = 'n';\n            goto quote;\n        case '\\b':\n            c = 'b';\n            goto quote;\n        case '\\f':\n            c = 'f';\n            goto quote;\n        case '\\\\':\n        quote:\n            js_putc(s, '\\\\');\n            js_putc(s, c);\n            break;\n        default:\n            if (c == sep)\n                goto quote;\n            if (c >= 32 && c <= 126) {\n                js_putc(s, c);\n            } else if (c < 32 || \n                       (c >= 0x7f && c <= 0x9f)) {\n            escape:\n                js_printf(s, \"\\\\u%04x\", c);\n            } else {\n                if (is_hi_surrogate(c)) {\n                    if ((i + 1) >= len)\n                        goto escape;\n                    c1 = string_get(p, i + 1);\n                    if (!is_lo_surrogate(c1))\n                        goto escape;\n                    i++;\n                    c = from_surrogate(c, c1);\n                } else if (is_lo_surrogate(c)) {\n                    goto escape;\n                }\n                l = unicode_to_utf8(buf, c);\n                s->write_func(s->write_opaque, (char *)buf, l);\n            }\n            break;\n        }\n    }\n}\n\nstatic void js_print_string_rec(JSPrintValueState *s, JSValueConst val,\n                                int sep, uint32_t pos)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {\n        JSString *p = JS_VALUE_GET_STRING(val);\n        uint32_t len;\n        if (pos < s->options.max_string_length) {\n            len = min_uint32(p->len, s->options.max_string_length - pos);\n            js_print_string1(s, p, len, sep);\n        }\n    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING_ROPE) {\n        JSStringRope *r = JS_VALUE_GET_PTR(val);\n        js_print_string_rec(s, r->left, sep, pos);\n        js_print_string_rec(s, r->right, sep, pos + js_string_get_length(r->left));\n    } else {\n        js_printf(s, \"<invalid string tag %d>\", (int)JS_VALUE_GET_TAG(val));\n    }\n}\n\nstatic void js_print_string(JSPrintValueState *s, JSValueConst val)\n{\n    int sep;\n    if (s->options.raw_dump && JS_VALUE_GET_TAG(val) == JS_TAG_STRING) {\n        JSString *p = JS_VALUE_GET_STRING(val);\n        js_printf(s, \"%d\", p->header.ref_count);\n        sep = (p->header.ref_count == 1) ? '\\\"' : '\\'';\n    } else {\n        sep = '\\\"';\n    }\n    js_putc(s, sep);\n    js_print_string_rec(s, val, sep, 0);\n    js_putc(s, sep);\n    if (js_string_get_length(val) > s->options.max_string_length) {\n        uint32_t n = js_string_get_length(val) - s->options.max_string_length;\n        js_printf(s, \"... %u more character%s\", n, n > 1 ? \"s\" : \"\");\n    }\n}\n\nstatic void js_print_raw_string(JSPrintValueState *s, JSValueConst val)\n{\n    const char *cstr;\n    size_t len;\n    cstr = JS_ToCStringLen(s->ctx, &len, val);\n    if (cstr) {\n        s->write_func(s->write_opaque, cstr, len);\n        JS_FreeCString(s->ctx, cstr);\n    }\n}\n\nstatic BOOL is_ascii_ident(const JSString *p)\n{\n    int i, c;\n\n    if (p->len == 0)\n        return FALSE;\n    for(i = 0; i < p->len; i++) {\n        c = string_get(p, i);\n        if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||\n              (c == '_' || c == '$') || (c >= '0' && c <= '9' && i > 0)))\n            return FALSE;\n    }\n    return TRUE;\n}\n\nstatic void js_print_atom(JSPrintValueState *s, JSAtom atom)\n{\n    int i;\n    if (__JS_AtomIsTaggedInt(atom)) {\n        js_printf(s, \"%u\", __JS_AtomToUInt32(atom));\n    } else if (atom == JS_ATOM_NULL) {\n        js_puts(s, \"<null>\");\n    } else {\n        assert(atom < s->rt->atom_size);\n        JSString *p;\n        p = s->rt->atom_array[atom];\n        if (is_ascii_ident(p)) {\n            for(i = 0; i < p->len; i++) {\n                js_putc(s, string_get(p, i));\n            }\n        } else {\n            js_putc(s, '\"');\n            js_print_string1(s, p, p->len, '\\\"');\n            js_putc(s, '\"');\n        }\n    }\n}\n\n/* return 0 if invalid length */\nstatic uint32_t js_print_array_get_length(JSObject *p)\n{\n    JSProperty *pr;\n    JSShapeProperty *prs;\n    JSValueConst val;\n\n    prs = find_own_property(&pr, p, JS_ATOM_length);\n    if (!prs)\n        return 0;\n    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)\n        return 0;\n    val = pr->u.value;\n    switch(JS_VALUE_GET_NORM_TAG(val)) {\n    case JS_TAG_INT:\n        return JS_VALUE_GET_INT(val);\n    case JS_TAG_FLOAT64:\n        return (uint32_t)JS_VALUE_GET_FLOAT64(val);\n    default:\n        return 0;\n    }\n}\n\nstatic void js_print_comma(JSPrintValueState *s, int *pcomma_state)\n{\n    switch(*pcomma_state) {\n    case 0:\n        break;\n    case 1:\n        js_printf(s, \", \");\n        break;\n    case 2:\n        js_printf(s, \" { \");\n        break;\n    }\n    *pcomma_state = 1;\n}\n\nstatic void js_print_more_items(JSPrintValueState *s, int *pcomma_state,\n                                uint32_t n)\n{\n    js_print_comma(s, pcomma_state);\n    js_printf(s, \"... %u more item%s\", n, n > 1 ? \"s\" : \"\");\n}\n\n/* similar to js_regexp_toString() but without side effect */\nstatic void js_print_regexp(JSPrintValueState *s, JSObject *p1)\n{\n    JSRegExp *re = &p1->u.regexp;\n    JSString *p;\n    int i, n, c, c2, bra, flags;\n    static const char regexp_flags[] = { 'g', 'i', 'm', 's', 'u', 'y', 'd', 'v' };\n\n    if (!re->pattern || !re->bytecode) {\n        /* the regexp fields are zeroed at init */\n        js_puts(s, \"[uninitialized_regexp]\");\n        return;\n    }\n    p = re->pattern;\n    js_putc(s, '/');\n    if (p->len == 0) {\n        js_puts(s, \"(?:)\");\n    } else {\n        bra = 0;\n        for (i = 0, n = p->len; i < n;) {\n            c2 = -1;\n            switch (c = string_get(p, i++)) {\n            case '\\\\':\n                if (i < n)\n                    c2 = string_get(p, i++);\n                break;\n            case ']':\n                bra = 0;\n                break;\n            case '[':\n                if (!bra) {\n                    if (i < n && string_get(p, i) == ']')\n                        c2 = string_get(p, i++);\n                    bra = 1;\n                }\n                break;\n            case '\\n':\n                c = '\\\\';\n                c2 = 'n';\n                break;\n            case '\\r':\n                c = '\\\\';\n                c2 = 'r';\n                break;\n            case '/':\n                if (!bra) {\n                    c = '\\\\';\n                    c2 = '/';\n                }\n                break;\n            }\n            js_putc(s, c);\n            if (c2 >= 0)\n                js_putc(s, c2);\n        }\n    }\n    js_putc(s, '/');\n\n    flags = lre_get_flags(re->bytecode->u.str8);\n    for(i = 0; i < countof(regexp_flags); i++) {\n        if ((flags >> i) & 1) {\n            js_putc(s, regexp_flags[i]);\n        }\n    }\n}\n\n/* similar to js_error_toString() but without side effect */\nstatic void js_print_error(JSPrintValueState *s, JSObject *p)\n{\n    const char *str;\n    size_t len;\n\n    str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_name);\n    if (!str) {\n        js_puts(s, \"Error\");\n    } else {\n        js_puts(s, str);\n        JS_FreeCString(s->ctx, str);\n    }\n    \n    str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_message);\n    if (str && str[0] != '\\0') {\n        js_puts(s, \": \");\n        js_puts(s, str);\n    }\n    JS_FreeCString(s->ctx, str);\n\n    /* dump the stack if present */\n    str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_stack);\n    if (str) {\n        js_putc(s, '\\n');\n        \n        /* XXX: should remove the last '\\n' in stack as\n           v8. SpiderMonkey does not do it */\n        len = strlen(str);\n        if (len > 0 && str[len - 1] == '\\n')\n            len--;\n        s->write_func(s->write_opaque, str, len);\n        \n        JS_FreeCString(s->ctx, str);\n    }\n}\n\nstatic void js_print_object(JSPrintValueState *s, JSObject *p)\n{\n    JSRuntime *rt = s->rt;\n    JSShape *sh;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    int comma_state;\n    BOOL is_array;\n    uint32_t i;\n    \n    comma_state = 0;\n    is_array = FALSE;\n    if (p->class_id == JS_CLASS_ARRAY) {\n        is_array = TRUE;\n        js_printf(s, \"[ \");\n        /* XXX: print array like properties even if not fast array */\n        if (p->fast_array) {\n            uint32_t len, n, len1;\n            len = js_print_array_get_length(p);\n\n            len1 = min_uint32(p->u.array.count, s->options.max_item_count);\n            for(i = 0; i < len1; i++) {\n                js_print_comma(s, &comma_state);\n                js_print_value(s, p->u.array.u.values[i]);\n            }\n            if (len1 < p->u.array.count)\n                js_print_more_items(s, &comma_state, p->u.array.count - len1);\n            if (p->u.array.count < len) {\n                n = len - p->u.array.count;\n                js_print_comma(s, &comma_state);\n                js_printf(s, \"<%u empty item%s>\", n, n > 1 ? \"s\" : \"\");\n            }\n        }\n    } else if (p->class_id >= JS_CLASS_UINT8C_ARRAY && p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n        uint32_t size = 1 << typed_array_size_log2(p->class_id);\n        uint32_t len1;\n        int64_t v;\n\n        js_print_atom(s, rt->class_array[p->class_id].class_name);\n        js_printf(s, \"(%u) [ \", p->u.array.count);\n        \n        is_array = TRUE;\n        len1 = min_uint32(p->u.array.count, s->options.max_item_count);\n        for(i = 0; i < len1; i++) {\n            const uint8_t *ptr = p->u.array.u.uint8_ptr + i * size;\n            js_print_comma(s, &comma_state);\n            switch(p->class_id) {\n            case JS_CLASS_UINT8C_ARRAY:\n            case JS_CLASS_UINT8_ARRAY:\n                v = *ptr;\n                goto ta_int64;\n            case JS_CLASS_INT8_ARRAY:\n                v = *(int8_t *)ptr;\n                goto ta_int64;\n            case JS_CLASS_INT16_ARRAY:\n                v = *(int16_t *)ptr;\n                goto ta_int64;\n            case JS_CLASS_UINT16_ARRAY:\n                v = *(uint16_t *)ptr;\n                goto ta_int64;\n            case JS_CLASS_INT32_ARRAY:\n                v = *(int32_t *)ptr;\n                goto ta_int64;\n            case JS_CLASS_UINT32_ARRAY:\n                v = *(uint32_t *)ptr;\n                goto ta_int64;\n            case JS_CLASS_BIG_INT64_ARRAY:\n                v = *(int64_t *)ptr;\n            ta_int64:\n                js_printf(s, \"%\" PRId64, v);\n                break;\n            case JS_CLASS_BIG_UINT64_ARRAY:\n                js_printf(s, \"%\" PRIu64, *(uint64_t *)ptr);\n                break;\n            case JS_CLASS_FLOAT16_ARRAY:\n                js_print_float64(s, fromfp16(*(uint16_t *)ptr));\n                break;\n            case JS_CLASS_FLOAT32_ARRAY:\n                js_print_float64(s, *(float *)ptr);\n                break;\n            case JS_CLASS_FLOAT64_ARRAY:\n                js_print_float64(s, *(double *)ptr);\n                break;\n            }\n        }\n        if (len1 < p->u.array.count)\n            js_print_more_items(s, &comma_state, p->u.array.count - len1);\n    } else if (p->class_id == JS_CLASS_BYTECODE_FUNCTION ||\n               (rt->class_array[p->class_id].call != NULL &&\n                p->class_id != JS_CLASS_PROXY)) {\n        js_printf(s, \"[Function\");\n        /* XXX: allow dump without ctx */\n        if (!s->options.raw_dump && s->ctx) {\n            const char *func_name_str;\n            js_putc(s, ' ');\n            func_name_str = get_prop_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), JS_ATOM_name);\n            if (!func_name_str || func_name_str[0] == '\\0')\n                js_puts(s, \"(anonymous)\");\n            else\n                js_puts(s, func_name_str);\n            JS_FreeCString(s->ctx, func_name_str);\n        }\n        js_printf(s, \"]\");\n        comma_state = 2;\n    } else if (p->class_id == JS_CLASS_MAP || p->class_id == JS_CLASS_SET) {\n        JSMapState *ms = p->u.opaque;\n        struct list_head *el;\n        \n        if (!ms)\n            goto default_obj;\n        js_print_atom(s, rt->class_array[p->class_id].class_name);\n        js_printf(s, \"(%u) { \", ms->record_count);\n        i = 0;\n        list_for_each(el, &ms->records) {\n            JSMapRecord *mr = list_entry(el, JSMapRecord, link);\n            js_print_comma(s, &comma_state);\n            if (mr->empty)\n                continue;\n            js_print_value(s, mr->key);\n            if (p->class_id == JS_CLASS_MAP) {\n                js_printf(s, \" => \");\n                js_print_value(s, mr->value);\n            }\n            i++;\n            if (i >= s->options.max_item_count)\n                break;\n        }\n        if (i < ms->record_count)\n            js_print_more_items(s, &comma_state, ms->record_count - i);\n    } else if (p->class_id == JS_CLASS_REGEXP && s->ctx) {\n        js_print_regexp(s, p);\n        comma_state = 2;\n    } else if (p->class_id == JS_CLASS_DATE && s->ctx) {\n        /* get_date_string() has no side effect */\n        JSValue str = get_date_string(s->ctx, JS_MKPTR(JS_TAG_OBJECT, p), 0, NULL, 0x23); /* toISOString() */\n        if (JS_IsException(str))\n            goto default_obj;\n        js_print_raw_string(s, str);\n        JS_FreeValueRT(s->rt, str);\n        comma_state = 2;\n    } else if (p->class_id == JS_CLASS_ERROR && s->ctx) {\n        js_print_error(s, p);\n        comma_state = 2;\n    } else {\n        default_obj:\n        if (p->class_id != JS_CLASS_OBJECT) {\n            js_print_atom(s, rt->class_array[p->class_id].class_name);\n            js_printf(s, \" \");\n        }\n        js_printf(s, \"{ \");\n    }\n    \n    sh = p->shape; /* the shape can be NULL while freeing an object */\n    if (sh) {\n        uint32_t j;\n        \n        j = 0;\n        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {\n            if (prs->atom != JS_ATOM_NULL) {\n                if (!(prs->flags & JS_PROP_ENUMERABLE) &&\n                    !s->options.show_hidden) {\n                    continue;\n                }\n                if (j < s->options.max_item_count) {\n                    pr = &p->prop[i];\n                    js_print_comma(s, &comma_state);\n                    js_print_atom(s, prs->atom);\n                    js_printf(s, \": \");\n                    \n                    /* XXX: autoinit property */\n                    if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                        if (s->options.raw_dump) {\n                            js_printf(s, \"[Getter %p Setter %p]\",\n                                    pr->u.getset.getter, pr->u.getset.setter);\n                        } else {\n                            if (pr->u.getset.getter && pr->u.getset.setter) {\n                                js_printf(s, \"[Getter/Setter]\");\n                            } else if (pr->u.getset.setter) {\n                                js_printf(s, \"[Setter]\");\n                            } else {\n                                js_printf(s, \"[Getter]\");\n                            }\n                        }\n                    } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n                        if (s->options.raw_dump) {\n                            js_printf(s, \"[varref %p]\", (void *)pr->u.var_ref);\n                        } else {\n                            js_print_value(s, *pr->u.var_ref->pvalue);\n                        }\n                    } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {\n                        if (s->options.raw_dump) {\n                            js_printf(s, \"[autoinit %p %d %p]\",\n                                    (void *)js_autoinit_get_realm(pr),\n                                    js_autoinit_get_id(pr),\n                                    (void *)pr->u.init.opaque);\n                        } else {\n                            /* XXX: could autoinit but need to restart\n                               the iteration */\n                            js_printf(s, \"[autoinit]\");\n                        }\n                    } else {\n                        js_print_value(s, pr->u.value);\n                    }\n                }\n                j++;\n            }\n        }\n        if (j > s->options.max_item_count)\n            js_print_more_items(s, &comma_state, j - s->options.max_item_count);\n    }\n    if (s->options.raw_dump && js_class_has_bytecode(p->class_id)) {\n        JSFunctionBytecode *b = p->u.func.function_bytecode;\n        if (b->closure_var_count) {\n            JSVarRef **var_refs;\n            var_refs = p->u.func.var_refs;\n            \n            js_print_comma(s, &comma_state);\n            js_printf(s, \"[[Closure]]: [\");\n            for(i = 0; i < b->closure_var_count; i++) {\n                if (i != 0)\n                    js_printf(s, \", \");\n                js_print_value(s, var_refs[i]->value);\n            }\n            js_printf(s, \" ]\");\n        }\n        if (p->u.func.home_object) {\n            js_print_comma(s, &comma_state);\n            js_printf(s, \"[[HomeObject]]: \");\n            js_print_value(s, JS_MKPTR(JS_TAG_OBJECT, p->u.func.home_object));\n        }\n    }\n\n    if (!is_array) {\n        if (comma_state != 2) {\n            js_printf(s, \" }\");\n        }\n    } else {\n        js_printf(s, \" ]\");\n    }\n}\n\nstatic int js_print_stack_index(JSPrintValueState *s, JSObject *p)\n{\n    int i;\n    for(i = 0; i < s->level; i++)\n        if (s->print_stack[i] == p)\n            return i;\n    return -1;\n}\n\nstatic void js_print_value(JSPrintValueState *s, JSValueConst val)\n{\n    uint32_t tag = JS_VALUE_GET_NORM_TAG(val);\n    const char *str;\n\n    switch(tag) {\n    case JS_TAG_INT:\n        js_printf(s, \"%d\", JS_VALUE_GET_INT(val));\n        break;\n    case JS_TAG_BOOL:\n        if (JS_VALUE_GET_BOOL(val))\n            str = \"true\";\n        else\n            str = \"false\";\n        goto print_str;\n    case JS_TAG_NULL:\n        str = \"null\";\n        goto print_str;\n    case JS_TAG_EXCEPTION:\n        str = \"exception\";\n        goto print_str;\n    case JS_TAG_UNINITIALIZED:\n        str = \"uninitialized\";\n        goto print_str;\n    case JS_TAG_UNDEFINED:\n        str = \"undefined\";\n    print_str:\n        js_puts(s, str);\n        break;\n    case JS_TAG_FLOAT64:\n        js_print_float64(s, JS_VALUE_GET_FLOAT64(val));\n        break;\n    case JS_TAG_SHORT_BIG_INT:\n        js_printf(s, \"%\" PRId64 \"n\", (int64_t)JS_VALUE_GET_SHORT_BIG_INT(val));\n        break;\n    case JS_TAG_BIG_INT:\n        if (!s->options.raw_dump && s->ctx) {\n            JSValue str = js_bigint_to_string(s->ctx, val);\n            if (JS_IsException(str))\n                goto raw_bigint;\n            js_print_raw_string(s, str);\n            js_putc(s, 'n');\n            JS_FreeValueRT(s->rt, str);\n        } else {\n            JSBigInt *p;\n            int sgn, i;\n        raw_bigint:\n            p = JS_VALUE_GET_PTR(val);\n            /* In order to avoid allocations we just dump the limbs */\n            sgn = js_bigint_sign(p);\n            if (sgn)\n                js_printf(s, \"BigInt.asIntN(%d,\", p->len * JS_LIMB_BITS);\n            js_printf(s, \"0x\");\n            for(i = p->len - 1; i >= 0; i--) {\n                if (i != p->len - 1)\n                    js_putc(s, '_');\n#if JS_LIMB_BITS == 32\n                js_printf(s, \"%08x\", p->tab[i]);\n#else\n                js_printf(s, \"%016\" PRIx64, p->tab[i]);\n#endif\n            }\n            js_putc(s, 'n');\n            if (sgn)\n                js_putc(s, ')');\n        }\n        break;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        if (s->options.raw_dump && tag == JS_TAG_STRING_ROPE) {\n            JSStringRope *r = JS_VALUE_GET_STRING_ROPE(val);\n            js_printf(s, \"[rope len=%d depth=%d]\", r->len, r->depth);\n        } else {\n            js_print_string(s, val);\n        }\n        break;\n    case JS_TAG_FUNCTION_BYTECODE:\n        {\n            JSFunctionBytecode *b = JS_VALUE_GET_PTR(val);\n            js_puts(s, \"[bytecode \");\n            js_print_atom(s, b->func_name);\n            js_putc(s, ']');\n        }\n        break;\n    case JS_TAG_OBJECT:\n        {\n            JSObject *p = JS_VALUE_GET_OBJ(val);\n            int idx;\n            idx = js_print_stack_index(s, p);\n            if (idx >= 0) {\n                js_printf(s, \"[circular %d]\", idx);\n            } else if (s->level < s->options.max_depth) {\n                s->print_stack[s->level++] = p;\n                js_print_object(s, JS_VALUE_GET_OBJ(val));\n                s->level--;\n            } else {\n                JSAtom atom = s->rt->class_array[p->class_id].class_name;\n                js_putc(s, '[');\n                js_print_atom(s, atom);\n                if (s->options.raw_dump) {\n                    js_printf(s, \" %p\", (void *)p);\n                }\n                js_putc(s, ']');\n            }\n        }\n        break;\n    case JS_TAG_SYMBOL:\n        {\n            JSAtomStruct *p = JS_VALUE_GET_PTR(val);\n            js_puts(s, \"Symbol(\");\n            js_print_atom(s, js_get_atom_index(s->rt, p));\n            js_putc(s, ')');\n        }\n        break;\n    case JS_TAG_MODULE:\n        js_puts(s, \"[module]\");\n        break;\n    default:\n        js_printf(s, \"[unknown tag %d]\", tag);\n        break;\n    }\n}\n\nvoid JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options)\n{\n    memset(options, 0, sizeof(*options));\n    options->max_depth = 2;\n    options->max_string_length = 1000;\n    options->max_item_count = 100;\n}\n\nstatic void JS_PrintValueInternal(JSRuntime *rt, JSContext *ctx, \n                                  JSPrintValueWrite *write_func, void *write_opaque,\n                                  JSValueConst val, const JSPrintValueOptions *options)\n{\n    JSPrintValueState ss, *s = &ss;\n    if (options)\n        s->options = *options;\n    else\n        JS_PrintValueSetDefaultOptions(&s->options);\n    if (s->options.max_depth <= 0)\n        s->options.max_depth = JS_PRINT_MAX_DEPTH;\n    else\n        s->options.max_depth = min_int(s->options.max_depth, JS_PRINT_MAX_DEPTH);\n    if (s->options.max_string_length == 0)\n        s->options.max_string_length = UINT32_MAX;\n    if (s->options.max_item_count == 0)\n        s->options.max_item_count = UINT32_MAX;\n    s->rt = rt;\n    s->ctx = ctx;\n    s->write_func = write_func;\n    s->write_opaque = write_opaque;\n    s->level = 0;\n    js_print_value(s, val);\n}\n\nvoid JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque,\n                     JSValueConst val, const JSPrintValueOptions *options)\n{\n    JS_PrintValueInternal(rt, NULL, write_func, write_opaque, val, options);\n}\n\nvoid JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque,\n                   JSValueConst val, const JSPrintValueOptions *options)\n{\n    JS_PrintValueInternal(ctx->rt, ctx, write_func, write_opaque, val, options);\n}\n\nstatic void js_dump_value_write(void *opaque, const char *buf, size_t len)\n{\n    FILE *fo = opaque;\n    fwrite(buf, 1, len, fo);\n}\n\nstatic __maybe_unused void print_atom(JSContext *ctx, JSAtom atom)\n{\n    JSPrintValueState ss, *s = &ss;\n    memset(s, 0, sizeof(*s));\n    s->rt = ctx->rt;\n    s->ctx = ctx;\n    s->write_func = js_dump_value_write;\n    s->write_opaque = stdout;\n    js_print_atom(s, atom);\n}\n\nstatic __maybe_unused void JS_DumpAtom(JSContext *ctx, const char *str, JSAtom atom)\n{\n    printf(\"%s=\", str);\n    print_atom(ctx, atom);\n    printf(\"\\n\");\n}\n\nstatic __maybe_unused void JS_DumpValue(JSContext *ctx, const char *str, JSValueConst val)\n{\n    printf(\"%s=\", str);\n    JS_PrintValue(ctx, js_dump_value_write, stdout, val, NULL);\n    printf(\"\\n\");\n}\n\nstatic __maybe_unused void JS_DumpValueRT(JSRuntime *rt, const char *str, JSValueConst val)\n{\n    printf(\"%s=\", str);\n    JS_PrintValueRT(rt, js_dump_value_write, stdout, val, NULL);\n    printf(\"\\n\");\n}\n\nstatic __maybe_unused void JS_DumpObjectHeader(JSRuntime *rt)\n{\n    printf(\"%14s %4s %4s %14s %s\\n\",\n           \"ADDRESS\", \"REFS\", \"SHRF\", \"PROTO\", \"CONTENT\");\n}\n\n/* for debug only: dump an object without side effect */\nstatic __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p)\n{\n    JSShape *sh;\n    JSPrintValueOptions options;\n    \n    /* XXX: should encode atoms with special characters */\n    sh = p->shape; /* the shape can be NULL while freeing an object */\n    printf(\"%14p %4d \",\n           (void *)p,\n           p->header.ref_count);\n    if (sh) {\n        printf(\"%3d%c %14p \",\n               sh->header.ref_count,\n               \" *\"[sh->is_hashed],\n               (void *)sh->proto);\n    } else {\n        printf(\"%3s  %14s \", \"-\", \"-\");\n    }\n\n    JS_PrintValueSetDefaultOptions(&options);\n    options.max_depth = 1;\n    options.show_hidden = TRUE;\n    options.raw_dump = TRUE;\n    JS_PrintValueRT(rt, js_dump_value_write, stdout, JS_MKPTR(JS_TAG_OBJECT, p), &options);\n\n    printf(\"\\n\");\n}\n\nstatic __maybe_unused void JS_DumpGCObject(JSRuntime *rt, JSGCObjectHeader *p)\n{\n    if (p->gc_obj_type == JS_GC_OBJ_TYPE_JS_OBJECT) {\n        JS_DumpObject(rt, (JSObject *)p);\n    } else {\n        printf(\"%14p %4d \",\n               (void *)p,\n               p->ref_count);\n        switch(p->gc_obj_type) {\n        case JS_GC_OBJ_TYPE_FUNCTION_BYTECODE:\n            printf(\"[function bytecode]\");\n            break;\n        case JS_GC_OBJ_TYPE_SHAPE:\n            printf(\"[shape]\");\n            break;\n        case JS_GC_OBJ_TYPE_VAR_REF:\n            printf(\"[var_ref]\");\n            break;\n        case JS_GC_OBJ_TYPE_ASYNC_FUNCTION:\n            printf(\"[async_function]\");\n            break;\n        case JS_GC_OBJ_TYPE_JS_CONTEXT:\n            printf(\"[js_context]\");\n            break;\n        case JS_GC_OBJ_TYPE_MODULE:\n            printf(\"[module]\");\n            break;\n        default:\n            printf(\"[unknown %d]\", p->gc_obj_type);\n            break;\n        }\n        printf(\"\\n\");\n    }\n}\n\n/* return -1 if exception (proxy case) or TRUE/FALSE */\n// TODO: should take flags to make proxy resolution and exceptions optional\nint JS_IsArray(JSContext *ctx, JSValueConst val)\n{\n    if (js_resolve_proxy(ctx, &val, TRUE))\n        return -1;\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(val);\n        return p->class_id == JS_CLASS_ARRAY;\n    } else {\n        return FALSE;\n    }\n}\n\nstatic double js_pow(double a, double b)\n{\n    if (unlikely(!isfinite(b)) && fabs(a) == 1) {\n        /* not compatible with IEEE 754 */\n        return JS_FLOAT64_NAN;\n    } else {\n        return pow(a, b);\n    }\n}\n\nJSValue JS_NewBigInt64(JSContext *ctx, int64_t v)\n{\n#if JS_SHORT_BIG_INT_BITS == 64\n    return __JS_NewShortBigInt(ctx, v);\n#else\n    if (v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX) {\n        return __JS_NewShortBigInt(ctx, v);\n    } else {\n        JSBigInt *p;\n        p = js_bigint_new_si64(ctx, v);\n        if (!p)\n            return JS_EXCEPTION;\n        return JS_MKPTR(JS_TAG_BIG_INT, p);\n    }\n#endif\n}\n\nJSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)\n{\n    if (v <= JS_SHORT_BIG_INT_MAX) {\n        return __JS_NewShortBigInt(ctx, v);\n    } else {\n        JSBigInt *p;\n        p = js_bigint_new_ui64(ctx, v);\n        if (!p)\n            return JS_EXCEPTION;\n        return JS_MKPTR(JS_TAG_BIG_INT, p);\n    }\n}\n\n/* return NaN if bad bigint literal */\nstatic JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)\n{\n    const char *str, *p;\n    size_t len;\n    int flags;\n\n    str = JS_ToCStringLen(ctx, &len, val);\n    JS_FreeValue(ctx, val);\n    if (!str)\n        return JS_EXCEPTION;\n    p = str;\n    p += skip_spaces(p);\n    if ((p - str) == len) {\n        val = JS_NewBigInt64(ctx, 0);\n    } else {\n        flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;\n        val = js_atof(ctx, p, &p, 0, flags);\n        p += skip_spaces(p);\n        if (!JS_IsException(val)) {\n            if ((p - str) != len) {\n                JS_FreeValue(ctx, val);\n                val = JS_NAN;\n            }\n        }\n    }\n    JS_FreeCString(ctx, str);\n    return val;\n}\n\nstatic JSValue JS_StringToBigIntErr(JSContext *ctx, JSValue val)\n{\n    val = JS_StringToBigInt(ctx, val);\n    if (JS_VALUE_IS_NAN(val))\n        return JS_ThrowSyntaxError(ctx, \"invalid bigint literal\");\n    return val;\n}\n\n/* JS Numbers are not allowed */\nstatic JSValue JS_ToBigIntFree(JSContext *ctx, JSValue val)\n{\n    uint32_t tag;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        break;\n    case JS_TAG_INT:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n    case JS_TAG_FLOAT64:\n        goto fail;\n    case JS_TAG_BOOL:\n        val = __JS_NewShortBigInt(ctx, JS_VALUE_GET_INT(val));\n        break;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        val = JS_StringToBigIntErr(ctx, val);\n        if (JS_IsException(val))\n            return val;\n        goto redo;\n    case JS_TAG_OBJECT:\n        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);\n        if (JS_IsException(val))\n            return val;\n        goto redo;\n    default:\n    fail:\n        JS_FreeValue(ctx, val);\n        return JS_ThrowTypeError(ctx, \"cannot convert to bigint\");\n    }\n    return val;\n}\n\nstatic JSValue JS_ToBigInt(JSContext *ctx, JSValueConst val)\n{\n    return JS_ToBigIntFree(ctx, JS_DupValue(ctx, val));\n}\n\n/* XXX: merge with JS_ToInt64Free with a specific flag ? */\nstatic int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val)\n{\n    uint64_t res;\n\n    val = JS_ToBigIntFree(ctx, val);\n    if (JS_IsException(val)) {\n        *pres = 0;\n        return -1;\n    }\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {\n        res = JS_VALUE_GET_SHORT_BIG_INT(val);\n    } else {\n        JSBigInt *p = JS_VALUE_GET_PTR(val);\n        /* return the value mod 2^64 */\n        res = p->tab[0];\n#if JS_LIMB_BITS == 32\n        if (p->len >= 2)\n            res |= (uint64_t)p->tab[1] << 32;\n#endif\n        JS_FreeValue(ctx, val);\n    }\n    *pres = res;\n    return 0;\n}\n\nint JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)\n{\n    return JS_ToBigInt64Free(ctx, pres, JS_DupValue(ctx, val));\n}\n\nstatic no_inline __exception int js_unary_arith_slow(JSContext *ctx,\n                                                     JSValue *sp,\n                                                     OPCodeEnum op)\n{\n    JSValue op1;\n    int v;\n    uint32_t tag;\n    JSBigIntBuf buf1;\n    JSBigInt *p1;\n\n    op1 = sp[-1];\n    /* fast path for float64 */\n    if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))\n        goto handle_float64;\n    op1 = JS_ToNumericFree(ctx, op1);\n    if (JS_IsException(op1))\n        goto exception;\n    tag = JS_VALUE_GET_TAG(op1);\n    switch(tag) {\n    case JS_TAG_INT:\n        {\n            int64_t v64;\n            v64 = JS_VALUE_GET_INT(op1);\n            switch(op) {\n            case OP_inc:\n            case OP_dec:\n                v = 2 * (op - OP_dec) - 1;\n                v64 += v;\n                break;\n            case OP_plus:\n                break;\n            case OP_neg:\n                if (v64 == 0) {\n                    sp[-1] = __JS_NewFloat64(ctx, -0.0);\n                    return 0;\n                } else {\n                    v64 = -v64;\n                }\n                break;\n            default:\n                abort();\n            }\n            sp[-1] = JS_NewInt64(ctx, v64);\n        }\n        break;\n    case JS_TAG_SHORT_BIG_INT:\n        {\n            int64_t v;\n            v = JS_VALUE_GET_SHORT_BIG_INT(op1);\n            switch(op) {\n            case OP_plus:\n                JS_ThrowTypeError(ctx, \"bigint argument with unary +\");\n                goto exception;\n            case OP_inc:\n                if (v == JS_SHORT_BIG_INT_MAX)\n                    goto bigint_slow_case;\n                sp[-1] = __JS_NewShortBigInt(ctx, v + 1);\n                break;\n            case OP_dec:\n                if (v == JS_SHORT_BIG_INT_MIN)\n                    goto bigint_slow_case;\n                sp[-1] = __JS_NewShortBigInt(ctx, v - 1);\n                break;\n            case OP_neg:\n                v = JS_VALUE_GET_SHORT_BIG_INT(op1);\n                if (v == JS_SHORT_BIG_INT_MIN) {\n                bigint_slow_case:\n                    p1 = js_bigint_set_short(&buf1, op1);\n                    goto bigint_slow_case1;\n                }\n                sp[-1] = __JS_NewShortBigInt(ctx, -v);\n                break;\n            default:\n                abort();\n            }\n        }\n        break;\n    case JS_TAG_BIG_INT:\n        {\n            JSBigInt *r;\n            p1 = JS_VALUE_GET_PTR(op1);\n        bigint_slow_case1:\n            switch(op) {\n            case OP_plus:\n                JS_ThrowTypeError(ctx, \"bigint argument with unary +\");\n                JS_FreeValue(ctx, op1);\n                goto exception;\n            case OP_inc:\n            case OP_dec:\n                {\n                    JSBigIntBuf buf2;\n                    JSBigInt *p2;\n                    p2 = js_bigint_set_si(&buf2, 2 * (op - OP_dec) - 1);\n                    r = js_bigint_add(ctx, p1, p2, 0);\n                }\n                break;\n            case OP_neg:\n                r = js_bigint_neg(ctx, p1);\n                break;\n            case OP_not:\n                r = js_bigint_not(ctx, p1);\n                break;\n            default:\n                abort();\n            }\n            JS_FreeValue(ctx, op1);\n            if (!r)\n                goto exception;\n            sp[-1] = JS_CompactBigInt(ctx, r);\n        }\n        break;\n    default:\n    handle_float64:\n        {\n            double d;\n            d = JS_VALUE_GET_FLOAT64(op1);\n            switch(op) {\n            case OP_inc:\n            case OP_dec:\n                v = 2 * (op - OP_dec) - 1;\n                d += v;\n                break;\n            case OP_plus:\n                break;\n            case OP_neg:\n                d = -d;\n                break;\n            default:\n                abort();\n            }\n            sp[-1] = __JS_NewFloat64(ctx, d);\n        }\n        break;\n    }\n    return 0;\n exception:\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\nstatic __exception int js_post_inc_slow(JSContext *ctx,\n                                        JSValue *sp, OPCodeEnum op)\n{\n    JSValue op1;\n\n    /* XXX: allow custom operators */\n    op1 = sp[-1];\n    op1 = JS_ToNumericFree(ctx, op1);\n    if (JS_IsException(op1)) {\n        sp[-1] = JS_UNDEFINED;\n        return -1;\n    }\n    sp[-1] = op1;\n    sp[0] = JS_DupValue(ctx, op1);\n    return js_unary_arith_slow(ctx, sp + 1, op - OP_post_dec + OP_dec);\n}\n\nstatic no_inline int js_not_slow(JSContext *ctx, JSValue *sp)\n{\n    JSValue op1;\n\n    op1 = sp[-1];\n    op1 = JS_ToNumericFree(ctx, op1);\n    if (JS_IsException(op1))\n        goto exception;\n    if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT) {\n        sp[-1] = __JS_NewShortBigInt(ctx, ~JS_VALUE_GET_SHORT_BIG_INT(op1));\n    } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {\n        JSBigInt *r;\n        r = js_bigint_not(ctx, JS_VALUE_GET_PTR(op1));\n        JS_FreeValue(ctx, op1);\n        if (!r)\n            goto exception;\n        sp[-1] = JS_CompactBigInt(ctx, r);\n    } else {\n        int32_t v1;\n        if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))\n            goto exception;\n        sp[-1] = JS_NewInt32(ctx, ~v1);\n    }\n    return 0;\n exception:\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\nstatic no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *sp,\n                                                      OPCodeEnum op)\n{\n    JSValue op1, op2;\n    uint32_t tag1, tag2;\n    double d1, d2;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n    /* fast path for float operations */\n    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {\n        d1 = JS_VALUE_GET_FLOAT64(op1);\n        d2 = JS_VALUE_GET_FLOAT64(op2);\n        goto handle_float64;\n    }\n    /* fast path for short big int operations */\n    if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {\n        js_slimb_t v1, v2;\n        js_sdlimb_t v;\n        v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);\n        v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);\n        switch(op) {\n        case OP_sub:\n            v = (js_sdlimb_t)v1 - (js_sdlimb_t)v2;\n            break;\n        case OP_mul:\n            v = (js_sdlimb_t)v1 * (js_sdlimb_t)v2;\n            break;\n        case OP_div:\n            if (v2 == 0 ||\n                ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&\n                 v2 == -1)) {\n                goto slow_big_int;\n            }\n            sp[-2] = __JS_NewShortBigInt(ctx, v1 / v2);\n            return 0;\n        case OP_mod:\n            if (v2 == 0 ||\n                ((js_limb_t)v1 == (js_limb_t)1 << (JS_LIMB_BITS - 1) &&\n                 v2 == -1)) {\n                goto slow_big_int;\n            }\n            sp[-2] = __JS_NewShortBigInt(ctx, v1 % v2);\n            return 0;\n        case OP_pow:\n            goto slow_big_int;\n        default:\n            abort();\n        }\n        if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {\n            sp[-2] = __JS_NewShortBigInt(ctx, v);\n        } else {\n            JSBigInt *r = js_bigint_new_di(ctx, v);\n            if (!r)\n                goto exception;\n            sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);\n        }\n        return 0;\n    }\n    op1 = JS_ToNumericFree(ctx, op1);\n    if (JS_IsException(op1)) {\n        JS_FreeValue(ctx, op2);\n        goto exception;\n    }\n    op2 = JS_ToNumericFree(ctx, op2);\n    if (JS_IsException(op2)) {\n        JS_FreeValue(ctx, op1);\n        goto exception;\n    }\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n\n    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {\n        int32_t v1, v2;\n        int64_t v;\n        v1 = JS_VALUE_GET_INT(op1);\n        v2 = JS_VALUE_GET_INT(op2);\n        switch(op) {\n        case OP_sub:\n            v = (int64_t)v1 - (int64_t)v2;\n            break;\n        case OP_mul:\n            v = (int64_t)v1 * (int64_t)v2;\n            if (v == 0 && (v1 | v2) < 0) {\n                sp[-2] = __JS_NewFloat64(ctx, -0.0);\n                return 0;\n            }\n            break;\n        case OP_div:\n            sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);\n            return 0;\n        case OP_mod:\n            if (v1 < 0 || v2 <= 0) {\n                sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));\n                return 0;\n            } else {\n                v = (int64_t)v1 % (int64_t)v2;\n            }\n            break;\n        case OP_pow:\n            sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));\n            return 0;\n        default:\n            abort();\n        }\n        sp[-2] = JS_NewInt64(ctx, v);\n    } else if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_BIG_INT) &&\n               (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_BIG_INT)) {\n        JSBigInt *p1, *p2, *r;\n        JSBigIntBuf buf1, buf2;\n    slow_big_int:\n        /* bigint result */\n        if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)\n            p1 = js_bigint_set_short(&buf1, op1);\n        else\n            p1 = JS_VALUE_GET_PTR(op1);\n        if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)\n            p2 = js_bigint_set_short(&buf2, op2);\n        else\n            p2 = JS_VALUE_GET_PTR(op2);\n        switch(op) {\n        case OP_add:\n            r = js_bigint_add(ctx, p1, p2, 0);\n            break;\n        case OP_sub:\n            r = js_bigint_add(ctx, p1, p2, 1);\n            break;\n        case OP_mul:\n            r = js_bigint_mul(ctx, p1, p2);\n            break;\n        case OP_div:\n            r = js_bigint_divrem(ctx, p1, p2, FALSE);\n            break;\n        case OP_mod:\n            r = js_bigint_divrem(ctx, p1, p2, TRUE);\n            break;\n        case OP_pow:\n            r = js_bigint_pow(ctx, p1, p2);\n            break;\n        default:\n            abort();\n        }\n        JS_FreeValue(ctx, op1);\n        JS_FreeValue(ctx, op2);\n        if (!r)\n            goto exception;\n        sp[-2] = JS_CompactBigInt(ctx, r);\n    } else {\n        double dr;\n        /* float64 result */\n        if (JS_ToFloat64Free(ctx, &d1, op1)) {\n            JS_FreeValue(ctx, op2);\n            goto exception;\n        }\n        if (JS_ToFloat64Free(ctx, &d2, op2))\n            goto exception;\n    handle_float64:\n        switch(op) {\n        case OP_sub:\n            dr = d1 - d2;\n            break;\n        case OP_mul:\n            dr = d1 * d2;\n            break;\n        case OP_div:\n            dr = d1 / d2;\n            break;\n        case OP_mod:\n            dr = fmod(d1, d2);\n            break;\n        case OP_pow:\n            dr = js_pow(d1, d2);\n            break;\n        default:\n            abort();\n        }\n        sp[-2] = __JS_NewFloat64(ctx, dr);\n    }\n    return 0;\n exception:\n    sp[-2] = JS_UNDEFINED;\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\nstatic inline BOOL tag_is_string(uint32_t tag)\n{\n    return tag == JS_TAG_STRING || tag == JS_TAG_STRING_ROPE;\n}\n\nstatic no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)\n{\n    JSValue op1, op2;\n    uint32_t tag1, tag2;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n    /* fast path for float64 */\n    if (tag1 == JS_TAG_FLOAT64 && tag2 == JS_TAG_FLOAT64) {\n        double d1, d2;\n        d1 = JS_VALUE_GET_FLOAT64(op1);\n        d2 = JS_VALUE_GET_FLOAT64(op2);\n        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);\n        return 0;\n    }\n    /* fast path for short bigint */\n    if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {\n        js_slimb_t v1, v2;\n        js_sdlimb_t v;\n        v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);\n        v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);\n        v = (js_sdlimb_t)v1 + (js_sdlimb_t)v2;\n        if (likely(v >= JS_SHORT_BIG_INT_MIN && v <= JS_SHORT_BIG_INT_MAX)) {\n            sp[-2] = __JS_NewShortBigInt(ctx, v);\n        } else {\n            JSBigInt *r = js_bigint_new_di(ctx, v);\n            if (!r)\n                goto exception;\n            sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);\n        }\n        return 0;\n    }\n    \n    if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {\n        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);\n        if (JS_IsException(op1)) {\n            JS_FreeValue(ctx, op2);\n            goto exception;\n        }\n\n        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);\n        if (JS_IsException(op2)) {\n            JS_FreeValue(ctx, op1);\n            goto exception;\n        }\n        tag1 = JS_VALUE_GET_NORM_TAG(op1);\n        tag2 = JS_VALUE_GET_NORM_TAG(op2);\n    }\n\n    if (tag_is_string(tag1) || tag_is_string(tag2)) {\n        sp[-2] = JS_ConcatString(ctx, op1, op2);\n        if (JS_IsException(sp[-2]))\n            goto exception;\n        return 0;\n    }\n\n    op1 = JS_ToNumericFree(ctx, op1);\n    if (JS_IsException(op1)) {\n        JS_FreeValue(ctx, op2);\n        goto exception;\n    }\n    op2 = JS_ToNumericFree(ctx, op2);\n    if (JS_IsException(op2)) {\n        JS_FreeValue(ctx, op1);\n        goto exception;\n    }\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n\n    if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {\n        int32_t v1, v2;\n        int64_t v;\n        v1 = JS_VALUE_GET_INT(op1);\n        v2 = JS_VALUE_GET_INT(op2);\n        v = (int64_t)v1 + (int64_t)v2;\n        sp[-2] = JS_NewInt64(ctx, v);\n    } else if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&\n               (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {\n        JSBigInt *p1, *p2, *r;\n        JSBigIntBuf buf1, buf2;\n        /* bigint result */\n        if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)\n            p1 = js_bigint_set_short(&buf1, op1);\n        else\n            p1 = JS_VALUE_GET_PTR(op1);\n        if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)\n            p2 = js_bigint_set_short(&buf2, op2);\n        else\n            p2 = JS_VALUE_GET_PTR(op2);\n        r = js_bigint_add(ctx, p1, p2, 0);\n        JS_FreeValue(ctx, op1);\n        JS_FreeValue(ctx, op2);\n        if (!r)\n            goto exception;\n        sp[-2] = JS_CompactBigInt(ctx, r);\n    } else {\n        double d1, d2;\n        /* float64 result */\n        if (JS_ToFloat64Free(ctx, &d1, op1)) {\n            JS_FreeValue(ctx, op2);\n            goto exception;\n        }\n        if (JS_ToFloat64Free(ctx, &d2, op2))\n            goto exception;\n        sp[-2] = __JS_NewFloat64(ctx, d1 + d2);\n    }\n    return 0;\n exception:\n    sp[-2] = JS_UNDEFINED;\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\nstatic no_inline __exception int js_binary_logic_slow(JSContext *ctx,\n                                                      JSValue *sp,\n                                                      OPCodeEnum op)\n{\n    JSValue op1, op2;\n    uint32_t tag1, tag2;\n    uint32_t v1, v2, r;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n\n    if (tag1 == JS_TAG_SHORT_BIG_INT && tag2 == JS_TAG_SHORT_BIG_INT) {\n        js_slimb_t v1, v2, v;\n        js_sdlimb_t vd;\n        v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);\n        v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);\n        /* bigint fast path */\n        switch(op) {\n        case OP_and:\n            v = v1 & v2;\n            break;\n        case OP_or:\n            v = v1 | v2;\n            break;\n        case OP_xor:\n            v = v1 ^ v2;\n            break;\n        case OP_sar:\n            if (v2 > (JS_LIMB_BITS - 1)) {\n                goto slow_big_int;\n            } else if (v2 < 0) {\n                if (v2 < -(JS_LIMB_BITS - 1))\n                    goto slow_big_int;\n                v2 = -v2;\n                goto bigint_shl;\n            }\n        bigint_sar:\n            v = v1 >> v2;\n            break;\n        case OP_shl:\n            if (v2 > (JS_LIMB_BITS - 1)) {\n                goto slow_big_int;\n            } else if (v2 < 0) {\n                if (v2 < -(JS_LIMB_BITS - 1))\n                    goto slow_big_int;\n                v2 = -v2;\n                goto bigint_sar;\n            }\n        bigint_shl:\n            vd = (js_dlimb_t)v1 << v2;\n            if (likely(vd >= JS_SHORT_BIG_INT_MIN &&\n                       vd <= JS_SHORT_BIG_INT_MAX)) {\n                v = vd;\n            } else {\n                JSBigInt *r = js_bigint_new_di(ctx, vd);\n                if (!r)\n                    goto exception;\n                sp[-2] = JS_MKPTR(JS_TAG_BIG_INT, r);\n                return 0;\n            }\n            break;\n        default:\n            abort();\n        }\n        sp[-2] = __JS_NewShortBigInt(ctx, v);\n        return 0;\n    }\n    op1 = JS_ToNumericFree(ctx, op1);\n    if (JS_IsException(op1)) {\n        JS_FreeValue(ctx, op2);\n        goto exception;\n    }\n    op2 = JS_ToNumericFree(ctx, op2);\n    if (JS_IsException(op2)) {\n        JS_FreeValue(ctx, op1);\n        goto exception;\n    }\n\n    tag1 = JS_VALUE_GET_TAG(op1);\n    tag2 = JS_VALUE_GET_TAG(op2);\n    if ((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&\n        (tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT)) {\n        JSBigInt *p1, *p2, *r;\n        JSBigIntBuf buf1, buf2;\n    slow_big_int:\n        if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)\n            p1 = js_bigint_set_short(&buf1, op1);\n        else\n            p1 = JS_VALUE_GET_PTR(op1);\n        if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)\n            p2 = js_bigint_set_short(&buf2, op2);\n        else\n            p2 = JS_VALUE_GET_PTR(op2);\n        switch(op) {\n        case OP_and:\n        case OP_or:\n        case OP_xor:\n            r = js_bigint_logic(ctx, p1, p2, op);\n            break;\n        case OP_shl:\n        case OP_sar:\n            {\n                js_slimb_t shift;\n                shift = js_bigint_get_si_sat(p2);\n                if (shift > INT32_MAX)\n                    shift = INT32_MAX;\n                else if (shift < -INT32_MAX)\n                    shift = -INT32_MAX;\n                if (op == OP_sar)\n                    shift = -shift;\n                if (shift >= 0)\n                    r = js_bigint_shl(ctx, p1, shift);\n                else\n                    r = js_bigint_shr(ctx, p1, -shift);\n            }\n            break;\n        default:\n            abort();\n        }\n        JS_FreeValue(ctx, op1);\n        JS_FreeValue(ctx, op2);\n        if (!r)\n            goto exception;\n        sp[-2] = JS_CompactBigInt(ctx, r);\n    } else {\n        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {\n            JS_FreeValue(ctx, op2);\n            goto exception;\n        }\n        if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))\n            goto exception;\n        switch(op) {\n        case OP_shl:\n            r = v1 << (v2 & 0x1f);\n            break;\n        case OP_sar:\n            r = (int)v1 >> (v2 & 0x1f);\n            break;\n        case OP_and:\n            r = v1 & v2;\n            break;\n        case OP_or:\n            r = v1 | v2;\n            break;\n        case OP_xor:\n            r = v1 ^ v2;\n            break;\n        default:\n            abort();\n        }\n        sp[-2] = JS_NewInt32(ctx, r);\n    }\n    return 0;\n exception:\n    sp[-2] = JS_UNDEFINED;\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\n/* op1 must be a bigint or int. */\nstatic JSBigInt *JS_ToBigIntBuf(JSContext *ctx, JSBigIntBuf *buf1,\n                                JSValue op1)\n{\n    JSBigInt *p1;\n    \n    switch(JS_VALUE_GET_TAG(op1)) {\n    case JS_TAG_INT:\n        p1 = js_bigint_set_si(buf1, JS_VALUE_GET_INT(op1));\n        break;\n    case JS_TAG_SHORT_BIG_INT:\n        p1 = js_bigint_set_short(buf1, op1);\n        break;\n    case JS_TAG_BIG_INT:\n        p1 = JS_VALUE_GET_PTR(op1);\n        break;\n    default:\n        abort();\n    }\n    return p1;\n}\n\n/* op1 and op2 must be numeric types and at least one must be a\n   bigint. No exception is generated. */\nstatic int js_compare_bigint(JSContext *ctx, OPCodeEnum op,\n                             JSValue op1, JSValue op2)\n{\n    int res, val, tag1, tag2;\n    JSBigIntBuf buf1, buf2;\n    JSBigInt *p1, *p2;\n    \n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n    if ((tag1 == JS_TAG_SHORT_BIG_INT || tag1 == JS_TAG_INT) &&\n        (tag2 == JS_TAG_SHORT_BIG_INT || tag2 == JS_TAG_INT)) {\n        /* fast path */\n        js_slimb_t v1, v2;\n        if (tag1 == JS_TAG_INT)\n            v1 = JS_VALUE_GET_INT(op1);\n        else\n            v1 = JS_VALUE_GET_SHORT_BIG_INT(op1);\n        if (tag2 == JS_TAG_INT)\n            v2 = JS_VALUE_GET_INT(op2);\n        else\n            v2 = JS_VALUE_GET_SHORT_BIG_INT(op2);\n        val = (v1 > v2) - (v1 < v2);\n    } else {\n        if (tag1 == JS_TAG_FLOAT64) {\n            p2 = JS_ToBigIntBuf(ctx, &buf2, op2);\n            val = js_bigint_float64_cmp(ctx, p2, JS_VALUE_GET_FLOAT64(op1));\n            if (val == 2)\n                goto unordered;\n            val = -val;\n        } else if (tag2 == JS_TAG_FLOAT64) {\n            p1 = JS_ToBigIntBuf(ctx, &buf1, op1);\n            val = js_bigint_float64_cmp(ctx, p1, JS_VALUE_GET_FLOAT64(op2));\n            if (val == 2) {\n            unordered:\n                JS_FreeValue(ctx, op1);\n                JS_FreeValue(ctx, op2);\n                return FALSE;\n            }\n        } else {\n            p1 = JS_ToBigIntBuf(ctx, &buf1, op1);\n            p2 = JS_ToBigIntBuf(ctx, &buf2, op2);\n            val = js_bigint_cmp(ctx, p1, p2);\n        }\n        JS_FreeValue(ctx, op1);\n        JS_FreeValue(ctx, op2);\n    }\n\n    switch(op) {\n    case OP_lt:\n        res = val < 0;\n        break;\n    case OP_lte:\n        res = val <= 0;\n        break;\n    case OP_gt:\n        res = val > 0;\n        break;\n    case OP_gte:\n        res = val >= 0;\n        break;\n    case OP_eq:\n        res = val == 0;\n        break;\n    default:\n        abort();\n    }\n    return res;\n}\n\nstatic no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,\n                                        OPCodeEnum op)\n{\n    JSValue op1, op2;\n    int res;\n    uint32_t tag1, tag2;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n    op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);\n    if (JS_IsException(op1)) {\n        JS_FreeValue(ctx, op2);\n        goto exception;\n    }\n    op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);\n    if (JS_IsException(op2)) {\n        JS_FreeValue(ctx, op1);\n        goto exception;\n    }\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n\n    if (tag_is_string(tag1) && tag_is_string(tag2)) {\n        if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {\n            res = js_string_compare(ctx, JS_VALUE_GET_STRING(op1),\n                                    JS_VALUE_GET_STRING(op2));\n        } else {\n            res = js_string_rope_compare(ctx, op1, op2, FALSE);\n        }\n        switch(op) {\n        case OP_lt:\n            res = (res < 0);\n            break;\n        case OP_lte:\n            res = (res <= 0);\n            break;\n        case OP_gt:\n            res = (res > 0);\n            break;\n        default:\n        case OP_gte:\n            res = (res >= 0);\n            break;\n        }\n        JS_FreeValue(ctx, op1);\n        JS_FreeValue(ctx, op2);\n    } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) &&\n               (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) {\n        /* fast path for float64/int */\n        goto float64_compare;\n    } else {\n        if ((((tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT) &&\n              tag_is_string(tag2)) ||\n             ((tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) &&\n              tag_is_string(tag1)))) {\n            if (tag_is_string(tag1)) {\n                op1 = JS_StringToBigInt(ctx, op1);\n                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&\n                    JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)\n                    goto invalid_bigint_string;\n            }\n            if (tag_is_string(tag2)) {\n                op2 = JS_StringToBigInt(ctx, op2);\n                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&\n                    JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT) {\n                invalid_bigint_string:\n                    JS_FreeValue(ctx, op1);\n                    JS_FreeValue(ctx, op2);\n                    res = FALSE;\n                    goto done;\n                }\n            }\n        } else {\n            op1 = JS_ToNumericFree(ctx, op1);\n            if (JS_IsException(op1)) {\n                JS_FreeValue(ctx, op2);\n                goto exception;\n            }\n            op2 = JS_ToNumericFree(ctx, op2);\n            if (JS_IsException(op2)) {\n                JS_FreeValue(ctx, op1);\n                goto exception;\n            }\n        }\n\n        tag1 = JS_VALUE_GET_NORM_TAG(op1);\n        tag2 = JS_VALUE_GET_NORM_TAG(op2);\n\n        if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||\n            tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {\n            res = js_compare_bigint(ctx, op, op1, op2);\n        } else {\n            double d1, d2;\n\n        float64_compare:\n            /* can use floating point comparison */\n            if (tag1 == JS_TAG_FLOAT64) {\n                d1 = JS_VALUE_GET_FLOAT64(op1);\n            } else {\n                d1 = JS_VALUE_GET_INT(op1);\n            }\n            if (tag2 == JS_TAG_FLOAT64) {\n                d2 = JS_VALUE_GET_FLOAT64(op2);\n            } else {\n                d2 = JS_VALUE_GET_INT(op2);\n            }\n            switch(op) {\n            case OP_lt:\n                res = (d1 < d2); /* if NaN return false */\n                break;\n            case OP_lte:\n                res = (d1 <= d2); /* if NaN return false */\n                break;\n            case OP_gt:\n                res = (d1 > d2); /* if NaN return false */\n                break;\n            default:\n            case OP_gte:\n                res = (d1 >= d2); /* if NaN return false */\n                break;\n            }\n        }\n    }\n done:\n    sp[-2] = JS_NewBool(ctx, res);\n    return 0;\n exception:\n    sp[-2] = JS_UNDEFINED;\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\nstatic BOOL tag_is_number(uint32_t tag)\n{\n    return (tag == JS_TAG_INT || \n            tag == JS_TAG_FLOAT64 ||\n            tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT);\n}\n\nstatic no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,\n                                            BOOL is_neq)\n{\n    JSValue op1, op2;\n    int res;\n    uint32_t tag1, tag2;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n redo:\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n    if (tag_is_number(tag1) && tag_is_number(tag2)) {\n        if (tag1 == JS_TAG_INT && tag2 == JS_TAG_INT) {\n            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);\n        } else if ((tag1 == JS_TAG_FLOAT64 &&\n                    (tag2 == JS_TAG_INT || tag2 == JS_TAG_FLOAT64)) ||\n                   (tag2 == JS_TAG_FLOAT64 &&\n                    (tag1 == JS_TAG_INT || tag1 == JS_TAG_FLOAT64))) {\n            double d1, d2;\n            if (tag1 == JS_TAG_FLOAT64) {\n                d1 = JS_VALUE_GET_FLOAT64(op1);\n            } else {\n                d1 = JS_VALUE_GET_INT(op1);\n            }\n            if (tag2 == JS_TAG_FLOAT64) {\n                d2 = JS_VALUE_GET_FLOAT64(op2);\n            } else {\n                d2 = JS_VALUE_GET_INT(op2);\n            }\n            res = (d1 == d2);\n        } else {\n            res = js_compare_bigint(ctx, OP_eq, op1, op2);\n        }\n    } else if (tag1 == tag2) {\n        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);\n    } else if ((tag1 == JS_TAG_NULL && tag2 == JS_TAG_UNDEFINED) ||\n               (tag2 == JS_TAG_NULL && tag1 == JS_TAG_UNDEFINED)) {\n        res = TRUE;\n    } else if (tag_is_string(tag1) && tag_is_string(tag2)) {\n        /* needed when comparing strings and ropes */\n        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);\n    } else if ((tag_is_string(tag1) && tag_is_number(tag2)) ||\n               (tag_is_string(tag2) && tag_is_number(tag1))) {\n\n        if (tag1 == JS_TAG_BIG_INT || tag1 == JS_TAG_SHORT_BIG_INT ||\n            tag2 == JS_TAG_BIG_INT || tag2 == JS_TAG_SHORT_BIG_INT) {\n            if (tag_is_string(tag1)) {\n                op1 = JS_StringToBigInt(ctx, op1);\n                if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT &&\n                    JS_VALUE_GET_TAG(op1) != JS_TAG_SHORT_BIG_INT)\n                    goto invalid_bigint_string;\n            }\n            if (tag_is_string(tag2)) {\n                op2 = JS_StringToBigInt(ctx, op2);\n                if (JS_VALUE_GET_TAG(op2) != JS_TAG_BIG_INT &&\n                    JS_VALUE_GET_TAG(op2) != JS_TAG_SHORT_BIG_INT ) {\n                invalid_bigint_string:\n                    JS_FreeValue(ctx, op1);\n                    JS_FreeValue(ctx, op2);\n                    res = FALSE;\n                    goto done;\n                }\n            }\n        } else {\n            op1 = JS_ToNumericFree(ctx, op1);\n            if (JS_IsException(op1)) {\n                JS_FreeValue(ctx, op2);\n                goto exception;\n            }\n            op2 = JS_ToNumericFree(ctx, op2);\n            if (JS_IsException(op2)) {\n                JS_FreeValue(ctx, op1);\n                goto exception;\n            }\n        }\n        res = js_strict_eq2(ctx, op1, op2, JS_EQ_STRICT);\n    } else if (tag1 == JS_TAG_BOOL) {\n        op1 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));\n        goto redo;\n    } else if (tag2 == JS_TAG_BOOL) {\n        op2 = JS_NewInt32(ctx, JS_VALUE_GET_INT(op2));\n        goto redo;\n    } else if ((tag1 == JS_TAG_OBJECT &&\n                (tag_is_number(tag2) || tag_is_string(tag2) || tag2 == JS_TAG_SYMBOL)) ||\n               (tag2 == JS_TAG_OBJECT &&\n                (tag_is_number(tag1) || tag_is_string(tag1) || tag1 == JS_TAG_SYMBOL))) {\n        op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);\n        if (JS_IsException(op1)) {\n            JS_FreeValue(ctx, op2);\n            goto exception;\n        }\n        op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);\n        if (JS_IsException(op2)) {\n            JS_FreeValue(ctx, op1);\n            goto exception;\n        }\n        goto redo;\n    } else {\n        /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */\n        if ((JS_IsHTMLDDA(ctx, op1) &&\n             (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) ||\n            (JS_IsHTMLDDA(ctx, op2) &&\n             (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) {\n            res = TRUE;\n        } else {\n            res = FALSE;\n        }\n        JS_FreeValue(ctx, op1);\n        JS_FreeValue(ctx, op2);\n    }\n done:\n    sp[-2] = JS_NewBool(ctx, res ^ is_neq);\n    return 0;\n exception:\n    sp[-2] = JS_UNDEFINED;\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\nstatic no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)\n{\n    JSValue op1, op2;\n    uint32_t v1, v2, r;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n    op1 = JS_ToNumericFree(ctx, op1);\n    if (JS_IsException(op1)) {\n        JS_FreeValue(ctx, op2);\n        goto exception;\n    }\n    op2 = JS_ToNumericFree(ctx, op2);\n    if (JS_IsException(op2)) {\n        JS_FreeValue(ctx, op1);\n        goto exception;\n    }\n    if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||\n        JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT ||\n        JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT ||\n        JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT) {\n        JS_ThrowTypeError(ctx, \"bigint operands are forbidden for >>>\");\n        JS_FreeValue(ctx, op1);\n        JS_FreeValue(ctx, op2);\n        goto exception;\n    }\n    /* cannot give an exception */\n    JS_ToUint32Free(ctx, &v1, op1);\n    JS_ToUint32Free(ctx, &v2, op2);\n    r = v1 >> (v2 & 0x1f);\n    sp[-2] = JS_NewUint32(ctx, r);\n    return 0;\n exception:\n    sp[-2] = JS_UNDEFINED;\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\n/* XXX: Should take JSValueConst arguments */\nstatic BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,\n                          JSStrictEqModeEnum eq_mode)\n{\n    BOOL res;\n    int tag1, tag2;\n    double d1, d2;\n\n    tag1 = JS_VALUE_GET_NORM_TAG(op1);\n    tag2 = JS_VALUE_GET_NORM_TAG(op2);\n    switch(tag1) {\n    case JS_TAG_BOOL:\n        if (tag1 != tag2) {\n            res = FALSE;\n        } else {\n            res = JS_VALUE_GET_INT(op1) == JS_VALUE_GET_INT(op2);\n            goto done_no_free;\n        }\n        break;\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        res = (tag1 == tag2);\n        break;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        {\n            if (!tag_is_string(tag2)) {\n                res = FALSE;\n            } else if (tag1 == JS_TAG_STRING && tag2 == JS_TAG_STRING) {\n                res = js_string_eq(ctx, JS_VALUE_GET_STRING(op1),\n                                   JS_VALUE_GET_STRING(op2));\n            } else {\n                res = (js_string_rope_compare(ctx, op1, op2, TRUE) == 0);\n            }\n        }\n        break;\n    case JS_TAG_SYMBOL:\n        {\n            JSAtomStruct *p1, *p2;\n            if (tag1 != tag2) {\n                res = FALSE;\n            } else {\n                p1 = JS_VALUE_GET_PTR(op1);\n                p2 = JS_VALUE_GET_PTR(op2);\n                res = (p1 == p2);\n            }\n        }\n        break;\n    case JS_TAG_OBJECT:\n        if (tag1 != tag2)\n            res = FALSE;\n        else\n            res = JS_VALUE_GET_OBJ(op1) == JS_VALUE_GET_OBJ(op2);\n        break;\n    case JS_TAG_INT:\n        d1 = JS_VALUE_GET_INT(op1);\n        if (tag2 == JS_TAG_INT) {\n            d2 = JS_VALUE_GET_INT(op2);\n            goto number_test;\n        } else if (tag2 == JS_TAG_FLOAT64) {\n            d2 = JS_VALUE_GET_FLOAT64(op2);\n            goto number_test;\n        } else {\n            res = FALSE;\n        }\n        break;\n    case JS_TAG_FLOAT64:\n        d1 = JS_VALUE_GET_FLOAT64(op1);\n        if (tag2 == JS_TAG_FLOAT64) {\n            d2 = JS_VALUE_GET_FLOAT64(op2);\n        } else if (tag2 == JS_TAG_INT) {\n            d2 = JS_VALUE_GET_INT(op2);\n        } else {\n            res = FALSE;\n            break;\n        }\n    number_test:\n        if (unlikely(eq_mode >= JS_EQ_SAME_VALUE)) {\n            JSFloat64Union u1, u2;\n            /* NaN is not always normalized, so this test is necessary */\n            if (isnan(d1) || isnan(d2)) {\n                res = isnan(d1) == isnan(d2);\n            } else if (eq_mode == JS_EQ_SAME_VALUE_ZERO) {\n                res = (d1 == d2); /* +0 == -0 */\n            } else {\n                u1.d = d1;\n                u2.d = d2;\n                res = (u1.u64 == u2.u64); /* +0 != -0 */\n            }\n        } else {\n            res = (d1 == d2); /* if NaN return false and +0 == -0 */\n        }\n        goto done_no_free;\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        {\n            JSBigIntBuf buf1, buf2;\n            JSBigInt *p1, *p2;\n\n            if (tag2 != JS_TAG_SHORT_BIG_INT &&\n                tag2 != JS_TAG_BIG_INT) {\n                res = FALSE;\n                break;\n            }\n            \n            if (JS_VALUE_GET_TAG(op1) == JS_TAG_SHORT_BIG_INT)\n                p1 = js_bigint_set_short(&buf1, op1);\n            else\n                p1 = JS_VALUE_GET_PTR(op1);\n            if (JS_VALUE_GET_TAG(op2) == JS_TAG_SHORT_BIG_INT)\n                p2 = js_bigint_set_short(&buf2, op2);\n            else\n                p2 = JS_VALUE_GET_PTR(op2);\n            res = (js_bigint_cmp(ctx, p1, p2) == 0);\n        }\n        break;\n    default:\n        res = FALSE;\n        break;\n    }\n    JS_FreeValue(ctx, op1);\n    JS_FreeValue(ctx, op2);\n done_no_free:\n    return res;\n}\n\nstatic BOOL js_strict_eq(JSContext *ctx, JSValueConst op1, JSValueConst op2)\n{\n    return js_strict_eq2(ctx,\n                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),\n                         JS_EQ_STRICT);\n}\n\nBOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2)\n{\n    return js_strict_eq(ctx, op1, op2);\n}\n\nstatic BOOL js_same_value(JSContext *ctx, JSValueConst op1, JSValueConst op2)\n{\n    return js_strict_eq2(ctx,\n                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),\n                         JS_EQ_SAME_VALUE);\n}\n\nBOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2)\n{\n    return js_same_value(ctx, op1, op2);\n}\n\nstatic BOOL js_same_value_zero(JSContext *ctx, JSValueConst op1, JSValueConst op2)\n{\n    return js_strict_eq2(ctx,\n                         JS_DupValue(ctx, op1), JS_DupValue(ctx, op2),\n                         JS_EQ_SAME_VALUE_ZERO);\n}\n\nBOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2)\n{\n    return js_same_value_zero(ctx, op1, op2);\n}\n\nstatic no_inline int js_strict_eq_slow(JSContext *ctx, JSValue *sp,\n                                       BOOL is_neq)\n{\n    BOOL res;\n    res = js_strict_eq2(ctx, sp[-2], sp[-1], JS_EQ_STRICT);\n    sp[-2] = JS_NewBool(ctx, res ^ is_neq);\n    return 0;\n}\n\nstatic __exception int js_operator_in(JSContext *ctx, JSValue *sp)\n{\n    JSValue op1, op2;\n    JSAtom atom;\n    int ret;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n\n    if (JS_VALUE_GET_TAG(op2) != JS_TAG_OBJECT) {\n        JS_ThrowTypeError(ctx, \"invalid 'in' operand\");\n        return -1;\n    }\n    atom = JS_ValueToAtom(ctx, op1);\n    if (unlikely(atom == JS_ATOM_NULL))\n        return -1;\n    ret = JS_HasProperty(ctx, op2, atom);\n    JS_FreeAtom(ctx, atom);\n    if (ret < 0)\n        return -1;\n    JS_FreeValue(ctx, op1);\n    JS_FreeValue(ctx, op2);\n    sp[-2] = JS_NewBool(ctx, ret);\n    return 0;\n}\n\nstatic __exception int js_operator_private_in(JSContext *ctx, JSValue *sp)\n{\n    JSValue op1, op2;\n    int ret;\n\n    op1 = sp[-2]; /* object */\n    op2 = sp[-1]; /* field name or method function */\n\n    if (JS_VALUE_GET_TAG(op1) != JS_TAG_OBJECT) {\n        JS_ThrowTypeError(ctx, \"invalid 'in' operand\");\n        return -1;\n    }\n    if (JS_IsObject(op2)) {\n        /* method: use the brand */\n        ret = JS_CheckBrand(ctx, op1, op2);\n        if (ret < 0)\n            return -1;\n    } else {\n        JSAtom atom;\n        JSObject *p;\n        JSShapeProperty *prs;\n        JSProperty *pr;\n        /* field */\n        atom = JS_ValueToAtom(ctx, op2);\n        if (unlikely(atom == JS_ATOM_NULL))\n            return -1;\n        p = JS_VALUE_GET_OBJ(op1);\n        prs = find_own_property(&pr, p, atom);\n        JS_FreeAtom(ctx, atom);\n        ret = (prs != NULL);\n    }\n    JS_FreeValue(ctx, op1);\n    JS_FreeValue(ctx, op2);\n    sp[-2] = JS_NewBool(ctx, ret);\n    return 0;\n}\n\nstatic __exception int js_has_unscopable(JSContext *ctx, JSValueConst obj,\n                                         JSAtom atom)\n{\n    JSValue arr, val;\n    int ret;\n\n    arr = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_unscopables);\n    if (JS_IsException(arr))\n        return -1;\n    ret = 0;\n    if (JS_IsObject(arr)) {\n        val = JS_GetProperty(ctx, arr, atom);\n        ret = JS_ToBoolFree(ctx, val);\n    }\n    JS_FreeValue(ctx, arr);\n    return ret;\n}\n\nstatic __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp)\n{\n    JSValue op1, op2;\n    BOOL ret;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n    ret = JS_IsInstanceOf(ctx, op1, op2);\n    if (ret < 0)\n        return ret;\n    JS_FreeValue(ctx, op1);\n    JS_FreeValue(ctx, op2);\n    sp[-2] = JS_NewBool(ctx, ret);\n    return 0;\n}\n\nstatic __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1)\n{\n    JSAtom atom;\n    uint32_t tag;\n\n    tag = JS_VALUE_GET_NORM_TAG(op1);\n    switch(tag) {\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        atom = JS_ATOM_bigint;\n        break;\n    case JS_TAG_INT:\n    case JS_TAG_FLOAT64:\n        atom = JS_ATOM_number;\n        break;\n    case JS_TAG_UNDEFINED:\n        atom = JS_ATOM_undefined;\n        break;\n    case JS_TAG_BOOL:\n        atom = JS_ATOM_boolean;\n        break;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        atom = JS_ATOM_string;\n        break;\n    case JS_TAG_OBJECT:\n        {\n            JSObject *p;\n            p = JS_VALUE_GET_OBJ(op1);\n            if (unlikely(p->is_HTMLDDA))\n                atom = JS_ATOM_undefined;\n            else if (JS_IsFunction(ctx, op1))\n                atom = JS_ATOM_function;\n            else\n                goto obj_type;\n        }\n        break;\n    case JS_TAG_NULL:\n    obj_type:\n        atom = JS_ATOM_object;\n        break;\n    case JS_TAG_SYMBOL:\n        atom = JS_ATOM_symbol;\n        break;\n    default:\n        atom = JS_ATOM_unknown;\n        break;\n    }\n    return atom;\n}\n\nstatic __exception int js_operator_delete(JSContext *ctx, JSValue *sp)\n{\n    JSValue op1, op2;\n    JSAtom atom;\n    int ret;\n\n    op1 = sp[-2];\n    op2 = sp[-1];\n    atom = JS_ValueToAtom(ctx, op2);\n    if (unlikely(atom == JS_ATOM_NULL))\n        return -1;\n    ret = JS_DeleteProperty(ctx, op1, atom, JS_PROP_THROW_STRICT);\n    JS_FreeAtom(ctx, atom);\n    if (unlikely(ret < 0))\n        return -1;\n    JS_FreeValue(ctx, op1);\n    JS_FreeValue(ctx, op2);\n    sp[-2] = JS_NewBool(ctx, ret);\n    return 0;\n}\n\n/* XXX: not 100% compatible, but mozilla seems to use a similar\n   implementation to ensure that caller in non strict mode does not\n   throw (ES5 compatibility) */\nstatic JSValue js_throw_type_error(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);\n    if (!b || (b->js_mode & JS_MODE_STRICT) || !b->has_prototype || argc >= 1) {\n        return JS_ThrowTypeError(ctx, \"invalid property access\");\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_function_proto_fileName(JSContext *ctx,\n                                          JSValueConst this_val)\n{\n    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);\n    if (b && b->has_debug) {\n        return JS_AtomToString(ctx, b->debug.filename);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_function_proto_lineNumber(JSContext *ctx,\n                                            JSValueConst this_val, int is_col)\n{\n    JSFunctionBytecode *b = JS_GetFunctionBytecode(this_val);\n    if (b && b->has_debug) {\n        int line_num, col_num;\n        line_num = find_line_num(ctx, b, -1, &col_num);\n        if (is_col)\n            return JS_NewInt32(ctx, col_num);\n        else\n            return JS_NewInt32(ctx, line_num);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic int js_arguments_define_own_property(JSContext *ctx,\n                                            JSValueConst this_obj,\n                                            JSAtom prop, JSValueConst val,\n                                            JSValueConst getter, JSValueConst setter, int flags)\n{\n    JSObject *p;\n    uint32_t idx;\n    p = JS_VALUE_GET_OBJ(this_obj);\n    /* convert to normal array when redefining an existing numeric field */\n    if (p->fast_array && JS_AtomIsArrayIndex(ctx, &idx, prop) &&\n        idx < p->u.array.count) {\n        if (convert_fast_array_to_array(ctx, p))\n            return -1;\n    }\n    /* run the default define own property */\n    return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,\n                             flags | JS_PROP_NO_EXOTIC);\n}\n\nstatic const JSClassExoticMethods js_arguments_exotic_methods = {\n    .define_own_property = js_arguments_define_own_property,\n};\n\nstatic JSValue js_build_arguments(JSContext *ctx, int argc, JSValueConst *argv)\n{\n    JSValue val, *tab;\n    JSProperty props[3];\n    JSObject *p;\n    int i;\n\n    props[0].u.value = JS_NewInt32(ctx, argc); /* length */\n    props[1].u.value = JS_DupValue(ctx, ctx->array_proto_values); /* Symbol.iterator */\n    props[2].u.getset.getter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, ctx->throw_type_error)); /* callee */\n    props[2].u.getset.setter = JS_VALUE_GET_OBJ(JS_DupValue(ctx, ctx->throw_type_error)); /* callee */\n    \n    val = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->arguments_shape),\n                                JS_CLASS_ARGUMENTS, props);\n    if (JS_IsException(val))\n        return val;\n    p = JS_VALUE_GET_OBJ(val);\n\n    /* initialize the fast array part */\n    tab = NULL;\n    if (argc > 0) {\n        tab = js_malloc(ctx, sizeof(tab[0]) * argc);\n        if (!tab)\n            goto fail;\n        for(i = 0; i < argc; i++) {\n            tab[i] = JS_DupValue(ctx, argv[i]);\n        }\n    }\n    p->u.array.u.values = tab;\n    p->u.array.count = argc;\n    return val;\n fail:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\n#define GLOBAL_VAR_OFFSET 0x40000000\n#define ARGUMENT_VAR_OFFSET 0x20000000\n\nstatic void js_mapped_arguments_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSVarRef **var_refs = p->u.array.u.var_refs;\n    int i;\n    for(i = 0; i < p->u.array.count; i++)\n        free_var_ref(rt, var_refs[i]);\n    js_free_rt(rt, var_refs);\n}\n\nstatic void js_mapped_arguments_mark(JSRuntime *rt, JSValueConst val,\n                                     JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSVarRef **var_refs = p->u.array.u.var_refs;\n    int i;\n    \n    for(i = 0; i < p->u.array.count; i++)\n        mark_func(rt, &var_refs[i]->header);\n}\n\n/* legacy arguments object: add references to the function arguments */\nstatic JSValue js_build_mapped_arguments(JSContext *ctx, int argc,\n                                         JSValueConst *argv,\n                                         JSStackFrame *sf, int arg_count)\n{\n    JSValue val;\n    JSProperty props[3];\n    JSVarRef **tab, *var_ref;\n    JSObject *p;\n    int i, j;\n\n    props[0].u.value = JS_NewInt32(ctx, argc); /* length */\n    props[1].u.value = JS_DupValue(ctx, ctx->array_proto_values); /* Symbol.iterator */\n    props[2].u.value = JS_DupValue(ctx, ctx->rt->current_stack_frame->cur_func); /* callee */\n    \n    val = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->mapped_arguments_shape),\n                                JS_CLASS_MAPPED_ARGUMENTS, props);\n    if (JS_IsException(val))\n        return val;\n    p = JS_VALUE_GET_OBJ(val);\n\n    /* initialize the fast array part */\n    tab = NULL;\n    if (argc > 0) {\n        tab = js_malloc(ctx, sizeof(tab[0]) * argc);\n        if (!tab)\n            goto fail;\n        for(i = 0; i < arg_count; i++) {\n            var_ref = get_var_ref(ctx, sf, i, TRUE);\n            if (!var_ref)\n                goto fail1;\n            tab[i] = var_ref;\n        }\n        for(i = arg_count; i < argc; i++) {\n            var_ref = js_create_var_ref(ctx, FALSE);\n            if (!var_ref) {\n            fail1:\n                for(j = 0; j < i; j++)\n                    free_var_ref(ctx->rt, tab[j]);\n                js_free(ctx, tab);\n                goto fail;\n            }\n            var_ref->value = JS_DupValue(ctx, argv[i]);\n            tab[i] = var_ref;\n        }\n    }\n    p->u.array.u.var_refs = tab;\n    p->u.array.count = argc;\n    return val;\n fail:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)\n{\n    JSObject *p, *p1;\n    JSPropertyEnum *tab_atom;\n    int i;\n    JSValue enum_obj;\n    JSForInIterator *it;\n    uint32_t tag, tab_atom_count;\n\n    tag = JS_VALUE_GET_TAG(obj);\n    if (tag != JS_TAG_OBJECT && tag != JS_TAG_NULL && tag != JS_TAG_UNDEFINED) {\n        obj = JS_ToObjectFree(ctx, obj);\n    }\n\n    it = js_malloc(ctx, sizeof(*it));\n    if (!it) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    enum_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_FOR_IN_ITERATOR);\n    if (JS_IsException(enum_obj)) {\n        js_free(ctx, it);\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    it->is_array = FALSE;\n    it->obj = obj;\n    it->idx = 0;\n    it->tab_atom = NULL;\n    it->atom_count = 0;\n    it->in_prototype_chain = FALSE;\n    p1 = JS_VALUE_GET_OBJ(enum_obj);\n    p1->u.for_in_iterator = it;\n\n    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)\n        return enum_obj;\n\n    p = JS_VALUE_GET_OBJ(obj);\n    if (p->fast_array) {\n        JSShape *sh;\n        JSShapeProperty *prs;\n        /* check that there are no enumerable normal fields */\n        sh = p->shape;\n        for(i = 0, prs = get_shape_prop(sh); i < sh->prop_count; i++, prs++) {\n            if (prs->flags & JS_PROP_ENUMERABLE)\n                goto normal_case;\n        }\n        /* for fast arrays, we only store the number of elements */\n        it->is_array = TRUE;\n        it->atom_count = p->u.array.count;\n    } else {\n    normal_case:\n        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,\n                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {\n            JS_FreeValue(ctx, enum_obj);\n            return JS_EXCEPTION;\n        }\n        it->tab_atom = tab_atom;\n        it->atom_count = tab_atom_count;\n    }\n    return enum_obj;\n}\n\n/* obj -> enum_obj */\nstatic __exception int js_for_in_start(JSContext *ctx, JSValue *sp)\n{\n    sp[-1] = build_for_in_iterator(ctx, sp[-1]);\n    if (JS_IsException(sp[-1]))\n        return -1;\n    return 0;\n}\n\n/* return -1 if exception, 0 if slow case, 1 if the enumeration is finished */\nstatic __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx,\n                                                              JSValueConst enum_obj)\n{\n    JSObject *p;\n    JSForInIterator *it;\n    JSPropertyEnum *tab_atom;\n    uint32_t tab_atom_count, i;\n    JSValue obj1;\n\n    p = JS_VALUE_GET_OBJ(enum_obj);\n    it = p->u.for_in_iterator;\n\n    /* check if there are enumerable properties in the prototype chain (fast path) */\n    obj1 = JS_DupValue(ctx, it->obj);\n    for(;;) {\n        obj1 = JS_GetPrototypeFree(ctx, obj1);\n        if (JS_IsNull(obj1))\n            break;\n        if (JS_IsException(obj1))\n            goto fail;\n        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,\n                                           JS_VALUE_GET_OBJ(obj1),\n                                           JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {\n            JS_FreeValue(ctx, obj1);\n            goto fail;\n        }\n        JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);\n        if (tab_atom_count != 0) {\n            JS_FreeValue(ctx, obj1);\n            goto slow_path;\n        }\n        /* must check for timeout to avoid infinite loop */\n        if (js_poll_interrupts(ctx)) {\n            JS_FreeValue(ctx, obj1);\n            goto fail;\n        }\n    }\n    JS_FreeValue(ctx, obj1);\n    return 1;\n\n slow_path:\n    /* add the visited properties, even if they are not enumerable */\n    if (it->is_array) {\n        if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,\n                                           JS_VALUE_GET_OBJ(it->obj),\n                                           JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {\n            goto fail;\n        }\n        it->is_array = FALSE;\n        it->tab_atom = tab_atom;\n        it->atom_count = tab_atom_count;\n    }\n\n    for(i = 0; i < it->atom_count; i++) {\n        if (JS_DefinePropertyValue(ctx, enum_obj, it->tab_atom[i].atom, JS_NULL, JS_PROP_ENUMERABLE) < 0)\n            goto fail;\n    }\n    return 0;\n fail:\n    return -1;\n}\n\n/* enum_obj -> enum_obj value done */\nstatic __exception int js_for_in_next(JSContext *ctx, JSValue *sp)\n{\n    JSValueConst enum_obj;\n    JSObject *p;\n    JSAtom prop;\n    JSForInIterator *it;\n    JSPropertyEnum *tab_atom;\n    uint32_t tab_atom_count;\n    int ret;\n\n    enum_obj = sp[-1];\n    /* fail safe */\n    if (JS_VALUE_GET_TAG(enum_obj) != JS_TAG_OBJECT)\n        goto done;\n    p = JS_VALUE_GET_OBJ(enum_obj);\n    if (p->class_id != JS_CLASS_FOR_IN_ITERATOR)\n        goto done;\n    it = p->u.for_in_iterator;\n\n    for(;;) {\n        if (it->idx >= it->atom_count) {\n            if (JS_IsNull(it->obj) || JS_IsUndefined(it->obj))\n                goto done; /* not an object */\n            /* no more property in the current object: look in the prototype */\n            if (!it->in_prototype_chain) {\n                ret = js_for_in_prepare_prototype_chain_enum(ctx, enum_obj);\n                if (ret < 0)\n                    return -1;\n                if (ret)\n                    goto done;\n                it->in_prototype_chain = TRUE;\n            }\n            it->obj = JS_GetPrototypeFree(ctx, it->obj);\n            if (JS_IsException(it->obj))\n                return -1;\n            if (JS_IsNull(it->obj))\n                goto done; /* no more prototype */\n\n            /* must check for timeout to avoid infinite loop */\n            if (js_poll_interrupts(ctx))\n                return -1;\n\n            if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,\n                                               JS_VALUE_GET_OBJ(it->obj),\n                                               JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {\n                return -1;\n            }\n            JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count);\n            it->tab_atom = tab_atom;\n            it->atom_count = tab_atom_count;\n            it->idx = 0;\n        } else {\n            if (it->is_array) {\n                prop = __JS_AtomFromUInt32(it->idx);\n                it->idx++;\n            } else {\n                BOOL is_enumerable;\n                prop = it->tab_atom[it->idx].atom;\n                is_enumerable = it->tab_atom[it->idx].is_enumerable;\n                it->idx++;\n                if (it->in_prototype_chain) {\n                    /* slow case: we are in the prototype chain */\n                    ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(enum_obj), prop);\n                    if (ret < 0)\n                        return ret;\n                    if (ret)\n                        continue; /* already visited */\n                    /* add to the visited property list */\n                    if (JS_DefinePropertyValue(ctx, enum_obj, prop, JS_NULL,\n                                               JS_PROP_ENUMERABLE) < 0)\n                        return -1;\n                }\n                if (!is_enumerable)\n                    continue;\n            }\n            /* check if the property was deleted */\n            ret = JS_GetOwnPropertyInternal(ctx, NULL, JS_VALUE_GET_OBJ(it->obj), prop);\n            if (ret < 0)\n                return ret;\n            if (ret)\n                break;\n        }\n    }\n    /* return the property */\n    sp[0] = JS_AtomToValue(ctx, prop);\n    sp[1] = JS_FALSE;\n    return 0;\n done:\n    /* return the end */\n    sp[0] = JS_UNDEFINED;\n    sp[1] = JS_TRUE;\n    return 0;\n}\n\nstatic JSValue JS_GetIterator2(JSContext *ctx, JSValueConst obj,\n                               JSValueConst method)\n{\n    JSValue enum_obj;\n\n    enum_obj = JS_Call(ctx, method, obj, 0, NULL);\n    if (JS_IsException(enum_obj))\n        return enum_obj;\n    if (!JS_IsObject(enum_obj)) {\n        JS_FreeValue(ctx, enum_obj);\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    }\n    return enum_obj;\n}\n\nstatic JSValue JS_GetIterator(JSContext *ctx, JSValueConst obj, BOOL is_async)\n{\n    JSValue method, ret, sync_iter;\n\n    if (is_async) {\n        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);\n        if (JS_IsException(method))\n            return method;\n        if (JS_IsUndefined(method) || JS_IsNull(method)) {\n            method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);\n            if (JS_IsException(method))\n                return method;\n            sync_iter = JS_GetIterator2(ctx, obj, method);\n            JS_FreeValue(ctx, method);\n            if (JS_IsException(sync_iter))\n                return sync_iter;\n            ret = JS_CreateAsyncFromSyncIterator(ctx, sync_iter);\n            JS_FreeValue(ctx, sync_iter);\n            return ret;\n        }\n    } else {\n        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);\n        if (JS_IsException(method))\n            return method;\n    }\n    if (!JS_IsFunction(ctx, method)) {\n        JS_FreeValue(ctx, method);\n        return JS_ThrowTypeError(ctx, \"value is not iterable\");\n    }\n    ret = JS_GetIterator2(ctx, obj, method);\n    JS_FreeValue(ctx, method);\n    return ret;\n}\n\n/* return *pdone = 2 if the iterator object is not parsed */\nstatic JSValue JS_IteratorNext2(JSContext *ctx, JSValueConst enum_obj,\n                                JSValueConst method,\n                                int argc, JSValueConst *argv, int *pdone)\n{\n    JSValue obj;\n\n    /* fast path for the built-in iterators (avoid creating the\n       intermediate result object) */\n    if (JS_IsObject(method)) {\n        JSObject *p = JS_VALUE_GET_OBJ(method);\n        if (p->class_id == JS_CLASS_C_FUNCTION &&\n            p->u.cfunc.cproto == JS_CFUNC_iterator_next) {\n            JSCFunctionType func;\n            JSValueConst args[1];\n\n            /* in case the function expects one argument */\n            if (argc == 0) {\n                args[0] = JS_UNDEFINED;\n                argv = args;\n            }\n            func = p->u.cfunc.c_function;\n            return func.iterator_next(ctx, enum_obj, argc, argv,\n                                      pdone, p->u.cfunc.magic);\n        }\n    }\n    obj = JS_Call(ctx, method, enum_obj, argc, argv);\n    if (JS_IsException(obj))\n        goto fail;\n    if (!JS_IsObject(obj)) {\n        JS_FreeValue(ctx, obj);\n        JS_ThrowTypeError(ctx, \"iterator must return an object\");\n        goto fail;\n    }\n    *pdone = 2;\n    return obj;\n fail:\n    *pdone = FALSE;\n    return JS_EXCEPTION;\n}\n\n/* Note: always return JS_UNDEFINED when *pdone = TRUE. */\nstatic JSValue JS_IteratorNext(JSContext *ctx, JSValueConst enum_obj,\n                               JSValueConst method,\n                               int argc, JSValueConst *argv, BOOL *pdone)\n{\n    JSValue obj, value, done_val;\n    int done;\n\n    obj = JS_IteratorNext2(ctx, enum_obj, method, argc, argv, &done);\n    if (JS_IsException(obj))\n        goto fail;\n    if (likely(done == 0)) {\n        *pdone = FALSE;\n        return obj;\n    } else if (done != 2) {\n        JS_FreeValue(ctx, obj);\n        *pdone = TRUE;\n        return JS_UNDEFINED;\n    } else {\n        done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);\n        if (JS_IsException(done_val))\n            goto fail;\n        *pdone = JS_ToBoolFree(ctx, done_val);\n        value = JS_UNDEFINED;\n        if (!*pdone) {\n            value = JS_GetProperty(ctx, obj, JS_ATOM_value);\n        }\n        JS_FreeValue(ctx, obj);\n        return value;\n    }\n fail:\n    JS_FreeValue(ctx, obj);\n    *pdone = FALSE;\n    return JS_EXCEPTION;\n}\n\n/* return < 0 in case of exception */\nstatic int JS_IteratorClose(JSContext *ctx, JSValueConst enum_obj,\n                            BOOL is_exception_pending)\n{\n    JSValue method, ret, ex_obj;\n    int res;\n\n    if (is_exception_pending) {\n        ex_obj = ctx->rt->current_exception;\n        ctx->rt->current_exception = JS_UNINITIALIZED;\n        res = -1;\n    } else {\n        ex_obj = JS_UNDEFINED;\n        res = 0;\n    }\n    method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);\n    if (JS_IsException(method)) {\n        res = -1;\n        goto done;\n    }\n    if (JS_IsUndefined(method) || JS_IsNull(method)) {\n        goto done;\n    }\n    ret = JS_CallFree(ctx, method, enum_obj, 0, NULL);\n    if (!is_exception_pending) {\n        if (JS_IsException(ret)) {\n            res = -1;\n        } else if (!JS_IsObject(ret)) {\n            JS_ThrowTypeErrorNotAnObject(ctx);\n            res = -1;\n        }\n    }\n    JS_FreeValue(ctx, ret);\n done:\n    if (is_exception_pending) {\n        JS_Throw(ctx, ex_obj);\n    }\n    return res;\n}\n\n/* obj -> enum_rec (3 slots) */\nstatic __exception int js_for_of_start(JSContext *ctx, JSValue *sp,\n                                       BOOL is_async)\n{\n    JSValue op1, obj, method;\n    op1 = sp[-1];\n    obj = JS_GetIterator(ctx, op1, is_async);\n    if (JS_IsException(obj))\n        return -1;\n    JS_FreeValue(ctx, op1);\n    sp[-1] = obj;\n    method = JS_GetProperty(ctx, obj, JS_ATOM_next);\n    if (JS_IsException(method))\n        return -1;\n    sp[0] = method;\n    return 0;\n}\n\n/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset'\n   objs. If 'done' is true or in case of exception, 'enum_rec' is set\n   to undefined. If 'done' is true, 'value' is always set to\n   undefined. */\nstatic __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)\n{\n    JSValue value = JS_UNDEFINED;\n    int done = 1;\n\n    if (likely(!JS_IsUndefined(sp[offset]))) {\n        value = JS_IteratorNext(ctx, sp[offset], sp[offset + 1], 0, NULL, &done);\n        if (JS_IsException(value))\n            done = -1;\n        if (done) {\n            /* value is JS_UNDEFINED or JS_EXCEPTION */\n            /* replace the iteration object with undefined */\n            JS_FreeValue(ctx, sp[offset]);\n            sp[offset] = JS_UNDEFINED;\n            if (done < 0) {\n                return -1;\n            } else {\n                JS_FreeValue(ctx, value);\n                value = JS_UNDEFINED;\n            }\n        }\n    }\n    sp[0] = value;\n    sp[1] = JS_NewBool(ctx, done);\n    return 0;\n}\n\nstatic __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp)\n{\n    JSValue obj, iter, next;\n\n    sp[-1] = JS_UNDEFINED; /* disable the catch offset so that\n                              exceptions do not close the iterator */\n    iter = sp[-3];\n    next = sp[-2];\n    obj = JS_Call(ctx, next, iter, 0, NULL);\n    if (JS_IsException(obj))\n        return -1;\n    sp[0] = obj;\n    return 0;\n}\n\nstatic JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,\n                                           BOOL *pdone)\n{\n    JSValue done_val, value;\n    BOOL done;\n    done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);\n    if (JS_IsException(done_val))\n        goto fail;\n    done = JS_ToBoolFree(ctx, done_val);\n    value = JS_GetProperty(ctx, obj, JS_ATOM_value);\n    if (JS_IsException(value))\n        goto fail;\n    *pdone = done;\n    return value;\n fail:\n    *pdone = FALSE;\n    return JS_EXCEPTION;\n}\n\nstatic __exception int js_iterator_get_value_done(JSContext *ctx, JSValue *sp)\n{\n    JSValue obj, value;\n    BOOL done;\n    obj = sp[-1];\n    if (!JS_IsObject(obj)) {\n        JS_ThrowTypeError(ctx, \"iterator must return an object\");\n        return -1;\n    }\n    value = JS_IteratorGetCompleteValue(ctx, obj, &done);\n    if (JS_IsException(value))\n        return -1;\n    JS_FreeValue(ctx, obj);\n    /* put again the catch offset so that exceptions close the\n       iterator */\n    sp[-2] = JS_NewCatchOffset(ctx, 0); \n    sp[-1] = value;\n    sp[0] = JS_NewBool(ctx, done);\n    return 0;\n}\n\nstatic JSValue js_create_iterator_result(JSContext *ctx,\n                                         JSValue val,\n                                         BOOL done)\n{\n    JSValue obj;\n    obj = JS_NewObject(ctx);\n    if (JS_IsException(obj)) {\n        JS_FreeValue(ctx, val);\n        return obj;\n    }\n    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_value,\n                               val, JS_PROP_C_W_E) < 0) {\n        goto fail;\n    }\n    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_done,\n                               JS_NewBool(ctx, done), JS_PROP_C_W_E) < 0) {\n    fail:\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    return obj;\n}\n\nstatic JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv,\n                                      BOOL *pdone, int magic);\n\nstatic JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv, int magic);\n\nstatic BOOL js_is_fast_array(JSContext *ctx, JSValueConst obj)\n{\n    /* Try and handle fast arrays explicitly */\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(obj);\n        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n/* Access an Array's internal JSValue array if available */\nstatic BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj,\n                              JSValue **arrpp, uint32_t *countp)\n{\n    /* Try and handle fast arrays explicitly */\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(obj);\n        if (p->class_id == JS_CLASS_ARRAY && p->fast_array) {\n            *countp = p->u.array.count;\n            *arrpp = p->u.array.u.values;\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\nstatic __exception int js_append_enumerate(JSContext *ctx, JSValue *sp)\n{\n    JSValue iterator, enumobj, method, value;\n    int is_array_iterator;\n    JSValue *arrp;\n    uint32_t i, count32, pos;\n    JSCFunctionType ft;\n\n    if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) {\n        JS_ThrowInternalError(ctx, \"invalid index for append\");\n        return -1;\n    }\n\n    pos = JS_VALUE_GET_INT(sp[-2]);\n\n    /* XXX: further optimisations:\n       - use ctx->array_proto_values?\n       - check if array_iterator_prototype next method is built-in and\n         avoid constructing actual iterator object?\n       - build this into js_for_of_start and use in all `for (x of o)` loops\n     */\n    iterator = JS_GetProperty(ctx, sp[-1], JS_ATOM_Symbol_iterator);\n    if (JS_IsException(iterator))\n        return -1;\n    ft.generic_magic = js_create_array_iterator;\n    is_array_iterator = JS_IsCFunction(ctx, iterator, ft.generic,\n                                       JS_ITERATOR_KIND_VALUE);\n    JS_FreeValue(ctx, iterator);\n\n    enumobj = JS_GetIterator(ctx, sp[-1], FALSE);\n    if (JS_IsException(enumobj))\n        return -1;\n    method = JS_GetProperty(ctx, enumobj, JS_ATOM_next);\n    if (JS_IsException(method)) {\n        JS_FreeValue(ctx, enumobj);\n        return -1;\n    }\n\n    ft.iterator_next = js_array_iterator_next;\n    if (is_array_iterator\n    &&  JS_IsCFunction(ctx, method, ft.generic, 0)\n    &&  js_get_fast_array(ctx, sp[-1], &arrp, &count32)) {\n        uint32_t len;\n        if (js_get_length32(ctx, &len, sp[-1]))\n            goto exception;\n        /* if len > count32, the elements >= count32 might be read in\n           the prototypes and might have side effects */\n        if (len != count32)\n            goto general_case;\n        /* Handle fast arrays explicitly */\n        for (i = 0; i < count32; i++) {\n            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++,\n                                             JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0)\n                goto exception;\n        }\n    } else {\n    general_case:\n        for (;;) {\n            BOOL done;\n            value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done);\n            if (JS_IsException(value))\n                goto exception;\n            if (done) {\n                /* value is JS_UNDEFINED */\n                break;\n            }\n            if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, value, JS_PROP_C_W_E) < 0)\n                goto exception;\n        }\n    }\n    /* Note: could raise an error if too many elements */\n    sp[-2] = JS_NewInt32(ctx, pos);\n    JS_FreeValue(ctx, enumobj);\n    JS_FreeValue(ctx, method);\n    return 0;\n\nexception:\n    JS_IteratorClose(ctx, enumobj, TRUE);\n    JS_FreeValue(ctx, enumobj);\n    JS_FreeValue(ctx, method);\n    return -1;\n}\n\nstatic __exception int JS_CopyDataProperties(JSContext *ctx,\n                                             JSValueConst target,\n                                             JSValueConst source,\n                                             JSValueConst excluded,\n                                             BOOL setprop)\n{\n    JSPropertyEnum *tab_atom;\n    JSValue val;\n    uint32_t i, tab_atom_count;\n    JSObject *p;\n    JSObject *pexcl = NULL;\n    int ret, gpn_flags;\n    JSPropertyDescriptor desc;\n    BOOL is_enumerable;\n\n    if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)\n        return 0;\n\n    if (JS_VALUE_GET_TAG(excluded) == JS_TAG_OBJECT)\n        pexcl = JS_VALUE_GET_OBJ(excluded);\n\n    p = JS_VALUE_GET_OBJ(source);\n\n    gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;\n    if (p->is_exotic) {\n        const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;\n        /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it\n           introduces a visible change */\n        if (em && em->get_own_property_names) {\n            gpn_flags &= ~JS_GPN_ENUM_ONLY;\n        }\n    }\n    if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,\n                                       gpn_flags))\n        return -1;\n\n    for (i = 0; i < tab_atom_count; i++) {\n        if (pexcl) {\n            ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);\n            if (ret) {\n                if (ret < 0)\n                    goto exception;\n                continue;\n            }\n        }\n        if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {\n            /* test if the property is enumerable */\n            ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);\n            if (ret < 0)\n                goto exception;\n            if (!ret)\n                continue;\n            is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;\n            js_free_desc(ctx, &desc);\n            if (!is_enumerable)\n                continue;\n        }\n        val = JS_GetProperty(ctx, source, tab_atom[i].atom);\n        if (JS_IsException(val))\n            goto exception;\n        if (setprop)\n            ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);\n        else\n            ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,\n                                         JS_PROP_C_W_E);\n        if (ret < 0)\n            goto exception;\n    }\n    JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);\n    return 0;\n exception:\n    JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count);\n    return -1;\n}\n\n/* only valid inside C functions */\nstatic JSValueConst JS_GetActiveFunction(JSContext *ctx)\n{\n    return ctx->rt->current_stack_frame->cur_func;\n}\n\nstatic JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical)\n{\n    JSVarRef *var_ref;\n    var_ref = js_malloc(ctx, sizeof(JSVarRef));\n    if (!var_ref)\n        return NULL;\n    var_ref->header.ref_count = 1;\n    if (is_lexical)\n        var_ref->value = JS_UNINITIALIZED;\n    else\n        var_ref->value = JS_UNDEFINED;\n    var_ref->pvalue = &var_ref->value;\n    var_ref->is_detached = TRUE;\n    var_ref->is_lexical = FALSE;\n    var_ref->is_const = FALSE;\n    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);\n    return var_ref;\n}\n\nstatic JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,\n                             BOOL is_arg)\n{\n    JSObject *p;\n    JSFunctionBytecode *b;\n    JSVarRef *var_ref;\n    JSValue *pvalue;\n    int var_ref_idx;\n    JSBytecodeVarDef *vd;\n    \n    p = JS_VALUE_GET_OBJ(sf->cur_func);\n    b = p->u.func.function_bytecode;\n    \n    if (is_arg) {\n        vd = &b->vardefs[var_idx];\n        pvalue = &sf->arg_buf[var_idx];\n    } else {\n        vd = &b->vardefs[b->arg_count + var_idx];\n        pvalue = &sf->var_buf[var_idx];\n    }\n    assert(vd->is_captured);\n    var_ref_idx = vd->var_ref_idx;\n    assert(var_ref_idx < b->var_ref_count);\n    var_ref = sf->var_refs[var_ref_idx];\n    if (var_ref) {\n        /* reference to the already created local variable */\n        assert(var_ref->pvalue == pvalue);\n        var_ref->header.ref_count++;\n        return var_ref;\n    }\n\n    /* create a new one */\n    var_ref = js_malloc(ctx, sizeof(JSVarRef));\n    if (!var_ref)\n        return NULL;\n    var_ref->header.ref_count = 1;\n    add_gc_object(ctx->rt, &var_ref->header, JS_GC_OBJ_TYPE_VAR_REF);\n    var_ref->is_detached = FALSE;\n    var_ref->is_lexical = FALSE;\n    var_ref->is_const = FALSE;\n    var_ref->var_ref_idx = var_ref_idx;\n    var_ref->stack_frame = sf;\n    sf->var_refs[var_ref_idx] = var_ref;\n    if (sf->js_mode & JS_MODE_ASYNC) {\n        JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);\n        /* The stack frame is detached and may be destroyed at any\n           time so its reference count must be increased. Calling\n           close_var_refs() when destroying the stack frame is not\n           possible because it would change the graph between the GC\n           objects. Another solution could be to temporarily detach\n           the JSVarRef of async functions during the GC. It would\n           have the advantage of allowing the release of unused stack\n           frames in a cycle. */\n        async_func->header.ref_count++;\n    }\n    var_ref->pvalue = pvalue;\n    return var_ref;\n}\n\nstatic void js_global_object_finalizer(JSRuntime *rt, JSValue obj)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(obj);\n    JS_FreeValueRT(rt, p->u.global_object.uninitialized_vars);\n}\n\nstatic void js_global_object_mark(JSRuntime *rt, JSValueConst val,\n                                  JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JS_MarkValue(rt, p->u.global_object.uninitialized_vars, mark_func);\n}\n\nstatic JSVarRef *js_global_object_get_uninitialized_var(JSContext *ctx, JSObject *p1, \n                                                        JSAtom atom)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(p1->u.global_object.uninitialized_vars);\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSVarRef *var_ref;\n    \n    prs = find_own_property(&pr, p, atom);\n    if (prs) {\n        assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);\n        var_ref = pr->u.var_ref;\n        var_ref->header.ref_count++;\n        return var_ref;\n    }\n\n    var_ref = js_create_var_ref(ctx, TRUE);\n    if (!var_ref)\n        return NULL;\n    pr = add_property(ctx, p, atom, JS_PROP_C_W_E | JS_PROP_VARREF);\n    if (unlikely(!pr)) {\n        free_var_ref(ctx->rt, var_ref);\n        return NULL;\n    }\n    pr->u.var_ref = var_ref;\n    var_ref->header.ref_count++;\n    return var_ref;\n}\n\n/* return a new variable reference. Get it from the uninitialized\n   variables if it is present. Return NULL in case of memory error. */\nstatic JSVarRef *js_global_object_find_uninitialized_var(JSContext *ctx, JSObject *p,\n                                                         JSAtom atom, BOOL is_lexical)\n{\n    JSObject *p1;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSVarRef *var_ref;\n    \n    p1 = JS_VALUE_GET_OBJ(p->u.global_object.uninitialized_vars);\n    prs = find_own_property(&pr, p1, atom);\n    if (prs) {\n        assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);\n        var_ref = pr->u.var_ref;\n        var_ref->header.ref_count++;\n        delete_property(ctx, p1, atom);\n        if (!is_lexical)\n            var_ref->value = JS_UNDEFINED;\n    } else {\n        var_ref = js_create_var_ref(ctx, is_lexical);\n        if (!var_ref)\n            return NULL;\n    }\n    return var_ref;\n}\n\nstatic JSVarRef *js_closure_define_global_var(JSContext *ctx, JSClosureVar *cv,\n                                              BOOL is_direct_or_indirect_eval)\n{\n    JSObject *p, *p1;\n    JSShapeProperty *prs;\n    int flags;\n    JSProperty *pr;\n    JSVarRef *var_ref;\n    \n    if (cv->is_lexical) {\n        p = JS_VALUE_GET_OBJ(ctx->global_var_obj);\n        flags = JS_PROP_ENUMERABLE | JS_PROP_CONFIGURABLE;\n        if (!cv->is_const)\n            flags |= JS_PROP_WRITABLE;\n\n        prs = find_own_property(&pr, p, cv->var_name);\n        if (prs) {\n            assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);\n            var_ref = pr->u.var_ref;\n            var_ref->header.ref_count++;\n            return var_ref;\n        }\n\n        /* if there is a corresponding global variable, reuse its\n           reference and create a new one for the global variable */\n        p1 = JS_VALUE_GET_OBJ(ctx->global_obj);\n        prs = find_own_property(&pr, p1, cv->var_name);\n        if (prs && (prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n            JSVarRef *var_ref1;\n            var_ref1 = js_create_var_ref(ctx, FALSE);\n            if (!var_ref1)\n                return NULL;\n            var_ref = pr->u.var_ref;\n            var_ref1->value = var_ref->value;\n            var_ref->value = JS_UNINITIALIZED;\n            pr->u.var_ref = var_ref1;\n            goto add_var_ref;\n        }\n    } else {\n        p = JS_VALUE_GET_OBJ(ctx->global_obj);\n        flags = JS_PROP_ENUMERABLE | JS_PROP_WRITABLE;\n        if (is_direct_or_indirect_eval)\n            flags |= JS_PROP_CONFIGURABLE;\n\n    retry:\n        prs = find_own_property(&pr, p, cv->var_name);\n        if (prs) {\n            if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT)) {\n                if (JS_AutoInitProperty(ctx, p, cv->var_name, pr, prs))\n                    return NULL;\n                goto retry;\n            } else if ((prs->flags & JS_PROP_TMASK) != JS_PROP_VARREF) {\n                var_ref = js_global_object_get_uninitialized_var(ctx, p, cv->var_name);\n                if (!var_ref)\n                    return NULL;\n            } else {\n                var_ref = pr->u.var_ref;\n                var_ref->header.ref_count++;\n            }\n            if (cv->var_kind == JS_VAR_GLOBAL_FUNCTION_DECL &&\n                (prs->flags & JS_PROP_CONFIGURABLE)) {\n                /* update the property flags if possible when\n                   declaring a global function */\n                if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                    free_property(ctx->rt, pr, prs->flags);\n                    prs->flags = flags | JS_PROP_VARREF;\n                    pr->u.var_ref = var_ref;\n                    var_ref->header.ref_count++;\n                } else {\n                    assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);\n                    prs->flags = (prs->flags & ~JS_PROP_C_W_E) | flags;\n                }\n                var_ref->is_const = FALSE;\n            }\n            return var_ref;\n        }\n        \n        if (!p->extensible) {\n            return js_global_object_get_uninitialized_var(ctx, p, cv->var_name);\n        }\n    }\n    \n    /* if there is a corresponding uninitialized variable, use it */\n    p1 = JS_VALUE_GET_OBJ(ctx->global_obj);\n    var_ref = js_global_object_find_uninitialized_var(ctx, p1, cv->var_name, cv->is_lexical);\n    if (!var_ref)\n        return NULL;\n add_var_ref:\n    if (cv->is_lexical) {\n        var_ref->is_lexical = TRUE;\n        var_ref->is_const = cv->is_const;\n    }\n\n    pr = add_property(ctx, p, cv->var_name, flags | JS_PROP_VARREF);\n    if (unlikely(!pr)) {\n        free_var_ref(ctx->rt, var_ref);\n        return NULL;\n    }\n    pr->u.var_ref = var_ref;\n    var_ref->header.ref_count++;\n    return var_ref;\n}\n\nstatic JSVarRef *js_closure_global_var(JSContext *ctx, JSClosureVar *cv)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    JSVarRef *var_ref;\n    \n    p = JS_VALUE_GET_OBJ(ctx->global_var_obj);\n    prs = find_own_property(&pr, p, cv->var_name);\n    if (prs) {\n        assert((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF);\n        var_ref = pr->u.var_ref;\n        var_ref->header.ref_count++;\n        return var_ref;\n    }\n    p = JS_VALUE_GET_OBJ(ctx->global_obj);\n redo:\n    prs = find_own_property(&pr, p, cv->var_name);\n    if (prs) {\n        if (unlikely((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT)) {\n            /* Instantiate property and retry */\n            if (JS_AutoInitProperty(ctx, p, cv->var_name, pr, prs))\n                return NULL;\n            goto redo;\n        }\n        if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {\n            var_ref = pr->u.var_ref;\n            var_ref->header.ref_count++;\n            return var_ref;\n        }\n    }\n    return js_global_object_get_uninitialized_var(ctx, p, cv->var_name);\n}\n\nstatic JSValue js_closure2(JSContext *ctx, JSValue func_obj,\n                           JSFunctionBytecode *b,\n                           JSVarRef **cur_var_refs,\n                           JSStackFrame *sf,\n                           BOOL is_eval, JSModuleDef *m)\n{\n    JSObject *p;\n    JSVarRef **var_refs;\n    int i;\n\n    p = JS_VALUE_GET_OBJ(func_obj);\n    p->u.func.function_bytecode = b;\n    p->u.func.home_object = NULL;\n    p->u.func.var_refs = NULL;\n    if (b->closure_var_count) {\n        var_refs = js_mallocz(ctx, sizeof(var_refs[0]) * b->closure_var_count);\n        if (!var_refs)\n            goto fail;\n        p->u.func.var_refs = var_refs;\n        if (is_eval) {\n            /* first pass to check the global variable definitions */\n            for(i = 0; i < b->closure_var_count; i++) {\n                JSClosureVar *cv = &b->closure_var[i];\n                if (cv->closure_type == JS_CLOSURE_GLOBAL_DECL) {\n                    int flags;\n                    flags = 0;\n                    if (cv->is_lexical)\n                        flags |= DEFINE_GLOBAL_LEX_VAR;\n                    if (cv->var_kind == JS_VAR_GLOBAL_FUNCTION_DECL)\n                        flags |= DEFINE_GLOBAL_FUNC_VAR;\n                    if (JS_CheckDefineGlobalVar(ctx, cv->var_name, flags))\n                        goto fail;\n                }\n            }\n        }\n        for(i = 0; i < b->closure_var_count; i++) {\n            JSClosureVar *cv = &b->closure_var[i];\n            JSVarRef *var_ref;\n            switch(cv->closure_type) {\n            case JS_CLOSURE_MODULE_IMPORT:\n                /* imported from other modules */\n                continue;\n            case JS_CLOSURE_MODULE_DECL:\n                var_ref = js_create_var_ref(ctx, cv->is_lexical);\n                break;\n            case JS_CLOSURE_GLOBAL_DECL:\n                var_ref = js_closure_define_global_var(ctx, cv, b->is_direct_or_indirect_eval);\n                break;\n            case JS_CLOSURE_GLOBAL:\n                var_ref = js_closure_global_var(ctx, cv);\n                break;\n            case JS_CLOSURE_LOCAL:\n                /* reuse the existing variable reference if it already exists */\n                var_ref = get_var_ref(ctx, sf, cv->var_idx, FALSE);\n                break;\n            case JS_CLOSURE_ARG:\n                /* reuse the existing variable reference if it already exists */\n                var_ref = get_var_ref(ctx, sf, cv->var_idx, TRUE);\n                break;\n            case JS_CLOSURE_REF:\n            case JS_CLOSURE_GLOBAL_REF:\n                var_ref = cur_var_refs[cv->var_idx];\n                var_ref->header.ref_count++;\n                break;\n            default:\n                abort();\n            }\n            if (!var_ref)\n                goto fail;\n            var_refs[i] = var_ref;\n        }\n    }\n    return func_obj;\n fail:\n    /* bfunc is freed when func_obj is freed */\n    JS_FreeValue(ctx, func_obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)\n{\n    JSValue obj, this_val;\n    int ret;\n\n    this_val = JS_MKPTR(JS_TAG_OBJECT, p);\n    obj = JS_NewObject(ctx);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    set_cycle_flag(ctx, obj);\n    set_cycle_flag(ctx, this_val);\n    ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,\n                                 JS_DupValue(ctx, this_val),\n                                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n    if (ret < 0) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    return obj;\n}\n\nstatic const uint16_t func_kind_to_class_id[] = {\n    [JS_FUNC_NORMAL] = JS_CLASS_BYTECODE_FUNCTION,\n    [JS_FUNC_GENERATOR] = JS_CLASS_GENERATOR_FUNCTION,\n    [JS_FUNC_ASYNC] = JS_CLASS_ASYNC_FUNCTION,\n    [JS_FUNC_ASYNC_GENERATOR] = JS_CLASS_ASYNC_GENERATOR_FUNCTION,\n};\n\nstatic JSValue js_closure(JSContext *ctx, JSValue bfunc,\n                          JSVarRef **cur_var_refs,\n                          JSStackFrame *sf, BOOL is_eval)\n{\n    JSFunctionBytecode *b;\n    JSValue func_obj;\n    JSAtom name_atom;\n\n    b = JS_VALUE_GET_PTR(bfunc);\n    func_obj = JS_NewObjectClass(ctx, func_kind_to_class_id[b->func_kind]);\n    if (JS_IsException(func_obj)) {\n        JS_FreeValue(ctx, bfunc);\n        return JS_EXCEPTION;\n    }\n    func_obj = js_closure2(ctx, func_obj, b, cur_var_refs, sf, is_eval, NULL);\n    if (JS_IsException(func_obj)) {\n        /* bfunc has been freed */\n        goto fail;\n    }\n    name_atom = b->func_name;\n    if (name_atom == JS_ATOM_NULL)\n        name_atom = JS_ATOM_empty_string;\n    js_function_set_properties(ctx, func_obj, name_atom,\n                               b->defined_arg_count);\n\n    if (b->func_kind & JS_FUNC_GENERATOR) {\n        JSValue proto;\n        int proto_class_id;\n        /* generators have a prototype field which is used as\n           prototype for the generator object */\n        if (b->func_kind == JS_FUNC_ASYNC_GENERATOR)\n            proto_class_id = JS_CLASS_ASYNC_GENERATOR;\n        else\n            proto_class_id = JS_CLASS_GENERATOR;\n        proto = JS_NewObjectProto(ctx, ctx->class_proto[proto_class_id]);\n        if (JS_IsException(proto))\n            goto fail;\n        JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto,\n                               JS_PROP_WRITABLE);\n    } else if (b->has_prototype) {\n        /* add the 'prototype' property: delay instantiation to avoid\n           creating cycles for every javascript function. The prototype\n           object is created on the fly when first accessed */\n        JS_SetConstructorBit(ctx, func_obj, TRUE);\n        JS_DefineAutoInitProperty(ctx, func_obj, JS_ATOM_prototype,\n                                  JS_AUTOINIT_ID_PROTOTYPE, NULL,\n                                  JS_PROP_WRITABLE);\n    }\n    return func_obj;\n fail:\n    /* bfunc is freed when func_obj is freed */\n    JS_FreeValue(ctx, func_obj);\n    return JS_EXCEPTION;\n}\n\n#define JS_DEFINE_CLASS_HAS_HERITAGE     (1 << 0)\n\nstatic int js_op_define_class(JSContext *ctx, JSValue *sp,\n                              JSAtom class_name, int class_flags,\n                              JSVarRef **cur_var_refs,\n                              JSStackFrame *sf, BOOL is_computed_name)\n{\n    JSValue bfunc, parent_class, proto = JS_UNDEFINED;\n    JSValue ctor = JS_UNDEFINED, parent_proto = JS_UNDEFINED;\n    JSFunctionBytecode *b;\n\n    parent_class = sp[-2];\n    bfunc = sp[-1];\n\n    if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE) {\n        if (JS_IsNull(parent_class)) {\n            parent_proto = JS_NULL;\n            parent_class = JS_DupValue(ctx, ctx->function_proto);\n        } else {\n            if (!JS_IsConstructor(ctx, parent_class)) {\n                JS_ThrowTypeError(ctx, \"parent class must be constructor\");\n                goto fail;\n            }\n            parent_proto = JS_GetProperty(ctx, parent_class, JS_ATOM_prototype);\n            if (JS_IsException(parent_proto))\n                goto fail;\n            if (!JS_IsNull(parent_proto) && !JS_IsObject(parent_proto)) {\n                JS_ThrowTypeError(ctx, \"parent prototype must be an object or null\");\n                goto fail;\n            }\n        }\n    } else {\n        /* parent_class is JS_UNDEFINED in this case */\n        parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);\n        parent_class = JS_DupValue(ctx, ctx->function_proto);\n    }\n    proto = JS_NewObjectProto(ctx, parent_proto);\n    if (JS_IsException(proto))\n        goto fail;\n\n    b = JS_VALUE_GET_PTR(bfunc);\n    assert(b->func_kind == JS_FUNC_NORMAL);\n    ctor = JS_NewObjectProtoClass(ctx, parent_class,\n                                  JS_CLASS_BYTECODE_FUNCTION);\n    if (JS_IsException(ctor))\n        goto fail;\n    ctor = js_closure2(ctx, ctor, b, cur_var_refs, sf, FALSE, NULL);\n    bfunc = JS_UNDEFINED;\n    if (JS_IsException(ctor))\n        goto fail;\n    js_method_set_home_object(ctx, ctor, proto);\n    JS_SetConstructorBit(ctx, ctor, TRUE);\n\n    JS_DefinePropertyValue(ctx, ctor, JS_ATOM_length,\n                           JS_NewInt32(ctx, b->defined_arg_count),\n                           JS_PROP_CONFIGURABLE);\n\n    if (is_computed_name) {\n        if (JS_DefineObjectNameComputed(ctx, ctor, sp[-3],\n                                        JS_PROP_CONFIGURABLE) < 0)\n            goto fail;\n    } else {\n        if (JS_DefineObjectName(ctx, ctor, class_name, JS_PROP_CONFIGURABLE) < 0)\n            goto fail;\n    }\n\n    /* the constructor property must be first. It can be overriden by\n       computed property names */\n    if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,\n                               JS_DupValue(ctx, ctor),\n                               JS_PROP_CONFIGURABLE |\n                               JS_PROP_WRITABLE | JS_PROP_THROW) < 0)\n        goto fail;\n    /* set the prototype property */\n    if (JS_DefinePropertyValue(ctx, ctor, JS_ATOM_prototype,\n                               JS_DupValue(ctx, proto), JS_PROP_THROW) < 0)\n        goto fail;\n    set_cycle_flag(ctx, ctor);\n    set_cycle_flag(ctx, proto);\n\n    JS_FreeValue(ctx, parent_proto);\n    JS_FreeValue(ctx, parent_class);\n\n    sp[-2] = ctor;\n    sp[-1] = proto;\n    return 0;\n fail:\n    JS_FreeValue(ctx, parent_class);\n    JS_FreeValue(ctx, parent_proto);\n    JS_FreeValue(ctx, bfunc);\n    JS_FreeValue(ctx, proto);\n    JS_FreeValue(ctx, ctor);\n    sp[-2] = JS_UNDEFINED;\n    sp[-1] = JS_UNDEFINED;\n    return -1;\n}\n\nstatic void close_var_ref(JSRuntime *rt, JSStackFrame *sf, JSVarRef *var_ref)\n{\n    if (sf->js_mode & JS_MODE_ASYNC) {\n        JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);\n        async_func_free(rt, async_func);\n    }\n    var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue);\n    var_ref->pvalue = &var_ref->value;\n    /* the reference is no longer to a local variable */\n    var_ref->is_detached = TRUE;\n}\n\nstatic void close_var_refs(JSRuntime *rt, JSFunctionBytecode *b, JSStackFrame *sf)\n{\n    JSVarRef *var_ref;\n    int i;\n\n    for(i = 0; i < b->var_ref_count; i++) {\n        var_ref = sf->var_refs[i];\n        if (var_ref)\n            close_var_ref(rt, sf, var_ref);\n    }\n}\n\nstatic void close_lexical_var(JSContext *ctx, JSFunctionBytecode *b,\n                              JSStackFrame *sf, int var_idx)\n{\n    JSVarRef *var_ref;\n    int var_ref_idx;\n    \n    var_ref_idx = b->vardefs[b->arg_count + var_idx].var_ref_idx;\n    var_ref = sf->var_refs[var_ref_idx];\n    if (var_ref) {\n        close_var_ref(ctx->rt, sf, var_ref);\n        sf->var_refs[var_ref_idx] = NULL;\n    }\n}\n\n#define JS_CALL_FLAG_COPY_ARGV   (1 << 1)\n#define JS_CALL_FLAG_GENERATOR   (1 << 2)\n\nstatic JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,\n                                  JSValueConst this_obj,\n                                  int argc, JSValueConst *argv, int flags)\n{\n    JSRuntime *rt = ctx->rt;\n    JSCFunctionType func;\n    JSObject *p;\n    JSStackFrame sf_s, *sf = &sf_s, *prev_sf;\n    JSValue ret_val;\n    JSValueConst *arg_buf;\n    int arg_count, i;\n    JSCFunctionEnum cproto;\n\n    p = JS_VALUE_GET_OBJ(func_obj);\n    cproto = p->u.cfunc.cproto;\n    arg_count = p->u.cfunc.length;\n\n    /* better to always check stack overflow */\n    if (js_check_stack_overflow(rt, sizeof(arg_buf[0]) * arg_count))\n        return JS_ThrowStackOverflow(ctx);\n\n    prev_sf = rt->current_stack_frame;\n    sf->prev_frame = prev_sf;\n    rt->current_stack_frame = sf;\n    ctx = p->u.cfunc.realm; /* change the current realm */\n    sf->js_mode = 0;\n    sf->cur_func = (JSValue)func_obj;\n    sf->arg_count = argc;\n    arg_buf = argv;\n\n    if (unlikely(argc < arg_count)) {\n        /* ensure that at least argc_count arguments are readable */\n        arg_buf = alloca(sizeof(arg_buf[0]) * arg_count);\n        for(i = 0; i < argc; i++)\n            arg_buf[i] = argv[i];\n        for(i = argc; i < arg_count; i++)\n            arg_buf[i] = JS_UNDEFINED;\n        sf->arg_count = arg_count;\n    }\n    sf->arg_buf = (JSValue*)arg_buf;\n\n    func = p->u.cfunc.c_function;\n    switch(cproto) {\n    case JS_CFUNC_constructor:\n    case JS_CFUNC_constructor_or_func:\n        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {\n            if (cproto == JS_CFUNC_constructor) {\n            not_a_constructor:\n                ret_val = JS_ThrowTypeError(ctx, \"must be called with new\");\n                break;\n            } else {\n                this_obj = JS_UNDEFINED;\n            }\n        }\n        /* here this_obj is new_target */\n        /* fall thru */\n    case JS_CFUNC_generic:\n        ret_val = func.generic(ctx, this_obj, argc, arg_buf);\n        break;\n    case JS_CFUNC_constructor_magic:\n    case JS_CFUNC_constructor_or_func_magic:\n        if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {\n            if (cproto == JS_CFUNC_constructor_magic) {\n                goto not_a_constructor;\n            } else {\n                this_obj = JS_UNDEFINED;\n            }\n        }\n        /* fall thru */\n    case JS_CFUNC_generic_magic:\n        ret_val = func.generic_magic(ctx, this_obj, argc, arg_buf,\n                                     p->u.cfunc.magic);\n        break;\n    case JS_CFUNC_getter:\n        ret_val = func.getter(ctx, this_obj);\n        break;\n    case JS_CFUNC_setter:\n        ret_val = func.setter(ctx, this_obj, arg_buf[0]);\n        break;\n    case JS_CFUNC_getter_magic:\n        ret_val = func.getter_magic(ctx, this_obj, p->u.cfunc.magic);\n        break;\n    case JS_CFUNC_setter_magic:\n        ret_val = func.setter_magic(ctx, this_obj, arg_buf[0], p->u.cfunc.magic);\n        break;\n    case JS_CFUNC_f_f:\n        {\n            double d1;\n\n            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {\n                ret_val = JS_EXCEPTION;\n                break;\n            }\n            ret_val = JS_NewFloat64(ctx, func.f_f(d1));\n        }\n        break;\n    case JS_CFUNC_f_f_f:\n        {\n            double d1, d2;\n\n            if (unlikely(JS_ToFloat64(ctx, &d1, arg_buf[0]))) {\n                ret_val = JS_EXCEPTION;\n                break;\n            }\n            if (unlikely(JS_ToFloat64(ctx, &d2, arg_buf[1]))) {\n                ret_val = JS_EXCEPTION;\n                break;\n            }\n            ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));\n        }\n        break;\n    case JS_CFUNC_iterator_next:\n        {\n            int done;\n            ret_val = func.iterator_next(ctx, this_obj, argc, arg_buf,\n                                         &done, p->u.cfunc.magic);\n            if (!JS_IsException(ret_val) && done != 2) {\n                ret_val = js_create_iterator_result(ctx, ret_val, done);\n            }\n        }\n        break;\n    default:\n        abort();\n    }\n\n    rt->current_stack_frame = sf->prev_frame;\n    return ret_val;\n}\n\nstatic JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj,\n                                      JSValueConst this_obj,\n                                      int argc, JSValueConst *argv, int flags)\n{\n    JSObject *p;\n    JSBoundFunction *bf;\n    JSValueConst *arg_buf, new_target;\n    int arg_count, i;\n\n    p = JS_VALUE_GET_OBJ(func_obj);\n    bf = p->u.bound_function;\n    arg_count = bf->argc + argc;\n    if (js_check_stack_overflow(ctx->rt, sizeof(JSValue) * arg_count))\n        return JS_ThrowStackOverflow(ctx);\n    arg_buf = alloca(sizeof(JSValue) * arg_count);\n    for(i = 0; i < bf->argc; i++) {\n        arg_buf[i] = bf->argv[i];\n    }\n    for(i = 0; i < argc; i++) {\n        arg_buf[bf->argc + i] = argv[i];\n    }\n    if (flags & JS_CALL_FLAG_CONSTRUCTOR) {\n        new_target = this_obj;\n        if (js_same_value(ctx, func_obj, new_target))\n            new_target = bf->func_obj;\n        return JS_CallConstructor2(ctx, bf->func_obj, new_target,\n                                   arg_count, arg_buf);\n    } else {\n        return JS_Call(ctx, bf->func_obj, bf->this_val,\n                       arg_count, arg_buf);\n    }\n}\n\n/* argument of OP_special_object */\ntypedef enum {\n    OP_SPECIAL_OBJECT_ARGUMENTS,\n    OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS,\n    OP_SPECIAL_OBJECT_THIS_FUNC,\n    OP_SPECIAL_OBJECT_NEW_TARGET,\n    OP_SPECIAL_OBJECT_HOME_OBJECT,\n    OP_SPECIAL_OBJECT_VAR_OBJECT,\n    OP_SPECIAL_OBJECT_IMPORT_META,\n} OPSpecialObjectEnum;\n\n#define FUNC_RET_AWAIT         0\n#define FUNC_RET_YIELD         1\n#define FUNC_RET_YIELD_STAR    2\n#define FUNC_RET_INITIAL_YIELD 3\n\n/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */\nstatic JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,\n                               JSValueConst this_obj, JSValueConst new_target,\n                               int argc, JSValue *argv, int flags)\n{\n    JSRuntime *rt = caller_ctx->rt;\n    JSContext *ctx;\n    JSObject *p;\n    JSFunctionBytecode *b;\n    JSStackFrame sf_s, *sf = &sf_s;\n    const uint8_t *pc;\n    int opcode, arg_allocated_size, i;\n    JSValue *local_buf, *stack_buf, *var_buf, *arg_buf, *sp, ret_val, *pval;\n    JSVarRef **var_refs;\n    size_t alloca_size;\n\n#if !DIRECT_DISPATCH\n#define SWITCH(pc)      switch (opcode = *pc++)\n#define CASE(op)        case op\n#define DEFAULT         default\n#define BREAK           break\n#else\n    static const void * const dispatch_table[256] = {\n#define DEF(id, size, n_pop, n_push, f) && case_OP_ ## id,\n#if SHORT_OPCODES\n#define def(id, size, n_pop, n_push, f)\n#else\n#define def(id, size, n_pop, n_push, f) && case_default,\n#endif\n#include \"quickjs-opcode.h\"\n        [ OP_COUNT ... 255 ] = &&case_default\n    };\n#define SWITCH(pc)      goto *dispatch_table[opcode = *pc++];\n#define CASE(op)        case_ ## op\n#define DEFAULT         case_default\n#define BREAK           SWITCH(pc)\n#endif\n\n    if (js_poll_interrupts(caller_ctx))\n        return JS_EXCEPTION;\n    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)) {\n        if (flags & JS_CALL_FLAG_GENERATOR) {\n            JSAsyncFunctionState *s = JS_VALUE_GET_PTR(func_obj);\n            /* func_obj get contains a pointer to JSFuncAsyncState */\n            /* the stack frame is already allocated */\n            sf = &s->frame;\n            p = JS_VALUE_GET_OBJ(sf->cur_func);\n            b = p->u.func.function_bytecode;\n            ctx = b->realm;\n            var_refs = p->u.func.var_refs;\n            local_buf = arg_buf = sf->arg_buf;\n            var_buf = sf->var_buf;\n            stack_buf = sf->var_buf + b->var_count;\n            sp = sf->cur_sp;\n            sf->cur_sp = NULL; /* cur_sp is NULL if the function is running */\n            pc = sf->cur_pc;\n            sf->prev_frame = rt->current_stack_frame;\n            rt->current_stack_frame = sf;\n            if (s->throw_flag)\n                goto exception;\n            else\n                goto restart;\n        } else {\n            goto not_a_function;\n        }\n    }\n    p = JS_VALUE_GET_OBJ(func_obj);\n    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {\n        JSClassCall *call_func;\n        call_func = rt->class_array[p->class_id].call;\n        if (!call_func) {\n        not_a_function:\n            return JS_ThrowTypeError(caller_ctx, \"not a function\");\n        }\n        return call_func(caller_ctx, func_obj, this_obj, argc,\n                         (JSValueConst *)argv, flags);\n    }\n    b = p->u.func.function_bytecode;\n\n    if (unlikely(argc < b->arg_count || (flags & JS_CALL_FLAG_COPY_ARGV))) {\n        arg_allocated_size = b->arg_count;\n    } else {\n        arg_allocated_size = 0;\n    }\n\n    alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +\n                                     b->stack_size) +\n        sizeof(JSVarRef *) * b->var_ref_count;\n    if (js_check_stack_overflow(rt, alloca_size))\n        return JS_ThrowStackOverflow(caller_ctx);\n\n    sf->js_mode = b->js_mode;\n    arg_buf = argv;\n    sf->arg_count = argc;\n    sf->cur_func = (JSValue)func_obj;\n    var_refs = p->u.func.var_refs;\n\n    local_buf = alloca(alloca_size);\n    if (unlikely(arg_allocated_size)) {\n        int n = min_int(argc, b->arg_count);\n        arg_buf = local_buf;\n        for(i = 0; i < n; i++)\n            arg_buf[i] = JS_DupValue(caller_ctx, argv[i]);\n        for(; i < b->arg_count; i++)\n            arg_buf[i] = JS_UNDEFINED;\n        sf->arg_count = b->arg_count;\n    }\n    var_buf = local_buf + arg_allocated_size;\n    sf->var_buf = var_buf;\n    sf->arg_buf = arg_buf;\n\n    for(i = 0; i < b->var_count; i++)\n        var_buf[i] = JS_UNDEFINED;\n\n    stack_buf = var_buf + b->var_count;\n    sf->var_refs = (JSVarRef **)(stack_buf + b->stack_size);\n    for(i = 0; i < b->var_ref_count; i++)\n        sf->var_refs[i] = NULL;\n    sp = stack_buf;\n    pc = b->byte_code_buf;\n    sf->prev_frame = rt->current_stack_frame;\n    rt->current_stack_frame = sf;\n    ctx = b->realm; /* set the current realm */\n\n restart:\n    for(;;) {\n        int call_argc;\n        JSValue *call_argv;\n\n        SWITCH(pc) {\n        CASE(OP_push_i32):\n            *sp++ = JS_NewInt32(ctx, get_u32(pc));\n            pc += 4;\n            BREAK;\n        CASE(OP_push_bigint_i32):\n            *sp++ = __JS_NewShortBigInt(ctx, (int)get_u32(pc));\n            pc += 4;\n            BREAK;\n        CASE(OP_push_const):\n            *sp++ = JS_DupValue(ctx, b->cpool[get_u32(pc)]);\n            pc += 4;\n            BREAK;\n#if SHORT_OPCODES\n        CASE(OP_push_minus1):\n        CASE(OP_push_0):\n        CASE(OP_push_1):\n        CASE(OP_push_2):\n        CASE(OP_push_3):\n        CASE(OP_push_4):\n        CASE(OP_push_5):\n        CASE(OP_push_6):\n        CASE(OP_push_7):\n            *sp++ = JS_NewInt32(ctx, opcode - OP_push_0);\n            BREAK;\n        CASE(OP_push_i8):\n            *sp++ = JS_NewInt32(ctx, get_i8(pc));\n            pc += 1;\n            BREAK;\n        CASE(OP_push_i16):\n            *sp++ = JS_NewInt32(ctx, get_i16(pc));\n            pc += 2;\n            BREAK;\n        CASE(OP_push_const8):\n            *sp++ = JS_DupValue(ctx, b->cpool[*pc++]);\n            BREAK;\n        CASE(OP_fclosure8):\n            *sp++ = js_closure(ctx, JS_DupValue(ctx, b->cpool[*pc++]), var_refs, sf, FALSE);\n            if (unlikely(JS_IsException(sp[-1])))\n                goto exception;\n            BREAK;\n        CASE(OP_push_empty_string):\n            *sp++ = JS_AtomToString(ctx, JS_ATOM_empty_string);\n            BREAK;\n#endif\n        CASE(OP_push_atom_value):\n            *sp++ = JS_AtomToValue(ctx, get_u32(pc));\n            pc += 4;\n            BREAK;\n        CASE(OP_undefined):\n            *sp++ = JS_UNDEFINED;\n            BREAK;\n        CASE(OP_null):\n            *sp++ = JS_NULL;\n            BREAK;\n        CASE(OP_push_this):\n            /* OP_push_this is only called at the start of a function */\n            {\n                JSValue val;\n                if (!(b->js_mode & JS_MODE_STRICT)) {\n                    uint32_t tag = JS_VALUE_GET_TAG(this_obj);\n                    if (likely(tag == JS_TAG_OBJECT))\n                        goto normal_this;\n                    if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED) {\n                        val = JS_DupValue(ctx, ctx->global_obj);\n                    } else {\n                        val = JS_ToObject(ctx, this_obj);\n                        if (JS_IsException(val))\n                            goto exception;\n                    }\n                } else {\n                normal_this:\n                    val = JS_DupValue(ctx, this_obj);\n                }\n                *sp++ = val;\n            }\n            BREAK;\n        CASE(OP_push_false):\n            *sp++ = JS_FALSE;\n            BREAK;\n        CASE(OP_push_true):\n            *sp++ = JS_TRUE;\n            BREAK;\n        CASE(OP_object):\n            *sp++ = JS_NewObject(ctx);\n            if (unlikely(JS_IsException(sp[-1])))\n                goto exception;\n            BREAK;\n        CASE(OP_special_object):\n            {\n                int arg = *pc++;\n                switch(arg) {\n                case OP_SPECIAL_OBJECT_ARGUMENTS:\n                    *sp++ = js_build_arguments(ctx, argc, (JSValueConst *)argv);\n                    if (unlikely(JS_IsException(sp[-1])))\n                        goto exception;\n                    break;\n                case OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS:\n                    *sp++ = js_build_mapped_arguments(ctx, argc, (JSValueConst *)argv,\n                                                      sf, min_int(argc, b->arg_count));\n                    if (unlikely(JS_IsException(sp[-1])))\n                        goto exception;\n                    break;\n                case OP_SPECIAL_OBJECT_THIS_FUNC:\n                    *sp++ = JS_DupValue(ctx, sf->cur_func);\n                    break;\n                case OP_SPECIAL_OBJECT_NEW_TARGET:\n                    *sp++ = JS_DupValue(ctx, new_target);\n                    break;\n                case OP_SPECIAL_OBJECT_HOME_OBJECT:\n                    {\n                        JSObject *p1;\n                        p1 = p->u.func.home_object;\n                        if (unlikely(!p1))\n                            *sp++ = JS_UNDEFINED;\n                        else\n                            *sp++ = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));\n                    }\n                    break;\n                case OP_SPECIAL_OBJECT_VAR_OBJECT:\n                    *sp++ = JS_NewObjectProto(ctx, JS_NULL);\n                    if (unlikely(JS_IsException(sp[-1])))\n                        goto exception;\n                    break;\n                case OP_SPECIAL_OBJECT_IMPORT_META:\n                    *sp++ = js_import_meta(ctx);\n                    if (unlikely(JS_IsException(sp[-1])))\n                        goto exception;\n                    break;\n                default:\n                    abort();\n                }\n            }\n            BREAK;\n        CASE(OP_rest):\n            {\n                int first = get_u16(pc);\n                pc += 2;\n                first = min_int(first, argc);\n                *sp++ = js_create_array(ctx, argc - first, (JSValueConst *)(argv + first));\n                if (unlikely(JS_IsException(sp[-1])))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_drop):\n            JS_FreeValue(ctx, sp[-1]);\n            sp--;\n            BREAK;\n        CASE(OP_nip):\n            JS_FreeValue(ctx, sp[-2]);\n            sp[-2] = sp[-1];\n            sp--;\n            BREAK;\n        CASE(OP_nip1): /* a b c -> b c */\n            JS_FreeValue(ctx, sp[-3]);\n            sp[-3] = sp[-2];\n            sp[-2] = sp[-1];\n            sp--;\n            BREAK;\n        CASE(OP_dup):\n            sp[0] = JS_DupValue(ctx, sp[-1]);\n            sp++;\n            BREAK;\n        CASE(OP_dup2): /* a b -> a b a b */\n            sp[0] = JS_DupValue(ctx, sp[-2]);\n            sp[1] = JS_DupValue(ctx, sp[-1]);\n            sp += 2;\n            BREAK;\n        CASE(OP_dup3): /* a b c -> a b c a b c */\n            sp[0] = JS_DupValue(ctx, sp[-3]);\n            sp[1] = JS_DupValue(ctx, sp[-2]);\n            sp[2] = JS_DupValue(ctx, sp[-1]);\n            sp += 3;\n            BREAK;\n        CASE(OP_dup1): /* a b -> a a b */\n            sp[0] = sp[-1];\n            sp[-1] = JS_DupValue(ctx, sp[-2]);\n            sp++;\n            BREAK;\n        CASE(OP_insert2): /* obj a -> a obj a (dup_x1) */\n            sp[0] = sp[-1];\n            sp[-1] = sp[-2];\n            sp[-2] = JS_DupValue(ctx, sp[0]);\n            sp++;\n            BREAK;\n        CASE(OP_insert3): /* obj prop a -> a obj prop a (dup_x2) */\n            sp[0] = sp[-1];\n            sp[-1] = sp[-2];\n            sp[-2] = sp[-3];\n            sp[-3] = JS_DupValue(ctx, sp[0]);\n            sp++;\n            BREAK;\n        CASE(OP_insert4): /* this obj prop a -> a this obj prop a */\n            sp[0] = sp[-1];\n            sp[-1] = sp[-2];\n            sp[-2] = sp[-3];\n            sp[-3] = sp[-4];\n            sp[-4] = JS_DupValue(ctx, sp[0]);\n            sp++;\n            BREAK;\n        CASE(OP_perm3): /* obj a b -> a obj b (213) */\n            {\n                JSValue tmp;\n                tmp = sp[-2];\n                sp[-2] = sp[-3];\n                sp[-3] = tmp;\n            }\n            BREAK;\n        CASE(OP_rot3l): /* x a b -> a b x (231) */\n            {\n                JSValue tmp;\n                tmp = sp[-3];\n                sp[-3] = sp[-2];\n                sp[-2] = sp[-1];\n                sp[-1] = tmp;\n            }\n            BREAK;\n        CASE(OP_rot4l): /* x a b c -> a b c x */\n            {\n                JSValue tmp;\n                tmp = sp[-4];\n                sp[-4] = sp[-3];\n                sp[-3] = sp[-2];\n                sp[-2] = sp[-1];\n                sp[-1] = tmp;\n            }\n            BREAK;\n        CASE(OP_rot5l): /* x a b c d -> a b c d x */\n            {\n                JSValue tmp;\n                tmp = sp[-5];\n                sp[-5] = sp[-4];\n                sp[-4] = sp[-3];\n                sp[-3] = sp[-2];\n                sp[-2] = sp[-1];\n                sp[-1] = tmp;\n            }\n            BREAK;\n        CASE(OP_rot3r): /* a b x -> x a b (312) */\n            {\n                JSValue tmp;\n                tmp = sp[-1];\n                sp[-1] = sp[-2];\n                sp[-2] = sp[-3];\n                sp[-3] = tmp;\n            }\n            BREAK;\n        CASE(OP_perm4): /* obj prop a b -> a obj prop b */\n            {\n                JSValue tmp;\n                tmp = sp[-2];\n                sp[-2] = sp[-3];\n                sp[-3] = sp[-4];\n                sp[-4] = tmp;\n            }\n            BREAK;\n        CASE(OP_perm5): /* this obj prop a b -> a this obj prop b */\n            {\n                JSValue tmp;\n                tmp = sp[-2];\n                sp[-2] = sp[-3];\n                sp[-3] = sp[-4];\n                sp[-4] = sp[-5];\n                sp[-5] = tmp;\n            }\n            BREAK;\n        CASE(OP_swap): /* a b -> b a */\n            {\n                JSValue tmp;\n                tmp = sp[-2];\n                sp[-2] = sp[-1];\n                sp[-1] = tmp;\n            }\n            BREAK;\n        CASE(OP_swap2): /* a b c d -> c d a b */\n            {\n                JSValue tmp1, tmp2;\n                tmp1 = sp[-4];\n                tmp2 = sp[-3];\n                sp[-4] = sp[-2];\n                sp[-3] = sp[-1];\n                sp[-2] = tmp1;\n                sp[-1] = tmp2;\n            }\n            BREAK;\n\n        CASE(OP_fclosure):\n            {\n                JSValue bfunc = JS_DupValue(ctx, b->cpool[get_u32(pc)]);\n                pc += 4;\n                *sp++ = js_closure(ctx, bfunc, var_refs, sf, FALSE);\n                if (unlikely(JS_IsException(sp[-1])))\n                    goto exception;\n            }\n            BREAK;\n#if SHORT_OPCODES\n        CASE(OP_call0):\n        CASE(OP_call1):\n        CASE(OP_call2):\n        CASE(OP_call3):\n            call_argc = opcode - OP_call0;\n            goto has_call_argc;\n#endif\n        CASE(OP_call):\n        CASE(OP_tail_call):\n            {\n                call_argc = get_u16(pc);\n                pc += 2;\n                goto has_call_argc;\n            has_call_argc:\n                call_argv = sp - call_argc;\n                sf->cur_pc = pc;\n                ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,\n                                          JS_UNDEFINED, call_argc, call_argv, 0);\n                if (unlikely(JS_IsException(ret_val)))\n                    goto exception;\n                if (opcode == OP_tail_call)\n                    goto done;\n                for(i = -1; i < call_argc; i++)\n                    JS_FreeValue(ctx, call_argv[i]);\n                sp -= call_argc + 1;\n                *sp++ = ret_val;\n            }\n            BREAK;\n        CASE(OP_call_constructor):\n            {\n                call_argc = get_u16(pc);\n                pc += 2;\n                call_argv = sp - call_argc;\n                sf->cur_pc = pc;\n                ret_val = JS_CallConstructorInternal(ctx, call_argv[-2],\n                                                     call_argv[-1],\n                                                     call_argc, call_argv, 0);\n                if (unlikely(JS_IsException(ret_val)))\n                    goto exception;\n                for(i = -2; i < call_argc; i++)\n                    JS_FreeValue(ctx, call_argv[i]);\n                sp -= call_argc + 2;\n                *sp++ = ret_val;\n            }\n            BREAK;\n        CASE(OP_call_method):\n        CASE(OP_tail_call_method):\n            {\n                call_argc = get_u16(pc);\n                pc += 2;\n                call_argv = sp - call_argc;\n                sf->cur_pc = pc;\n                ret_val = JS_CallInternal(ctx, call_argv[-1], call_argv[-2],\n                                          JS_UNDEFINED, call_argc, call_argv, 0);\n                if (unlikely(JS_IsException(ret_val)))\n                    goto exception;\n                if (opcode == OP_tail_call_method)\n                    goto done;\n                for(i = -2; i < call_argc; i++)\n                    JS_FreeValue(ctx, call_argv[i]);\n                sp -= call_argc + 2;\n                *sp++ = ret_val;\n            }\n            BREAK;\n        CASE(OP_array_from):\n            call_argc = get_u16(pc);\n            pc += 2;\n            ret_val = js_create_array_free(ctx, call_argc, sp - call_argc);\n            sp -= call_argc;\n            if (unlikely(JS_IsException(ret_val)))\n                goto exception;\n            *sp++ = ret_val;\n            BREAK;\n\n        CASE(OP_apply):\n            {\n                int magic;\n                magic = get_u16(pc);\n                pc += 2;\n                sf->cur_pc = pc;\n\n                ret_val = js_function_apply(ctx, sp[-3], 2, (JSValueConst *)&sp[-2], magic);\n                if (unlikely(JS_IsException(ret_val)))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-3]);\n                JS_FreeValue(ctx, sp[-2]);\n                JS_FreeValue(ctx, sp[-1]);\n                sp -= 3;\n                *sp++ = ret_val;\n            }\n            BREAK;\n        CASE(OP_return):\n            ret_val = *--sp;\n            goto done;\n        CASE(OP_return_undef):\n            ret_val = JS_UNDEFINED;\n            goto done;\n\n        CASE(OP_check_ctor_return):\n            /* return TRUE if 'this' should be returned */\n            if (!JS_IsObject(sp[-1])) {\n                if (!JS_IsUndefined(sp[-1])) {\n                    JS_ThrowTypeError(caller_ctx, \"derived class constructor must return an object or undefined\");\n                    goto exception;\n                }\n                sp[0] = JS_TRUE;\n            } else {\n                sp[0] = JS_FALSE;\n            }\n            sp++;\n            BREAK;\n        CASE(OP_check_ctor):\n            if (JS_IsUndefined(new_target)) {\n            non_ctor_call:\n                JS_ThrowTypeError(ctx, \"class constructors must be invoked with 'new'\");\n                goto exception;\n            }\n            BREAK;\n        CASE(OP_init_ctor):\n            {\n                JSValue super, ret;\n                sf->cur_pc = pc;\n                if (JS_IsUndefined(new_target))\n                    goto non_ctor_call;\n                super = JS_GetPrototype(ctx, func_obj);\n                if (JS_IsException(super))\n                    goto exception;\n                ret = JS_CallConstructor2(ctx, super, new_target, argc, (JSValueConst *)argv);\n                JS_FreeValue(ctx, super);\n                if (JS_IsException(ret))\n                    goto exception;\n                *sp++ = ret;\n            }\n            BREAK;\n        CASE(OP_check_brand):\n            {\n                int ret = JS_CheckBrand(ctx, sp[-2], sp[-1]);\n                if (ret < 0)\n                    goto exception;\n                if (!ret) {\n                    JS_ThrowTypeError(ctx, \"invalid brand on object\");\n                    goto exception;\n                }\n            }\n            BREAK;\n        CASE(OP_add_brand):\n            if (JS_AddBrand(ctx, sp[-2], sp[-1]) < 0)\n                goto exception;\n            JS_FreeValue(ctx, sp[-2]);\n            JS_FreeValue(ctx, sp[-1]);\n            sp -= 2;\n            BREAK;\n\n        CASE(OP_throw):\n            JS_Throw(ctx, *--sp);\n            goto exception;\n\n        CASE(OP_throw_error):\n#define JS_THROW_VAR_RO             0\n#define JS_THROW_VAR_REDECL         1\n#define JS_THROW_VAR_UNINITIALIZED  2\n#define JS_THROW_ERROR_DELETE_SUPER   3\n#define JS_THROW_ERROR_ITERATOR_THROW 4\n            {\n                JSAtom atom;\n                int type;\n                atom = get_u32(pc);\n                type = pc[4];\n                pc += 5;\n                if (type == JS_THROW_VAR_RO)\n                    JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, atom);\n                else\n                if (type == JS_THROW_VAR_REDECL)\n                    JS_ThrowSyntaxErrorVarRedeclaration(ctx, atom);\n                else\n                if (type == JS_THROW_VAR_UNINITIALIZED)\n                    JS_ThrowReferenceErrorUninitialized(ctx, atom);\n                else\n                if (type == JS_THROW_ERROR_DELETE_SUPER)\n                    JS_ThrowReferenceError(ctx, \"unsupported reference to 'super'\");\n                else\n                if (type == JS_THROW_ERROR_ITERATOR_THROW)\n                    JS_ThrowTypeError(ctx, \"iterator does not have a throw method\");\n                else\n                    JS_ThrowInternalError(ctx, \"invalid throw var type %d\", type);\n            }\n            goto exception;\n\n        CASE(OP_eval):\n            {\n                JSValueConst obj;\n                int scope_idx;\n                call_argc = get_u16(pc);\n                scope_idx = get_u16(pc + 2) + ARG_SCOPE_END;\n                pc += 4;\n                call_argv = sp - call_argc;\n                sf->cur_pc = pc;\n                if (js_same_value(ctx, call_argv[-1], ctx->eval_obj)) {\n                    if (call_argc >= 1)\n                        obj = call_argv[0];\n                    else\n                        obj = JS_UNDEFINED;\n                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,\n                                            JS_EVAL_TYPE_DIRECT, scope_idx);\n                } else {\n                    ret_val = JS_CallInternal(ctx, call_argv[-1], JS_UNDEFINED,\n                                              JS_UNDEFINED, call_argc, call_argv, 0);\n                }\n                if (unlikely(JS_IsException(ret_val)))\n                    goto exception;\n                for(i = -1; i < call_argc; i++)\n                    JS_FreeValue(ctx, call_argv[i]);\n                sp -= call_argc + 1;\n                *sp++ = ret_val;\n            }\n            BREAK;\n            /* could merge with OP_apply */\n        CASE(OP_apply_eval):\n            {\n                int scope_idx;\n                uint32_t len;\n                JSValue *tab;\n                JSValueConst obj;\n\n                scope_idx = get_u16(pc) + ARG_SCOPE_END;\n                pc += 2;\n                sf->cur_pc = pc;\n                tab = build_arg_list(ctx, &len, sp[-1]);\n                if (!tab)\n                    goto exception;\n                if (js_same_value(ctx, sp[-2], ctx->eval_obj)) {\n                    if (len >= 1)\n                        obj = tab[0];\n                    else\n                        obj = JS_UNDEFINED;\n                    ret_val = JS_EvalObject(ctx, JS_UNDEFINED, obj,\n                                            JS_EVAL_TYPE_DIRECT, scope_idx);\n                } else {\n                    ret_val = JS_Call(ctx, sp[-2], JS_UNDEFINED, len,\n                                      (JSValueConst *)tab);\n                }\n                free_arg_list(ctx, tab, len);\n                if (unlikely(JS_IsException(ret_val)))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-2]);\n                JS_FreeValue(ctx, sp[-1]);\n                sp -= 2;\n                *sp++ = ret_val;\n            }\n            BREAK;\n\n        CASE(OP_regexp):\n            {\n                sp[-2] = JS_NewRegexp(ctx, sp[-2], sp[-1]);\n                sp--;\n                if (JS_IsException(sp[-1]))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_get_super):\n            {\n                JSValue proto;\n                sf->cur_pc = pc;\n                proto = JS_GetPrototype(ctx, sp[-1]);\n                if (JS_IsException(proto))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-1]);\n                sp[-1] = proto;\n            }\n            BREAK;\n\n        CASE(OP_import):\n            {\n                JSValue val;\n                sf->cur_pc = pc;\n                val = js_dynamic_import(ctx, sp[-2], sp[-1]);\n                if (JS_IsException(val))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-2]);\n                JS_FreeValue(ctx, sp[-1]);\n                sp--;\n                sp[-1] = val;\n            }\n            BREAK;\n\n        CASE(OP_get_var_undef):\n        CASE(OP_get_var):\n            {\n                int idx;\n                JSValue val;\n                idx = get_u16(pc);\n                pc += 2;\n                val = *var_refs[idx]->pvalue;\n                if (unlikely(JS_IsUninitialized(val))) {\n                    JSClosureVar *cv = &b->closure_var[idx];\n                    if (cv->is_lexical) {\n                        JS_ThrowReferenceErrorUninitialized(ctx, cv->var_name);\n                        goto exception;\n                    } else {\n                        sf->cur_pc = pc;\n                        sp[0] = JS_GetPropertyInternal(ctx, ctx->global_obj,\n                                                       cv->var_name,\n                                                       ctx->global_obj,\n                                                       opcode - OP_get_var_undef);\n                        if (JS_IsException(sp[0]))\n                            goto exception;\n                    }\n                } else {\n                    sp[0] = JS_DupValue(ctx, val);\n                }\n                sp++;\n            }\n            BREAK;\n\n        CASE(OP_put_var):\n        CASE(OP_put_var_init):\n            {\n                int idx, ret;\n                JSVarRef *var_ref;\n                idx = get_u16(pc);\n                pc += 2;\n                var_ref = var_refs[idx];\n                if (unlikely(JS_IsUninitialized(*var_ref->pvalue) ||\n                             var_ref->is_const)) {\n                    JSClosureVar *cv = &b->closure_var[idx];\n                    if (var_ref->is_lexical) {\n                        if (opcode == OP_put_var_init)\n                            goto put_var_ok;\n                        if (JS_IsUninitialized(*var_ref->pvalue))\n                            JS_ThrowReferenceErrorUninitialized(ctx, cv->var_name);\n                        else\n                            JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, cv->var_name);\n                        goto exception;\n                    } else {\n                        sf->cur_pc = pc;\n                        ret = JS_HasProperty(ctx, ctx->global_obj, cv->var_name);\n                        if (ret < 0)\n                            goto exception;\n                        if (ret == 0 && is_strict_mode(ctx)) {\n                            JS_ThrowReferenceErrorNotDefined(ctx, cv->var_name);\n                            goto exception;\n                        }\n                        ret = JS_SetPropertyInternal(ctx, ctx->global_obj, cv->var_name, sp[-1],\n                                                     ctx->global_obj, JS_PROP_THROW_STRICT);\n                        sp--;\n                        if (ret < 0)\n                            goto exception;\n                    }\n                } else {\n                put_var_ok:\n                   set_value(ctx, var_ref->pvalue, sp[-1]);\n                   sp--;\n                }\n            }\n            BREAK;\n        CASE(OP_get_loc):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                sp[0] = JS_DupValue(ctx, var_buf[idx]);\n                sp++;\n            }\n            BREAK;\n        CASE(OP_put_loc):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                set_value(ctx, &var_buf[idx], sp[-1]);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_set_loc):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));\n            }\n            BREAK;\n        CASE(OP_get_arg):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                sp[0] = JS_DupValue(ctx, arg_buf[idx]);\n                sp++;\n            }\n            BREAK;\n        CASE(OP_put_arg):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                set_value(ctx, &arg_buf[idx], sp[-1]);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_set_arg):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                set_value(ctx, &arg_buf[idx], JS_DupValue(ctx, sp[-1]));\n            }\n            BREAK;\n\n#if SHORT_OPCODES\n        CASE(OP_get_loc8): *sp++ = JS_DupValue(ctx, var_buf[*pc++]); BREAK;\n        CASE(OP_put_loc8): set_value(ctx, &var_buf[*pc++], *--sp); BREAK;\n        CASE(OP_set_loc8): set_value(ctx, &var_buf[*pc++], JS_DupValue(ctx, sp[-1])); BREAK;\n\n        CASE(OP_get_loc0): *sp++ = JS_DupValue(ctx, var_buf[0]); BREAK;\n        CASE(OP_get_loc1): *sp++ = JS_DupValue(ctx, var_buf[1]); BREAK;\n        CASE(OP_get_loc2): *sp++ = JS_DupValue(ctx, var_buf[2]); BREAK;\n        CASE(OP_get_loc3): *sp++ = JS_DupValue(ctx, var_buf[3]); BREAK;\n        CASE(OP_put_loc0): set_value(ctx, &var_buf[0], *--sp); BREAK;\n        CASE(OP_put_loc1): set_value(ctx, &var_buf[1], *--sp); BREAK;\n        CASE(OP_put_loc2): set_value(ctx, &var_buf[2], *--sp); BREAK;\n        CASE(OP_put_loc3): set_value(ctx, &var_buf[3], *--sp); BREAK;\n        CASE(OP_set_loc0): set_value(ctx, &var_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_loc1): set_value(ctx, &var_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_loc2): set_value(ctx, &var_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_loc3): set_value(ctx, &var_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_get_arg0): *sp++ = JS_DupValue(ctx, arg_buf[0]); BREAK;\n        CASE(OP_get_arg1): *sp++ = JS_DupValue(ctx, arg_buf[1]); BREAK;\n        CASE(OP_get_arg2): *sp++ = JS_DupValue(ctx, arg_buf[2]); BREAK;\n        CASE(OP_get_arg3): *sp++ = JS_DupValue(ctx, arg_buf[3]); BREAK;\n        CASE(OP_put_arg0): set_value(ctx, &arg_buf[0], *--sp); BREAK;\n        CASE(OP_put_arg1): set_value(ctx, &arg_buf[1], *--sp); BREAK;\n        CASE(OP_put_arg2): set_value(ctx, &arg_buf[2], *--sp); BREAK;\n        CASE(OP_put_arg3): set_value(ctx, &arg_buf[3], *--sp); BREAK;\n        CASE(OP_set_arg0): set_value(ctx, &arg_buf[0], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_arg1): set_value(ctx, &arg_buf[1], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_arg2): set_value(ctx, &arg_buf[2], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_arg3): set_value(ctx, &arg_buf[3], JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_get_var_ref0): *sp++ = JS_DupValue(ctx, *var_refs[0]->pvalue); BREAK;\n        CASE(OP_get_var_ref1): *sp++ = JS_DupValue(ctx, *var_refs[1]->pvalue); BREAK;\n        CASE(OP_get_var_ref2): *sp++ = JS_DupValue(ctx, *var_refs[2]->pvalue); BREAK;\n        CASE(OP_get_var_ref3): *sp++ = JS_DupValue(ctx, *var_refs[3]->pvalue); BREAK;\n        CASE(OP_put_var_ref0): set_value(ctx, var_refs[0]->pvalue, *--sp); BREAK;\n        CASE(OP_put_var_ref1): set_value(ctx, var_refs[1]->pvalue, *--sp); BREAK;\n        CASE(OP_put_var_ref2): set_value(ctx, var_refs[2]->pvalue, *--sp); BREAK;\n        CASE(OP_put_var_ref3): set_value(ctx, var_refs[3]->pvalue, *--sp); BREAK;\n        CASE(OP_set_var_ref0): set_value(ctx, var_refs[0]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_var_ref1): set_value(ctx, var_refs[1]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_var_ref2): set_value(ctx, var_refs[2]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;\n        CASE(OP_set_var_ref3): set_value(ctx, var_refs[3]->pvalue, JS_DupValue(ctx, sp[-1])); BREAK;\n#endif\n\n        CASE(OP_get_var_ref):\n            {\n                int idx;\n                JSValue val;\n                idx = get_u16(pc);\n                pc += 2;\n                val = *var_refs[idx]->pvalue;\n                sp[0] = JS_DupValue(ctx, val);\n                sp++;\n            }\n            BREAK;\n        CASE(OP_put_var_ref):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_set_var_ref):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                set_value(ctx, var_refs[idx]->pvalue, JS_DupValue(ctx, sp[-1]));\n            }\n            BREAK;\n        CASE(OP_get_var_ref_check):\n            {\n                int idx;\n                JSValue val;\n                idx = get_u16(pc);\n                pc += 2;\n                val = *var_refs[idx]->pvalue;\n                if (unlikely(JS_IsUninitialized(val))) {\n                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);\n                    goto exception;\n                }\n                sp[0] = JS_DupValue(ctx, val);\n                sp++;\n            }\n            BREAK;\n        CASE(OP_put_var_ref_check):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {\n                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);\n                    goto exception;\n                }\n                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_put_var_ref_check_init):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {\n                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);\n                    goto exception;\n                }\n                set_value(ctx, var_refs[idx]->pvalue, sp[-1]);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_set_loc_uninitialized):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                set_value(ctx, &var_buf[idx], JS_UNINITIALIZED);\n            }\n            BREAK;\n        CASE(OP_get_loc_check):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {\n                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);\n                    goto exception;\n                }\n                sp[0] = JS_DupValue(ctx, var_buf[idx]);\n                sp++;\n            }\n            BREAK;\n        CASE(OP_get_loc_checkthis):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {\n                    JS_ThrowReferenceErrorUninitialized2(caller_ctx, b, idx, FALSE);\n                    goto exception;\n                }\n                sp[0] = JS_DupValue(ctx, var_buf[idx]);\n                sp++;\n            }\n            BREAK;\n        CASE(OP_put_loc_check):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {\n                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);\n                    goto exception;\n                }\n                set_value(ctx, &var_buf[idx], sp[-1]);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_set_loc_check):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                if (unlikely(JS_IsUninitialized(var_buf[idx]))) {\n                    JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);\n                    goto exception;\n                }\n                set_value(ctx, &var_buf[idx], JS_DupValue(ctx, sp[-1]));\n            }\n            BREAK;\n        CASE(OP_put_loc_check_init):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                if (unlikely(!JS_IsUninitialized(var_buf[idx]))) {\n                    JS_ThrowReferenceError(ctx, \"'this' can be initialized only once\");\n                    goto exception;\n                }\n                set_value(ctx, &var_buf[idx], sp[-1]);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_close_loc):\n            {\n                int idx;\n                idx = get_u16(pc);\n                pc += 2;\n                close_lexical_var(ctx, b, sf, idx);\n            }\n            BREAK;\n\n        CASE(OP_make_loc_ref):\n        CASE(OP_make_arg_ref):\n        CASE(OP_make_var_ref_ref):\n            {\n                JSVarRef *var_ref;\n                JSProperty *pr;\n                JSAtom atom;\n                int idx;\n                atom = get_u32(pc);\n                idx = get_u16(pc + 4);\n                pc += 6;\n                *sp++ = JS_NewObjectProto(ctx, JS_NULL);\n                if (unlikely(JS_IsException(sp[-1])))\n                    goto exception;\n                if (opcode == OP_make_var_ref_ref) {\n                    var_ref = var_refs[idx];\n                    var_ref->header.ref_count++;\n                } else {\n                    var_ref = get_var_ref(ctx, sf, idx, opcode == OP_make_arg_ref);\n                    if (!var_ref)\n                        goto exception;\n                }\n                pr = add_property(ctx, JS_VALUE_GET_OBJ(sp[-1]), atom,\n                                  JS_PROP_WRITABLE | JS_PROP_VARREF);\n                if (!pr) {\n                    free_var_ref(rt, var_ref);\n                    goto exception;\n                }\n                pr->u.var_ref = var_ref;\n                *sp++ = JS_AtomToValue(ctx, atom);\n            }\n            BREAK;\n        CASE(OP_make_var_ref):\n            {\n                JSAtom atom;\n                atom = get_u32(pc);\n                pc += 4;\n                sf->cur_pc = pc;\n\n                if (JS_GetGlobalVarRef(ctx, atom, sp))\n                    goto exception;\n                sp += 2;\n            }\n            BREAK;\n\n        CASE(OP_goto):\n            pc += (int32_t)get_u32(pc);\n            if (unlikely(js_poll_interrupts(ctx)))\n                goto exception;\n            BREAK;\n#if SHORT_OPCODES\n        CASE(OP_goto16):\n            pc += (int16_t)get_u16(pc);\n            if (unlikely(js_poll_interrupts(ctx)))\n                goto exception;\n            BREAK;\n        CASE(OP_goto8):\n            pc += (int8_t)pc[0];\n            if (unlikely(js_poll_interrupts(ctx)))\n                goto exception;\n            BREAK;\n#endif\n        CASE(OP_if_true):\n            {\n                int res;\n                JSValue op1;\n\n                op1 = sp[-1];\n                pc += 4;\n                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {\n                    res = JS_VALUE_GET_INT(op1);\n                } else {\n                    res = JS_ToBoolFree(ctx, op1);\n                }\n                sp--;\n                if (res) {\n                    pc += (int32_t)get_u32(pc - 4) - 4;\n                }\n                if (unlikely(js_poll_interrupts(ctx)))\n                    goto exception;\n            }\n            BREAK;\n        CASE(OP_if_false):\n            {\n                int res;\n                JSValue op1;\n\n                op1 = sp[-1];\n                pc += 4;\n                /* quick and dirty test for JS_TAG_INT, JS_TAG_BOOL, JS_TAG_NULL and JS_TAG_UNDEFINED */\n                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {\n                    res = JS_VALUE_GET_INT(op1);\n                } else {\n                    res = JS_ToBoolFree(ctx, op1);\n                }\n                sp--;\n                if (!res) {\n                    pc += (int32_t)get_u32(pc - 4) - 4;\n                }\n                if (unlikely(js_poll_interrupts(ctx)))\n                    goto exception;\n            }\n            BREAK;\n#if SHORT_OPCODES\n        CASE(OP_if_true8):\n            {\n                int res;\n                JSValue op1;\n\n                op1 = sp[-1];\n                pc += 1;\n                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {\n                    res = JS_VALUE_GET_INT(op1);\n                } else {\n                    res = JS_ToBoolFree(ctx, op1);\n                }\n                sp--;\n                if (res) {\n                    pc += (int8_t)pc[-1] - 1;\n                }\n                if (unlikely(js_poll_interrupts(ctx)))\n                    goto exception;\n            }\n            BREAK;\n        CASE(OP_if_false8):\n            {\n                int res;\n                JSValue op1;\n\n                op1 = sp[-1];\n                pc += 1;\n                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {\n                    res = JS_VALUE_GET_INT(op1);\n                } else {\n                    res = JS_ToBoolFree(ctx, op1);\n                }\n                sp--;\n                if (!res) {\n                    pc += (int8_t)pc[-1] - 1;\n                }\n                if (unlikely(js_poll_interrupts(ctx)))\n                    goto exception;\n            }\n            BREAK;\n#endif\n        CASE(OP_catch):\n            {\n                int32_t diff;\n                diff = get_u32(pc);\n                sp[0] = JS_NewCatchOffset(ctx, pc + diff - b->byte_code_buf);\n                sp++;\n                pc += 4;\n            }\n            BREAK;\n        CASE(OP_gosub):\n            {\n                int32_t diff;\n                diff = get_u32(pc);\n                /* XXX: should have a different tag to avoid security flaw */\n                sp[0] = JS_NewInt32(ctx, pc + 4 - b->byte_code_buf);\n                sp++;\n                pc += diff;\n            }\n            BREAK;\n        CASE(OP_ret):\n            {\n                JSValue op1;\n                uint32_t pos;\n                op1 = sp[-1];\n                if (unlikely(JS_VALUE_GET_TAG(op1) != JS_TAG_INT))\n                    goto ret_fail;\n                pos = JS_VALUE_GET_INT(op1);\n                if (unlikely(pos >= b->byte_code_len)) {\n                ret_fail:\n                    JS_ThrowInternalError(ctx, \"invalid ret value\");\n                    goto exception;\n                }\n                sp--;\n                pc = b->byte_code_buf + pos;\n            }\n            BREAK;\n\n        CASE(OP_for_in_start):\n            sf->cur_pc = pc;\n            if (js_for_in_start(ctx, sp))\n                goto exception;\n            BREAK;\n        CASE(OP_for_in_next):\n            sf->cur_pc = pc;\n            if (js_for_in_next(ctx, sp))\n                goto exception;\n            sp += 2;\n            BREAK;\n        CASE(OP_for_of_start):\n            sf->cur_pc = pc;\n            if (js_for_of_start(ctx, sp, FALSE))\n                goto exception;\n            sp += 1;\n            *sp++ = JS_NewCatchOffset(ctx, 0);\n            BREAK;\n        CASE(OP_for_of_next):\n            {\n                int offset = -3 - pc[0];\n                pc += 1;\n                sf->cur_pc = pc;\n                if (js_for_of_next(ctx, sp, offset))\n                    goto exception;\n                sp += 2;\n            }\n            BREAK;\n        CASE(OP_for_await_of_next):\n            sf->cur_pc = pc;\n            if (js_for_await_of_next(ctx, sp))\n                goto exception;\n            sp++;\n            BREAK;\n        CASE(OP_for_await_of_start):\n            sf->cur_pc = pc;\n            if (js_for_of_start(ctx, sp, TRUE))\n                goto exception;\n            sp += 1;\n            *sp++ = JS_NewCatchOffset(ctx, 0);\n            BREAK;\n        CASE(OP_iterator_get_value_done):\n            sf->cur_pc = pc;\n            if (js_iterator_get_value_done(ctx, sp))\n                goto exception;\n            sp += 1;\n            BREAK;\n        CASE(OP_iterator_check_object):\n            if (unlikely(!JS_IsObject(sp[-1]))) {\n                JS_ThrowTypeError(ctx, \"iterator must return an object\");\n                goto exception;\n            }\n            BREAK;\n\n        CASE(OP_iterator_close):\n            /* iter_obj next catch_offset -> */\n            sp--; /* drop the catch offset to avoid getting caught by exception */\n            JS_FreeValue(ctx, sp[-1]); /* drop the next method */\n            sp--;\n            if (!JS_IsUndefined(sp[-1])) {\n                sf->cur_pc = pc;\n                if (JS_IteratorClose(ctx, sp[-1], FALSE))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-1]);\n            }\n            sp--;\n            BREAK;\n        CASE(OP_nip_catch):\n            {\n                JSValue ret_val;\n                /* catch_offset ... ret_val -> ret_eval */\n                ret_val = *--sp;\n                while (sp > stack_buf &&\n                       JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_CATCH_OFFSET) {\n                    JS_FreeValue(ctx, *--sp);\n                }\n                if (unlikely(sp == stack_buf)) {\n                    JS_ThrowInternalError(ctx, \"nip_catch\");\n                    JS_FreeValue(ctx, ret_val);\n                    goto exception;\n                }\n                sp[-1] = ret_val;\n            }\n            BREAK;\n\n        CASE(OP_iterator_next):\n            /* stack: iter_obj next catch_offset val */\n            {\n                JSValue ret;\n                sf->cur_pc = pc;\n                ret = JS_Call(ctx, sp[-3], sp[-4],\n                              1, (JSValueConst *)(sp - 1));\n                if (JS_IsException(ret))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-1]);\n                sp[-1] = ret;\n            }\n            BREAK;\n\n        CASE(OP_iterator_call):\n            /* stack: iter_obj next catch_offset val */\n            {\n                JSValue method, ret;\n                BOOL ret_flag;\n                int flags;\n                flags = *pc++;\n                sf->cur_pc = pc;\n                method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?\n                                        JS_ATOM_throw : JS_ATOM_return);\n                if (JS_IsException(method))\n                    goto exception;\n                if (JS_IsUndefined(method) || JS_IsNull(method)) {\n                    ret_flag = TRUE;\n                } else {\n                    if (flags & 2) {\n                        /* no argument */\n                        ret = JS_CallFree(ctx, method, sp[-4],\n                                          0, NULL);\n                    } else {\n                        ret = JS_CallFree(ctx, method, sp[-4],\n                                          1, (JSValueConst *)(sp - 1));\n                    }\n                    if (JS_IsException(ret))\n                        goto exception;\n                    JS_FreeValue(ctx, sp[-1]);\n                    sp[-1] = ret;\n                    ret_flag = FALSE;\n                }\n                sp[0] = JS_NewBool(ctx, ret_flag);\n                sp += 1;\n            }\n            BREAK;\n\n        CASE(OP_lnot):\n            {\n                int res;\n                JSValue op1;\n\n                op1 = sp[-1];\n                if ((uint32_t)JS_VALUE_GET_TAG(op1) <= JS_TAG_UNDEFINED) {\n                    res = JS_VALUE_GET_INT(op1) != 0;\n                } else {\n                    res = JS_ToBoolFree(ctx, op1);\n                }\n                sp[-1] = JS_NewBool(ctx, !res);\n            }\n            BREAK;\n\n#define GET_FIELD_INLINE(name, keep, is_length)                         \\\n            {                                                           \\\n                JSValue val, obj;                                       \\\n                JSAtom atom;                                            \\\n                JSObject *p;                                            \\\n                JSProperty *pr;                                         \\\n                JSShapeProperty *prs;                                   \\\n                                                                        \\\n                if (is_length) {                                        \\\n                    atom = JS_ATOM_length;                              \\\n                } else {                                                \\\n                    atom = get_u32(pc);                                 \\\n                    pc += 4;                                            \\\n                }                                                       \\\n                                                                        \\\n                obj = sp[-1];                                           \\\n                if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {   \\\n                    p = JS_VALUE_GET_OBJ(obj);                          \\\n                    for(;;) {                                           \\\n                        prs = find_own_property(&pr, p, atom);          \\\n                        if (prs) {                                      \\\n                            /* found */                                 \\\n                            if (unlikely(prs->flags & JS_PROP_TMASK))   \\\n                                    goto name ## _slow_path;            \\\n                            val = JS_DupValue(ctx, pr->u.value);        \\\n                            break;                                      \\\n                        }                                               \\\n                        if (unlikely(p->is_exotic)) {                   \\\n                            /* XXX: should avoid the slow path for arrays \\\n                               and typed arrays by ensuring that 'prop' is \\\n                               not numeric */                           \\\n                            obj = JS_MKPTR(JS_TAG_OBJECT, p);           \\\n                            goto name ## _slow_path;                    \\\n                        }                                               \\\n                        p = p->shape->proto;                            \\\n                        if (!p) {                                       \\\n                            val = JS_UNDEFINED;                         \\\n                            break;                                      \\\n                        }                                               \\\n                    }                                                   \\\n                } else {                                                \\\n                name ## _slow_path:                                     \\\n                    sf->cur_pc = pc;                                    \\\n                    val = JS_GetPropertyInternal(ctx, obj, atom, sp[-1], 0); \\\n                    if (unlikely(JS_IsException(val)))                  \\\n                        goto exception;                                 \\\n                }                                                       \\\n                if (keep) {                                             \\\n                    *sp++ = val;                                        \\\n                } else {                                                \\\n                    JS_FreeValue(ctx, sp[-1]);                          \\\n                    sp[-1] = val;                                       \\\n                }                                                       \\\n            }\n\n            \n        CASE(OP_get_field):\n            GET_FIELD_INLINE(get_field, 0, 0);\n            BREAK;\n\n        CASE(OP_get_field2):\n            GET_FIELD_INLINE(get_field2, 1, 0);\n            BREAK;\n\n#if SHORT_OPCODES\n        CASE(OP_get_length):\n            GET_FIELD_INLINE(get_length, 0, 1);\n            BREAK;\n#endif\n            \n        CASE(OP_put_field):\n            {\n                int ret;\n                JSValue obj;\n                JSAtom atom;\n                JSObject *p;\n                JSProperty *pr;\n                JSShapeProperty *prs;\n\n                atom = get_u32(pc);\n                pc += 4;\n\n                obj = sp[-2];\n                if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT)) {\n                    p = JS_VALUE_GET_OBJ(obj);\n                    prs = find_own_property(&pr, p, atom);\n                    if (!prs)\n                        goto put_field_slow_path;\n                    if (likely((prs->flags & (JS_PROP_TMASK | JS_PROP_WRITABLE |\n                                              JS_PROP_LENGTH)) == JS_PROP_WRITABLE)) {\n                        /* fast path */\n                        set_value(ctx, &pr->u.value, sp[-1]);\n                    } else {\n                        goto put_field_slow_path;\n                    }\n                    JS_FreeValue(ctx, obj);\n                    sp -= 2;\n                } else {\n                put_field_slow_path:\n                    sf->cur_pc = pc;\n                    ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-1], obj,\n                                                 JS_PROP_THROW_STRICT);\n                    JS_FreeValue(ctx, obj);\n                    sp -= 2;\n                    if (unlikely(ret < 0))\n                        goto exception;\n                }\n                \n            }\n            BREAK;\n\n        CASE(OP_private_symbol):\n            {\n                JSAtom atom;\n                JSValue val;\n\n                atom = get_u32(pc);\n                pc += 4;\n                val = JS_NewSymbolFromAtom(ctx, atom, JS_ATOM_TYPE_PRIVATE);\n                if (JS_IsException(val))\n                    goto exception;\n                *sp++ = val;\n            }\n            BREAK;\n\n        CASE(OP_get_private_field):\n            {\n                JSValue val;\n\n                val = JS_GetPrivateField(ctx, sp[-2], sp[-1]);\n                JS_FreeValue(ctx, sp[-1]);\n                JS_FreeValue(ctx, sp[-2]);\n                sp[-2] = val;\n                sp--;\n                if (unlikely(JS_IsException(val)))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_put_private_field):\n            {\n                int ret;\n                ret = JS_SetPrivateField(ctx, sp[-3], sp[-1], sp[-2]);\n                JS_FreeValue(ctx, sp[-3]);\n                JS_FreeValue(ctx, sp[-1]);\n                sp -= 3;\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_define_private_field):\n            {\n                int ret;\n                ret = JS_DefinePrivateField(ctx, sp[-3], sp[-2], sp[-1]);\n                JS_FreeValue(ctx, sp[-2]);\n                sp -= 2;\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_define_field):\n            {\n                int ret;\n                JSAtom atom;\n                atom = get_u32(pc);\n                pc += 4;\n\n                ret = JS_DefinePropertyValue(ctx, sp[-2], atom, sp[-1],\n                                             JS_PROP_C_W_E | JS_PROP_THROW);\n                sp--;\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_set_name):\n            {\n                int ret;\n                JSAtom atom;\n                atom = get_u32(pc);\n                pc += 4;\n\n                ret = JS_DefineObjectName(ctx, sp[-1], atom, JS_PROP_CONFIGURABLE);\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n        CASE(OP_set_name_computed):\n            {\n                int ret;\n                ret = JS_DefineObjectNameComputed(ctx, sp[-1], sp[-2], JS_PROP_CONFIGURABLE);\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n        CASE(OP_set_proto):\n            {\n                JSValue proto;\n                sf->cur_pc = pc;\n                proto = sp[-1];\n                if (JS_IsObject(proto) || JS_IsNull(proto)) {\n                    if (JS_SetPrototypeInternal(ctx, sp[-2], proto, TRUE) < 0)\n                        goto exception;\n                }\n                JS_FreeValue(ctx, proto);\n                sp--;\n            }\n            BREAK;\n        CASE(OP_set_home_object):\n            js_method_set_home_object(ctx, sp[-1], sp[-2]);\n            BREAK;\n        CASE(OP_define_method):\n        CASE(OP_define_method_computed):\n            {\n                JSValue getter, setter, value;\n                JSValueConst obj;\n                JSAtom atom;\n                int flags, ret, op_flags;\n                BOOL is_computed;\n#define OP_DEFINE_METHOD_METHOD 0\n#define OP_DEFINE_METHOD_GETTER 1\n#define OP_DEFINE_METHOD_SETTER 2\n#define OP_DEFINE_METHOD_ENUMERABLE 4\n\n                is_computed = (opcode == OP_define_method_computed);\n                if (is_computed) {\n                    atom = JS_ValueToAtom(ctx, sp[-2]);\n                    if (unlikely(atom == JS_ATOM_NULL))\n                        goto exception;\n                    opcode += OP_define_method - OP_define_method_computed;\n                } else {\n                    atom = get_u32(pc);\n                    pc += 4;\n                }\n                op_flags = *pc++;\n\n                obj = sp[-2 - is_computed];\n                flags = JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE |\n                    JS_PROP_HAS_ENUMERABLE | JS_PROP_THROW;\n                if (op_flags & OP_DEFINE_METHOD_ENUMERABLE)\n                    flags |= JS_PROP_ENUMERABLE;\n                op_flags &= 3;\n                value = JS_UNDEFINED;\n                getter = JS_UNDEFINED;\n                setter = JS_UNDEFINED;\n                if (op_flags == OP_DEFINE_METHOD_METHOD) {\n                    value = sp[-1];\n                    flags |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE;\n                } else if (op_flags == OP_DEFINE_METHOD_GETTER) {\n                    getter = sp[-1];\n                    flags |= JS_PROP_HAS_GET;\n                } else {\n                    setter = sp[-1];\n                    flags |= JS_PROP_HAS_SET;\n                }\n                ret = js_method_set_properties(ctx, sp[-1], atom, flags, obj);\n                if (ret >= 0) {\n                    ret = JS_DefineProperty(ctx, obj, atom, value,\n                                            getter, setter, flags);\n                }\n                JS_FreeValue(ctx, sp[-1]);\n                if (is_computed) {\n                    JS_FreeAtom(ctx, atom);\n                    JS_FreeValue(ctx, sp[-2]);\n                }\n                sp -= 1 + is_computed;\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_define_class):\n        CASE(OP_define_class_computed):\n            {\n                int class_flags;\n                JSAtom atom;\n\n                atom = get_u32(pc);\n                class_flags = pc[4];\n                pc += 5;\n                if (js_op_define_class(ctx, sp, atom, class_flags,\n                                       var_refs, sf,\n                                       (opcode == OP_define_class_computed)) < 0)\n                    goto exception;\n            }\n            BREAK;\n\n#define GET_ARRAY_EL_INLINE(name, keep)                                 \\\n            {                                                           \\\n                JSValue val, obj, prop;                                 \\\n                JSObject *p;                                            \\\n                uint32_t idx;                                           \\\n                                                                        \\\n                obj = sp[-2];                                           \\\n                prop = sp[-1];                                          \\\n                if (likely(JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT &&    \\\n                           JS_VALUE_GET_TAG(prop) == JS_TAG_INT)) {     \\\n                    p = JS_VALUE_GET_OBJ(obj);                          \\\n                    idx = JS_VALUE_GET_INT(prop);                       \\\n                    if (unlikely(p->class_id != JS_CLASS_ARRAY))        \\\n                        goto name ## _slow_path;                        \\\n                    if (unlikely(idx >= p->u.array.count))              \\\n                        goto name ## _slow_path;                        \\\n                    val = JS_DupValue(ctx, p->u.array.u.values[idx]);   \\\n                } else {                                                \\\n                    name ## _slow_path:                                 \\\n                    sf->cur_pc = pc;                                    \\\n                    val = JS_GetPropertyValue(ctx, obj, prop);          \\\n                    if (unlikely(JS_IsException(val))) {                \\\n                        if (keep)                                       \\\n                            sp[-1] = JS_UNDEFINED;                      \\\n                        else                                            \\\n                            sp--;                                       \\\n                        goto exception;                                 \\\n                    }                                                   \\\n                }                                                       \\\n                if (keep) {                                             \\\n                    sp[-1] = val;                                       \\\n                } else {                                                \\\n                    JS_FreeValue(ctx, obj);                             \\\n                    sp[-2] = val;                                       \\\n                    sp--;                                               \\\n                }                                                       \\\n            }\n            \n        CASE(OP_get_array_el):\n            GET_ARRAY_EL_INLINE(get_array_el, 0);\n            BREAK;\n\n        CASE(OP_get_array_el2):\n            GET_ARRAY_EL_INLINE(get_array_el2, 1);\n            BREAK;\n\n        CASE(OP_get_array_el3):\n            {\n                JSValue val;\n                JSObject *p;\n                uint32_t idx;\n\n                if (likely(JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_OBJECT &&\n                           JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_INT)) {\n                    p = JS_VALUE_GET_OBJ(sp[-2]);\n                    idx = JS_VALUE_GET_INT(sp[-1]);\n                    if (unlikely(p->class_id != JS_CLASS_ARRAY))\n                        goto get_array_el3_slow_path;\n                    if (unlikely(idx >= p->u.array.count))\n                        goto get_array_el3_slow_path;\n                    val = JS_DupValue(ctx, p->u.array.u.values[idx]);\n                } else {\n                get_array_el3_slow_path:\n                    switch (JS_VALUE_GET_TAG(sp[-1])) {\n                    case JS_TAG_INT:\n                    case JS_TAG_STRING:\n                    case JS_TAG_SYMBOL:\n                        /* undefined and null are tested in JS_GetPropertyValue() */\n                        break;\n                    default:\n                        /* must be tested before JS_ToPropertyKey */\n                        if (unlikely(JS_IsUndefined(sp[-2]) || JS_IsNull(sp[-2]))) {\n                            JS_ThrowTypeError(ctx, \"value has no property\");\n                            goto exception;\n                        }\n                        sf->cur_pc = pc;\n                        ret_val = JS_ToPropertyKey(ctx, sp[-1]);\n                        if (JS_IsException(ret_val))\n                            goto exception;\n                        JS_FreeValue(ctx, sp[-1]);\n                        sp[-1] = ret_val;\n                        break;\n                    }\n                    sf->cur_pc = pc;\n                    val = JS_GetPropertyValue(ctx, sp[-2], JS_DupValue(ctx, sp[-1]));\n                    if (unlikely(JS_IsException(val)))\n                        goto exception;\n                }\n                *sp++ = val;\n            }\n            BREAK;\n            \n        CASE(OP_get_ref_value):\n            {\n                JSValue val;\n                JSAtom atom;\n                int ret;\n                \n                sf->cur_pc = pc;\n                atom = JS_ValueToAtom(ctx, sp[-1]);\n                if (atom == JS_ATOM_NULL)\n                    goto exception;\n                if (unlikely(JS_IsUndefined(sp[-2]))) {\n                    JS_ThrowReferenceErrorNotDefined(ctx, atom);\n                    JS_FreeAtom(ctx, atom);\n                    goto exception;\n                }\n                ret = JS_HasProperty(ctx, sp[-2], atom);\n                if (unlikely(ret <= 0)) {\n                    if (ret < 0) {\n                        JS_FreeAtom(ctx, atom);\n                        goto exception;\n                    }\n                    if (is_strict_mode(ctx)) {\n                        JS_ThrowReferenceErrorNotDefined(ctx, atom);\n                        JS_FreeAtom(ctx, atom);\n                        goto exception;\n                    } \n                    val = JS_UNDEFINED;\n                } else {\n                    val = JS_GetProperty(ctx, sp[-2], atom);\n                }\n                JS_FreeAtom(ctx, atom);\n                if (unlikely(JS_IsException(val)))\n                    goto exception;\n                sp[0] = val;\n                sp++;\n            }\n            BREAK;\n\n        CASE(OP_get_super_value):\n            {\n                JSValue val;\n                JSAtom atom;\n                sf->cur_pc = pc;\n                atom = JS_ValueToAtom(ctx, sp[-1]);\n                if (unlikely(atom == JS_ATOM_NULL))\n                    goto exception;\n                val = JS_GetPropertyInternal(ctx, sp[-2], atom, sp[-3], FALSE);\n                JS_FreeAtom(ctx, atom);\n                if (unlikely(JS_IsException(val)))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-1]);\n                JS_FreeValue(ctx, sp[-2]);\n                JS_FreeValue(ctx, sp[-3]);\n                sp[-3] = val;\n                sp -= 2;\n            }\n            BREAK;\n\n        CASE(OP_put_array_el):\n            {\n                int ret;\n                JSObject *p;\n                uint32_t idx;\n\n                if (likely(JS_VALUE_GET_TAG(sp[-3]) == JS_TAG_OBJECT &&\n                           JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_INT)) {\n                    p = JS_VALUE_GET_OBJ(sp[-3]);\n                    idx = JS_VALUE_GET_INT(sp[-2]);\n                    if (unlikely(p->class_id != JS_CLASS_ARRAY))\n                        goto put_array_el_slow_path;\n                    if (unlikely(idx >= (uint32_t)p->u.array.count)) {\n                        uint32_t new_len, array_len;\n                        if (unlikely(idx != (uint32_t)p->u.array.count ||\n                                     !p->fast_array ||\n                                     !can_extend_fast_array(p))) {\n                            goto put_array_el_slow_path;\n                        }\n                        if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))\n                            goto put_array_el_slow_path;\n                        /* cannot overflow otherwise the length would not be an integer */\n                        new_len = idx + 1;\n                        if (unlikely(new_len > p->u.array.u1.size))\n                            goto put_array_el_slow_path;\n                        array_len = JS_VALUE_GET_INT(p->prop[0].u.value);\n                        if (new_len > array_len) {\n                            if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE)))\n                                goto put_array_el_slow_path;\n                            p->prop[0].u.value = JS_NewInt32(ctx, new_len);\n                        }\n                        p->u.array.count = new_len;\n                        p->u.array.u.values[idx] = sp[-1];\n                    } else {\n                        set_value(ctx, &p->u.array.u.values[idx], sp[-1]);\n                    }\n                    JS_FreeValue(ctx, sp[-3]);\n                    sp -= 3;\n                } else {\n                put_array_el_slow_path:\n                    sf->cur_pc = pc;\n                    ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);\n                    JS_FreeValue(ctx, sp[-3]);\n                    sp -= 3;\n                    if (unlikely(ret < 0))\n                        goto exception;\n                }\n            }\n            BREAK;\n\n        CASE(OP_put_ref_value):\n            {\n                int ret;\n                JSAtom atom;\n                sf->cur_pc = pc;\n                atom = JS_ValueToAtom(ctx, sp[-2]);\n                if (unlikely(atom == JS_ATOM_NULL))\n                    goto exception;\n                if (unlikely(JS_IsUndefined(sp[-3]))) {\n                    if (is_strict_mode(ctx)) {\n                        JS_ThrowReferenceErrorNotDefined(ctx, atom);\n                        JS_FreeAtom(ctx, atom);\n                        goto exception;\n                    } else {\n                        sp[-3] = JS_DupValue(ctx, ctx->global_obj);\n                    }\n                }\n                ret = JS_HasProperty(ctx, sp[-3], atom);\n                if (unlikely(ret <= 0)) {\n                    if (unlikely(ret < 0)) {\n                        JS_FreeAtom(ctx, atom);\n                        goto exception;\n                    }\n                    if (is_strict_mode(ctx)) {\n                        JS_ThrowReferenceErrorNotDefined(ctx, atom);\n                        JS_FreeAtom(ctx, atom);\n                        goto exception;\n                    }\n                }\n                ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-3], JS_PROP_THROW_STRICT);\n                JS_FreeAtom(ctx, atom);\n                JS_FreeValue(ctx, sp[-2]);\n                JS_FreeValue(ctx, sp[-3]);\n                sp -= 3;\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_put_super_value):\n            {\n                int ret;\n                JSAtom atom;\n                sf->cur_pc = pc;\n                if (JS_VALUE_GET_TAG(sp[-3]) != JS_TAG_OBJECT) {\n                    JS_ThrowTypeErrorNotAnObject(ctx);\n                    goto exception;\n                }\n                atom = JS_ValueToAtom(ctx, sp[-2]);\n                if (unlikely(atom == JS_ATOM_NULL))\n                    goto exception;\n                ret = JS_SetPropertyInternal(ctx, sp[-3], atom, sp[-1], sp[-4],\n                                             JS_PROP_THROW_STRICT);\n                JS_FreeAtom(ctx, atom);\n                JS_FreeValue(ctx, sp[-4]);\n                JS_FreeValue(ctx, sp[-3]);\n                JS_FreeValue(ctx, sp[-2]);\n                sp -= 4;\n                if (ret < 0)\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_define_array_el):\n            {\n                int ret;\n                ret = JS_DefinePropertyValueValue(ctx, sp[-3], JS_DupValue(ctx, sp[-2]), sp[-1],\n                                                  JS_PROP_C_W_E | JS_PROP_THROW);\n                sp -= 1;\n                if (unlikely(ret < 0))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_append):    /* array pos enumobj -- array pos */\n            {\n                sf->cur_pc = pc;\n                if (js_append_enumerate(ctx, sp))\n                    goto exception;\n                JS_FreeValue(ctx, *--sp);\n            }\n            BREAK;\n\n        CASE(OP_copy_data_properties):    /* target source excludeList */\n            {\n                /* stack offsets (-1 based):\n                   2 bits for target,\n                   3 bits for source,\n                   2 bits for exclusionList */\n                int mask;\n\n                mask = *pc++;\n                sf->cur_pc = pc;\n                if (JS_CopyDataProperties(ctx, sp[-1 - (mask & 3)],\n                                          sp[-1 - ((mask >> 2) & 7)],\n                                          sp[-1 - ((mask >> 5) & 7)], 0))\n                    goto exception;\n            }\n            BREAK;\n\n        CASE(OP_add):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    int64_t r;\n                    r = (int64_t)JS_VALUE_GET_INT(op1) + JS_VALUE_GET_INT(op2);\n                    if (unlikely((int)r != r)) {\n                        sp[-2] = __JS_NewFloat64(ctx, (double)r);\n                    } else {\n                        sp[-2] = JS_NewInt32(ctx, r);\n                    }\n                    sp--;\n                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {\n                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) +\n                                             JS_VALUE_GET_FLOAT64(op2));\n                    sp--;\n                } else if (JS_IsString(op1) && JS_IsString(op2)) {\n                    sp[-2] = JS_ConcatString(ctx, op1, op2);\n                    sp--;\n                    if (JS_IsException(sp[-1]))\n                        goto exception;\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_add_slow(ctx, sp))\n                        goto exception;\n                    sp--;\n                }\n            }\n            BREAK;\n        CASE(OP_add_loc):\n            {\n                JSValue op2;\n                JSValue *pv;\n                int idx;\n                idx = *pc;\n                pc += 1;\n\n                op2 = sp[-1];\n                pv = &var_buf[idx];\n                if (likely(JS_VALUE_IS_BOTH_INT(*pv, op2))) {\n                    int64_t r;\n                    r = (int64_t)JS_VALUE_GET_INT(*pv) + JS_VALUE_GET_INT(op2);\n                    if (unlikely((int)r != r)) {\n                        *pv = __JS_NewFloat64(ctx, (double)r);\n                    } else {\n                        *pv = JS_NewInt32(ctx, r);\n                    }\n                    sp--;\n                } else if (JS_VALUE_IS_BOTH_FLOAT(*pv, op2)) {\n                    *pv = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(*pv) +\n                                               JS_VALUE_GET_FLOAT64(op2));\n                    sp--;\n                } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING &&\n                           JS_VALUE_GET_TAG(op2) == JS_TAG_STRING) {\n                    sp--;\n                    sf->cur_pc = pc;\n                    if (JS_ConcatStringInPlace(ctx, JS_VALUE_GET_STRING(*pv), op2)) {\n                        JS_FreeValue(ctx, op2);\n                    } else {\n                        op2 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op2);\n                        if (JS_IsException(op2))\n                            goto exception;\n                        set_value(ctx, pv, op2);\n                    }\n                } else {\n                    JSValue ops[2];\n                    /* In case of exception, js_add_slow frees ops[0]\n                       and ops[1], so we must duplicate *pv */\n                    sf->cur_pc = pc;\n                    ops[0] = JS_DupValue(ctx, *pv);\n                    ops[1] = op2;\n                    sp--;\n                    if (js_add_slow(ctx, ops + 2))\n                        goto exception;\n                    set_value(ctx, pv, ops[0]);\n                }\n            }\n            BREAK;\n        CASE(OP_sub):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    int64_t r;\n                    r = (int64_t)JS_VALUE_GET_INT(op1) - JS_VALUE_GET_INT(op2);\n                    if (unlikely((int)r != r)) {\n                        sp[-2] = __JS_NewFloat64(ctx, (double)r);\n                    } else {\n                        sp[-2] = JS_NewInt32(ctx, r);\n                    }\n                    sp--;\n                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {\n                    sp[-2] = __JS_NewFloat64(ctx, JS_VALUE_GET_FLOAT64(op1) -\n                                             JS_VALUE_GET_FLOAT64(op2));\n                    sp--;\n                } else {\n                    goto binary_arith_slow;\n                }\n            }\n            BREAK;\n        CASE(OP_mul):\n            {\n                JSValue op1, op2;\n                double d;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    int32_t v1, v2;\n                    int64_t r;\n                    v1 = JS_VALUE_GET_INT(op1);\n                    v2 = JS_VALUE_GET_INT(op2);\n                    r = (int64_t)v1 * v2;\n                    if (unlikely((int)r != r)) {\n                        d = (double)r;\n                        goto mul_fp_res;\n                    }\n                    /* need to test zero case for -0 result */\n                    if (unlikely(r == 0 && (v1 | v2) < 0)) {\n                        d = -0.0;\n                        goto mul_fp_res;\n                    }\n                    sp[-2] = JS_NewInt32(ctx, r);\n                    sp--;\n                } else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {\n                    d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);\n                mul_fp_res:\n                    sp[-2] = __JS_NewFloat64(ctx, d);\n                    sp--;\n                } else {\n                    goto binary_arith_slow;\n                }\n            }\n            BREAK;\n        CASE(OP_div):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    int v1, v2;\n                    v1 = JS_VALUE_GET_INT(op1);\n                    v2 = JS_VALUE_GET_INT(op2);\n                    sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);\n                    sp--;\n                } else {\n                    goto binary_arith_slow;\n                }\n            }\n            BREAK;\n        CASE(OP_mod):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    int v1, v2, r;\n                    v1 = JS_VALUE_GET_INT(op1);\n                    v2 = JS_VALUE_GET_INT(op2);\n                    /* We must avoid v2 = 0, v1 = INT32_MIN and v2 =\n                       -1 and the cases where the result is -0. */\n                    if (unlikely(v1 < 0 || v2 <= 0))\n                        goto binary_arith_slow;\n                    r = v1 % v2;\n                    sp[-2] = JS_NewInt32(ctx, r);\n                    sp--;\n                } else {\n                    goto binary_arith_slow;\n                }\n            }\n            BREAK;\n        CASE(OP_pow):\n        binary_arith_slow:\n            sf->cur_pc = pc;\n            if (js_binary_arith_slow(ctx, sp, opcode))\n                goto exception;\n            sp--;\n            BREAK;\n\n        CASE(OP_plus):\n            {\n                JSValue op1;\n                uint32_t tag;\n                op1 = sp[-1];\n                tag = JS_VALUE_GET_TAG(op1);\n                if (tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag)) {\n                } else if (tag == JS_TAG_NULL || tag == JS_TAG_BOOL) {\n                    sp[-1] = JS_NewInt32(ctx, JS_VALUE_GET_INT(op1));\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_unary_arith_slow(ctx, sp, opcode))\n                        goto exception;\n                }\n            }\n            BREAK;\n        CASE(OP_neg):\n            {\n                JSValue op1;\n                uint32_t tag;\n                int val;\n                double d;\n                op1 = sp[-1];\n                tag = JS_VALUE_GET_TAG(op1);\n                if (tag == JS_TAG_INT ||\n                    tag == JS_TAG_BOOL ||\n                    tag == JS_TAG_NULL) {\n                    val = JS_VALUE_GET_INT(op1);\n                    /* Note: -0 cannot be expressed as integer */\n                    if (unlikely(val == 0)) {\n                        d = -0.0;\n                        goto neg_fp_res;\n                    }\n                    if (unlikely(val == INT32_MIN)) {\n                        d = -(double)val;\n                        goto neg_fp_res;\n                    }\n                    sp[-1] = JS_NewInt32(ctx, -val);\n                } else if (JS_TAG_IS_FLOAT64(tag)) {\n                    d = -JS_VALUE_GET_FLOAT64(op1);\n                neg_fp_res:\n                    sp[-1] = __JS_NewFloat64(ctx, d);\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_unary_arith_slow(ctx, sp, opcode))\n                        goto exception;\n                }\n            }\n            BREAK;\n        CASE(OP_inc):\n            {\n                JSValue op1;\n                int val;\n                op1 = sp[-1];\n                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {\n                    val = JS_VALUE_GET_INT(op1);\n                    if (unlikely(val == INT32_MAX))\n                        goto inc_slow;\n                    sp[-1] = JS_NewInt32(ctx, val + 1);\n                } else {\n                inc_slow:\n                    sf->cur_pc = pc;\n                    if (js_unary_arith_slow(ctx, sp, opcode))\n                        goto exception;\n                }\n            }\n            BREAK;\n        CASE(OP_dec):\n            {\n                JSValue op1;\n                int val;\n                op1 = sp[-1];\n                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {\n                    val = JS_VALUE_GET_INT(op1);\n                    if (unlikely(val == INT32_MIN))\n                        goto dec_slow;\n                    sp[-1] = JS_NewInt32(ctx, val - 1);\n                } else {\n                dec_slow:\n                    sf->cur_pc = pc;\n                    if (js_unary_arith_slow(ctx, sp, opcode))\n                        goto exception;\n                }\n            }\n            BREAK;\n        CASE(OP_post_inc):\n            {\n                JSValue op1;\n                int val;\n                op1 = sp[-1];\n                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {\n                    val = JS_VALUE_GET_INT(op1);\n                    if (unlikely(val == INT32_MAX))\n                        goto post_inc_slow;\n                    sp[0] = JS_NewInt32(ctx, val + 1);\n                } else {\n                post_inc_slow:\n                    sf->cur_pc = pc;\n                    if (js_post_inc_slow(ctx, sp, opcode))\n                        goto exception;\n                }\n                sp++;\n            }\n            BREAK;\n        CASE(OP_post_dec):\n            {\n                JSValue op1;\n                int val;\n                op1 = sp[-1];\n                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {\n                    val = JS_VALUE_GET_INT(op1);\n                    if (unlikely(val == INT32_MIN))\n                        goto post_dec_slow;\n                    sp[0] = JS_NewInt32(ctx, val - 1);\n                } else {\n                post_dec_slow:\n                    sf->cur_pc = pc;\n                    if (js_post_inc_slow(ctx, sp, opcode))\n                        goto exception;\n                }\n                sp++;\n            }\n            BREAK;\n        CASE(OP_inc_loc):\n            {\n                JSValue op1;\n                int val;\n                int idx;\n                idx = *pc;\n                pc += 1;\n\n                op1 = var_buf[idx];\n                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {\n                    val = JS_VALUE_GET_INT(op1);\n                    if (unlikely(val == INT32_MAX))\n                        goto inc_loc_slow;\n                    var_buf[idx] = JS_NewInt32(ctx, val + 1);\n                } else {\n                inc_loc_slow:\n                    sf->cur_pc = pc;\n                    /* must duplicate otherwise the variable value may\n                       be destroyed before JS code accesses it */\n                    op1 = JS_DupValue(ctx, op1);\n                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))\n                        goto exception;\n                    set_value(ctx, &var_buf[idx], op1);\n                }\n            }\n            BREAK;\n        CASE(OP_dec_loc):\n            {\n                JSValue op1;\n                int val;\n                int idx;\n                idx = *pc;\n                pc += 1;\n\n                op1 = var_buf[idx];\n                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {\n                    val = JS_VALUE_GET_INT(op1);\n                    if (unlikely(val == INT32_MIN))\n                        goto dec_loc_slow;\n                    var_buf[idx] = JS_NewInt32(ctx, val - 1);\n                } else {\n                dec_loc_slow:\n                    sf->cur_pc = pc;\n                    /* must duplicate otherwise the variable value may\n                       be destroyed before JS code accesses it */\n                    op1 = JS_DupValue(ctx, op1);\n                    if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))\n                        goto exception;\n                    set_value(ctx, &var_buf[idx], op1);\n                }\n            }\n            BREAK;\n        CASE(OP_not):\n            {\n                JSValue op1;\n                op1 = sp[-1];\n                if (JS_VALUE_GET_TAG(op1) == JS_TAG_INT) {\n                    sp[-1] = JS_NewInt32(ctx, ~JS_VALUE_GET_INT(op1));\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_not_slow(ctx, sp))\n                        goto exception;\n                }\n            }\n            BREAK;\n\n        CASE(OP_shl):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    uint32_t v1, v2;\n                    v1 = JS_VALUE_GET_INT(op1);\n                    v2 = JS_VALUE_GET_INT(op2);\n                    v2 &= 0x1f;\n                    sp[-2] = JS_NewInt32(ctx, v1 << v2);\n                    sp--;\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_binary_logic_slow(ctx, sp, opcode))\n                        goto exception;\n                    sp--;\n                }\n            }\n            BREAK;\n        CASE(OP_shr):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    uint32_t v2;\n                    v2 = JS_VALUE_GET_INT(op2);\n                    v2 &= 0x1f;\n                    sp[-2] = JS_NewUint32(ctx,\n                                          (uint32_t)JS_VALUE_GET_INT(op1) >>\n                                          v2);\n                    sp--;\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_shr_slow(ctx, sp))\n                        goto exception;\n                    sp--;\n                }\n            }\n            BREAK;\n        CASE(OP_sar):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    uint32_t v2;\n                    v2 = JS_VALUE_GET_INT(op2);\n                    v2 &= 0x1f;\n                    sp[-2] = JS_NewInt32(ctx,\n                                          (int)JS_VALUE_GET_INT(op1) >> v2);\n                    sp--;\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_binary_logic_slow(ctx, sp, opcode))\n                        goto exception;\n                    sp--;\n                }\n            }\n            BREAK;\n        CASE(OP_and):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    sp[-2] = JS_NewInt32(ctx,\n                                         JS_VALUE_GET_INT(op1) &\n                                         JS_VALUE_GET_INT(op2));\n                    sp--;\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_binary_logic_slow(ctx, sp, opcode))\n                        goto exception;\n                    sp--;\n                }\n            }\n            BREAK;\n        CASE(OP_or):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    sp[-2] = JS_NewInt32(ctx,\n                                         JS_VALUE_GET_INT(op1) |\n                                         JS_VALUE_GET_INT(op2));\n                    sp--;\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_binary_logic_slow(ctx, sp, opcode))\n                        goto exception;\n                    sp--;\n                }\n            }\n            BREAK;\n        CASE(OP_xor):\n            {\n                JSValue op1, op2;\n                op1 = sp[-2];\n                op2 = sp[-1];\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {\n                    sp[-2] = JS_NewInt32(ctx,\n                                         JS_VALUE_GET_INT(op1) ^\n                                         JS_VALUE_GET_INT(op2));\n                    sp--;\n                } else {\n                    sf->cur_pc = pc;\n                    if (js_binary_logic_slow(ctx, sp, opcode))\n                        goto exception;\n                    sp--;\n                }\n            }\n            BREAK;\n\n\n#define OP_CMP(opcode, binary_op, slow_call)              \\\n            CASE(opcode):                                 \\\n                {                                         \\\n                JSValue op1, op2;                         \\\n                op1 = sp[-2];                             \\\n                op2 = sp[-1];                                   \\\n                if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {           \\\n                    sp[-2] = JS_NewBool(ctx, JS_VALUE_GET_INT(op1) binary_op JS_VALUE_GET_INT(op2)); \\\n                    sp--;                                               \\\n                } else {                                                \\\n                    sf->cur_pc = pc;                                    \\\n                    if (slow_call)                                      \\\n                        goto exception;                                 \\\n                    sp--;                                               \\\n                }                                                       \\\n                }                                                       \\\n            BREAK\n\n            OP_CMP(OP_lt, <, js_relational_slow(ctx, sp, opcode));\n            OP_CMP(OP_lte, <=, js_relational_slow(ctx, sp, opcode));\n            OP_CMP(OP_gt, >, js_relational_slow(ctx, sp, opcode));\n            OP_CMP(OP_gte, >=, js_relational_slow(ctx, sp, opcode));\n            OP_CMP(OP_eq, ==, js_eq_slow(ctx, sp, 0));\n            OP_CMP(OP_neq, !=, js_eq_slow(ctx, sp, 1));\n            OP_CMP(OP_strict_eq, ==, js_strict_eq_slow(ctx, sp, 0));\n            OP_CMP(OP_strict_neq, !=, js_strict_eq_slow(ctx, sp, 1));\n\n        CASE(OP_in):\n            sf->cur_pc = pc;\n            if (js_operator_in(ctx, sp))\n                goto exception;\n            sp--;\n            BREAK;\n        CASE(OP_private_in):\n            sf->cur_pc = pc;\n            if (js_operator_private_in(ctx, sp))\n                goto exception;\n            sp--;\n            BREAK;\n        CASE(OP_instanceof):\n            sf->cur_pc = pc;\n            if (js_operator_instanceof(ctx, sp))\n                goto exception;\n            sp--;\n            BREAK;\n        CASE(OP_typeof):\n            {\n                JSValue op1;\n                JSAtom atom;\n\n                op1 = sp[-1];\n                atom = js_operator_typeof(ctx, op1);\n                JS_FreeValue(ctx, op1);\n                sp[-1] = JS_AtomToString(ctx, atom);\n            }\n            BREAK;\n        CASE(OP_delete):\n            sf->cur_pc = pc;\n            if (js_operator_delete(ctx, sp))\n                goto exception;\n            sp--;\n            BREAK;\n        CASE(OP_delete_var):\n            {\n                JSAtom atom;\n                int ret;\n\n                atom = get_u32(pc);\n                pc += 4;\n                sf->cur_pc = pc;\n\n                ret = JS_DeleteGlobalVar(ctx, atom);\n                if (unlikely(ret < 0))\n                    goto exception;\n                *sp++ = JS_NewBool(ctx, ret);\n            }\n            BREAK;\n\n        CASE(OP_to_object):\n            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_OBJECT) {\n                sf->cur_pc = pc;\n                ret_val = JS_ToObject(ctx, sp[-1]);\n                if (JS_IsException(ret_val))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-1]);\n                sp[-1] = ret_val;\n            }\n            BREAK;\n\n        CASE(OP_to_propkey):\n            switch (JS_VALUE_GET_TAG(sp[-1])) {\n            case JS_TAG_INT:\n            case JS_TAG_STRING:\n            case JS_TAG_SYMBOL:\n                break;\n            default:\n                sf->cur_pc = pc;\n                ret_val = JS_ToPropertyKey(ctx, sp[-1]);\n                if (JS_IsException(ret_val))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-1]);\n                sp[-1] = ret_val;\n                break;\n            }\n            BREAK;\n\n#if 0\n        CASE(OP_to_string):\n            if (JS_VALUE_GET_TAG(sp[-1]) != JS_TAG_STRING) {\n                ret_val = JS_ToString(ctx, sp[-1]);\n                if (JS_IsException(ret_val))\n                    goto exception;\n                JS_FreeValue(ctx, sp[-1]);\n                sp[-1] = ret_val;\n            }\n            BREAK;\n#endif\n        CASE(OP_with_get_var):\n        CASE(OP_with_put_var):\n        CASE(OP_with_delete_var):\n        CASE(OP_with_make_ref):\n        CASE(OP_with_get_ref):\n            {\n                JSAtom atom;\n                int32_t diff;\n                JSValue obj, val;\n                int ret, is_with;\n                atom = get_u32(pc);\n                diff = get_u32(pc + 4);\n                is_with = pc[8];\n                pc += 9;\n                sf->cur_pc = pc;\n\n                obj = sp[-1];\n                ret = JS_HasProperty(ctx, obj, atom);\n                if (unlikely(ret < 0))\n                    goto exception;\n                if (ret) {\n                    if (is_with) {\n                        ret = js_has_unscopable(ctx, obj, atom);\n                        if (unlikely(ret < 0))\n                            goto exception;\n                        if (ret)\n                            goto no_with;\n                    }\n                    switch (opcode) {\n                    case OP_with_get_var:\n                        /* in Object Environment Records, GetBindingValue() calls HasProperty() */\n                        ret = JS_HasProperty(ctx, obj, atom);\n                        if (unlikely(ret <= 0)) {\n                            if (ret < 0)\n                                goto exception;\n                            if (is_strict_mode(ctx)) {\n                                JS_ThrowReferenceErrorNotDefined(ctx, atom);\n                                goto exception;\n                            } \n                            val = JS_UNDEFINED;\n                        } else {\n                            val = JS_GetProperty(ctx, obj, atom);\n                            if (unlikely(JS_IsException(val)))\n                                goto exception;\n                        }\n                        set_value(ctx, &sp[-1], val);\n                        break;\n                    case OP_with_put_var: /* used e.g. in for in/of */\n                        /* in Object Environment Records, SetMutableBinding() calls HasProperty() */\n                        ret = JS_HasProperty(ctx, obj, atom);\n                        if (unlikely(ret <= 0)) {\n                            if (ret < 0)\n                                goto exception;\n                            if (is_strict_mode(ctx)) {\n                                JS_ThrowReferenceErrorNotDefined(ctx, atom);\n                                goto exception;\n                            } \n                        }\n                        ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2], obj,\n                                                     JS_PROP_THROW_STRICT);\n                        JS_FreeValue(ctx, sp[-1]);\n                        sp -= 2;\n                        if (unlikely(ret < 0))\n                            goto exception;\n                        break;\n                    case OP_with_delete_var:\n                        ret = JS_DeleteProperty(ctx, obj, atom, 0);\n                        if (unlikely(ret < 0))\n                            goto exception;\n                        JS_FreeValue(ctx, sp[-1]);\n                        sp[-1] = JS_NewBool(ctx, ret);\n                        break;\n                    case OP_with_make_ref:\n                        /* produce a pair object/propname on the stack */\n                        *sp++ = JS_AtomToValue(ctx, atom);\n                        break;\n                    case OP_with_get_ref:\n                        /* produce a pair object/method on the stack */\n                        /* in Object Environment Records, GetBindingValue() calls HasProperty() */\n                        ret = JS_HasProperty(ctx, obj, atom);\n                        if (unlikely(ret < 0))\n                            goto exception;\n                        if (!ret) {\n                            val = JS_UNDEFINED;\n                        } else {\n                            val = JS_GetProperty(ctx, obj, atom);\n                            if (unlikely(JS_IsException(val)))\n                                goto exception;\n                        }\n                        *sp++ = val;\n                        break;\n                    }\n                    pc += diff - 5;\n                } else {\n                no_with:\n                    /* if not jumping, drop the object argument */\n                    JS_FreeValue(ctx, sp[-1]);\n                    sp--;\n                }\n            }\n            BREAK;\n\n        CASE(OP_await):\n            ret_val = JS_NewInt32(ctx, FUNC_RET_AWAIT);\n            goto done_generator;\n        CASE(OP_yield):\n            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD);\n            goto done_generator;\n        CASE(OP_yield_star):\n        CASE(OP_async_yield_star):\n            ret_val = JS_NewInt32(ctx, FUNC_RET_YIELD_STAR);\n            goto done_generator;\n        CASE(OP_return_async):\n            ret_val = JS_UNDEFINED;\n            goto done_generator;\n        CASE(OP_initial_yield):\n            ret_val = JS_NewInt32(ctx, FUNC_RET_INITIAL_YIELD);\n            goto done_generator;\n\n        CASE(OP_nop):\n            BREAK;\n        CASE(OP_is_undefined_or_null):\n            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED ||\n                JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {\n                goto set_true;\n            } else {\n                goto free_and_set_false;\n            }\n#if SHORT_OPCODES\n        CASE(OP_is_undefined):\n            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_UNDEFINED) {\n                goto set_true;\n            } else {\n                goto free_and_set_false;\n            }\n        CASE(OP_is_null):\n            if (JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_NULL) {\n                goto set_true;\n            } else {\n                goto free_and_set_false;\n            }\n            /* XXX: could merge to a single opcode */\n        CASE(OP_typeof_is_undefined):\n            /* different from OP_is_undefined because of isHTMLDDA */\n            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) {\n                goto free_and_set_true;\n            } else {\n                goto free_and_set_false;\n            }\n        CASE(OP_typeof_is_function):\n            if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) {\n                goto free_and_set_true;\n            } else {\n                goto free_and_set_false;\n            }\n        free_and_set_true:\n            JS_FreeValue(ctx, sp[-1]);\n#endif\n        set_true:\n            sp[-1] = JS_TRUE;\n            BREAK;\n        free_and_set_false:\n            JS_FreeValue(ctx, sp[-1]);\n            sp[-1] = JS_FALSE;\n            BREAK;\n        CASE(OP_invalid):\n        DEFAULT:\n            JS_ThrowInternalError(ctx, \"invalid opcode: pc=%u opcode=0x%02x\",\n                                  (int)(pc - b->byte_code_buf - 1), opcode);\n            goto exception;\n        }\n    }\n exception:\n    if (is_backtrace_needed(ctx, rt->current_exception)) {\n        /* add the backtrace information now (it is not done\n           before if the exception happens in a bytecode\n           operation */\n        sf->cur_pc = pc;\n        build_backtrace(ctx, rt->current_exception, NULL, 0, 0, 0);\n    }\n    if (!rt->current_exception_is_uncatchable) {\n        while (sp > stack_buf) {\n            JSValue val = *--sp;\n            JS_FreeValue(ctx, val);\n            if (JS_VALUE_GET_TAG(val) == JS_TAG_CATCH_OFFSET) {\n                int pos = JS_VALUE_GET_INT(val);\n                if (pos == 0) {\n                    /* enumerator: close it with a throw */\n                    JS_FreeValue(ctx, sp[-1]); /* drop the next method */\n                    sp--;\n                    JS_IteratorClose(ctx, sp[-1], TRUE);\n                } else {\n                    *sp++ = rt->current_exception;\n                    rt->current_exception = JS_UNINITIALIZED;\n                    pc = b->byte_code_buf + pos;\n                    goto restart;\n                }\n            }\n        }\n    }\n    ret_val = JS_EXCEPTION;\n    /* the local variables are freed by the caller in the generator\n       case. Hence the label 'done' should never be reached in a\n       generator function. */\n    if (b->func_kind != JS_FUNC_NORMAL) {\n    done_generator:\n        sf->cur_pc = pc;\n        sf->cur_sp = sp;\n    } else {\n    done:\n        if (unlikely(b->var_ref_count != 0)) {\n            /* variable references reference the stack: must close them */\n            close_var_refs(rt, b, sf);\n        }\n        /* free the local variables and stack */\n        for(pval = local_buf; pval < sp; pval++) {\n            JS_FreeValue(ctx, *pval);\n        }\n    }\n    rt->current_stack_frame = sf->prev_frame;\n    return ret_val;\n}\n\nJSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,\n                int argc, JSValueConst *argv)\n{\n    return JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,\n                           argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);\n}\n\nstatic JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_obj,\n                           int argc, JSValueConst *argv)\n{\n    JSValue res = JS_CallInternal(ctx, func_obj, this_obj, JS_UNDEFINED,\n                                  argc, (JSValue *)argv, JS_CALL_FLAG_COPY_ARGV);\n    JS_FreeValue(ctx, func_obj);\n    return res;\n}\n\n/* warning: the refcount of the context is not incremented. Return\n   NULL in case of exception (case of revoked proxy only) */\nstatic JSContext *JS_GetFunctionRealm(JSContext *ctx, JSValueConst func_obj)\n{\n    JSObject *p;\n    JSContext *realm;\n\n    if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)\n        return ctx;\n    p = JS_VALUE_GET_OBJ(func_obj);\n    switch(p->class_id) {\n    case JS_CLASS_C_FUNCTION:\n        realm = p->u.cfunc.realm;\n        break;\n    case JS_CLASS_BYTECODE_FUNCTION:\n    case JS_CLASS_GENERATOR_FUNCTION:\n    case JS_CLASS_ASYNC_FUNCTION:\n    case JS_CLASS_ASYNC_GENERATOR_FUNCTION:\n        {\n            JSFunctionBytecode *b;\n            b = p->u.func.function_bytecode;\n            realm = b->realm;\n        }\n        break;\n    case JS_CLASS_PROXY:\n        {\n            JSProxyData *s = p->u.opaque;\n            if (!s)\n                return ctx;\n            if (s->is_revoked) {\n                JS_ThrowTypeErrorRevokedProxy(ctx);\n                return NULL;\n            } else {\n                realm = JS_GetFunctionRealm(ctx, s->target);\n            }\n        }\n        break;\n    case JS_CLASS_BOUND_FUNCTION:\n        {\n            JSBoundFunction *bf = p->u.bound_function;\n            realm = JS_GetFunctionRealm(ctx, bf->func_obj);\n        }\n        break;\n    default:\n        realm = ctx;\n        break;\n    }\n    return realm;\n}\n\nstatic JSValue js_create_from_ctor(JSContext *ctx, JSValueConst ctor,\n                                   int class_id)\n{\n    JSValue proto, obj;\n    JSContext *realm;\n\n    if (JS_IsUndefined(ctor)) {\n        proto = JS_DupValue(ctx, ctx->class_proto[class_id]);\n    } else {\n        proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);\n        if (JS_IsException(proto))\n            return proto;\n        if (!JS_IsObject(proto)) {\n            JS_FreeValue(ctx, proto);\n            realm = JS_GetFunctionRealm(ctx, ctor);\n            if (!realm)\n                return JS_EXCEPTION;\n            proto = JS_DupValue(ctx, realm->class_proto[class_id]);\n        }\n    }\n    obj = JS_NewObjectProtoClass(ctx, proto, class_id);\n    JS_FreeValue(ctx, proto);\n    return obj;\n}\n\n/* argv[] is modified if (flags & JS_CALL_FLAG_COPY_ARGV) = 0. */\nstatic JSValue JS_CallConstructorInternal(JSContext *ctx,\n                                          JSValueConst func_obj,\n                                          JSValueConst new_target,\n                                          int argc, JSValue *argv, int flags)\n{\n    JSObject *p;\n    JSFunctionBytecode *b;\n\n    if (js_poll_interrupts(ctx))\n        return JS_EXCEPTION;\n    flags |= JS_CALL_FLAG_CONSTRUCTOR;\n    if (unlikely(JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT))\n        goto not_a_function;\n    p = JS_VALUE_GET_OBJ(func_obj);\n    if (unlikely(!p->is_constructor))\n        return JS_ThrowTypeErrorNotAConstructor(ctx, func_obj);\n    if (unlikely(p->class_id != JS_CLASS_BYTECODE_FUNCTION)) {\n        JSClassCall *call_func;\n        call_func = ctx->rt->class_array[p->class_id].call;\n        if (!call_func) {\n        not_a_function:\n            return JS_ThrowTypeError(ctx, \"not a function\");\n        }\n        return call_func(ctx, func_obj, new_target, argc,\n                         (JSValueConst *)argv, flags);\n    }\n\n    b = p->u.func.function_bytecode;\n    if (b->is_derived_class_constructor) {\n        return JS_CallInternal(ctx, func_obj, JS_UNDEFINED, new_target, argc, argv, flags);\n    } else {\n        JSValue obj, ret;\n        /* legacy constructor behavior */\n        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);\n        if (JS_IsException(obj))\n            return JS_EXCEPTION;\n        ret = JS_CallInternal(ctx, func_obj, obj, new_target, argc, argv, flags);\n        if (JS_VALUE_GET_TAG(ret) == JS_TAG_OBJECT ||\n            JS_IsException(ret)) {\n            JS_FreeValue(ctx, obj);\n            return ret;\n        } else {\n            JS_FreeValue(ctx, ret);\n            return obj;\n        }\n    }\n}\n\nJSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,\n                            JSValueConst new_target,\n                            int argc, JSValueConst *argv)\n{\n    return JS_CallConstructorInternal(ctx, func_obj, new_target,\n                                      argc, (JSValue *)argv,\n                                      JS_CALL_FLAG_COPY_ARGV);\n}\n\nJSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,\n                           int argc, JSValueConst *argv)\n{\n    return JS_CallConstructorInternal(ctx, func_obj, func_obj,\n                                      argc, (JSValue *)argv,\n                                      JS_CALL_FLAG_COPY_ARGV);\n}\n\nJSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,\n                  int argc, JSValueConst *argv)\n{\n    JSValue func_obj;\n    func_obj = JS_GetProperty(ctx, this_val, atom);\n    if (JS_IsException(func_obj))\n        return func_obj;\n    return JS_CallFree(ctx, func_obj, this_val, argc, argv);\n}\n\nstatic JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,\n                             int argc, JSValueConst *argv)\n{\n    JSValue res = JS_Invoke(ctx, this_val, atom, argc, argv);\n    JS_FreeValue(ctx, this_val);\n    return res;\n}\n\n/* JSAsyncFunctionState (used by generator and async functions) */\nstatic JSAsyncFunctionState *async_func_init(JSContext *ctx,\n                                             JSValueConst func_obj, JSValueConst this_obj,\n                                             int argc, JSValueConst *argv)\n{\n    JSAsyncFunctionState *s;\n    JSObject *p;\n    JSFunctionBytecode *b;\n    JSStackFrame *sf;\n    int i, arg_buf_len, n;\n\n    p = JS_VALUE_GET_OBJ(func_obj);\n    b = p->u.func.function_bytecode;\n    arg_buf_len = max_int(b->arg_count, argc);\n    s = js_malloc(ctx, sizeof(*s) + sizeof(JSValue) * (arg_buf_len + b->var_count + b->stack_size) + sizeof(JSVarRef *) * b->var_ref_count);\n    if (!s)\n        return NULL;\n    memset(s, 0, sizeof(*s));\n    s->header.ref_count = 1;\n    add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);\n\n    sf = &s->frame;\n    sf->js_mode = b->js_mode | JS_MODE_ASYNC;\n    sf->cur_pc = b->byte_code_buf;\n    sf->arg_buf = (JSValue *)(s + 1);\n    sf->cur_func = JS_DupValue(ctx, func_obj);\n    s->this_val = JS_DupValue(ctx, this_obj);\n    s->argc = argc;\n    sf->arg_count = arg_buf_len;\n    sf->var_buf = sf->arg_buf + arg_buf_len;\n    sf->cur_sp = sf->var_buf + b->var_count;\n    sf->var_refs = (JSVarRef **)(sf->cur_sp + b->stack_size);\n    for(i = 0; i < b->var_ref_count; i++)\n        sf->var_refs[i] = NULL;\n    for(i = 0; i < argc; i++)\n        sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);\n    n = arg_buf_len + b->var_count;\n    for(i = argc; i < n; i++)\n        sf->arg_buf[i] = JS_UNDEFINED;\n    s->resolving_funcs[0] = JS_UNDEFINED;\n    s->resolving_funcs[1] = JS_UNDEFINED;\n    s->is_completed = FALSE;\n    return s;\n}\n\nstatic void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s)\n{\n    JSStackFrame *sf = &s->frame;\n    JSValue *sp;\n\n    /* cannot free the function if it is running */\n    assert(sf->cur_sp != NULL);\n    for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {\n        JS_FreeValueRT(rt, *sp);\n    }\n    JS_FreeValueRT(rt, sf->cur_func);\n    JS_FreeValueRT(rt, s->this_val);\n}\n\nstatic JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)\n{\n    JSRuntime *rt = ctx->rt;\n    JSStackFrame *sf = &s->frame;\n    JSValue func_obj, ret;\n\n    assert(!s->is_completed);\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        ret = JS_ThrowStackOverflow(ctx);\n    } else {\n        /* the tag does not matter provided it is not an object */\n        func_obj = JS_MKPTR(JS_TAG_INT, s);\n        ret = JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,\n                              s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);\n    }\n    if (JS_IsException(ret) || JS_IsUndefined(ret)) {\n        JSObject *p;\n        JSFunctionBytecode *b;\n        \n        p = JS_VALUE_GET_OBJ(sf->cur_func);\n        b = p->u.func.function_bytecode;\n        \n        if (JS_IsUndefined(ret)) {\n            ret = sf->cur_sp[-1];\n            sf->cur_sp[-1] = JS_UNDEFINED;\n        }\n        /* end of execution */\n        s->is_completed = TRUE;\n\n        /* close the closure variables. */\n        close_var_refs(rt, b, sf);\n        \n        async_func_free_frame(rt, s);\n    }\n    return ret;\n}\n\nstatic void __async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)\n{\n    /* cannot close the closure variables here because it would\n       potentially modify the object graph */\n    if (!s->is_completed) {\n        async_func_free_frame(rt, s);\n    }\n\n    JS_FreeValueRT(rt, s->resolving_funcs[0]);\n    JS_FreeValueRT(rt, s->resolving_funcs[1]);\n\n    remove_gc_object(&s->header);\n    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && s->header.ref_count != 0) {\n        list_add_tail(&s->header.link, &rt->gc_zero_ref_count_list);\n    } else {\n        js_free_rt(rt, s);\n    }\n}\n\nstatic void async_func_free(JSRuntime *rt, JSAsyncFunctionState *s)\n{\n    if (--s->header.ref_count == 0) {\n        if (rt->gc_phase != JS_GC_PHASE_REMOVE_CYCLES) {\n            list_del(&s->header.link);\n            list_add(&s->header.link, &rt->gc_zero_ref_count_list);\n            if (rt->gc_phase == JS_GC_PHASE_NONE) {\n                free_zero_refcount(rt);\n            }\n        }\n    }\n}\n\n/* Generators */\n\ntypedef enum JSGeneratorStateEnum {\n    JS_GENERATOR_STATE_SUSPENDED_START,\n    JS_GENERATOR_STATE_SUSPENDED_YIELD,\n    JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR,\n    JS_GENERATOR_STATE_EXECUTING,\n    JS_GENERATOR_STATE_COMPLETED,\n} JSGeneratorStateEnum;\n\ntypedef struct JSGeneratorData {\n    JSGeneratorStateEnum state;\n    JSAsyncFunctionState *func_state;\n} JSGeneratorData;\n\nstatic void free_generator_stack_rt(JSRuntime *rt, JSGeneratorData *s)\n{\n    if (s->state == JS_GENERATOR_STATE_COMPLETED)\n        return;\n    if (s->func_state) {\n        async_func_free(rt, s->func_state);\n        s->func_state = NULL;\n    }\n    s->state = JS_GENERATOR_STATE_COMPLETED;\n}\n\nstatic void js_generator_finalizer(JSRuntime *rt, JSValue obj)\n{\n    JSGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_GENERATOR);\n\n    if (s) {\n        free_generator_stack_rt(rt, s);\n        js_free_rt(rt, s);\n    }\n}\n\nstatic void free_generator_stack(JSContext *ctx, JSGeneratorData *s)\n{\n    free_generator_stack_rt(ctx->rt, s);\n}\n\nstatic void js_generator_mark(JSRuntime *rt, JSValueConst val,\n                              JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSGeneratorData *s = p->u.generator_data;\n\n    if (!s || !s->func_state)\n        return;\n    mark_func(rt, &s->func_state->header);\n}\n\n/* XXX: use enum */\n#define GEN_MAGIC_NEXT   0\n#define GEN_MAGIC_RETURN 1\n#define GEN_MAGIC_THROW  2\n\nstatic JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv,\n                                 BOOL *pdone, int magic)\n{\n    JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);\n    JSStackFrame *sf;\n    JSValue ret, func_ret;\n\n    *pdone = TRUE;\n    if (!s)\n        return JS_ThrowTypeError(ctx, \"not a generator\");\n    switch(s->state) {\n    default:\n    case JS_GENERATOR_STATE_SUSPENDED_START:\n        sf = &s->func_state->frame;\n        if (magic == GEN_MAGIC_NEXT) {\n            goto exec_no_arg;\n        } else {\n            free_generator_stack(ctx, s);\n            goto done;\n        }\n        break;\n    case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:\n    case JS_GENERATOR_STATE_SUSPENDED_YIELD:\n        sf = &s->func_state->frame;\n        /* cur_sp[-1] was set to JS_UNDEFINED in the previous call */\n        ret = JS_DupValue(ctx, argv[0]);\n        if (magic == GEN_MAGIC_THROW &&\n            s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {\n            JS_Throw(ctx, ret);\n            s->func_state->throw_flag = TRUE;\n        } else {\n            sf->cur_sp[-1] = ret;\n            sf->cur_sp[0] = JS_NewInt32(ctx, magic);\n            sf->cur_sp++;\n        exec_no_arg:\n            s->func_state->throw_flag = FALSE;\n        }\n        s->state = JS_GENERATOR_STATE_EXECUTING;\n        func_ret = async_func_resume(ctx, s->func_state);\n        s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD;\n        if (s->func_state->is_completed) {\n            /* finalize the execution in case of exception or normal return */\n            free_generator_stack(ctx, s);\n            return func_ret;\n        } else {\n            assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);\n            /* get the returned yield value at the top of the stack */\n            ret = sf->cur_sp[-1];\n            sf->cur_sp[-1] = JS_UNDEFINED;\n            if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {\n                s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;\n                /* return (value, done) object */\n                *pdone = 2;\n            } else {\n                *pdone = FALSE;\n            }\n        }\n        break;\n    case JS_GENERATOR_STATE_COMPLETED:\n    done:\n        /* execution is finished */\n        switch(magic) {\n        default:\n        case GEN_MAGIC_NEXT:\n            ret = JS_UNDEFINED;\n            break;\n        case GEN_MAGIC_RETURN:\n            ret = JS_DupValue(ctx, argv[0]);\n            break;\n        case GEN_MAGIC_THROW:\n            ret = JS_Throw(ctx, JS_DupValue(ctx, argv[0]));\n            break;\n        }\n        break;\n    case JS_GENERATOR_STATE_EXECUTING:\n        ret = JS_ThrowTypeError(ctx, \"cannot invoke a running generator\");\n        break;\n    }\n    return ret;\n}\n\nstatic JSValue js_generator_function_call(JSContext *ctx, JSValueConst func_obj,\n                                          JSValueConst this_obj,\n                                          int argc, JSValueConst *argv,\n                                          int flags)\n{\n    JSValue obj, func_ret;\n    JSGeneratorData *s;\n\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s)\n        return JS_EXCEPTION;\n    s->state = JS_GENERATOR_STATE_SUSPENDED_START;\n    s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);\n    if (!s->func_state) {\n        s->state = JS_GENERATOR_STATE_COMPLETED;\n        goto fail;\n    }\n\n    /* execute the function up to 'OP_initial_yield' */\n    func_ret = async_func_resume(ctx, s->func_state);\n    if (JS_IsException(func_ret))\n        goto fail;\n    JS_FreeValue(ctx, func_ret);\n\n    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_GENERATOR);\n    if (JS_IsException(obj))\n        goto fail;\n    JS_SetOpaque(obj, s);\n    return obj;\n fail:\n    free_generator_stack_rt(ctx->rt, s);\n    js_free(ctx, s);\n    return JS_EXCEPTION;\n}\n\n/* AsyncFunction */\n\nstatic void js_async_function_resolve_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSAsyncFunctionState *s = p->u.async_function_data;\n    if (s) {\n        async_func_free(rt, s);\n    }\n}\n\nstatic void js_async_function_resolve_mark(JSRuntime *rt, JSValueConst val,\n                                           JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSAsyncFunctionState *s = p->u.async_function_data;\n    if (s) {\n        mark_func(rt, &s->header);\n    }\n}\n\nstatic int js_async_function_resolve_create(JSContext *ctx,\n                                            JSAsyncFunctionState *s,\n                                            JSValue *resolving_funcs)\n{\n    int i;\n    JSObject *p;\n\n    for(i = 0; i < 2; i++) {\n        resolving_funcs[i] =\n            JS_NewObjectProtoClass(ctx, ctx->function_proto,\n                                   JS_CLASS_ASYNC_FUNCTION_RESOLVE + i);\n        if (JS_IsException(resolving_funcs[i])) {\n            if (i == 1)\n                JS_FreeValue(ctx, resolving_funcs[0]);\n            return -1;\n        }\n        p = JS_VALUE_GET_OBJ(resolving_funcs[i]);\n        s->header.ref_count++;\n        p->u.async_function_data = s;\n    }\n    return 0;\n}\n\nstatic void js_async_function_resume(JSContext *ctx, JSAsyncFunctionState *s)\n{\n    JSValue func_ret, ret2;\n\n    func_ret = async_func_resume(ctx, s);\n    if (s->is_completed) {\n        if (JS_IsException(func_ret)) {\n            JSValue error;\n        fail:\n            error = JS_GetException(ctx);\n            ret2 = JS_Call(ctx, s->resolving_funcs[1], JS_UNDEFINED,\n                           1, (JSValueConst *)&error);\n            JS_FreeValue(ctx, error);\n            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */\n        } else {\n            /* normal return */\n            ret2 = JS_Call(ctx, s->resolving_funcs[0], JS_UNDEFINED,\n                           1, (JSValueConst *)&func_ret);\n            JS_FreeValue(ctx, func_ret);\n            JS_FreeValue(ctx, ret2); /* XXX: what to do if exception ? */\n        }\n    } else {\n        JSValue value, promise, resolving_funcs[2], resolving_funcs1[2];\n        int i, res;\n\n        value = s->frame.cur_sp[-1];\n        s->frame.cur_sp[-1] = JS_UNDEFINED;\n\n        /* await */\n        JS_FreeValue(ctx, func_ret); /* not used */\n        promise = js_promise_resolve(ctx, ctx->promise_ctor,\n                                     1, (JSValueConst *)&value, 0);\n        JS_FreeValue(ctx, value);\n        if (JS_IsException(promise))\n            goto fail;\n        if (js_async_function_resolve_create(ctx, s, resolving_funcs)) {\n            JS_FreeValue(ctx, promise);\n            goto fail;\n        }\n\n        /* Note: no need to create 'thrownawayCapability' as in\n           the spec */\n        for(i = 0; i < 2; i++)\n            resolving_funcs1[i] = JS_UNDEFINED;\n        res = perform_promise_then(ctx, promise,\n                                   (JSValueConst *)resolving_funcs,\n                                   (JSValueConst *)resolving_funcs1);\n        JS_FreeValue(ctx, promise);\n        for(i = 0; i < 2; i++)\n            JS_FreeValue(ctx, resolving_funcs[i]);\n        if (res)\n            goto fail;\n    }\n}\n\nstatic JSValue js_async_function_resolve_call(JSContext *ctx,\n                                              JSValueConst func_obj,\n                                              JSValueConst this_obj,\n                                              int argc, JSValueConst *argv,\n                                              int flags)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(func_obj);\n    JSAsyncFunctionState *s = p->u.async_function_data;\n    BOOL is_reject = p->class_id - JS_CLASS_ASYNC_FUNCTION_RESOLVE;\n    JSValueConst arg;\n\n    if (argc > 0)\n        arg = argv[0];\n    else\n        arg = JS_UNDEFINED;\n    s->throw_flag = is_reject;\n    if (is_reject) {\n        JS_Throw(ctx, JS_DupValue(ctx, arg));\n    } else {\n        /* return value of await */\n        s->frame.cur_sp[-1] = JS_DupValue(ctx, arg);\n    }\n    js_async_function_resume(ctx, s);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_async_function_call(JSContext *ctx, JSValueConst func_obj,\n                                      JSValueConst this_obj,\n                                      int argc, JSValueConst *argv, int flags)\n{\n    JSValue promise;\n    JSAsyncFunctionState *s;\n\n    s = async_func_init(ctx, func_obj, this_obj, argc, argv);\n    if (!s)\n        return JS_EXCEPTION;\n\n    promise = JS_NewPromiseCapability(ctx, s->resolving_funcs);\n    if (JS_IsException(promise)) {\n        async_func_free(ctx->rt, s);\n        return JS_EXCEPTION;\n    }\n\n    js_async_function_resume(ctx, s);\n\n    async_func_free(ctx->rt, s);\n\n    return promise;\n}\n\n/* AsyncGenerator */\n\ntypedef enum JSAsyncGeneratorStateEnum {\n    JS_ASYNC_GENERATOR_STATE_SUSPENDED_START,\n    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD,\n    JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR,\n    JS_ASYNC_GENERATOR_STATE_EXECUTING,\n    JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN,\n    JS_ASYNC_GENERATOR_STATE_COMPLETED,\n} JSAsyncGeneratorStateEnum;\n\ntypedef struct JSAsyncGeneratorRequest {\n    struct list_head link;\n    /* completion */\n    int completion_type; /* GEN_MAGIC_x */\n    JSValue result;\n    /* promise capability */\n    JSValue promise;\n    JSValue resolving_funcs[2];\n} JSAsyncGeneratorRequest;\n\ntypedef struct JSAsyncGeneratorData {\n    JSObject *generator; /* back pointer to the object (const) */\n    JSAsyncGeneratorStateEnum state;\n    /* func_state is NULL is state AWAITING_RETURN and COMPLETED */\n    JSAsyncFunctionState *func_state;\n    struct list_head queue; /* list of JSAsyncGeneratorRequest.link */\n} JSAsyncGeneratorData;\n\nstatic void js_async_generator_free(JSRuntime *rt,\n                                    JSAsyncGeneratorData *s)\n{\n    struct list_head *el, *el1;\n    JSAsyncGeneratorRequest *req;\n\n    list_for_each_safe(el, el1, &s->queue) {\n        req = list_entry(el, JSAsyncGeneratorRequest, link);\n        JS_FreeValueRT(rt, req->result);\n        JS_FreeValueRT(rt, req->promise);\n        JS_FreeValueRT(rt, req->resolving_funcs[0]);\n        JS_FreeValueRT(rt, req->resolving_funcs[1]);\n        js_free_rt(rt, req);\n    }\n    if (s->func_state)\n        async_func_free(rt, s->func_state);\n    js_free_rt(rt, s);\n}\n\nstatic void js_async_generator_finalizer(JSRuntime *rt, JSValue obj)\n{\n    JSAsyncGeneratorData *s = JS_GetOpaque(obj, JS_CLASS_ASYNC_GENERATOR);\n\n    if (s) {\n        js_async_generator_free(rt, s);\n    }\n}\n\nstatic void js_async_generator_mark(JSRuntime *rt, JSValueConst val,\n                                    JS_MarkFunc *mark_func)\n{\n    JSAsyncGeneratorData *s = JS_GetOpaque(val, JS_CLASS_ASYNC_GENERATOR);\n    struct list_head *el;\n    JSAsyncGeneratorRequest *req;\n    if (s) {\n        list_for_each(el, &s->queue) {\n            req = list_entry(el, JSAsyncGeneratorRequest, link);\n            JS_MarkValue(rt, req->result, mark_func);\n            JS_MarkValue(rt, req->promise, mark_func);\n            JS_MarkValue(rt, req->resolving_funcs[0], mark_func);\n            JS_MarkValue(rt, req->resolving_funcs[1], mark_func);\n        }\n        if (s->func_state) {\n            mark_func(rt, &s->func_state->header);\n        }\n    }\n}\n\nstatic JSValue js_async_generator_resolve_function(JSContext *ctx,\n                                          JSValueConst this_obj,\n                                          int argc, JSValueConst *argv,\n                                          int magic, JSValue *func_data);\n\nstatic int js_async_generator_resolve_function_create(JSContext *ctx,\n                                                      JSValueConst generator,\n                                                      JSValue *resolving_funcs,\n                                                      BOOL is_resume_next)\n{\n    int i;\n    JSValue func;\n\n    for(i = 0; i < 2; i++) {\n        func = JS_NewCFunctionData(ctx, js_async_generator_resolve_function, 1,\n                                   i + is_resume_next * 2, 1, &generator);\n        if (JS_IsException(func)) {\n            if (i == 1)\n                JS_FreeValue(ctx, resolving_funcs[0]);\n            return -1;\n        }\n        resolving_funcs[i] = func;\n    }\n    return 0;\n}\n\nstatic int js_async_generator_await(JSContext *ctx,\n                                    JSAsyncGeneratorData *s,\n                                    JSValueConst value)\n{\n    JSValue promise, resolving_funcs[2], resolving_funcs1[2];\n    int i, res;\n\n    promise = js_promise_resolve(ctx, ctx->promise_ctor,\n                                 1, &value, 0);\n    if (JS_IsException(promise))\n        goto fail;\n\n    if (js_async_generator_resolve_function_create(ctx, JS_MKPTR(JS_TAG_OBJECT, s->generator),\n                                                   resolving_funcs, FALSE)) {\n        JS_FreeValue(ctx, promise);\n        goto fail;\n    }\n\n    /* Note: no need to create 'thrownawayCapability' as in\n       the spec */\n    for(i = 0; i < 2; i++)\n        resolving_funcs1[i] = JS_UNDEFINED;\n    res = perform_promise_then(ctx, promise,\n                               (JSValueConst *)resolving_funcs,\n                               (JSValueConst *)resolving_funcs1);\n    JS_FreeValue(ctx, promise);\n    for(i = 0; i < 2; i++)\n        JS_FreeValue(ctx, resolving_funcs[i]);\n    if (res)\n        goto fail;\n    return 0;\n fail:\n    return -1;\n}\n\nstatic void js_async_generator_resolve_or_reject(JSContext *ctx,\n                                                 JSAsyncGeneratorData *s,\n                                                 JSValueConst result,\n                                                 int is_reject)\n{\n    JSAsyncGeneratorRequest *next;\n    JSValue ret;\n\n    next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);\n    list_del(&next->link);\n    ret = JS_Call(ctx, next->resolving_funcs[is_reject], JS_UNDEFINED, 1,\n                  &result);\n    JS_FreeValue(ctx, ret);\n    JS_FreeValue(ctx, next->result);\n    JS_FreeValue(ctx, next->promise);\n    JS_FreeValue(ctx, next->resolving_funcs[0]);\n    JS_FreeValue(ctx, next->resolving_funcs[1]);\n    js_free(ctx, next);\n}\n\nstatic void js_async_generator_resolve(JSContext *ctx,\n                                       JSAsyncGeneratorData *s,\n                                       JSValueConst value,\n                                       BOOL done)\n{\n    JSValue result;\n    result = js_create_iterator_result(ctx, JS_DupValue(ctx, value), done);\n    /* XXX: better exception handling ? */\n    js_async_generator_resolve_or_reject(ctx, s, result, 0);\n    JS_FreeValue(ctx, result);\n }\n\nstatic void js_async_generator_reject(JSContext *ctx,\n                                       JSAsyncGeneratorData *s,\n                                       JSValueConst exception)\n{\n    js_async_generator_resolve_or_reject(ctx, s, exception, 1);\n}\n\nstatic void js_async_generator_complete(JSContext *ctx,\n                                        JSAsyncGeneratorData *s)\n{\n    if (s->state != JS_ASYNC_GENERATOR_STATE_COMPLETED) {\n        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;\n        async_func_free(ctx->rt, s->func_state);\n        s->func_state = NULL;\n    }\n}\n\nstatic int js_async_generator_completed_return(JSContext *ctx,\n                                               JSAsyncGeneratorData *s,\n                                               JSValueConst value)\n{\n    JSValue promise, resolving_funcs[2], resolving_funcs1[2];\n    int res;\n\n    // Can fail looking up JS_ATOM_constructor when is_reject==0.\n    promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, &value,\n                                 /*is_reject*/0);\n    // A poisoned .constructor property is observable and the resulting\n    // exception should be delivered to the catch handler.\n    if (JS_IsException(promise)) {\n        JSValue err = JS_GetException(ctx);\n        promise = js_promise_resolve(ctx, ctx->promise_ctor, 1, (JSValueConst *)&err,\n                                     /*is_reject*/1);\n        JS_FreeValue(ctx, err);\n        if (JS_IsException(promise))\n            return -1;\n    }\n    if (js_async_generator_resolve_function_create(ctx,\n                                                   JS_MKPTR(JS_TAG_OBJECT, s->generator),\n                                                   resolving_funcs1,\n                                                   TRUE)) {\n        JS_FreeValue(ctx, promise);\n        return -1;\n    }\n    resolving_funcs[0] = JS_UNDEFINED;\n    resolving_funcs[1] = JS_UNDEFINED;\n    res = perform_promise_then(ctx, promise,\n                               (JSValueConst *)resolving_funcs1,\n                               (JSValueConst *)resolving_funcs);\n    JS_FreeValue(ctx, resolving_funcs1[0]);\n    JS_FreeValue(ctx, resolving_funcs1[1]);\n    JS_FreeValue(ctx, promise);\n    return res;\n}\n\nstatic void js_async_generator_resume_next(JSContext *ctx,\n                                           JSAsyncGeneratorData *s)\n{\n    JSAsyncGeneratorRequest *next;\n    JSValue func_ret, value;\n\n    for(;;) {\n        if (list_empty(&s->queue))\n            break;\n        next = list_entry(s->queue.next, JSAsyncGeneratorRequest, link);\n        switch(s->state) {\n        case JS_ASYNC_GENERATOR_STATE_EXECUTING:\n            /* only happens when restarting execution after await() */\n            goto resume_exec;\n        case JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN:\n            goto done;\n        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_START:\n            if (next->completion_type == GEN_MAGIC_NEXT) {\n                goto exec_no_arg;\n            } else {\n                js_async_generator_complete(ctx, s);\n            }\n            break;\n        case JS_ASYNC_GENERATOR_STATE_COMPLETED:\n            if (next->completion_type == GEN_MAGIC_NEXT) {\n                js_async_generator_resolve(ctx, s, JS_UNDEFINED, TRUE);\n            } else if (next->completion_type == GEN_MAGIC_RETURN) {\n                s->state = JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN;\n                js_async_generator_completed_return(ctx, s, next->result);\n            } else {\n                js_async_generator_reject(ctx, s, next->result);\n            }\n            goto done;\n        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD:\n        case JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR:\n            value = JS_DupValue(ctx, next->result);\n            if (next->completion_type == GEN_MAGIC_THROW &&\n                s->state == JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD) {\n                JS_Throw(ctx, value);\n                s->func_state->throw_flag = TRUE;\n            } else {\n                /* 'yield' returns a value. 'yield *' also returns a value\n                   in case the 'throw' method is called */\n                s->func_state->frame.cur_sp[-1] = value;\n                s->func_state->frame.cur_sp[0] =\n                    JS_NewInt32(ctx, next->completion_type);\n                s->func_state->frame.cur_sp++;\n            exec_no_arg:\n                s->func_state->throw_flag = FALSE;\n            }\n            s->state = JS_ASYNC_GENERATOR_STATE_EXECUTING;\n        resume_exec:\n            func_ret = async_func_resume(ctx, s->func_state);\n            if (s->func_state->is_completed) {\n                if (JS_IsException(func_ret)) {\n                    value = JS_GetException(ctx);\n                    js_async_generator_complete(ctx, s);\n                    js_async_generator_reject(ctx, s, value);\n                    JS_FreeValue(ctx, value);\n                } else {\n                    /* end of function */\n                    js_async_generator_complete(ctx, s);\n                    js_async_generator_resolve(ctx, s, func_ret, TRUE);\n                    JS_FreeValue(ctx, func_ret);\n                }\n            } else {\n                int func_ret_code, ret;\n                assert(JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT);\n                func_ret_code = JS_VALUE_GET_INT(func_ret);\n                value = s->func_state->frame.cur_sp[-1];\n                s->func_state->frame.cur_sp[-1] = JS_UNDEFINED;\n                switch(func_ret_code) {\n                case FUNC_RET_YIELD:\n                case FUNC_RET_YIELD_STAR:\n                    if (func_ret_code == FUNC_RET_YIELD_STAR)\n                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD_STAR;\n                    else\n                        s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_YIELD;\n                    js_async_generator_resolve(ctx, s, value, FALSE);\n                    JS_FreeValue(ctx, value);\n                    break;\n                case FUNC_RET_AWAIT:\n                    ret = js_async_generator_await(ctx, s, value);\n                    JS_FreeValue(ctx, value);\n                    if (ret < 0) {\n                        /* exception: throw it */\n                        s->func_state->throw_flag = TRUE;\n                        goto resume_exec;\n                    }\n                    goto done;\n                default:\n                    abort();\n                }\n            }\n            break;\n        default:\n            abort();\n        }\n    }\n done: ;\n}\n\nstatic JSValue js_async_generator_resolve_function(JSContext *ctx,\n                                                   JSValueConst this_obj,\n                                                   int argc, JSValueConst *argv,\n                                                   int magic, JSValue *func_data)\n{\n    BOOL is_reject = magic & 1;\n    JSAsyncGeneratorData *s = JS_GetOpaque(func_data[0], JS_CLASS_ASYNC_GENERATOR);\n    JSValueConst arg = argv[0];\n\n    /* XXX: what if s == NULL */\n\n    if (magic >= 2) {\n        /* resume next case in AWAITING_RETURN state */\n        assert(s->state == JS_ASYNC_GENERATOR_STATE_AWAITING_RETURN ||\n               s->state == JS_ASYNC_GENERATOR_STATE_COMPLETED);\n        s->state = JS_ASYNC_GENERATOR_STATE_COMPLETED;\n        if (is_reject) {\n            js_async_generator_reject(ctx, s, arg);\n        } else {\n            js_async_generator_resolve(ctx, s, arg, TRUE);\n        }\n    } else {\n        /* restart function execution after await() */\n        assert(s->state == JS_ASYNC_GENERATOR_STATE_EXECUTING);\n        s->func_state->throw_flag = is_reject;\n        if (is_reject) {\n            JS_Throw(ctx, JS_DupValue(ctx, arg));\n        } else {\n            /* return value of await */\n            s->func_state->frame.cur_sp[-1] = JS_DupValue(ctx, arg);\n        }\n        js_async_generator_resume_next(ctx, s);\n    }\n    return JS_UNDEFINED;\n}\n\n/* magic = GEN_MAGIC_x */\nstatic JSValue js_async_generator_next(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv,\n                                       int magic)\n{\n    JSAsyncGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_GENERATOR);\n    JSValue promise, resolving_funcs[2];\n    JSAsyncGeneratorRequest *req;\n\n    promise = JS_NewPromiseCapability(ctx, resolving_funcs);\n    if (JS_IsException(promise))\n        return JS_EXCEPTION;\n    if (!s) {\n        JSValue err, res2;\n        JS_ThrowTypeError(ctx, \"not an AsyncGenerator object\");\n        err = JS_GetException(ctx);\n        res2 = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,\n                       1, (JSValueConst *)&err);\n        JS_FreeValue(ctx, err);\n        JS_FreeValue(ctx, res2);\n        JS_FreeValue(ctx, resolving_funcs[0]);\n        JS_FreeValue(ctx, resolving_funcs[1]);\n        return promise;\n    }\n    req = js_mallocz(ctx, sizeof(*req));\n    if (!req)\n        goto fail;\n    req->completion_type = magic;\n    req->result = JS_DupValue(ctx, argv[0]);\n    req->promise = JS_DupValue(ctx, promise);\n    req->resolving_funcs[0] = resolving_funcs[0];\n    req->resolving_funcs[1] = resolving_funcs[1];\n    list_add_tail(&req->link, &s->queue);\n    if (s->state != JS_ASYNC_GENERATOR_STATE_EXECUTING) {\n        js_async_generator_resume_next(ctx, s);\n    }\n    return promise;\n fail:\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    JS_FreeValue(ctx, promise);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_async_generator_function_call(JSContext *ctx, JSValueConst func_obj,\n                                                JSValueConst this_obj,\n                                                int argc, JSValueConst *argv,\n                                                int flags)\n{\n    JSValue obj, func_ret;\n    JSAsyncGeneratorData *s;\n\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s)\n        return JS_EXCEPTION;\n    s->state = JS_ASYNC_GENERATOR_STATE_SUSPENDED_START;\n    init_list_head(&s->queue);\n    s->func_state = async_func_init(ctx, func_obj, this_obj, argc, argv);\n    if (!s->func_state)\n        goto fail;\n    /* execute the function up to 'OP_initial_yield' (no yield nor\n       await are possible) */\n    func_ret = async_func_resume(ctx, s->func_state);\n    if (JS_IsException(func_ret))\n        goto fail;\n    JS_FreeValue(ctx, func_ret);\n\n    obj = js_create_from_ctor(ctx, func_obj, JS_CLASS_ASYNC_GENERATOR);\n    if (JS_IsException(obj))\n        goto fail;\n    s->generator = JS_VALUE_GET_OBJ(obj);\n    JS_SetOpaque(obj, s);\n    return obj;\n fail:\n    js_async_generator_free(ctx->rt, s);\n    return JS_EXCEPTION;\n}\n\n/* JS parser */\n\nenum {\n    TOK_NUMBER = -128,\n    TOK_STRING,\n    TOK_TEMPLATE,\n    TOK_IDENT,\n    TOK_REGEXP,\n    /* warning: order matters (see js_parse_assign_expr) */\n    TOK_MUL_ASSIGN,\n    TOK_DIV_ASSIGN,\n    TOK_MOD_ASSIGN,\n    TOK_PLUS_ASSIGN,\n    TOK_MINUS_ASSIGN,\n    TOK_SHL_ASSIGN,\n    TOK_SAR_ASSIGN,\n    TOK_SHR_ASSIGN,\n    TOK_AND_ASSIGN,\n    TOK_XOR_ASSIGN,\n    TOK_OR_ASSIGN,\n    TOK_POW_ASSIGN,\n    TOK_LAND_ASSIGN,\n    TOK_LOR_ASSIGN,\n    TOK_DOUBLE_QUESTION_MARK_ASSIGN,\n    TOK_DEC,\n    TOK_INC,\n    TOK_SHL,\n    TOK_SAR,\n    TOK_SHR,\n    TOK_LT,\n    TOK_LTE,\n    TOK_GT,\n    TOK_GTE,\n    TOK_EQ,\n    TOK_STRICT_EQ,\n    TOK_NEQ,\n    TOK_STRICT_NEQ,\n    TOK_LAND,\n    TOK_LOR,\n    TOK_POW,\n    TOK_ARROW,\n    TOK_ELLIPSIS,\n    TOK_DOUBLE_QUESTION_MARK,\n    TOK_QUESTION_MARK_DOT,\n    TOK_ERROR,\n    TOK_PRIVATE_NAME,\n    TOK_EOF,\n    /* keywords: WARNING: same order as atoms */\n    TOK_NULL, /* must be first */\n    TOK_FALSE,\n    TOK_TRUE,\n    TOK_IF,\n    TOK_ELSE,\n    TOK_RETURN,\n    TOK_VAR,\n    TOK_THIS,\n    TOK_DELETE,\n    TOK_VOID,\n    TOK_TYPEOF,\n    TOK_NEW,\n    TOK_IN,\n    TOK_INSTANCEOF,\n    TOK_DO,\n    TOK_WHILE,\n    TOK_FOR,\n    TOK_BREAK,\n    TOK_CONTINUE,\n    TOK_SWITCH,\n    TOK_CASE,\n    TOK_DEFAULT,\n    TOK_THROW,\n    TOK_TRY,\n    TOK_CATCH,\n    TOK_FINALLY,\n    TOK_FUNCTION,\n    TOK_DEBUGGER,\n    TOK_WITH,\n    /* FutureReservedWord */\n    TOK_CLASS,\n    TOK_CONST,\n    TOK_ENUM,\n    TOK_EXPORT,\n    TOK_EXTENDS,\n    TOK_IMPORT,\n    TOK_SUPER,\n    /* FutureReservedWords when parsing strict mode code */\n    TOK_IMPLEMENTS,\n    TOK_INTERFACE,\n    TOK_LET,\n    TOK_PACKAGE,\n    TOK_PRIVATE,\n    TOK_PROTECTED,\n    TOK_PUBLIC,\n    TOK_STATIC,\n    TOK_YIELD,\n    TOK_AWAIT, /* must be last */\n    TOK_OF,     /* only used for js_parse_skip_parens_token() */\n};\n\n#define TOK_FIRST_KEYWORD   TOK_NULL\n#define TOK_LAST_KEYWORD    TOK_AWAIT\n\n/* unicode code points */\n#define CP_NBSP 0x00a0\n#define CP_BOM  0xfeff\n\n#define CP_LS   0x2028\n#define CP_PS   0x2029\n\ntypedef struct BlockEnv {\n    struct BlockEnv *prev;\n    JSAtom label_name; /* JS_ATOM_NULL if none */\n    int label_break; /* -1 if none */\n    int label_cont; /* -1 if none */\n    int drop_count; /* number of stack elements to drop */\n    int label_finally; /* -1 if none */\n    int scope_level;\n    uint8_t has_iterator : 1;\n    uint8_t is_regular_stmt : 1; /* i.e. not a loop statement */\n} BlockEnv;\n\ntypedef struct JSGlobalVar {\n    int cpool_idx; /* if >= 0, index in the constant pool for hoisted\n                      function defintion*/\n    uint8_t force_init : 1; /* force initialization to undefined */\n    uint8_t is_lexical : 1; /* global let/const definition */\n    uint8_t is_const   : 1; /* const definition */\n    int scope_level;    /* scope of definition */\n    JSAtom var_name;  /* variable name */\n} JSGlobalVar;\n\ntypedef struct RelocEntry {\n    struct RelocEntry *next;\n    uint32_t addr; /* address to patch */\n    int size;   /* address size: 1, 2 or 4 bytes */\n} RelocEntry;\n\ntypedef struct JumpSlot {\n    int op;\n    int size;\n    int pos;\n    int label;\n} JumpSlot;\n\ntypedef struct LabelSlot {\n    int ref_count;\n    int pos;    /* phase 1 address, -1 means not resolved yet */\n    int pos2;   /* phase 2 address, -1 means not resolved yet */\n    int addr;   /* phase 3 address, -1 means not resolved yet */\n    RelocEntry *first_reloc;\n} LabelSlot;\n\ntypedef struct LineNumberSlot {\n    uint32_t pc;\n    uint32_t source_pos;\n} LineNumberSlot;\n\ntypedef struct {\n    /* last source position */\n    const uint8_t *ptr;\n    int line_num;\n    int col_num;\n    const uint8_t *buf_start;\n} GetLineColCache;\n\ntypedef enum JSParseFunctionEnum {\n    JS_PARSE_FUNC_STATEMENT,\n    JS_PARSE_FUNC_VAR,\n    JS_PARSE_FUNC_EXPR,\n    JS_PARSE_FUNC_ARROW,\n    JS_PARSE_FUNC_GETTER,\n    JS_PARSE_FUNC_SETTER,\n    JS_PARSE_FUNC_METHOD,\n    JS_PARSE_FUNC_CLASS_STATIC_INIT,\n    JS_PARSE_FUNC_CLASS_CONSTRUCTOR,\n    JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR,\n} JSParseFunctionEnum;\n\ntypedef enum JSParseExportEnum {\n    JS_PARSE_EXPORT_NONE,\n    JS_PARSE_EXPORT_NAMED,\n    JS_PARSE_EXPORT_DEFAULT,\n} JSParseExportEnum;\n\ntypedef struct JSVarScope {\n    int parent;  /* index into fd->scopes of the enclosing scope */\n    int first;   /* index into fd->vars of the last variable in this scope */\n} JSVarScope;\n\ntypedef struct JSVarDef {\n    JSAtom var_name;\n    /* index into fd->scopes of this variable lexical scope */\n    int scope_level;\n    /* - if scope_level = 0: scope in which the variable is defined\n       - if scope_level != 0: index into fd->vars of the next\n       variable in the same or enclosing lexical scope\n    */\n    int scope_next;\n    uint8_t is_const : 1;\n    uint8_t is_lexical : 1;\n    uint8_t is_captured : 1; /* XXX: could remove and use a var_ref_idx value */\n    uint8_t is_static_private : 1; /* only used during private class field parsing */\n    uint8_t var_kind : 4; /* see JSVarKindEnum */\n    /* if is_captured = TRUE, provides, the index of the corresponding\n       JSVarRef on stack */\n    uint16_t var_ref_idx;\n    /* function pool index for lexical variables with var_kind =\n       JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of\n       the definition of the 'var' variables (they have scope_level =\n       0) */\n    int func_pool_idx;\n} JSVarDef;\n\ntypedef struct JSFunctionDef {\n    JSContext *ctx;\n    struct JSFunctionDef *parent;\n    int parent_cpool_idx; /* index in the constant pool of the parent\n                             or -1 if none */\n    int parent_scope_level; /* scope level in parent at point of definition */\n    struct list_head child_list; /* list of JSFunctionDef.link */\n    struct list_head link;\n\n    BOOL is_eval; /* TRUE if eval code */\n    int eval_type; /* only valid if is_eval = TRUE */\n    BOOL is_global_var; /* TRUE if variables are not defined locally:\n                           eval global, eval module or non strict eval */\n    BOOL is_func_expr; /* TRUE if function expression */\n    BOOL has_home_object; /* TRUE if the home object is available */\n    BOOL has_prototype; /* true if a prototype field is necessary */\n    BOOL has_simple_parameter_list;\n    BOOL has_parameter_expressions; /* if true, an argument scope is created */\n    BOOL has_use_strict; /* to reject directive in special cases */\n    BOOL has_eval_call; /* true if the function contains a call to eval() */\n    BOOL has_arguments_binding; /* true if the 'arguments' binding is\n                                   available in the function */\n    BOOL has_this_binding; /* true if the 'this' and new.target binding are\n                              available in the function */\n    BOOL new_target_allowed; /* true if the 'new.target' does not\n                                throw a syntax error */\n    BOOL super_call_allowed; /* true if super() is allowed */\n    BOOL super_allowed; /* true if super. or super[] is allowed */\n    BOOL arguments_allowed; /* true if the 'arguments' identifier is allowed */\n    BOOL is_derived_class_constructor;\n    BOOL in_function_body;\n    JSFunctionKindEnum func_kind : 8;\n    JSParseFunctionEnum func_type : 8;\n    uint8_t js_mode; /* bitmap of JS_MODE_x */\n    JSAtom func_name; /* JS_ATOM_NULL if no name */\n\n    JSVarDef *vars;\n    int var_size; /* allocated size for vars[] */\n    int var_count;\n    JSVarDef *args;\n    int arg_size; /* allocated size for args[] */\n    int arg_count; /* number of arguments */\n    int defined_arg_count;\n    int var_ref_count; /* number of local/arg variable references */\n    int var_object_idx; /* -1 if none */\n    int arg_var_object_idx; /* -1 if none (var object for the argument scope) */\n    int arguments_var_idx; /* -1 if none */\n    int arguments_arg_idx; /* argument variable definition in argument scope,\n                              -1 if none */\n    int func_var_idx; /* variable containing the current function (-1\n                         if none, only used if is_func_expr is true) */\n    int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */\n    int this_var_idx; /* variable containg the 'this' value, -1 if none */\n    int new_target_var_idx; /* variable containg the 'new.target' value, -1 if none */\n    int this_active_func_var_idx; /* variable containg the 'this.active_func' value, -1 if none */\n    int home_object_var_idx;\n    BOOL need_home_object;\n\n    int scope_level;    /* index into fd->scopes if the current lexical scope */\n    int scope_first;    /* index into vd->vars of first lexically scoped variable */\n    int scope_size;     /* allocated size of fd->scopes array */\n    int scope_count;    /* number of entries used in the fd->scopes array */\n    JSVarScope *scopes;\n    JSVarScope def_scope_array[4];\n    int body_scope; /* scope of the body of the function or eval */\n\n    int global_var_count;\n    int global_var_size;\n    JSGlobalVar *global_vars;\n\n    DynBuf byte_code;\n    int last_opcode_pos; /* -1 if no last opcode */\n    const uint8_t *last_opcode_source_ptr;\n    BOOL use_short_opcodes; /* true if short opcodes are used in byte_code */\n\n    LabelSlot *label_slots;\n    int label_size; /* allocated size for label_slots[] */\n    int label_count;\n    BlockEnv *top_break; /* break/continue label stack */\n\n    /* constant pool (strings, functions, numbers) */\n    JSValue *cpool;\n    int cpool_count;\n    int cpool_size;\n\n    /* list of variables in the closure */\n    int closure_var_count;\n    int closure_var_size;\n    JSClosureVar *closure_var;\n\n    JumpSlot *jump_slots;\n    int jump_size;\n    int jump_count;\n\n    LineNumberSlot *line_number_slots;\n    int line_number_size;\n    int line_number_count;\n    int line_number_last;\n    int line_number_last_pc;\n\n    /* pc2line table */\n    BOOL strip_debug : 1; /* strip all debug info (implies strip_source = TRUE) */\n    BOOL strip_source : 1; /* strip only source code */\n    JSAtom filename;\n    uint32_t source_pos; /* pointer in the eval() source */\n    GetLineColCache *get_line_col_cache; /* XXX: could remove to save memory */\n    DynBuf pc2line;\n\n    char *source;  /* raw source, utf-8 encoded */\n    int source_len;\n\n    JSModuleDef *module; /* != NULL when parsing a module */\n    BOOL has_await; /* TRUE if await is used (used in module eval) */\n} JSFunctionDef;\n\ntypedef struct JSToken {\n    int val;\n    const uint8_t *ptr; /* position in the source */\n    union {\n        struct {\n            JSValue str;\n            int sep;\n        } str;\n        struct {\n            JSValue val;\n        } num;\n        struct {\n            JSAtom atom;\n            BOOL has_escape;\n            BOOL is_reserved;\n        } ident;\n        struct {\n            JSValue body;\n            JSValue flags;\n        } regexp;\n    } u;\n} JSToken;\n\ntypedef struct JSParseState {\n    JSContext *ctx;\n    const char *filename;\n    JSToken token;\n    BOOL got_lf; /* true if got line feed before the current token */\n    const uint8_t *last_ptr;\n    const uint8_t *buf_start;\n    const uint8_t *buf_ptr;\n    const uint8_t *buf_end;\n\n    /* current function code */\n    JSFunctionDef *cur_func;\n    BOOL is_module; /* parsing a module */\n    BOOL allow_html_comments;\n    BOOL ext_json; /* true if accepting JSON superset */\n    GetLineColCache get_line_col_cache;\n} JSParseState;\n\ntypedef struct JSOpCode {\n#ifdef DUMP_BYTECODE\n    const char *name;\n#endif\n    uint8_t size; /* in bytes */\n    /* the opcodes remove n_pop items from the top of the stack, then\n       pushes n_push items */\n    uint8_t n_pop;\n    uint8_t n_push;\n    uint8_t fmt;\n} JSOpCode;\n\nstatic const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {\n#define FMT(f)\n#ifdef DUMP_BYTECODE\n#define DEF(id, size, n_pop, n_push, f) { #id, size, n_pop, n_push, OP_FMT_ ## f },\n#else\n#define DEF(id, size, n_pop, n_push, f) { size, n_pop, n_push, OP_FMT_ ## f },\n#endif\n#include \"quickjs-opcode.h\"\n#undef DEF\n#undef FMT\n};\n\n#if SHORT_OPCODES\n/* After the final compilation pass, short opcodes are used. Their\n   opcodes overlap with the temporary opcodes which cannot appear in\n   the final bytecode. Their description is after the temporary\n   opcodes in opcode_info[]. */\n#define short_opcode_info(op)           \\\n    opcode_info[(op) >= OP_TEMP_START ? \\\n                (op) + (OP_TEMP_END - OP_TEMP_START) : (op)]\n#else\n#define short_opcode_info(op) opcode_info[op]\n#endif\n\nstatic __exception int next_token(JSParseState *s);\n\nstatic void free_token(JSParseState *s, JSToken *token)\n{\n    switch(token->val) {\n    case TOK_NUMBER:\n        JS_FreeValue(s->ctx, token->u.num.val);\n        break;\n    case TOK_STRING:\n    case TOK_TEMPLATE:\n        JS_FreeValue(s->ctx, token->u.str.str);\n        break;\n    case TOK_REGEXP:\n        JS_FreeValue(s->ctx, token->u.regexp.body);\n        JS_FreeValue(s->ctx, token->u.regexp.flags);\n        break;\n    case TOK_IDENT:\n    case TOK_PRIVATE_NAME:\n        JS_FreeAtom(s->ctx, token->u.ident.atom);\n        break;\n    default:\n        if (token->val >= TOK_FIRST_KEYWORD &&\n            token->val <= TOK_LAST_KEYWORD) {\n            JS_FreeAtom(s->ctx, token->u.ident.atom);\n        }\n        break;\n    }\n}\n\nstatic void __attribute((unused)) dump_token(JSParseState *s,\n                                             const JSToken *token)\n{\n    switch(token->val) {\n    case TOK_NUMBER:\n        {\n            double d;\n            JS_ToFloat64(s->ctx, &d, token->u.num.val);  /* no exception possible */\n            printf(\"number: %.14g\\n\", d);\n        }\n        break;\n    case TOK_IDENT:\n    dump_atom:\n        {\n            char buf[ATOM_GET_STR_BUF_SIZE];\n            printf(\"ident: '%s'\\n\",\n                   JS_AtomGetStr(s->ctx, buf, sizeof(buf), token->u.ident.atom));\n        }\n        break;\n    case TOK_STRING:\n        {\n            const char *str;\n            /* XXX: quote the string */\n            str = JS_ToCString(s->ctx, token->u.str.str);\n            printf(\"string: '%s'\\n\", str);\n            JS_FreeCString(s->ctx, str);\n        }\n        break;\n    case TOK_TEMPLATE:\n        {\n            const char *str;\n            str = JS_ToCString(s->ctx, token->u.str.str);\n            printf(\"template: `%s`\\n\", str);\n            JS_FreeCString(s->ctx, str);\n        }\n        break;\n    case TOK_REGEXP:\n        {\n            const char *str, *str2;\n            str = JS_ToCString(s->ctx, token->u.regexp.body);\n            str2 = JS_ToCString(s->ctx, token->u.regexp.flags);\n            printf(\"regexp: '%s' '%s'\\n\", str, str2);\n            JS_FreeCString(s->ctx, str);\n            JS_FreeCString(s->ctx, str2);\n        }\n        break;\n    case TOK_EOF:\n        printf(\"eof\\n\");\n        break;\n    default:\n        if (s->token.val >= TOK_NULL && s->token.val <= TOK_LAST_KEYWORD) {\n            goto dump_atom;\n        } else if (s->token.val >= 256) {\n            printf(\"token: %d\\n\", token->val);\n        } else {\n            printf(\"token: '%c'\\n\", token->val);\n        }\n        break;\n    }\n}\n\n/* return the zero based line and column number in the source. */\n/* Note: we no longer support '\\r' as line terminator */\nstatic int get_line_col(int *pcol_num, const uint8_t *buf, size_t len)\n{\n    int line_num, col_num, c;\n    size_t i;\n    \n    line_num = 0;\n    col_num = 0;\n    for(i = 0; i < len; i++) {\n        c = buf[i];\n        if (c == '\\n') {\n            line_num++;\n            col_num = 0;\n        } else if (c < 0x80 || c >= 0xc0) {\n            col_num++;\n        }\n    }\n    *pcol_num = col_num;\n    return line_num;\n}\n\nstatic int get_line_col_cached(GetLineColCache *s, int *pcol_num, const uint8_t *ptr)\n{\n    int line_num, col_num;\n    if (ptr >= s->ptr) {\n        line_num = get_line_col(&col_num, s->ptr, ptr - s->ptr);\n        if (line_num == 0) {\n            s->col_num += col_num;\n        } else {\n            s->line_num += line_num;\n            s->col_num = col_num;\n        }\n    } else {\n        line_num = get_line_col(&col_num, ptr, s->ptr - ptr);\n        if (line_num == 0) {\n            s->col_num -= col_num;\n        } else {\n            const uint8_t *p;\n            s->line_num -= line_num;\n            /* find the absolute column position */\n            col_num = 0;\n            for(p = ptr - 1; p >= s->buf_start; p--) {\n                if (*p == '\\n') {\n                    break;\n                } else if (*p < 0x80 || *p >= 0xc0) {\n                    col_num++;\n                }\n            }\n            s->col_num = col_num;\n        }\n    }\n    s->ptr = ptr;\n    *pcol_num = s->col_num;\n    return s->line_num;\n}\n\n/* 'ptr' is the position of the error in the source */\nstatic int js_parse_error_v(JSParseState *s, const uint8_t *ptr, const char *fmt, va_list ap)\n{\n    JSContext *ctx = s->ctx;\n    int line_num, col_num;\n    line_num = get_line_col(&col_num, s->buf_start, ptr - s->buf_start);\n    JS_ThrowError2(ctx, JS_SYNTAX_ERROR, fmt, ap, FALSE);\n    build_backtrace(ctx, ctx->rt->current_exception, s->filename,\n                    line_num + 1, col_num + 1, 0);\n    return -1;\n}\n\nstatic __attribute__((format(printf, 3, 4))) int js_parse_error_pos(JSParseState *s, const uint8_t *ptr, const char *fmt, ...)\n{\n    va_list ap;\n    int ret;\n    \n    va_start(ap, fmt);\n    ret = js_parse_error_v(s, ptr, fmt, ap);\n    va_end(ap);\n    return ret;\n}\n\nstatic __attribute__((format(printf, 2, 3))) int js_parse_error(JSParseState *s, const char *fmt, ...)\n{\n    va_list ap;\n    int ret;\n    \n    va_start(ap, fmt);\n    ret = js_parse_error_v(s, s->token.ptr, fmt, ap);\n    va_end(ap);\n    return ret;\n}\n\nstatic int js_parse_expect(JSParseState *s, int tok)\n{\n    if (s->token.val != tok) {\n        /* XXX: dump token correctly in all cases */\n        return js_parse_error(s, \"expecting '%c'\", tok);\n    }\n    return next_token(s);\n}\n\nstatic int js_parse_expect_semi(JSParseState *s)\n{\n    if (s->token.val != ';') {\n        /* automatic insertion of ';' */\n        if (s->token.val == TOK_EOF || s->token.val == '}' || s->got_lf) {\n            return 0;\n        }\n        return js_parse_error(s, \"expecting '%c'\", ';');\n    }\n    return next_token(s);\n}\n\nstatic int js_parse_error_reserved_identifier(JSParseState *s)\n{\n    char buf1[ATOM_GET_STR_BUF_SIZE];\n    return js_parse_error(s, \"'%s' is a reserved identifier\",\n                          JS_AtomGetStr(s->ctx, buf1, sizeof(buf1),\n                                        s->token.u.ident.atom));\n}\n\nstatic __exception int js_parse_template_part(JSParseState *s, const uint8_t *p)\n{\n    uint32_t c;\n    StringBuffer b_s, *b = &b_s;\n    JSValue str;\n\n    /* p points to the first byte of the template part */\n    if (string_buffer_init(s->ctx, b, 32))\n        goto fail;\n    for(;;) {\n        if (p >= s->buf_end)\n            goto unexpected_eof;\n        c = *p++;\n        if (c == '`') {\n            /* template end part */\n            break;\n        }\n        if (c == '$' && *p == '{') {\n            /* template start or middle part */\n            p++;\n            break;\n        }\n        if (c == '\\\\') {\n            if (string_buffer_putc8(b, c))\n                goto fail;\n            if (p >= s->buf_end)\n                goto unexpected_eof;\n            c = *p++;\n        }\n        /* newline sequences are normalized as single '\\n' bytes */\n        if (c == '\\r') {\n            if (*p == '\\n')\n                p++;\n            c = '\\n';\n        }\n        if (c >= 0x80) {\n            const uint8_t *p_next;\n            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);\n            if (c > 0x10FFFF) {\n                js_parse_error_pos(s, p - 1, \"invalid UTF-8 sequence\");\n                goto fail;\n            }\n            p = p_next;\n        }\n        if (string_buffer_putc(b, c))\n            goto fail;\n    }\n    str = string_buffer_end(b);\n    if (JS_IsException(str))\n        return -1;\n    s->token.val = TOK_TEMPLATE;\n    s->token.u.str.sep = c;\n    s->token.u.str.str = str;\n    s->buf_ptr = p;\n    return 0;\n\n unexpected_eof:\n    js_parse_error(s, \"unexpected end of string\");\n fail:\n    string_buffer_free(b);\n    return -1;\n}\n\nstatic __exception int js_parse_string(JSParseState *s, int sep,\n                                       BOOL do_throw, const uint8_t *p,\n                                       JSToken *token, const uint8_t **pp)\n{\n    int ret;\n    uint32_t c;\n    StringBuffer b_s, *b = &b_s;\n    const uint8_t *p_escape;\n    JSValue str;\n\n    /* string */\n    if (string_buffer_init(s->ctx, b, 32))\n        goto fail;\n    for(;;) {\n        if (p >= s->buf_end)\n            goto invalid_char;\n        c = *p;\n        if (c < 0x20) {\n            if (sep == '`') {\n                if (c == '\\r') {\n                    if (p[1] == '\\n')\n                        p++;\n                    c = '\\n';\n                }\n                /* do not update s->line_num */\n            } else if (c == '\\n' || c == '\\r')\n                goto invalid_char;\n        }\n        p++;\n        if (c == sep)\n            break;\n        if (c == '$' && *p == '{' && sep == '`') {\n            /* template start or middle part */\n            p++;\n            break;\n        }\n        if (c == '\\\\') {\n            p_escape = p - 1;\n            c = *p;\n            /* XXX: need a specific JSON case to avoid\n               accepting invalid escapes */\n            switch(c) {\n            case '\\0':\n                if (p >= s->buf_end)\n                    goto invalid_char;\n                p++;\n                break;\n            case '\\'':\n            case '\\\"':\n            case '\\\\':\n                p++;\n                break;\n            case '\\r':  /* accept DOS and MAC newline sequences */\n                if (p[1] == '\\n') {\n                    p++;\n                }\n                /* fall thru */\n            case '\\n':\n                /* ignore escaped newline sequence */\n                p++;\n                continue;\n            default:\n                if (c >= '0' && c <= '9') {\n                    if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`')\n                        goto parse_escape;\n                    if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) {\n                        p++;\n                        c = '\\0';\n                    } else {\n                        if (c >= '8' || sep == '`') {\n                            /* Note: according to ES2021, \\8 and \\9 are not\n                               accepted in strict mode or in templates. */\n                            goto invalid_escape;\n                        } else {\n                            if (do_throw)\n                                js_parse_error_pos(s, p_escape, \"octal escape sequences are not allowed in strict mode\");\n                        }\n                        goto fail;\n                    }\n                } else if (c >= 0x80) {\n                    const uint8_t *p_next;\n                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);\n                    if (c > 0x10FFFF) {\n                        goto invalid_utf8;\n                    }\n                    p = p_next;\n                    /* LS or PS are skipped */\n                    if (c == CP_LS || c == CP_PS)\n                        continue;\n                } else {\n                parse_escape:\n                    ret = lre_parse_escape(&p, TRUE);\n                    if (ret == -1) {\n                    invalid_escape:\n                        if (do_throw)\n                            js_parse_error_pos(s, p_escape, \"malformed escape sequence in string literal\");\n                        goto fail;\n                    } else if (ret < 0) {\n                        /* ignore the '\\' (could output a warning) */\n                        p++;\n                    } else {\n                        c = ret;\n                    }\n                }\n                break;\n            }\n        } else if (c >= 0x80) {\n            const uint8_t *p_next;\n            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);\n            if (c > 0x10FFFF)\n                goto invalid_utf8;\n            p = p_next;\n        }\n        if (string_buffer_putc(b, c))\n            goto fail;\n    }\n    str = string_buffer_end(b);\n    if (JS_IsException(str))\n        return -1;\n    token->val = TOK_STRING;\n    token->u.str.sep = c;\n    token->u.str.str = str;\n    *pp = p;\n    return 0;\n\n invalid_utf8:\n    if (do_throw)\n        js_parse_error(s, \"invalid UTF-8 sequence\");\n    goto fail;\n invalid_char:\n    if (do_throw)\n        js_parse_error(s, \"unexpected end of string\");\n fail:\n    string_buffer_free(b);\n    return -1;\n}\n\nstatic inline BOOL token_is_pseudo_keyword(JSParseState *s, JSAtom atom) {\n    return s->token.val == TOK_IDENT && s->token.u.ident.atom == atom &&\n        !s->token.u.ident.has_escape;\n}\n\nstatic __exception int js_parse_regexp(JSParseState *s)\n{\n    const uint8_t *p;\n    BOOL in_class;\n    StringBuffer b_s, *b = &b_s;\n    StringBuffer b2_s, *b2 = &b2_s;\n    uint32_t c;\n    JSValue body_str, flags_str;\n\n    p = s->buf_ptr;\n    p++;\n    in_class = FALSE;\n    if (string_buffer_init(s->ctx, b, 32))\n        return -1;\n    if (string_buffer_init(s->ctx, b2, 1))\n        goto fail;\n    for(;;) {\n        if (p >= s->buf_end) {\n        eof_error:\n            js_parse_error(s, \"unexpected end of regexp\");\n            goto fail;\n        }\n        c = *p++;\n        if (c == '\\n' || c == '\\r') {\n            goto eol_error;\n        } else if (c == '/') {\n            if (!in_class)\n                break;\n        } else if (c == '[') {\n            in_class = TRUE;\n        } else if (c == ']') {\n            /* XXX: incorrect as the first character in a class */\n            in_class = FALSE;\n        } else if (c == '\\\\') {\n            if (string_buffer_putc8(b, c))\n                goto fail;\n            c = *p++;\n            if (c == '\\n' || c == '\\r')\n                goto eol_error;\n            else if (c == '\\0' && p >= s->buf_end)\n                goto eof_error;\n            else if (c >= 0x80) {\n                const uint8_t *p_next;\n                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);\n                if (c > 0x10FFFF) {\n                    goto invalid_utf8;\n                }\n                p = p_next;\n                if (c == CP_LS || c == CP_PS)\n                    goto eol_error;\n            }\n        } else if (c >= 0x80) {\n            const uint8_t *p_next;\n            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);\n            if (c > 0x10FFFF) {\n            invalid_utf8:\n                js_parse_error_pos(s, p - 1, \"invalid UTF-8 sequence\");\n                goto fail;\n            }\n            /* LS or PS are considered as line terminator */\n            if (c == CP_LS || c == CP_PS) {\n            eol_error:\n                js_parse_error_pos(s, p - 1, \"unexpected line terminator in regexp\");\n                goto fail;\n            }\n            p = p_next;\n        }\n        if (string_buffer_putc(b, c))\n            goto fail;\n    }\n\n    /* flags */\n    for(;;) {\n        const uint8_t *p_next = p;\n        c = *p_next++;\n        if (c >= 0x80) {\n            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p_next);\n            if (c > 0x10FFFF) {\n                p++;\n                goto invalid_utf8;\n            }\n        }\n        if (!lre_js_is_ident_next(c))\n            break;\n        if (string_buffer_putc(b2, c))\n            goto fail;\n        p = p_next;\n    }\n\n    body_str = string_buffer_end(b);\n    flags_str = string_buffer_end(b2);\n    if (JS_IsException(body_str) ||\n        JS_IsException(flags_str)) {\n        JS_FreeValue(s->ctx, body_str);\n        JS_FreeValue(s->ctx, flags_str);\n        return -1;\n    }\n    s->token.val = TOK_REGEXP;\n    s->token.u.regexp.body = body_str;\n    s->token.u.regexp.flags = flags_str;\n    s->buf_ptr = p;\n    return 0;\n fail:\n    string_buffer_free(b);\n    string_buffer_free(b2);\n    return -1;\n}\n\nstatic __exception int ident_realloc(JSContext *ctx, char **pbuf, size_t *psize,\n                                     char *static_buf)\n{\n    char *buf, *new_buf;\n    size_t size, new_size;\n\n    buf = *pbuf;\n    size = *psize;\n    if (size >= (SIZE_MAX / 3) * 2)\n        new_size = SIZE_MAX;\n    else\n        new_size = size + (size >> 1);\n    if (buf == static_buf) {\n        new_buf = js_malloc(ctx, new_size);\n        if (!new_buf)\n            return -1;\n        memcpy(new_buf, buf, size);\n    } else {\n        new_buf = js_realloc(ctx, buf, new_size);\n        if (!new_buf)\n            return -1;\n    }\n    *pbuf = new_buf;\n    *psize = new_size;\n    return 0;\n}\n\n/* convert a TOK_IDENT to a keyword when needed */\nstatic void update_token_ident(JSParseState *s)\n{\n    if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||\n        (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&\n         (s->cur_func->js_mode & JS_MODE_STRICT)) ||\n        (s->token.u.ident.atom == JS_ATOM_yield &&\n         ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||\n          (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&\n           !s->cur_func->in_function_body && s->cur_func->parent &&\n           (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||\n        (s->token.u.ident.atom == JS_ATOM_await &&\n         (s->is_module ||\n          (s->cur_func->func_kind & JS_FUNC_ASYNC) ||\n          s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT ||\n          (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&\n           !s->cur_func->in_function_body && s->cur_func->parent &&\n           ((s->cur_func->parent->func_kind & JS_FUNC_ASYNC) ||\n            s->cur_func->parent->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))))) {\n        if (s->token.u.ident.has_escape) {\n            s->token.u.ident.is_reserved = TRUE;\n            s->token.val = TOK_IDENT;\n        } else {\n            /* The keywords atoms are pre allocated */\n            s->token.val = s->token.u.ident.atom - 1 + TOK_FIRST_KEYWORD;\n        }\n    }\n}\n\n/* if the current token is an identifier or keyword, reparse it\n   according to the current function type */\nstatic void reparse_ident_token(JSParseState *s)\n{\n    if (s->token.val == TOK_IDENT ||\n        (s->token.val >= TOK_FIRST_KEYWORD &&\n         s->token.val <= TOK_LAST_KEYWORD)) {\n        s->token.val = TOK_IDENT;\n        s->token.u.ident.is_reserved = FALSE;\n        update_token_ident(s);\n    }\n}\n\n/* 'c' is the first character. Return JS_ATOM_NULL in case of error */\nstatic JSAtom parse_ident(JSParseState *s, const uint8_t **pp,\n                          BOOL *pident_has_escape, int c, BOOL is_private)\n{\n    const uint8_t *p, *p1;\n    char ident_buf[128], *buf;\n    size_t ident_size, ident_pos;\n    JSAtom atom;\n\n    p = *pp;\n    buf = ident_buf;\n    ident_size = sizeof(ident_buf);\n    ident_pos = 0;\n    if (is_private)\n        buf[ident_pos++] = '#';\n    for(;;) {\n        p1 = p;\n\n        if (c < 128) {\n            buf[ident_pos++] = c;\n        } else {\n            ident_pos += unicode_to_utf8((uint8_t*)buf + ident_pos, c);\n        }\n        c = *p1++;\n        if (c == '\\\\' && *p1 == 'u') {\n            c = lre_parse_escape(&p1, TRUE);\n            *pident_has_escape = TRUE;\n        } else if (c >= 128) {\n            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);\n        }\n        if (!lre_js_is_ident_next(c))\n            break;\n        p = p1;\n        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {\n            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {\n                atom = JS_ATOM_NULL;\n                goto done;\n            }\n        }\n    }\n    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);\n done:\n    if (unlikely(buf != ident_buf))\n        js_free(s->ctx, buf);\n    *pp = p;\n    return atom;\n}\n\n\nstatic __exception int next_token(JSParseState *s)\n{\n    const uint8_t *p;\n    int c;\n    BOOL ident_has_escape;\n    JSAtom atom;\n\n    if (js_check_stack_overflow(s->ctx->rt, 0)) {\n        return js_parse_error(s, \"stack overflow\");\n    }\n\n    free_token(s, &s->token);\n\n    p = s->last_ptr = s->buf_ptr;\n    s->got_lf = FALSE;\n redo:\n    s->token.ptr = p;\n    c = *p;\n    switch(c) {\n    case 0:\n        if (p >= s->buf_end) {\n            s->token.val = TOK_EOF;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '`':\n        if (js_parse_template_part(s, p + 1))\n            goto fail;\n        p = s->buf_ptr;\n        break;\n    case '\\'':\n    case '\\\"':\n        if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))\n            goto fail;\n        break;\n    case '\\r':  /* accept DOS and MAC newline sequences */\n        if (p[1] == '\\n') {\n            p++;\n        }\n        /* fall thru */\n    case '\\n':\n        p++;\n    line_terminator:\n        s->got_lf = TRUE;\n        goto redo;\n    case '\\f':\n    case '\\v':\n    case ' ':\n    case '\\t':\n        p++;\n        goto redo;\n    case '/':\n        if (p[1] == '*') {\n            /* comment */\n            p += 2;\n            for(;;) {\n                if (*p == '\\0' && p >= s->buf_end) {\n                    js_parse_error(s, \"unexpected end of comment\");\n                    goto fail;\n                }\n                if (p[0] == '*' && p[1] == '/') {\n                    p += 2;\n                    break;\n                }\n                if (*p == '\\n' || *p == '\\r') {\n                    s->got_lf = TRUE; /* considered as LF for ASI */\n                    p++;\n                } else if (*p >= 0x80) {\n                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n                    if (c == CP_LS || c == CP_PS) {\n                        s->got_lf = TRUE; /* considered as LF for ASI */\n                    } else if (c == -1) {\n                        p++; /* skip invalid UTF-8 */\n                    }\n                } else {\n                    p++;\n                }\n            }\n            goto redo;\n        } else if (p[1] == '/') {\n            /* line comment */\n            p += 2;\n        skip_line_comment:\n            for(;;) {\n                if (*p == '\\0' && p >= s->buf_end)\n                    break;\n                if (*p == '\\r' || *p == '\\n')\n                    break;\n                if (*p >= 0x80) {\n                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n                    /* LS or PS are considered as line terminator */\n                    if (c == CP_LS || c == CP_PS) {\n                        break;\n                    } else if (c == -1) {\n                        p++; /* skip invalid UTF-8 */\n                    }\n                } else {\n                    p++;\n                }\n            }\n            goto redo;\n        } else if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_DIV_ASSIGN;\n        } else {\n            p++;\n            s->token.val = c;\n        }\n        break;\n    case '\\\\':\n        if (p[1] == 'u') {\n            const uint8_t *p1 = p + 1;\n            int c1 = lre_parse_escape(&p1, TRUE);\n            if (c1 >= 0 && lre_js_is_ident_first(c1)) {\n                c = c1;\n                p = p1;\n                ident_has_escape = TRUE;\n                goto has_ident;\n            } else {\n                /* XXX: syntax error? */\n            }\n        }\n        goto def_token;\n    case 'a': case 'b': case 'c': case 'd':\n    case 'e': case 'f': case 'g': case 'h':\n    case 'i': case 'j': case 'k': case 'l':\n    case 'm': case 'n': case 'o': case 'p':\n    case 'q': case 'r': case 's': case 't':\n    case 'u': case 'v': case 'w': case 'x':\n    case 'y': case 'z':\n    case 'A': case 'B': case 'C': case 'D':\n    case 'E': case 'F': case 'G': case 'H':\n    case 'I': case 'J': case 'K': case 'L':\n    case 'M': case 'N': case 'O': case 'P':\n    case 'Q': case 'R': case 'S': case 'T':\n    case 'U': case 'V': case 'W': case 'X':\n    case 'Y': case 'Z':\n    case '_':\n    case '$':\n        /* identifier */\n        p++;\n        ident_has_escape = FALSE;\n    has_ident:\n        atom = parse_ident(s, &p, &ident_has_escape, c, FALSE);\n        if (atom == JS_ATOM_NULL)\n            goto fail;\n        s->token.u.ident.atom = atom;\n        s->token.u.ident.has_escape = ident_has_escape;\n        s->token.u.ident.is_reserved = FALSE;\n        s->token.val = TOK_IDENT;\n        update_token_ident(s);\n        break;\n    case '#':\n        /* private name */\n        {\n            const uint8_t *p1;\n            p++;\n            p1 = p;\n            c = *p1++;\n            if (c == '\\\\' && *p1 == 'u') {\n                c = lre_parse_escape(&p1, TRUE);\n            } else if (c >= 128) {\n                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1);\n            }\n            if (!lre_js_is_ident_first(c)) {\n                js_parse_error(s, \"invalid first character of private name\");\n                goto fail;\n            }\n            p = p1;\n            ident_has_escape = FALSE; /* not used */\n            atom = parse_ident(s, &p, &ident_has_escape, c, TRUE);\n            if (atom == JS_ATOM_NULL)\n                goto fail;\n            s->token.u.ident.atom = atom;\n            s->token.val = TOK_PRIVATE_NAME;\n        }\n        break;\n    case '.':\n        if (p[1] == '.' && p[2] == '.') {\n            p += 3;\n            s->token.val = TOK_ELLIPSIS;\n            break;\n        }\n        if (p[1] >= '0' && p[1] <= '9') {\n            goto parse_number;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '0':\n        /* in strict mode, octal literals are not accepted */\n        if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {\n            js_parse_error(s, \"octal literals are deprecated in strict mode\");\n            goto fail;\n        }\n        goto parse_number;\n    case '1': case '2': case '3': case '4':\n    case '5': case '6': case '7': case '8':\n    case '9':\n        /* number */\n    parse_number:\n        {\n            JSValue ret;\n            const uint8_t *p1;\n            int flags;\n            flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |\n                ATOD_ACCEPT_UNDERSCORES | ATOD_ACCEPT_SUFFIX;\n            ret = js_atof(s->ctx, (const char *)p, (const char **)&p, 0,\n                          flags);\n            if (JS_IsException(ret))\n                goto fail;\n            /* reject `10instanceof Number` */\n            if (JS_VALUE_IS_NAN(ret) ||\n                lre_js_is_ident_next(unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1))) {\n                JS_FreeValue(s->ctx, ret);\n                js_parse_error(s, \"invalid number literal\");\n                goto fail;\n            }\n            s->token.val = TOK_NUMBER;\n            s->token.u.num.val = ret;\n        }\n        break;\n    case '*':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_MUL_ASSIGN;\n        } else if (p[1] == '*') {\n            if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_POW_ASSIGN;\n            } else {\n                p += 2;\n                s->token.val = TOK_POW;\n            }\n        } else {\n            goto def_token;\n        }\n        break;\n    case '%':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_MOD_ASSIGN;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '+':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_PLUS_ASSIGN;\n        } else if (p[1] == '+') {\n            p += 2;\n            s->token.val = TOK_INC;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '-':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_MINUS_ASSIGN;\n        } else if (p[1] == '-') {\n            if (s->allow_html_comments && p[2] == '>' &&\n                (s->got_lf || s->last_ptr == s->buf_start)) {\n                /* Annex B: `-->` at beginning of line is an html comment end.\n                   It extends to the end of the line.\n                 */\n                goto skip_line_comment;\n            }\n            p += 2;\n            s->token.val = TOK_DEC;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '<':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_LTE;\n        } else if (p[1] == '<') {\n            if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_SHL_ASSIGN;\n            } else {\n                p += 2;\n                s->token.val = TOK_SHL;\n            }\n        } else if (s->allow_html_comments &&\n                   p[1] == '!' && p[2] == '-' && p[3] == '-') {\n            /* Annex B: handle `<!--` single line html comments */\n            goto skip_line_comment;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '>':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_GTE;\n        } else if (p[1] == '>') {\n            if (p[2] == '>') {\n                if (p[3] == '=') {\n                    p += 4;\n                    s->token.val = TOK_SHR_ASSIGN;\n                } else {\n                    p += 3;\n                    s->token.val = TOK_SHR;\n                }\n            } else if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_SAR_ASSIGN;\n            } else {\n                p += 2;\n                s->token.val = TOK_SAR;\n            }\n        } else {\n            goto def_token;\n        }\n        break;\n    case '=':\n        if (p[1] == '=') {\n            if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_STRICT_EQ;\n            } else {\n                p += 2;\n                s->token.val = TOK_EQ;\n            }\n        } else if (p[1] == '>') {\n            p += 2;\n            s->token.val = TOK_ARROW;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '!':\n        if (p[1] == '=') {\n            if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_STRICT_NEQ;\n            } else {\n                p += 2;\n                s->token.val = TOK_NEQ;\n            }\n        } else {\n            goto def_token;\n        }\n        break;\n    case '&':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_AND_ASSIGN;\n        } else if (p[1] == '&') {\n            if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_LAND_ASSIGN;\n            } else {\n                p += 2;\n                s->token.val = TOK_LAND;\n            }\n        } else {\n            goto def_token;\n        }\n        break;\n    case '^':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_XOR_ASSIGN;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '|':\n        if (p[1] == '=') {\n            p += 2;\n            s->token.val = TOK_OR_ASSIGN;\n        } else if (p[1] == '|') {\n            if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_LOR_ASSIGN;\n            } else {\n                p += 2;\n                s->token.val = TOK_LOR;\n            }\n        } else {\n            goto def_token;\n        }\n        break;\n    case '?':\n        if (p[1] == '?') {\n            if (p[2] == '=') {\n                p += 3;\n                s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN;\n            } else {\n                p += 2;\n                s->token.val = TOK_DOUBLE_QUESTION_MARK;\n            }\n        } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) {\n            p += 2;\n            s->token.val = TOK_QUESTION_MARK_DOT;\n        } else {\n            goto def_token;\n        }\n        break;\n    default:\n        if (c >= 128) {\n            /* unicode value */\n            c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n            switch(c) {\n            case CP_PS:\n            case CP_LS:\n                /* XXX: should avoid incrementing line_number, but\n                   needed to handle HTML comments */\n                goto line_terminator;\n            default:\n                if (lre_is_space(c)) {\n                    goto redo;\n                } else if (lre_js_is_ident_first(c)) {\n                    ident_has_escape = FALSE;\n                    goto has_ident;\n                } else {\n                    js_parse_error(s, \"unexpected character\");\n                    goto fail;\n                }\n            }\n        }\n    def_token:\n        s->token.val = c;\n        p++;\n        break;\n    }\n    s->buf_ptr = p;\n\n    //    dump_token(s, &s->token);\n    return 0;\n\n fail:\n    s->token.val = TOK_ERROR;\n    return -1;\n}\n\n/* 'c' is the first character. Return JS_ATOM_NULL in case of error */\n/* XXX: accept unicode identifiers as JSON5 ? */\nstatic JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)\n{\n    const uint8_t *p;\n    char ident_buf[128], *buf;\n    size_t ident_size, ident_pos;\n    JSAtom atom;\n\n    p = *pp;\n    buf = ident_buf;\n    ident_size = sizeof(ident_buf);\n    ident_pos = 0;\n    for(;;) {\n        buf[ident_pos++] = c;\n        c = *p;\n        if (c >= 128 || !lre_is_id_continue_byte(c))\n            break;\n        p++;\n        if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {\n            if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {\n                atom = JS_ATOM_NULL;\n                goto done;\n            }\n        }\n    }\n    atom = JS_NewAtomLen(s->ctx, buf, ident_pos);\n done:\n    if (unlikely(buf != ident_buf))\n        js_free(s->ctx, buf);\n    *pp = p;\n    return atom;\n}\n\nstatic int json_parse_string(JSParseState *s, const uint8_t **pp, int sep)\n{\n    const uint8_t *p, *p_next;\n    int i;\n    uint32_t c;\n    StringBuffer b_s, *b = &b_s;\n\n    if (string_buffer_init(s->ctx, b, 32))\n        goto fail;\n\n    p = *pp;\n    for(;;) {\n        if (p >= s->buf_end) {\n            goto end_of_input;\n        }\n        c = *p++;\n        if (c == sep)\n            break;\n        if (c < 0x20) {\n            js_parse_error_pos(s, p - 1, \"Bad control character in string literal\");\n            goto fail;\n        }\n        if (c == '\\\\') {\n            c = *p++;\n            switch(c) {\n            case 'b':   c = '\\b'; break;\n            case 'f':   c = '\\f'; break;\n            case 'n':   c = '\\n'; break;\n            case 'r':   c = '\\r'; break;\n            case 't':   c = '\\t'; break;\n            case '\\\\':  break;\n            case '/':   break; \n            case 'u':\n                c = 0;\n                for(i = 0; i < 4; i++) {\n                    int h = from_hex(*p++);\n                    if (h < 0) {\n                        js_parse_error_pos(s, p - 1, \"Bad Unicode escape\");\n                        goto fail;\n                    }\n                    c = (c << 4) | h;\n                }\n                break;\n            case '\\n':\n                if (s->ext_json)\n                    continue;\n                goto bad_escape;\n            case 'v':\n                if (s->ext_json) {\n                    c = '\\v';\n                    break;\n                }\n                goto bad_escape;\n            default:\n                if (c == sep)\n                    break;\n                if (p > s->buf_end)\n                    goto end_of_input;\n            bad_escape:\n                js_parse_error_pos(s, p - 1, \"Bad escaped character\");\n                goto fail;\n            }\n        } else\n        if (c >= 0x80) {\n            c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next);\n            if (c > 0x10FFFF) {\n                js_parse_error_pos(s, p - 1, \"Bad UTF-8 sequence\");\n                goto fail;\n            }\n            p = p_next;\n        }\n        if (string_buffer_putc(b, c))\n            goto fail;\n    }\n    s->token.val = TOK_STRING;\n    s->token.u.str.sep = sep;\n    s->token.u.str.str = string_buffer_end(b);\n    *pp = p;\n    return 0;\n\n end_of_input:\n    js_parse_error(s, \"Unexpected end of JSON input\");\n fail:\n    string_buffer_free(b);\n    return -1;\n}\n\nstatic int json_parse_number(JSParseState *s, const uint8_t **pp)\n{\n    const uint8_t *p = *pp;\n    const uint8_t *p_start = p;\n    int radix;\n    double d;\n    JSATODTempMem atod_mem;\n    \n    if (*p == '+' || *p == '-')\n        p++;\n\n    if (!is_digit(*p)) {\n        if (s->ext_json) {\n            if (strstart((const char *)p, \"Infinity\", (const char **)&p)) {\n                d = 1.0 / 0.0;\n                if (*p_start == '-')\n                    d = -d;\n                goto done;\n            } else if (strstart((const char *)p, \"NaN\", (const char **)&p)) {\n                d = NAN;\n                goto done;\n            } else if (*p != '.') {\n                goto unexpected_token;\n            }\n        } else {\n            goto unexpected_token;\n        }\n    }\n\n    if (p[0] == '0') {\n        if (s->ext_json) {\n            /* also accepts base 16, 8 and 2 prefix for integers */\n            radix = 10;\n            if (p[1] == 'x' || p[1] == 'X') {\n                p += 2;\n                radix = 16;\n            } else if ((p[1] == 'o' || p[1] == 'O')) {\n                p += 2;\n                radix = 8;\n            } else if ((p[1] == 'b' || p[1] == 'B')) {\n                p += 2;\n                radix = 2;\n            }\n            if (radix != 10) {\n                /* prefix is present */\n                if (to_digit(*p) >= radix) {\n                unexpected_token:\n                    return js_parse_error_pos(s, p, \"Unexpected token '%c'\", *p);\n                }\n                d = js_atod((const char *)p_start, (const char **)&p, 0,\n                            JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT, &atod_mem);\n                goto done;\n            }\n        }\n        if (is_digit(p[1]))\n            return js_parse_error_pos(s, p, \"Unexpected number\");\n    }\n\n    while (is_digit(*p))\n        p++;\n\n    if (*p == '.') {\n        p++;\n        if (!is_digit(*p))\n            return js_parse_error_pos(s, p, \"Unterminated fractional number\");\n        while (is_digit(*p))\n            p++;\n    }\n    if (*p == 'e' || *p == 'E') {\n        p++;\n        if (*p == '+' || *p == '-')\n            p++;\n        if (!is_digit(*p))\n            return js_parse_error_pos(s, p, \"Exponent part is missing a number\");\n        while (is_digit(*p))\n            p++;\n    }\n    d = js_atod((const char *)p_start, NULL, 10, 0, &atod_mem);\n done:\n    s->token.val = TOK_NUMBER;\n    s->token.u.num.val = JS_NewFloat64(s->ctx, d);\n    *pp = p;\n    return 0;\n}\n\nstatic __exception int json_next_token(JSParseState *s)\n{\n    const uint8_t *p;\n    int c;\n    JSAtom atom;\n\n    if (js_check_stack_overflow(s->ctx->rt, 0)) {\n        return js_parse_error(s, \"stack overflow\");\n    }\n\n    free_token(s, &s->token);\n\n    p = s->last_ptr = s->buf_ptr;\n redo:\n    s->token.ptr = p;\n    c = *p;\n    switch(c) {\n    case 0:\n        if (p >= s->buf_end) {\n            s->token.val = TOK_EOF;\n        } else {\n            goto def_token;\n        }\n        break;\n    case '\\'':\n        if (!s->ext_json) {\n            /* JSON does not accept single quoted strings */\n            goto def_token;\n        }\n        /* fall through */\n    case '\\\"':\n        p++;\n        if (json_parse_string(s, &p, c))\n            goto fail;\n        break;\n    case '\\r':  /* accept DOS and MAC newline sequences */\n        if (p[1] == '\\n') {\n            p++;\n        }\n        /* fall thru */\n    case '\\n':\n        p++;\n        goto redo;\n    case '\\f':\n    case '\\v':\n        if (!s->ext_json) {\n            /* JSONWhitespace does not match <VT>, nor <FF> */\n            goto def_token;\n        }\n        /* fall through */\n    case ' ':\n    case '\\t':\n        p++;\n        goto redo;\n    case '/':\n        if (!s->ext_json) {\n            /* JSON does not accept comments */\n            goto def_token;\n        }\n        if (p[1] == '*') {\n            /* comment */\n            p += 2;\n            for(;;) {\n                if (*p == '\\0' && p >= s->buf_end) {\n                    js_parse_error(s, \"unexpected end of comment\");\n                    goto fail;\n                }\n                if (p[0] == '*' && p[1] == '/') {\n                    p += 2;\n                    break;\n                }\n                if (*p >= 0x80) {\n                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n                    if (c == -1) {\n                        p++; /* skip invalid UTF-8 */\n                    }\n                } else {\n                    p++;\n                }\n            }\n            goto redo;\n        } else if (p[1] == '/') {\n            /* line comment */\n            p += 2;\n            for(;;) {\n                if (*p == '\\0' && p >= s->buf_end)\n                    break;\n                if (*p == '\\r' || *p == '\\n')\n                    break;\n                if (*p >= 0x80) {\n                    c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n                    /* LS or PS are considered as line terminator */\n                    if (c == CP_LS || c == CP_PS) {\n                        break;\n                    } else if (c == -1) {\n                        p++; /* skip invalid UTF-8 */\n                    }\n                } else {\n                    p++;\n                }\n            }\n            goto redo;\n        } else {\n            goto def_token;\n        }\n        break;\n    case 'a': case 'b': case 'c': case 'd':\n    case 'e': case 'f': case 'g': case 'h':\n    case 'i': case 'j': case 'k': case 'l':\n    case 'm': case 'n': case 'o': case 'p':\n    case 'q': case 'r': case 's': case 't':\n    case 'u': case 'v': case 'w': case 'x':\n    case 'y': case 'z':\n    case 'A': case 'B': case 'C': case 'D':\n    case 'E': case 'F': case 'G': case 'H':\n    case 'I': case 'J': case 'K': case 'L':\n    case 'M': case 'N': case 'O': case 'P':\n    case 'Q': case 'R': case 'S': case 'T':\n    case 'U': case 'V': case 'W': case 'X':\n    case 'Y': case 'Z':\n    case '_':\n    case '$':\n        p++;\n        atom = json_parse_ident(s, &p, c);\n        if (atom == JS_ATOM_NULL)\n            goto fail;\n        s->token.u.ident.atom = atom;\n        s->token.u.ident.has_escape = FALSE;\n        s->token.u.ident.is_reserved = FALSE;\n        s->token.val = TOK_IDENT;\n        break;\n    case '+':\n        if (!s->ext_json)\n            goto def_token;\n        goto parse_number;\n    case '.':\n        if (s->ext_json && is_digit(p[1]))\n            goto parse_number;\n        else\n            goto def_token;\n    case '-':\n    case '0':\n    case '1': case '2': case '3': case '4':\n    case '5': case '6': case '7': case '8':\n    case '9':\n        /* number */\n    parse_number:\n        if (json_parse_number(s, &p))\n            goto fail;\n        break;\n    default:\n        if (c >= 128) {\n            js_parse_error(s, \"unexpected character\");\n            goto fail;\n        }\n    def_token:\n        s->token.val = c;\n        p++;\n        break;\n    }\n    s->buf_ptr = p;\n\n    //    dump_token(s, &s->token);\n    return 0;\n\n fail:\n    s->token.val = TOK_ERROR;\n    return -1;\n}\n\nstatic int match_identifier(const uint8_t *p, const char *s) {\n    uint32_t c;\n    while (*s) {\n        if ((uint8_t)*s++ != *p++)\n            return 0;\n    }\n    c = *p;\n    if (c >= 128)\n        c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n    return !lre_js_is_ident_next(c);\n}\n\n/* simple_next_token() is used to check for the next token in simple cases.\n   It is only used for ':' and '=>', 'let' or 'function' look-ahead.\n   (*pp) is only set if TOK_IMPORT is returned for JS_DetectModule()\n   Whitespace and comments are skipped correctly.\n   Then the next token is analyzed, only for specific words.\n   Return values:\n   - '\\n' if !no_line_terminator\n   - TOK_ARROW, TOK_IN, TOK_IMPORT, TOK_OF, TOK_EXPORT, TOK_FUNCTION\n   - TOK_IDENT is returned for other identifiers and keywords\n   - otherwise the next character or unicode codepoint is returned.\n */\nstatic int simple_next_token(const uint8_t **pp, BOOL no_line_terminator)\n{\n    const uint8_t *p;\n    uint32_t c;\n\n    /* skip spaces and comments */\n    p = *pp;\n    for (;;) {\n        switch(c = *p++) {\n        case '\\r':\n        case '\\n':\n            if (no_line_terminator)\n                return '\\n';\n            continue;\n        case ' ':\n        case '\\t':\n        case '\\v':\n        case '\\f':\n            continue;\n        case '/':\n            if (*p == '/') {\n                if (no_line_terminator)\n                    return '\\n';\n                while (*p && *p != '\\r' && *p != '\\n')\n                    p++;\n                continue;\n            }\n            if (*p == '*') {\n                while (*++p) {\n                    if ((*p == '\\r' || *p == '\\n') && no_line_terminator)\n                        return '\\n';\n                    if (*p == '*' && p[1] == '/') {\n                        p += 2;\n                        break;\n                    }\n                }\n                continue;\n            }\n            break;\n        case '=':\n            if (*p == '>')\n                return TOK_ARROW;\n            break;\n        case 'i':\n            if (match_identifier(p, \"n\"))\n                return TOK_IN;\n            if (match_identifier(p, \"mport\")) {\n                *pp = p + 5;\n                return TOK_IMPORT;\n            }\n            return TOK_IDENT;\n        case 'o':\n            if (match_identifier(p, \"f\"))\n                return TOK_OF;\n            return TOK_IDENT;\n        case 'e':\n            if (match_identifier(p, \"xport\"))\n                return TOK_EXPORT;\n            return TOK_IDENT;\n        case 'f':\n            if (match_identifier(p, \"unction\"))\n                return TOK_FUNCTION;\n            return TOK_IDENT;\n        case '\\\\':\n            if (*p == 'u') {\n                if (lre_js_is_ident_first(lre_parse_escape(&p, TRUE)))\n                    return TOK_IDENT;\n            }\n            break;\n        default:\n            if (c >= 128) {\n                c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p);\n                if (no_line_terminator && (c == CP_PS || c == CP_LS))\n                    return '\\n';\n            }\n            if (lre_is_space(c))\n                continue;\n            if (lre_js_is_ident_first(c))\n                return TOK_IDENT;\n            break;\n        }\n        return c;\n    }\n}\n\nstatic int peek_token(JSParseState *s, BOOL no_line_terminator)\n{\n    const uint8_t *p = s->buf_ptr;\n    return simple_next_token(&p, no_line_terminator);\n}\n\nstatic void skip_shebang(const uint8_t **pp, const uint8_t *buf_end)\n{\n    const uint8_t *p = *pp;\n    int c;\n\n    if (p[0] == '#' && p[1] == '!') {\n        p += 2;\n        while (p < buf_end) {\n            if (*p == '\\n' || *p == '\\r') {\n                break;\n            } else if (*p >= 0x80) {\n                c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);\n                if (c == CP_LS || c == CP_PS) {\n                    break;\n                } else if (c == -1) {\n                    p++; /* skip invalid UTF-8 */\n                }\n            } else {\n                p++;\n            }\n        }\n        *pp = p;\n    }\n}\n\n/* return true if 'input' contains the source of a module\n   (heuristic). 'input' must be a zero terminated.\n\n   Heuristic: skip comments and expect 'import' keyword not followed\n   by '(' or '.' or export keyword.\n*/\nBOOL JS_DetectModule(const char *input, size_t input_len)\n{\n    const uint8_t *p = (const uint8_t *)input;\n    int tok;\n\n    skip_shebang(&p, p + input_len);\n    switch(simple_next_token(&p, FALSE)) {\n    case TOK_IMPORT:\n        tok = simple_next_token(&p, FALSE);\n        return (tok != '.' && tok != '(');\n    case TOK_EXPORT:\n        return TRUE;\n    default:\n        return FALSE;\n    }\n}\n\nstatic inline int get_prev_opcode(JSFunctionDef *fd) {\n    if (fd->last_opcode_pos < 0 || dbuf_error(&fd->byte_code))\n        return OP_invalid;\n    else\n        return fd->byte_code.buf[fd->last_opcode_pos];\n}\n\nstatic BOOL js_is_live_code(JSParseState *s) {\n    switch (get_prev_opcode(s->cur_func)) {\n    case OP_tail_call:\n    case OP_tail_call_method:\n    case OP_return:\n    case OP_return_undef:\n    case OP_return_async:\n    case OP_throw:\n    case OP_throw_error:\n    case OP_goto:\n#if SHORT_OPCODES\n    case OP_goto8:\n    case OP_goto16:\n#endif\n    case OP_ret:\n        return FALSE;\n    default:\n        return TRUE;\n    }\n}\n\nstatic void emit_u8(JSParseState *s, uint8_t val)\n{\n    dbuf_putc(&s->cur_func->byte_code, val);\n}\n\nstatic void emit_u16(JSParseState *s, uint16_t val)\n{\n    dbuf_put_u16(&s->cur_func->byte_code, val);\n}\n\nstatic void emit_u32(JSParseState *s, uint32_t val)\n{\n    dbuf_put_u32(&s->cur_func->byte_code, val);\n}\n\nstatic void emit_source_pos(JSParseState *s, const uint8_t *source_ptr)\n{\n    JSFunctionDef *fd = s->cur_func;\n    DynBuf *bc = &fd->byte_code;\n\n    if (unlikely(fd->last_opcode_source_ptr != source_ptr)) {\n        dbuf_putc(bc, OP_line_num);\n        dbuf_put_u32(bc, source_ptr - s->buf_start);\n        fd->last_opcode_source_ptr = source_ptr;\n    }\n}\n\nstatic void emit_op(JSParseState *s, uint8_t val)\n{\n    JSFunctionDef *fd = s->cur_func;\n    DynBuf *bc = &fd->byte_code;\n\n    fd->last_opcode_pos = bc->size;\n    dbuf_putc(bc, val);\n}\n\nstatic void emit_atom(JSParseState *s, JSAtom name)\n{\n    DynBuf *bc = &s->cur_func->byte_code;\n    if (dbuf_claim(bc, 4))\n        return; /* not enough memory : don't duplicate the atom */\n    put_u32(bc->buf + bc->size, JS_DupAtom(s->ctx, name));\n    bc->size += 4;\n}\n\nstatic int update_label(JSFunctionDef *s, int label, int delta)\n{\n    LabelSlot *ls;\n\n    assert(label >= 0 && label < s->label_count);\n    ls = &s->label_slots[label];\n    ls->ref_count += delta;\n    assert(ls->ref_count >= 0);\n    return ls->ref_count;\n}\n\nstatic int new_label_fd(JSFunctionDef *fd)\n{\n    int label;\n    LabelSlot *ls;\n\n    if (js_resize_array(fd->ctx, (void *)&fd->label_slots,\n                        sizeof(fd->label_slots[0]),\n                        &fd->label_size, fd->label_count + 1))\n        return -1;\n    label = fd->label_count++;\n    ls = &fd->label_slots[label];\n    ls->ref_count = 0;\n    ls->pos = -1;\n    ls->pos2 = -1;\n    ls->addr = -1;\n    ls->first_reloc = NULL;\n    return label;\n}\n\nstatic int new_label(JSParseState *s)\n{\n    int label;\n    label = new_label_fd(s->cur_func);\n    if (unlikely(label < 0)) {\n        dbuf_set_error(&s->cur_func->byte_code);\n    }\n    return label;\n}\n\n/* don't update the last opcode and don't emit line number info */\nstatic void emit_label_raw(JSParseState *s, int label)\n{\n    emit_u8(s, OP_label);\n    emit_u32(s, label);\n    s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;\n}\n\n/* return the label ID offset */\nstatic int emit_label(JSParseState *s, int label)\n{\n    if (label >= 0) {\n        emit_op(s, OP_label);\n        emit_u32(s, label);\n        s->cur_func->label_slots[label].pos = s->cur_func->byte_code.size;\n        return s->cur_func->byte_code.size - 4;\n    } else {\n        return -1;\n    }\n}\n\n/* return label or -1 if dead code */\nstatic int emit_goto(JSParseState *s, int opcode, int label)\n{\n    if (js_is_live_code(s)) {\n        if (label < 0) {\n            label = new_label(s);\n            if (label < 0)\n                return -1;\n        }\n        emit_op(s, opcode);\n        emit_u32(s, label);\n        s->cur_func->label_slots[label].ref_count++;\n        return label;\n    }\n    return -1;\n}\n\n/* return the constant pool index. 'val' is not duplicated. */\nstatic int cpool_add(JSParseState *s, JSValue val)\n{\n    JSFunctionDef *fd = s->cur_func;\n\n    if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),\n                        &fd->cpool_size, fd->cpool_count + 1)) {\n        JS_FreeValue(s->ctx, val);\n        return -1;\n    }\n    fd->cpool[fd->cpool_count++] = val;\n    return fd->cpool_count - 1;\n}\n\nstatic __exception int emit_push_const(JSParseState *s, JSValueConst val,\n                                       BOOL as_atom)\n{\n    int idx;\n\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_STRING && as_atom) {\n        JSAtom atom;\n        /* warning: JS_NewAtomStr frees the string value */\n        JS_DupValue(s->ctx, val);\n        atom = JS_NewAtomStr(s->ctx, JS_VALUE_GET_STRING(val));\n        if (atom != JS_ATOM_NULL && !__JS_AtomIsTaggedInt(atom)) {\n            emit_op(s, OP_push_atom_value);\n            emit_u32(s, atom);\n            return 0;\n        }\n    }\n\n    idx = cpool_add(s, JS_DupValue(s->ctx, val));\n    if (idx < 0)\n        return -1;\n    emit_op(s, OP_push_const);\n    emit_u32(s, idx);\n    return 0;\n}\n\n/* return the variable index or -1 if not found,\n   add ARGUMENT_VAR_OFFSET for argument variables */\nstatic int find_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)\n{\n    int i;\n    for(i = fd->arg_count; i-- > 0;) {\n        if (fd->args[i].var_name == name)\n            return i | ARGUMENT_VAR_OFFSET;\n    }\n    return -1;\n}\n\nstatic int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)\n{\n    int i;\n    for(i = fd->var_count; i-- > 0;) {\n        if (fd->vars[i].var_name == name && fd->vars[i].scope_level == 0)\n            return i;\n    }\n    return find_arg(ctx, fd, name);\n}\n\n/* find a variable declaration in a given scope */\nstatic int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,\n                             JSAtom name, int scope_level)\n{\n    int scope_idx;\n    for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;\n        scope_idx = fd->vars[scope_idx].scope_next) {\n        if (fd->vars[scope_idx].scope_level != scope_level)\n            break;\n        if (fd->vars[scope_idx].var_name == name)\n            return scope_idx;\n    }\n    return -1;\n}\n\n/* return true if scope == parent_scope or if scope is a child of\n   parent_scope */\nstatic BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,\n                           int scope, int parent_scope)\n{\n    while (scope >= 0) {\n        if (scope == parent_scope)\n            return TRUE;\n        scope = fd->scopes[scope].parent;\n    }\n    return FALSE;\n}\n\n/* find a 'var' declaration in the same scope or a child scope */\nstatic int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,\n                                   JSAtom name, int scope_level)\n{\n    int i;\n    for(i = 0; i < fd->var_count; i++) {\n        JSVarDef *vd = &fd->vars[i];\n        if (vd->var_name == name && vd->scope_level == 0) {\n            if (is_child_scope(ctx, fd, vd->scope_next,\n                               scope_level))\n                return i;\n        }\n    }\n    return -1;\n}\n\n\nstatic JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)\n{\n    int i;\n    for(i = 0; i < fd->global_var_count; i++) {\n        JSGlobalVar *hf = &fd->global_vars[i];\n        if (hf->var_name == name)\n            return hf;\n    }\n    return NULL;\n\n}\n\nstatic JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)\n{\n    JSGlobalVar *hf = find_global_var(fd, name);\n    if (hf && hf->is_lexical)\n        return hf;\n    else\n        return NULL;\n}\n\nstatic int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,\n                             int scope_idx, BOOL check_catch_var)\n{\n    while (scope_idx >= 0) {\n        JSVarDef *vd = &fd->vars[scope_idx];\n        if (vd->var_name == name &&\n            (vd->is_lexical || (vd->var_kind == JS_VAR_CATCH &&\n                                check_catch_var)))\n            return scope_idx;\n        scope_idx = vd->scope_next;\n    }\n\n    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {\n        if (find_lexical_global_var(fd, name))\n            return GLOBAL_VAR_OFFSET;\n    }\n    return -1;\n}\n\nstatic int push_scope(JSParseState *s) {\n    if (s->cur_func) {\n        JSFunctionDef *fd = s->cur_func;\n        int scope = fd->scope_count;\n        /* XXX: should check for scope overflow */\n        if ((fd->scope_count + 1) > fd->scope_size) {\n            int new_size;\n            size_t slack;\n            JSVarScope *new_buf;\n            /* XXX: potential arithmetic overflow */\n            new_size = max_int(fd->scope_count + 1, fd->scope_size * 3 / 2);\n            if (fd->scopes == fd->def_scope_array) {\n                new_buf = js_realloc2(s->ctx, NULL, new_size * sizeof(*fd->scopes), &slack);\n                if (!new_buf)\n                    return -1;\n                memcpy(new_buf, fd->scopes, fd->scope_count * sizeof(*fd->scopes));\n            } else {\n                new_buf = js_realloc2(s->ctx, fd->scopes, new_size * sizeof(*fd->scopes), &slack);\n                if (!new_buf)\n                    return -1;\n            }\n            new_size += slack / sizeof(*new_buf);\n            fd->scopes = new_buf;\n            fd->scope_size = new_size;\n        }\n        fd->scope_count++;\n        fd->scopes[scope].parent = fd->scope_level;\n        fd->scopes[scope].first = fd->scope_first;\n        emit_op(s, OP_enter_scope);\n        emit_u16(s, scope);\n        return fd->scope_level = scope;\n    }\n    return 0;\n}\n\nstatic int get_first_lexical_var(JSFunctionDef *fd, int scope)\n{\n    while (scope >= 0) {\n        int scope_idx = fd->scopes[scope].first;\n        if (scope_idx >= 0)\n            return scope_idx;\n        scope = fd->scopes[scope].parent;\n    }\n    return -1;\n}\n\nstatic void pop_scope(JSParseState *s) {\n    if (s->cur_func) {\n        /* disable scoped variables */\n        JSFunctionDef *fd = s->cur_func;\n        int scope = fd->scope_level;\n        emit_op(s, OP_leave_scope);\n        emit_u16(s, scope);\n        fd->scope_level = fd->scopes[scope].parent;\n        fd->scope_first = get_first_lexical_var(fd, fd->scope_level);\n    }\n}\n\nstatic void close_scopes(JSParseState *s, int scope, int scope_stop)\n{\n    while (scope > scope_stop) {\n        emit_op(s, OP_leave_scope);\n        emit_u16(s, scope);\n        scope = s->cur_func->scopes[scope].parent;\n    }\n}\n\n/* return the variable index or -1 if error */\nstatic int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)\n{\n    JSVarDef *vd;\n\n    /* the local variable indexes are currently stored on 16 bits */\n    if (fd->var_count >= JS_MAX_LOCAL_VARS) {\n        JS_ThrowInternalError(ctx, \"too many local variables\");\n        return -1;\n    }\n    if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),\n                        &fd->var_size, fd->var_count + 1))\n        return -1;\n    vd = &fd->vars[fd->var_count++];\n    memset(vd, 0, sizeof(*vd));\n    vd->var_name = JS_DupAtom(ctx, name);\n    vd->func_pool_idx = -1;\n    return fd->var_count - 1;\n}\n\nstatic int add_scope_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name,\n                         JSVarKindEnum var_kind)\n{\n    int idx = add_var(ctx, fd, name);\n    if (idx >= 0) {\n        JSVarDef *vd = &fd->vars[idx];\n        vd->var_kind = var_kind;\n        vd->scope_level = fd->scope_level;\n        vd->scope_next = fd->scope_first;\n        fd->scopes[fd->scope_level].first = idx;\n        fd->scope_first = idx;\n    }\n    return idx;\n}\n\nstatic int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)\n{\n    int idx = fd->func_var_idx;\n    if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {\n        fd->func_var_idx = idx;\n        fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;\n        if (fd->js_mode & JS_MODE_STRICT)\n            fd->vars[idx].is_const = TRUE;\n    }\n    return idx;\n}\n\nstatic int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)\n{\n    int idx = fd->arguments_var_idx;\n    if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {\n        fd->arguments_var_idx = idx;\n    }\n    return idx;\n}\n\n/* add an argument definition in the argument scope. Only needed when\n   \"eval()\" may be called in the argument scope. Return 0 if OK. */\nstatic int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)\n{\n    int idx;\n    if (fd->arguments_arg_idx < 0) {\n        idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);\n        if (idx < 0) {\n            /* XXX: the scope links are not fully updated. May be an\n               issue if there are child scopes of the argument\n               scope */\n            idx = add_var(ctx, fd, JS_ATOM_arguments);\n            if (idx < 0)\n                return -1;\n            fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;\n            fd->scopes[ARG_SCOPE_INDEX].first = idx;\n            fd->vars[idx].scope_level = ARG_SCOPE_INDEX;\n            fd->vars[idx].is_lexical = TRUE;\n\n            fd->arguments_arg_idx = idx;\n        }\n    }\n    return 0;\n}\n\nstatic int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)\n{\n    JSVarDef *vd;\n\n    /* the local variable indexes are currently stored on 16 bits */\n    if (fd->arg_count >= JS_MAX_LOCAL_VARS) {\n        JS_ThrowInternalError(ctx, \"too many arguments\");\n        return -1;\n    }\n    if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),\n                        &fd->arg_size, fd->arg_count + 1))\n        return -1;\n    vd = &fd->args[fd->arg_count++];\n    memset(vd, 0, sizeof(*vd));\n    vd->var_name = JS_DupAtom(ctx, name);\n    vd->func_pool_idx = -1;\n    return fd->arg_count - 1;\n}\n\n/* add a global variable definition */\nstatic JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,\n                                     JSAtom name)\n{\n    JSGlobalVar *hf;\n\n    if (js_resize_array(ctx, (void **)&s->global_vars,\n                        sizeof(s->global_vars[0]),\n                        &s->global_var_size, s->global_var_count + 1))\n        return NULL;\n    hf = &s->global_vars[s->global_var_count++];\n    hf->cpool_idx = -1;\n    hf->force_init = FALSE;\n    hf->is_lexical = FALSE;\n    hf->is_const = FALSE;\n    hf->scope_level = s->scope_level;\n    hf->var_name = JS_DupAtom(ctx, name);\n    return hf;\n}\n\ntypedef enum {\n    JS_VAR_DEF_WITH,\n    JS_VAR_DEF_LET,\n    JS_VAR_DEF_CONST,\n    JS_VAR_DEF_FUNCTION_DECL, /* function declaration */\n    JS_VAR_DEF_NEW_FUNCTION_DECL, /* async/generator function declaration */\n    JS_VAR_DEF_CATCH,\n    JS_VAR_DEF_VAR,\n} JSVarDefEnum;\n\nstatic int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,\n                      JSVarDefEnum var_def_type)\n{\n    JSContext *ctx = s->ctx;\n    JSVarDef *vd;\n    int idx;\n\n    switch (var_def_type) {\n    case JS_VAR_DEF_WITH:\n        idx = add_scope_var(ctx, fd, name, JS_VAR_NORMAL);\n        break;\n\n    case JS_VAR_DEF_LET:\n    case JS_VAR_DEF_CONST:\n    case JS_VAR_DEF_FUNCTION_DECL:\n    case JS_VAR_DEF_NEW_FUNCTION_DECL:\n        idx = find_lexical_decl(ctx, fd, name, fd->scope_first, TRUE);\n        if (idx >= 0) {\n            if (idx < GLOBAL_VAR_OFFSET) {\n                if (fd->vars[idx].scope_level == fd->scope_level) {\n                    /* same scope: in non strict mode, functions\n                       can be redefined (annex B.3.3.4). */\n                    if (!(!(fd->js_mode & JS_MODE_STRICT) &&\n                          var_def_type == JS_VAR_DEF_FUNCTION_DECL &&\n                          fd->vars[idx].var_kind == JS_VAR_FUNCTION_DECL)) {\n                        goto redef_lex_error;\n                    }\n                } else if (fd->vars[idx].var_kind == JS_VAR_CATCH && (fd->vars[idx].scope_level + 2) == fd->scope_level) {\n                    goto redef_lex_error;\n                }\n            } else {\n                if (fd->scope_level == fd->body_scope) {\n                redef_lex_error:\n                    /* redefining a scoped var in the same scope: error */\n                    return js_parse_error(s, \"invalid redefinition of lexical identifier\");\n                }\n            }\n        }\n        if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&\n            var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&\n            fd->scope_level == fd->body_scope &&\n            find_arg(ctx, fd, name) >= 0) {\n            /* lexical variable redefines a parameter name */\n            return js_parse_error(s, \"invalid redefinition of parameter name\");\n        }\n\n        if (find_var_in_child_scope(ctx, fd, name, fd->scope_level) >= 0) {\n            return js_parse_error(s, \"invalid redefinition of a variable\");\n        }\n\n        if (fd->is_global_var) {\n            JSGlobalVar *hf;\n            hf = find_global_var(fd, name);\n            if (hf && is_child_scope(ctx, fd, hf->scope_level,\n                                     fd->scope_level)) {\n                return js_parse_error(s, \"invalid redefinition of global identifier\");\n            }\n        }\n\n        if (fd->is_eval &&\n            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||\n             fd->eval_type == JS_EVAL_TYPE_MODULE) &&\n            fd->scope_level == fd->body_scope) {\n            JSGlobalVar *hf;\n            hf = add_global_var(s->ctx, fd, name);\n            if (!hf)\n                return -1;\n            hf->is_lexical = TRUE;\n            hf->is_const = (var_def_type == JS_VAR_DEF_CONST);\n            idx = GLOBAL_VAR_OFFSET;\n        } else {\n            JSVarKindEnum var_kind;\n            if (var_def_type == JS_VAR_DEF_FUNCTION_DECL)\n                var_kind = JS_VAR_FUNCTION_DECL;\n            else if (var_def_type == JS_VAR_DEF_NEW_FUNCTION_DECL)\n                var_kind = JS_VAR_NEW_FUNCTION_DECL;\n            else\n                var_kind = JS_VAR_NORMAL;\n            idx = add_scope_var(ctx, fd, name, var_kind);\n            if (idx >= 0) {\n                vd = &fd->vars[idx];\n                vd->is_lexical = 1;\n                vd->is_const = (var_def_type == JS_VAR_DEF_CONST);\n            }\n        }\n        break;\n\n    case JS_VAR_DEF_CATCH:\n        idx = add_scope_var(ctx, fd, name, JS_VAR_CATCH);\n        break;\n\n    case JS_VAR_DEF_VAR:\n        if (find_lexical_decl(ctx, fd, name, fd->scope_first,\n                              FALSE) >= 0) {\n       invalid_lexical_redefinition:\n            /* error to redefine a var that inside a lexical scope */\n            return js_parse_error(s, \"invalid redefinition of lexical identifier\");\n        }\n        if (fd->is_global_var) {\n            JSGlobalVar *hf;\n            hf = find_global_var(fd, name);\n            if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&\n                fd->eval_type == JS_EVAL_TYPE_MODULE) {\n                goto invalid_lexical_redefinition;\n            }\n            hf = add_global_var(s->ctx, fd, name);\n            if (!hf)\n                return -1;\n            idx = GLOBAL_VAR_OFFSET;\n        } else {\n            /* if the variable already exists, don't add it again  */\n            idx = find_var(ctx, fd, name);\n            if (idx >= 0)\n                break;\n            idx = add_var(ctx, fd, name);\n            if (idx >= 0) {\n                if (name == JS_ATOM_arguments && fd->has_arguments_binding)\n                    fd->arguments_var_idx = idx;\n                fd->vars[idx].scope_next = fd->scope_level;\n            }\n        }\n        break;\n    default:\n        abort();\n    }\n    return idx;\n}\n\n/* add a private field variable in the current scope */\nstatic int add_private_class_field(JSParseState *s, JSFunctionDef *fd,\n                                   JSAtom name, JSVarKindEnum var_kind, BOOL is_static)\n{\n    JSContext *ctx = s->ctx;\n    JSVarDef *vd;\n    int idx;\n\n    idx = add_scope_var(ctx, fd, name, var_kind);\n    if (idx < 0)\n        return idx;\n    vd = &fd->vars[idx];\n    vd->is_lexical = 1;\n    vd->is_const = 1;\n    vd->is_static_private = is_static;\n    return idx;\n}\n\nstatic __exception int js_parse_expr(JSParseState *s);\nstatic __exception int js_parse_function_decl(JSParseState *s,\n                                              JSParseFunctionEnum func_type,\n                                              JSFunctionKindEnum func_kind,\n                                              JSAtom func_name, const uint8_t *ptr);\nstatic JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s);\nstatic __exception int js_parse_function_decl2(JSParseState *s,\n                                               JSParseFunctionEnum func_type,\n                                               JSFunctionKindEnum func_kind,\n                                               JSAtom func_name,\n                                               const uint8_t *ptr,\n                                               JSParseExportEnum export_flag,\n                                               JSFunctionDef **pfd);\nstatic __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);\nstatic __exception int js_parse_assign_expr(JSParseState *s);\nstatic __exception int js_parse_unary(JSParseState *s, int parse_flags);\nstatic void push_break_entry(JSFunctionDef *fd, BlockEnv *be,\n                             JSAtom label_name,\n                             int label_break, int label_cont,\n                             int drop_count);\nstatic void pop_break_entry(JSFunctionDef *fd);\nstatic JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,\n                                       JSAtom local_name, JSAtom export_name,\n                                       JSExportTypeEnum export_type);\n\n/* Note: all the fields are already sealed except length */\nstatic int seal_template_obj(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    JSShapeProperty *prs;\n\n    p = JS_VALUE_GET_OBJ(obj);\n    prs = find_own_property1(p, JS_ATOM_length);\n    if (prs) {\n        if (js_update_property_flags(ctx, p, &prs,\n                                     prs->flags & ~(JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)))\n            return -1;\n    }\n    p->extensible = FALSE;\n    return 0;\n}\n\nstatic __exception int js_parse_template(JSParseState *s, int call, int *argc)\n{\n    JSContext *ctx = s->ctx;\n    JSValue raw_array, template_object;\n    JSToken cooked;\n    int depth, ret;\n\n    raw_array = JS_UNDEFINED; /* avoid warning */\n    template_object = JS_UNDEFINED; /* avoid warning */\n    if (call) {\n        /* Create a template object: an array of cooked strings */\n        /* Create an array of raw strings and store it to the raw property */\n        template_object = JS_NewArray(ctx);\n        if (JS_IsException(template_object))\n            return -1;\n        //        pool_idx = s->cur_func->cpool_count;\n        ret = emit_push_const(s, template_object, 0);\n        JS_FreeValue(ctx, template_object);\n        if (ret)\n            return -1;\n        raw_array = JS_NewArray(ctx);\n        if (JS_IsException(raw_array))\n            return -1;\n        if (JS_DefinePropertyValue(ctx, template_object, JS_ATOM_raw,\n                                   raw_array, JS_PROP_THROW) < 0) {\n            return -1;\n        }\n    }\n\n    depth = 0;\n    while (s->token.val == TOK_TEMPLATE) {\n        const uint8_t *p = s->token.ptr + 1;\n        cooked = s->token;\n        if (call) {\n            if (JS_DefinePropertyValueUint32(ctx, raw_array, depth,\n                                             JS_DupValue(ctx, s->token.u.str.str),\n                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {\n                return -1;\n            }\n            /* re-parse the string with escape sequences but do not throw a\n               syntax error if it contains invalid sequences\n             */\n            if (js_parse_string(s, '`', FALSE, p, &cooked, &p)) {\n                cooked.u.str.str = JS_UNDEFINED;\n            }\n            if (JS_DefinePropertyValueUint32(ctx, template_object, depth,\n                                             cooked.u.str.str,\n                                             JS_PROP_ENUMERABLE | JS_PROP_THROW) < 0) {\n                return -1;\n            }\n        } else {\n            JSString *str;\n            /* re-parse the string with escape sequences and throw a\n               syntax error if it contains invalid sequences\n             */\n            JS_FreeValue(ctx, s->token.u.str.str);\n            s->token.u.str.str = JS_UNDEFINED;\n            if (js_parse_string(s, '`', TRUE, p, &cooked, &p))\n                return -1;\n            str = JS_VALUE_GET_STRING(cooked.u.str.str);\n            if (str->len != 0 || depth == 0) {\n                ret = emit_push_const(s, cooked.u.str.str, 1);\n                JS_FreeValue(s->ctx, cooked.u.str.str);\n                if (ret)\n                    return -1;\n                if (depth == 0) {\n                    if (s->token.u.str.sep == '`')\n                        goto done1;\n                    emit_op(s, OP_get_field2);\n                    emit_atom(s, JS_ATOM_concat);\n                }\n                depth++;\n            } else {\n                JS_FreeValue(s->ctx, cooked.u.str.str);\n            }\n        }\n        if (s->token.u.str.sep == '`')\n            goto done;\n        if (next_token(s))\n            return -1;\n        if (js_parse_expr(s))\n            return -1;\n        depth++;\n        if (s->token.val != '}') {\n            return js_parse_error(s, \"expected '}' after template expression\");\n        }\n        /* XXX: should convert to string at this stage? */\n        free_token(s, &s->token);\n        /* Resume TOK_TEMPLATE parsing (s->token.line_num and\n         * s->token.ptr are OK) */\n        s->got_lf = FALSE;\n        if (js_parse_template_part(s, s->buf_ptr))\n            return -1;\n    }\n    return js_parse_expect(s, TOK_TEMPLATE);\n\n done:\n    if (call) {\n        /* Seal the objects */\n        seal_template_obj(ctx, raw_array);\n        seal_template_obj(ctx, template_object);\n        *argc = depth + 1;\n    } else {\n        emit_op(s, OP_call_method);\n        emit_u16(s, depth - 1);\n    }\n done1:\n    return next_token(s);\n}\n\n\n#define PROP_TYPE_IDENT 0\n#define PROP_TYPE_VAR   1\n#define PROP_TYPE_GET   2\n#define PROP_TYPE_SET   3\n#define PROP_TYPE_STAR  4\n#define PROP_TYPE_ASYNC 5\n#define PROP_TYPE_ASYNC_STAR 6\n\n#define PROP_TYPE_PRIVATE (1 << 4)\n\nstatic BOOL token_is_ident(int tok)\n{\n    /* Accept keywords and reserved words as property names */\n    return (tok == TOK_IDENT ||\n            (tok >= TOK_FIRST_KEYWORD &&\n             tok <= TOK_LAST_KEYWORD));\n}\n\n/* if the property is an expression, name = JS_ATOM_NULL */\nstatic int __exception js_parse_property_name(JSParseState *s,\n                                              JSAtom *pname,\n                                              BOOL allow_method, BOOL allow_var,\n                                              BOOL allow_private)\n{\n    int is_private = 0;\n    BOOL is_non_reserved_ident;\n    JSAtom name;\n    int prop_type;\n\n    prop_type = PROP_TYPE_IDENT;\n    if (allow_method) {\n        /* if allow_private is true (for class field parsing) and\n           get/set is following by ';' (or LF with ASI), then it\n           is a field name */\n        if ((token_is_pseudo_keyword(s, JS_ATOM_get) ||\n             token_is_pseudo_keyword(s, JS_ATOM_set)) &&\n            (!allow_private || peek_token(s, TRUE) != '\\n')) {\n            /* get x(), set x() */\n            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);\n            if (next_token(s))\n                goto fail1;\n            if (s->token.val == ':' || s->token.val == ',' ||\n                s->token.val == '}' || s->token.val == '(' ||\n                s->token.val == '=' ||\n                (s->token.val == ';' && allow_private)) {\n                is_non_reserved_ident = TRUE;\n                goto ident_found;\n            }\n            prop_type = PROP_TYPE_GET + (name == JS_ATOM_set);\n            JS_FreeAtom(s->ctx, name);\n        } else if (s->token.val == '*') {\n            if (next_token(s))\n                goto fail;\n            prop_type = PROP_TYPE_STAR;\n        } else if (token_is_pseudo_keyword(s, JS_ATOM_async) &&\n                   peek_token(s, TRUE) != '\\n') {\n            name = JS_DupAtom(s->ctx, s->token.u.ident.atom);\n            if (next_token(s))\n                goto fail1;\n            if (s->token.val == ':' || s->token.val == ',' ||\n                s->token.val == '}' || s->token.val == '(' ||\n                s->token.val == '=') {\n                is_non_reserved_ident = TRUE;\n                goto ident_found;\n            }\n            JS_FreeAtom(s->ctx, name);\n            if (s->token.val == '*') {\n                if (next_token(s))\n                    goto fail;\n                prop_type = PROP_TYPE_ASYNC_STAR;\n            } else {\n                prop_type = PROP_TYPE_ASYNC;\n            }\n        }\n    }\n\n    if (token_is_ident(s->token.val)) {\n        /* variable can only be a non-reserved identifier */\n        is_non_reserved_ident =\n            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved);\n        /* keywords and reserved words have a valid atom */\n        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);\n        if (next_token(s))\n            goto fail1;\n    ident_found:\n        if (is_non_reserved_ident &&\n            prop_type == PROP_TYPE_IDENT && allow_var) {\n            if (!(s->token.val == ':' ||\n                  (s->token.val == '(' && allow_method))) {\n                prop_type = PROP_TYPE_VAR;\n            }\n        }\n    } else if (s->token.val == TOK_STRING) {\n        name = JS_ValueToAtom(s->ctx, s->token.u.str.str);\n        if (name == JS_ATOM_NULL)\n            goto fail;\n        if (next_token(s))\n            goto fail1;\n    } else if (s->token.val == TOK_NUMBER) {\n        JSValue val;\n        val = s->token.u.num.val;\n        name = JS_ValueToAtom(s->ctx, val);\n        if (name == JS_ATOM_NULL)\n            goto fail;\n        if (next_token(s))\n            goto fail1;\n    } else if (s->token.val == '[') {\n        if (next_token(s))\n            goto fail;\n        if (js_parse_assign_expr(s))\n            goto fail;\n        if (js_parse_expect(s, ']'))\n            goto fail;\n        name = JS_ATOM_NULL;\n    } else if (s->token.val == TOK_PRIVATE_NAME && allow_private) {\n        name = JS_DupAtom(s->ctx, s->token.u.ident.atom);\n        if (next_token(s))\n            goto fail1;\n        is_private = PROP_TYPE_PRIVATE;\n    } else {\n        goto invalid_prop;\n    }\n    if (prop_type != PROP_TYPE_IDENT && prop_type != PROP_TYPE_VAR &&\n        s->token.val != '(') {\n        JS_FreeAtom(s->ctx, name);\n    invalid_prop:\n        js_parse_error(s, \"invalid property name\");\n        goto fail;\n    }\n    *pname = name;\n    return prop_type | is_private;\n fail1:\n    JS_FreeAtom(s->ctx, name);\n fail:\n    *pname = JS_ATOM_NULL;\n    return -1;\n}\n\ntypedef struct JSParsePos {\n    BOOL got_lf;\n    const uint8_t *ptr;\n} JSParsePos;\n\nstatic int js_parse_get_pos(JSParseState *s, JSParsePos *sp)\n{\n    sp->ptr = s->token.ptr;\n    sp->got_lf = s->got_lf;\n    return 0;\n}\n\nstatic __exception int js_parse_seek_token(JSParseState *s, const JSParsePos *sp)\n{\n    s->buf_ptr = sp->ptr;\n    s->got_lf = sp->got_lf;\n    return next_token(s);\n}\n\n/* return TRUE if a regexp literal is allowed after this token */\nstatic BOOL is_regexp_allowed(int tok)\n{\n    switch (tok) {\n    case TOK_NUMBER:\n    case TOK_STRING:\n    case TOK_REGEXP:\n    case TOK_DEC:\n    case TOK_INC:\n    case TOK_NULL:\n    case TOK_FALSE:\n    case TOK_TRUE:\n    case TOK_THIS:\n    case ')':\n    case ']':\n    case '}': /* XXX: regexp may occur after */\n    case TOK_IDENT:\n        return FALSE;\n    default:\n        return TRUE;\n    }\n}\n\n#define SKIP_HAS_SEMI       (1 << 0)\n#define SKIP_HAS_ELLIPSIS   (1 << 1)\n#define SKIP_HAS_ASSIGNMENT (1 << 2)\n\nstatic BOOL has_lf_in_range(const uint8_t *p1, const uint8_t *p2)\n{\n    const uint8_t *tmp;\n    if (p1 > p2) {\n        tmp = p1;\n        p1 = p2;\n        p2 = tmp;\n    }\n    return (memchr(p1, '\\n', p2 - p1) != NULL);\n}\n\n/* XXX: improve speed with early bailout */\n/* XXX: no longer works if regexps are present. Could use previous\n   regexp parsing heuristics to handle most cases */\nstatic int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_terminator)\n{\n    char state[256];\n    size_t level = 0;\n    JSParsePos pos;\n    int last_tok, tok = TOK_EOF;\n    int c, tok_len, bits = 0;\n    const uint8_t *last_token_ptr;\n    \n    /* protect from underflow */\n    state[level++] = 0;\n\n    js_parse_get_pos(s, &pos);\n    last_tok = 0;\n    for (;;) {\n        switch(s->token.val) {\n        case '(':\n        case '[':\n        case '{':\n            if (level >= sizeof(state))\n                goto done;\n            state[level++] = s->token.val;\n            break;\n        case ')':\n            if (state[--level] != '(')\n                goto done;\n            break;\n        case ']':\n            if (state[--level] != '[')\n                goto done;\n            break;\n        case '}':\n            c = state[--level];\n            if (c == '`') {\n                /* continue the parsing of the template */\n                free_token(s, &s->token);\n                /* Resume TOK_TEMPLATE parsing (s->token.line_num and\n                 * s->token.ptr are OK) */\n                s->got_lf = FALSE;\n                if (js_parse_template_part(s, s->buf_ptr))\n                    goto done;\n                goto handle_template;\n            } else if (c != '{') {\n                goto done;\n            }\n            break;\n        case TOK_TEMPLATE:\n        handle_template:\n            if (s->token.u.str.sep != '`') {\n                /* '${' inside the template : closing '}' and continue\n                   parsing the template */\n                if (level >= sizeof(state))\n                    goto done;\n                state[level++] = '`';\n            }\n            break;\n        case TOK_EOF:\n            goto done;\n        case ';':\n            if (level == 2) {\n                bits |= SKIP_HAS_SEMI;\n            }\n            break;\n        case TOK_ELLIPSIS:\n            if (level == 2) {\n                bits |= SKIP_HAS_ELLIPSIS;\n            }\n            break;\n        case '=':\n            bits |= SKIP_HAS_ASSIGNMENT;\n            break;\n\n        case TOK_DIV_ASSIGN:\n            tok_len = 2;\n            goto parse_regexp;\n        case '/':\n            tok_len = 1;\n        parse_regexp:\n            if (is_regexp_allowed(last_tok)) {\n                s->buf_ptr -= tok_len;\n                if (js_parse_regexp(s)) {\n                    /* XXX: should clear the exception */\n                    goto done;\n                }\n            }\n            break;\n        }\n        /* last_tok is only used to recognize regexps */\n        if (s->token.val == TOK_IDENT &&\n            (token_is_pseudo_keyword(s, JS_ATOM_of) ||\n             token_is_pseudo_keyword(s, JS_ATOM_yield))) {\n            last_tok = TOK_OF;\n        } else {\n            last_tok = s->token.val;\n        }\n        last_token_ptr = s->token.ptr;\n        if (next_token(s)) {\n            /* XXX: should clear the exception generated by next_token() */\n            break;\n        }\n        if (level <= 1) {\n            tok = s->token.val;\n            if (token_is_pseudo_keyword(s, JS_ATOM_of))\n                tok = TOK_OF;\n            if (no_line_terminator && has_lf_in_range(last_token_ptr, s->token.ptr))\n                tok = '\\n';\n            break;\n        }\n    }\n done:\n    if (pbits) {\n        *pbits = bits;\n    }\n    if (js_parse_seek_token(s, &pos))\n        return -1;\n    return tok;\n}\n\nstatic void set_object_name(JSParseState *s, JSAtom name)\n{\n    JSFunctionDef *fd = s->cur_func;\n    int opcode;\n\n    opcode = get_prev_opcode(fd);\n    if (opcode == OP_set_name) {\n        /* XXX: should free atom after OP_set_name? */\n        fd->byte_code.size = fd->last_opcode_pos;\n        fd->last_opcode_pos = -1;\n        emit_op(s, OP_set_name);\n        emit_atom(s, name);\n    } else if (opcode == OP_set_class_name) {\n        int define_class_pos;\n        JSAtom atom;\n        define_class_pos = fd->last_opcode_pos + 1 -\n            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);\n        /* for consistency we free the previous atom which is\n           JS_ATOM_empty_string */\n        atom = get_u32(fd->byte_code.buf + define_class_pos + 1);\n        JS_FreeAtom(s->ctx, atom);\n        put_u32(fd->byte_code.buf + define_class_pos + 1,\n                JS_DupAtom(s->ctx, name));\n        fd->last_opcode_pos = -1;\n    }\n}\n\nstatic void set_object_name_computed(JSParseState *s)\n{\n    JSFunctionDef *fd = s->cur_func;\n    int opcode;\n\n    opcode = get_prev_opcode(fd);\n    if (opcode == OP_set_name) {\n        /* XXX: should free atom after OP_set_name? */\n        fd->byte_code.size = fd->last_opcode_pos;\n        fd->last_opcode_pos = -1;\n        emit_op(s, OP_set_name_computed);\n    } else if (opcode == OP_set_class_name) {\n        int define_class_pos;\n        define_class_pos = fd->last_opcode_pos + 1 -\n            get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n        assert(fd->byte_code.buf[define_class_pos] == OP_define_class);\n        fd->byte_code.buf[define_class_pos] = OP_define_class_computed;\n        fd->last_opcode_pos = -1;\n    }\n}\n\nstatic __exception int js_parse_object_literal(JSParseState *s)\n{\n    JSAtom name = JS_ATOM_NULL;\n    const uint8_t *start_ptr;\n    int prop_type;\n    BOOL has_proto;\n\n    if (next_token(s))\n        goto fail;\n    /* XXX: add an initial length that will be patched back */\n    emit_op(s, OP_object);\n    has_proto = FALSE;\n    while (s->token.val != '}') {\n        /* specific case for getter/setter */\n        start_ptr = s->token.ptr;\n\n        if (s->token.val == TOK_ELLIPSIS) {\n            if (next_token(s))\n                return -1;\n            if (js_parse_assign_expr(s))\n                return -1;\n            emit_op(s, OP_null);  /* dummy excludeList */\n            emit_op(s, OP_copy_data_properties);\n            emit_u8(s, 2 | (1 << 2) | (0 << 5));\n            emit_op(s, OP_drop); /* pop excludeList */\n            emit_op(s, OP_drop); /* pop src object */\n            goto next;\n        }\n\n        prop_type = js_parse_property_name(s, &name, TRUE, TRUE, FALSE);\n        if (prop_type < 0)\n            goto fail;\n\n        if (prop_type == PROP_TYPE_VAR) {\n            /* shortcut for x: x */\n            emit_op(s, OP_scope_get_var);\n            emit_atom(s, name);\n            emit_u16(s, s->cur_func->scope_level);\n            emit_op(s, OP_define_field);\n            emit_atom(s, name);\n        } else if (s->token.val == '(') {\n            BOOL is_getset = (prop_type == PROP_TYPE_GET ||\n                              prop_type == PROP_TYPE_SET);\n            JSParseFunctionEnum func_type;\n            JSFunctionKindEnum func_kind;\n            int op_flags;\n\n            func_kind = JS_FUNC_NORMAL;\n            if (is_getset) {\n                func_type = JS_PARSE_FUNC_GETTER + prop_type - PROP_TYPE_GET;\n            } else {\n                func_type = JS_PARSE_FUNC_METHOD;\n                if (prop_type == PROP_TYPE_STAR)\n                    func_kind = JS_FUNC_GENERATOR;\n                else if (prop_type == PROP_TYPE_ASYNC)\n                    func_kind = JS_FUNC_ASYNC;\n                else if (prop_type == PROP_TYPE_ASYNC_STAR)\n                    func_kind = JS_FUNC_ASYNC_GENERATOR;\n            }\n            if (js_parse_function_decl(s, func_type, func_kind, JS_ATOM_NULL,\n                                       start_ptr))\n                goto fail;\n            if (name == JS_ATOM_NULL) {\n                emit_op(s, OP_define_method_computed);\n            } else {\n                emit_op(s, OP_define_method);\n                emit_atom(s, name);\n            }\n            if (is_getset) {\n                op_flags = OP_DEFINE_METHOD_GETTER +\n                    prop_type - PROP_TYPE_GET;\n            } else {\n                op_flags = OP_DEFINE_METHOD_METHOD;\n            }\n            emit_u8(s, op_flags | OP_DEFINE_METHOD_ENUMERABLE);\n        } else {\n            if (name == JS_ATOM_NULL) {\n                /* must be done before evaluating expr */\n                emit_op(s, OP_to_propkey);\n            }\n            if (js_parse_expect(s, ':'))\n                goto fail;\n            if (js_parse_assign_expr(s))\n                goto fail;\n            if (name == JS_ATOM_NULL) {\n                set_object_name_computed(s);\n                emit_op(s, OP_define_array_el);\n                emit_op(s, OP_drop);\n            } else if (name == JS_ATOM___proto__) {\n                if (has_proto) {\n                    js_parse_error(s, \"duplicate __proto__ property name\");\n                    goto fail;\n                }\n                emit_op(s, OP_set_proto);\n                has_proto = TRUE;\n            } else {\n                set_object_name(s, name);\n                emit_op(s, OP_define_field);\n                emit_atom(s, name);\n            }\n        }\n        JS_FreeAtom(s->ctx, name);\n    next:\n        name = JS_ATOM_NULL;\n        if (s->token.val != ',')\n            break;\n        if (next_token(s))\n            goto fail;\n    }\n    if (js_parse_expect(s, '}'))\n        goto fail;\n    return 0;\n fail:\n    JS_FreeAtom(s->ctx, name);\n    return -1;\n}\n\n/* allow the 'in' binary operator */\n#define PF_IN_ACCEPTED  (1 << 0)\n/* allow function calls parsing in js_parse_postfix_expr() */\n#define PF_POSTFIX_CALL (1 << 1)\n/* allow the exponentiation operator in js_parse_unary() */\n#define PF_POW_ALLOWED  (1 << 2)\n/* forbid the exponentiation operator in js_parse_unary() */\n#define PF_POW_FORBIDDEN (1 << 3)\n\nstatic __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);\nstatic void emit_class_field_init(JSParseState *s);\nstatic JSFunctionDef *js_new_function_def(JSContext *ctx,\n                                          JSFunctionDef *parent,\n                                          BOOL is_eval,\n                                          BOOL is_func_expr,\n                                          const char *filename,\n                                          const uint8_t *source_ptr,\n                                          GetLineColCache *get_line_col_cache);\nstatic void emit_return(JSParseState *s, BOOL hasval);\n\nstatic __exception int js_parse_left_hand_side_expr(JSParseState *s)\n{\n    return js_parse_postfix_expr(s, PF_POSTFIX_CALL);\n}\n\nstatic __exception int js_parse_class_default_ctor(JSParseState *s,\n                                                   BOOL has_super,\n                                                   JSFunctionDef **pfd)\n{\n    JSParseFunctionEnum func_type;\n    JSFunctionDef *fd = s->cur_func;\n    int idx;\n\n    fd = js_new_function_def(s->ctx, fd, FALSE, FALSE, s->filename,\n                             s->token.ptr, &s->get_line_col_cache);\n    if (!fd)\n        return -1;\n\n    s->cur_func = fd;\n    fd->has_home_object = TRUE;\n    fd->super_allowed = TRUE;\n    fd->has_prototype = FALSE;\n    fd->has_this_binding = TRUE;\n    fd->new_target_allowed = TRUE;\n\n    push_scope(s);  /* enter body scope */\n    fd->body_scope = fd->scope_level;\n    if (has_super) {\n        fd->is_derived_class_constructor = TRUE;\n        fd->super_call_allowed = TRUE;\n        fd->arguments_allowed = TRUE;\n        fd->has_arguments_binding = TRUE;\n        func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;\n        emit_op(s, OP_init_ctor);\n        // TODO(bnoordhuis) roll into OP_init_ctor\n        emit_op(s, OP_scope_put_var_init);\n        emit_atom(s, JS_ATOM_this);\n        emit_u16(s, 0);\n        emit_class_field_init(s);\n    } else {\n        func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;\n        /* error if not invoked as a constructor */\n        emit_op(s, OP_check_ctor);\n        emit_class_field_init(s);\n    }\n\n    fd->func_kind = JS_FUNC_NORMAL;\n    fd->func_type = func_type;\n    emit_return(s, FALSE);\n\n    s->cur_func = fd->parent;\n    if (pfd)\n        *pfd = fd;\n\n    /* the real object will be set at the end of the compilation */\n    idx = cpool_add(s, JS_NULL);\n    fd->parent_cpool_idx = idx;\n\n    return 0;\n}\n\n/* find field in the current scope */\nstatic int find_private_class_field(JSContext *ctx, JSFunctionDef *fd,\n                                    JSAtom name, int scope_level)\n{\n    int idx;\n    idx = fd->scopes[scope_level].first;\n    while (idx != -1) {\n        if (fd->vars[idx].scope_level != scope_level)\n            break;\n        if (fd->vars[idx].var_name == name)\n            return idx;\n        idx = fd->vars[idx].scope_next;\n    }\n    return -1;\n}\n\n/* initialize the class fields, called by the constructor. Note:\n   super() can be called in an arrow function, so <this> and\n   <class_fields_init> can be variable references */\nstatic void emit_class_field_init(JSParseState *s)\n{\n    int label_next;\n\n    emit_op(s, OP_scope_get_var);\n    emit_atom(s, JS_ATOM_class_fields_init);\n    emit_u16(s, s->cur_func->scope_level);\n\n    /* no need to call the class field initializer if not defined */\n    emit_op(s, OP_dup);\n    label_next = emit_goto(s, OP_if_false, -1);\n\n    emit_op(s, OP_scope_get_var);\n    emit_atom(s, JS_ATOM_this);\n    emit_u16(s, 0);\n\n    emit_op(s, OP_swap);\n\n    emit_op(s, OP_call_method);\n    emit_u16(s, 0);\n\n    emit_label(s, label_next);\n    emit_op(s, OP_drop);\n}\n\n/* build a private setter function name from the private getter name */\nstatic JSAtom get_private_setter_name(JSContext *ctx, JSAtom name)\n{\n    return js_atom_concat_str(ctx, name, \"<set>\");\n}\n\ntypedef struct {\n    JSFunctionDef *fields_init_fd;\n    int computed_fields_count;\n    BOOL need_brand;\n    int brand_push_pos;\n    BOOL is_static;\n} ClassFieldsDef;\n\nstatic __exception int emit_class_init_start(JSParseState *s,\n                                             ClassFieldsDef *cf)\n{\n    int label_add_brand;\n\n    cf->fields_init_fd = js_parse_function_class_fields_init(s);\n    if (!cf->fields_init_fd)\n        return -1;\n\n    s->cur_func = cf->fields_init_fd;\n\n    if (!cf->is_static) {\n        /* add the brand to the newly created instance */\n        /* XXX: would be better to add the code only if needed, maybe in a\n           later pass */\n        emit_op(s, OP_push_false); /* will be patched later */\n        cf->brand_push_pos = cf->fields_init_fd->last_opcode_pos;\n        label_add_brand = emit_goto(s, OP_if_false, -1);\n\n        emit_op(s, OP_scope_get_var);\n        emit_atom(s, JS_ATOM_this);\n        emit_u16(s, 0);\n\n        emit_op(s, OP_scope_get_var);\n        emit_atom(s, JS_ATOM_home_object);\n        emit_u16(s, 0);\n\n        emit_op(s, OP_add_brand);\n\n        emit_label(s, label_add_brand);\n    }\n    s->cur_func = s->cur_func->parent;\n    return 0;\n}\n\nstatic void emit_class_init_end(JSParseState *s, ClassFieldsDef *cf)\n{\n    int cpool_idx;\n\n    s->cur_func = cf->fields_init_fd;\n    emit_op(s, OP_return_undef);\n    s->cur_func = s->cur_func->parent;\n\n    cpool_idx = cpool_add(s, JS_NULL);\n    cf->fields_init_fd->parent_cpool_idx = cpool_idx;\n    emit_op(s, OP_fclosure);\n    emit_u32(s, cpool_idx);\n    emit_op(s, OP_set_home_object);\n}\n\n\nstatic __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,\n                                      JSParseExportEnum export_flag)\n{\n    JSContext *ctx = s->ctx;\n    JSFunctionDef *fd = s->cur_func;\n    JSAtom name = JS_ATOM_NULL, class_name = JS_ATOM_NULL, class_name1;\n    JSAtom class_var_name = JS_ATOM_NULL;\n    JSFunctionDef *method_fd, *ctor_fd;\n    int saved_js_mode, class_name_var_idx, prop_type, ctor_cpool_offset;\n    int class_flags = 0, i, define_class_offset;\n    BOOL is_static, is_private;\n    const uint8_t *class_start_ptr = s->token.ptr;\n    const uint8_t *start_ptr;\n    ClassFieldsDef class_fields[2];\n\n    /* classes are parsed and executed in strict mode */\n    saved_js_mode = fd->js_mode;\n    fd->js_mode |= JS_MODE_STRICT;\n    if (next_token(s))\n        goto fail;\n    if (s->token.val == TOK_IDENT) {\n        if (s->token.u.ident.is_reserved) {\n            js_parse_error_reserved_identifier(s);\n            goto fail;\n        }\n        class_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n        if (next_token(s))\n            goto fail;\n    } else if (!is_class_expr && export_flag != JS_PARSE_EXPORT_DEFAULT) {\n        js_parse_error(s, \"class statement requires a name\");\n        goto fail;\n    }\n    if (!is_class_expr) {\n        if (class_name == JS_ATOM_NULL)\n            class_var_name = JS_ATOM__default_; /* export default */\n        else\n            class_var_name = class_name;\n        class_var_name = JS_DupAtom(ctx, class_var_name);\n    }\n\n    push_scope(s);\n\n    if (s->token.val == TOK_EXTENDS) {\n        class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;\n        if (next_token(s))\n            goto fail;\n        if (js_parse_left_hand_side_expr(s))\n            goto fail;\n    } else {\n        emit_op(s, OP_undefined);\n    }\n\n    /* add a 'const' definition for the class name */\n    if (class_name != JS_ATOM_NULL) {\n        class_name_var_idx = define_var(s, fd, class_name, JS_VAR_DEF_CONST);\n        if (class_name_var_idx < 0)\n            goto fail;\n    }\n\n    if (js_parse_expect(s, '{'))\n        goto fail;\n\n    /* this scope contains the private fields */\n    push_scope(s);\n\n    emit_op(s, OP_push_const);\n    ctor_cpool_offset = fd->byte_code.size;\n    emit_u32(s, 0); /* will be patched at the end of the class parsing */\n\n    if (class_name == JS_ATOM_NULL) {\n        if (class_var_name != JS_ATOM_NULL)\n            class_name1 = JS_ATOM_default;\n        else\n            class_name1 = JS_ATOM_empty_string;\n    } else {\n        class_name1 = class_name;\n    }\n\n    emit_op(s, OP_define_class);\n    emit_atom(s, class_name1);\n    emit_u8(s, class_flags);\n    define_class_offset = fd->last_opcode_pos;\n\n    for(i = 0; i < 2; i++) {\n        ClassFieldsDef *cf = &class_fields[i];\n        cf->fields_init_fd = NULL;\n        cf->computed_fields_count = 0;\n        cf->need_brand = FALSE;\n        cf->is_static = i;\n    }\n\n    ctor_fd = NULL;\n    while (s->token.val != '}') {\n        if (s->token.val == ';') {\n            if (next_token(s))\n                goto fail;\n            continue;\n        }\n        is_static = FALSE;\n        if (s->token.val == TOK_STATIC) {\n            int next = peek_token(s, TRUE);\n            if (!(next == ';' || next == '}' || next == '(' || next == '='))\n                is_static = TRUE;\n        }\n        prop_type = -1;\n        if (is_static) {\n            if (next_token(s))\n                goto fail;\n            if (s->token.val == '{') {\n                ClassFieldsDef *cf = &class_fields[is_static];\n                JSFunctionDef *init;\n                if (!cf->fields_init_fd) {\n                    if (emit_class_init_start(s, cf))\n                        goto fail;\n                }\n                s->cur_func = cf->fields_init_fd;\n                /* XXX: could try to avoid creating a new function and\n                   reuse 'fields_init_fd' with a specific 'var'\n                   scope */\n                // stack is now: <empty>\n                if (js_parse_function_decl2(s, JS_PARSE_FUNC_CLASS_STATIC_INIT,\n                                            JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                            s->token.ptr,\n                                            JS_PARSE_EXPORT_NONE, &init) < 0) {\n                    goto fail;\n                }\n                // stack is now: fclosure\n                push_scope(s);\n                emit_op(s, OP_scope_get_var);\n                emit_atom(s, JS_ATOM_this);\n                emit_u16(s, 0);\n                // stack is now: fclosure this\n                emit_op(s, OP_swap);\n                // stack is now: this fclosure\n                emit_op(s, OP_call_method);\n                emit_u16(s, 0);\n                // stack is now: returnvalue\n                emit_op(s, OP_drop);\n                // stack is now: <empty>\n                pop_scope(s);\n                s->cur_func = s->cur_func->parent;\n                continue;\n            }\n            /* allow \"static\" field name */\n            if (s->token.val == ';' || s->token.val == '=') {\n                is_static = FALSE;\n                name = JS_DupAtom(ctx, JS_ATOM_static);\n                prop_type = PROP_TYPE_IDENT;\n            }\n        }\n        if (is_static)\n            emit_op(s, OP_swap);\n        start_ptr = s->token.ptr;\n        if (prop_type < 0) {\n            prop_type = js_parse_property_name(s, &name, TRUE, FALSE, TRUE);\n            if (prop_type < 0)\n                goto fail;\n        }\n        is_private = prop_type & PROP_TYPE_PRIVATE;\n        prop_type &= ~PROP_TYPE_PRIVATE;\n\n        if ((name == JS_ATOM_constructor && !is_static &&\n             prop_type != PROP_TYPE_IDENT) ||\n            (name == JS_ATOM_prototype && is_static) ||\n            name == JS_ATOM_hash_constructor) {\n            js_parse_error(s, \"invalid method name\");\n            goto fail;\n        }\n        if (prop_type == PROP_TYPE_GET || prop_type == PROP_TYPE_SET) {\n            BOOL is_set = prop_type - PROP_TYPE_GET;\n            JSFunctionDef *method_fd;\n\n            if (is_private) {\n                int idx, var_kind, is_static1;\n                idx = find_private_class_field(ctx, fd, name, fd->scope_level);\n                if (idx >= 0) {\n                    var_kind = fd->vars[idx].var_kind;\n                    is_static1 = fd->vars[idx].is_static_private;\n                    if (var_kind == JS_VAR_PRIVATE_FIELD ||\n                        var_kind == JS_VAR_PRIVATE_METHOD ||\n                        var_kind == JS_VAR_PRIVATE_GETTER_SETTER ||\n                        var_kind == (JS_VAR_PRIVATE_GETTER + is_set) ||\n                        (var_kind == (JS_VAR_PRIVATE_GETTER + 1 - is_set) &&\n                         is_static != is_static1)) {\n                        goto private_field_already_defined;\n                    }\n                    fd->vars[idx].var_kind = JS_VAR_PRIVATE_GETTER_SETTER;\n                } else {\n                    if (add_private_class_field(s, fd, name,\n                                                JS_VAR_PRIVATE_GETTER + is_set, is_static) < 0)\n                        goto fail;\n                }\n                class_fields[is_static].need_brand = TRUE;\n            }\n\n            if (js_parse_function_decl2(s, JS_PARSE_FUNC_GETTER + is_set,\n                                        JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                        start_ptr,\n                                        JS_PARSE_EXPORT_NONE, &method_fd))\n                goto fail;\n            if (is_private) {\n                method_fd->need_home_object = TRUE; /* needed for brand check */\n                emit_op(s, OP_set_home_object);\n                /* XXX: missing function name */\n                emit_op(s, OP_scope_put_var_init);\n                if (is_set) {\n                    JSAtom setter_name;\n                    int ret;\n\n                    setter_name = get_private_setter_name(ctx, name);\n                    if (setter_name == JS_ATOM_NULL)\n                        goto fail;\n                    emit_atom(s, setter_name);\n                    ret = add_private_class_field(s, fd, setter_name,\n                                                  JS_VAR_PRIVATE_SETTER, is_static);\n                    JS_FreeAtom(ctx, setter_name);\n                    if (ret < 0)\n                        goto fail;\n                } else {\n                    emit_atom(s, name);\n                }\n                emit_u16(s, s->cur_func->scope_level);\n            } else {\n                if (name == JS_ATOM_NULL) {\n                    emit_op(s, OP_define_method_computed);\n                } else {\n                    emit_op(s, OP_define_method);\n                    emit_atom(s, name);\n                }\n                emit_u8(s, OP_DEFINE_METHOD_GETTER + is_set);\n            }\n        } else if (prop_type == PROP_TYPE_IDENT && s->token.val != '(') {\n            ClassFieldsDef *cf = &class_fields[is_static];\n            JSAtom field_var_name = JS_ATOM_NULL;\n\n            /* class field */\n\n            /* XXX: spec: not consistent with method name checks */\n            if (name == JS_ATOM_constructor || name == JS_ATOM_prototype) {\n                js_parse_error(s, \"invalid field name\");\n                goto fail;\n            }\n\n            if (is_private) {\n                if (find_private_class_field(ctx, fd, name,\n                                             fd->scope_level) >= 0) {\n                    goto private_field_already_defined;\n                }\n                if (add_private_class_field(s, fd, name,\n                                            JS_VAR_PRIVATE_FIELD, is_static) < 0)\n                    goto fail;\n                emit_op(s, OP_private_symbol);\n                emit_atom(s, name);\n                emit_op(s, OP_scope_put_var_init);\n                emit_atom(s, name);\n                emit_u16(s, s->cur_func->scope_level);\n            }\n\n            if (!cf->fields_init_fd) {\n                if (emit_class_init_start(s, cf))\n                    goto fail;\n            }\n            if (name == JS_ATOM_NULL ) {\n                /* save the computed field name into a variable */\n                field_var_name = js_atom_concat_num(ctx, JS_ATOM_computed_field + is_static, cf->computed_fields_count);\n                if (field_var_name == JS_ATOM_NULL)\n                    goto fail;\n                if (define_var(s, fd, field_var_name, JS_VAR_DEF_CONST) < 0) {\n                    JS_FreeAtom(ctx, field_var_name);\n                    goto fail;\n                }\n                emit_op(s, OP_to_propkey);\n                emit_op(s, OP_scope_put_var_init);\n                emit_atom(s, field_var_name);\n                emit_u16(s, s->cur_func->scope_level);\n            }\n            s->cur_func = cf->fields_init_fd;\n            emit_op(s, OP_scope_get_var);\n            emit_atom(s, JS_ATOM_this);\n            emit_u16(s, 0);\n\n            if (name == JS_ATOM_NULL) {\n                emit_op(s, OP_scope_get_var);\n                emit_atom(s, field_var_name);\n                emit_u16(s, s->cur_func->scope_level);\n                cf->computed_fields_count++;\n                JS_FreeAtom(ctx, field_var_name);\n            } else if (is_private) {\n                emit_op(s, OP_scope_get_var);\n                emit_atom(s, name);\n                emit_u16(s, s->cur_func->scope_level);\n            }\n\n            if (s->token.val == '=') {\n                if (next_token(s))\n                    goto fail;\n                if (js_parse_assign_expr(s))\n                    goto fail;\n            } else {\n                emit_op(s, OP_undefined);\n            }\n            if (is_private) {\n                set_object_name_computed(s);\n                emit_op(s, OP_define_private_field);\n            } else if (name == JS_ATOM_NULL) {\n                set_object_name_computed(s);\n                emit_op(s, OP_define_array_el);\n                emit_op(s, OP_drop);\n            } else {\n                set_object_name(s, name);\n                emit_op(s, OP_define_field);\n                emit_atom(s, name);\n            }\n            s->cur_func = s->cur_func->parent;\n            if (js_parse_expect_semi(s))\n                goto fail;\n        } else {\n            JSParseFunctionEnum func_type;\n            JSFunctionKindEnum func_kind;\n\n            func_type = JS_PARSE_FUNC_METHOD;\n            func_kind = JS_FUNC_NORMAL;\n            if (prop_type == PROP_TYPE_STAR) {\n                func_kind = JS_FUNC_GENERATOR;\n            } else if (prop_type == PROP_TYPE_ASYNC) {\n                func_kind = JS_FUNC_ASYNC;\n            } else if (prop_type == PROP_TYPE_ASYNC_STAR) {\n                func_kind = JS_FUNC_ASYNC_GENERATOR;\n            } else if (name == JS_ATOM_constructor && !is_static) {\n                if (ctor_fd) {\n                    js_parse_error(s, \"property constructor appears more than once\");\n                    goto fail;\n                }\n                if (class_flags & JS_DEFINE_CLASS_HAS_HERITAGE)\n                    func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;\n                else\n                    func_type = JS_PARSE_FUNC_CLASS_CONSTRUCTOR;\n            }\n            if (is_private) {\n                class_fields[is_static].need_brand = TRUE;\n            }\n            if (js_parse_function_decl2(s, func_type, func_kind, JS_ATOM_NULL, start_ptr, JS_PARSE_EXPORT_NONE, &method_fd))\n                goto fail;\n            if (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ||\n                func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {\n                ctor_fd = method_fd;\n            } else if (is_private) {\n                method_fd->need_home_object = TRUE; /* needed for brand check */\n                if (find_private_class_field(ctx, fd, name,\n                                             fd->scope_level) >= 0) {\n                private_field_already_defined:\n                    js_parse_error(s, \"private class field is already defined\");\n                    goto fail;\n                }\n                if (add_private_class_field(s, fd, name,\n                                            JS_VAR_PRIVATE_METHOD, is_static) < 0)\n                    goto fail;\n                emit_op(s, OP_set_home_object);\n                emit_op(s, OP_set_name);\n                emit_atom(s, name);\n                emit_op(s, OP_scope_put_var_init);\n                emit_atom(s, name);\n                emit_u16(s, s->cur_func->scope_level);\n            } else {\n                if (name == JS_ATOM_NULL) {\n                    emit_op(s, OP_define_method_computed);\n                } else {\n                    emit_op(s, OP_define_method);\n                    emit_atom(s, name);\n                }\n                emit_u8(s, OP_DEFINE_METHOD_METHOD);\n            }\n        }\n        if (is_static)\n            emit_op(s, OP_swap);\n        JS_FreeAtom(ctx, name);\n        name = JS_ATOM_NULL;\n    }\n\n    if (s->token.val != '}') {\n        js_parse_error(s, \"expecting '%c'\", '}');\n        goto fail;\n    }\n\n    if (!ctor_fd) {\n        if (js_parse_class_default_ctor(s, class_flags & JS_DEFINE_CLASS_HAS_HERITAGE, &ctor_fd))\n            goto fail;\n    }\n    /* patch the constant pool index for the constructor */\n    put_u32(fd->byte_code.buf + ctor_cpool_offset, ctor_fd->parent_cpool_idx);\n\n    /* store the class source code in the constructor. */\n    if (!fd->strip_source) {\n        js_free(ctx, ctor_fd->source);\n        ctor_fd->source_len = s->buf_ptr - class_start_ptr;\n        ctor_fd->source = js_strndup(ctx, (const char *)class_start_ptr,\n                                     ctor_fd->source_len);\n        if (!ctor_fd->source)\n            goto fail;\n    }\n\n    /* consume the '}' */\n    if (next_token(s))\n        goto fail;\n\n    {\n        ClassFieldsDef *cf = &class_fields[0];\n        int var_idx;\n\n        if (cf->need_brand) {\n            /* add a private brand to the prototype */\n            emit_op(s, OP_dup);\n            emit_op(s, OP_null);\n            emit_op(s, OP_swap);\n            emit_op(s, OP_add_brand);\n\n            /* define the brand field in 'this' of the initializer */\n            if (!cf->fields_init_fd) {\n                if (emit_class_init_start(s, cf))\n                    goto fail;\n            }\n            /* patch the start of the function to enable the\n               OP_add_brand_instance code */\n            cf->fields_init_fd->byte_code.buf[cf->brand_push_pos] = OP_push_true;\n        }\n\n        /* store the function to initialize the fields to that it can be\n           referenced by the constructor */\n        var_idx = define_var(s, fd, JS_ATOM_class_fields_init,\n                             JS_VAR_DEF_CONST);\n        if (var_idx < 0)\n            goto fail;\n        if (cf->fields_init_fd) {\n            emit_class_init_end(s, cf);\n        } else {\n            emit_op(s, OP_undefined);\n        }\n        emit_op(s, OP_scope_put_var_init);\n        emit_atom(s, JS_ATOM_class_fields_init);\n        emit_u16(s, s->cur_func->scope_level);\n    }\n\n    /* drop the prototype */\n    emit_op(s, OP_drop);\n\n    if (class_fields[1].need_brand) {\n        /* add a private brand to the class */\n        emit_op(s, OP_dup);\n        emit_op(s, OP_dup);\n        emit_op(s, OP_add_brand);\n    }\n\n    if (class_name != JS_ATOM_NULL) {\n        /* store the class name in the scoped class name variable (it\n           is independent from the class statement variable\n           definition) */\n        emit_op(s, OP_dup);\n        emit_op(s, OP_scope_put_var_init);\n        emit_atom(s, class_name);\n        emit_u16(s, fd->scope_level);\n    }\n\n    /* initialize the static fields */\n    if (class_fields[1].fields_init_fd != NULL) {\n        ClassFieldsDef *cf = &class_fields[1];\n        emit_op(s, OP_dup);\n        emit_class_init_end(s, cf);\n        emit_op(s, OP_call_method);\n        emit_u16(s, 0);\n        emit_op(s, OP_drop);\n    }\n\n    pop_scope(s);\n    pop_scope(s);\n\n    /* the class statements have a block level scope */\n    if (class_var_name != JS_ATOM_NULL) {\n        if (define_var(s, fd, class_var_name, JS_VAR_DEF_LET) < 0)\n            goto fail;\n        emit_op(s, OP_scope_put_var_init);\n        emit_atom(s, class_var_name);\n        emit_u16(s, fd->scope_level);\n    } else {\n        if (class_name == JS_ATOM_NULL) {\n            /* cannot use OP_set_name because the name of the class\n               must be defined before the static initializers are\n               executed */\n            emit_op(s, OP_set_class_name);\n            emit_u32(s, fd->last_opcode_pos + 1 - define_class_offset);\n        }\n    }\n\n    if (export_flag != JS_PARSE_EXPORT_NONE) {\n        if (!add_export_entry(s, fd->module,\n                              class_var_name,\n                              export_flag == JS_PARSE_EXPORT_NAMED ? class_var_name : JS_ATOM_default,\n                              JS_EXPORT_TYPE_LOCAL))\n            goto fail;\n    }\n\n    JS_FreeAtom(ctx, class_name);\n    JS_FreeAtom(ctx, class_var_name);\n    fd->js_mode = saved_js_mode;\n    return 0;\n fail:\n    JS_FreeAtom(ctx, name);\n    JS_FreeAtom(ctx, class_name);\n    JS_FreeAtom(ctx, class_var_name);\n    fd->js_mode = saved_js_mode;\n    return -1;\n}\n\nstatic __exception int js_parse_array_literal(JSParseState *s)\n{\n    uint32_t idx;\n    BOOL need_length;\n\n    if (next_token(s))\n        return -1;\n    /* small regular arrays are created on the stack */\n    idx = 0;\n    while (s->token.val != ']' && idx < 32) {\n        if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)\n            break;\n        if (js_parse_assign_expr(s))\n            return -1;\n        idx++;\n        /* accept trailing comma */\n        if (s->token.val == ',') {\n            if (next_token(s))\n                return -1;\n        } else\n        if (s->token.val != ']')\n            goto done;\n    }\n    emit_op(s, OP_array_from);\n    emit_u16(s, idx);\n\n    /* larger arrays and holes are handled with explicit indices */\n    need_length = FALSE;\n    while (s->token.val != ']' && idx < 0x7fffffff) {\n        if (s->token.val == TOK_ELLIPSIS)\n            break;\n        need_length = TRUE;\n        if (s->token.val != ',') {\n            if (js_parse_assign_expr(s))\n                return -1;\n            emit_op(s, OP_define_field);\n            emit_u32(s, __JS_AtomFromUInt32(idx));\n            need_length = FALSE;\n        }\n        idx++;\n        /* accept trailing comma */\n        if (s->token.val == ',') {\n            if (next_token(s))\n                return -1;\n        }\n    }\n    if (s->token.val == ']') {\n        if (need_length) {\n            /* Set the length: Cannot use OP_define_field because\n               length is not configurable */\n            emit_op(s, OP_dup);\n            emit_op(s, OP_push_i32);\n            emit_u32(s, idx);\n            emit_op(s, OP_put_field);\n            emit_atom(s, JS_ATOM_length);\n        }\n        goto done;\n    }\n\n    /* huge arrays and spread elements require a dynamic index on the stack */\n    emit_op(s, OP_push_i32);\n    emit_u32(s, idx);\n\n    /* stack has array, index */\n    while (s->token.val != ']') {\n        if (s->token.val == TOK_ELLIPSIS) {\n            if (next_token(s))\n                return -1;\n            if (js_parse_assign_expr(s))\n                return -1;\n#if 1\n            emit_op(s, OP_append);\n#else\n            int label_next, label_done;\n            label_next = new_label(s);\n            label_done = new_label(s);\n            /* enumerate object */\n            emit_op(s, OP_for_of_start);\n            emit_op(s, OP_rot5l);\n            emit_op(s, OP_rot5l);\n            emit_label(s, label_next);\n            /* on stack: enum_rec array idx */\n            emit_op(s, OP_for_of_next);\n            emit_u8(s, 2);\n            emit_goto(s, OP_if_true, label_done);\n            /* append element */\n            /* enum_rec array idx val -> enum_rec array new_idx */\n            emit_op(s, OP_define_array_el);\n            emit_op(s, OP_inc);\n            emit_goto(s, OP_goto, label_next);\n            emit_label(s, label_done);\n            /* close enumeration */\n            emit_op(s, OP_drop); /* drop undef val */\n            emit_op(s, OP_nip1); /* drop enum_rec */\n            emit_op(s, OP_nip1);\n            emit_op(s, OP_nip1);\n#endif\n        } else {\n            need_length = TRUE;\n            if (s->token.val != ',') {\n                if (js_parse_assign_expr(s))\n                    return -1;\n                /* a idx val */\n                emit_op(s, OP_define_array_el);\n                need_length = FALSE;\n            }\n            emit_op(s, OP_inc);\n        }\n        if (s->token.val != ',')\n            break;\n        if (next_token(s))\n            return -1;\n    }\n    if (need_length) {\n        /* Set the length: cannot use OP_define_field because\n           length is not configurable */\n        emit_op(s, OP_dup1);    /* array length - array array length */\n        emit_op(s, OP_put_field);\n        emit_atom(s, JS_ATOM_length);\n    } else {\n        emit_op(s, OP_drop);    /* array length - array */\n    }\ndone:\n    return js_parse_expect(s, ']');\n}\n\n/* check if scope chain contains a with statement */\nstatic BOOL has_with_scope(JSFunctionDef *s, int scope_level)\n{\n    while (s) {\n        /* no with in strict mode */\n        if (!(s->js_mode & JS_MODE_STRICT)) {\n            int scope_idx = s->scopes[scope_level].first;\n            while (scope_idx >= 0) {\n                JSVarDef *vd = &s->vars[scope_idx];\n                if (vd->var_name == JS_ATOM__with_)\n                    return TRUE;\n                scope_idx = vd->scope_next;\n            }\n        }\n        /* check parent scopes */\n        scope_level = s->parent_scope_level;\n        s = s->parent;\n    }\n    return FALSE;\n}\n\nstatic __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope,\n                                  JSAtom *pname, int *plabel, int *pdepth, BOOL keep,\n                                  int tok)\n{\n    JSFunctionDef *fd;\n    int opcode, scope, label, depth;\n    JSAtom name;\n\n    /* we check the last opcode to get the lvalue type */\n    fd = s->cur_func;\n    scope = 0;\n    name = JS_ATOM_NULL;\n    label = -1;\n    depth = 0;\n    switch(opcode = get_prev_opcode(fd)) {\n    case OP_scope_get_var:\n        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);\n        if ((name == JS_ATOM_arguments || name == JS_ATOM_eval) &&\n            (fd->js_mode & JS_MODE_STRICT)) {\n            return js_parse_error(s, \"invalid lvalue in strict mode\");\n        }\n        if (name == JS_ATOM_this || name == JS_ATOM_new_target)\n            goto invalid_lvalue;\n        if (has_with_scope(fd, scope)) {\n            depth = 2;  /* will generate OP_get_ref_value */\n        } else {\n            depth = 0;\n        }\n        break;\n    case OP_get_field:\n        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n        depth = 1;\n        break;\n    case OP_scope_get_private_field:\n        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);\n        depth = 1;\n        break;\n    case OP_get_array_el:\n        depth = 2;\n        break;\n    case OP_get_super_value:\n        depth = 3;\n        break;\n    default:\n    invalid_lvalue:\n        if (tok == TOK_FOR) {\n            return js_parse_error(s, \"invalid for in/of left hand-side\");\n        } else if (tok == TOK_INC || tok == TOK_DEC) {\n            return js_parse_error(s, \"invalid increment/decrement operand\");\n        } else if (tok == '[' || tok == '{') {\n            return js_parse_error(s, \"invalid destructuring target\");\n        } else {\n            return js_parse_error(s, \"invalid assignment left-hand side\");\n        }\n    }\n    /* remove the last opcode */\n    fd->byte_code.size = fd->last_opcode_pos;\n    fd->last_opcode_pos = -1;\n\n    if (keep) {\n        /* get the value but keep the object/fields on the stack */\n        switch(opcode) {\n        case OP_scope_get_var:\n            if (depth != 0) {\n                label = new_label(s);\n                if (label < 0)\n                    return -1;\n                emit_op(s, OP_scope_make_ref);\n                emit_atom(s, name);\n                emit_u32(s, label);\n                emit_u16(s, scope);\n                update_label(fd, label, 1);\n                emit_op(s, OP_get_ref_value);\n                opcode = OP_get_ref_value;\n            } else {\n                emit_op(s, OP_scope_get_var);\n                emit_atom(s, name);\n                emit_u16(s, scope);\n            }\n            break;\n        case OP_get_field:\n            emit_op(s, OP_get_field2);\n            emit_atom(s, name);\n            break;\n        case OP_scope_get_private_field:\n            emit_op(s, OP_scope_get_private_field2);\n            emit_atom(s, name);\n            emit_u16(s, scope);\n            break;\n        case OP_get_array_el:\n            emit_op(s, OP_get_array_el3);\n            break;\n        case OP_get_super_value:\n            emit_op(s, OP_to_propkey);\n            emit_op(s, OP_dup3);\n            emit_op(s, OP_get_super_value);\n            break;\n        default:\n            abort();\n        }\n    } else {\n        switch(opcode) {\n        case OP_scope_get_var:\n            if (depth != 0) {\n                label = new_label(s);\n                if (label < 0)\n                    return -1;\n                emit_op(s, OP_scope_make_ref);\n                emit_atom(s, name);\n                emit_u32(s, label);\n                emit_u16(s, scope);\n                update_label(fd, label, 1);\n                opcode = OP_get_ref_value;\n            }\n            break;\n        default:\n            break;\n        }\n    }\n\n    *popcode = opcode;\n    *pscope = scope;\n    /* name has refcount for OP_get_field and OP_get_ref_value,\n       and JS_ATOM_NULL for other opcodes */\n    *pname = name;\n    *plabel = label;\n    if (pdepth)\n        *pdepth = depth;\n    return 0;\n}\n\ntypedef enum {\n    PUT_LVALUE_NOKEEP, /* [depth] v -> */\n    PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently\n                                just disable optimizations) */\n    PUT_LVALUE_KEEP_TOP,  /* [depth] v -> v */\n    PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */\n    PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */\n} PutLValueEnum;\n\n/* name has a live reference. 'is_let' is only used with opcode =\n   OP_scope_get_var which is never generated by get_lvalue(). */\nstatic void put_lvalue(JSParseState *s, int opcode, int scope,\n                       JSAtom name, int label, PutLValueEnum special,\n                       BOOL is_let)\n{\n    switch(opcode) {\n    case OP_scope_get_var:\n        /* depth = 0 */\n        switch(special) {\n        case PUT_LVALUE_NOKEEP:\n        case PUT_LVALUE_NOKEEP_DEPTH:\n        case PUT_LVALUE_KEEP_SECOND:\n        case PUT_LVALUE_NOKEEP_BOTTOM:\n            break;\n        case PUT_LVALUE_KEEP_TOP:\n            emit_op(s, OP_dup);\n            break;\n        default:\n            abort();\n        }\n        break;\n    case OP_get_field:\n    case OP_scope_get_private_field:\n        /* depth = 1 */\n        switch(special) {\n        case PUT_LVALUE_NOKEEP:\n        case PUT_LVALUE_NOKEEP_DEPTH:\n            break;\n        case PUT_LVALUE_KEEP_TOP:\n            emit_op(s, OP_insert2); /* obj v -> v obj v */\n            break;\n        case PUT_LVALUE_KEEP_SECOND:\n            emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */\n            break;\n        case PUT_LVALUE_NOKEEP_BOTTOM:\n            emit_op(s, OP_swap);\n            break;\n        default:\n            abort();\n        }\n        break;\n    case OP_get_array_el:\n    case OP_get_ref_value:\n        /* depth = 2 */\n        if (opcode == OP_get_ref_value) {\n            JS_FreeAtom(s->ctx, name);\n            emit_label(s, label);\n        }\n        switch(special) {\n        case PUT_LVALUE_NOKEEP:\n            emit_op(s, OP_nop); /* will trigger optimization */\n            break;\n        case PUT_LVALUE_NOKEEP_DEPTH:\n            break;\n        case PUT_LVALUE_KEEP_TOP:\n            emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */\n            break;\n        case PUT_LVALUE_KEEP_SECOND:\n            emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */\n            break;\n        case PUT_LVALUE_NOKEEP_BOTTOM:\n            emit_op(s, OP_rot3l);\n            break;\n        default:\n            abort();\n        }\n        break;\n    case OP_get_super_value:\n        /* depth = 3 */\n        switch(special) {\n        case PUT_LVALUE_NOKEEP:\n        case PUT_LVALUE_NOKEEP_DEPTH:\n            break;\n        case PUT_LVALUE_KEEP_TOP:\n            emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */\n            break;\n        case PUT_LVALUE_KEEP_SECOND:\n            emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */\n            break;\n        case PUT_LVALUE_NOKEEP_BOTTOM:\n            emit_op(s, OP_rot4l);\n            break;\n        default:\n            abort();\n        }\n        break;\n    default:\n        break;\n    }\n\n    switch(opcode) {\n    case OP_scope_get_var:  /* val -- */\n        emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var);\n        emit_u32(s, name);  /* has refcount */\n        emit_u16(s, scope);\n        break;\n    case OP_get_field:\n        emit_op(s, OP_put_field);\n        emit_u32(s, name);  /* name has refcount */\n        break;\n    case OP_scope_get_private_field:\n        emit_op(s, OP_scope_put_private_field);\n        emit_u32(s, name);  /* name has refcount */\n        emit_u16(s, scope);\n        break;\n    case OP_get_array_el:\n        emit_op(s, OP_put_array_el);\n        break;\n    case OP_get_ref_value:\n        emit_op(s, OP_put_ref_value);\n        break;\n    case OP_get_super_value:\n        emit_op(s, OP_put_super_value);\n        break;\n    default:\n        abort();\n    }\n}\n\nstatic __exception int js_parse_expr_paren(JSParseState *s)\n{\n    if (js_parse_expect(s, '('))\n        return -1;\n    if (js_parse_expr(s))\n        return -1;\n    if (js_parse_expect(s, ')'))\n        return -1;\n    return 0;\n}\n\nstatic int js_unsupported_keyword(JSParseState *s, JSAtom atom)\n{\n    char buf[ATOM_GET_STR_BUF_SIZE];\n    return js_parse_error(s, \"unsupported keyword: %s\",\n                          JS_AtomGetStr(s->ctx, buf, sizeof(buf), atom));\n}\n\nstatic __exception int js_define_var(JSParseState *s, JSAtom name, int tok)\n{\n    JSFunctionDef *fd = s->cur_func;\n    JSVarDefEnum var_def_type;\n\n    if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {\n        return js_parse_error(s, \"yield is a reserved identifier\");\n    }\n    if ((name == JS_ATOM_arguments || name == JS_ATOM_eval)\n    &&  (fd->js_mode & JS_MODE_STRICT)) {\n        return js_parse_error(s, \"invalid variable name in strict mode\");\n    }\n    if (name == JS_ATOM_let\n    &&  (tok == TOK_LET || tok == TOK_CONST)) {\n        return js_parse_error(s, \"invalid lexical variable name\");\n    }\n    switch(tok) {\n    case TOK_LET:\n        var_def_type = JS_VAR_DEF_LET;\n        break;\n    case TOK_CONST:\n        var_def_type = JS_VAR_DEF_CONST;\n        break;\n    case TOK_VAR:\n        var_def_type = JS_VAR_DEF_VAR;\n        break;\n    case TOK_CATCH:\n        var_def_type = JS_VAR_DEF_CATCH;\n        break;\n    default:\n        abort();\n    }\n    if (define_var(s, fd, name, var_def_type) < 0)\n        return -1;\n    return 0;\n}\n\nstatic void js_emit_spread_code(JSParseState *s, int depth)\n{\n    int label_rest_next, label_rest_done;\n\n    /* XXX: could check if enum object is an actual array and optimize\n       slice extraction. enumeration record and target array are in a\n       different order from OP_append case. */\n    /* enum_rec xxx -- enum_rec xxx array 0 */\n    emit_op(s, OP_array_from);\n    emit_u16(s, 0);\n    emit_op(s, OP_push_i32);\n    emit_u32(s, 0);\n    emit_label(s, label_rest_next = new_label(s));\n    emit_op(s, OP_for_of_next);\n    emit_u8(s, 2 + depth);\n    label_rest_done = emit_goto(s, OP_if_true, -1);\n    /* array idx val -- array idx */\n    emit_op(s, OP_define_array_el);\n    emit_op(s, OP_inc);\n    emit_goto(s, OP_goto, label_rest_next);\n    emit_label(s, label_rest_done);\n    /* enum_rec xxx array idx undef -- enum_rec xxx array */\n    emit_op(s, OP_drop);\n    emit_op(s, OP_drop);\n}\n\nstatic int js_parse_check_duplicate_parameter(JSParseState *s, JSAtom name)\n{\n    /* Check for duplicate parameter names */\n    JSFunctionDef *fd = s->cur_func;\n    int i;\n    for (i = 0; i < fd->arg_count; i++) {\n        if (fd->args[i].var_name == name)\n            goto duplicate;\n    }\n    for (i = 0; i < fd->var_count; i++) {\n        if (fd->vars[i].var_name == name)\n            goto duplicate;\n    }\n    return 0;\n\nduplicate:\n    return js_parse_error(s, \"duplicate parameter names not allowed in this context\");\n}\n\n/* tok = TOK_VAR, TOK_LET or TOK_CONST. Return whether a reference\n   must be taken to the variable for proper 'with' or global variable\n   evaluation */\n/* Note: this function is needed only because variable references are\n   not yet optimized in destructuring */\nstatic BOOL need_var_reference(JSParseState *s, int tok)\n{\n    JSFunctionDef *fd = s->cur_func;\n    if (tok != TOK_VAR)\n        return FALSE; /* no reference for let/const */\n    if (fd->js_mode & JS_MODE_STRICT) {\n        if (!fd->is_global_var)\n            return FALSE; /* local definitions in strict mode in function or direct eval */\n        if (s->is_module)\n            return FALSE; /* in a module global variables are like closure variables */\n    }\n    return TRUE;\n}\n\nstatic JSAtom js_parse_destructuring_var(JSParseState *s, int tok, int is_arg)\n{\n    JSAtom name;\n\n    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)\n    ||  ((s->cur_func->js_mode & JS_MODE_STRICT) &&\n         (s->token.u.ident.atom == JS_ATOM_eval || s->token.u.ident.atom == JS_ATOM_arguments))) {\n        js_parse_error(s, \"invalid destructuring target\");\n        return JS_ATOM_NULL;\n    }\n    name = JS_DupAtom(s->ctx, s->token.u.ident.atom);\n    if (is_arg && js_parse_check_duplicate_parameter(s, name))\n        goto fail;\n    if (next_token(s))\n        goto fail;\n\n    return name;\nfail:\n    JS_FreeAtom(s->ctx, name);\n    return JS_ATOM_NULL;\n}\n\n/* Return -1 if error, 0 if no initializer, 1 if an initializer is\n   present at the top level. */\nstatic int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,\n                                        int hasval, int has_ellipsis,\n                                        BOOL allow_initializer, BOOL export_flag)\n{\n    int label_parse, label_assign, label_done, label_lvalue, depth_lvalue;\n    int start_addr, assign_addr;\n    JSAtom prop_name, var_name;\n    int opcode, scope, tok1, skip_bits;\n    BOOL has_initializer;\n\n    if (has_ellipsis < 0) {\n        /* pre-parse destructuration target for spread detection */\n        js_parse_skip_parens_token(s, &skip_bits, FALSE);\n        has_ellipsis = skip_bits & SKIP_HAS_ELLIPSIS;\n    }\n\n    label_parse = new_label(s);\n    label_assign = new_label(s);\n\n    start_addr = s->cur_func->byte_code.size;\n    if (hasval) {\n        /* consume value from the stack */\n        emit_op(s, OP_dup);\n        emit_op(s, OP_undefined);\n        emit_op(s, OP_strict_eq);\n        emit_goto(s, OP_if_true, label_parse);\n        emit_label(s, label_assign);\n    } else {\n        emit_goto(s, OP_goto, label_parse);\n        emit_label(s, label_assign);\n        /* leave value on the stack */\n        emit_op(s, OP_dup);\n    }\n    assign_addr = s->cur_func->byte_code.size;\n    if (s->token.val == '{') {\n        if (next_token(s))\n            return -1;\n        /* throw an exception if the value cannot be converted to an object */\n        emit_op(s, OP_to_object);\n        if (has_ellipsis) {\n            /* add excludeList on stack just below src object */\n            emit_op(s, OP_object);\n            emit_op(s, OP_swap);\n        }\n        while (s->token.val != '}') {\n            int prop_type;\n            if (s->token.val == TOK_ELLIPSIS) {\n                if (!has_ellipsis) {\n                    JS_ThrowInternalError(s->ctx, \"unexpected ellipsis token\");\n                    return -1;\n                }\n                if (next_token(s))\n                    return -1;\n                if (tok) {\n                    var_name = js_parse_destructuring_var(s, tok, is_arg);\n                    if (var_name == JS_ATOM_NULL)\n                        return -1;\n                    if (need_var_reference(s, tok)) {\n                        /* Must make a reference for proper `with` semantics */\n                        emit_op(s, OP_scope_get_var);\n                        emit_atom(s, var_name);\n                        emit_u16(s, s->cur_func->scope_level);\n                        JS_FreeAtom(s->ctx, var_name);\n                        goto lvalue0;\n                    } else {\n                        opcode = OP_scope_get_var;\n                        scope = s->cur_func->scope_level;\n                        label_lvalue = -1;\n                        depth_lvalue = 0;\n                    }\n                } else {\n                    if (js_parse_left_hand_side_expr(s))\n                        return -1;\n                lvalue0:\n                    if (get_lvalue(s, &opcode, &scope, &var_name,\n                                   &label_lvalue, &depth_lvalue, FALSE, '{'))\n                        return -1;\n                }\n                if (s->token.val != '}') {\n                    js_parse_error(s, \"assignment rest property must be last\");\n                    goto var_error;\n                }\n                emit_op(s, OP_object);  /* target */\n                emit_op(s, OP_copy_data_properties);\n                emit_u8(s, 0 | ((depth_lvalue + 1) << 2) | ((depth_lvalue + 2) << 5));\n                goto set_val;\n            }\n            prop_type = js_parse_property_name(s, &prop_name, FALSE, TRUE, FALSE);\n            if (prop_type < 0)\n                return -1;\n            var_name = JS_ATOM_NULL;\n            if (prop_type == PROP_TYPE_IDENT) {\n                if (next_token(s))\n                    goto prop_error;\n                if ((s->token.val == '[' || s->token.val == '{')\n                    &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||\n                         tok1 == '=' || tok1 == '}')) {\n                    if (prop_name == JS_ATOM_NULL) {\n                        /* computed property name on stack */\n                        if (has_ellipsis) {\n                            /* define the property in excludeList */\n                            emit_op(s, OP_to_propkey); /* avoid calling ToString twice */\n                            emit_op(s, OP_perm3); /* TOS: src excludeList prop */\n                            emit_op(s, OP_null); /* TOS: src excludeList prop null */\n                            emit_op(s, OP_define_array_el); /* TOS: src excludeList prop */\n                            emit_op(s, OP_perm3); /* TOS: excludeList src prop */\n                        }\n                        /* get the computed property from the source object */\n                        emit_op(s, OP_get_array_el2);\n                    } else {\n                        /* named property */\n                        if (has_ellipsis) {\n                            /* define the property in excludeList */\n                            emit_op(s, OP_swap); /* TOS: src excludeList */\n                            emit_op(s, OP_null); /* TOS: src excludeList null */\n                            emit_op(s, OP_define_field); /* TOS: src excludeList */\n                            emit_atom(s, prop_name);\n                            emit_op(s, OP_swap); /* TOS: excludeList src */\n                        }\n                        /* get the named property from the source object */\n                        emit_op(s, OP_get_field2);\n                        emit_u32(s, prop_name);\n                    }\n                    if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE, export_flag) < 0)\n                        return -1;\n                    if (s->token.val == '}')\n                        break;\n                    /* accept a trailing comma before the '}' */\n                    if (js_parse_expect(s, ','))\n                        return -1;\n                    continue;\n                }\n                if (prop_name == JS_ATOM_NULL) {\n                    emit_op(s, OP_to_propkey);\n                    if (has_ellipsis) {\n                        /* define the property in excludeList */\n                        emit_op(s, OP_perm3);\n                        emit_op(s, OP_null);\n                        emit_op(s, OP_define_array_el);\n                        emit_op(s, OP_perm3);\n                    }\n                    /* source prop -- source source prop */\n                    emit_op(s, OP_dup1);\n                } else {\n                    if (has_ellipsis) {\n                        /* define the property in excludeList */\n                        emit_op(s, OP_swap);\n                        emit_op(s, OP_null);\n                        emit_op(s, OP_define_field);\n                        emit_atom(s, prop_name);\n                        emit_op(s, OP_swap);\n                    }\n                    /* source -- source source */\n                    emit_op(s, OP_dup);\n                }\n                if (tok) {\n                    var_name = js_parse_destructuring_var(s, tok, is_arg);\n                    if (var_name == JS_ATOM_NULL)\n                        goto prop_error;\n                    if (need_var_reference(s, tok)) {\n                        /* Must make a reference for proper `with` semantics */\n                        emit_op(s, OP_scope_get_var);\n                        emit_atom(s, var_name);\n                        emit_u16(s, s->cur_func->scope_level);\n                        JS_FreeAtom(s->ctx, var_name);\n                        goto lvalue1;\n                    } else {\n                        /* no need to make a reference for let/const */\n                        opcode = OP_scope_get_var;\n                        scope = s->cur_func->scope_level;\n                        label_lvalue = -1;\n                        depth_lvalue = 0;\n                    }\n                } else {\n                    if (js_parse_left_hand_side_expr(s))\n                        goto prop_error;\n                lvalue1:\n                    if (get_lvalue(s, &opcode, &scope, &var_name,\n                                   &label_lvalue, &depth_lvalue, FALSE, '{'))\n                        goto prop_error;\n                    /* swap ref and lvalue object if any */\n                    if (prop_name == JS_ATOM_NULL) {\n                        switch(depth_lvalue) {\n                        case 0:\n                            break;\n                        case 1:\n                            /* source prop x -> x source prop */\n                            emit_op(s, OP_rot3r);\n                            break;\n                        case 2:\n                            /* source prop x y -> x y source prop */\n                            emit_op(s, OP_swap2);   /* t p2 s p1 */\n                            break;\n                        case 3:\n                            /* source prop x y z -> x y z source prop */\n                            emit_op(s, OP_rot5l);\n                            emit_op(s, OP_rot5l);\n                            break;\n                        default:\n                            abort();\n                        }\n                    } else {\n                        switch(depth_lvalue) {\n                        case 0:\n                            break;\n                        case 1:\n                            /* source x -> x source */\n                            emit_op(s, OP_swap);\n                            break;\n                        case 2:\n                            /* source x y -> x y source */\n                            emit_op(s, OP_rot3l);\n                            break;\n                        case 3:\n                            /* source x y z -> x y z source */\n                            emit_op(s, OP_rot4l);\n                            break;\n                        default:\n                            abort();\n                        }\n                    }\n                }\n                if (prop_name == JS_ATOM_NULL) {\n                    /* computed property name on stack */\n                    /* XXX: should have OP_get_array_el2x with depth */\n                    /* source prop -- val */\n                    emit_op(s, OP_get_array_el);\n                } else {\n                    /* named property */\n                    /* XXX: should have OP_get_field2x with depth */\n                    /* source -- val */\n                    emit_op(s, OP_get_field);\n                    emit_u32(s, prop_name);\n                }\n            } else {\n                /* prop_type = PROP_TYPE_VAR, cannot be a computed property */\n                if (is_arg && js_parse_check_duplicate_parameter(s, prop_name))\n                    goto prop_error;\n                if ((s->cur_func->js_mode & JS_MODE_STRICT) &&\n                    (prop_name == JS_ATOM_eval || prop_name == JS_ATOM_arguments)) {\n                    js_parse_error(s, \"invalid destructuring target\");\n                    goto prop_error;\n                }\n                if (has_ellipsis) {\n                    /* define the property in excludeList */\n                    emit_op(s, OP_swap);\n                    emit_op(s, OP_null);\n                    emit_op(s, OP_define_field);\n                    emit_atom(s, prop_name);\n                    emit_op(s, OP_swap);\n                }\n                if (!tok || need_var_reference(s, tok)) {\n                    /* generate reference */\n                    /* source -- source source */\n                    emit_op(s, OP_dup);\n                    emit_op(s, OP_scope_get_var);\n                    emit_atom(s, prop_name);\n                    emit_u16(s, s->cur_func->scope_level);\n                    goto lvalue1;\n                } else {\n                    /* no need to make a reference for let/const */\n                    var_name = JS_DupAtom(s->ctx, prop_name);\n                    opcode = OP_scope_get_var;\n                    scope = s->cur_func->scope_level;\n                    label_lvalue = -1;\n                    depth_lvalue = 0;\n                    \n                    /* source -- source val */\n                    emit_op(s, OP_get_field2);\n                    emit_u32(s, prop_name);\n                }\n            }\n        set_val:\n            if (tok) {\n                if (js_define_var(s, var_name, tok))\n                    goto var_error;\n                if (export_flag) {\n                    if (!add_export_entry(s, s->cur_func->module, var_name, var_name,\n                                          JS_EXPORT_TYPE_LOCAL))\n                        goto var_error;\n                }\n                scope = s->cur_func->scope_level; /* XXX: check */\n            }\n            if (s->token.val == '=') {  /* handle optional default value */\n                int label_hasval;\n                emit_op(s, OP_dup);\n                emit_op(s, OP_undefined);\n                emit_op(s, OP_strict_eq);\n                label_hasval = emit_goto(s, OP_if_false, -1);\n                if (next_token(s))\n                    goto var_error;\n                emit_op(s, OP_drop);\n                if (js_parse_assign_expr(s))\n                    goto var_error;\n                if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)\n                    set_object_name(s, var_name);\n                emit_label(s, label_hasval);\n            }\n            /* store value into lvalue object */\n            put_lvalue(s, opcode, scope, var_name, label_lvalue,\n                       PUT_LVALUE_NOKEEP_DEPTH,\n                       (tok == TOK_CONST || tok == TOK_LET));\n            if (s->token.val == '}')\n                break;\n            /* accept a trailing comma before the '}' */\n            if (js_parse_expect(s, ','))\n                return -1;\n        }\n        /* drop the source object */\n        emit_op(s, OP_drop);\n        if (has_ellipsis) {\n            emit_op(s, OP_drop); /* pop excludeList */\n        }\n        if (next_token(s))\n            return -1;\n    } else if (s->token.val == '[') {\n        BOOL has_spread;\n        int enum_depth;\n        BlockEnv block_env;\n\n        if (next_token(s))\n            return -1;\n        /* the block environment is only needed in generators in case\n           'yield' triggers a 'return' */\n        push_break_entry(s->cur_func, &block_env,\n                         JS_ATOM_NULL, -1, -1, 2);\n        block_env.has_iterator = TRUE;\n        emit_op(s, OP_for_of_start);\n        has_spread = FALSE;\n        while (s->token.val != ']') {\n            /* get the next value */\n            if (s->token.val == TOK_ELLIPSIS) {\n                if (next_token(s))\n                    return -1;\n                if (s->token.val == ',' || s->token.val == ']')\n                    return js_parse_error(s, \"missing binding pattern...\");\n                has_spread = TRUE;\n            }\n            if (s->token.val == ',') {\n                /* do nothing, skip the value, has_spread is false */\n                emit_op(s, OP_for_of_next);\n                emit_u8(s, 0);\n                emit_op(s, OP_drop);\n                emit_op(s, OP_drop);\n            } else if ((s->token.val == '[' || s->token.val == '{')\n                   &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == ',' ||\n                        tok1 == '=' || tok1 == ']')) {\n                if (has_spread) {\n                    if (tok1 == '=')\n                        return js_parse_error(s, \"rest element cannot have a default value\");\n                    js_emit_spread_code(s, 0);\n                } else {\n                    emit_op(s, OP_for_of_next);\n                    emit_u8(s, 0);\n                    emit_op(s, OP_drop);\n                }\n                if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0)\n                    return -1;\n            } else {\n                var_name = JS_ATOM_NULL;\n                if (tok) {\n                    var_name = js_parse_destructuring_var(s, tok, is_arg);\n                    if (var_name == JS_ATOM_NULL)\n                        goto var_error;\n                    if (js_define_var(s, var_name, tok))\n                        goto var_error;\n                    if (need_var_reference(s, tok)) {\n                        /* Must make a reference for proper `with` semantics */\n                        emit_op(s, OP_scope_get_var);\n                        emit_atom(s, var_name);\n                        emit_u16(s, s->cur_func->scope_level);\n                        JS_FreeAtom(s->ctx, var_name);\n                        goto lvalue2;\n                    } else {\n                        /* no need to make a reference for let/const */\n                        opcode = OP_scope_get_var;\n                        scope = s->cur_func->scope_level;\n                        label_lvalue = -1;\n                        enum_depth = 0;\n                    }\n                } else {\n                    if (js_parse_left_hand_side_expr(s))\n                        return -1;\n                lvalue2:\n                    if (get_lvalue(s, &opcode, &scope, &var_name,\n                                   &label_lvalue, &enum_depth, FALSE, '[')) {\n                        return -1;\n                    }\n                }\n                if (has_spread) {\n                    js_emit_spread_code(s, enum_depth);\n                } else {\n                    emit_op(s, OP_for_of_next);\n                    emit_u8(s, enum_depth);\n                    emit_op(s, OP_drop);\n                }\n                if (s->token.val == '=' && !has_spread) {\n                    /* handle optional default value */\n                    int label_hasval;\n                    emit_op(s, OP_dup);\n                    emit_op(s, OP_undefined);\n                    emit_op(s, OP_strict_eq);\n                    label_hasval = emit_goto(s, OP_if_false, -1);\n                    if (next_token(s))\n                        goto var_error;\n                    emit_op(s, OP_drop);\n                    if (js_parse_assign_expr(s))\n                        goto var_error;\n                    if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)\n                        set_object_name(s, var_name);\n                    emit_label(s, label_hasval);\n                }\n                /* store value into lvalue object */\n                put_lvalue(s, opcode, scope, var_name,\n                           label_lvalue, PUT_LVALUE_NOKEEP_DEPTH,\n                           (tok == TOK_CONST || tok == TOK_LET));\n            }\n            if (s->token.val == ']')\n                break;\n            if (has_spread)\n                return js_parse_error(s, \"rest element must be the last one\");\n            /* accept a trailing comma before the ']' */\n            if (js_parse_expect(s, ','))\n                return -1;\n        }\n        /* close iterator object:\n           if completed, enum_obj has been replaced by undefined */\n        emit_op(s, OP_iterator_close);\n        pop_break_entry(s->cur_func);\n        if (next_token(s))\n            return -1;\n    } else {\n        return js_parse_error(s, \"invalid assignment syntax\");\n    }\n    if (s->token.val == '=' && allow_initializer) {\n        label_done = emit_goto(s, OP_goto, -1);\n        if (next_token(s))\n            return -1;\n        emit_label(s, label_parse);\n        if (hasval)\n            emit_op(s, OP_drop);\n        if (js_parse_assign_expr(s))\n            return -1;\n        emit_goto(s, OP_goto, label_assign);\n        emit_label(s, label_done);\n        has_initializer = TRUE;\n    } else {\n        /* normally hasval is true except if\n           js_parse_skip_parens_token() was wrong in the parsing */\n        //        assert(hasval);\n        if (!hasval) {\n            js_parse_error(s, \"too complicated destructuring expression\");\n            return -1;\n        }\n        /* remove test and decrement label ref count */\n        memset(s->cur_func->byte_code.buf + start_addr, OP_nop,\n               assign_addr - start_addr);\n        s->cur_func->label_slots[label_parse].ref_count--;\n        has_initializer = FALSE;\n    }\n    return has_initializer;\n\n prop_error:\n    JS_FreeAtom(s->ctx, prop_name);\n var_error:\n    JS_FreeAtom(s->ctx, var_name);\n    return -1;\n}\n\ntypedef enum FuncCallType {\n    FUNC_CALL_NORMAL,\n    FUNC_CALL_NEW,\n    FUNC_CALL_SUPER_CTOR,\n    FUNC_CALL_TEMPLATE,\n} FuncCallType;\n\nstatic void optional_chain_test(JSParseState *s, int *poptional_chaining_label,\n                                int drop_count)\n{\n    int label_next, i;\n    if (*poptional_chaining_label < 0)\n        *poptional_chaining_label = new_label(s);\n   /* XXX: could be more efficient with a specific opcode */\n    emit_op(s, OP_dup);\n    emit_op(s, OP_is_undefined_or_null);\n    label_next = emit_goto(s, OP_if_false, -1);\n    for(i = 0; i < drop_count; i++)\n        emit_op(s, OP_drop);\n    emit_op(s, OP_undefined);\n    emit_goto(s, OP_goto, *poptional_chaining_label);\n    emit_label(s, label_next);\n}\n\n/* allowed parse_flags: PF_POSTFIX_CALL */\nstatic __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)\n{\n    FuncCallType call_type;\n    int optional_chaining_label;\n    BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;\n    const uint8_t *op_token_ptr;\n    \n    call_type = FUNC_CALL_NORMAL;\n    switch(s->token.val) {\n    case TOK_NUMBER:\n        {\n            JSValue val;\n            val = s->token.u.num.val;\n\n            if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {\n                emit_op(s, OP_push_i32);\n                emit_u32(s, JS_VALUE_GET_INT(val));\n            } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SHORT_BIG_INT) {\n                int64_t v;\n                v = JS_VALUE_GET_SHORT_BIG_INT(val);\n                if (v >= INT32_MIN && v <= INT32_MAX) {\n                    emit_op(s, OP_push_bigint_i32);\n                    emit_u32(s, v);\n                } else {\n                    goto large_number;\n                }\n            } else {\n            large_number:\n                if (emit_push_const(s, val, 0) < 0)\n                    return -1;\n            }\n        }\n        if (next_token(s))\n            return -1;\n        break;\n    case TOK_TEMPLATE:\n        if (js_parse_template(s, 0, NULL))\n            return -1;\n        break;\n    case TOK_STRING:\n        if (emit_push_const(s, s->token.u.str.str, 1))\n            return -1;\n        if (next_token(s))\n            return -1;\n        break;\n\n    case TOK_DIV_ASSIGN:\n        s->buf_ptr -= 2;\n        goto parse_regexp;\n    case '/':\n        s->buf_ptr--;\n    parse_regexp:\n        {\n            JSValue str;\n            int ret;\n            if (!s->ctx->compile_regexp)\n                return js_parse_error(s, \"RegExp are not supported\");\n            /* the previous token is '/' or '/=', so no need to free */\n            if (js_parse_regexp(s))\n                return -1;\n            ret = emit_push_const(s, s->token.u.regexp.body, 0);\n            str = s->ctx->compile_regexp(s->ctx, s->token.u.regexp.body,\n                                         s->token.u.regexp.flags);\n            if (JS_IsException(str)) {\n                /* add the line number info */\n                int line_num, col_num;\n                line_num = get_line_col(&col_num, s->buf_start, s->token.ptr - s->buf_start);\n                build_backtrace(s->ctx, s->ctx->rt->current_exception,\n                                s->filename, line_num + 1, col_num + 1, 0);\n                return -1;\n            }\n            ret = emit_push_const(s, str, 0);\n            JS_FreeValue(s->ctx, str);\n            if (ret)\n                return -1;\n            /* we use a specific opcode to be sure the correct\n               function is called (otherwise the bytecode would have\n               to be verified by the RegExp constructor) */\n            emit_op(s, OP_regexp);\n            if (next_token(s))\n                return -1;\n        }\n        break;\n    case '(':\n        if (js_parse_expr_paren(s))\n            return -1;\n        break;\n    case TOK_FUNCTION:\n        if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,\n                                   JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                   s->token.ptr))\n            return -1;\n        break;\n    case TOK_CLASS:\n        if (js_parse_class(s, TRUE, JS_PARSE_EXPORT_NONE))\n            return -1;\n        break;\n    case TOK_NULL:\n        if (next_token(s))\n            return -1;\n        emit_op(s, OP_null);\n        break;\n    case TOK_THIS:\n        if (next_token(s))\n            return -1;\n        emit_op(s, OP_scope_get_var);\n        emit_atom(s, JS_ATOM_this);\n        emit_u16(s, 0);\n        break;\n    case TOK_FALSE:\n        if (next_token(s))\n            return -1;\n        emit_op(s, OP_push_false);\n        break;\n    case TOK_TRUE:\n        if (next_token(s))\n            return -1;\n        emit_op(s, OP_push_true);\n        break;\n    case TOK_IDENT:\n        {\n            JSAtom name;\n            const uint8_t *source_ptr;\n            if (s->token.u.ident.is_reserved) {\n                return js_parse_error_reserved_identifier(s);\n            }\n            source_ptr = s->token.ptr;\n            if (token_is_pseudo_keyword(s, JS_ATOM_async) &&\n                peek_token(s, TRUE) != '\\n') {\n                if (next_token(s))\n                    return -1;\n                if (s->token.val == TOK_FUNCTION) {\n                    if (js_parse_function_decl(s, JS_PARSE_FUNC_EXPR,\n                                               JS_FUNC_ASYNC, JS_ATOM_NULL,\n                                               source_ptr))\n                        return -1;\n                } else {\n                    name = JS_DupAtom(s->ctx, JS_ATOM_async);\n                    goto do_get_var;\n                }\n            } else {\n                if (s->token.u.ident.atom == JS_ATOM_arguments &&\n                    !s->cur_func->arguments_allowed) {\n                    js_parse_error(s, \"'arguments' identifier is not allowed in class field initializer\");\n                    return -1;\n                }\n                name = JS_DupAtom(s->ctx, s->token.u.ident.atom);\n                if (next_token(s)) {\n                    JS_FreeAtom(s->ctx, name);\n                    return -1;\n                }\n            do_get_var:\n                emit_source_pos(s, source_ptr);\n                emit_op(s, OP_scope_get_var);\n                emit_u32(s, name);\n                emit_u16(s, s->cur_func->scope_level);\n            }\n        }\n        break;\n    case '{':\n    case '[':\n        if (s->token.val == '{') {\n            if (js_parse_object_literal(s))\n                return -1;\n        } else {\n            if (js_parse_array_literal(s))\n                return -1;\n        }\n        break;\n    case TOK_NEW:\n        if (next_token(s))\n            return -1;\n        if (s->token.val == '.') {\n            if (next_token(s))\n                return -1;\n            if (!token_is_pseudo_keyword(s, JS_ATOM_target))\n                return js_parse_error(s, \"expecting target\");\n            if (!s->cur_func->new_target_allowed)\n                return js_parse_error(s, \"new.target only allowed within functions\");\n            if (next_token(s))\n                return -1;\n            emit_op(s, OP_scope_get_var);\n            emit_atom(s, JS_ATOM_new_target);\n            emit_u16(s, 0);\n        } else {\n            if (js_parse_postfix_expr(s, 0))\n                return -1;\n            accept_lparen = TRUE;\n            if (s->token.val != '(') {\n                /* new operator on an object */\n                emit_source_pos(s, s->token.ptr);\n                emit_op(s, OP_dup);\n                emit_op(s, OP_call_constructor);\n                emit_u16(s, 0);\n            } else {\n                call_type = FUNC_CALL_NEW;\n            }\n        }\n        break;\n    case TOK_SUPER:\n        if (next_token(s))\n            return -1;\n        if (s->token.val == '(') {\n            if (!s->cur_func->super_call_allowed)\n                return js_parse_error(s, \"super() is only valid in a derived class constructor\");\n            call_type = FUNC_CALL_SUPER_CTOR;\n        } else if (s->token.val == '.' || s->token.val == '[') {\n            if (!s->cur_func->super_allowed)\n                return js_parse_error(s, \"'super' is only valid in a method\");\n            emit_op(s, OP_scope_get_var);\n            emit_atom(s, JS_ATOM_this);\n            emit_u16(s, 0);\n            emit_op(s, OP_scope_get_var);\n            emit_atom(s, JS_ATOM_home_object);\n            emit_u16(s, 0);\n            emit_op(s, OP_get_super);\n        } else {\n            return js_parse_error(s, \"invalid use of 'super'\");\n        }\n        break;\n    case TOK_IMPORT:\n        if (next_token(s))\n            return -1;\n        if (s->token.val == '.') {\n            if (next_token(s))\n                return -1;\n            if (!token_is_pseudo_keyword(s, JS_ATOM_meta))\n                return js_parse_error(s, \"meta expected\");\n            if (!s->is_module)\n                return js_parse_error(s, \"import.meta only valid in module code\");\n            if (next_token(s))\n                return -1;\n            emit_op(s, OP_special_object);\n            emit_u8(s, OP_SPECIAL_OBJECT_IMPORT_META);\n        } else {\n            if (js_parse_expect(s, '('))\n                return -1;\n            if (!accept_lparen)\n                return js_parse_error(s, \"invalid use of 'import()'\");\n            if (js_parse_assign_expr(s))\n                return -1;\n            if (s->token.val == ',') {\n                if (next_token(s))\n                    return -1;\n                if (s->token.val != ')') {\n                    if (js_parse_assign_expr(s))\n                        return -1;\n                    /* accept a trailing comma */\n                    if (s->token.val == ',') {\n                        if (next_token(s))\n                            return -1;\n                    }\n                } else {\n                    emit_op(s, OP_undefined);\n                }\n            } else {\n                emit_op(s, OP_undefined);\n            }\n            if (js_parse_expect(s, ')'))\n                return -1;\n            emit_op(s, OP_import);\n        }\n        break;\n    default:\n        return js_parse_error(s, \"unexpected token in expression: '%.*s'\",\n                              (int)(s->buf_ptr - s->token.ptr), s->token.ptr);\n    }\n\n    optional_chaining_label = -1;\n    for(;;) {\n        JSFunctionDef *fd = s->cur_func;\n        BOOL has_optional_chain = FALSE;\n\n        if (s->token.val == TOK_QUESTION_MARK_DOT) {\n            if ((parse_flags & PF_POSTFIX_CALL) == 0)\n                return js_parse_error(s, \"new keyword cannot be used with an optional chain\");\n            op_token_ptr = s->token.ptr;\n            /* optional chaining */\n            if (next_token(s))\n                return -1;\n            has_optional_chain = TRUE;\n            if (s->token.val == '(' && accept_lparen) {\n                goto parse_func_call;\n            } else if (s->token.val == '[') {\n                goto parse_array_access;\n            } else {\n                goto parse_property;\n            }\n        } else if (s->token.val == TOK_TEMPLATE &&\n                   call_type == FUNC_CALL_NORMAL) {\n            if (optional_chaining_label >= 0) {\n                return js_parse_error(s, \"template literal cannot appear in an optional chain\");\n            }\n            call_type = FUNC_CALL_TEMPLATE;\n            op_token_ptr = s->token.ptr; /* XXX: check if right position */\n            goto parse_func_call2;\n        } else if (s->token.val == '(' && accept_lparen) {\n            int opcode, arg_count, drop_count;\n\n            /* function call */\n        parse_func_call:\n            op_token_ptr = s->token.ptr;\n            if (next_token(s))\n                return -1;\n\n            if (call_type == FUNC_CALL_NORMAL) {\n            parse_func_call2:\n                switch(opcode = get_prev_opcode(fd)) {\n                case OP_get_field:\n                    /* keep the object on the stack */\n                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;\n                    drop_count = 2;\n                    break;\n                case OP_get_field_opt_chain:\n                    {\n                        int opt_chain_label, next_label;\n                        opt_chain_label = get_u32(fd->byte_code.buf +\n                                                  fd->last_opcode_pos + 1 + 4 + 1);\n                        /* keep the object on the stack */\n                        fd->byte_code.buf[fd->last_opcode_pos] = OP_get_field2;\n                        fd->byte_code.size = fd->last_opcode_pos + 1 + 4;\n                        next_label = emit_goto(s, OP_goto, -1);\n                        emit_label(s, opt_chain_label);\n                        /* need an additional undefined value for the\n                           case where the optional field does not\n                           exists */\n                        emit_op(s, OP_undefined);\n                        emit_label(s, next_label);\n                        drop_count = 2;\n                        opcode = OP_get_field;\n                    }\n                    break;\n                case OP_scope_get_private_field:\n                    /* keep the object on the stack */\n                    fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_private_field2;\n                    drop_count = 2;\n                    break;\n                case OP_get_array_el:\n                    /* keep the object on the stack */\n                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;\n                    drop_count = 2;\n                    break;\n                case OP_get_array_el_opt_chain:\n                    {\n                        int opt_chain_label, next_label;\n                        opt_chain_label = get_u32(fd->byte_code.buf +\n                                                  fd->last_opcode_pos + 1 + 1);\n                        /* keep the object on the stack */\n                        fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el2;\n                        fd->byte_code.size = fd->last_opcode_pos + 1;\n                        next_label = emit_goto(s, OP_goto, -1);\n                        emit_label(s, opt_chain_label);\n                        /* need an additional undefined value for the\n                           case where the optional field does not\n                           exists */\n                        emit_op(s, OP_undefined);\n                        emit_label(s, next_label);\n                        drop_count = 2;\n                        opcode = OP_get_array_el;\n                    }\n                    break;\n                case OP_scope_get_var:\n                    {\n                        JSAtom name;\n                        int scope;\n                        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n                        scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);\n                        if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {\n                            /* direct 'eval' */\n                            opcode = OP_eval;\n                        } else {\n                            /* verify if function name resolves to a simple\n                               get_loc/get_arg: a function call inside a `with`\n                               statement can resolve to a method call of the\n                               `with` context object\n                             */\n                            /* XXX: always generate the OP_scope_get_ref\n                               and remove it in variable resolution\n                               pass ? */\n                            if (has_with_scope(fd, scope)) {\n                                opcode = OP_scope_get_ref;\n                                fd->byte_code.buf[fd->last_opcode_pos] = opcode;\n                            }\n                        }\n                        drop_count = 1;\n                    }\n                    break;\n                case OP_get_super_value:\n                    fd->byte_code.buf[fd->last_opcode_pos] = OP_get_array_el;\n                    /* on stack: this func_obj */\n                    opcode = OP_get_array_el;\n                    drop_count = 2;\n                    break;\n                default:\n                    opcode = OP_invalid;\n                    drop_count = 1;\n                    break;\n                }\n                if (has_optional_chain) {\n                    optional_chain_test(s, &optional_chaining_label,\n                                        drop_count);\n                }\n            } else {\n                opcode = OP_invalid;\n            }\n\n            if (call_type == FUNC_CALL_TEMPLATE) {\n                if (js_parse_template(s, 1, &arg_count))\n                    return -1;\n                goto emit_func_call;\n            } else if (call_type == FUNC_CALL_SUPER_CTOR) {\n                emit_op(s, OP_scope_get_var);\n                emit_atom(s, JS_ATOM_this_active_func);\n                emit_u16(s, 0);\n\n                emit_op(s, OP_get_super);\n\n                emit_op(s, OP_scope_get_var);\n                emit_atom(s, JS_ATOM_new_target);\n                emit_u16(s, 0);\n            } else if (call_type == FUNC_CALL_NEW) {\n                emit_op(s, OP_dup); /* new.target = function */\n            }\n\n            /* parse arguments */\n            arg_count = 0;\n            while (s->token.val != ')') {\n                if (arg_count >= 65535) {\n                    return js_parse_error(s, \"Too many call arguments\");\n                }\n                if (s->token.val == TOK_ELLIPSIS)\n                    break;\n                if (js_parse_assign_expr(s))\n                    return -1;\n                arg_count++;\n                if (s->token.val == ')')\n                    break;\n                /* accept a trailing comma before the ')' */\n                if (js_parse_expect(s, ','))\n                    return -1;\n            }\n            if (s->token.val == TOK_ELLIPSIS) {\n                emit_op(s, OP_array_from);\n                emit_u16(s, arg_count);\n                emit_op(s, OP_push_i32);\n                emit_u32(s, arg_count);\n\n                /* on stack: array idx */\n                while (s->token.val != ')') {\n                    if (s->token.val == TOK_ELLIPSIS) {\n                        if (next_token(s))\n                            return -1;\n                        if (js_parse_assign_expr(s))\n                            return -1;\n#if 1\n                        /* XXX: could pass is_last indicator? */\n                        emit_op(s, OP_append);\n#else\n                        int label_next, label_done;\n                        label_next = new_label(s);\n                        label_done = new_label(s);\n                        /* push enumerate object below array/idx pair */\n                        emit_op(s, OP_for_of_start);\n                        emit_op(s, OP_rot5l);\n                        emit_op(s, OP_rot5l);\n                        emit_label(s, label_next);\n                        /* on stack: enum_rec array idx */\n                        emit_op(s, OP_for_of_next);\n                        emit_u8(s, 2);\n                        emit_goto(s, OP_if_true, label_done);\n                        /* append element */\n                        /* enum_rec array idx val -> enum_rec array new_idx */\n                        emit_op(s, OP_define_array_el);\n                        emit_op(s, OP_inc);\n                        emit_goto(s, OP_goto, label_next);\n                        emit_label(s, label_done);\n                        /* close enumeration, drop enum_rec and idx */\n                        emit_op(s, OP_drop); /* drop undef */\n                        emit_op(s, OP_nip1); /* drop enum_rec */\n                        emit_op(s, OP_nip1);\n                        emit_op(s, OP_nip1);\n#endif\n                    } else {\n                        if (js_parse_assign_expr(s))\n                            return -1;\n                        /* array idx val */\n                        emit_op(s, OP_define_array_el);\n                        emit_op(s, OP_inc);\n                    }\n                    if (s->token.val == ')')\n                        break;\n                    /* accept a trailing comma before the ')' */\n                    if (js_parse_expect(s, ','))\n                        return -1;\n                }\n                if (next_token(s))\n                    return -1;\n                /* drop the index */\n                emit_op(s, OP_drop);\n\n                emit_source_pos(s, op_token_ptr);\n                /* apply function call */\n                switch(opcode) {\n                case OP_get_field:\n                case OP_scope_get_private_field:\n                case OP_get_array_el:\n                case OP_scope_get_ref:\n                    /* obj func array -> func obj array */\n                    emit_op(s, OP_perm3);\n                    emit_op(s, OP_apply);\n                    emit_u16(s, call_type == FUNC_CALL_NEW);\n                    break;\n                case OP_eval:\n                    emit_op(s, OP_apply_eval);\n                    emit_u16(s, fd->scope_level);\n                    fd->has_eval_call = TRUE;\n                    break;\n                default:\n                    if (call_type == FUNC_CALL_SUPER_CTOR) {\n                        emit_op(s, OP_apply);\n                        emit_u16(s, 1);\n                        /* set the 'this' value */\n                        emit_op(s, OP_dup);\n                        emit_op(s, OP_scope_put_var_init);\n                        emit_atom(s, JS_ATOM_this);\n                        emit_u16(s, 0);\n\n                        emit_class_field_init(s);\n                    } else if (call_type == FUNC_CALL_NEW) {\n                        /* obj func array -> func obj array */\n                        emit_op(s, OP_perm3);\n                        emit_op(s, OP_apply);\n                        emit_u16(s, 1);\n                    } else {\n                        /* func array -> func undef array */\n                        emit_op(s, OP_undefined);\n                        emit_op(s, OP_swap);\n                        emit_op(s, OP_apply);\n                        emit_u16(s, 0);\n                    }\n                    break;\n                }\n            } else {\n                if (next_token(s))\n                    return -1;\n            emit_func_call:\n                emit_source_pos(s, op_token_ptr);\n                switch(opcode) {\n                case OP_get_field:\n                case OP_scope_get_private_field:\n                case OP_get_array_el:\n                case OP_scope_get_ref:\n                    emit_op(s, OP_call_method);\n                    emit_u16(s, arg_count);\n                    break;\n                case OP_eval:\n                    emit_op(s, OP_eval);\n                    emit_u16(s, arg_count);\n                    emit_u16(s, fd->scope_level);\n                    fd->has_eval_call = TRUE;\n                    break;\n                default:\n                    if (call_type == FUNC_CALL_SUPER_CTOR) {\n                        emit_op(s, OP_call_constructor);\n                        emit_u16(s, arg_count);\n\n                        /* set the 'this' value */\n                        emit_op(s, OP_dup);\n                        emit_op(s, OP_scope_put_var_init);\n                        emit_atom(s, JS_ATOM_this);\n                        emit_u16(s, 0);\n\n                        emit_class_field_init(s);\n                    } else if (call_type == FUNC_CALL_NEW) {\n                        emit_op(s, OP_call_constructor);\n                        emit_u16(s, arg_count);\n                    } else {\n                        emit_op(s, OP_call);\n                        emit_u16(s, arg_count);\n                    }\n                    break;\n                }\n            }\n            call_type = FUNC_CALL_NORMAL;\n        } else if (s->token.val == '.') {\n            op_token_ptr = s->token.ptr;\n            if (next_token(s))\n                return -1;\n        parse_property:\n            emit_source_pos(s, op_token_ptr);\n            if (s->token.val == TOK_PRIVATE_NAME) {\n                /* private class field */\n                if (get_prev_opcode(fd) == OP_get_super) {\n                    return js_parse_error(s, \"private class field forbidden after super\");\n                }\n                if (has_optional_chain) {\n                    optional_chain_test(s, &optional_chaining_label, 1);\n                }\n                emit_op(s, OP_scope_get_private_field);\n                emit_atom(s, s->token.u.ident.atom);\n                emit_u16(s, s->cur_func->scope_level);\n            } else {\n                if (!token_is_ident(s->token.val)) {\n                    return js_parse_error(s, \"expecting field name\");\n                }\n                if (get_prev_opcode(fd) == OP_get_super) {\n                    JSValue val;\n                    int ret;\n                    val = JS_AtomToValue(s->ctx, s->token.u.ident.atom);\n                    ret = emit_push_const(s, val, 1);\n                    JS_FreeValue(s->ctx, val);\n                    if (ret)\n                        return -1;\n                    emit_op(s, OP_get_super_value);\n                } else {\n                    if (has_optional_chain) {\n                        optional_chain_test(s, &optional_chaining_label, 1);\n                    }\n                    emit_op(s, OP_get_field);\n                    emit_atom(s, s->token.u.ident.atom);\n                }\n            }\n            if (next_token(s))\n                return -1;\n        } else if (s->token.val == '[') {\n            int prev_op;\n            op_token_ptr = s->token.ptr;\n        parse_array_access:\n            prev_op = get_prev_opcode(fd);\n            if (has_optional_chain) {\n                optional_chain_test(s, &optional_chaining_label, 1);\n            }\n            if (next_token(s))\n                return -1;\n            if (js_parse_expr(s))\n                return -1;\n            if (js_parse_expect(s, ']'))\n                return -1;\n            emit_source_pos(s, op_token_ptr);\n            if (prev_op == OP_get_super) {\n                emit_op(s, OP_get_super_value);\n            } else {\n                emit_op(s, OP_get_array_el);\n            }\n        } else {\n            break;\n        }\n    }\n    if (optional_chaining_label >= 0) {\n        JSFunctionDef *fd = s->cur_func;\n        int opcode;\n        emit_label_raw(s, optional_chaining_label);\n        /* modify the last opcode so that it is an indicator of an\n           optional chain */\n        opcode = get_prev_opcode(fd);\n        if (opcode == OP_get_field || opcode == OP_get_array_el) {\n            if (opcode == OP_get_field)\n                opcode = OP_get_field_opt_chain;\n            else\n                opcode = OP_get_array_el_opt_chain;\n            fd->byte_code.buf[fd->last_opcode_pos] = opcode;\n        } else {\n            fd->last_opcode_pos = -1;\n        }\n    }\n    return 0;\n}\n\nstatic __exception int js_parse_delete(JSParseState *s)\n{\n    JSFunctionDef *fd = s->cur_func;\n    JSAtom name;\n    int opcode;\n\n    if (next_token(s))\n        return -1;\n    if (js_parse_unary(s, PF_POW_FORBIDDEN))\n        return -1;\n    switch(opcode = get_prev_opcode(fd)) {\n    case OP_get_field:\n    case OP_get_field_opt_chain:\n        {\n            JSValue val;\n            int ret, opt_chain_label, next_label;\n            if (opcode == OP_get_field_opt_chain) {\n                opt_chain_label = get_u32(fd->byte_code.buf +\n                                          fd->last_opcode_pos + 1 + 4 + 1);\n            } else {\n                opt_chain_label = -1;\n            }\n            name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n            fd->byte_code.size = fd->last_opcode_pos;\n            val = JS_AtomToValue(s->ctx, name);\n            ret = emit_push_const(s, val, 1);\n            JS_FreeValue(s->ctx, val);\n            JS_FreeAtom(s->ctx, name);\n            if (ret)\n                return ret;\n            emit_op(s, OP_delete);\n            if (opt_chain_label >= 0) {\n                next_label = emit_goto(s, OP_goto, -1);\n                emit_label(s, opt_chain_label);\n                /* if the optional chain is not taken, return 'true' */\n                emit_op(s, OP_drop);\n                emit_op(s, OP_push_true);\n                emit_label(s, next_label);\n            }\n            fd->last_opcode_pos = -1;\n        }\n        break;\n    case OP_get_array_el:\n        fd->byte_code.size = fd->last_opcode_pos;\n        fd->last_opcode_pos = -1;\n        emit_op(s, OP_delete);\n        break;\n    case OP_get_array_el_opt_chain:\n        {\n            int opt_chain_label, next_label;\n            opt_chain_label = get_u32(fd->byte_code.buf +\n                                      fd->last_opcode_pos + 1 + 1);\n            fd->byte_code.size = fd->last_opcode_pos;\n            emit_op(s, OP_delete);\n            next_label = emit_goto(s, OP_goto, -1);\n            emit_label(s, opt_chain_label);\n            /* if the optional chain is not taken, return 'true' */\n            emit_op(s, OP_drop);\n            emit_op(s, OP_push_true);\n            emit_label(s, next_label);\n            fd->last_opcode_pos = -1;\n        }\n        break;\n    case OP_scope_get_var:\n        /* 'delete this': this is not a reference */\n        name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);\n        if (name == JS_ATOM_this || name == JS_ATOM_new_target)\n            goto ret_true;\n        if (fd->js_mode & JS_MODE_STRICT) {\n            return js_parse_error(s, \"cannot delete a direct reference in strict mode\");\n        } else {\n            fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_delete_var;\n        }\n        break;\n    case OP_scope_get_private_field:\n        return js_parse_error(s, \"cannot delete a private class field\");\n    case OP_get_super_value:\n        fd->byte_code.size = fd->last_opcode_pos;\n        fd->last_opcode_pos = -1;\n        emit_op(s, OP_throw_error);\n        emit_atom(s, JS_ATOM_NULL);\n        emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);\n        break;\n    default:\n    ret_true:\n        emit_op(s, OP_drop);\n        emit_op(s, OP_push_true);\n        break;\n    }\n    return 0;\n}\n\n/* allowed parse_flags: PF_POW_ALLOWED, PF_POW_FORBIDDEN */\nstatic __exception int js_parse_unary(JSParseState *s, int parse_flags)\n{\n    int op;\n    const uint8_t *op_token_ptr;\n\n    switch(s->token.val) {\n    case '+':\n    case '-':\n    case '!':\n    case '~':\n    case TOK_VOID:\n        op_token_ptr = s->token.ptr;\n        op = s->token.val;\n        if (next_token(s))\n            return -1;\n        if (js_parse_unary(s, PF_POW_FORBIDDEN))\n            return -1;\n        switch(op) {\n        case '-':\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, OP_neg);\n            break;\n        case '+':\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, OP_plus);\n            break;\n        case '!':\n            emit_op(s, OP_lnot);\n            break;\n        case '~':\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, OP_not);\n            break;\n        case TOK_VOID:\n            emit_op(s, OP_drop);\n            emit_op(s, OP_undefined);\n            break;\n        default:\n            abort();\n        }\n        parse_flags = 0;\n        break;\n    case TOK_DEC:\n    case TOK_INC:\n        {\n            int opcode, op, scope, label;\n            JSAtom name;\n            op = s->token.val;\n            op_token_ptr = s->token.ptr;\n            if (next_token(s))\n                return -1;\n            if (js_parse_unary(s, 0))\n                return -1;\n            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))\n                return -1;\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, OP_dec + op - TOK_DEC);\n            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP,\n                       FALSE);\n        }\n        break;\n    case TOK_TYPEOF:\n        {\n            JSFunctionDef *fd;\n            if (next_token(s))\n                return -1;\n            if (js_parse_unary(s, PF_POW_FORBIDDEN))\n                return -1;\n            /* reference access should not return an exception, so we\n               patch the get_var */\n            fd = s->cur_func;\n            if (get_prev_opcode(fd) == OP_scope_get_var) {\n                fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;\n            }\n            emit_op(s, OP_typeof);\n            parse_flags = 0;\n        }\n        break;\n    case TOK_DELETE:\n        if (js_parse_delete(s))\n            return -1;\n        parse_flags = 0;\n        break;\n    case TOK_AWAIT:\n        if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))\n            return js_parse_error(s, \"unexpected 'await' keyword\");\n        if (!s->cur_func->in_function_body)\n            return js_parse_error(s, \"await in default expression\");\n        if (next_token(s))\n            return -1;\n        if (js_parse_unary(s, PF_POW_FORBIDDEN))\n            return -1;\n        s->cur_func->has_await = TRUE;\n        emit_op(s, OP_await);\n        parse_flags = 0;\n        break;\n    default:\n        if (js_parse_postfix_expr(s, PF_POSTFIX_CALL))\n            return -1;\n        if (!s->got_lf &&\n            (s->token.val == TOK_DEC || s->token.val == TOK_INC)) {\n            int opcode, op, scope, label;\n            JSAtom name;\n            op = s->token.val;\n            op_token_ptr = s->token.ptr;\n            if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))\n                return -1;\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, OP_post_dec + op - TOK_DEC);\n            put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND,\n                       FALSE);\n            if (next_token(s))\n                return -1;\n        }\n        break;\n    }\n    if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {\n        if (s->token.val == TOK_POW) {\n            /* Strict ES7 exponentiation syntax rules: To solve\n               conficting semantics between different implementations\n               regarding the precedence of prefix operators and the\n               postifx exponential, ES7 specifies that -2**2 is a\n               syntax error. */\n            if (parse_flags & PF_POW_FORBIDDEN) {\n                JS_ThrowSyntaxError(s->ctx, \"unparenthesized unary expression can't appear on the left-hand side of '**'\");\n                return -1;\n            }\n            op_token_ptr = s->token.ptr;\n            if (next_token(s))\n                return -1;\n            if (js_parse_unary(s, PF_POW_ALLOWED))\n                return -1;\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, OP_pow);\n        }\n    }\n    return 0;\n}\n\n/* allowed parse_flags: PF_IN_ACCEPTED */\nstatic __exception int js_parse_expr_binary(JSParseState *s, int level,\n                                            int parse_flags)\n{\n    int op, opcode;\n    const uint8_t *op_token_ptr;\n    \n    if (level == 0) {\n        return js_parse_unary(s, PF_POW_ALLOWED);\n    } else if (s->token.val == TOK_PRIVATE_NAME &&\n               (parse_flags & PF_IN_ACCEPTED) && level == 4 &&\n               peek_token(s, FALSE) == TOK_IN) {\n        JSAtom atom;\n\n        atom = JS_DupAtom(s->ctx, s->token.u.ident.atom);\n        if (next_token(s))\n            goto fail_private_in;\n        if (s->token.val != TOK_IN)\n            goto fail_private_in;\n        if (next_token(s))\n            goto fail_private_in;\n        if (js_parse_expr_binary(s, level - 1, parse_flags)) {\n        fail_private_in:\n            JS_FreeAtom(s->ctx, atom);\n            return -1;\n        }\n        emit_op(s, OP_scope_in_private_field);\n        emit_atom(s, atom);\n        emit_u16(s, s->cur_func->scope_level);\n        JS_FreeAtom(s->ctx, atom);\n        return 0;\n    } else {\n        if (js_parse_expr_binary(s, level - 1, parse_flags))\n            return -1;\n    }\n    for(;;) {\n        op = s->token.val;\n        op_token_ptr = s->token.ptr;\n        switch(level) {\n        case 1:\n            switch(op) {\n            case '*':\n                opcode = OP_mul;\n                break;\n            case '/':\n                opcode = OP_div;\n                break;\n            case '%':\n                opcode = OP_mod;\n                break;\n            default:\n                return 0;\n            }\n            break;\n        case 2:\n            switch(op) {\n            case '+':\n                opcode = OP_add;\n                break;\n            case '-':\n                opcode = OP_sub;\n                break;\n            default:\n                return 0;\n            }\n            break;\n        case 3:\n            switch(op) {\n            case TOK_SHL:\n                opcode = OP_shl;\n                break;\n            case TOK_SAR:\n                opcode = OP_sar;\n                break;\n            case TOK_SHR:\n                opcode = OP_shr;\n                break;\n            default:\n                return 0;\n            }\n            break;\n        case 4:\n            switch(op) {\n            case '<':\n                opcode = OP_lt;\n                break;\n            case '>':\n                opcode = OP_gt;\n                break;\n            case TOK_LTE:\n                opcode = OP_lte;\n                break;\n            case TOK_GTE:\n                opcode = OP_gte;\n                break;\n            case TOK_INSTANCEOF:\n                opcode = OP_instanceof;\n                break;\n            case TOK_IN:\n                if (parse_flags & PF_IN_ACCEPTED) {\n                    opcode = OP_in;\n                } else {\n                    return 0;\n                }\n                break;\n            default:\n                return 0;\n            }\n            break;\n        case 5:\n            switch(op) {\n            case TOK_EQ:\n                opcode = OP_eq;\n                break;\n            case TOK_NEQ:\n                opcode = OP_neq;\n                break;\n            case TOK_STRICT_EQ:\n                opcode = OP_strict_eq;\n                break;\n            case TOK_STRICT_NEQ:\n                opcode = OP_strict_neq;\n                break;\n            default:\n                return 0;\n            }\n            break;\n        case 6:\n            switch(op) {\n            case '&':\n                opcode = OP_and;\n                break;\n            default:\n                return 0;\n            }\n            break;\n        case 7:\n            switch(op) {\n            case '^':\n                opcode = OP_xor;\n                break;\n            default:\n                return 0;\n            }\n            break;\n        case 8:\n            switch(op) {\n            case '|':\n                opcode = OP_or;\n                break;\n            default:\n                return 0;\n            }\n            break;\n        default:\n            abort();\n        }\n        if (next_token(s))\n            return -1;\n        if (js_parse_expr_binary(s, level - 1, parse_flags))\n            return -1;\n        emit_source_pos(s, op_token_ptr);\n        emit_op(s, opcode);\n    }\n    return 0;\n}\n\n/* allowed parse_flags: PF_IN_ACCEPTED */\nstatic __exception int js_parse_logical_and_or(JSParseState *s, int op,\n                                               int parse_flags)\n{\n    int label1;\n\n    if (op == TOK_LAND) {\n        if (js_parse_expr_binary(s, 8, parse_flags))\n            return -1;\n    } else {\n        if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))\n            return -1;\n    }\n    if (s->token.val == op) {\n        label1 = new_label(s);\n\n        for(;;) {\n            if (next_token(s))\n                return -1;\n            emit_op(s, OP_dup);\n            emit_goto(s, op == TOK_LAND ? OP_if_false : OP_if_true, label1);\n            emit_op(s, OP_drop);\n\n            if (op == TOK_LAND) {\n                if (js_parse_expr_binary(s, 8, parse_flags))\n                    return -1;\n            } else {\n                if (js_parse_logical_and_or(s, TOK_LAND,\n                                            parse_flags))\n                    return -1;\n            }\n            if (s->token.val != op) {\n                if (s->token.val == TOK_DOUBLE_QUESTION_MARK)\n                    return js_parse_error(s, \"cannot mix ?? with && or ||\");\n                break;\n            }\n        }\n\n        emit_label(s, label1);\n    }\n    return 0;\n}\n\nstatic __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)\n{\n    int label1;\n\n    if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))\n        return -1;\n    if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {\n        label1 = new_label(s);\n        for(;;) {\n            if (next_token(s))\n                return -1;\n\n            emit_op(s, OP_dup);\n            emit_op(s, OP_is_undefined_or_null);\n            emit_goto(s, OP_if_false, label1);\n            emit_op(s, OP_drop);\n\n            if (js_parse_expr_binary(s, 8, parse_flags))\n                return -1;\n            if (s->token.val != TOK_DOUBLE_QUESTION_MARK)\n                break;\n        }\n        emit_label(s, label1);\n    }\n    return 0;\n}\n\n/* allowed parse_flags: PF_IN_ACCEPTED */\nstatic __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)\n{\n    int label1, label2;\n\n    if (js_parse_coalesce_expr(s, parse_flags))\n        return -1;\n    if (s->token.val == '?') {\n        if (next_token(s))\n            return -1;\n        label1 = emit_goto(s, OP_if_false, -1);\n\n        if (js_parse_assign_expr(s))\n            return -1;\n        if (js_parse_expect(s, ':'))\n            return -1;\n\n        label2 = emit_goto(s, OP_goto, -1);\n\n        emit_label(s, label1);\n\n        if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))\n            return -1;\n\n        emit_label(s, label2);\n    }\n    return 0;\n}\n\n/* allowed parse_flags: PF_IN_ACCEPTED */\nstatic __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)\n{\n    int opcode, op, scope, skip_bits;\n    JSAtom name0 = JS_ATOM_NULL;\n    JSAtom name;\n\n    if (s->token.val == TOK_YIELD) {\n        BOOL is_star = FALSE, is_async;\n\n        if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))\n            return js_parse_error(s, \"unexpected 'yield' keyword\");\n        if (!s->cur_func->in_function_body)\n            return js_parse_error(s, \"yield in default expression\");\n        if (next_token(s))\n            return -1;\n        /* XXX: is there a better method to detect 'yield' without\n           parameters ? */\n        if (s->token.val != ';' && s->token.val != ')' &&\n            s->token.val != ']' && s->token.val != '}' &&\n            s->token.val != ',' && s->token.val != ':' && !s->got_lf) {\n            if (s->token.val == '*') {\n                is_star = TRUE;\n                if (next_token(s))\n                    return -1;\n            }\n            if (js_parse_assign_expr2(s, parse_flags))\n                return -1;\n        } else {\n            emit_op(s, OP_undefined);\n        }\n        is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);\n\n        if (is_star) {\n            int label_loop, label_return, label_next;\n            int label_return1, label_yield, label_throw, label_throw1;\n            int label_throw2;\n\n            label_loop = new_label(s);\n            label_yield = new_label(s);\n\n            emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);\n\n            /* remove the catch offset (XXX: could avoid pushing back\n               undefined) */\n            emit_op(s, OP_drop);\n            emit_op(s, OP_undefined);\n\n            emit_op(s, OP_undefined); /* initial value */\n\n            emit_label(s, label_loop);\n            emit_op(s, OP_iterator_next);\n            if (is_async)\n                emit_op(s, OP_await);\n            emit_op(s, OP_iterator_check_object);\n            emit_op(s, OP_get_field2);\n            emit_atom(s, JS_ATOM_done);\n            label_next = emit_goto(s, OP_if_true, -1); /* end of loop */\n            emit_label(s, label_yield);\n            if (is_async) {\n                /* OP_async_yield_star takes the value as parameter */\n                emit_op(s, OP_get_field);\n                emit_atom(s, JS_ATOM_value);\n                emit_op(s, OP_async_yield_star);\n            } else {\n                /* OP_yield_star takes (value, done) as parameter */\n                emit_op(s, OP_yield_star);\n            }\n            emit_op(s, OP_dup);\n            label_return = emit_goto(s, OP_if_true, -1);\n            emit_op(s, OP_drop);\n            emit_goto(s, OP_goto, label_loop);\n\n            emit_label(s, label_return);\n            emit_op(s, OP_push_i32);\n            emit_u32(s, 2);\n            emit_op(s, OP_strict_eq);\n            label_throw = emit_goto(s, OP_if_true, -1);\n\n            /* return handling */\n            if (is_async)\n                emit_op(s, OP_await);\n            emit_op(s, OP_iterator_call);\n            emit_u8(s, 0);\n            label_return1 = emit_goto(s, OP_if_true, -1);\n            if (is_async)\n                emit_op(s, OP_await);\n            emit_op(s, OP_iterator_check_object);\n            emit_op(s, OP_get_field2);\n            emit_atom(s, JS_ATOM_done);\n            emit_goto(s, OP_if_false, label_yield);\n\n            emit_op(s, OP_get_field);\n            emit_atom(s, JS_ATOM_value);\n\n            emit_label(s, label_return1);\n            emit_op(s, OP_nip);\n            emit_op(s, OP_nip);\n            emit_op(s, OP_nip);\n            emit_return(s, TRUE);\n\n            /* throw handling */\n            emit_label(s, label_throw);\n            emit_op(s, OP_iterator_call);\n            emit_u8(s, 1);\n            label_throw1 = emit_goto(s, OP_if_true, -1);\n            if (is_async)\n                emit_op(s, OP_await);\n            emit_op(s, OP_iterator_check_object);\n            emit_op(s, OP_get_field2);\n            emit_atom(s, JS_ATOM_done);\n            emit_goto(s, OP_if_false, label_yield);\n            emit_goto(s, OP_goto, label_next);\n            /* close the iterator and throw a type error exception */\n            emit_label(s, label_throw1);\n            emit_op(s, OP_iterator_call);\n            emit_u8(s, 2);\n            label_throw2 = emit_goto(s, OP_if_true, -1);\n            if (is_async)\n                emit_op(s, OP_await);\n            emit_label(s, label_throw2);\n\n            emit_op(s, OP_throw_error);\n            emit_atom(s, JS_ATOM_NULL);\n            emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);\n\n            emit_label(s, label_next);\n            emit_op(s, OP_get_field);\n            emit_atom(s, JS_ATOM_value);\n            emit_op(s, OP_nip); /* keep the value associated with\n                                   done = true */\n            emit_op(s, OP_nip);\n            emit_op(s, OP_nip);\n        } else {\n            int label_next;\n\n            if (is_async)\n                emit_op(s, OP_await);\n            emit_op(s, OP_yield);\n            label_next = emit_goto(s, OP_if_false, -1);\n            emit_return(s, TRUE);\n            emit_label(s, label_next);\n        }\n        return 0;\n    } else if (s->token.val == '(' &&\n               js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {\n        return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,\n                                      JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                      s->token.ptr);\n    } else if (token_is_pseudo_keyword(s, JS_ATOM_async)) {\n        const uint8_t *source_ptr;\n        int tok;\n        JSParsePos pos;\n\n        /* fast test */\n        tok = peek_token(s, TRUE);\n        if (tok == TOK_FUNCTION || tok == '\\n')\n            goto next;\n\n        source_ptr = s->token.ptr;\n        js_parse_get_pos(s, &pos);\n        if (next_token(s))\n            return -1;\n        if ((s->token.val == '(' &&\n             js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||\n            (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&\n             peek_token(s, TRUE) == TOK_ARROW)) {\n            return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,\n                                          JS_FUNC_ASYNC, JS_ATOM_NULL,\n                                          source_ptr);\n        } else {\n            /* undo the token parsing */\n            if (js_parse_seek_token(s, &pos))\n                return -1;\n        }\n    } else if (s->token.val == TOK_IDENT &&\n               peek_token(s, TRUE) == TOK_ARROW) {\n        return js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,\n                                      JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                      s->token.ptr);\n    } else if ((s->token.val == '{' || s->token.val == '[') &&\n               js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {\n        if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)\n            return -1;\n        return 0;\n    }\n next:\n    if (s->token.val == TOK_IDENT) {\n        /* name0 is used to check for OP_set_name pattern, not duplicated */\n        name0 = s->token.u.ident.atom;\n    }\n    if (js_parse_cond_expr(s, parse_flags))\n        return -1;\n\n    op = s->token.val;\n    if (op == '=' || (op >= TOK_MUL_ASSIGN && op <= TOK_POW_ASSIGN)) {\n        int label;\n        const uint8_t *op_token_ptr;\n        op_token_ptr = s->token.ptr;\n        if (next_token(s))\n            return -1;\n        if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)\n            return -1;\n\n        if (js_parse_assign_expr2(s, parse_flags)) {\n            JS_FreeAtom(s->ctx, name);\n            return -1;\n        }\n\n        if (op == '=') {\n            if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {\n                set_object_name(s, name);\n            }\n        } else {\n            static const uint8_t assign_opcodes[] = {\n                OP_mul, OP_div, OP_mod, OP_add, OP_sub,\n                OP_shl, OP_sar, OP_shr, OP_and, OP_xor, OP_or,\n                OP_pow,\n            };\n            op = assign_opcodes[op - TOK_MUL_ASSIGN];\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, op);\n        }\n        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE);\n    } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) {\n        int label, label1, depth_lvalue, label2;\n\n        if (next_token(s))\n            return -1;\n        if (get_lvalue(s, &opcode, &scope, &name, &label,\n                       &depth_lvalue, TRUE, op) < 0)\n            return -1;\n\n        emit_op(s, OP_dup);\n        if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN)\n            emit_op(s, OP_is_undefined_or_null);\n        label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false,\n                           -1);\n        emit_op(s, OP_drop);\n\n        if (js_parse_assign_expr2(s, parse_flags)) {\n            JS_FreeAtom(s->ctx, name);\n            return -1;\n        }\n\n        if ((opcode == OP_get_ref_value || opcode == OP_scope_get_var) && name == name0) {\n            set_object_name(s, name);\n        }\n\n        switch(depth_lvalue) {\n        case 0:\n            emit_op(s, OP_dup);\n            break;\n        case 1:\n            emit_op(s, OP_insert2);\n            break;\n        case 2:\n            emit_op(s, OP_insert3);\n            break;\n        case 3:\n            emit_op(s, OP_insert4);\n            break;\n        default:\n            abort();\n        }\n\n        /* XXX: we disable the OP_put_ref_value optimization by not\n           using put_lvalue() otherwise depth_lvalue is not correct */\n        put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH,\n                   FALSE);\n        label2 = emit_goto(s, OP_goto, -1);\n\n        emit_label(s, label1);\n\n        /* remove the lvalue stack entries */\n        while (depth_lvalue != 0) {\n            emit_op(s, OP_nip);\n            depth_lvalue--;\n        }\n\n        emit_label(s, label2);\n    }\n    return 0;\n}\n\nstatic __exception int js_parse_assign_expr(JSParseState *s)\n{\n    return js_parse_assign_expr2(s, PF_IN_ACCEPTED);\n}\n\n/* allowed parse_flags: PF_IN_ACCEPTED */\nstatic __exception int js_parse_expr2(JSParseState *s, int parse_flags)\n{\n    BOOL comma = FALSE;\n    for(;;) {\n        if (js_parse_assign_expr2(s, parse_flags))\n            return -1;\n        if (comma) {\n            /* prevent get_lvalue from using the last expression\n               as an lvalue. This also prevents the conversion of\n               of get_var to get_ref for method lookup in function\n               call inside `with` statement.\n             */\n            s->cur_func->last_opcode_pos = -1;\n        }\n        if (s->token.val != ',')\n            break;\n        comma = TRUE;\n        if (next_token(s))\n            return -1;\n        emit_op(s, OP_drop);\n    }\n    return 0;\n}\n\nstatic __exception int js_parse_expr(JSParseState *s)\n{\n    return js_parse_expr2(s, PF_IN_ACCEPTED);\n}\n\nstatic void push_break_entry(JSFunctionDef *fd, BlockEnv *be,\n                             JSAtom label_name,\n                             int label_break, int label_cont,\n                             int drop_count)\n{\n    be->prev = fd->top_break;\n    fd->top_break = be;\n    be->label_name = label_name;\n    be->label_break = label_break;\n    be->label_cont = label_cont;\n    be->drop_count = drop_count;\n    be->label_finally = -1;\n    be->scope_level = fd->scope_level;\n    be->has_iterator = FALSE;\n    be->is_regular_stmt = FALSE;\n}\n\nstatic void pop_break_entry(JSFunctionDef *fd)\n{\n    BlockEnv *be;\n    be = fd->top_break;\n    fd->top_break = be->prev;\n}\n\nstatic __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)\n{\n    BlockEnv *top;\n    int i, scope_level;\n\n    scope_level = s->cur_func->scope_level;\n    top = s->cur_func->top_break;\n    while (top != NULL) {\n        close_scopes(s, scope_level, top->scope_level);\n        scope_level = top->scope_level;\n        if (is_cont &&\n            top->label_cont != -1 &&\n            (name == JS_ATOM_NULL || top->label_name == name)) {\n            /* continue stays inside the same block */\n            emit_goto(s, OP_goto, top->label_cont);\n            return 0;\n        }\n        if (!is_cont &&\n            top->label_break != -1 &&\n            ((name == JS_ATOM_NULL && !top->is_regular_stmt) ||\n             top->label_name == name)) {\n            emit_goto(s, OP_goto, top->label_break);\n            return 0;\n        }\n        i = 0;\n        if (top->has_iterator) {\n            emit_op(s, OP_iterator_close);\n            i += 3;\n        }\n        for(; i < top->drop_count; i++)\n            emit_op(s, OP_drop);\n        if (top->label_finally != -1) {\n            /* must push dummy value to keep same stack depth */\n            emit_op(s, OP_undefined);\n            emit_goto(s, OP_gosub, top->label_finally);\n            emit_op(s, OP_drop);\n        }\n        top = top->prev;\n    }\n    if (name == JS_ATOM_NULL) {\n        if (is_cont)\n            return js_parse_error(s, \"continue must be inside loop\");\n        else\n            return js_parse_error(s, \"break must be inside loop or switch\");\n    } else {\n        return js_parse_error(s, \"break/continue label not found\");\n    }\n}\n\n/* execute the finally blocks before return */\nstatic void emit_return(JSParseState *s, BOOL hasval)\n{\n    BlockEnv *top;\n\n    if (s->cur_func->func_kind != JS_FUNC_NORMAL) {\n        if (!hasval) {\n            /* no value: direct return in case of async generator */\n            emit_op(s, OP_undefined);\n            hasval = TRUE;\n        } else if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {\n            /* the await must be done before handling the \"finally\" in\n               case it raises an exception */\n            emit_op(s, OP_await);\n        }\n    }\n\n    top = s->cur_func->top_break;\n    while (top != NULL) {\n        if (top->has_iterator || top->label_finally != -1) {\n            if (!hasval) {\n                emit_op(s, OP_undefined);\n                hasval = TRUE;\n            }\n            /* Remove the stack elements up to and including the catch\n               offset. When 'yield' is used in an expression we have\n               no easy way to count them, so we use this specific\n               instruction instead. */\n            emit_op(s, OP_nip_catch);\n            /* stack: iter_obj next ret_val */\n            if (top->has_iterator) {\n                if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {\n                    int label_next, label_next2;\n                    emit_op(s, OP_nip); /* next */\n                    emit_op(s, OP_swap);\n                    emit_op(s, OP_get_field2);\n                    emit_atom(s, JS_ATOM_return);\n                    /* stack: iter_obj return_func */\n                    emit_op(s, OP_dup);\n                    emit_op(s, OP_is_undefined_or_null);\n                    label_next = emit_goto(s, OP_if_true, -1);\n                    emit_op(s, OP_call_method);\n                    emit_u16(s, 0);\n                    emit_op(s, OP_iterator_check_object);\n                    emit_op(s, OP_await);\n                    label_next2 = emit_goto(s, OP_goto, -1);\n                    emit_label(s, label_next);\n                    emit_op(s, OP_drop);\n                    emit_label(s, label_next2);\n                    emit_op(s, OP_drop);\n                } else {\n                    emit_op(s, OP_rot3r);\n                    emit_op(s, OP_undefined); /* dummy catch offset */\n                    emit_op(s, OP_iterator_close);\n                }\n            } else {\n                /* execute the \"finally\" block */\n                emit_goto(s, OP_gosub, top->label_finally);\n            }\n        }\n        top = top->prev;\n    }\n    if (s->cur_func->is_derived_class_constructor) {\n        int label_return;\n\n        /* 'this' can be uninitialized, so it may be accessed only if\n           the derived class constructor does not return an object */\n        if (hasval) {\n            emit_op(s, OP_check_ctor_return);\n            label_return = emit_goto(s, OP_if_false, -1);\n            emit_op(s, OP_drop);\n        } else {\n            label_return = -1;\n        }\n\n        /* The error should be raised in the caller context, so we use\n           a specific opcode */\n        emit_op(s, OP_scope_get_var_checkthis);\n        emit_atom(s, JS_ATOM_this);\n        emit_u16(s, 0);\n\n        emit_label(s, label_return);\n        emit_op(s, OP_return);\n    } else if (s->cur_func->func_kind != JS_FUNC_NORMAL) {\n        emit_op(s, OP_return_async);\n    } else {\n        emit_op(s, hasval ? OP_return : OP_return_undef);\n    }\n}\n\n#define DECL_MASK_FUNC  (1 << 0) /* allow normal function declaration */\n/* ored with DECL_MASK_FUNC if function declarations are allowed with a label */\n#define DECL_MASK_FUNC_WITH_LABEL (1 << 1)\n#define DECL_MASK_OTHER (1 << 2) /* all other declarations */\n#define DECL_MASK_ALL   (DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL | DECL_MASK_OTHER)\n\nstatic __exception int js_parse_statement_or_decl(JSParseState *s,\n                                                  int decl_mask);\n\nstatic __exception int js_parse_statement(JSParseState *s)\n{\n    return js_parse_statement_or_decl(s, 0);\n}\n\nstatic __exception int js_parse_block(JSParseState *s)\n{\n    if (js_parse_expect(s, '{'))\n        return -1;\n    if (s->token.val != '}') {\n        push_scope(s);\n        for(;;) {\n            if (js_parse_statement_or_decl(s, DECL_MASK_ALL))\n                return -1;\n            if (s->token.val == '}')\n                break;\n        }\n        pop_scope(s);\n    }\n    if (next_token(s))\n        return -1;\n    return 0;\n}\n\n/* allowed parse_flags: PF_IN_ACCEPTED */\nstatic __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,\n                                    BOOL export_flag)\n{\n    JSContext *ctx = s->ctx;\n    JSFunctionDef *fd = s->cur_func;\n    JSAtom name = JS_ATOM_NULL;\n\n    for (;;) {\n        if (s->token.val == TOK_IDENT) {\n            if (s->token.u.ident.is_reserved) {\n                return js_parse_error_reserved_identifier(s);\n            }\n            name = JS_DupAtom(ctx, s->token.u.ident.atom);\n            if (name == JS_ATOM_let && (tok == TOK_LET || tok == TOK_CONST)) {\n                js_parse_error(s, \"'let' is not a valid lexical identifier\");\n                goto var_error;\n            }\n            if (next_token(s))\n                goto var_error;\n            if (js_define_var(s, name, tok))\n                goto var_error;\n            if (export_flag) {\n                if (!add_export_entry(s, s->cur_func->module, name, name,\n                                      JS_EXPORT_TYPE_LOCAL))\n                    goto var_error;\n            }\n\n            if (s->token.val == '=') {\n                if (next_token(s))\n                    goto var_error;\n                if (need_var_reference(s, tok)) {\n                    /* Must make a reference for proper `with` semantics */\n                    int opcode, scope, label;\n                    JSAtom name1;\n\n                    emit_op(s, OP_scope_get_var);\n                    emit_atom(s, name);\n                    emit_u16(s, fd->scope_level);\n                    if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)\n                        goto var_error;\n                    if (js_parse_assign_expr2(s, parse_flags)) {\n                        JS_FreeAtom(ctx, name1);\n                        goto var_error;\n                    }\n                    set_object_name(s, name);\n                    put_lvalue(s, opcode, scope, name1, label,\n                               PUT_LVALUE_NOKEEP, FALSE);\n                } else {\n                    if (js_parse_assign_expr2(s, parse_flags))\n                        goto var_error;\n                    set_object_name(s, name);\n                    emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?\n                        OP_scope_put_var_init : OP_scope_put_var);\n                    emit_atom(s, name);\n                    emit_u16(s, fd->scope_level);\n                }\n            } else {\n                if (tok == TOK_CONST) {\n                    js_parse_error(s, \"missing initializer for const variable\");\n                    goto var_error;\n                }\n                if (tok == TOK_LET) {\n                    /* initialize lexical variable upon entering its scope */\n                    emit_op(s, OP_undefined);\n                    emit_op(s, OP_scope_put_var_init);\n                    emit_atom(s, name);\n                    emit_u16(s, fd->scope_level);\n                }\n            }\n            JS_FreeAtom(ctx, name);\n        } else {\n            int skip_bits;\n            if ((s->token.val == '[' || s->token.val == '{')\n            &&  js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {\n                emit_op(s, OP_undefined);\n                if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, export_flag) < 0)\n                    return -1;\n            } else {\n                return js_parse_error(s, \"variable name expected\");\n            }\n        }\n        if (s->token.val != ',')\n            break;\n        if (next_token(s))\n            return -1;\n    }\n    return 0;\n\n var_error:\n    JS_FreeAtom(ctx, name);\n    return -1;\n}\n\n/* test if the current token is a label. Use simplistic look-ahead scanner */\nstatic BOOL is_label(JSParseState *s)\n{\n    return (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&\n            peek_token(s, FALSE) == ':');\n}\n\n/* test if the current token is a let keyword. Use simplistic look-ahead scanner */\nstatic int is_let(JSParseState *s, int decl_mask)\n{\n    int res = FALSE;\n    const uint8_t *last_token_ptr;\n    \n    if (token_is_pseudo_keyword(s, JS_ATOM_let)) {\n        JSParsePos pos;\n        js_parse_get_pos(s, &pos);\n        for (;;) {\n            last_token_ptr = s->token.ptr;\n            if (next_token(s)) {\n                res = -1;\n                break;\n            }\n            if (s->token.val == '[') {\n                /* let [ is a syntax restriction:\n                   it never introduces an ExpressionStatement */\n                res = TRUE;\n                break;\n            }\n            if (s->token.val == '{' ||\n                (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved) ||\n                s->token.val == TOK_LET ||\n                s->token.val == TOK_YIELD ||\n                s->token.val == TOK_AWAIT) {\n                /* Check for possible ASI if not scanning for Declaration */\n                /* XXX: should also check that `{` introduces a BindingPattern,\n                   but Firefox does not and rejects eval(\"let=1;let\\n{if(1)2;}\") */\n                if (!has_lf_in_range(last_token_ptr, s->token.ptr) ||\n                    (decl_mask & DECL_MASK_OTHER)) {\n                    res = TRUE;\n                    break;\n                }\n                break;\n            }\n            break;\n        }\n        if (js_parse_seek_token(s, &pos)) {\n            res = -1;\n        }\n    }\n    return res;\n}\n\n/* XXX: handle IteratorClose when exiting the loop before the\n   enumeration is done */\nstatic __exception int js_parse_for_in_of(JSParseState *s, int label_name,\n                                          BOOL is_async)\n{\n    JSContext *ctx = s->ctx;\n    JSFunctionDef *fd = s->cur_func;\n    JSAtom var_name;\n    BOOL has_initializer, is_for_of, has_destructuring;\n    int tok, tok1, opcode, scope, block_scope_level;\n    int label_next, label_expr, label_cont, label_body, label_break;\n    int pos_next, pos_expr;\n    BlockEnv break_entry;\n\n    has_initializer = FALSE;\n    has_destructuring = FALSE;\n    is_for_of = FALSE;\n    block_scope_level = fd->scope_level;\n    label_cont = new_label(s);\n    label_body = new_label(s);\n    label_break = new_label(s);\n    label_next = new_label(s);\n\n    /* create scope for the lexical variables declared in the enumeration\n       expressions. XXX: Not completely correct because of weird capturing\n       semantics in `for (i of o) a.push(function(){return i})` */\n    push_scope(s);\n\n    /* local for_in scope starts here so individual elements\n       can be closed in statement. */\n    push_break_entry(s->cur_func, &break_entry,\n                     label_name, label_break, label_cont, 1);\n    break_entry.scope_level = block_scope_level;\n\n    label_expr = emit_goto(s, OP_goto, -1);\n\n    pos_next = s->cur_func->byte_code.size;\n    emit_label(s, label_next);\n\n    tok = s->token.val;\n    switch (is_let(s, DECL_MASK_OTHER)) {\n    case TRUE:\n        tok = TOK_LET;\n        break;\n    case FALSE:\n        break;\n    default:\n        return -1;\n    }\n    if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {\n        if (next_token(s))\n            return -1;\n\n        if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {\n            if (s->token.val == '[' || s->token.val == '{') {\n                if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE, FALSE) < 0)\n                    return -1;\n                has_destructuring = TRUE;\n            } else {\n                return js_parse_error(s, \"variable name expected\");\n            }\n            var_name = JS_ATOM_NULL;\n        } else {\n            var_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n            if (next_token(s)) {\n                JS_FreeAtom(s->ctx, var_name);\n                return -1;\n            }\n            if (js_define_var(s, var_name, tok)) {\n                JS_FreeAtom(s->ctx, var_name);\n                return -1;\n            }\n            emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?\n                    OP_scope_put_var_init : OP_scope_put_var);\n            emit_atom(s, var_name);\n            emit_u16(s, fd->scope_level);\n        }\n    } else if (!is_async && token_is_pseudo_keyword(s, JS_ATOM_async) &&\n               peek_token(s, FALSE) == TOK_OF) {\n        return js_parse_error(s, \"'for of' expression cannot start with 'async'\");\n    } else {\n        int skip_bits;\n        if ((s->token.val == '[' || s->token.val == '{')\n        &&  ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {\n            if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE, FALSE) < 0)\n                return -1;\n        } else {\n            int lvalue_label;\n            if (js_parse_left_hand_side_expr(s))\n                return -1;\n            if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,\n                           NULL, FALSE, TOK_FOR))\n                return -1;\n            put_lvalue(s, opcode, scope, var_name, lvalue_label,\n                       PUT_LVALUE_NOKEEP_BOTTOM, FALSE);\n        }\n        var_name = JS_ATOM_NULL;\n    }\n    emit_goto(s, OP_goto, label_body);\n\n    pos_expr = s->cur_func->byte_code.size;\n    emit_label(s, label_expr);\n    if (s->token.val == '=') {\n        /* XXX: potential scoping issue if inside `with` statement */\n        has_initializer = TRUE;\n        /* parse and evaluate initializer prior to evaluating the\n           object (only used with \"for in\" with a non lexical variable\n           in non strict mode */\n        if (next_token(s) || js_parse_assign_expr2(s, 0)) {\n            JS_FreeAtom(ctx, var_name);\n            return -1;\n        }\n        if (var_name != JS_ATOM_NULL) {\n            emit_op(s, OP_scope_put_var);\n            emit_atom(s, var_name);\n            emit_u16(s, fd->scope_level);\n        }\n    }\n    JS_FreeAtom(ctx, var_name);\n\n    if (token_is_pseudo_keyword(s, JS_ATOM_of)) {\n        break_entry.has_iterator = is_for_of = TRUE;\n        break_entry.drop_count += 2;\n        if (has_initializer)\n            goto initializer_error;\n    } else if (s->token.val == TOK_IN) {\n        if (is_async)\n            return js_parse_error(s, \"'for await' loop should be used with 'of'\");\n        if (has_initializer &&\n            (tok != TOK_VAR || (fd->js_mode & JS_MODE_STRICT) ||\n             has_destructuring)) {\n        initializer_error:\n            return js_parse_error(s, \"a declaration in the head of a for-%s loop can't have an initializer\",\n                                  is_for_of ? \"of\" : \"in\");\n        }\n    } else {\n        return js_parse_error(s, \"expected 'of' or 'in' in for control expression\");\n    }\n    if (next_token(s))\n        return -1;\n    if (is_for_of) {\n        if (js_parse_assign_expr(s))\n            return -1;\n    } else {\n        if (js_parse_expr(s))\n            return -1;\n    }\n    /* close the scope after having evaluated the expression so that\n       the TDZ values are in the closures */\n    close_scopes(s, s->cur_func->scope_level, block_scope_level);\n    if (is_for_of) {\n        if (is_async)\n            emit_op(s, OP_for_await_of_start);\n        else\n            emit_op(s, OP_for_of_start);\n        /* on stack: enum_rec */\n    } else {\n        emit_op(s, OP_for_in_start);\n        /* on stack: enum_obj */\n    }\n    emit_goto(s, OP_goto, label_cont);\n\n    if (js_parse_expect(s, ')'))\n        return -1;\n\n    if (OPTIMIZE) {\n        /* move the `next` code here */\n        DynBuf *bc = &s->cur_func->byte_code;\n        int chunk_size = pos_expr - pos_next;\n        int offset = bc->size - pos_next;\n        int i;\n        dbuf_claim(bc, chunk_size);\n        dbuf_put(bc, bc->buf + pos_next, chunk_size);\n        memset(bc->buf + pos_next, OP_nop, chunk_size);\n        /* `next` part ends with a goto */\n        s->cur_func->last_opcode_pos = bc->size - 5;\n        /* relocate labels */\n        for (i = label_cont; i < s->cur_func->label_count; i++) {\n            LabelSlot *ls = &s->cur_func->label_slots[i];\n            if (ls->pos >= pos_next && ls->pos < pos_expr)\n                ls->pos += offset;\n        }\n    }\n\n    emit_label(s, label_body);\n    if (js_parse_statement(s))\n        return -1;\n\n    close_scopes(s, s->cur_func->scope_level, block_scope_level);\n\n    emit_label(s, label_cont);\n    if (is_for_of) {\n        if (is_async) {\n            /* stack: iter_obj next catch_offset */\n            /* call the next method */\n            emit_op(s, OP_for_await_of_next); \n            /* get the result of the promise */\n            emit_op(s, OP_await);\n            /* unwrap the value and done values */\n            emit_op(s, OP_iterator_get_value_done);\n        } else {\n            emit_op(s, OP_for_of_next);\n            emit_u8(s, 0);\n        }\n    } else {\n        emit_op(s, OP_for_in_next);\n    }\n    /* on stack: enum_rec / enum_obj value bool */\n    emit_goto(s, OP_if_false, label_next);\n    /* drop the undefined value from for_xx_next */\n    emit_op(s, OP_drop);\n\n    emit_label(s, label_break);\n    if (is_for_of) {\n        /* close and drop enum_rec */\n        emit_op(s, OP_iterator_close);\n    } else {\n        emit_op(s, OP_drop);\n    }\n    pop_break_entry(s->cur_func);\n    pop_scope(s);\n    return 0;\n}\n\nstatic void set_eval_ret_undefined(JSParseState *s)\n{\n    if (s->cur_func->eval_ret_idx >= 0) {\n        emit_op(s, OP_undefined);\n        emit_op(s, OP_put_loc);\n        emit_u16(s, s->cur_func->eval_ret_idx);\n    }\n}\n\nstatic __exception int js_parse_statement_or_decl(JSParseState *s,\n                                                  int decl_mask)\n{\n    JSContext *ctx = s->ctx;\n    JSAtom label_name;\n    int tok;\n\n    /* specific label handling */\n    /* XXX: support multiple labels on loop statements */\n    label_name = JS_ATOM_NULL;\n    if (is_label(s)) {\n        BlockEnv *be;\n\n        label_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n\n        for (be = s->cur_func->top_break; be; be = be->prev) {\n            if (be->label_name == label_name) {\n                js_parse_error(s, \"duplicate label name\");\n                goto fail;\n            }\n        }\n\n        if (next_token(s))\n            goto fail;\n        if (js_parse_expect(s, ':'))\n            goto fail;\n        if (s->token.val != TOK_FOR\n        &&  s->token.val != TOK_DO\n        &&  s->token.val != TOK_WHILE) {\n            /* labelled regular statement */\n            int label_break, mask;\n            BlockEnv break_entry;\n\n            label_break = new_label(s);\n            push_break_entry(s->cur_func, &break_entry,\n                             label_name, label_break, -1, 0);\n            break_entry.is_regular_stmt = TRUE;\n            if (!(s->cur_func->js_mode & JS_MODE_STRICT) &&\n                (decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {\n                mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;\n            } else {\n                mask = 0;\n            }\n            if (js_parse_statement_or_decl(s, mask))\n                goto fail;\n            emit_label(s, label_break);\n            pop_break_entry(s->cur_func);\n            goto done;\n        }\n    }\n\n    switch(tok = s->token.val) {\n    case '{':\n        if (js_parse_block(s))\n            goto fail;\n        break;\n    case TOK_RETURN:\n        {\n            const uint8_t *op_token_ptr;\n            if (s->cur_func->is_eval) {\n                js_parse_error(s, \"return not in a function\");\n                goto fail;\n            }\n            if (s->cur_func->func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {\n                js_parse_error(s, \"return in a static initializer block\");\n                goto fail;\n            }\n            op_token_ptr = s->token.ptr;\n            if (next_token(s))\n                goto fail;\n            if (s->token.val != ';' && s->token.val != '}' && !s->got_lf) {\n                if (js_parse_expr(s))\n                    goto fail;\n                emit_source_pos(s, op_token_ptr);\n                emit_return(s, TRUE);\n            } else {\n                emit_source_pos(s, op_token_ptr);\n                emit_return(s, FALSE);\n            }\n            if (js_parse_expect_semi(s))\n                goto fail;\n        }\n        break;\n    case TOK_THROW:\n        {\n            const uint8_t *op_token_ptr;\n            op_token_ptr = s->token.ptr;\n            if (next_token(s))\n                goto fail;\n            if (s->got_lf) {\n                js_parse_error(s, \"line terminator not allowed after throw\");\n                goto fail;\n            }\n            if (js_parse_expr(s))\n                goto fail;\n            emit_source_pos(s, op_token_ptr);\n            emit_op(s, OP_throw);\n            if (js_parse_expect_semi(s))\n                goto fail;\n        }\n        break;\n    case TOK_LET:\n    case TOK_CONST:\n    haslet:\n        if (!(decl_mask & DECL_MASK_OTHER)) {\n            js_parse_error(s, \"lexical declarations can't appear in single-statement context\");\n            goto fail;\n        }\n        /* fall thru */\n    case TOK_VAR:\n        if (next_token(s))\n            goto fail;\n        if (js_parse_var(s, TRUE, tok, FALSE))\n            goto fail;\n        if (js_parse_expect_semi(s))\n            goto fail;\n        break;\n    case TOK_IF:\n        {\n            int label1, label2, mask;\n            if (next_token(s))\n                goto fail;\n            /* create a new scope for `let f;if(1) function f(){}` */\n            push_scope(s);\n            set_eval_ret_undefined(s);\n            if (js_parse_expr_paren(s))\n                goto fail;\n            label1 = emit_goto(s, OP_if_false, -1);\n            if (s->cur_func->js_mode & JS_MODE_STRICT)\n                mask = 0;\n            else\n                mask = DECL_MASK_FUNC; /* Annex B.3.4 */\n\n            if (js_parse_statement_or_decl(s, mask))\n                goto fail;\n\n            if (s->token.val == TOK_ELSE) {\n                label2 = emit_goto(s, OP_goto, -1);\n                if (next_token(s))\n                    goto fail;\n\n                emit_label(s, label1);\n                if (js_parse_statement_or_decl(s, mask))\n                    goto fail;\n\n                label1 = label2;\n            }\n            emit_label(s, label1);\n            pop_scope(s);\n        }\n        break;\n    case TOK_WHILE:\n        {\n            int label_cont, label_break;\n            BlockEnv break_entry;\n\n            label_cont = new_label(s);\n            label_break = new_label(s);\n\n            push_break_entry(s->cur_func, &break_entry,\n                             label_name, label_break, label_cont, 0);\n\n            if (next_token(s))\n                goto fail;\n\n            set_eval_ret_undefined(s);\n\n            emit_label(s, label_cont);\n            if (js_parse_expr_paren(s))\n                goto fail;\n            emit_goto(s, OP_if_false, label_break);\n\n            if (js_parse_statement(s))\n                goto fail;\n            emit_goto(s, OP_goto, label_cont);\n\n            emit_label(s, label_break);\n\n            pop_break_entry(s->cur_func);\n        }\n        break;\n    case TOK_DO:\n        {\n            int label_cont, label_break, label1;\n            BlockEnv break_entry;\n\n            label_cont = new_label(s);\n            label_break = new_label(s);\n            label1 = new_label(s);\n\n            push_break_entry(s->cur_func, &break_entry,\n                             label_name, label_break, label_cont, 0);\n\n            if (next_token(s))\n                goto fail;\n\n            emit_label(s, label1);\n\n            set_eval_ret_undefined(s);\n\n            if (js_parse_statement(s))\n                goto fail;\n\n            emit_label(s, label_cont);\n            if (js_parse_expect(s, TOK_WHILE))\n                goto fail;\n            if (js_parse_expr_paren(s))\n                goto fail;\n            /* Insert semicolon if missing */\n            if (s->token.val == ';') {\n                if (next_token(s))\n                    goto fail;\n            }\n            emit_goto(s, OP_if_true, label1);\n\n            emit_label(s, label_break);\n\n            pop_break_entry(s->cur_func);\n        }\n        break;\n    case TOK_FOR:\n        {\n            int label_cont, label_break, label_body, label_test;\n            int pos_cont, pos_body, block_scope_level;\n            BlockEnv break_entry;\n            int tok, bits;\n            BOOL is_async;\n\n            if (next_token(s))\n                goto fail;\n\n            set_eval_ret_undefined(s);\n            bits = 0;\n            is_async = FALSE;\n            if (s->token.val == '(') {\n                js_parse_skip_parens_token(s, &bits, FALSE);\n            } else if (s->token.val == TOK_AWAIT) {\n                if (!(s->cur_func->func_kind & JS_FUNC_ASYNC)) {\n                    js_parse_error(s, \"for await is only valid in asynchronous functions\");\n                    goto fail;\n                }\n                is_async = TRUE;\n                if (next_token(s))\n                    goto fail;\n                s->cur_func->has_await = TRUE;\n            }\n            if (js_parse_expect(s, '('))\n                goto fail;\n\n            if (!(bits & SKIP_HAS_SEMI)) {\n                /* parse for/in or for/of */\n                if (js_parse_for_in_of(s, label_name, is_async))\n                    goto fail;\n                break;\n            }\n            block_scope_level = s->cur_func->scope_level;\n\n            /* create scope for the lexical variables declared in the initial,\n               test and increment expressions */\n            push_scope(s);\n            /* initial expression */\n            tok = s->token.val;\n            if (tok != ';') {\n                switch (is_let(s, DECL_MASK_OTHER)) {\n                case TRUE:\n                    tok = TOK_LET;\n                    break;\n                case FALSE:\n                    break;\n                default:\n                    goto fail;\n                }\n                if (tok == TOK_VAR || tok == TOK_LET || tok == TOK_CONST) {\n                    if (next_token(s))\n                        goto fail;\n                    if (js_parse_var(s, FALSE, tok, FALSE))\n                        goto fail;\n                } else {\n                    if (js_parse_expr2(s, FALSE))\n                        goto fail;\n                    emit_op(s, OP_drop);\n                }\n\n                /* close the closures before the first iteration */\n                close_scopes(s, s->cur_func->scope_level, block_scope_level);\n            }\n            if (js_parse_expect(s, ';'))\n                goto fail;\n\n            label_test = new_label(s);\n            label_cont = new_label(s);\n            label_body = new_label(s);\n            label_break = new_label(s);\n\n            push_break_entry(s->cur_func, &break_entry,\n                             label_name, label_break, label_cont, 0);\n\n            /* test expression */\n            if (s->token.val == ';') {\n                /* no test expression */\n                label_test = label_body;\n            } else {\n                emit_label(s, label_test);\n                if (js_parse_expr(s))\n                    goto fail;\n                emit_goto(s, OP_if_false, label_break);\n            }\n            if (js_parse_expect(s, ';'))\n                goto fail;\n\n            if (s->token.val == ')') {\n                /* no end expression */\n                break_entry.label_cont = label_cont = label_test;\n                pos_cont = 0; /* avoid warning */\n            } else {\n                /* skip the end expression */\n                emit_goto(s, OP_goto, label_body);\n\n                pos_cont = s->cur_func->byte_code.size;\n                emit_label(s, label_cont);\n                if (js_parse_expr(s))\n                    goto fail;\n                emit_op(s, OP_drop);\n                if (label_test != label_body)\n                    emit_goto(s, OP_goto, label_test);\n            }\n            if (js_parse_expect(s, ')'))\n                goto fail;\n\n            pos_body = s->cur_func->byte_code.size;\n            emit_label(s, label_body);\n            if (js_parse_statement(s))\n                goto fail;\n\n            /* close the closures before the next iteration */\n            /* XXX: check continue case */\n            close_scopes(s, s->cur_func->scope_level, block_scope_level);\n\n            if (OPTIMIZE && label_test != label_body && label_cont != label_test) {\n                /* move the increment code here */\n                DynBuf *bc = &s->cur_func->byte_code;\n                int chunk_size = pos_body - pos_cont;\n                int offset = bc->size - pos_cont;\n                int i;\n                dbuf_claim(bc, chunk_size);\n                dbuf_put(bc, bc->buf + pos_cont, chunk_size);\n                memset(bc->buf + pos_cont, OP_nop, chunk_size);\n                /* increment part ends with a goto */\n                s->cur_func->last_opcode_pos = bc->size - 5;\n                /* relocate labels */\n                for (i = label_cont; i < s->cur_func->label_count; i++) {\n                    LabelSlot *ls = &s->cur_func->label_slots[i];\n                    if (ls->pos >= pos_cont && ls->pos < pos_body)\n                        ls->pos += offset;\n                }\n            } else {\n                emit_goto(s, OP_goto, label_cont);\n            }\n\n            emit_label(s, label_break);\n\n            pop_break_entry(s->cur_func);\n            pop_scope(s);\n        }\n        break;\n    case TOK_BREAK:\n    case TOK_CONTINUE:\n        {\n            int is_cont = s->token.val - TOK_BREAK;\n            int label;\n\n            if (next_token(s))\n                goto fail;\n            if (!s->got_lf && s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)\n                label = s->token.u.ident.atom;\n            else\n                label = JS_ATOM_NULL;\n            if (emit_break(s, label, is_cont))\n                goto fail;\n            if (label != JS_ATOM_NULL) {\n                if (next_token(s))\n                    goto fail;\n            }\n            if (js_parse_expect_semi(s))\n                goto fail;\n        }\n        break;\n    case TOK_SWITCH:\n        {\n            int label_case, label_break, label1;\n            int default_label_pos;\n            BlockEnv break_entry;\n\n            if (next_token(s))\n                goto fail;\n\n            set_eval_ret_undefined(s);\n            if (js_parse_expr_paren(s))\n                goto fail;\n\n            push_scope(s);\n            label_break = new_label(s);\n            push_break_entry(s->cur_func, &break_entry,\n                             label_name, label_break, -1, 1);\n\n            if (js_parse_expect(s, '{'))\n                goto fail;\n\n            default_label_pos = -1;\n            label_case = -1;\n            while (s->token.val != '}') {\n                if (s->token.val == TOK_CASE) {\n                    label1 = -1;\n                    if (label_case >= 0) {\n                        /* skip the case if needed */\n                        label1 = emit_goto(s, OP_goto, -1);\n                    }\n                    emit_label(s, label_case);\n                    label_case = -1;\n                    for (;;) {\n                        /* parse a sequence of case clauses */\n                        if (next_token(s))\n                            goto fail;\n                        emit_op(s, OP_dup);\n                        if (js_parse_expr(s))\n                            goto fail;\n                        if (js_parse_expect(s, ':'))\n                            goto fail;\n                        emit_op(s, OP_strict_eq);\n                        if (s->token.val == TOK_CASE) {\n                            label1 = emit_goto(s, OP_if_true, label1);\n                        } else {\n                            label_case = emit_goto(s, OP_if_false, -1);\n                            emit_label(s, label1);\n                            break;\n                        }\n                    }\n                } else if (s->token.val == TOK_DEFAULT) {\n                    if (next_token(s))\n                        goto fail;\n                    if (js_parse_expect(s, ':'))\n                        goto fail;\n                    if (default_label_pos >= 0) {\n                        js_parse_error(s, \"duplicate default\");\n                        goto fail;\n                    }\n                    if (label_case < 0) {\n                        /* falling thru direct from switch expression */\n                        label_case = emit_goto(s, OP_goto, -1);\n                    }\n                    /* Emit a dummy label opcode. Label will be patched after\n                       the end of the switch body. Do not use emit_label(s, 0)\n                       because it would clobber label 0 address, preventing\n                       proper optimizer operation.\n                     */\n                    emit_op(s, OP_label);\n                    emit_u32(s, 0);\n                    default_label_pos = s->cur_func->byte_code.size - 4;\n                } else {\n                    if (label_case < 0) {\n                        /* falling thru direct from switch expression */\n                        js_parse_error(s, \"invalid switch statement\");\n                        goto fail;\n                    }\n                    if (js_parse_statement_or_decl(s, DECL_MASK_ALL))\n                        goto fail;\n                }\n            }\n            if (js_parse_expect(s, '}'))\n                goto fail;\n            if (default_label_pos >= 0) {\n                /* Ugly patch for the the `default` label, shameful and risky */\n                put_u32(s->cur_func->byte_code.buf + default_label_pos,\n                        label_case);\n                s->cur_func->label_slots[label_case].pos = default_label_pos + 4;\n            } else {\n                emit_label(s, label_case);\n            }\n            emit_label(s, label_break);\n            emit_op(s, OP_drop); /* drop the switch expression */\n\n            pop_break_entry(s->cur_func);\n            pop_scope(s);\n        }\n        break;\n    case TOK_TRY:\n        {\n            int label_catch, label_catch2, label_finally, label_end;\n            JSAtom name;\n            BlockEnv block_env;\n\n            set_eval_ret_undefined(s);\n            if (next_token(s))\n                goto fail;\n            label_catch = new_label(s);\n            label_catch2 = new_label(s);\n            label_finally = new_label(s);\n            label_end = new_label(s);\n\n            emit_goto(s, OP_catch, label_catch);\n\n            push_break_entry(s->cur_func, &block_env,\n                             JS_ATOM_NULL, -1, -1, 1);\n            block_env.label_finally = label_finally;\n\n            if (js_parse_block(s))\n                goto fail;\n\n            pop_break_entry(s->cur_func);\n\n            if (js_is_live_code(s)) {\n                /* drop the catch offset */\n                emit_op(s, OP_drop);\n                /* must push dummy value to keep same stack size */\n                emit_op(s, OP_undefined);\n                emit_goto(s, OP_gosub, label_finally);\n                emit_op(s, OP_drop);\n\n                emit_goto(s, OP_goto, label_end);\n            }\n\n            if (s->token.val == TOK_CATCH) {\n                if (next_token(s))\n                    goto fail;\n\n                push_scope(s);  /* catch variable */\n                emit_label(s, label_catch);\n\n                if (s->token.val == '{') {\n                    /* support optional-catch-binding feature */\n                    emit_op(s, OP_drop);    /* pop the exception object */\n                } else {\n                    if (js_parse_expect(s, '('))\n                        goto fail;\n                    if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {\n                        if (s->token.val == '[' || s->token.val == '{') {\n                            /* XXX: TOK_LET is not completely correct */\n                            if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE, FALSE) < 0)\n                                goto fail;\n                        } else {\n                            js_parse_error(s, \"identifier expected\");\n                            goto fail;\n                        }\n                    } else {\n                        name = JS_DupAtom(ctx, s->token.u.ident.atom);\n                        if (next_token(s)\n                        ||  js_define_var(s, name, TOK_CATCH) < 0) {\n                            JS_FreeAtom(ctx, name);\n                            goto fail;\n                        }\n                        /* store the exception value in the catch variable */\n                        emit_op(s, OP_scope_put_var);\n                        emit_u32(s, name);\n                        emit_u16(s, s->cur_func->scope_level);\n                    }\n                    if (js_parse_expect(s, ')'))\n                        goto fail;\n                }\n                /* XXX: should keep the address to nop it out if there is no finally block */\n                emit_goto(s, OP_catch, label_catch2);\n\n                push_scope(s);  /* catch block */\n                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,\n                                 -1, -1, 1);\n                block_env.label_finally = label_finally;\n\n                if (js_parse_block(s))\n                    goto fail;\n\n                pop_break_entry(s->cur_func);\n                pop_scope(s);  /* catch block */\n                pop_scope(s);  /* catch variable */\n\n                if (js_is_live_code(s)) {\n                    /* drop the catch2 offset */\n                    emit_op(s, OP_drop);\n                    /* XXX: should keep the address to nop it out if there is no finally block */\n                    /* must push dummy value to keep same stack size */\n                    emit_op(s, OP_undefined);\n                    emit_goto(s, OP_gosub, label_finally);\n                    emit_op(s, OP_drop);\n                    emit_goto(s, OP_goto, label_end);\n                }\n                /* catch exceptions thrown in the catch block to execute the\n                 * finally clause and rethrow the exception */\n                emit_label(s, label_catch2);\n                /* catch value is at TOS, no need to push undefined */\n                emit_goto(s, OP_gosub, label_finally);\n                emit_op(s, OP_throw);\n\n            } else if (s->token.val == TOK_FINALLY) {\n                /* finally without catch : execute the finally clause\n                 * and rethrow the exception */\n                emit_label(s, label_catch);\n                /* catch value is at TOS, no need to push undefined */\n                emit_goto(s, OP_gosub, label_finally);\n                emit_op(s, OP_throw);\n            } else {\n                js_parse_error(s, \"expecting catch or finally\");\n                goto fail;\n            }\n            emit_label(s, label_finally);\n            if (s->token.val == TOK_FINALLY) {\n                int saved_eval_ret_idx = 0; /* avoid warning */\n\n                if (next_token(s))\n                    goto fail;\n                /* on the stack: ret_value gosub_ret_value */\n                push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,\n                                 -1, -1, 2);\n\n                if (s->cur_func->eval_ret_idx >= 0) {\n                    /* 'finally' updates eval_ret only if not a normal\n                       termination */\n                    saved_eval_ret_idx =\n                        add_var(s->ctx, s->cur_func, JS_ATOM__ret_);\n                    if (saved_eval_ret_idx < 0)\n                        goto fail;\n                    emit_op(s, OP_get_loc);\n                    emit_u16(s, s->cur_func->eval_ret_idx);\n                    emit_op(s, OP_put_loc);\n                    emit_u16(s, saved_eval_ret_idx);\n                    set_eval_ret_undefined(s);\n                }\n\n                if (js_parse_block(s))\n                    goto fail;\n\n                if (s->cur_func->eval_ret_idx >= 0) {\n                    emit_op(s, OP_get_loc);\n                    emit_u16(s, saved_eval_ret_idx);\n                    emit_op(s, OP_put_loc);\n                    emit_u16(s, s->cur_func->eval_ret_idx);\n                }\n                pop_break_entry(s->cur_func);\n            }\n            emit_op(s, OP_ret);\n            emit_label(s, label_end);\n        }\n        break;\n    case ';':\n        /* empty statement */\n        if (next_token(s))\n            goto fail;\n        break;\n    case TOK_WITH:\n        if (s->cur_func->js_mode & JS_MODE_STRICT) {\n            js_parse_error(s, \"invalid keyword: with\");\n            goto fail;\n        } else {\n            int with_idx;\n\n            if (next_token(s))\n                goto fail;\n\n            if (js_parse_expr_paren(s))\n                goto fail;\n\n            push_scope(s);\n            with_idx = define_var(s, s->cur_func, JS_ATOM__with_,\n                                  JS_VAR_DEF_WITH);\n            if (with_idx < 0)\n                goto fail;\n            emit_op(s, OP_to_object);\n            emit_op(s, OP_put_loc);\n            emit_u16(s, with_idx);\n\n            set_eval_ret_undefined(s);\n            if (js_parse_statement(s))\n                goto fail;\n\n            /* Popping scope drops lexical context for the with object variable */\n            pop_scope(s);\n        }\n        break;\n    case TOK_FUNCTION:\n        /* ES6 Annex B.3.2 and B.3.3 semantics */\n        if (!(decl_mask & DECL_MASK_FUNC))\n            goto func_decl_error;\n        if (!(decl_mask & DECL_MASK_OTHER) && peek_token(s, FALSE) == '*')\n            goto func_decl_error;\n        goto parse_func_var;\n    case TOK_IDENT:\n        if (s->token.u.ident.is_reserved) {\n            js_parse_error_reserved_identifier(s);\n            goto fail;\n        }\n        /* Determine if `let` introduces a Declaration or an ExpressionStatement */\n        switch (is_let(s, decl_mask)) {\n        case TRUE:\n            tok = TOK_LET;\n            goto haslet;\n        case FALSE:\n            break;\n        default:\n            goto fail;\n        }\n        if (token_is_pseudo_keyword(s, JS_ATOM_async) &&\n            peek_token(s, TRUE) == TOK_FUNCTION) {\n            if (!(decl_mask & DECL_MASK_OTHER)) {\n            func_decl_error:\n                js_parse_error(s, \"function declarations can't appear in single-statement context\");\n                goto fail;\n            }\n        parse_func_var:\n            if (js_parse_function_decl(s, JS_PARSE_FUNC_VAR,\n                                       JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                       s->token.ptr))\n                goto fail;\n            break;\n        }\n        goto hasexpr;\n\n    case TOK_CLASS:\n        if (!(decl_mask & DECL_MASK_OTHER)) {\n            js_parse_error(s, \"class declarations can't appear in single-statement context\");\n            goto fail;\n        }\n        if (js_parse_class(s, FALSE, JS_PARSE_EXPORT_NONE))\n            return -1;\n        break;\n\n    case TOK_DEBUGGER:\n        /* currently no debugger, so just skip the keyword */\n        if (next_token(s))\n            goto fail;\n        if (js_parse_expect_semi(s))\n            goto fail;\n        break;\n\n    case TOK_ENUM:\n    case TOK_EXPORT:\n    case TOK_EXTENDS:\n        js_unsupported_keyword(s, s->token.u.ident.atom);\n        goto fail;\n\n    default:\n    hasexpr:\n        emit_source_pos(s, s->token.ptr);\n        if (js_parse_expr(s))\n            goto fail;\n        if (s->cur_func->eval_ret_idx >= 0) {\n            /* store the expression value so that it can be returned\n               by eval() */\n            emit_op(s, OP_put_loc);\n            emit_u16(s, s->cur_func->eval_ret_idx);\n        } else {\n            emit_op(s, OP_drop); /* drop the result */\n        }\n        if (js_parse_expect_semi(s))\n            goto fail;\n        break;\n    }\ndone:\n    JS_FreeAtom(ctx, label_name);\n    return 0;\nfail:\n    JS_FreeAtom(ctx, label_name);\n    return -1;\n}\n\n/* 'name' is freed. The module is referenced by 'ctx->loaded_modules' */\nstatic JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name)\n{\n    JSModuleDef *m;\n    m = js_mallocz(ctx, sizeof(*m));\n    if (!m) {\n        JS_FreeAtom(ctx, name);\n        return NULL;\n    }\n    m->header.ref_count = 1;\n    add_gc_object(ctx->rt, &m->header, JS_GC_OBJ_TYPE_MODULE);\n    m->module_name = name;\n    m->module_ns = JS_UNDEFINED;\n    m->func_obj = JS_UNDEFINED;\n    m->eval_exception = JS_UNDEFINED;\n    m->meta_obj = JS_UNDEFINED;\n    m->promise = JS_UNDEFINED;\n    m->resolving_funcs[0] = JS_UNDEFINED;\n    m->resolving_funcs[1] = JS_UNDEFINED;\n    m->private_value = JS_UNDEFINED;\n    list_add_tail(&m->link, &ctx->loaded_modules);\n    return m;\n}\n\nstatic void js_mark_module_def(JSRuntime *rt, JSModuleDef *m,\n                               JS_MarkFunc *mark_func)\n{\n    int i;\n\n    for(i = 0; i < m->req_module_entries_count; i++) {\n        JSReqModuleEntry *rme = &m->req_module_entries[i];\n        JS_MarkValue(rt, rme->attributes, mark_func);\n    }\n    \n    for(i = 0; i < m->export_entries_count; i++) {\n        JSExportEntry *me = &m->export_entries[i];\n        if (me->export_type == JS_EXPORT_TYPE_LOCAL &&\n            me->u.local.var_ref) {\n            mark_func(rt, &me->u.local.var_ref->header);\n        }\n    }\n\n    JS_MarkValue(rt, m->module_ns, mark_func);\n    JS_MarkValue(rt, m->func_obj, mark_func);\n    JS_MarkValue(rt, m->eval_exception, mark_func);\n    JS_MarkValue(rt, m->meta_obj, mark_func);\n    JS_MarkValue(rt, m->promise, mark_func);\n    JS_MarkValue(rt, m->resolving_funcs[0], mark_func);\n    JS_MarkValue(rt, m->resolving_funcs[1], mark_func);\n    JS_MarkValue(rt, m->private_value, mark_func);\n}\n\nstatic void js_free_module_def(JSRuntime *rt, JSModuleDef *m)\n{\n    int i;\n\n    JS_FreeAtomRT(rt, m->module_name);\n\n    for(i = 0; i < m->req_module_entries_count; i++) {\n        JSReqModuleEntry *rme = &m->req_module_entries[i];\n        JS_FreeAtomRT(rt, rme->module_name);\n        JS_FreeValueRT(rt, rme->attributes);\n    }\n    js_free_rt(rt, m->req_module_entries);\n\n    for(i = 0; i < m->export_entries_count; i++) {\n        JSExportEntry *me = &m->export_entries[i];\n        if (me->export_type == JS_EXPORT_TYPE_LOCAL)\n            free_var_ref(rt, me->u.local.var_ref);\n        JS_FreeAtomRT(rt, me->export_name);\n        JS_FreeAtomRT(rt, me->local_name);\n    }\n    js_free_rt(rt, m->export_entries);\n\n    js_free_rt(rt, m->star_export_entries);\n\n    for(i = 0; i < m->import_entries_count; i++) {\n        JSImportEntry *mi = &m->import_entries[i];\n        JS_FreeAtomRT(rt, mi->import_name);\n    }\n    js_free_rt(rt, m->import_entries);\n    js_free_rt(rt, m->async_parent_modules);\n\n    JS_FreeValueRT(rt, m->module_ns);\n    JS_FreeValueRT(rt, m->func_obj);\n    JS_FreeValueRT(rt, m->eval_exception);\n    JS_FreeValueRT(rt, m->meta_obj);\n    JS_FreeValueRT(rt, m->promise);\n    JS_FreeValueRT(rt, m->resolving_funcs[0]);\n    JS_FreeValueRT(rt, m->resolving_funcs[1]);\n    JS_FreeValueRT(rt, m->private_value);\n    /* during the GC the finalizers are called in an arbitrary\n       order so the module may no longer be referenced by the JSContext list */\n    if (m->link.next) {\n        list_del(&m->link);\n    }\n    remove_gc_object(&m->header);\n    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && m->header.ref_count != 0) {\n        list_add_tail(&m->header.link, &rt->gc_zero_ref_count_list);\n    } else {\n        js_free_rt(rt, m);\n    }\n}\n\nstatic int add_req_module_entry(JSContext *ctx, JSModuleDef *m,\n                                JSAtom module_name)\n{\n    JSReqModuleEntry *rme;\n\n    if (js_resize_array(ctx, (void **)&m->req_module_entries,\n                        sizeof(JSReqModuleEntry),\n                        &m->req_module_entries_size,\n                        m->req_module_entries_count + 1))\n        return -1;\n    rme = &m->req_module_entries[m->req_module_entries_count++];\n    rme->module_name = JS_DupAtom(ctx, module_name);\n    rme->module = NULL;\n    rme->attributes = JS_UNDEFINED;\n    return m->req_module_entries_count - 1;\n}\n\nstatic JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m,\n                                        JSAtom export_name)\n{\n    JSExportEntry *me;\n    int i;\n    for(i = 0; i < m->export_entries_count; i++) {\n        me = &m->export_entries[i];\n        if (me->export_name == export_name)\n            return me;\n    }\n    return NULL;\n}\n\nstatic JSExportEntry *add_export_entry2(JSContext *ctx,\n                                        JSParseState *s, JSModuleDef *m,\n                                       JSAtom local_name, JSAtom export_name,\n                                       JSExportTypeEnum export_type)\n{\n    JSExportEntry *me;\n\n    if (find_export_entry(ctx, m, export_name)) {\n        char buf1[ATOM_GET_STR_BUF_SIZE];\n        if (s) {\n            js_parse_error(s, \"duplicate exported name '%s'\",\n                           JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));\n        } else {\n            JS_ThrowSyntaxErrorAtom(ctx, \"duplicate exported name '%s'\", export_name);\n        }\n        return NULL;\n    }\n\n    if (js_resize_array(ctx, (void **)&m->export_entries,\n                        sizeof(JSExportEntry),\n                        &m->export_entries_size,\n                        m->export_entries_count + 1))\n        return NULL;\n    me = &m->export_entries[m->export_entries_count++];\n    memset(me, 0, sizeof(*me));\n    me->local_name = JS_DupAtom(ctx, local_name);\n    me->export_name = JS_DupAtom(ctx, export_name);\n    me->export_type = export_type;\n    return me;\n}\n\nstatic JSExportEntry *add_export_entry(JSParseState *s, JSModuleDef *m,\n                                       JSAtom local_name, JSAtom export_name,\n                                       JSExportTypeEnum export_type)\n{\n    return add_export_entry2(s->ctx, s, m, local_name, export_name,\n                             export_type);\n}\n\nstatic int add_star_export_entry(JSContext *ctx, JSModuleDef *m,\n                                 int req_module_idx)\n{\n    JSStarExportEntry *se;\n\n    if (js_resize_array(ctx, (void **)&m->star_export_entries,\n                        sizeof(JSStarExportEntry),\n                        &m->star_export_entries_size,\n                        m->star_export_entries_count + 1))\n        return -1;\n    se = &m->star_export_entries[m->star_export_entries_count++];\n    se->req_module_idx = req_module_idx;\n    return 0;\n}\n\n/* create a C module */\nJSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,\n                           JSModuleInitFunc *func)\n{\n    JSModuleDef *m;\n    JSAtom name;\n    name = JS_NewAtom(ctx, name_str);\n    if (name == JS_ATOM_NULL)\n        return NULL;\n    m = js_new_module_def(ctx, name);\n    if (!m)\n        return NULL;\n    m->init_func = func;\n    return m;\n}\n\nint JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name)\n{\n    JSExportEntry *me;\n    JSAtom name;\n    name = JS_NewAtom(ctx, export_name);\n    if (name == JS_ATOM_NULL)\n        return -1;\n    me = add_export_entry2(ctx, NULL, m, JS_ATOM_NULL, name,\n                           JS_EXPORT_TYPE_LOCAL);\n    JS_FreeAtom(ctx, name);\n    if (!me)\n        return -1;\n    else\n        return 0;\n}\n\nint JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,\n                       JSValue val)\n{\n    JSExportEntry *me;\n    JSAtom name;\n    name = JS_NewAtom(ctx, export_name);\n    if (name == JS_ATOM_NULL)\n        goto fail;\n    me = find_export_entry(ctx, m, name);\n    JS_FreeAtom(ctx, name);\n    if (!me)\n        goto fail;\n    set_value(ctx, me->u.local.var_ref->pvalue, val);\n    return 0;\n fail:\n    JS_FreeValue(ctx, val);\n    return -1;\n}\n\nint JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val)\n{\n    set_value(ctx, &m->private_value, val);\n    return 0;\n}\n\nJSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m)\n{\n    return JS_DupValue(ctx, m->private_value);\n}\n\nvoid JS_SetModuleLoaderFunc(JSRuntime *rt,\n                            JSModuleNormalizeFunc *module_normalize,\n                            JSModuleLoaderFunc *module_loader, void *opaque)\n{\n    rt->module_normalize_func = module_normalize;\n    rt->module_loader_has_attr = FALSE;\n    rt->u.module_loader_func = module_loader;\n    rt->module_check_attrs = NULL;\n    rt->module_loader_opaque = opaque;\n}\n\nvoid JS_SetModuleLoaderFunc2(JSRuntime *rt,\n                             JSModuleNormalizeFunc *module_normalize,\n                             JSModuleLoaderFunc2 *module_loader,\n                             JSModuleCheckSupportedImportAttributes *module_check_attrs,\n                             void *opaque)\n{\n    rt->module_normalize_func = module_normalize;\n    rt->module_loader_has_attr = TRUE;\n    rt->u.module_loader_func2 = module_loader;\n    rt->module_check_attrs = module_check_attrs;\n    rt->module_loader_opaque = opaque;\n}\n\n/* default module filename normalizer */\nstatic char *js_default_module_normalize_name(JSContext *ctx,\n                                              const char *base_name,\n                                              const char *name)\n{\n    char *filename, *p;\n    const char *r;\n    int cap;\n    int len;\n\n    if (name[0] != '.') {\n        /* if no initial dot, the module name is not modified */\n        return js_strdup(ctx, name);\n    }\n\n    p = strrchr(base_name, '/');\n    if (p)\n        len = p - base_name;\n    else\n        len = 0;\n\n    cap = len + strlen(name) + 1 + 1;\n    filename = js_malloc(ctx, cap);\n    if (!filename)\n        return NULL;\n    memcpy(filename, base_name, len);\n    filename[len] = '\\0';\n\n    /* we only normalize the leading '..' or '.' */\n    r = name;\n    for(;;) {\n        if (r[0] == '.' && r[1] == '/') {\n            r += 2;\n        } else if (r[0] == '.' && r[1] == '.' && r[2] == '/') {\n            /* remove the last path element of filename, except if \".\"\n               or \"..\" */\n            if (filename[0] == '\\0')\n                break;\n            p = strrchr(filename, '/');\n            if (!p)\n                p = filename;\n            else\n                p++;\n            if (!strcmp(p, \".\") || !strcmp(p, \"..\"))\n                break;\n            if (p > filename)\n                p--;\n            *p = '\\0';\n            r += 3;\n        } else {\n            break;\n        }\n    }\n    if (filename[0] != '\\0')\n        pstrcat(filename, cap, \"/\");\n    pstrcat(filename, cap, r);\n    //    printf(\"normalize: %s %s -> %s\\n\", base_name, name, filename);\n    return filename;\n}\n\nstatic JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name)\n{\n    struct list_head *el;\n    JSModuleDef *m;\n\n    /* first look at the loaded modules */\n    list_for_each(el, &ctx->loaded_modules) {\n        m = list_entry(el, JSModuleDef, link);\n        if (m->module_name == name)\n            return m;\n    }\n    return NULL;\n}\n\n/* return NULL in case of exception (e.g. module could not be loaded) */\nstatic JSModuleDef *js_host_resolve_imported_module(JSContext *ctx,\n                                                    const char *base_cname,\n                                                    const char *cname1,\n                                                    JSValueConst attributes)\n{\n    JSRuntime *rt = ctx->rt;\n    JSModuleDef *m;\n    char *cname;\n    JSAtom module_name;\n\n    if (!rt->module_normalize_func) {\n        cname = js_default_module_normalize_name(ctx, base_cname, cname1);\n    } else {\n        cname = rt->module_normalize_func(ctx, base_cname, cname1,\n                                          rt->module_loader_opaque);\n    }\n    if (!cname)\n        return NULL;\n\n    module_name = JS_NewAtom(ctx, cname);\n    if (module_name == JS_ATOM_NULL) {\n        js_free(ctx, cname);\n        return NULL;\n    }\n\n    /* first look at the loaded modules */\n    m = js_find_loaded_module(ctx, module_name);\n    if (m) {\n        js_free(ctx, cname);\n        JS_FreeAtom(ctx, module_name);\n        return m;\n    }\n\n    JS_FreeAtom(ctx, module_name);\n\n    /* load the module */\n    if (!rt->u.module_loader_func) {\n        /* XXX: use a syntax error ? */\n        JS_ThrowReferenceError(ctx, \"could not load module '%s'\",\n                               cname);\n        js_free(ctx, cname);\n        return NULL;\n    }\n    if (rt->module_loader_has_attr) {\n        m = rt->u.module_loader_func2(ctx, cname, rt->module_loader_opaque, attributes);\n    } else {\n        m = rt->u.module_loader_func(ctx, cname, rt->module_loader_opaque);\n    }\n    js_free(ctx, cname);\n    return m;\n}\n\nstatic JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx,\n                                                         JSAtom base_module_name,\n                                                         JSAtom module_name1,\n                                                         JSValueConst attributes)\n{\n    const char *base_cname, *cname;\n    JSModuleDef *m;\n\n    base_cname = JS_AtomToCString(ctx, base_module_name);\n    if (!base_cname)\n        return NULL;\n    cname = JS_AtomToCString(ctx, module_name1);\n    if (!cname) {\n        JS_FreeCString(ctx, base_cname);\n        return NULL;\n    }\n    m = js_host_resolve_imported_module(ctx, base_cname, cname, attributes);\n    JS_FreeCString(ctx, base_cname);\n    JS_FreeCString(ctx, cname);\n    return m;\n}\n\ntypedef struct JSResolveEntry {\n    JSModuleDef *module;\n    JSAtom name;\n} JSResolveEntry;\n\ntypedef struct JSResolveState {\n    JSResolveEntry *array;\n    int size;\n    int count;\n} JSResolveState;\n\nstatic int find_resolve_entry(JSResolveState *s,\n                              JSModuleDef *m, JSAtom name)\n{\n    int i;\n    for(i = 0; i < s->count; i++) {\n        JSResolveEntry *re = &s->array[i];\n        if (re->module == m && re->name == name)\n            return i;\n    }\n    return -1;\n}\n\nstatic int add_resolve_entry(JSContext *ctx, JSResolveState *s,\n                             JSModuleDef *m, JSAtom name)\n{\n    JSResolveEntry *re;\n\n    if (js_resize_array(ctx, (void **)&s->array,\n                        sizeof(JSResolveEntry),\n                        &s->size, s->count + 1))\n        return -1;\n    re = &s->array[s->count++];\n    re->module = m;\n    re->name = JS_DupAtom(ctx, name);\n    return 0;\n}\n\ntypedef enum JSResolveResultEnum {\n    JS_RESOLVE_RES_EXCEPTION = -1, /* memory alloc error */\n    JS_RESOLVE_RES_FOUND = 0,\n    JS_RESOLVE_RES_NOT_FOUND,\n    JS_RESOLVE_RES_CIRCULAR,\n    JS_RESOLVE_RES_AMBIGUOUS,\n} JSResolveResultEnum;\n\nstatic JSResolveResultEnum js_resolve_export1(JSContext *ctx,\n                                              JSModuleDef **pmodule,\n                                              JSExportEntry **pme,\n                                              JSModuleDef *m,\n                                              JSAtom export_name,\n                                              JSResolveState *s)\n{\n    JSExportEntry *me;\n\n    *pmodule = NULL;\n    *pme = NULL;\n    if (find_resolve_entry(s, m, export_name) >= 0)\n        return JS_RESOLVE_RES_CIRCULAR;\n    if (add_resolve_entry(ctx, s, m, export_name) < 0)\n        return JS_RESOLVE_RES_EXCEPTION;\n    me = find_export_entry(ctx, m, export_name);\n    if (me) {\n        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {\n            /* local export */\n            *pmodule = m;\n            *pme = me;\n            return JS_RESOLVE_RES_FOUND;\n        } else {\n            /* indirect export */\n            JSModuleDef *m1;\n            m1 = m->req_module_entries[me->u.req_module_idx].module;\n            if (me->local_name == JS_ATOM__star_) {\n                /* export ns from */\n                *pmodule = m;\n                *pme = me;\n                return JS_RESOLVE_RES_FOUND;\n            } else {\n                return js_resolve_export1(ctx, pmodule, pme, m1,\n                                          me->local_name, s);\n            }\n        }\n    } else {\n        if (export_name != JS_ATOM_default) {\n            /* not found in direct or indirect exports: try star exports */\n            int i;\n\n            for(i = 0; i < m->star_export_entries_count; i++) {\n                JSStarExportEntry *se = &m->star_export_entries[i];\n                JSModuleDef *m1, *res_m;\n                JSExportEntry *res_me;\n                JSResolveResultEnum ret;\n\n                m1 = m->req_module_entries[se->req_module_idx].module;\n                ret = js_resolve_export1(ctx, &res_m, &res_me, m1,\n                                         export_name, s);\n                if (ret == JS_RESOLVE_RES_AMBIGUOUS ||\n                    ret == JS_RESOLVE_RES_EXCEPTION) {\n                    return ret;\n                } else if (ret == JS_RESOLVE_RES_FOUND) {\n                    if (*pme != NULL) {\n                        if (*pmodule != res_m ||\n                            res_me->local_name != (*pme)->local_name) {\n                            *pmodule = NULL;\n                            *pme = NULL;\n                            return JS_RESOLVE_RES_AMBIGUOUS;\n                        }\n                    } else {\n                        *pmodule = res_m;\n                        *pme = res_me;\n                    }\n                }\n            }\n            if (*pme != NULL)\n                return JS_RESOLVE_RES_FOUND;\n        }\n        return JS_RESOLVE_RES_NOT_FOUND;\n    }\n}\n\n/* If the return value is JS_RESOLVE_RES_FOUND, return the module\n  (*pmodule) and the corresponding local export entry\n  (*pme). Otherwise return (NULL, NULL) */\nstatic JSResolveResultEnum js_resolve_export(JSContext *ctx,\n                                             JSModuleDef **pmodule,\n                                             JSExportEntry **pme,\n                                             JSModuleDef *m,\n                                             JSAtom export_name)\n{\n    JSResolveState ss, *s = &ss;\n    int i;\n    JSResolveResultEnum ret;\n\n    s->array = NULL;\n    s->size = 0;\n    s->count = 0;\n\n    ret = js_resolve_export1(ctx, pmodule, pme, m, export_name, s);\n\n    for(i = 0; i < s->count; i++)\n        JS_FreeAtom(ctx, s->array[i].name);\n    js_free(ctx, s->array);\n\n    return ret;\n}\n\nstatic void js_resolve_export_throw_error(JSContext *ctx,\n                                          JSResolveResultEnum res,\n                                          JSModuleDef *m, JSAtom export_name)\n{\n    char buf1[ATOM_GET_STR_BUF_SIZE];\n    char buf2[ATOM_GET_STR_BUF_SIZE];\n    switch(res) {\n    case JS_RESOLVE_RES_EXCEPTION:\n        break;\n    default:\n    case JS_RESOLVE_RES_NOT_FOUND:\n        JS_ThrowSyntaxError(ctx, \"Could not find export '%s' in module '%s'\",\n                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),\n                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));\n        break;\n    case JS_RESOLVE_RES_CIRCULAR:\n        JS_ThrowSyntaxError(ctx, \"circular reference when looking for export '%s' in module '%s'\",\n                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),\n                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));\n        break;\n    case JS_RESOLVE_RES_AMBIGUOUS:\n        JS_ThrowSyntaxError(ctx, \"export '%s' in module '%s' is ambiguous\",\n                            JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),\n                            JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));\n        break;\n    }\n}\n\n\ntypedef enum {\n    EXPORTED_NAME_AMBIGUOUS,\n    EXPORTED_NAME_NORMAL,\n    EXPORTED_NAME_DELAYED,\n} ExportedNameEntryEnum;\n\ntypedef struct ExportedNameEntry {\n    JSAtom export_name;\n    ExportedNameEntryEnum export_type;\n    union {\n        JSExportEntry *me; /* using when the list is built */\n        JSVarRef *var_ref; /* EXPORTED_NAME_NORMAL */\n    } u;\n} ExportedNameEntry;\n\ntypedef struct GetExportNamesState {\n    JSModuleDef **modules;\n    int modules_size;\n    int modules_count;\n\n    ExportedNameEntry *exported_names;\n    int exported_names_size;\n    int exported_names_count;\n} GetExportNamesState;\n\nstatic int find_exported_name(GetExportNamesState *s, JSAtom name)\n{\n    int i;\n    for(i = 0; i < s->exported_names_count; i++) {\n        if (s->exported_names[i].export_name == name)\n            return i;\n    }\n    return -1;\n}\n\nstatic __exception int get_exported_names(JSContext *ctx,\n                                          GetExportNamesState *s,\n                                          JSModuleDef *m, BOOL from_star)\n{\n    ExportedNameEntry *en;\n    int i, j;\n\n    /* check circular reference */\n    for(i = 0; i < s->modules_count; i++) {\n        if (s->modules[i] == m)\n            return 0;\n    }\n    if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),\n                        &s->modules_size, s->modules_count + 1))\n        return -1;\n    s->modules[s->modules_count++] = m;\n\n    for(i = 0; i < m->export_entries_count; i++) {\n        JSExportEntry *me = &m->export_entries[i];\n        if (from_star && me->export_name == JS_ATOM_default)\n            continue;\n        j = find_exported_name(s, me->export_name);\n        if (j < 0) {\n            if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),\n                                &s->exported_names_size,\n                                s->exported_names_count + 1))\n                return -1;\n            en = &s->exported_names[s->exported_names_count++];\n            en->export_name = me->export_name;\n            /* avoid a second lookup for simple module exports */\n            if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)\n                en->u.me = NULL;\n            else\n                en->u.me = me;\n        } else {\n            en = &s->exported_names[j];\n            en->u.me = NULL;\n        }\n    }\n    for(i = 0; i < m->star_export_entries_count; i++) {\n        JSStarExportEntry *se = &m->star_export_entries[i];\n        JSModuleDef *m1;\n        m1 = m->req_module_entries[se->req_module_idx].module;\n        if (get_exported_names(ctx, s, m1, TRUE))\n            return -1;\n    }\n    return 0;\n}\n\n/* Unfortunately, the spec gives a different behavior from GetOwnProperty ! */\nstatic int js_module_ns_has(JSContext *ctx, JSValueConst obj, JSAtom atom)\n{\n    return (find_own_property1(JS_VALUE_GET_OBJ(obj), atom) != NULL);\n}\n\nstatic const JSClassExoticMethods js_module_ns_exotic_methods = {\n    .has_property = js_module_ns_has,\n};\n\nstatic int exported_names_cmp(const void *p1, const void *p2, void *opaque)\n{\n    JSContext *ctx = opaque;\n    const ExportedNameEntry *me1 = p1;\n    const ExportedNameEntry *me2 = p2;\n    JSValue str1, str2;\n    int ret;\n\n    /* XXX: should avoid allocation memory in atom comparison */\n    str1 = JS_AtomToString(ctx, me1->export_name);\n    str2 = JS_AtomToString(ctx, me2->export_name);\n    if (JS_IsException(str1) || JS_IsException(str2)) {\n        /* XXX: raise an error ? */\n        ret = 0;\n    } else {\n        ret = js_string_compare(ctx, JS_VALUE_GET_STRING(str1),\n                                JS_VALUE_GET_STRING(str2));\n    }\n    JS_FreeValue(ctx, str1);\n    JS_FreeValue(ctx, str2);\n    return ret;\n}\n\nstatic JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,\n                                     void *opaque)\n{\n    JSModuleDef *m = opaque;\n    JSResolveResultEnum res;\n    JSExportEntry *res_me;\n    JSModuleDef *res_m;\n    JSVarRef *var_ref;\n\n    res = js_resolve_export(ctx, &res_m, &res_me, m, atom);\n    if (res != JS_RESOLVE_RES_FOUND) {\n        /* fail safe: normally no error should happen here except for memory */\n        js_resolve_export_throw_error(ctx, res, m, atom);\n        return JS_EXCEPTION;\n    }\n    if (res_me->local_name == JS_ATOM__star_) {\n        return JS_GetModuleNamespace(ctx, res_m->req_module_entries[res_me->u.req_module_idx].module);\n    } else {\n        if (res_me->u.local.var_ref) {\n            var_ref = res_me->u.local.var_ref;\n        } else {\n            JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);\n            var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];\n        }\n        /* WARNING: a varref is returned as a string ! */\n        return JS_MKPTR(JS_TAG_STRING, var_ref);\n    }\n}\n\nstatic JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)\n{\n    JSValue obj;\n    JSObject *p;\n    GetExportNamesState s_s, *s = &s_s;\n    int i, ret;\n    JSProperty *pr;\n\n    obj = JS_NewObjectClass(ctx, JS_CLASS_MODULE_NS);\n    if (JS_IsException(obj))\n        return obj;\n    p = JS_VALUE_GET_OBJ(obj);\n\n    memset(s, 0, sizeof(*s));\n    ret = get_exported_names(ctx, s, m, FALSE);\n    js_free(ctx, s->modules);\n    if (ret)\n        goto fail;\n\n    /* Resolve the exported names. The ambiguous exports are removed */\n    for(i = 0; i < s->exported_names_count; i++) {\n        ExportedNameEntry *en = &s->exported_names[i];\n        JSResolveResultEnum res;\n        JSExportEntry *res_me;\n        JSModuleDef *res_m;\n\n        if (en->u.me) {\n            res_me = en->u.me; /* fast case: no resolution needed */\n            res_m = m;\n            res = JS_RESOLVE_RES_FOUND;\n        } else {\n            res = js_resolve_export(ctx, &res_m, &res_me, m,\n                                    en->export_name);\n        }\n        if (res != JS_RESOLVE_RES_FOUND) {\n            if (res != JS_RESOLVE_RES_AMBIGUOUS) {\n                js_resolve_export_throw_error(ctx, res, m, en->export_name);\n                goto fail;\n            }\n            en->export_type = EXPORTED_NAME_AMBIGUOUS;\n        } else {\n            if (res_me->local_name == JS_ATOM__star_) {\n                en->export_type = EXPORTED_NAME_DELAYED;\n            } else {\n                if (res_me->u.local.var_ref) {\n                    en->u.var_ref = res_me->u.local.var_ref;\n                } else {\n                    JSObject *p1 = JS_VALUE_GET_OBJ(res_m->func_obj);\n                    en->u.var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];\n                }\n                if (en->u.var_ref == NULL)\n                    en->export_type = EXPORTED_NAME_DELAYED;\n                else\n                    en->export_type = EXPORTED_NAME_NORMAL;\n            }\n        }\n    }\n\n    /* sort the exported names */\n    rqsort(s->exported_names, s->exported_names_count,\n           sizeof(s->exported_names[0]), exported_names_cmp, ctx);\n\n    for(i = 0; i < s->exported_names_count; i++) {\n        ExportedNameEntry *en = &s->exported_names[i];\n        switch(en->export_type) {\n        case EXPORTED_NAME_NORMAL:\n            {\n                JSVarRef *var_ref = en->u.var_ref;\n                pr = add_property(ctx, p, en->export_name,\n                                  JS_PROP_ENUMERABLE | JS_PROP_WRITABLE |\n                                  JS_PROP_VARREF);\n                if (!pr)\n                    goto fail;\n                var_ref->header.ref_count++;\n                pr->u.var_ref = var_ref;\n            }\n            break;\n        case EXPORTED_NAME_DELAYED:\n            /* the exported namespace or reference may depend on\n               circular references, so we resolve it lazily */\n            if (JS_DefineAutoInitProperty(ctx, obj,\n                                          en->export_name,\n                                          JS_AUTOINIT_ID_MODULE_NS,\n                                          m, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)\n                goto fail;\n            break;\n        default:\n            break;\n        }\n    }\n\n    js_free(ctx, s->exported_names);\n\n    JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_toStringTag,\n                           JS_AtomToString(ctx, JS_ATOM_Module),\n                           0);\n\n    p->extensible = FALSE;\n    return obj;\n fail:\n    js_free(ctx, s->exported_names);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nJSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m)\n{\n    if (JS_IsUndefined(m->module_ns)) {\n        JSValue val;\n        val = js_build_module_ns(ctx, m);\n        if (JS_IsException(val))\n            return JS_EXCEPTION;\n        m->module_ns = val;\n    }\n    return JS_DupValue(ctx, m->module_ns);\n}\n\n/* Load all the required modules for module 'm' */\nstatic int js_resolve_module(JSContext *ctx, JSModuleDef *m)\n{\n    int i;\n    JSModuleDef *m1;\n\n    if (m->resolved)\n        return 0;\n#ifdef DUMP_MODULE_RESOLVE\n    {\n        char buf1[ATOM_GET_STR_BUF_SIZE];\n        printf(\"resolving module '%s':\\n\", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));\n    }\n#endif\n    m->resolved = TRUE;\n    /* resolve each requested module */\n    for(i = 0; i < m->req_module_entries_count; i++) {\n        JSReqModuleEntry *rme = &m->req_module_entries[i];\n        m1 = js_host_resolve_imported_module_atom(ctx, m->module_name,\n                                                  rme->module_name,\n                                                  rme->attributes);\n        if (!m1)\n            return -1;\n        rme->module = m1;\n        /* already done in js_host_resolve_imported_module() except if\n           the module was loaded with JS_EvalBinary() */\n        if (js_resolve_module(ctx, m1) < 0)\n            return -1;\n    }\n    return 0;\n}\n\n/* Create the <eval> function associated with the module */\nstatic int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)\n{\n    JSFunctionBytecode *b;\n    JSValue func_obj, bfunc;\n\n    bfunc = m->func_obj;\n    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,\n                                      JS_CLASS_BYTECODE_FUNCTION);\n\n    if (JS_IsException(func_obj))\n        return -1;\n    m->func_obj = func_obj;\n    b = JS_VALUE_GET_PTR(bfunc);\n    func_obj = js_closure2(ctx, func_obj, b, NULL, NULL, TRUE, m);\n    if (JS_IsException(func_obj)) {\n        m->func_obj = JS_UNDEFINED; /* XXX: keep it ? */\n        JS_FreeValue(ctx, func_obj);\n        return -1;\n    }\n    return 0;\n}\n\n/* must be done before js_link_module() because of cyclic references */\nstatic int js_create_module_function(JSContext *ctx, JSModuleDef *m)\n{\n    BOOL is_c_module;\n    int i;\n    JSVarRef *var_ref;\n\n    if (m->func_created)\n        return 0;\n\n    is_c_module = (m->init_func != NULL);\n\n    if (is_c_module) {\n        /* initialize the exported variables */\n        for(i = 0; i < m->export_entries_count; i++) {\n            JSExportEntry *me = &m->export_entries[i];\n            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {\n                var_ref = js_create_var_ref(ctx, FALSE);\n                if (!var_ref)\n                    return -1;\n                me->u.local.var_ref = var_ref;\n            }\n        }\n    } else {\n        if (js_create_module_bytecode_function(ctx, m))\n            return -1;\n    }\n    m->func_created = TRUE;\n\n    /* do it on the dependencies */\n\n    for(i = 0; i < m->req_module_entries_count; i++) {\n        JSReqModuleEntry *rme = &m->req_module_entries[i];\n        if (js_create_module_function(ctx, rme->module) < 0)\n            return -1;\n    }\n\n    return 0;\n}\n\n\n/* Prepare a module to be executed by resolving all the imported\n   variables. */\nstatic int js_inner_module_linking(JSContext *ctx, JSModuleDef *m,\n                                   JSModuleDef **pstack_top, int index)\n{\n    int i;\n    JSImportEntry *mi;\n    JSModuleDef *m1;\n    JSVarRef **var_refs, *var_ref;\n    JSObject *p;\n    BOOL is_c_module;\n    JSValue ret_val;\n\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        JS_ThrowStackOverflow(ctx);\n        return -1;\n    }\n\n#ifdef DUMP_MODULE_RESOLVE\n    {\n        char buf1[ATOM_GET_STR_BUF_SIZE];\n        printf(\"js_inner_module_linking '%s':\\n\", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));\n    }\n#endif\n\n    if (m->status == JS_MODULE_STATUS_LINKING ||\n        m->status == JS_MODULE_STATUS_LINKED ||\n        m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n        m->status == JS_MODULE_STATUS_EVALUATED)\n        return index;\n\n    assert(m->status == JS_MODULE_STATUS_UNLINKED);\n    m->status = JS_MODULE_STATUS_LINKING;\n    m->dfs_index = index;\n    m->dfs_ancestor_index = index;\n    index++;\n    /* push 'm' on stack */\n    m->stack_prev = *pstack_top;\n    *pstack_top = m;\n\n    for(i = 0; i < m->req_module_entries_count; i++) {\n        JSReqModuleEntry *rme = &m->req_module_entries[i];\n        m1 = rme->module;\n        index = js_inner_module_linking(ctx, m1, pstack_top, index);\n        if (index < 0)\n            goto fail;\n        assert(m1->status == JS_MODULE_STATUS_LINKING ||\n               m1->status == JS_MODULE_STATUS_LINKED ||\n               m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n               m1->status == JS_MODULE_STATUS_EVALUATED);\n        if (m1->status == JS_MODULE_STATUS_LINKING) {\n            m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,\n                                            m1->dfs_ancestor_index);\n        }\n    }\n\n#ifdef DUMP_MODULE_RESOLVE\n    {\n        char buf1[ATOM_GET_STR_BUF_SIZE];\n        printf(\"instantiating module '%s':\\n\", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));\n    }\n#endif\n    /* check the indirect exports */\n    for(i = 0; i < m->export_entries_count; i++) {\n        JSExportEntry *me = &m->export_entries[i];\n        if (me->export_type == JS_EXPORT_TYPE_INDIRECT &&\n            me->local_name != JS_ATOM__star_) {\n            JSResolveResultEnum ret;\n            JSExportEntry *res_me;\n            JSModuleDef *res_m, *m1;\n            m1 = m->req_module_entries[me->u.req_module_idx].module;\n            ret = js_resolve_export(ctx, &res_m, &res_me, m1, me->local_name);\n            if (ret != JS_RESOLVE_RES_FOUND) {\n                js_resolve_export_throw_error(ctx, ret, m, me->export_name);\n                goto fail;\n            }\n        }\n    }\n\n#ifdef DUMP_MODULE_RESOLVE\n    {\n        printf(\"exported bindings:\\n\");\n        for(i = 0; i < m->export_entries_count; i++) {\n            JSExportEntry *me = &m->export_entries[i];\n            printf(\" name=\"); print_atom(ctx, me->export_name);\n            printf(\" local=\"); print_atom(ctx, me->local_name);\n            printf(\" type=%d idx=%d\\n\", me->export_type, me->u.local.var_idx);\n        }\n    }\n#endif\n\n    is_c_module = (m->init_func != NULL);\n\n    if (!is_c_module) {\n        p = JS_VALUE_GET_OBJ(m->func_obj);\n        var_refs = p->u.func.var_refs;\n\n        for(i = 0; i < m->import_entries_count; i++) {\n            mi = &m->import_entries[i];\n#ifdef DUMP_MODULE_RESOLVE\n            printf(\"import var_idx=%d name=\", mi->var_idx);\n            print_atom(ctx, mi->import_name);\n            printf(\": \");\n#endif\n            m1 = m->req_module_entries[mi->req_module_idx].module;\n            if (mi->is_star) {\n                JSValue val;\n                /* name space import */\n                val = JS_GetModuleNamespace(ctx, m1);\n                if (JS_IsException(val))\n                    goto fail;\n                set_value(ctx, &var_refs[mi->var_idx]->value, val);\n#ifdef DUMP_MODULE_RESOLVE\n                printf(\"namespace\\n\");\n#endif\n            } else {\n                JSResolveResultEnum ret;\n                JSExportEntry *res_me;\n                JSModuleDef *res_m;\n                JSObject *p1;\n\n                ret = js_resolve_export(ctx, &res_m,\n                                        &res_me, m1, mi->import_name);\n                if (ret != JS_RESOLVE_RES_FOUND) {\n                    js_resolve_export_throw_error(ctx, ret, m1, mi->import_name);\n                    goto fail;\n                }\n                if (res_me->local_name == JS_ATOM__star_) {\n                    JSValue val;\n                    JSModuleDef *m2;\n                    /* name space import from */\n                    m2 = res_m->req_module_entries[res_me->u.req_module_idx].module;\n                    val = JS_GetModuleNamespace(ctx, m2);\n                    if (JS_IsException(val))\n                        goto fail;\n                    var_ref = js_create_var_ref(ctx, TRUE);\n                    if (!var_ref) {\n                        JS_FreeValue(ctx, val);\n                        goto fail;\n                    }\n                    set_value(ctx, &var_ref->value, val);\n                    var_refs[mi->var_idx] = var_ref;\n#ifdef DUMP_MODULE_RESOLVE\n                    printf(\"namespace from\\n\");\n#endif\n                } else {\n                    var_ref = res_me->u.local.var_ref;\n                    if (!var_ref) {\n                        p1 = JS_VALUE_GET_OBJ(res_m->func_obj);\n                        var_ref = p1->u.func.var_refs[res_me->u.local.var_idx];\n                    }\n                    var_ref->header.ref_count++;\n                    var_refs[mi->var_idx] = var_ref;\n#ifdef DUMP_MODULE_RESOLVE\n                    printf(\"local export (var_ref=%p)\\n\", var_ref);\n#endif\n                }\n            }\n        }\n\n        /* keep the exported variables in the module export entries (they\n           are used when the eval function is deleted and cannot be\n           initialized before in case imports are exported) */\n        for(i = 0; i < m->export_entries_count; i++) {\n            JSExportEntry *me = &m->export_entries[i];\n            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {\n                var_ref = var_refs[me->u.local.var_idx];\n                var_ref->header.ref_count++;\n                me->u.local.var_ref = var_ref;\n            }\n        }\n\n        /* initialize the global variables */\n        ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);\n        if (JS_IsException(ret_val))\n            goto fail;\n        JS_FreeValue(ctx, ret_val);\n    }\n\n    assert(m->dfs_ancestor_index <= m->dfs_index);\n    if (m->dfs_index == m->dfs_ancestor_index) {\n        for(;;) {\n            /* pop m1 from stack */\n            m1 = *pstack_top;\n            *pstack_top = m1->stack_prev;\n            m1->status = JS_MODULE_STATUS_LINKED;\n            if (m1 == m)\n                break;\n        }\n    }\n\n#ifdef DUMP_MODULE_RESOLVE\n    printf(\"js_inner_module_linking done\\n\");\n#endif\n    return index;\n fail:\n    return -1;\n}\n\n/* Prepare a module to be executed by resolving all the imported\n   variables. */\nstatic int js_link_module(JSContext *ctx, JSModuleDef *m)\n{\n    JSModuleDef *stack_top, *m1;\n\n#ifdef DUMP_MODULE_RESOLVE\n    {\n        char buf1[ATOM_GET_STR_BUF_SIZE];\n        printf(\"js_link_module '%s':\\n\", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));\n    }\n#endif\n    assert(m->status == JS_MODULE_STATUS_UNLINKED ||\n           m->status == JS_MODULE_STATUS_LINKED ||\n           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n           m->status == JS_MODULE_STATUS_EVALUATED);\n    stack_top = NULL;\n    if (js_inner_module_linking(ctx, m, &stack_top, 0) < 0) {\n        while (stack_top != NULL) {\n            m1 = stack_top;\n            assert(m1->status == JS_MODULE_STATUS_LINKING);\n            m1->status = JS_MODULE_STATUS_UNLINKED;\n            stack_top = m1->stack_prev;\n        }\n        return -1;\n    }\n    assert(stack_top == NULL);\n    assert(m->status == JS_MODULE_STATUS_LINKED ||\n           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n           m->status == JS_MODULE_STATUS_EVALUATED);\n    return 0;\n}\n\n/* return JS_ATOM_NULL if the name cannot be found. Only works with\n   not striped bytecode functions. */\nJSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels)\n{\n    JSStackFrame *sf;\n    JSFunctionBytecode *b;\n    JSObject *p;\n    /* XXX: currently we just use the filename of the englobing\n       function from the debug info. May need to add a ScriptOrModule\n       info in JSFunctionBytecode. */\n    sf = ctx->rt->current_stack_frame;\n    if (!sf)\n        return JS_ATOM_NULL;\n    while (n_stack_levels-- > 0) {\n        sf = sf->prev_frame;\n        if (!sf)\n            return JS_ATOM_NULL;\n    }\n    for(;;) {\n        if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT)\n            return JS_ATOM_NULL;\n        p = JS_VALUE_GET_OBJ(sf->cur_func);\n        if (!js_class_has_bytecode(p->class_id))\n            return JS_ATOM_NULL;\n        b = p->u.func.function_bytecode;\n        if (!b->is_direct_or_indirect_eval) {\n            if (!b->has_debug)\n                return JS_ATOM_NULL;\n            return JS_DupAtom(ctx, b->debug.filename);\n        } else {\n            sf = sf->prev_frame;\n            if (!sf)\n                return JS_ATOM_NULL;\n        }\n    }\n}\n\nJSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m)\n{\n    return JS_DupAtom(ctx, m->module_name);\n}\n\nJSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m)\n{\n    JSValue obj;\n    /* allocate meta_obj only if requested to save memory */\n    obj = m->meta_obj;\n    if (JS_IsUndefined(obj)) {\n        obj = JS_NewObjectProto(ctx, JS_NULL);\n        if (JS_IsException(obj))\n            return JS_EXCEPTION;\n        m->meta_obj = obj;\n    }\n    return JS_DupValue(ctx, obj);\n}\n\nstatic JSValue js_import_meta(JSContext *ctx)\n{\n    JSAtom filename;\n    JSModuleDef *m;\n\n    filename = JS_GetScriptOrModuleName(ctx, 0);\n    if (filename == JS_ATOM_NULL)\n        goto fail;\n\n    /* XXX: inefficient, need to add a module or script pointer in\n       JSFunctionBytecode */\n    m = js_find_loaded_module(ctx, filename);\n    JS_FreeAtom(ctx, filename);\n    if (!m) {\n    fail:\n        JS_ThrowTypeError(ctx, \"import.meta not supported in this context\");\n        return JS_EXCEPTION;\n    }\n    return JS_GetImportMeta(ctx, m);\n}\n\nstatic JSValue JS_NewModuleValue(JSContext *ctx, JSModuleDef *m)\n{\n    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));\n}\n\nstatic JSValue js_load_module_rejected(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv, int magic, JSValue *func_data)\n{\n    JSValueConst *resolving_funcs = (JSValueConst *)func_data;\n    JSValueConst error;\n    JSValue ret;\n\n    /* XXX: check if the test is necessary */\n    if (argc >= 1)\n        error = argv[0];\n    else\n        error = JS_UNDEFINED;\n    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,\n                  1, &error);\n    JS_FreeValue(ctx, ret);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv, int magic, JSValue *func_data)\n{\n    JSValueConst *resolving_funcs = (JSValueConst *)func_data;\n    JSModuleDef *m = JS_VALUE_GET_PTR(func_data[2]);\n    JSValue ret, ns;\n\n    /* return the module namespace */\n    ns = JS_GetModuleNamespace(ctx, m);\n    if (JS_IsException(ns)) {\n        JSValue err = JS_GetException(ctx);\n        js_load_module_rejected(ctx, JS_UNDEFINED, 1, (JSValueConst *)&err, 0, func_data);\n        return JS_UNDEFINED;\n    }\n    ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,\n                   1, (JSValueConst *)&ns);\n    JS_FreeValue(ctx, ret);\n    JS_FreeValue(ctx, ns);\n    return JS_UNDEFINED;\n}\n\nstatic void JS_LoadModuleInternal(JSContext *ctx, const char *basename,\n                                  const char *filename,\n                                  JSValueConst *resolving_funcs,\n                                  JSValueConst attributes)\n{\n    JSValue evaluate_promise;\n    JSModuleDef *m;\n    JSValue ret, err, func_obj, evaluate_resolving_funcs[2];\n    JSValueConst func_data[3];\n\n    m = js_host_resolve_imported_module(ctx, basename, filename, attributes);\n    if (!m)\n        goto fail;\n\n    if (js_resolve_module(ctx, m) < 0) {\n        js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);\n        goto fail;\n    }\n\n    /* Evaluate the module code */\n    func_obj = JS_NewModuleValue(ctx, m);\n    evaluate_promise = JS_EvalFunction(ctx, func_obj);\n    if (JS_IsException(evaluate_promise)) {\n    fail:\n        err = JS_GetException(ctx);\n        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,\n                      1, (JSValueConst *)&err);\n        JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */\n        JS_FreeValue(ctx, err);\n        return;\n    }\n\n    func_obj = JS_NewModuleValue(ctx, m);\n    func_data[0] = resolving_funcs[0];\n    func_data[1] = resolving_funcs[1];\n    func_data[2] = func_obj;\n    evaluate_resolving_funcs[0] = JS_NewCFunctionData(ctx, js_load_module_fulfilled, 0, 0, 3, func_data);\n    evaluate_resolving_funcs[1] = JS_NewCFunctionData(ctx, js_load_module_rejected, 0, 0, 3, func_data);\n    JS_FreeValue(ctx, func_obj);\n    ret = js_promise_then(ctx, evaluate_promise, 2, (JSValueConst *)evaluate_resolving_funcs);\n    JS_FreeValue(ctx, ret);\n    JS_FreeValue(ctx, evaluate_resolving_funcs[0]);\n    JS_FreeValue(ctx, evaluate_resolving_funcs[1]);\n    JS_FreeValue(ctx, evaluate_promise);\n}\n\n/* Return a promise or an exception in case of memory error. Used by\n   os.Worker() */\nJSValue JS_LoadModule(JSContext *ctx, const char *basename,\n                      const char *filename)\n{\n    JSValue promise, resolving_funcs[2];\n\n    promise = JS_NewPromiseCapability(ctx, resolving_funcs);\n    if (JS_IsException(promise))\n        return JS_EXCEPTION;\n    JS_LoadModuleInternal(ctx, basename, filename,\n                          (JSValueConst *)resolving_funcs, JS_UNDEFINED);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    return promise;\n}\n\nstatic JSValue js_dynamic_import_job(JSContext *ctx,\n                                     int argc, JSValueConst *argv)\n{\n    JSValueConst *resolving_funcs = argv;\n    JSValueConst basename_val = argv[2];\n    JSValueConst specifier = argv[3];\n    JSValueConst attributes = argv[4];\n    const char *basename = NULL, *filename;\n    JSValue ret, err;\n\n    if (!JS_IsString(basename_val)) {\n        JS_ThrowTypeError(ctx, \"no function filename for import()\");\n        goto exception;\n    }\n    basename = JS_ToCString(ctx, basename_val);\n    if (!basename)\n        goto exception;\n\n    filename = JS_ToCString(ctx, specifier);\n    if (!filename)\n        goto exception;\n\n    JS_LoadModuleInternal(ctx, basename, filename,\n                          resolving_funcs, attributes);\n    JS_FreeCString(ctx, filename);\n    JS_FreeCString(ctx, basename);\n    return JS_UNDEFINED;\n exception:\n    err = JS_GetException(ctx);\n    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,\n                   1, (JSValueConst *)&err);\n    JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */\n    JS_FreeValue(ctx, err);\n    JS_FreeCString(ctx, basename);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options)\n{\n    JSAtom basename;\n    JSValue promise, resolving_funcs[2], basename_val, err, ret;\n    JSValue specifier_str = JS_UNDEFINED, attributes = JS_UNDEFINED, attributes_obj = JS_UNDEFINED;\n    JSValueConst args[5];\n\n    basename = JS_GetScriptOrModuleName(ctx, 0);\n    if (basename == JS_ATOM_NULL)\n        basename_val = JS_NULL;\n    else\n        basename_val = JS_AtomToValue(ctx, basename);\n    JS_FreeAtom(ctx, basename);\n    if (JS_IsException(basename_val))\n        return basename_val;\n\n    promise = JS_NewPromiseCapability(ctx, resolving_funcs);\n    if (JS_IsException(promise)) {\n        JS_FreeValue(ctx, basename_val);\n        return promise;\n    }\n\n    /* the string conversion must occur here */\n    specifier_str = JS_ToString(ctx, specifier);\n    if (JS_IsException(specifier_str))\n        goto exception;\n    \n    if (!JS_IsUndefined(options)) {\n        if (!JS_IsObject(options)) {\n            JS_ThrowTypeError(ctx, \"options must be an object\");\n            goto exception;\n        }\n        attributes_obj = JS_GetProperty(ctx, options, JS_ATOM_with);\n        if (JS_IsException(attributes_obj))\n            goto exception;\n        if (!JS_IsUndefined(attributes_obj)) {\n            JSPropertyEnum *atoms;\n            uint32_t atoms_len, i;\n            JSValue val;\n            \n            if (!JS_IsObject(attributes_obj)) {\n                JS_ThrowTypeError(ctx, \"options.with must be an object\");\n                goto exception;\n            }\n            attributes = JS_NewObjectProto(ctx, JS_NULL);\n            if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &atoms_len, JS_VALUE_GET_OBJ(attributes_obj),\n                                               JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {\n                goto exception;\n            }\n            for(i = 0; i < atoms_len; i++) {\n                val = JS_GetProperty(ctx, attributes_obj, atoms[i].atom);\n                if (JS_IsException(val))\n                    goto exception1;\n                if (!JS_IsString(val)) {\n                    JS_FreeValue(ctx, val);\n                    JS_ThrowTypeError(ctx, \"module attribute values must be strings\");\n                    goto exception1;\n                }\n                if (JS_DefinePropertyValue(ctx, attributes,  atoms[i].atom, val,\n                                           JS_PROP_C_W_E) < 0) {\n                exception1:\n                    JS_FreePropertyEnum(ctx, atoms, atoms_len);\n                    goto exception;\n                }\n            }\n            JS_FreePropertyEnum(ctx, atoms, atoms_len);\n            if (ctx->rt->module_check_attrs &&\n                ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, attributes) < 0) {\n                goto exception;\n            }\n            JS_FreeValue(ctx, attributes_obj);\n        }\n    }\n\n    args[0] = resolving_funcs[0];\n    args[1] = resolving_funcs[1];\n    args[2] = basename_val;\n    args[3] = specifier_str;\n    args[4] = attributes;\n    \n    /* cannot run JS_LoadModuleInternal synchronously because it would\n       cause an unexpected recursion in js_evaluate_module() */\n    JS_EnqueueJob(ctx, js_dynamic_import_job, 5, args);\n done:\n    JS_FreeValue(ctx, basename_val);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    JS_FreeValue(ctx, specifier_str);\n    JS_FreeValue(ctx, attributes);\n    return promise;\n exception:\n    JS_FreeValue(ctx, attributes_obj);\n    err = JS_GetException(ctx);\n    ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED,\n                   1, (JSValueConst *)&err);\n    JS_FreeValue(ctx, ret);\n    JS_FreeValue(ctx, err);\n    goto done;\n}\n\nstatic void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m)\n{\n    m->status = JS_MODULE_STATUS_EVALUATED;\n    if (!JS_IsUndefined(m->promise)) {\n        JSValue value, ret_val;\n        assert(m->cycle_root == m);\n        value = JS_UNDEFINED;\n        ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,\n                          1, (JSValueConst *)&value);\n        JS_FreeValue(ctx, ret_val);\n    }\n}\n\ntypedef struct {\n    JSModuleDef **tab;\n    int count;\n    int size;\n} ExecModuleList;\n\n/* XXX: slow. Could use a linked list instead of ExecModuleList */\nstatic BOOL find_in_exec_module_list(ExecModuleList *exec_list, JSModuleDef *m)\n{\n    int i;\n    for(i = 0; i < exec_list->count; i++) {\n        if (exec_list->tab[i] == m)\n            return TRUE;\n    }\n    return FALSE;\n}\n\nstatic int gather_available_ancestors(JSContext *ctx, JSModuleDef *module,\n                                      ExecModuleList *exec_list)\n{\n    int i;\n\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        JS_ThrowStackOverflow(ctx);\n        return -1;\n    }\n    for(i = 0; i < module->async_parent_modules_count; i++) {\n        JSModuleDef *m = module->async_parent_modules[i];\n        if (!find_in_exec_module_list(exec_list, m) &&\n            !m->cycle_root->eval_has_exception) {\n            assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC);\n            assert(!m->eval_has_exception);\n            assert(m->async_evaluation);\n            assert(m->pending_async_dependencies > 0);\n            m->pending_async_dependencies--;\n            if (m->pending_async_dependencies == 0) {\n                if (js_resize_array(ctx, (void **)&exec_list->tab, sizeof(exec_list->tab[0]), &exec_list->size, exec_list->count + 1)) {\n                    return -1;\n                }\n                exec_list->tab[exec_list->count++] = m;\n                if (!m->has_tla) {\n                    if (gather_available_ancestors(ctx, m, exec_list))\n                        return -1;\n                }\n            }\n        }\n    }\n    return 0;\n}\n\nstatic int exec_module_list_cmp(const void *p1, const void *p2, void *opaque)\n{\n    JSModuleDef *m1 = *(JSModuleDef **)p1;\n    JSModuleDef *m2 = *(JSModuleDef **)p2;\n    return (m1->async_evaluation_timestamp > m2->async_evaluation_timestamp) -\n        (m1->async_evaluation_timestamp < m2->async_evaluation_timestamp);\n}\n\nstatic int js_execute_async_module(JSContext *ctx, JSModuleDef *m);\nstatic int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,\n                                  JSValue *pvalue);\n#ifdef DUMP_MODULE_EXEC\nstatic void js_dump_module(JSContext *ctx, const char *str, JSModuleDef *m)\n{\n    char buf1[ATOM_GET_STR_BUF_SIZE];\n    static const char *module_status_str[] = { \"unlinked\", \"linking\", \"linked\", \"evaluating\", \"evaluating_async\", \"evaluated\" };\n    printf(\"%s: %s status=%s\\n\", str, JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name), module_status_str[m->status]);\n}\n#endif\n\nstatic JSValue js_async_module_execution_rejected(JSContext *ctx, JSValueConst this_val,\n                                                  int argc, JSValueConst *argv, int magic, JSValue *func_data)\n{\n    JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);\n    JSValueConst error = argv[0];\n    int i;\n\n#ifdef DUMP_MODULE_EXEC\n    js_dump_module(ctx, __func__, module);\n#endif\n    if (js_check_stack_overflow(ctx->rt, 0))\n        return JS_ThrowStackOverflow(ctx);\n\n    if (module->status == JS_MODULE_STATUS_EVALUATED) {\n        assert(module->eval_has_exception);\n        return JS_UNDEFINED;\n    }\n\n    assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);\n    assert(!module->eval_has_exception);\n    assert(module->async_evaluation);\n\n    module->eval_has_exception = TRUE;\n    module->eval_exception = JS_DupValue(ctx, error);\n    module->status = JS_MODULE_STATUS_EVALUATED;\n    module->async_evaluation = FALSE;\n\n    if (!JS_IsUndefined(module->promise)) {\n        JSValue ret_val;\n        assert(module->cycle_root == module);\n        ret_val = JS_Call(ctx, module->resolving_funcs[1], JS_UNDEFINED,\n                          1, &error);\n        JS_FreeValue(ctx, ret_val);\n    }\n\n    for(i = 0; i < module->async_parent_modules_count; i++) {\n        JSModuleDef *m = module->async_parent_modules[i];\n        JSValue m_obj = JS_NewModuleValue(ctx, m);\n        js_async_module_execution_rejected(ctx, JS_UNDEFINED, 1, &error, 0,\n                                           &m_obj);\n        JS_FreeValue(ctx, m_obj);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_async_module_execution_fulfilled(JSContext *ctx, JSValueConst this_val,\n                                                   int argc, JSValueConst *argv, int magic, JSValue *func_data)\n{\n    JSModuleDef *module = JS_VALUE_GET_PTR(func_data[0]);\n    ExecModuleList exec_list_s, *exec_list = &exec_list_s;\n    int i;\n\n#ifdef DUMP_MODULE_EXEC\n    js_dump_module(ctx, __func__, module);\n#endif\n    if (module->status == JS_MODULE_STATUS_EVALUATED) {\n        assert(module->eval_has_exception);\n        return JS_UNDEFINED;\n    }\n    assert(module->status == JS_MODULE_STATUS_EVALUATING_ASYNC);\n    assert(!module->eval_has_exception);\n    assert(module->async_evaluation);\n    module->async_evaluation = FALSE;\n    js_set_module_evaluated(ctx, module);\n\n    exec_list->tab = NULL;\n    exec_list->count = 0;\n    exec_list->size = 0;\n\n    if (gather_available_ancestors(ctx, module, exec_list) < 0) {\n        js_free(ctx, exec_list->tab);\n        return JS_EXCEPTION;\n    }\n\n    /* sort by increasing async_evaluation timestamp */\n    rqsort(exec_list->tab, exec_list->count, sizeof(exec_list->tab[0]),\n           exec_module_list_cmp, NULL);\n\n    for(i = 0; i < exec_list->count; i++) {\n        JSModuleDef *m = exec_list->tab[i];\n#ifdef DUMP_MODULE_EXEC\n        printf(\"  %d/%d\", i, exec_list->count); js_dump_module(ctx, \"\", m);\n#endif\n        if (m->status == JS_MODULE_STATUS_EVALUATED) {\n            assert(m->eval_has_exception);\n        } else if (m->has_tla) {\n            js_execute_async_module(ctx, m);\n        } else {\n            JSValue error;\n            if (js_execute_sync_module(ctx, m, &error) < 0) {\n                JSValue m_obj = JS_NewModuleValue(ctx, m);\n                js_async_module_execution_rejected(ctx, JS_UNDEFINED,\n                                                   1, (JSValueConst *)&error, 0,\n                                                   &m_obj);\n                JS_FreeValue(ctx, m_obj);\n                JS_FreeValue(ctx, error);\n            } else {\n                m->async_evaluation = FALSE;\n                js_set_module_evaluated(ctx, m);\n            }\n        }\n    }\n    js_free(ctx, exec_list->tab);\n    return JS_UNDEFINED;\n}\n\nstatic int js_execute_async_module(JSContext *ctx, JSModuleDef *m)\n{\n    JSValue promise, m_obj;\n    JSValue resolve_funcs[2], ret_val;\n#ifdef DUMP_MODULE_EXEC\n    js_dump_module(ctx, __func__, m);\n#endif\n    promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);\n    if (JS_IsException(promise))\n        return -1;\n    m_obj = JS_NewModuleValue(ctx, m);\n    resolve_funcs[0] = JS_NewCFunctionData(ctx, js_async_module_execution_fulfilled, 0, 0, 1, (JSValueConst *)&m_obj);\n    resolve_funcs[1] = JS_NewCFunctionData(ctx, js_async_module_execution_rejected, 0, 0, 1, (JSValueConst *)&m_obj);\n    ret_val = js_promise_then(ctx, promise, 2, (JSValueConst *)resolve_funcs);\n    JS_FreeValue(ctx, ret_val);\n    JS_FreeValue(ctx, m_obj);\n    JS_FreeValue(ctx, resolve_funcs[0]);\n    JS_FreeValue(ctx, resolve_funcs[1]);\n    JS_FreeValue(ctx, promise);\n    return 0;\n}\n\n/* return < 0 in case of exception. *pvalue contains the exception. */\nstatic int js_execute_sync_module(JSContext *ctx, JSModuleDef *m,\n                                  JSValue *pvalue)\n{\n#ifdef DUMP_MODULE_EXEC\n    js_dump_module(ctx, __func__, m);\n#endif\n    if (m->init_func) {\n        /* C module init : no asynchronous execution */\n        if (m->init_func(ctx, m) < 0)\n            goto fail;\n    } else {\n        JSValue promise;\n        JSPromiseStateEnum state;\n\n        promise = js_async_function_call(ctx, m->func_obj, JS_UNDEFINED, 0, NULL, 0);\n        if (JS_IsException(promise))\n            goto fail;\n        state = JS_PromiseState(ctx, promise);\n        if (state == JS_PROMISE_FULFILLED) {\n            JS_FreeValue(ctx, promise);\n        } else if (state == JS_PROMISE_REJECTED) {\n            *pvalue = JS_PromiseResult(ctx, promise);\n            JS_FreeValue(ctx, promise);\n            return -1;\n        } else {\n            JS_FreeValue(ctx, promise);\n            JS_ThrowTypeError(ctx, \"promise is pending\");\n        fail:\n            *pvalue = JS_GetException(ctx);\n            return -1;\n        }\n    }\n    *pvalue = JS_UNDEFINED;\n    return 0;\n}\n\n/* spec: InnerModuleEvaluation. Return (index, JS_UNDEFINED) or (-1,\n   exception) */\nstatic int js_inner_module_evaluation(JSContext *ctx, JSModuleDef *m,\n                                      int index, JSModuleDef **pstack_top,\n                                      JSValue *pvalue)\n{\n    JSModuleDef *m1;\n    int i;\n\n#ifdef DUMP_MODULE_EXEC\n    js_dump_module(ctx, __func__, m);\n#endif\n\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        JS_ThrowStackOverflow(ctx);\n        *pvalue = JS_GetException(ctx);\n        return -1;\n    }\n\n    if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n        m->status == JS_MODULE_STATUS_EVALUATED) {\n        if (m->eval_has_exception) {\n            *pvalue = JS_DupValue(ctx, m->eval_exception);\n            return -1;\n        } else {\n            *pvalue = JS_UNDEFINED;\n            return index;\n        }\n    }\n    if (m->status == JS_MODULE_STATUS_EVALUATING) {\n        *pvalue = JS_UNDEFINED;\n        return index;\n    }\n    assert(m->status == JS_MODULE_STATUS_LINKED);\n\n    m->status = JS_MODULE_STATUS_EVALUATING;\n    m->dfs_index = index;\n    m->dfs_ancestor_index = index;\n    m->pending_async_dependencies = 0;\n    index++;\n    /* push 'm' on stack */\n    m->stack_prev = *pstack_top;\n    *pstack_top = m;\n\n    for(i = 0; i < m->req_module_entries_count; i++) {\n        JSReqModuleEntry *rme = &m->req_module_entries[i];\n        m1 = rme->module;\n        index = js_inner_module_evaluation(ctx, m1, index, pstack_top, pvalue);\n        if (index < 0)\n            return -1;\n        assert(m1->status == JS_MODULE_STATUS_EVALUATING ||\n               m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n               m1->status == JS_MODULE_STATUS_EVALUATED);\n        if (m1->status == JS_MODULE_STATUS_EVALUATING) {\n            m->dfs_ancestor_index = min_int(m->dfs_ancestor_index,\n                                            m1->dfs_ancestor_index);\n        } else {\n            m1 = m1->cycle_root;\n            assert(m1->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n                   m1->status == JS_MODULE_STATUS_EVALUATED);\n            if (m1->eval_has_exception) {\n                *pvalue = JS_DupValue(ctx, m1->eval_exception);\n                return -1;\n            }\n        }\n        if (m1->async_evaluation) {\n            m->pending_async_dependencies++;\n            if (js_resize_array(ctx, (void **)&m1->async_parent_modules, sizeof(m1->async_parent_modules[0]), &m1->async_parent_modules_size, m1->async_parent_modules_count + 1)) {\n                *pvalue = JS_GetException(ctx);\n                return -1;\n            }\n            m1->async_parent_modules[m1->async_parent_modules_count++] = m;\n        }\n    }\n\n    if (m->pending_async_dependencies > 0) {\n        assert(!m->async_evaluation);\n        m->async_evaluation = TRUE;\n        m->async_evaluation_timestamp =\n            ctx->rt->module_async_evaluation_next_timestamp++;\n    } else if (m->has_tla) {\n        assert(!m->async_evaluation);\n        m->async_evaluation = TRUE;\n        m->async_evaluation_timestamp =\n            ctx->rt->module_async_evaluation_next_timestamp++;\n        js_execute_async_module(ctx, m);\n    } else {\n        if (js_execute_sync_module(ctx, m, pvalue) < 0)\n            return -1;\n    }\n\n    assert(m->dfs_ancestor_index <= m->dfs_index);\n    if (m->dfs_index == m->dfs_ancestor_index) {\n        for(;;) {\n            /* pop m1 from stack */\n            m1 = *pstack_top;\n            *pstack_top = m1->stack_prev;\n            if (!m1->async_evaluation) {\n                m1->status = JS_MODULE_STATUS_EVALUATED;\n            } else {\n                m1->status = JS_MODULE_STATUS_EVALUATING_ASYNC;\n            }\n            /* spec bug: cycle_root must be assigned before the test */\n            m1->cycle_root = m;\n            if (m1 == m)\n                break;\n        }\n    }\n    *pvalue = JS_UNDEFINED;\n    return index;\n}\n\n/* Run the <eval> function of the module and of all its requested\n   modules. Return a promise or an exception. */\nstatic JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m)\n{\n    JSModuleDef *m1, *stack_top;\n    JSValue ret_val, result;\n\n#ifdef DUMP_MODULE_EXEC\n    js_dump_module(ctx, __func__, m);\n#endif\n    assert(m->status == JS_MODULE_STATUS_LINKED ||\n           m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n           m->status == JS_MODULE_STATUS_EVALUATED);\n    if (m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n        m->status == JS_MODULE_STATUS_EVALUATED) {\n        m = m->cycle_root;\n    }\n    /* a promise may be created only on the cycle_root of a cycle */\n    if (!JS_IsUndefined(m->promise))\n        return JS_DupValue(ctx, m->promise);\n    m->promise = JS_NewPromiseCapability(ctx, m->resolving_funcs);\n    if (JS_IsException(m->promise))\n        return JS_EXCEPTION;\n\n    stack_top = NULL;\n    if (js_inner_module_evaluation(ctx, m, 0, &stack_top, &result) < 0) {\n        while (stack_top != NULL) {\n            m1 = stack_top;\n            assert(m1->status == JS_MODULE_STATUS_EVALUATING);\n            m1->status = JS_MODULE_STATUS_EVALUATED;\n            m1->eval_has_exception = TRUE;\n            m1->eval_exception = JS_DupValue(ctx, result);\n            m1->cycle_root = m; /* spec bug: should be present */\n            stack_top = m1->stack_prev;\n        }\n        JS_FreeValue(ctx, result);\n        assert(m->status == JS_MODULE_STATUS_EVALUATED);\n        assert(m->eval_has_exception);\n        ret_val = JS_Call(ctx, m->resolving_funcs[1], JS_UNDEFINED,\n                          1, (JSValueConst *)&m->eval_exception);\n        JS_FreeValue(ctx, ret_val);\n    } else {\n#ifdef DUMP_MODULE_EXEC\n        js_dump_module(ctx, \"  done\", m);\n#endif\n        assert(m->status == JS_MODULE_STATUS_EVALUATING_ASYNC ||\n               m->status == JS_MODULE_STATUS_EVALUATED);\n        assert(!m->eval_has_exception);\n        if (!m->async_evaluation) {\n            JSValue value;\n            assert(m->status == JS_MODULE_STATUS_EVALUATED);\n            value = JS_UNDEFINED;\n            ret_val = JS_Call(ctx, m->resolving_funcs[0], JS_UNDEFINED,\n                              1, (JSValueConst *)&value);\n            JS_FreeValue(ctx, ret_val);\n        }\n        assert(stack_top == NULL);\n    }\n    return JS_DupValue(ctx, m->promise);\n}\n\nstatic __exception int js_parse_with_clause(JSParseState *s, JSReqModuleEntry *rme)\n{\n    JSContext *ctx = s->ctx;\n    JSAtom key;\n    int ret;\n    const uint8_t *key_token_ptr;\n    \n    if (next_token(s))\n        return -1;\n    if (js_parse_expect(s, '{'))\n        return -1;\n    while (s->token.val != '}') {\n        key_token_ptr = s->token.ptr;\n        if (s->token.val == TOK_STRING) {\n            key = JS_ValueToAtom(ctx, s->token.u.str.str);\n            if (key == JS_ATOM_NULL)\n                return -1;\n        } else {\n            if (!token_is_ident(s->token.val)) {\n                js_parse_error(s, \"identifier expected\");\n                return -1;\n            }\n            key = JS_DupAtom(ctx, s->token.u.ident.atom);\n        }\n        if (next_token(s))\n            return -1;\n        if (js_parse_expect(s, ':')) {\n            JS_FreeAtom(ctx, key);\n            return -1;\n        }\n        if (s->token.val != TOK_STRING) {\n            js_parse_error_pos(s, key_token_ptr, \"string expected\");\n            return -1;\n        }\n        if (JS_IsUndefined(rme->attributes)) {\n            JSValue attributes = JS_NewObjectProto(ctx, JS_NULL);\n            if (JS_IsException(attributes)) {\n                JS_FreeAtom(ctx, key);\n                return -1;\n            }\n            rme->attributes = attributes;\n        }\n        ret = JS_HasProperty(ctx, rme->attributes, key);\n        if (ret != 0) {\n            JS_FreeAtom(ctx, key);\n            if (ret < 0)\n                return -1;\n            else\n                return js_parse_error(s, \"duplicate with key\");\n        }\n        ret = JS_DefinePropertyValue(ctx, rme->attributes, key,\n                                     JS_DupValue(ctx, s->token.u.str.str), JS_PROP_C_W_E);\n        JS_FreeAtom(ctx, key);\n        if (ret < 0)\n            return -1;\n        if (next_token(s))\n            return -1;\n        if (s->token.val != ',')\n            break;\n        if (next_token(s))\n            return -1;\n    }\n    if (!JS_IsUndefined(rme->attributes) &&\n        ctx->rt->module_check_attrs &&\n        ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, rme->attributes) < 0) {\n        return -1;\n    }\n    return js_parse_expect(s, '}');\n}\n\n/* return the module index in m->req_module_entries[] or < 0 if error */\nstatic __exception int js_parse_from_clause(JSParseState *s, JSModuleDef *m)\n{\n    JSAtom module_name;\n    int idx;\n\n    if (!token_is_pseudo_keyword(s, JS_ATOM_from)) {\n        js_parse_error(s, \"from clause expected\");\n        return -1;\n    }\n    if (next_token(s))\n        return -1;\n    if (s->token.val != TOK_STRING) {\n        js_parse_error(s, \"string expected\");\n        return -1;\n    }\n    module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);\n    if (module_name == JS_ATOM_NULL)\n        return -1;\n    if (next_token(s)) {\n        JS_FreeAtom(s->ctx, module_name);\n        return -1;\n    }\n\n    idx = add_req_module_entry(s->ctx, m, module_name);\n    JS_FreeAtom(s->ctx, module_name);\n    if (idx < 0)\n        return -1;\n    if (s->token.val == TOK_WITH) {\n        if (js_parse_with_clause(s, &m->req_module_entries[idx]))\n            return -1;\n    }\n    return idx;\n}\n\nstatic __exception int js_parse_export(JSParseState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSModuleDef *m = s->cur_func->module;\n    JSAtom local_name, export_name;\n    int first_export, idx, i, tok;\n    JSExportEntry *me;\n\n    if (next_token(s))\n        return -1;\n\n    tok = s->token.val;\n    if (tok == TOK_CLASS) {\n        return js_parse_class(s, FALSE, JS_PARSE_EXPORT_NAMED);\n    } else if (tok == TOK_FUNCTION ||\n               (token_is_pseudo_keyword(s, JS_ATOM_async) &&\n                peek_token(s, TRUE) == TOK_FUNCTION)) {\n        return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,\n                                       JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                       s->token.ptr,\n                                       JS_PARSE_EXPORT_NAMED, NULL);\n    }\n\n    if (next_token(s))\n        return -1;\n\n    switch(tok) {\n    case '{':\n        first_export = m->export_entries_count;\n        while (s->token.val != '}') {\n            if (!token_is_ident(s->token.val)) {\n                js_parse_error(s, \"identifier expected\");\n                return -1;\n            }\n            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n            export_name = JS_ATOM_NULL;\n            if (next_token(s))\n                goto fail;\n            if (token_is_pseudo_keyword(s, JS_ATOM_as)) {\n                if (next_token(s))\n                    goto fail;\n                if (s->token.val == TOK_STRING) {\n                    if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {\n                        js_parse_error(s, \"contains unpaired surrogate\");\n                        goto fail;\n                    }\n                    export_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);\n                    if (export_name == JS_ATOM_NULL)\n                        goto fail;\n                } else {\n                    if (!token_is_ident(s->token.val)) {\n                        js_parse_error(s, \"identifier expected\");\n                        goto fail;\n                    }\n                    export_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n                }\n                if (next_token(s)) {\n                fail:\n                    JS_FreeAtom(ctx, local_name);\n                fail1:\n                    JS_FreeAtom(ctx, export_name);\n                    return -1;\n                }\n            } else {\n                export_name = JS_DupAtom(ctx, local_name);\n            }\n            me = add_export_entry(s, m, local_name, export_name,\n                                  JS_EXPORT_TYPE_LOCAL);\n            JS_FreeAtom(ctx, local_name);\n            JS_FreeAtom(ctx, export_name);\n            if (!me)\n                return -1;\n            if (s->token.val != ',')\n                break;\n            if (next_token(s))\n                return -1;\n        }\n        if (js_parse_expect(s, '}'))\n            return -1;\n        if (token_is_pseudo_keyword(s, JS_ATOM_from)) {\n            idx = js_parse_from_clause(s, m);\n            if (idx < 0)\n                return -1;\n            for(i = first_export; i < m->export_entries_count; i++) {\n                me = &m->export_entries[i];\n                me->export_type = JS_EXPORT_TYPE_INDIRECT;\n                me->u.req_module_idx = idx;\n            }\n        }\n        break;\n    case '*':\n        if (token_is_pseudo_keyword(s, JS_ATOM_as)) {\n            /* export ns from */\n            if (next_token(s))\n                return -1;\n            if (!token_is_ident(s->token.val)) {\n                js_parse_error(s, \"identifier expected\");\n                return -1;\n            }\n            export_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n            if (next_token(s))\n                goto fail1;\n            idx = js_parse_from_clause(s, m);\n            if (idx < 0)\n                goto fail1;\n            me = add_export_entry(s, m, JS_ATOM__star_, export_name,\n                                  JS_EXPORT_TYPE_INDIRECT);\n            JS_FreeAtom(ctx, export_name);\n            if (!me)\n                return -1;\n            me->u.req_module_idx = idx;\n        } else {\n            idx = js_parse_from_clause(s, m);\n            if (idx < 0)\n                return -1;\n            if (add_star_export_entry(ctx, m, idx) < 0)\n                return -1;\n        }\n        break;\n    case TOK_DEFAULT:\n        if (s->token.val == TOK_CLASS) {\n            return js_parse_class(s, FALSE, JS_PARSE_EXPORT_DEFAULT);\n        } else if (s->token.val == TOK_FUNCTION ||\n                   (token_is_pseudo_keyword(s, JS_ATOM_async) &&\n                    peek_token(s, TRUE) == TOK_FUNCTION)) {\n            return js_parse_function_decl2(s, JS_PARSE_FUNC_STATEMENT,\n                                           JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                           s->token.ptr,\n                                           JS_PARSE_EXPORT_DEFAULT, NULL);\n        } else {\n            if (js_parse_assign_expr(s))\n                return -1;\n        }\n        /* set the name of anonymous functions */\n        set_object_name(s, JS_ATOM_default);\n\n        /* store the value in the _default_ global variable and export\n           it */\n        local_name = JS_ATOM__default_;\n        if (define_var(s, s->cur_func, local_name, JS_VAR_DEF_LET) < 0)\n            return -1;\n        emit_op(s, OP_scope_put_var_init);\n        emit_atom(s, local_name);\n        emit_u16(s, 0);\n\n        if (!add_export_entry(s, m, local_name, JS_ATOM_default,\n                              JS_EXPORT_TYPE_LOCAL))\n            return -1;\n        break;\n    case TOK_VAR:\n    case TOK_LET:\n    case TOK_CONST:\n        return js_parse_var(s, TRUE, tok, TRUE);\n    default:\n        return js_parse_error(s, \"invalid export syntax\");\n    }\n    return js_parse_expect_semi(s);\n}\n\nstatic int add_closure_var(JSContext *ctx, JSFunctionDef *s,\n                           JSClosureTypeEnum closure_type,\n                           int var_idx, JSAtom var_name,\n                           BOOL is_const, BOOL is_lexical,\n                           JSVarKindEnum var_kind);\n\nstatic int add_import(JSParseState *s, JSModuleDef *m,\n                      JSAtom local_name, JSAtom import_name, BOOL is_star)\n{\n    JSContext *ctx = s->ctx;\n    int i, var_idx;\n    JSImportEntry *mi;\n\n    if (local_name == JS_ATOM_arguments || local_name == JS_ATOM_eval)\n        return js_parse_error(s, \"invalid import binding\");\n\n    if (local_name != JS_ATOM_default) {\n        for (i = 0; i < s->cur_func->closure_var_count; i++) {\n            if (s->cur_func->closure_var[i].var_name == local_name)\n                return js_parse_error(s, \"duplicate import binding\");\n        }\n    }\n\n    var_idx = add_closure_var(ctx, s->cur_func,\n                              is_star ? JS_CLOSURE_MODULE_DECL : JS_CLOSURE_MODULE_IMPORT,\n                              m->import_entries_count,\n                              local_name, TRUE, TRUE, JS_VAR_NORMAL);\n    if (var_idx < 0)\n        return -1;\n    if (js_resize_array(ctx, (void **)&m->import_entries,\n                        sizeof(JSImportEntry),\n                        &m->import_entries_size,\n                        m->import_entries_count + 1))\n        return -1;\n    mi = &m->import_entries[m->import_entries_count++];\n    mi->import_name = JS_DupAtom(ctx, import_name);\n    mi->var_idx = var_idx;\n    mi->is_star = is_star;\n    return 0;\n}\n\nstatic __exception int js_parse_import(JSParseState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSModuleDef *m = s->cur_func->module;\n    JSAtom local_name, import_name, module_name;\n    int first_import, i, idx;\n\n    if (next_token(s))\n        return -1;\n\n    first_import = m->import_entries_count;\n    if (s->token.val == TOK_STRING) {\n        module_name = JS_ValueToAtom(ctx, s->token.u.str.str);\n        if (module_name == JS_ATOM_NULL)\n            return -1;\n        if (next_token(s)) {\n            JS_FreeAtom(ctx, module_name);\n            return -1;\n        }\n        idx = add_req_module_entry(ctx, m, module_name);\n        JS_FreeAtom(ctx, module_name);\n        if (idx < 0)\n            return -1;\n        if (s->token.val == TOK_WITH) {\n            if (js_parse_with_clause(s, &m->req_module_entries[idx]))\n                return -1;\n        }\n    } else {\n        if (s->token.val == TOK_IDENT) {\n            if (s->token.u.ident.is_reserved) {\n                return js_parse_error_reserved_identifier(s);\n            }\n            /* \"default\" import */\n            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n            import_name = JS_ATOM_default;\n            if (next_token(s))\n                goto fail;\n            if (add_import(s, m, local_name, import_name, FALSE))\n                goto fail;\n            JS_FreeAtom(ctx, local_name);\n\n            if (s->token.val != ',')\n                goto end_import_clause;\n            if (next_token(s))\n                return -1;\n        }\n\n        if (s->token.val == '*') {\n            /* name space import */\n            if (next_token(s))\n                return -1;\n            if (!token_is_pseudo_keyword(s, JS_ATOM_as))\n                return js_parse_error(s, \"expecting 'as'\");\n            if (next_token(s))\n                return -1;\n            if (!token_is_ident(s->token.val)) {\n                js_parse_error(s, \"identifier expected\");\n                return -1;\n            }\n            local_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n            import_name = JS_ATOM__star_;\n            if (next_token(s))\n                goto fail;\n            if (add_import(s, m, local_name, import_name, TRUE))\n                goto fail;\n            JS_FreeAtom(ctx, local_name);\n        } else if (s->token.val == '{') {\n            if (next_token(s))\n                return -1;\n\n            while (s->token.val != '}') {\n                BOOL is_string;\n                if (s->token.val == TOK_STRING) {\n                    is_string = TRUE;\n                    if (js_string_find_invalid_codepoint(JS_VALUE_GET_STRING(s->token.u.str.str)) >= 0) {\n                        js_parse_error(s, \"contains unpaired surrogate\");\n                        return -1;\n                    }\n                    import_name = JS_ValueToAtom(s->ctx, s->token.u.str.str);\n                    if (import_name == JS_ATOM_NULL)\n                        return -1;\n                } else {\n                    is_string = FALSE;\n                    if (!token_is_ident(s->token.val)) {\n                        js_parse_error(s, \"identifier expected\");\n                        return -1;\n                    }\n                    import_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n                }\n                local_name = JS_ATOM_NULL;\n                if (next_token(s))\n                    goto fail;\n                if (token_is_pseudo_keyword(s, JS_ATOM_as)) {\n                    if (next_token(s))\n                        goto fail;\n                    if (!token_is_ident(s->token.val)) {\n                        js_parse_error(s, \"identifier expected\");\n                        goto fail;\n                    }\n                    local_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n                    if (next_token(s))\n                        goto fail;\n                } else {\n                    if (is_string) {\n                        js_parse_error(s, \"expecting 'as'\");\n                    fail:\n                        JS_FreeAtom(ctx, local_name);\n                        JS_FreeAtom(ctx, import_name);\n                        return -1;\n                    }\n                    local_name = JS_DupAtom(ctx, import_name);\n                }\n                if (add_import(s, m, local_name, import_name, FALSE))\n                    goto fail;\n                JS_FreeAtom(ctx, local_name);\n                JS_FreeAtom(ctx, import_name);\n                if (s->token.val != ',')\n                    break;\n                if (next_token(s))\n                    return -1;\n            }\n            if (js_parse_expect(s, '}'))\n                return -1;\n        }\n    end_import_clause:\n        idx = js_parse_from_clause(s, m);\n        if (idx < 0)\n            return -1;\n    }\n    for(i = first_import; i < m->import_entries_count; i++)\n        m->import_entries[i].req_module_idx = idx;\n\n    return js_parse_expect_semi(s);\n}\n\nstatic __exception int js_parse_source_element(JSParseState *s)\n{\n    JSFunctionDef *fd = s->cur_func;\n    int tok;\n\n    if (s->token.val == TOK_FUNCTION ||\n        (token_is_pseudo_keyword(s, JS_ATOM_async) &&\n         peek_token(s, TRUE) == TOK_FUNCTION)) {\n        if (js_parse_function_decl(s, JS_PARSE_FUNC_STATEMENT,\n                                   JS_FUNC_NORMAL, JS_ATOM_NULL,\n                                   s->token.ptr))\n            return -1;\n    } else if (s->token.val == TOK_EXPORT && fd->module) {\n        if (js_parse_export(s))\n            return -1;\n    } else if (s->token.val == TOK_IMPORT && fd->module &&\n               ((tok = peek_token(s, FALSE)) != '(' && tok != '.'))  {\n        /* the peek_token is needed to avoid confusion with ImportCall\n           (dynamic import) or import.meta */\n        if (js_parse_import(s))\n            return -1;\n    } else {\n        if (js_parse_statement_or_decl(s, DECL_MASK_ALL))\n            return -1;\n    }\n    return 0;\n}\n\nstatic JSFunctionDef *js_new_function_def(JSContext *ctx,\n                                          JSFunctionDef *parent,\n                                          BOOL is_eval,\n                                          BOOL is_func_expr,\n                                          const char *filename,\n                                          const uint8_t *source_ptr,\n                                          GetLineColCache *get_line_col_cache)\n{\n    JSFunctionDef *fd;\n\n    fd = js_mallocz(ctx, sizeof(*fd));\n    if (!fd)\n        return NULL;\n\n    fd->ctx = ctx;\n    init_list_head(&fd->child_list);\n\n    /* insert in parent list */\n    fd->parent = parent;\n    fd->parent_cpool_idx = -1;\n    if (parent) {\n        list_add_tail(&fd->link, &parent->child_list);\n        fd->js_mode = parent->js_mode;\n        fd->parent_scope_level = parent->scope_level;\n    }\n    fd->strip_debug = ((ctx->rt->strip_flags & JS_STRIP_DEBUG) != 0);\n    fd->strip_source = ((ctx->rt->strip_flags & (JS_STRIP_DEBUG | JS_STRIP_SOURCE)) != 0);\n\n    fd->is_eval = is_eval;\n    fd->is_func_expr = is_func_expr;\n    js_dbuf_bytecode_init(ctx, &fd->byte_code);\n    fd->last_opcode_pos = -1;\n    fd->func_name = JS_ATOM_NULL;\n    fd->var_object_idx = -1;\n    fd->arg_var_object_idx = -1;\n    fd->arguments_var_idx = -1;\n    fd->arguments_arg_idx = -1;\n    fd->func_var_idx = -1;\n    fd->eval_ret_idx = -1;\n    fd->this_var_idx = -1;\n    fd->new_target_var_idx = -1;\n    fd->this_active_func_var_idx = -1;\n    fd->home_object_var_idx = -1;\n\n    /* XXX: should distinguish arg, var and var object and body scopes */\n    fd->scopes = fd->def_scope_array;\n    fd->scope_size = countof(fd->def_scope_array);\n    fd->scope_count = 1;\n    fd->scopes[0].first = -1;\n    fd->scopes[0].parent = -1;\n    fd->scope_level = 0;  /* 0: var/arg scope */\n    fd->scope_first = -1;\n    fd->body_scope = -1;\n\n    fd->filename = JS_NewAtom(ctx, filename);\n    fd->source_pos = source_ptr - get_line_col_cache->buf_start;\n    fd->get_line_col_cache = get_line_col_cache;\n    \n    js_dbuf_init(ctx, &fd->pc2line);\n    //fd->pc2line_last_line_num = line_num;\n    //fd->pc2line_last_pc = 0;\n    fd->last_opcode_source_ptr = source_ptr;\n    return fd;\n}\n\nstatic void free_bytecode_atoms(JSRuntime *rt,\n                                const uint8_t *bc_buf, int bc_len,\n                                BOOL use_short_opcodes)\n{\n    int pos, len, op;\n    JSAtom atom;\n    const JSOpCode *oi;\n\n    pos = 0;\n    while (pos < bc_len) {\n        op = bc_buf[pos];\n        if (use_short_opcodes)\n            oi = &short_opcode_info(op);\n        else\n            oi = &opcode_info[op];\n\n        len = oi->size;\n        switch(oi->fmt) {\n        case OP_FMT_atom:\n        case OP_FMT_atom_u8:\n        case OP_FMT_atom_u16:\n        case OP_FMT_atom_label_u8:\n        case OP_FMT_atom_label_u16:\n            if ((pos + 1 + 4) > bc_len)\n                break; /* may happen if there is not enough memory when emiting bytecode */\n            atom = get_u32(bc_buf + pos + 1);\n            JS_FreeAtomRT(rt, atom);\n            break;\n        default:\n            break;\n        }\n        pos += len;\n    }\n}\n\nstatic void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)\n{\n    int i;\n    struct list_head *el, *el1;\n\n    /* free the child functions */\n    list_for_each_safe(el, el1, &fd->child_list) {\n        JSFunctionDef *fd1;\n        fd1 = list_entry(el, JSFunctionDef, link);\n        js_free_function_def(ctx, fd1);\n    }\n\n    free_bytecode_atoms(ctx->rt, fd->byte_code.buf, fd->byte_code.size,\n                        fd->use_short_opcodes);\n    dbuf_free(&fd->byte_code);\n    js_free(ctx, fd->jump_slots);\n    js_free(ctx, fd->label_slots);\n    js_free(ctx, fd->line_number_slots);\n\n    for(i = 0; i < fd->cpool_count; i++) {\n        JS_FreeValue(ctx, fd->cpool[i]);\n    }\n    js_free(ctx, fd->cpool);\n\n    JS_FreeAtom(ctx, fd->func_name);\n\n    for(i = 0; i < fd->var_count; i++) {\n        JS_FreeAtom(ctx, fd->vars[i].var_name);\n    }\n    js_free(ctx, fd->vars);\n    for(i = 0; i < fd->arg_count; i++) {\n        JS_FreeAtom(ctx, fd->args[i].var_name);\n    }\n    js_free(ctx, fd->args);\n\n    for(i = 0; i < fd->global_var_count; i++) {\n        JS_FreeAtom(ctx, fd->global_vars[i].var_name);\n    }\n    js_free(ctx, fd->global_vars);\n\n    for(i = 0; i < fd->closure_var_count; i++) {\n        JSClosureVar *cv = &fd->closure_var[i];\n        JS_FreeAtom(ctx, cv->var_name);\n    }\n    js_free(ctx, fd->closure_var);\n\n    if (fd->scopes != fd->def_scope_array)\n        js_free(ctx, fd->scopes);\n\n    JS_FreeAtom(ctx, fd->filename);\n    dbuf_free(&fd->pc2line);\n\n    js_free(ctx, fd->source);\n\n    if (fd->parent) {\n        /* remove in parent list */\n        list_del(&fd->link);\n    }\n    js_free(ctx, fd);\n}\n\n#ifdef DUMP_BYTECODE\nstatic const char *skip_lines(const char *p, int n) {\n    while (n-- > 0 && *p) {\n        while (*p && *p++ != '\\n')\n            continue;\n    }\n    return p;\n}\n\nstatic void print_lines(const char *source, int line, int line1) {\n    const char *s = source;\n    const char *p = skip_lines(s, line);\n    if (*p) {\n        while (line++ < line1) {\n            p = skip_lines(s = p, 1);\n            printf(\";; %.*s\", (int)(p - s), s);\n            if (!*p) {\n                if (p[-1] != '\\n')\n                    printf(\"\\n\");\n                break;\n            }\n        }\n    }\n}\n\nstatic void dump_byte_code(JSContext *ctx, int pass,\n                           const uint8_t *tab, int len,\n                           const JSBytecodeVarDef *vardefs, \n                           const JSVarDef *args, int arg_count,\n                           const JSVarDef *vars, int var_count,\n                           const JSClosureVar *closure_var, int closure_var_count,\n                           const JSValue *cpool, uint32_t cpool_count,\n                           const char *source,\n                           const LabelSlot *label_slots, JSFunctionBytecode *b)\n{\n    const JSOpCode *oi;\n    int pos, pos_next, op, size, idx, addr, line, line1, in_source, line_num;\n    uint8_t *bits = js_mallocz(ctx, len * sizeof(*bits));\n    BOOL use_short_opcodes = (b != NULL);\n\n    if (b) {\n        int col_num;\n        line_num = find_line_num(ctx, b, -1, &col_num);\n    }\n    \n    /* scan for jump targets */\n    for (pos = 0; pos < len; pos = pos_next) {\n        op = tab[pos];\n        if (use_short_opcodes)\n            oi = &short_opcode_info(op);\n        else\n            oi = &opcode_info[op];\n        pos_next = pos + oi->size;\n        if (op < OP_COUNT) {\n            switch (oi->fmt) {\n#if SHORT_OPCODES\n            case OP_FMT_label8:\n                pos++;\n                addr = (int8_t)tab[pos];\n                goto has_addr;\n            case OP_FMT_label16:\n                pos++;\n                addr = (int16_t)get_u16(tab + pos);\n                goto has_addr;\n#endif\n            case OP_FMT_atom_label_u8:\n            case OP_FMT_atom_label_u16:\n                pos += 4;\n                /* fall thru */\n            case OP_FMT_label:\n            case OP_FMT_label_u16:\n                pos++;\n                addr = get_u32(tab + pos);\n                goto has_addr;\n            has_addr:\n                if (pass == 1)\n                    addr = label_slots[addr].pos;\n                if (pass == 2)\n                    addr = label_slots[addr].pos2;\n                if (pass == 3)\n                    addr += pos;\n                if (addr >= 0 && addr < len)\n                    bits[addr] |= 1;\n                break;\n            }\n        }\n    }\n    in_source = 0;\n    if (source) {\n        /* Always print first line: needed if single line */\n        print_lines(source, 0, 1);\n        in_source = 1;\n    }\n    line1 = line = 1;\n    pos = 0;\n    while (pos < len) {\n        op = tab[pos];\n        if (source && b) {\n            int col_num;\n            if (b) {\n                line1 = find_line_num(ctx, b, pos, &col_num) - line_num + 1;\n            } else if (op == OP_line_num) {\n                /* XXX: no longer works */\n                line1 = get_u32(tab + pos + 1) - line_num + 1;\n            }\n            if (line1 > line) {\n                if (!in_source)\n                    printf(\"\\n\");\n                in_source = 1;\n                print_lines(source, line, line1);\n                line = line1;\n                //bits[pos] |= 2;\n            }\n        }\n        if (in_source)\n            printf(\"\\n\");\n        in_source = 0;\n        if (op >= OP_COUNT) {\n            printf(\"invalid opcode (0x%02x)\\n\", op);\n            pos++;\n            continue;\n        }\n        if (use_short_opcodes)\n            oi = &short_opcode_info(op);\n        else\n            oi = &opcode_info[op];\n        size = oi->size;\n        if (pos + size > len) {\n            printf(\"truncated opcode (0x%02x)\\n\", op);\n            break;\n        }\n#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 16)\n        {\n            int i, x, x0;\n            x = x0 = printf(\"%5d \", pos);\n            for (i = 0; i < size; i++) {\n                if (i == 6) {\n                    printf(\"\\n%*s\", x = x0, \"\");\n                }\n                x += printf(\" %02X\", tab[pos + i]);\n            }\n            printf(\"%*s\", x0 + 20 - x, \"\");\n        }\n#endif\n        if (bits[pos]) {\n            printf(\"%5d:  \", pos);\n        } else {\n            printf(\"        \");\n        }\n        printf(\"%s\", oi->name);\n        pos++;\n        switch(oi->fmt) {\n        case OP_FMT_none_int:\n            printf(\" %d\", op - OP_push_0);\n            break;\n        case OP_FMT_npopx:\n            printf(\" %d\", op - OP_call0);\n            break;\n        case OP_FMT_u8:\n            printf(\" %u\", get_u8(tab + pos));\n            break;\n        case OP_FMT_i8:\n            printf(\" %d\", get_i8(tab + pos));\n            break;\n        case OP_FMT_u16:\n        case OP_FMT_npop:\n            printf(\" %u\", get_u16(tab + pos));\n            break;\n        case OP_FMT_npop_u16:\n            printf(\" %u,%u\", get_u16(tab + pos), get_u16(tab + pos + 2));\n            break;\n        case OP_FMT_i16:\n            printf(\" %d\", get_i16(tab + pos));\n            break;\n        case OP_FMT_i32:\n            printf(\" %d\", get_i32(tab + pos));\n            break;\n        case OP_FMT_u32:\n            printf(\" %u\", get_u32(tab + pos));\n            break;\n#if SHORT_OPCODES\n        case OP_FMT_label8:\n            addr = get_i8(tab + pos);\n            goto has_addr1;\n        case OP_FMT_label16:\n            addr = get_i16(tab + pos);\n            goto has_addr1;\n#endif\n        case OP_FMT_label:\n            addr = get_u32(tab + pos);\n            goto has_addr1;\n        has_addr1:\n            if (pass == 1)\n                printf(\" %u:%u\", addr, label_slots[addr].pos);\n            if (pass == 2)\n                printf(\" %u:%u\", addr, label_slots[addr].pos2);\n            if (pass == 3)\n                printf(\" %u\", addr + pos);\n            break;\n        case OP_FMT_label_u16:\n            addr = get_u32(tab + pos);\n            if (pass == 1)\n                printf(\" %u:%u\", addr, label_slots[addr].pos);\n            if (pass == 2)\n                printf(\" %u:%u\", addr, label_slots[addr].pos2);\n            if (pass == 3)\n                printf(\" %u\", addr + pos);\n            printf(\",%u\", get_u16(tab + pos + 4));\n            break;\n#if SHORT_OPCODES\n        case OP_FMT_const8:\n            idx = get_u8(tab + pos);\n            goto has_pool_idx;\n#endif\n        case OP_FMT_const:\n            idx = get_u32(tab + pos);\n            goto has_pool_idx;\n        has_pool_idx:\n            printf(\" %u: \", idx);\n            if (idx < cpool_count) {\n                JS_PrintValue(ctx, js_dump_value_write, stdout, cpool[idx], NULL);\n            }\n            break;\n        case OP_FMT_atom:\n            printf(\" \");\n            print_atom(ctx, get_u32(tab + pos));\n            break;\n        case OP_FMT_atom_u8:\n            printf(\" \");\n            print_atom(ctx, get_u32(tab + pos));\n            printf(\",%d\", get_u8(tab + pos + 4));\n            break;\n        case OP_FMT_atom_u16:\n            printf(\" \");\n            print_atom(ctx, get_u32(tab + pos));\n            printf(\",%d\", get_u16(tab + pos + 4));\n            break;\n        case OP_FMT_atom_label_u8:\n        case OP_FMT_atom_label_u16:\n            printf(\" \");\n            print_atom(ctx, get_u32(tab + pos));\n            addr = get_u32(tab + pos + 4);\n            if (pass == 1)\n                printf(\",%u:%u\", addr, label_slots[addr].pos);\n            if (pass == 2)\n                printf(\",%u:%u\", addr, label_slots[addr].pos2);\n            if (pass == 3)\n                printf(\",%u\", addr + pos + 4);\n            if (oi->fmt == OP_FMT_atom_label_u8)\n                printf(\",%u\", get_u8(tab + pos + 8));\n            else\n                printf(\",%u\", get_u16(tab + pos + 8));\n            break;\n        case OP_FMT_none_loc:\n            idx = (op - OP_get_loc0) % 4;\n            goto has_loc;\n        case OP_FMT_loc8:\n            idx = get_u8(tab + pos);\n            goto has_loc;\n        case OP_FMT_loc:\n            idx = get_u16(tab + pos);\n        has_loc:\n            printf(\" %d: \", idx);\n            if (idx < var_count) {\n                print_atom(ctx, vars ? vars[idx].var_name : vardefs[arg_count + idx].var_name);\n            }\n            break;\n        case OP_FMT_none_arg:\n            idx = (op - OP_get_arg0) % 4;\n            goto has_arg;\n        case OP_FMT_arg:\n            idx = get_u16(tab + pos);\n        has_arg:\n            printf(\" %d: \", idx);\n            if (idx < arg_count) {\n                print_atom(ctx, args ? args[idx].var_name : vardefs[idx].var_name);\n            }\n            break;\n        case OP_FMT_none_var_ref:\n            idx = (op - OP_get_var_ref0) % 4;\n            goto has_var_ref;\n        case OP_FMT_var_ref:\n            idx = get_u16(tab + pos);\n        has_var_ref:\n            printf(\" %d: \", idx);\n            if (idx < closure_var_count) {\n                print_atom(ctx, closure_var[idx].var_name);\n            }\n            break;\n        default:\n            break;\n        }\n        printf(\"\\n\");\n        pos += oi->size - 1;\n    }\n    if (source) {\n        if (!in_source)\n            printf(\"\\n\");\n        print_lines(source, line, INT32_MAX);\n    }\n    js_free(ctx, bits);\n}\n\nstatic __maybe_unused void dump_pc2line(JSContext *ctx, const uint8_t *buf, int len)\n{\n    const uint8_t *p_end, *p;\n    int pc, v, line_num, col_num, ret;\n    unsigned int op;\n    uint32_t val;\n    \n    if (len <= 0)\n        return;\n\n    printf(\"%5s %5s %5s\\n\", \"PC\", \"LINE\", \"COL\");\n\n    p = buf;\n    p_end = buf + len;\n    \n    /* get the function line and column numbers */\n    ret = get_leb128(&val, p, p_end);\n    if (ret < 0)\n        goto fail;\n    p += ret;\n    line_num = val + 1;\n\n    ret = get_leb128(&val, p, p_end);\n    if (ret < 0)\n        goto fail;\n    p += ret;\n    col_num = val + 1;\n\n    printf(\"%5s %5d %5d\\n\", \"-\", line_num, col_num);\n    \n    pc = 0;\n    while (p < p_end) {\n        op = *p++;\n        if (op == 0) {\n            ret = get_leb128(&val, p, p_end);\n            if (ret < 0)\n                goto fail;\n            pc += val;\n            p += ret;\n            ret = get_sleb128(&v, p, p_end);\n            if (ret < 0)\n                goto fail;\n            p += ret;\n            line_num += v;\n        } else {\n            op -= PC2LINE_OP_FIRST;\n            pc += (op / PC2LINE_RANGE);\n            line_num += (op % PC2LINE_RANGE) + PC2LINE_BASE;\n        }\n        ret = get_sleb128(&v, p, p_end);\n        if (ret < 0)\n            goto fail;\n        p += ret;\n        col_num += v;\n        \n        printf(\"%5d %5d %5d\\n\", pc, line_num, col_num);\n    }\n fail: ;\n}\n\nstatic __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionBytecode *b)\n{\n    int i;\n    char atom_buf[ATOM_GET_STR_BUF_SIZE];\n    const char *str;\n\n    if (b->has_debug && b->debug.filename != JS_ATOM_NULL) {\n        int line_num, col_num;\n        str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->debug.filename);\n        line_num = find_line_num(ctx, b, -1, &col_num);\n        printf(\"%s:%d:%d: \", str, line_num, col_num);\n    }\n\n    str = JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), b->func_name);\n    printf(\"function: %s%s\\n\", &\"*\"[b->func_kind != JS_FUNC_GENERATOR], str);\n    if (b->js_mode) {\n        printf(\"  mode:\");\n        if (b->js_mode & JS_MODE_STRICT)\n            printf(\" strict\");\n        printf(\"\\n\");\n    }\n    if (b->arg_count && b->vardefs) {\n        printf(\"  args:\");\n        for(i = 0; i < b->arg_count; i++) {\n            printf(\" %s\", JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),\n                                        b->vardefs[i].var_name));\n        }\n        printf(\"\\n\");\n    }\n    if (b->var_count && b->vardefs) {\n        printf(\"  locals:\\n\");\n        for(i = 0; i < b->var_count; i++) {\n            JSBytecodeVarDef *vd = &b->vardefs[b->arg_count + i];\n            printf(\"%5d: %s %s\", i,\n                   vd->var_kind == JS_VAR_CATCH ? \"catch\" :\n                   (vd->var_kind == JS_VAR_FUNCTION_DECL ||\n                    vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) ? \"function\" :\n                   vd->is_const ? \"const\" :\n                   vd->is_lexical ? \"let\" : \"var\",\n                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));\n            if (vd->has_scope)\n                printf(\" [next:%d]\", vd->scope_next);\n            printf(\"\\n\");\n        }\n    }\n    if (b->closure_var_count) {\n        printf(\"  closure vars:\\n\");\n        for(i = 0; i < b->closure_var_count; i++) {\n            JSClosureVar *cv = &b->closure_var[i];\n            printf(\"%5d: %s %s\", i,\n                   cv->is_const ? \"const\" :\n                   cv->is_lexical ? \"let\" : \"var\",\n                   JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), cv->var_name));\n            switch(cv->closure_type) {\n            case JS_CLOSURE_LOCAL:\n                printf(\" [loc%d]\\n\", cv->var_idx);\n                break;\n            case JS_CLOSURE_ARG:\n                printf(\" [arg%d]\\n\", cv->var_idx);\n                break;\n            case JS_CLOSURE_REF:\n                printf(\" [ref%d]\\n\", cv->var_idx);\n                break;\n            case JS_CLOSURE_GLOBAL_REF:\n                printf(\" [global_ref%d]\\n\", cv->var_idx);\n                break;\n            case JS_CLOSURE_GLOBAL_DECL:\n                printf(\" [global_decl]\\n\");\n                break;\n            case JS_CLOSURE_GLOBAL:\n                printf(\" [global]\\n\");\n                break;\n            case JS_CLOSURE_MODULE_DECL:\n                printf(\" [module_decl]\\n\");\n                break;\n            case JS_CLOSURE_MODULE_IMPORT:\n                printf(\" [module_import]\\n\");\n                break;\n            default:\n                printf(\" [?]\\n\");\n                break;\n            }\n        }\n    }\n    printf(\"  stack_size: %d\\n\", b->stack_size);\n    printf(\"  var_ref_count: %d\\n\", b->var_ref_count);\n    printf(\"  opcodes:\\n\");\n    dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,\n                   b->vardefs,\n                   NULL, b->arg_count,\n                   NULL, b->var_count,\n                   b->closure_var, b->closure_var_count,\n                   b->cpool, b->cpool_count,\n                   b->has_debug ? b->debug.source : NULL,\n                   NULL, b);\n#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 32)\n    if (b->has_debug)\n        dump_pc2line(ctx, b->debug.pc2line_buf, b->debug.pc2line_len);\n#endif\n    printf(\"\\n\");\n}\n#endif\n\nstatic int add_closure_var(JSContext *ctx, JSFunctionDef *s,\n                           JSClosureTypeEnum closure_type,\n                           int var_idx, JSAtom var_name,\n                           BOOL is_const, BOOL is_lexical,\n                           JSVarKindEnum var_kind)\n{\n    JSClosureVar *cv;\n\n    /* the closure variable indexes are currently stored on 16 bits */\n    if (s->closure_var_count >= JS_MAX_LOCAL_VARS) {\n        JS_ThrowInternalError(ctx, \"too many closure variables\");\n        return -1;\n    }\n\n    if (js_resize_array(ctx, (void **)&s->closure_var,\n                        sizeof(s->closure_var[0]),\n                        &s->closure_var_size, s->closure_var_count + 1))\n        return -1;\n    cv = &s->closure_var[s->closure_var_count++];\n    cv->closure_type = closure_type;\n    cv->is_const = is_const;\n    cv->is_lexical = is_lexical;\n    cv->var_kind = var_kind;\n    cv->var_idx = var_idx;\n    cv->var_name = JS_DupAtom(ctx, var_name);\n    return s->closure_var_count - 1;\n}\n\nstatic int find_closure_var(JSContext *ctx, JSFunctionDef *s,\n                            JSAtom var_name)\n{\n    int i;\n    for(i = 0; i < s->closure_var_count; i++) {\n        JSClosureVar *cv = &s->closure_var[i];\n        if (cv->var_name == var_name)\n            return i;\n    }\n    return -1;\n}\n\n/* 'fd' must be a parent of 's'. Create in 's' a closure referencing\n   another one in 'fd' */\nstatic int get_closure_var(JSContext *ctx, JSFunctionDef *s,\n                           JSFunctionDef *fd, JSClosureTypeEnum closure_type,\n                           int var_idx, JSAtom var_name,\n                           BOOL is_const, BOOL is_lexical,\n                           JSVarKindEnum var_kind)\n{\n    int i;\n\n    if (fd != s->parent) {\n        var_idx = get_closure_var(ctx, s->parent, fd, closure_type,\n                                  var_idx, var_name,\n                                  is_const, is_lexical, var_kind);\n        if (var_idx < 0)\n            return -1;\n        if (closure_type != JS_CLOSURE_GLOBAL_REF)\n            closure_type = JS_CLOSURE_REF;\n    }\n    for(i = 0; i < s->closure_var_count; i++) {\n        JSClosureVar *cv = &s->closure_var[i];\n        if (cv->var_idx == var_idx && cv->closure_type == closure_type)\n            return i;\n    }\n    return add_closure_var(ctx, s, closure_type, var_idx, var_name,\n                           is_const, is_lexical, var_kind);\n}\n\nstatic int get_with_scope_opcode(int op)\n{\n    if (op == OP_scope_get_var_undef)\n        return OP_with_get_var;\n    else\n        return OP_with_get_var + (op - OP_scope_get_var);\n}\n\nstatic BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos)\n{\n    int opcode = bc_buf[pos];\n    return (bc_buf[pos + 1] == OP_put_ref_value &&\n            (opcode == OP_insert3 ||\n             opcode == OP_perm4 ||\n             opcode == OP_nop ||\n             opcode == OP_rot3l));\n}\n\nstatic BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos)\n{\n    int opcode = bc_buf[pos];\n    return (bc_buf[pos + 1] == OP_put_ref_value &&\n            (opcode == OP_insert3 ||\n             opcode == OP_perm4 ||\n             opcode == OP_nop ||\n             opcode == OP_rot3l));\n}\n\nstatic int optimize_scope_make_ref(JSContext *ctx, JSFunctionDef *s,\n                                   DynBuf *bc, uint8_t *bc_buf,\n                                   LabelSlot *ls, int pos_next,\n                                   int get_op, int var_idx)\n{\n    int label_pos, end_pos, pos;\n\n    /* XXX: should optimize `loc(a) += expr` as `expr add_loc(a)`\n       but only if expr does not modify `a`.\n       should scan the code between pos_next and label_pos\n       for operations that can potentially change `a`:\n       OP_scope_make_ref(a), function calls, jumps and gosub.\n     */\n    /* replace the reference get/put with normal variable\n       accesses */\n    if (bc_buf[pos_next] == OP_get_ref_value) {\n        dbuf_putc(bc, get_op);\n        dbuf_put_u16(bc, var_idx);\n        pos_next++;\n    }\n    /* remove the OP_label to make room for replacement */\n    /* label should have a refcount of 0 anyway */\n    /* XXX: should avoid this patch by inserting nops in phase 1 */\n    label_pos = ls->pos;\n    pos = label_pos - 5;\n    assert(bc_buf[pos] == OP_label);\n    /* label points to an instruction pair:\n       - insert3 / put_ref_value\n       - perm4 / put_ref_value\n       - rot3l / put_ref_value\n       - nop / put_ref_value\n     */\n    end_pos = label_pos + 2;\n    if (bc_buf[label_pos] == OP_insert3)\n        bc_buf[pos++] = OP_dup;\n    bc_buf[pos] = get_op + 1;\n    put_u16(bc_buf + pos + 1, var_idx);\n    pos += 3;\n    /* pad with OP_nop */\n    while (pos < end_pos)\n        bc_buf[pos++] = OP_nop;\n    return pos_next;\n}\n\nstatic int add_var_this(JSContext *ctx, JSFunctionDef *fd)\n{\n    int idx;\n    idx = add_var(ctx, fd, JS_ATOM_this);\n    if (idx >= 0 && fd->is_derived_class_constructor) {\n        JSVarDef *vd = &fd->vars[idx];\n        /* XXX: should have is_this flag or var type */\n        vd->is_lexical = 1; /* used to trigger 'uninitialized' checks\n                               in a derived class constructor */\n    }\n    return idx;\n}\n\nstatic int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,\n                               JSAtom var_name)\n{\n    int var_idx;\n\n    if (!s->has_this_binding)\n        return -1;\n    switch(var_name) {\n    case JS_ATOM_home_object:\n        /* 'home_object' pseudo variable */\n        if (s->home_object_var_idx < 0)\n            s->home_object_var_idx = add_var(ctx, s, var_name);\n        var_idx = s->home_object_var_idx;\n        break;\n    case JS_ATOM_this_active_func:\n        /* 'this.active_func' pseudo variable */\n        if (s->this_active_func_var_idx < 0)\n            s->this_active_func_var_idx = add_var(ctx, s, var_name);\n        var_idx = s->this_active_func_var_idx;\n        break;\n    case JS_ATOM_new_target:\n        /* 'new.target' pseudo variable */\n        if (s->new_target_var_idx < 0)\n            s->new_target_var_idx = add_var(ctx, s, var_name);\n        var_idx = s->new_target_var_idx;\n        break;\n    case JS_ATOM_this:\n        /* 'this' pseudo variable */\n        if (s->this_var_idx < 0)\n            s->this_var_idx = add_var_this(ctx, s);\n        var_idx = s->this_var_idx;\n        break;\n    default:\n        var_idx = -1;\n        break;\n    }\n    return var_idx;\n}\n\n/* test if 'var_name' is in the variable object on the stack. If is it\n   the case, handle it and jump to 'label_done' */\nstatic void var_object_test(JSContext *ctx, JSFunctionDef *s,\n                            JSAtom var_name, int op, DynBuf *bc,\n                            int *plabel_done, BOOL is_with)\n{\n    dbuf_putc(bc, get_with_scope_opcode(op));\n    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n    if (*plabel_done < 0) {\n        *plabel_done = new_label_fd(s);\n        if (*plabel_done < 0) {\n            dbuf_set_error(bc);\n            return;\n        }\n    }\n    dbuf_put_u32(bc, *plabel_done);\n    dbuf_putc(bc, is_with);\n    update_label(s, *plabel_done, 1);\n    s->jump_size++;\n}\n\nstatic inline void capture_var(JSFunctionDef *s, JSVarDef *vd)\n{\n    if (!vd->is_captured) {\n        vd->is_captured = 1;\n        vd->var_ref_idx = s->var_ref_count++;\n    }\n}\n\n/* return the position of the next opcode or -1 if error */\nstatic int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,\n                             JSAtom var_name, int scope_level, int op,\n                             DynBuf *bc, uint8_t *bc_buf,\n                             LabelSlot *ls, int pos_next)\n{\n    int idx, var_idx, is_put;\n    int label_done;\n    JSFunctionDef *fd;\n    JSVarDef *vd;\n    BOOL is_pseudo_var, is_arg_scope;\n\n    label_done = -1;\n\n    /* XXX: could be simpler to use a specific function to\n       resolve the pseudo variables */\n    is_pseudo_var = (var_name == JS_ATOM_home_object ||\n                     var_name == JS_ATOM_this_active_func ||\n                     var_name == JS_ATOM_new_target ||\n                     var_name == JS_ATOM_this);\n\n    /* resolve local scoped variables */\n    var_idx = -1;\n    for (idx = s->scopes[scope_level].first; idx >= 0;) {\n        vd = &s->vars[idx];\n        if (vd->var_name == var_name) {\n            if (op == OP_scope_put_var || op == OP_scope_make_ref) {\n                if (vd->is_const) {\n                    dbuf_putc(bc, OP_throw_error);\n                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                    dbuf_putc(bc, JS_THROW_VAR_RO);\n                    goto done;\n                }\n            }\n            var_idx = idx;\n            break;\n        } else\n        if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {\n            dbuf_putc(bc, OP_get_loc);\n            dbuf_put_u16(bc, idx);\n            var_object_test(ctx, s, var_name, op, bc, &label_done, 1);\n        }\n        idx = vd->scope_next;\n    }\n    is_arg_scope = (idx == ARG_SCOPE_END);\n    if (var_idx < 0) {\n        /* argument scope: variables are not visible but pseudo\n           variables are visible */\n        if (!is_arg_scope) {\n            var_idx = find_var(ctx, s, var_name);\n        }\n\n        if (var_idx < 0 && is_pseudo_var)\n            var_idx = resolve_pseudo_var(ctx, s, var_name);\n\n        if (var_idx < 0 && var_name == JS_ATOM_arguments &&\n            s->has_arguments_binding) {\n            /* 'arguments' pseudo variable */\n            var_idx = add_arguments_var(ctx, s);\n        }\n        if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {\n            /* add a new variable with the function name */\n            var_idx = add_func_var(ctx, s, var_name);\n        }\n    }\n    if (var_idx >= 0) {\n        if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&\n            !(var_idx & ARGUMENT_VAR_OFFSET) &&\n            s->vars[var_idx].is_const) {\n            /* only happens when assigning a function expression name\n               in strict mode */\n            dbuf_putc(bc, OP_throw_error);\n            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n            dbuf_putc(bc, JS_THROW_VAR_RO);\n            goto done;\n        }\n        /* OP_scope_put_var_init is only used to initialize a\n           lexical variable, so it is never used in a with or var object. It\n           can be used with a closure (module global variable case). */\n        switch (op) {\n        case OP_scope_make_ref:\n            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&\n                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {\n                /* Create a dummy object reference for the func_var */\n                dbuf_putc(bc, OP_object);\n                dbuf_putc(bc, OP_get_loc);\n                dbuf_put_u16(bc, var_idx);\n                dbuf_putc(bc, OP_define_field);\n                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                dbuf_putc(bc, OP_push_atom_value);\n                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n            } else\n            if (label_done == -1 && can_opt_put_ref_value(bc_buf, ls->pos)) {\n                int get_op;\n                if (var_idx & ARGUMENT_VAR_OFFSET) {\n                    get_op = OP_get_arg;\n                    var_idx -= ARGUMENT_VAR_OFFSET;\n                } else {\n                    if (s->vars[var_idx].is_lexical)\n                        get_op = OP_get_loc_check;\n                    else\n                        get_op = OP_get_loc;\n                }\n                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,\n                                                   pos_next, get_op, var_idx);\n            } else {\n                /* Create a dummy object with a named slot that is\n                   a reference to the local variable */\n                if (var_idx & ARGUMENT_VAR_OFFSET) {\n                    capture_var(s, &s->args[var_idx - ARGUMENT_VAR_OFFSET]);\n                    dbuf_putc(bc, OP_make_arg_ref);\n                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                    dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);\n                } else {\n                    capture_var(s, &s->vars[var_idx]);\n                    dbuf_putc(bc, OP_make_loc_ref);\n                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                    dbuf_put_u16(bc, var_idx);\n                }\n            }\n            break;\n        case OP_scope_put_var:\n            if (!(var_idx & ARGUMENT_VAR_OFFSET) &&\n                s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {\n                /* in non strict mode, modifying the function name is ignored */\n                dbuf_putc(bc, OP_drop);\n                goto done;\n            }\n            goto local_scope_var;\n        case OP_scope_get_ref:\n            dbuf_putc(bc, OP_undefined);\n            goto local_scope_var;\n        case OP_scope_get_var_checkthis:\n        case OP_scope_get_var_undef:\n        case OP_scope_get_var:\n        case OP_scope_put_var_init:\n        local_scope_var:\n            is_put = (op == OP_scope_put_var || op == OP_scope_put_var_init);\n            if (var_idx & ARGUMENT_VAR_OFFSET) {\n                dbuf_putc(bc, OP_get_arg + is_put);\n                dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);\n            } else {\n                if (is_put) {\n                    if (s->vars[var_idx].is_lexical) {\n                        if (op == OP_scope_put_var_init) {\n                            /* 'this' can only be initialized once */\n                            if (var_name == JS_ATOM_this)\n                                dbuf_putc(bc, OP_put_loc_check_init);\n                            else\n                                dbuf_putc(bc, OP_put_loc);\n                        } else {\n                            dbuf_putc(bc, OP_put_loc_check);\n                        }\n                    } else {\n                        dbuf_putc(bc, OP_put_loc);\n                    }\n                } else {\n                    if (s->vars[var_idx].is_lexical) {\n                        if (op == OP_scope_get_var_checkthis) {\n                            /* only used for 'this' return in derived class constructors */\n                            dbuf_putc(bc, OP_get_loc_checkthis);\n                        } else {\n                            dbuf_putc(bc, OP_get_loc_check);\n                        }\n                    } else {\n                        dbuf_putc(bc, OP_get_loc);\n                    }\n                }\n                dbuf_put_u16(bc, var_idx);\n            }\n            break;\n        case OP_scope_delete_var:\n            dbuf_putc(bc, OP_push_false);\n            break;\n        }\n        goto done;\n    }\n    /* check eval object */\n    if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {\n        dbuf_putc(bc, OP_get_loc);\n        dbuf_put_u16(bc, s->var_object_idx);\n        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);\n    }\n    /* check eval object in argument scope */\n    if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {\n        dbuf_putc(bc, OP_get_loc);\n        dbuf_put_u16(bc, s->arg_var_object_idx);\n        var_object_test(ctx, s, var_name, op, bc, &label_done, 0);\n    }\n\n    /* check parent scopes */\n    for (fd = s; fd->parent;) {\n        scope_level = fd->parent_scope_level;\n        fd = fd->parent;\n        for (idx = fd->scopes[scope_level].first; idx >= 0;) {\n            vd = &fd->vars[idx];\n            if (vd->var_name == var_name) {\n                if (op == OP_scope_put_var || op == OP_scope_make_ref) {\n                    if (vd->is_const) {\n                        dbuf_putc(bc, OP_throw_error);\n                        dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                        dbuf_putc(bc, JS_THROW_VAR_RO);\n                        goto done;\n                    }\n                }\n                var_idx = idx;\n                break;\n            } else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {\n                capture_var(fd, vd);\n                idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);\n                if (idx >= 0) {\n                    dbuf_putc(bc, OP_get_var_ref);\n                    dbuf_put_u16(bc, idx);\n                    var_object_test(ctx, s, var_name, op, bc, &label_done, 1);\n                }\n            }\n            idx = vd->scope_next;\n        }\n        is_arg_scope = (idx == ARG_SCOPE_END);\n        if (var_idx >= 0)\n            break;\n\n        if (!is_arg_scope) {\n            var_idx = find_var(ctx, fd, var_name);\n            if (var_idx >= 0)\n                break;\n        }\n        if (is_pseudo_var) {\n            var_idx = resolve_pseudo_var(ctx, fd, var_name);\n            if (var_idx >= 0)\n                break;\n        }\n        if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {\n            var_idx = add_arguments_var(ctx, fd);\n            break;\n        }\n        if (fd->is_func_expr && fd->func_name == var_name) {\n            /* add a new variable with the function name */\n            var_idx = add_func_var(ctx, fd, var_name);\n            break;\n        }\n\n        /* check eval object */\n        if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {\n            vd = &fd->vars[fd->var_object_idx];\n            capture_var(fd, vd);\n            idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,\n                                  fd->var_object_idx, vd->var_name,\n                                  FALSE, FALSE, JS_VAR_NORMAL);\n            dbuf_putc(bc, OP_get_var_ref);\n            dbuf_put_u16(bc, idx);\n            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);\n        }\n\n        /* check eval object in argument scope */\n        if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {\n            vd = &fd->vars[fd->arg_var_object_idx];\n            capture_var(fd, vd);\n            idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,\n                                  fd->arg_var_object_idx, vd->var_name,\n                                  FALSE, FALSE, JS_VAR_NORMAL);\n            dbuf_putc(bc, OP_get_var_ref);\n            dbuf_put_u16(bc, idx);\n            var_object_test(ctx, s, var_name, op, bc, &label_done, 0);\n        }\n\n        if (fd->is_eval)\n            break; /* it it necessarily the top level function */\n    }\n\n    /* check direct eval scope (in the closure of the eval function\n       which is necessarily at the top level) */\n    if (!fd)\n        fd = s;\n    if (var_idx < 0 && fd->is_eval) {\n        int idx1;\n        for (idx1 = 0; idx1 < fd->closure_var_count; idx1++) {\n            JSClosureVar *cv = &fd->closure_var[idx1];\n            if (var_name == cv->var_name) {\n                if (fd != s) {\n                    JSClosureTypeEnum closure_type;\n                    if (cv->closure_type == JS_CLOSURE_GLOBAL ||\n                        cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||\n                        cv->closure_type == JS_CLOSURE_GLOBAL_REF)\n                        closure_type = JS_CLOSURE_GLOBAL_REF;\n                    else\n                        closure_type = JS_CLOSURE_REF;\n                    idx = get_closure_var(ctx, s, fd,\n                                          closure_type,\n                                          idx1,\n                                          cv->var_name, cv->is_const,\n                                          cv->is_lexical, cv->var_kind);\n                } else {\n                    idx = idx1;\n                }\n                if (cv->closure_type == JS_CLOSURE_GLOBAL ||\n                    cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||\n                    cv->closure_type == JS_CLOSURE_GLOBAL_REF)\n                    goto has_global_idx;\n                else\n                    goto has_idx;\n            } else if ((cv->var_name == JS_ATOM__var_ ||\n                        cv->var_name == JS_ATOM__arg_var_ ||\n                        cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {\n                int is_with = (cv->var_name == JS_ATOM__with_);\n                if (fd != s) {\n                    idx = get_closure_var(ctx, s, fd,\n                                          JS_CLOSURE_REF,\n                                          idx1,\n                                          cv->var_name, FALSE, FALSE,\n                                          JS_VAR_NORMAL);\n                } else {\n                    idx = idx1;\n                }\n                dbuf_putc(bc, OP_get_var_ref);\n                dbuf_put_u16(bc, idx);\n                var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);\n            }\n        }\n\n        /* not found: add a closure for a global variable access */\n        idx1 = add_closure_var(ctx, fd, JS_CLOSURE_GLOBAL, 0, var_name,\n                              FALSE, FALSE, JS_VAR_NORMAL);\n        if (idx1 < 0)\n            return -1;\n        if (fd != s) {\n            idx = get_closure_var(ctx, s, fd,\n                                  JS_CLOSURE_GLOBAL_REF,\n                                  idx1,\n                                  var_name, FALSE, FALSE, \n                                  JS_VAR_NORMAL);\n        } else {\n            idx = idx1;\n        }\n    has_global_idx:\n        /* global variable access */\n        switch (op) {\n        case OP_scope_make_ref:\n            if (label_done == -1 && can_opt_put_global_ref_value(bc_buf, ls->pos)) {\n                pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,\n                                                   pos_next,\n                                                   OP_get_var, idx);\n            } else {\n                dbuf_putc(bc, OP_make_var_ref);\n                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n            }\n            break;\n        case OP_scope_get_ref:\n            /* XXX: should create a dummy object with a named slot that is\n               a reference to the global variable */\n            dbuf_putc(bc, OP_undefined);\n            dbuf_putc(bc, OP_get_var);\n            dbuf_put_u16(bc, idx);\n            break;\n        case OP_scope_get_var_undef:\n        case OP_scope_get_var:\n        case OP_scope_put_var:\n            dbuf_putc(bc, OP_get_var_undef + (op - OP_scope_get_var_undef));\n            dbuf_put_u16(bc, idx);\n            break;\n        case OP_scope_put_var_init:\n            dbuf_putc(bc, OP_put_var_init);\n            dbuf_put_u16(bc, idx);\n            break;\n        case OP_scope_delete_var:\n            dbuf_putc(bc, OP_delete_var);\n            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n            break;\n        }\n    } else {\n        /* find the corresponding closure variable */\n        if (var_idx & ARGUMENT_VAR_OFFSET) {\n            capture_var(fd, &fd->args[var_idx - ARGUMENT_VAR_OFFSET]);\n            idx = get_closure_var(ctx, s, fd,\n                                  JS_CLOSURE_ARG, var_idx - ARGUMENT_VAR_OFFSET,\n                                  var_name, FALSE, FALSE, JS_VAR_NORMAL);\n        } else {\n            capture_var(fd, &fd->vars[var_idx]);\n            idx = get_closure_var(ctx, s, fd,\n                                  JS_CLOSURE_LOCAL, var_idx,\n                                  var_name,\n                                  fd->vars[var_idx].is_const,\n                                  fd->vars[var_idx].is_lexical,\n                                  fd->vars[var_idx].var_kind);\n        }\n        if (idx >= 0) {\n        has_idx:\n            if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&\n                s->closure_var[idx].is_const) {\n                dbuf_putc(bc, OP_throw_error);\n                dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                dbuf_putc(bc, JS_THROW_VAR_RO);\n                goto done;\n            }\n            switch (op) {\n            case OP_scope_make_ref:\n                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {\n                    /* Create a dummy object reference for the func_var */\n                    dbuf_putc(bc, OP_object);\n                    dbuf_putc(bc, OP_get_var_ref);\n                    dbuf_put_u16(bc, idx);\n                    dbuf_putc(bc, OP_define_field);\n                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                    dbuf_putc(bc, OP_push_atom_value);\n                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                } else\n                if (label_done == -1 &&\n                    can_opt_put_ref_value(bc_buf, ls->pos)) {\n                    int get_op;\n                    if (s->closure_var[idx].is_lexical)\n                        get_op = OP_get_var_ref_check;\n                    else\n                        get_op = OP_get_var_ref;\n                    pos_next = optimize_scope_make_ref(ctx, s, bc, bc_buf, ls,\n                                                       pos_next,\n                                                       get_op, idx);\n                } else {\n                    /* Create a dummy object with a named slot that is\n                       a reference to the closure variable */\n                    dbuf_putc(bc, OP_make_var_ref_ref);\n                    dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n                    dbuf_put_u16(bc, idx);\n                }\n                break;\n            case OP_scope_put_var:\n                if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {\n                    /* in non strict mode, modifying the function name is ignored */\n                    dbuf_putc(bc, OP_drop);\n                    goto done;\n                }\n                goto closure_scope_var;\n            case OP_scope_get_ref:\n                /* XXX: should create a dummy object with a named slot that is\n                   a reference to the closure variable */\n                dbuf_putc(bc, OP_undefined);\n                goto closure_scope_var;\n            case OP_scope_get_var_undef:\n            case OP_scope_get_var:\n            case OP_scope_put_var_init:\n            closure_scope_var:\n                is_put = (op == OP_scope_put_var ||\n                          op == OP_scope_put_var_init);\n                if (is_put) {\n                    if (s->closure_var[idx].is_lexical) {\n                        if (op == OP_scope_put_var_init) {\n                            /* 'this' can only be initialized once */\n                            if (var_name == JS_ATOM_this)\n                                dbuf_putc(bc, OP_put_var_ref_check_init);\n                            else\n                                dbuf_putc(bc, OP_put_var_ref);\n                        } else {\n                            dbuf_putc(bc, OP_put_var_ref_check);\n                        }\n                    } else {\n                        dbuf_putc(bc, OP_put_var_ref);\n                    }\n                } else {\n                    if (s->closure_var[idx].is_lexical) {\n                        dbuf_putc(bc, OP_get_var_ref_check);\n                    } else {\n                        dbuf_putc(bc, OP_get_var_ref);\n                    }\n                }\n                dbuf_put_u16(bc, idx);\n                break;\n            case OP_scope_delete_var:\n                dbuf_putc(bc, OP_push_false);\n                break;\n            }\n            goto done;\n        }\n    }\n\ndone:\n    if (label_done >= 0) {\n        dbuf_putc(bc, OP_label);\n        dbuf_put_u32(bc, label_done);\n        s->label_slots[label_done].pos2 = bc->size;\n    }\n    return pos_next;\n}\n\n/* search in all scopes */\nstatic int find_private_class_field_all(JSContext *ctx, JSFunctionDef *fd,\n                                        JSAtom name, int scope_level)\n{\n    int idx;\n\n    idx = fd->scopes[scope_level].first;\n    while (idx >= 0) {\n        if (fd->vars[idx].var_name == name)\n            return idx;\n        idx = fd->vars[idx].scope_next;\n    }\n    return -1;\n}\n\nstatic void get_loc_or_ref(DynBuf *bc, BOOL is_ref, int idx)\n{\n    /* if the field is not initialized, the error is catched when\n       accessing it */\n    if (is_ref)\n        dbuf_putc(bc, OP_get_var_ref);\n    else\n        dbuf_putc(bc, OP_get_loc);\n    dbuf_put_u16(bc, idx);\n}\n\nstatic int resolve_scope_private_field1(JSContext *ctx,\n                                        BOOL *pis_ref, int *pvar_kind,\n                                        JSFunctionDef *s,\n                                        JSAtom var_name, int scope_level)\n{\n    int idx, var_kind;\n    JSFunctionDef *fd;\n    BOOL is_ref;\n\n    fd = s;\n    is_ref = FALSE;\n    for(;;) {\n        idx = find_private_class_field_all(ctx, fd, var_name, scope_level);\n        if (idx >= 0) {\n            var_kind = fd->vars[idx].var_kind;\n            if (is_ref) {\n                capture_var(fd, &fd->vars[idx]);\n                idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, var_name,\n                                      TRUE, TRUE, JS_VAR_NORMAL);\n                if (idx < 0)\n                    return -1;\n            }\n            break;\n        }\n        scope_level = fd->parent_scope_level;\n        if (!fd->parent) {\n            if (fd->is_eval) {\n                /* closure of the eval function (top level) */\n                for (idx = 0; idx < fd->closure_var_count; idx++) {\n                    JSClosureVar *cv = &fd->closure_var[idx];\n                    if (cv->var_name == var_name) {\n                        var_kind = cv->var_kind;\n                        is_ref = TRUE;\n                        if (fd != s) {\n                            idx = get_closure_var(ctx, s, fd,\n                                                  JS_CLOSURE_REF,\n                                                  idx,\n                                                  cv->var_name, cv->is_const,\n                                                  cv->is_lexical,\n                                                  cv->var_kind);\n                            if (idx < 0)\n                                return -1;\n                        }\n                        goto done;\n                    }\n                }\n            }\n            /* XXX: no line number info */\n            JS_ThrowSyntaxErrorAtom(ctx, \"undefined private field '%s'\",\n                                    var_name);\n            return -1;\n        } else {\n            fd = fd->parent;\n        }\n        is_ref = TRUE;\n    }\n done:\n    *pis_ref = is_ref;\n    *pvar_kind = var_kind;\n    return idx;\n}\n\n/* return 0 if OK or -1 if the private field could not be resolved */\nstatic int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,\n                                       JSAtom var_name, int scope_level, int op,\n                                       DynBuf *bc)\n{\n    int idx, var_kind;\n    BOOL is_ref;\n\n    idx = resolve_scope_private_field1(ctx, &is_ref, &var_kind, s,\n                                       var_name, scope_level);\n    if (idx < 0)\n        return -1;\n    assert(var_kind != JS_VAR_NORMAL);\n    switch (op) {\n    case OP_scope_get_private_field:\n    case OP_scope_get_private_field2:\n        switch(var_kind) {\n        case JS_VAR_PRIVATE_FIELD:\n            if (op == OP_scope_get_private_field2)\n                dbuf_putc(bc, OP_dup);\n            get_loc_or_ref(bc, is_ref, idx);\n            dbuf_putc(bc, OP_get_private_field);\n            break;\n        case JS_VAR_PRIVATE_METHOD:\n            get_loc_or_ref(bc, is_ref, idx);\n            dbuf_putc(bc, OP_check_brand);\n            if (op != OP_scope_get_private_field2)\n                dbuf_putc(bc, OP_nip);\n            break;\n        case JS_VAR_PRIVATE_GETTER:\n        case JS_VAR_PRIVATE_GETTER_SETTER:\n            if (op == OP_scope_get_private_field2)\n                dbuf_putc(bc, OP_dup);\n            get_loc_or_ref(bc, is_ref, idx);\n            dbuf_putc(bc, OP_check_brand);\n            dbuf_putc(bc, OP_call_method);\n            dbuf_put_u16(bc, 0);\n            break;\n        case JS_VAR_PRIVATE_SETTER:\n            /* XXX: add clearer error message */\n            dbuf_putc(bc, OP_throw_error);\n            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n            dbuf_putc(bc, JS_THROW_VAR_RO);\n            break;\n        default:\n            abort();\n        }\n        break;\n    case OP_scope_put_private_field:\n        switch(var_kind) {\n        case JS_VAR_PRIVATE_FIELD:\n            get_loc_or_ref(bc, is_ref, idx);\n            dbuf_putc(bc, OP_put_private_field);\n            break;\n        case JS_VAR_PRIVATE_METHOD:\n        case JS_VAR_PRIVATE_GETTER:\n            /* XXX: add clearer error message */\n            dbuf_putc(bc, OP_throw_error);\n            dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));\n            dbuf_putc(bc, JS_THROW_VAR_RO);\n            break;\n        case JS_VAR_PRIVATE_SETTER:\n        case JS_VAR_PRIVATE_GETTER_SETTER:\n            {\n                JSAtom setter_name = get_private_setter_name(ctx, var_name);\n                if (setter_name == JS_ATOM_NULL)\n                    return -1;\n                idx = resolve_scope_private_field1(ctx, &is_ref,\n                                                   &var_kind, s,\n                                                   setter_name, scope_level);\n                JS_FreeAtom(ctx, setter_name);\n                if (idx < 0)\n                    return -1;\n                assert(var_kind == JS_VAR_PRIVATE_SETTER);\n                get_loc_or_ref(bc, is_ref, idx);\n                dbuf_putc(bc, OP_swap);\n                /* obj func value */\n                dbuf_putc(bc, OP_rot3r);\n                /* value obj func */\n                dbuf_putc(bc, OP_check_brand);\n                dbuf_putc(bc, OP_rot3l);\n                /* obj func value */\n                dbuf_putc(bc, OP_call_method);\n                dbuf_put_u16(bc, 1);\n                dbuf_putc(bc, OP_drop);\n            }\n            break;\n        default:\n            abort();\n        }\n        break;\n    case OP_scope_in_private_field:\n        get_loc_or_ref(bc, is_ref, idx);\n        dbuf_putc(bc, OP_private_in);\n        break;\n    default:\n        abort();\n    }\n    return 0;\n}\n\nstatic void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,\n                                         int scope_level)\n{\n    int idx;\n    JSVarDef *vd;\n\n    for (idx = s->scopes[scope_level].first; idx >= 0;) {\n        vd = &s->vars[idx];\n        capture_var(s, vd);\n        idx = vd->scope_next;\n    }\n}\n\n/* XXX: should handle the argument scope generically */\nstatic BOOL is_var_in_arg_scope(JSAtom var_name, JSVarKindEnum var_kind)\n{\n    return (var_name == JS_ATOM_home_object ||\n            var_name == JS_ATOM_this_active_func ||\n            var_name == JS_ATOM_new_target ||\n            var_name == JS_ATOM_this ||\n            var_name == JS_ATOM__arg_var_ ||\n            var_kind == JS_VAR_FUNCTION_NAME);\n}\n\nstatic void add_eval_variables(JSContext *ctx, JSFunctionDef *s)\n{\n    JSFunctionDef *fd;\n    JSVarDef *vd;\n    int i, scope_level, scope_idx;\n    BOOL has_arguments_binding, has_this_binding, is_arg_scope;\n\n    /* in non strict mode, variables are created in the caller's\n       environment object */\n    if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {\n        s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);\n        if (s->has_parameter_expressions) {\n            /* an additional variable object is needed for the\n               argument scope */\n            s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);\n        }\n    }\n\n    /* eval can potentially use 'arguments' so we must define it */\n    has_this_binding = s->has_this_binding;\n    if (has_this_binding) {\n        if (s->this_var_idx < 0)\n            s->this_var_idx = add_var_this(ctx, s);\n        if (s->new_target_var_idx < 0)\n            s->new_target_var_idx = add_var(ctx, s, JS_ATOM_new_target);\n        if (s->is_derived_class_constructor && s->this_active_func_var_idx < 0)\n            s->this_active_func_var_idx = add_var(ctx, s, JS_ATOM_this_active_func);\n        if (s->has_home_object && s->home_object_var_idx < 0)\n            s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);\n    }\n    has_arguments_binding = s->has_arguments_binding;\n    if (has_arguments_binding) {\n        add_arguments_var(ctx, s);\n        /* also add an arguments binding in the argument scope to\n           raise an error if a direct eval in the argument scope tries\n           to redefine it */\n        if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))\n            add_arguments_arg(ctx, s);\n    }\n    if (s->is_func_expr && s->func_name != JS_ATOM_NULL)\n        add_func_var(ctx, s, s->func_name);\n\n    for(i = 0; i < s->arg_count; i++) {\n        vd = &s->args[i];\n        capture_var(s, vd);\n    }\n    for(i = 0; i < s->var_count; i++) {\n        vd = &s->vars[i];\n        /* do not close top level last result */\n        if (vd->scope_level == 0 &&\n            vd->var_name != JS_ATOM__ret_ &&\n            vd->var_name != JS_ATOM_NULL) {\n            capture_var(s, vd);\n        }\n    }\n    \n    /* eval can use all the variables of the enclosing functions, so\n       they must be all put in the closure. The closure variables are\n       ordered by scope. It works only because no closure are created\n       before. */\n    assert(s->is_eval || s->closure_var_count == 0);\n\n    /* XXX: inefficient, but eval performance is less critical */\n    fd = s;\n    for(;;) {\n        scope_level = fd->parent_scope_level;\n        fd = fd->parent;\n        if (!fd)\n            break;\n        /* add 'this' if it was not previously added */\n        if (!has_this_binding && fd->has_this_binding) {\n            if (fd->this_var_idx < 0)\n                fd->this_var_idx = add_var_this(ctx, fd);\n            if (fd->new_target_var_idx < 0)\n                fd->new_target_var_idx = add_var(ctx, fd, JS_ATOM_new_target);\n            if (fd->is_derived_class_constructor && fd->this_active_func_var_idx < 0)\n                fd->this_active_func_var_idx = add_var(ctx, fd, JS_ATOM_this_active_func);\n            if (fd->has_home_object && fd->home_object_var_idx < 0)\n                fd->home_object_var_idx = add_var(ctx, fd, JS_ATOM_home_object);\n            has_this_binding = TRUE;\n        }\n        /* add 'arguments' if it was not previously added */\n        if (!has_arguments_binding && fd->has_arguments_binding) {\n            add_arguments_var(ctx, fd);\n            has_arguments_binding = TRUE;\n        }\n        /* add function name */\n        if (fd->is_func_expr && fd->func_name != JS_ATOM_NULL)\n            add_func_var(ctx, fd, fd->func_name);\n\n        /* add lexical variables */\n        scope_idx = fd->scopes[scope_level].first;\n        while (scope_idx >= 0) {\n            vd = &fd->vars[scope_idx];\n            capture_var(fd, vd);\n            get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, scope_idx,\n                            vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);\n            scope_idx = vd->scope_next;\n        }\n        is_arg_scope = (scope_idx == ARG_SCOPE_END);\n        if (!is_arg_scope) {\n            /* add unscoped variables */\n            /* XXX: propagate is_const and var_kind too ? */\n            for(i = 0; i < fd->arg_count; i++) {\n                vd = &fd->args[i];\n                if (vd->var_name != JS_ATOM_NULL) {\n                    capture_var(fd, vd);\n                    get_closure_var(ctx, s, fd,\n                                    JS_CLOSURE_ARG, i, vd->var_name, FALSE,\n                                    vd->is_lexical, JS_VAR_NORMAL);\n                }\n            }\n            for(i = 0; i < fd->var_count; i++) {\n                vd = &fd->vars[i];\n                /* do not close top level last result */\n                if (vd->scope_level == 0 &&\n                    vd->var_name != JS_ATOM__ret_ &&\n                    vd->var_name != JS_ATOM_NULL) {\n                    capture_var(fd, vd);\n                    get_closure_var(ctx, s, fd,\n                                    JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,\n                                    vd->is_lexical, JS_VAR_NORMAL);\n                }\n            }\n        } else {\n            for(i = 0; i < fd->var_count; i++) {\n                vd = &fd->vars[i];\n                /* do not close top level last result */\n                if (vd->scope_level == 0 && is_var_in_arg_scope(vd->var_name, vd->var_kind)) {\n                    capture_var(fd, vd);\n                    get_closure_var(ctx, s, fd,\n                                    JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,\n                                    vd->is_lexical, JS_VAR_NORMAL);\n                }\n            }\n        }\n        if (fd->is_eval) {\n            int idx;\n            /* add direct eval variables (we are necessarily at the\n               top level). */\n            for (idx = 0; idx < fd->closure_var_count; idx++) {\n                JSClosureVar *cv = &fd->closure_var[idx];\n                /* Global variables are removed but module\n                   definitions are kept. */\n                if (cv->closure_type != JS_CLOSURE_GLOBAL_REF &&\n                    cv->closure_type != JS_CLOSURE_GLOBAL_DECL &&\n                    cv->closure_type != JS_CLOSURE_GLOBAL) {\n                    get_closure_var(ctx, s, fd,\n                                    JS_CLOSURE_REF,\n                                    idx, cv->var_name, cv->is_const,\n                                    cv->is_lexical, cv->var_kind);\n                }\n            }\n        }\n    }\n}\n\nstatic void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,\n                                 JSBytecodeVarDef *vd, int var_idx)\n{\n    cv->closure_type = JS_CLOSURE_LOCAL;\n    cv->is_const = vd->is_const;\n    cv->is_lexical = vd->is_lexical;\n    cv->var_kind = vd->var_kind;\n    cv->var_idx = var_idx;\n    cv->var_name = JS_DupAtom(ctx, vd->var_name);\n}\n\n/* for direct eval compilation: add references to the variables of the\n   calling function */\nstatic __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,\n                                             JSFunctionBytecode *b, int scope_idx)\n{\n    int i, count;\n    JSBytecodeVarDef *vd;\n    BOOL is_arg_scope;\n\n    count = b->arg_count + b->var_count + b->closure_var_count;\n    s->closure_var = NULL;\n    s->closure_var_count = 0;\n    s->closure_var_size = count;\n    if (count == 0)\n        return 0;\n    s->closure_var = js_malloc(ctx, sizeof(s->closure_var[0]) * count);\n    if (!s->closure_var)\n        return -1;\n    /* Add lexical variables in scope at the point of evaluation */\n    for (i = scope_idx; i >= 0;) {\n        vd = &b->vardefs[b->arg_count + i];\n        if (vd->has_scope) {\n            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];\n            set_closure_from_var(ctx, cv, vd, i);\n        }\n        i = vd->scope_next;\n    }\n    is_arg_scope = (i == ARG_SCOPE_END);\n    if (!is_arg_scope) {\n        /* Add argument variables */\n        for(i = 0; i < b->arg_count; i++) {\n            JSClosureVar *cv = &s->closure_var[s->closure_var_count++];\n            vd = &b->vardefs[i];\n            cv->closure_type = JS_CLOSURE_ARG;\n            cv->is_const = FALSE;\n            cv->is_lexical = FALSE;\n            cv->var_kind = JS_VAR_NORMAL;\n            cv->var_idx = i;\n            cv->var_name = JS_DupAtom(ctx, vd->var_name);\n        }\n        /* Add local non lexical variables */\n        for(i = 0; i < b->var_count; i++) {\n            vd = &b->vardefs[b->arg_count + i];\n            if (!vd->has_scope && vd->var_name != JS_ATOM__ret_) {\n                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];\n                set_closure_from_var(ctx, cv, vd, i);\n            }\n        }\n    } else {\n        /* only add pseudo variables */\n        for(i = 0; i < b->var_count; i++) {\n            vd = &b->vardefs[b->arg_count + i];\n            if (!vd->has_scope && is_var_in_arg_scope(vd->var_name, vd->var_kind)) {\n                JSClosureVar *cv = &s->closure_var[s->closure_var_count++];\n                set_closure_from_var(ctx, cv, vd, i);\n            }\n        }\n    }\n    for(i = 0; i < b->closure_var_count; i++) {\n        JSClosureVar *cv0 = &b->closure_var[i];\n        JSClosureVar *cv;\n\n        switch(cv0->closure_type) {\n        case JS_CLOSURE_LOCAL:\n        case JS_CLOSURE_ARG:\n        case JS_CLOSURE_REF:\n        case JS_CLOSURE_MODULE_DECL:\n        case JS_CLOSURE_MODULE_IMPORT:\n            break;\n        case JS_CLOSURE_GLOBAL_REF:\n        case JS_CLOSURE_GLOBAL_DECL:\n        case JS_CLOSURE_GLOBAL:\n            continue; /* not necessary to add global variables */\n        default:\n            abort();\n        }\n        cv = &s->closure_var[s->closure_var_count++];\n        cv->closure_type = JS_CLOSURE_REF;\n        cv->is_const = cv0->is_const;\n        cv->is_lexical = cv0->is_lexical;\n        cv->var_kind = cv0->var_kind;\n        cv->var_idx = i;\n        cv->var_name = JS_DupAtom(ctx, cv0->var_name);\n    }\n    return 0;\n}\n\ntypedef struct CodeContext {\n    const uint8_t *bc_buf; /* code buffer */\n    int bc_len;   /* length of the code buffer */\n    int pos;      /* position past the matched code pattern */\n    int line_num; /* last visited OP_line_num parameter or -1 */\n    int op;\n    int idx;\n    int label;\n    int val;\n    JSAtom atom;\n} CodeContext;\n\n#define M2(op1, op2)            ((op1) | ((op2) << 8))\n#define M3(op1, op2, op3)       ((op1) | ((op2) << 8) | ((op3) << 16))\n#define M4(op1, op2, op3, op4)  ((op1) | ((op2) << 8) | ((op3) << 16) | ((op4) << 24))\n\nstatic BOOL code_match(CodeContext *s, int pos, ...)\n{\n    const uint8_t *tab = s->bc_buf;\n    int op, len, op1, line_num, pos_next;\n    va_list ap;\n    BOOL ret = FALSE;\n\n    line_num = -1;\n    va_start(ap, pos);\n\n    for(;;) {\n        op1 = va_arg(ap, int);\n        if (op1 == -1) {\n            s->pos = pos;\n            s->line_num = line_num;\n            ret = TRUE;\n            break;\n        }\n        for (;;) {\n            if (pos >= s->bc_len)\n                goto done;\n            op = tab[pos];\n            len = opcode_info[op].size;\n            pos_next = pos + len;\n            if (pos_next > s->bc_len)\n                goto done;\n            if (op == OP_line_num) {\n                line_num = get_u32(tab + pos + 1);\n                pos = pos_next;\n            } else {\n                break;\n            }\n        }\n        if (op != op1) {\n            if (op1 == (uint8_t)op1 || !op)\n                break;\n            if (op != (uint8_t)op1\n            &&  op != (uint8_t)(op1 >> 8)\n            &&  op != (uint8_t)(op1 >> 16)\n            &&  op != (uint8_t)(op1 >> 24)) {\n                break;\n            }\n            s->op = op;\n        }\n\n        pos++;\n        switch(opcode_info[op].fmt) {\n        case OP_FMT_loc8:\n        case OP_FMT_u8:\n            {\n                int idx = tab[pos];\n                int arg = va_arg(ap, int);\n                if (arg == -1) {\n                    s->idx = idx;\n                } else {\n                    if (arg != idx)\n                        goto done;\n                }\n                break;\n            }\n        case OP_FMT_u16:\n        case OP_FMT_npop:\n        case OP_FMT_loc:\n        case OP_FMT_arg:\n        case OP_FMT_var_ref:\n            {\n                int idx = get_u16(tab + pos);\n                int arg = va_arg(ap, int);\n                if (arg == -1) {\n                    s->idx = idx;\n                } else {\n                    if (arg != idx)\n                        goto done;\n                }\n                break;\n            }\n        case OP_FMT_i32:\n        case OP_FMT_u32:\n        case OP_FMT_label:\n        case OP_FMT_const:\n            {\n                s->label = get_u32(tab + pos);\n                break;\n            }\n        case OP_FMT_label_u16:\n            {\n                s->label = get_u32(tab + pos);\n                s->val = get_u16(tab + pos + 4);\n                break;\n            }\n        case OP_FMT_atom:\n            {\n                s->atom = get_u32(tab + pos);\n                break;\n            }\n        case OP_FMT_atom_u8:\n            {\n                s->atom = get_u32(tab + pos);\n                s->val = get_u8(tab + pos + 4);\n                break;\n            }\n        case OP_FMT_atom_u16:\n            {\n                s->atom = get_u32(tab + pos);\n                s->val = get_u16(tab + pos + 4);\n                break;\n            }\n        case OP_FMT_atom_label_u8:\n            {\n                s->atom = get_u32(tab + pos);\n                s->label = get_u32(tab + pos + 4);\n                s->val = get_u8(tab + pos + 8);\n                break;\n            }\n        default:\n            break;\n        }\n        pos = pos_next;\n    }\n done:\n    va_end(ap);\n    return ret;\n}\n\nstatic void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)\n{\n    int i, idx, label_next = -1;\n\n    /* add the hoisted functions in arguments and local variables */\n    for(i = 0; i < s->arg_count; i++) {\n        JSVarDef *vd = &s->args[i];\n        if (vd->func_pool_idx >= 0) {\n            dbuf_putc(bc, OP_fclosure);\n            dbuf_put_u32(bc, vd->func_pool_idx);\n            dbuf_putc(bc, OP_put_arg);\n            dbuf_put_u16(bc, i);\n        }\n    }\n    for(i = 0; i < s->var_count; i++) {\n        JSVarDef *vd = &s->vars[i];\n        if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {\n            dbuf_putc(bc, OP_fclosure);\n            dbuf_put_u32(bc, vd->func_pool_idx);\n            dbuf_putc(bc, OP_put_loc);\n            dbuf_put_u16(bc, i);\n        }\n    }\n\n    /* the module global variables must be initialized before\n       evaluating the module so that the exported functions are\n       visible if there are cyclic module references */\n    if (s->module) {\n        label_next = new_label_fd(s);\n        if (label_next < 0) {\n            dbuf_set_error(bc);\n            return;\n        }\n        /* if 'this' is true, initialize the global variables and return */\n        dbuf_putc(bc, OP_push_this);\n        dbuf_putc(bc, OP_if_false);\n        dbuf_put_u32(bc, label_next);\n        update_label(s, label_next, 1);\n        s->jump_size++;\n    }\n\n    /* add the global variables (only happens if s->is_global_var is\n       true) */\n    /* XXX: inefficient, add a closure index in JSGlobalVar */\n    for(i = 0; i < s->global_var_count; i++) {\n        JSGlobalVar *hf = &s->global_vars[i];\n        BOOL has_var_obj = FALSE;\n        BOOL force_init = hf->force_init;\n        /* we are in an eval, so the closure contains all the\n           enclosing variables */\n        /* If the outer function has a variable environment,\n           create a property for the variable there */\n        for(idx = 0; idx < s->closure_var_count; idx++) {\n            JSClosureVar *cv = &s->closure_var[idx];\n            if (cv->var_name == hf->var_name) {\n                force_init = FALSE;\n                goto closure_found;\n            }\n            if (cv->var_name == JS_ATOM__var_ ||\n                cv->var_name == JS_ATOM__arg_var_) {\n                dbuf_putc(bc, OP_get_var_ref);\n                dbuf_put_u16(bc, idx);\n                has_var_obj = TRUE;\n                force_init = TRUE;\n                goto closure_found;\n            }\n        }\n        abort();\n    closure_found:\n        if (hf->cpool_idx >= 0 || force_init) {\n            if (hf->cpool_idx >= 0) {\n                dbuf_putc(bc, OP_fclosure);\n                dbuf_put_u32(bc, hf->cpool_idx);\n                if (hf->var_name == JS_ATOM__default_) {\n                    /* set default export function name */\n                    dbuf_putc(bc, OP_set_name);\n                    dbuf_put_u32(bc, JS_DupAtom(ctx, JS_ATOM_default));\n                }\n            } else {\n                dbuf_putc(bc, OP_undefined);\n            }\n            if (!has_var_obj) {\n                dbuf_putc(bc, OP_put_var_ref);\n                dbuf_put_u16(bc, idx);\n            } else {\n                dbuf_putc(bc, OP_define_field);\n                dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));\n                dbuf_putc(bc, OP_drop);\n            }\n        }\n        JS_FreeAtom(ctx, hf->var_name);\n    }\n\n    if (s->module) {\n        dbuf_putc(bc, OP_return_undef);\n\n        dbuf_putc(bc, OP_label);\n        dbuf_put_u32(bc, label_next);\n        s->label_slots[label_next].pos2 = bc->size;\n    }\n\n    js_free(ctx, s->global_vars);\n    s->global_vars = NULL;\n    s->global_var_count = 0;\n    s->global_var_size = 0;\n}\n\nstatic int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,\n                          int pos, int *linep)\n{\n    int op, len, label;\n\n    for (; pos < bc_len; pos += len) {\n        op = bc_buf[pos];\n        len = opcode_info[op].size;\n        if (op == OP_line_num) {\n            *linep = get_u32(bc_buf + pos + 1);\n        } else\n        if (op == OP_label) {\n            label = get_u32(bc_buf + pos + 1);\n            if (update_label(s, label, 0) > 0)\n                break;\n#if 0\n            if (s->label_slots[label].first_reloc) {\n                printf(\"line %d: unreferenced label %d:%d has relocations\\n\",\n                       *linep, label, s->label_slots[label].pos2);\n            }\n#endif\n            assert(s->label_slots[label].first_reloc == NULL);\n        } else {\n            /* XXX: output a warning for unreachable code? */\n            JSAtom atom;\n            switch(opcode_info[op].fmt) {\n            case OP_FMT_label:\n            case OP_FMT_label_u16:\n                label = get_u32(bc_buf + pos + 1);\n                update_label(s, label, -1);\n                break;\n            case OP_FMT_atom_label_u8:\n            case OP_FMT_atom_label_u16:\n                label = get_u32(bc_buf + pos + 5);\n                update_label(s, label, -1);\n                /* fall thru */\n            case OP_FMT_atom:\n            case OP_FMT_atom_u8:\n            case OP_FMT_atom_u16:\n                atom = get_u32(bc_buf + pos + 1);\n                JS_FreeAtom(s->ctx, atom);\n                break;\n            default:\n                break;\n            }\n        }\n    }\n    return pos;\n}\n\nstatic int get_label_pos(JSFunctionDef *s, int label)\n{\n    int i, pos;\n    for (i = 0; i < 20; i++) {\n        pos = s->label_slots[label].pos;\n        for (;;) {\n            switch (s->byte_code.buf[pos]) {\n            case OP_line_num:\n            case OP_label:\n                pos += 5;\n                continue;\n            case OP_goto:\n                label = get_u32(s->byte_code.buf + pos + 1);\n                break;\n            default:\n                return pos;\n            }\n            break;\n        }\n    }\n    return pos;\n}\n\n/* convert global variable accesses to local variables or closure\n   variables when necessary */\nstatic __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)\n{\n    int pos, pos_next, bc_len, op, len, line_num, i, idx;\n    uint8_t *bc_buf;\n    JSAtom var_name;\n    DynBuf bc_out;\n    CodeContext cc;\n    int scope;\n\n    cc.bc_buf = bc_buf = s->byte_code.buf;\n    cc.bc_len = bc_len = s->byte_code.size;\n    js_dbuf_bytecode_init(ctx, &bc_out);\n\n    /* first pass for runtime checks (must be done before the\n       variables are created) */\n    /* XXX: inefficient */\n    for(i = 0; i < s->global_var_count; i++) {\n        JSGlobalVar *hf = &s->global_vars[i];\n\n        /* check if global variable (XXX: simplify) */\n        for(idx = 0; idx < s->closure_var_count; idx++) {\n            JSClosureVar *cv = &s->closure_var[idx];\n            if (cv->closure_type == JS_CLOSURE_GLOBAL_REF ||\n                cv->closure_type == JS_CLOSURE_GLOBAL_DECL ||\n                cv->closure_type == JS_CLOSURE_GLOBAL ||\n                cv->closure_type == JS_CLOSURE_MODULE_DECL ||\n                cv->closure_type == JS_CLOSURE_MODULE_IMPORT)\n                goto next; /* don't look at global variables (they are at the end) */\n            if (cv->var_name == hf->var_name) {\n                if (s->eval_type == JS_EVAL_TYPE_DIRECT &&\n                    cv->is_lexical) {\n                    /* Check if a lexical variable is\n                       redefined as 'var'. XXX: Could abort\n                       compilation here, but for consistency\n                       with the other checks, we delay the\n                       error generation. */\n                    dbuf_putc(&bc_out, OP_throw_error);\n                    dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));\n                    dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);\n                }\n                goto next;\n            }\n            if (cv->var_name == JS_ATOM__var_ ||\n                cv->var_name == JS_ATOM__arg_var_)\n                goto next;\n        }\n    next: ;\n    }\n\n    line_num = 0; /* avoid warning */\n    for (pos = 0; pos < bc_len; pos = pos_next) {\n        op = bc_buf[pos];\n        len = opcode_info[op].size;\n        pos_next = pos + len;\n        switch(op) {\n        case OP_line_num:\n            line_num = get_u32(bc_buf + pos + 1);\n            s->line_number_size++;\n            goto no_change;\n\n        case OP_eval: /* convert scope index to adjusted variable index */\n            {\n                int call_argc = get_u16(bc_buf + pos + 1);\n                scope = get_u16(bc_buf + pos + 1 + 2);\n                mark_eval_captured_variables(ctx, s, scope);\n                dbuf_putc(&bc_out, op);\n                dbuf_put_u16(&bc_out, call_argc);\n                dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);\n            }\n            break;\n        case OP_apply_eval: /* convert scope index to adjusted variable index */\n            scope = get_u16(bc_buf + pos + 1);\n            mark_eval_captured_variables(ctx, s, scope);\n            dbuf_putc(&bc_out, op);\n            dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);\n            break;\n        case OP_scope_get_var_checkthis:\n        case OP_scope_get_var_undef:\n        case OP_scope_get_var:\n        case OP_scope_put_var:\n        case OP_scope_delete_var:\n        case OP_scope_get_ref:\n        case OP_scope_put_var_init:\n            var_name = get_u32(bc_buf + pos + 1);\n            scope = get_u16(bc_buf + pos + 5);\n            pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,\n                                         NULL, NULL, pos_next);\n            JS_FreeAtom(ctx, var_name);\n            break;\n        case OP_scope_make_ref:\n            {\n                int label;\n                LabelSlot *ls;\n                var_name = get_u32(bc_buf + pos + 1);\n                label = get_u32(bc_buf + pos + 5);\n                scope = get_u16(bc_buf + pos + 9);\n                ls = &s->label_slots[label];\n                ls->ref_count--;  /* always remove label reference */\n                pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,\n                                             bc_buf, ls, pos_next);\n                JS_FreeAtom(ctx, var_name);\n            }\n            break;\n        case OP_scope_get_private_field:\n        case OP_scope_get_private_field2:\n        case OP_scope_put_private_field:\n        case OP_scope_in_private_field:\n            {\n                int ret;\n                var_name = get_u32(bc_buf + pos + 1);\n                scope = get_u16(bc_buf + pos + 5);\n                ret = resolve_scope_private_field(ctx, s, var_name, scope, op, &bc_out);\n                if (ret < 0)\n                    goto fail;\n                JS_FreeAtom(ctx, var_name);\n            }\n            break;\n        case OP_gosub:\n            s->jump_size++;\n            if (OPTIMIZE) {\n                /* remove calls to empty finalizers  */\n                int label;\n                LabelSlot *ls;\n\n                label = get_u32(bc_buf + pos + 1);\n                assert(label >= 0 && label < s->label_count);\n                ls = &s->label_slots[label];\n                if (code_match(&cc, ls->pos, OP_ret, -1)) {\n                    ls->ref_count--;\n                    break;\n                }\n            }\n            goto no_change;\n        case OP_drop:\n            if (0) {\n                /* remove drops before return_undef */\n                /* do not perform this optimization in pass2 because\n                   it breaks patterns recognised in resolve_labels */\n                int pos1 = pos_next;\n                int line1 = line_num;\n                while (code_match(&cc, pos1, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line1 = cc.line_num;\n                    pos1 = cc.pos;\n                }\n                if (code_match(&cc, pos1, OP_return_undef, -1)) {\n                    pos_next = pos1;\n                    if (line1 != -1 && line1 != line_num) {\n                        line_num = line1;\n                        s->line_number_size++;\n                        dbuf_putc(&bc_out, OP_line_num);\n                        dbuf_put_u32(&bc_out, line_num);\n                    }\n                    break;\n                }\n            }\n            goto no_change;\n        case OP_insert3:\n            if (OPTIMIZE) {\n                /* Transformation: insert3 put_array_el|put_ref_value drop -> put_array_el|put_ref_value */\n                if (code_match(&cc, pos_next, M2(OP_put_array_el, OP_put_ref_value), OP_drop, -1)) {\n                    dbuf_putc(&bc_out, cc.op);\n                    pos_next = cc.pos;\n                    if (cc.line_num != -1 && cc.line_num != line_num) {\n                        line_num = cc.line_num;\n                        s->line_number_size++;\n                        dbuf_putc(&bc_out, OP_line_num);\n                        dbuf_put_u32(&bc_out, line_num);\n                    }\n                    break;\n                }\n            }\n            goto no_change;\n\n        case OP_goto:\n            s->jump_size++;\n            /* fall thru */\n        case OP_tail_call:\n        case OP_tail_call_method:\n        case OP_return:\n        case OP_return_undef:\n        case OP_throw:\n        case OP_throw_error:\n        case OP_ret:\n            if (OPTIMIZE) {\n                /* remove dead code */\n                int line = -1;\n                dbuf_put(&bc_out, bc_buf + pos, len);\n                pos = skip_dead_code(s, bc_buf, bc_len, pos + len, &line);\n                pos_next = pos;\n                if (pos < bc_len && line >= 0 && line_num != line) {\n                    line_num = line;\n                    s->line_number_size++;\n                    dbuf_putc(&bc_out, OP_line_num);\n                    dbuf_put_u32(&bc_out, line_num);\n                }\n                break;\n            }\n            goto no_change;\n\n        case OP_label:\n            {\n                int label;\n                LabelSlot *ls;\n\n                label = get_u32(bc_buf + pos + 1);\n                assert(label >= 0 && label < s->label_count);\n                ls = &s->label_slots[label];\n                ls->pos2 = bc_out.size + opcode_info[op].size;\n            }\n            goto no_change;\n\n        case OP_enter_scope:\n            {\n                int scope_idx, scope = get_u16(bc_buf + pos + 1);\n\n                if (scope == s->body_scope) {\n                    instantiate_hoisted_definitions(ctx, s, &bc_out);\n                }\n\n                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {\n                    JSVarDef *vd = &s->vars[scope_idx];\n                    if (vd->scope_level == scope) {\n                        if (scope_idx != s->arguments_arg_idx) {\n                            if (vd->var_kind == JS_VAR_FUNCTION_DECL ||\n                                vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {\n                                /* Initialize lexical variable upon entering scope */\n                                dbuf_putc(&bc_out, OP_fclosure);\n                                dbuf_put_u32(&bc_out, vd->func_pool_idx);\n                                dbuf_putc(&bc_out, OP_put_loc);\n                                dbuf_put_u16(&bc_out, scope_idx);\n                            } else {\n                                /* XXX: should check if variable can be used\n                                   before initialization */\n                                dbuf_putc(&bc_out, OP_set_loc_uninitialized);\n                                dbuf_put_u16(&bc_out, scope_idx);\n                            }\n                        }\n                        scope_idx = vd->scope_next;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            break;\n\n        case OP_leave_scope:\n            {\n                int scope_idx, scope = get_u16(bc_buf + pos + 1);\n\n                for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {\n                    JSVarDef *vd = &s->vars[scope_idx];\n                    if (vd->scope_level == scope) {\n                        if (vd->is_captured) {\n                            dbuf_putc(&bc_out, OP_close_loc);\n                            dbuf_put_u16(&bc_out, scope_idx);\n                        }\n                        scope_idx = vd->scope_next;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            break;\n\n        case OP_set_name:\n            {\n                /* remove dummy set_name opcodes */\n                JSAtom name = get_u32(bc_buf + pos + 1);\n                if (name == JS_ATOM_NULL)\n                    break;\n            }\n            goto no_change;\n\n        case OP_if_false:\n        case OP_if_true:\n        case OP_catch:\n            s->jump_size++;\n            goto no_change;\n\n        case OP_dup:\n            if (OPTIMIZE) {\n                /* Transformation: dup if_false(l1) drop, l1: if_false(l2) -> if_false(l2) */\n                /* Transformation: dup if_true(l1) drop, l1: if_true(l2) -> if_true(l2) */\n                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), OP_drop, -1)) {\n                    int lab0, lab1, op1, pos1, line1, pos2;\n                    lab0 = lab1 = cc.label;\n                    assert(lab1 >= 0 && lab1 < s->label_count);\n                    op1 = cc.op;\n                    pos1 = cc.pos;\n                    line1 = cc.line_num;\n                    while (code_match(&cc, (pos2 = get_label_pos(s, lab1)), OP_dup, op1, OP_drop, -1)) {\n                        lab1 = cc.label;\n                    }\n                    if (code_match(&cc, pos2, op1, -1)) {\n                        s->jump_size++;\n                        update_label(s, lab0, -1);\n                        update_label(s, cc.label, +1);\n                        dbuf_putc(&bc_out, op1);\n                        dbuf_put_u32(&bc_out, cc.label);\n                        pos_next = pos1;\n                        if (line1 != -1 && line1 != line_num) {\n                            line_num = line1;\n                            s->line_number_size++;\n                            dbuf_putc(&bc_out, OP_line_num);\n                            dbuf_put_u32(&bc_out, line_num);\n                        }\n                        break;\n                    }\n                }\n            }\n            goto no_change;\n\n        case OP_nop:\n            /* remove erased code */\n            break;\n        case OP_set_class_name:\n            /* only used during parsing */\n            break;\n\n        case OP_get_field_opt_chain: /* equivalent to OP_get_field */\n            {\n                JSAtom name = get_u32(bc_buf + pos + 1);\n                dbuf_putc(&bc_out, OP_get_field);\n                dbuf_put_u32(&bc_out, name);\n            }\n            break;\n        case OP_get_array_el_opt_chain: /* equivalent to OP_get_array_el */\n            dbuf_putc(&bc_out, OP_get_array_el);\n            break;\n\n        default:\n        no_change:\n            dbuf_put(&bc_out, bc_buf + pos, len);\n            break;\n        }\n    }\n\n    /* set the new byte code */\n    dbuf_free(&s->byte_code);\n    s->byte_code = bc_out;\n    if (dbuf_error(&s->byte_code)) {\n        JS_ThrowOutOfMemory(ctx);\n        return -1;\n    }\n    return 0;\n fail:\n    /* continue the copy to keep the atom refcounts consistent */\n    /* XXX: find a better solution ? */\n    for (; pos < bc_len; pos = pos_next) {\n        op = bc_buf[pos];\n        len = opcode_info[op].size;\n        pos_next = pos + len;\n        dbuf_put(&bc_out, bc_buf + pos, len);\n    }\n    dbuf_free(&s->byte_code);\n    s->byte_code = bc_out;\n    return -1;\n}\n\n/* the pc2line table gives a source position for each PC value */\nstatic void add_pc2line_info(JSFunctionDef *s, uint32_t pc, uint32_t source_pos)\n{\n    if (s->line_number_slots != NULL\n    &&  s->line_number_count < s->line_number_size\n    &&  pc >= s->line_number_last_pc\n    &&  source_pos != s->line_number_last) {\n        s->line_number_slots[s->line_number_count].pc = pc;\n        s->line_number_slots[s->line_number_count].source_pos = source_pos;\n        s->line_number_count++;\n        s->line_number_last_pc = pc;\n        s->line_number_last = source_pos;\n    }\n}\n\n/* XXX: could use a more compact storage */\n/* XXX: get_line_col_cached() is slow. For more predictable\n   performance, line/cols could be stored every N source\n   bytes. Alternatively, get_line_col_cached() could be issued in\n   emit_source_pos() so that the deltas are more likely to be\n   small. */\nstatic void compute_pc2line_info(JSFunctionDef *s)\n{\n    if (!s->strip_debug) {\n        int last_line_num, last_col_num;\n        uint32_t last_pc = 0;\n        int i, line_num, col_num;\n        const uint8_t *buf_start = s->get_line_col_cache->buf_start;\n        js_dbuf_init(s->ctx, &s->pc2line);\n\n        last_line_num = get_line_col_cached(s->get_line_col_cache,\n                                            &last_col_num,\n                                            buf_start + s->source_pos);\n        dbuf_put_leb128(&s->pc2line, last_line_num); /* line number minus 1 */\n        dbuf_put_leb128(&s->pc2line, last_col_num); /* column number minus 1 */\n\n        for (i = 0; i < s->line_number_count; i++) {\n            uint32_t pc = s->line_number_slots[i].pc;\n            uint32_t source_pos = s->line_number_slots[i].source_pos;\n            int diff_pc, diff_line, diff_col;\n\n            if (source_pos == -1)\n                continue;\n            diff_pc = pc - last_pc;\n            if (diff_pc < 0)\n                continue;\n\n            line_num = get_line_col_cached(s->get_line_col_cache, &col_num,\n                                           buf_start + source_pos);\n            diff_line = line_num - last_line_num;\n            diff_col = col_num - last_col_num;\n            if (diff_line == 0 && diff_col == 0)\n                continue;\n\n            if (diff_line >= PC2LINE_BASE &&\n                diff_line < PC2LINE_BASE + PC2LINE_RANGE &&\n                diff_pc <= PC2LINE_DIFF_PC_MAX) {\n                dbuf_putc(&s->pc2line, (diff_line - PC2LINE_BASE) +\n                          diff_pc * PC2LINE_RANGE + PC2LINE_OP_FIRST);\n            } else {\n                /* longer encoding */\n                dbuf_putc(&s->pc2line, 0);\n                dbuf_put_leb128(&s->pc2line, diff_pc);\n                dbuf_put_sleb128(&s->pc2line, diff_line);\n            }\n            dbuf_put_sleb128(&s->pc2line, diff_col);\n                \n            last_pc = pc;\n            last_line_num = line_num;\n            last_col_num = col_num;\n        }\n    }\n}\n\nstatic RelocEntry *add_reloc(JSContext *ctx, LabelSlot *ls, uint32_t addr, int size)\n{\n    RelocEntry *re;\n    re = js_malloc(ctx, sizeof(*re));\n    if (!re)\n        return NULL;\n    re->addr = addr;\n    re->size = size;\n    re->next = ls->first_reloc;\n    ls->first_reloc = re;\n    return re;\n}\n\nstatic BOOL code_has_label(CodeContext *s, int pos, int label)\n{\n    while (pos < s->bc_len) {\n        int op = s->bc_buf[pos];\n        if (op == OP_line_num) {\n            pos += 5;\n            continue;\n        }\n        if (op == OP_label) {\n            int lab = get_u32(s->bc_buf + pos + 1);\n            if (lab == label)\n                return TRUE;\n            pos += 5;\n            continue;\n        }\n        if (op == OP_goto) {\n            int lab = get_u32(s->bc_buf + pos + 1);\n            if (lab == label)\n                return TRUE;\n        }\n        break;\n    }\n    return FALSE;\n}\n\n/* return the target label, following the OP_goto jumps\n   the first opcode at destination is stored in *pop\n */\nstatic int find_jump_target(JSFunctionDef *s, int label0, int *pop, int *pline)\n{\n    int i, pos, op, label;\n\n    label = label0;\n    update_label(s, label, -1);\n    for (i = 0; i < 10; i++) {\n        assert(label >= 0 && label < s->label_count);\n        pos = s->label_slots[label].pos2;\n        for (;;) {\n            switch(op = s->byte_code.buf[pos]) {\n            case OP_line_num:\n                if (pline)\n                    *pline = get_u32(s->byte_code.buf + pos + 1);\n                /* fall thru */\n            case OP_label:\n                pos += opcode_info[op].size;\n                continue;\n            case OP_goto:\n                label = get_u32(s->byte_code.buf + pos + 1);\n                break;\n            case OP_drop:\n                /* ignore drop opcodes if followed by OP_return_undef */\n                while (s->byte_code.buf[++pos] == OP_drop)\n                    continue;\n                if (s->byte_code.buf[pos] == OP_return_undef)\n                    op = OP_return_undef;\n                /* fall thru */\n            default:\n                goto done;\n            }\n            break;\n        }\n    }\n    /* cycle detected, could issue a warning */\n    /* XXX: the combination of find_jump_target() and skip_dead_code()\n       seems incorrect with cyclic labels. See for exemple:\n\n       for (;;) {\n       l:break l;\n       l:break l;\n       l:break l;\n       l:break l;\n       }\n\n       Avoiding changing the target is just a workaround and might not\n       suffice to completely fix the problem. */\n    label = label0;\n done:\n    *pop = op;\n    update_label(s, label, +1);\n    return label;\n}\n\nstatic void push_short_int(DynBuf *bc_out, int val)\n{\n#if SHORT_OPCODES\n    if (val >= -1 && val <= 7) {\n        dbuf_putc(bc_out, OP_push_0 + val);\n        return;\n    }\n    if (val == (int8_t)val) {\n        dbuf_putc(bc_out, OP_push_i8);\n        dbuf_putc(bc_out, val);\n        return;\n    }\n    if (val == (int16_t)val) {\n        dbuf_putc(bc_out, OP_push_i16);\n        dbuf_put_u16(bc_out, val);\n        return;\n    }\n#endif\n    dbuf_putc(bc_out, OP_push_i32);\n    dbuf_put_u32(bc_out, val);\n}\n\nstatic void put_short_code(DynBuf *bc_out, int op, int idx)\n{\n#if SHORT_OPCODES\n    if (idx < 4) {\n        switch (op) {\n        case OP_get_loc:\n            dbuf_putc(bc_out, OP_get_loc0 + idx);\n            return;\n        case OP_put_loc:\n            dbuf_putc(bc_out, OP_put_loc0 + idx);\n            return;\n        case OP_set_loc:\n            dbuf_putc(bc_out, OP_set_loc0 + idx);\n            return;\n        case OP_get_arg:\n            dbuf_putc(bc_out, OP_get_arg0 + idx);\n            return;\n        case OP_put_arg:\n            dbuf_putc(bc_out, OP_put_arg0 + idx);\n            return;\n        case OP_set_arg:\n            dbuf_putc(bc_out, OP_set_arg0 + idx);\n            return;\n        case OP_get_var_ref:\n            dbuf_putc(bc_out, OP_get_var_ref0 + idx);\n            return;\n        case OP_put_var_ref:\n            dbuf_putc(bc_out, OP_put_var_ref0 + idx);\n            return;\n        case OP_set_var_ref:\n            dbuf_putc(bc_out, OP_set_var_ref0 + idx);\n            return;\n        case OP_call:\n            dbuf_putc(bc_out, OP_call0 + idx);\n            return;\n        }\n    }\n    if (idx < 256) {\n        switch (op) {\n        case OP_get_loc:\n            dbuf_putc(bc_out, OP_get_loc8);\n            dbuf_putc(bc_out, idx);\n            return;\n        case OP_put_loc:\n            dbuf_putc(bc_out, OP_put_loc8);\n            dbuf_putc(bc_out, idx);\n            return;\n        case OP_set_loc:\n            dbuf_putc(bc_out, OP_set_loc8);\n            dbuf_putc(bc_out, idx);\n            return;\n        }\n    }\n#endif\n    dbuf_putc(bc_out, op);\n    dbuf_put_u16(bc_out, idx);\n}\n\n/* peephole optimizations and resolve goto/labels */\nstatic __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)\n{\n    int pos, pos_next, bc_len, op, op1, len, i, line_num;\n    const uint8_t *bc_buf;\n    DynBuf bc_out;\n    LabelSlot *label_slots, *ls;\n    RelocEntry *re, *re_next;\n    CodeContext cc;\n    int label;\n#if SHORT_OPCODES\n    JumpSlot *jp;\n#endif\n\n    label_slots = s->label_slots;\n\n    line_num = s->source_pos;\n\n    cc.bc_buf = bc_buf = s->byte_code.buf;\n    cc.bc_len = bc_len = s->byte_code.size;\n    js_dbuf_bytecode_init(ctx, &bc_out);\n\n#if SHORT_OPCODES\n    if (s->jump_size) {\n        s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);\n        if (s->jump_slots == NULL)\n            return -1;\n    }\n#endif\n    /* XXX: Should skip this phase if not generating SHORT_OPCODES */\n    if (s->line_number_size && !s->strip_debug) {\n        s->line_number_slots = js_mallocz(s->ctx, sizeof(*s->line_number_slots) * s->line_number_size);\n        if (s->line_number_slots == NULL)\n            return -1;\n        s->line_number_last = s->source_pos;\n        s->line_number_last_pc = 0;\n    }\n\n    /* initialize the 'home_object' variable if needed */\n    if (s->home_object_var_idx >= 0) {\n        dbuf_putc(&bc_out, OP_special_object);\n        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_HOME_OBJECT);\n        put_short_code(&bc_out, OP_put_loc, s->home_object_var_idx);\n    }\n    /* initialize the 'this.active_func' variable if needed */\n    if (s->this_active_func_var_idx >= 0) {\n        dbuf_putc(&bc_out, OP_special_object);\n        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);\n        put_short_code(&bc_out, OP_put_loc, s->this_active_func_var_idx);\n    }\n    /* initialize the 'new.target' variable if needed */\n    if (s->new_target_var_idx >= 0) {\n        dbuf_putc(&bc_out, OP_special_object);\n        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_NEW_TARGET);\n        put_short_code(&bc_out, OP_put_loc, s->new_target_var_idx);\n    }\n    /* initialize the 'this' variable if needed. In a derived class\n       constructor, this is initially uninitialized. */\n    if (s->this_var_idx >= 0) {\n        if (s->is_derived_class_constructor) {\n            dbuf_putc(&bc_out, OP_set_loc_uninitialized);\n            dbuf_put_u16(&bc_out, s->this_var_idx);\n        } else {\n            dbuf_putc(&bc_out, OP_push_this);\n            put_short_code(&bc_out, OP_put_loc, s->this_var_idx);\n        }\n    }\n    /* initialize the 'arguments' variable if needed */\n    if (s->arguments_var_idx >= 0) {\n        if ((s->js_mode & JS_MODE_STRICT) || !s->has_simple_parameter_list) {\n            dbuf_putc(&bc_out, OP_special_object);\n            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_ARGUMENTS);\n        } else {\n            dbuf_putc(&bc_out, OP_special_object);\n            dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);\n            /* the arguments are implicitly captured because\n               references to them are created with the 'argument'\n               object */\n            for(i = 0; i < s->arg_count; i++)\n                capture_var(s, &s->args[i]);\n        }\n        if (s->arguments_arg_idx >= 0)\n            put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);\n        put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);\n    }\n    /* initialize a reference to the current function if needed */\n    if (s->func_var_idx >= 0) {\n        dbuf_putc(&bc_out, OP_special_object);\n        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_THIS_FUNC);\n        put_short_code(&bc_out, OP_put_loc, s->func_var_idx);\n    }\n    /* initialize the variable environment object if needed */\n    if (s->var_object_idx >= 0) {\n        dbuf_putc(&bc_out, OP_special_object);\n        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);\n        put_short_code(&bc_out, OP_put_loc, s->var_object_idx);\n    }\n    if (s->arg_var_object_idx >= 0) {\n        dbuf_putc(&bc_out, OP_special_object);\n        dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);\n        put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);\n    }\n\n    for (pos = 0; pos < bc_len; pos = pos_next) {\n        int val;\n        op = bc_buf[pos];\n        len = opcode_info[op].size;\n        pos_next = pos + len;\n        switch(op) {\n        case OP_line_num:\n            /* line number info (for debug). We put it in a separate\n               compressed table to reduce memory usage and get better\n               performance */\n            line_num = get_u32(bc_buf + pos + 1);\n            break;\n\n        case OP_label:\n            {\n                label = get_u32(bc_buf + pos + 1);\n                assert(label >= 0 && label < s->label_count);\n                ls = &label_slots[label];\n                assert(ls->addr == -1);\n                ls->addr = bc_out.size;\n                /* resolve the relocation entries */\n                for(re = ls->first_reloc; re != NULL; re = re_next) {\n                    int diff = ls->addr - re->addr;\n                    re_next = re->next;\n                    switch (re->size) {\n                    case 4:\n                        put_u32(bc_out.buf + re->addr, diff);\n                        break;\n                    case 2:\n                        assert(diff == (int16_t)diff);\n                        put_u16(bc_out.buf + re->addr, diff);\n                        break;\n                    case 1:\n                        assert(diff == (int8_t)diff);\n                        put_u8(bc_out.buf + re->addr, diff);\n                        break;\n                    }\n                    js_free(ctx, re);\n                }\n                ls->first_reloc = NULL;\n            }\n            break;\n\n        case OP_call:\n        case OP_call_method:\n            {\n                /* detect and transform tail calls */\n                int argc;\n                argc = get_u16(bc_buf + pos + 1);\n                if (code_match(&cc, pos_next, OP_return, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    put_short_code(&bc_out, op + 1, argc);\n                    pos_next = skip_dead_code(s, bc_buf, bc_len, cc.pos, &line_num);\n                    break;\n                }\n                add_pc2line_info(s, bc_out.size, line_num);\n                put_short_code(&bc_out, op, argc);\n                break;\n            }\n            goto no_change;\n\n        case OP_return:\n        case OP_return_undef:\n        case OP_return_async:\n        case OP_throw:\n        case OP_throw_error:\n            pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);\n            goto no_change;\n\n        case OP_goto:\n            label = get_u32(bc_buf + pos + 1);\n        has_goto:\n            if (OPTIMIZE) {\n                int line1 = -1;\n                /* Use custom matcher because multiple labels can follow */\n                label = find_jump_target(s, label, &op1, &line1);\n                if (code_has_label(&cc, pos_next, label)) {\n                    /* jump to next instruction: remove jump */\n                    update_label(s, label, -1);\n                    break;\n                }\n                if (op1 == OP_return || op1 == OP_return_undef || op1 == OP_throw) {\n                    /* jump to return/throw: remove jump, append return/throw */\n                    /* updating the line number obfuscates assembly listing */\n                    //if (line1 != -1) line_num = line1;\n                    update_label(s, label, -1);\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, op1);\n                    pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);\n                    break;\n                }\n                /* XXX: should duplicate single instructions followed by goto or return */\n                /* For example, can match one of these followed by return:\n                   push_i32 / push_const / push_atom_value / get_var /\n                   undefined / null / push_false / push_true / get_ref_value /\n                   get_loc / get_arg / get_var_ref\n                 */\n            }\n            goto has_label;\n\n        case OP_gosub:\n            label = get_u32(bc_buf + pos + 1);\n            if (0 && OPTIMIZE) {\n                label = find_jump_target(s, label, &op1, NULL);\n                if (op1 == OP_ret) {\n                    update_label(s, label, -1);\n                    /* empty finally clause: remove gosub */\n                    break;\n                }\n            }\n            goto has_label;\n\n        case OP_catch:\n            label = get_u32(bc_buf + pos + 1);\n            goto has_label;\n\n        case OP_if_true:\n        case OP_if_false:\n            label = get_u32(bc_buf + pos + 1);\n            if (OPTIMIZE) {\n                label = find_jump_target(s, label, &op1, NULL);\n                /* transform if_false/if_true(l1) label(l1) -> drop label(l1) */\n                if (code_has_label(&cc, pos_next, label)) {\n                    update_label(s, label, -1);\n                    dbuf_putc(&bc_out, OP_drop);\n                    break;\n                }\n                /* transform if_false(l1) goto(l2) label(l1) -> if_false(l2) label(l1) */\n                if (code_match(&cc, pos_next, OP_goto, -1)) {\n                    int pos1 = cc.pos;\n                    int line1 = cc.line_num;\n                    if (code_has_label(&cc, pos1, label)) {\n                        if (line1 != -1) line_num = line1;\n                        pos_next = pos1;\n                        update_label(s, label, -1);\n                        label = cc.label;\n                        op ^= OP_if_true ^ OP_if_false;\n                    }\n                }\n            }\n        has_label:\n            add_pc2line_info(s, bc_out.size, line_num);\n            if (op == OP_goto) {\n                pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);\n            }\n            assert(label >= 0 && label < s->label_count);\n            ls = &label_slots[label];\n#if SHORT_OPCODES\n            jp = &s->jump_slots[s->jump_count++];\n            jp->op = op;\n            jp->size = 4;\n            jp->pos = bc_out.size + 1;\n            jp->label = label;\n\n            if (ls->addr == -1) {\n                int diff = ls->pos2 - pos - 1;\n                if (diff < 128 && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {\n                    jp->size = 1;\n                    jp->op = OP_if_false8 + (op - OP_if_false);\n                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));\n                    dbuf_putc(&bc_out, 0);\n                    if (!add_reloc(ctx, ls, bc_out.size - 1, 1))\n                        goto fail;\n                    break;\n                }\n                if (diff < 32768 && op == OP_goto) {\n                    jp->size = 2;\n                    jp->op = OP_goto16;\n                    dbuf_putc(&bc_out, OP_goto16);\n                    dbuf_put_u16(&bc_out, 0);\n                    if (!add_reloc(ctx, ls, bc_out.size - 2, 2))\n                        goto fail;\n                    break;\n                }\n            } else {\n                int diff = ls->addr - bc_out.size - 1;\n                if (diff == (int8_t)diff && (op == OP_if_false || op == OP_if_true || op == OP_goto)) {\n                    jp->size = 1;\n                    jp->op = OP_if_false8 + (op - OP_if_false);\n                    dbuf_putc(&bc_out, OP_if_false8 + (op - OP_if_false));\n                    dbuf_putc(&bc_out, diff);\n                    break;\n                }\n                if (diff == (int16_t)diff && op == OP_goto) {\n                    jp->size = 2;\n                    jp->op = OP_goto16;\n                    dbuf_putc(&bc_out, OP_goto16);\n                    dbuf_put_u16(&bc_out, diff);\n                    break;\n                }\n            }\n#endif\n            dbuf_putc(&bc_out, op);\n            dbuf_put_u32(&bc_out, ls->addr - bc_out.size);\n            if (ls->addr == -1) {\n                /* unresolved yet: create a new relocation entry */\n                if (!add_reloc(ctx, ls, bc_out.size - 4, 4))\n                    goto fail;\n            }\n            break;\n        case OP_with_get_var:\n        case OP_with_put_var:\n        case OP_with_delete_var:\n        case OP_with_make_ref:\n        case OP_with_get_ref:\n            {\n                JSAtom atom;\n                int is_with;\n\n                atom = get_u32(bc_buf + pos + 1);\n                label = get_u32(bc_buf + pos + 5);\n                is_with = bc_buf[pos + 9];\n                if (OPTIMIZE) {\n                    label = find_jump_target(s, label, &op1, NULL);\n                }\n                assert(label >= 0 && label < s->label_count);\n                ls = &label_slots[label];\n                add_pc2line_info(s, bc_out.size, line_num);\n#if SHORT_OPCODES\n                jp = &s->jump_slots[s->jump_count++];\n                jp->op = op;\n                jp->size = 4;\n                jp->pos = bc_out.size + 5;\n                jp->label = label;\n#endif\n                dbuf_putc(&bc_out, op);\n                dbuf_put_u32(&bc_out, atom);\n                dbuf_put_u32(&bc_out, ls->addr - bc_out.size);\n                if (ls->addr == -1) {\n                    /* unresolved yet: create a new relocation entry */\n                    if (!add_reloc(ctx, ls, bc_out.size - 4, 4))\n                        goto fail;\n                }\n                dbuf_putc(&bc_out, is_with);\n            }\n            break;\n\n        case OP_drop:\n            if (OPTIMIZE) {\n                /* remove useless drops before return */\n                if (code_match(&cc, pos_next, OP_return_undef, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    break;\n                }\n            }\n            goto no_change;\n\n        case OP_null:\n#if SHORT_OPCODES\n            if (OPTIMIZE) {\n                /* transform null strict_eq into is_null */\n                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_is_null);\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* transform null strict_neq if_false/if_true -> is_null if_true/if_false */\n                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_is_null);\n                    pos_next = cc.pos;\n                    label = cc.label;\n                    op = cc.op ^ OP_if_false ^ OP_if_true;\n                    goto has_label;\n                }\n            }\n#endif\n            /* fall thru */\n        case OP_push_false:\n        case OP_push_true:\n            if (OPTIMIZE) {\n                val = (op == OP_push_true);\n                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {\n                has_constant_test:\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    if (val == cc.op - OP_if_false) {\n                        /* transform null if_false(l1) -> goto l1 */\n                        /* transform false if_false(l1) -> goto l1 */\n                        /* transform true if_true(l1) -> goto l1 */\n                        pos_next = cc.pos;\n                        op = OP_goto;\n                        label = cc.label;\n                        goto has_goto;\n                    } else {\n                        /* transform null if_true(l1) -> nop */\n                        /* transform false if_true(l1) -> nop */\n                        /* transform true if_false(l1) -> nop */\n                        pos_next = cc.pos;\n                        update_label(s, cc.label, -1);\n                        break;\n                    }\n                }\n            }\n            goto no_change;\n\n        case OP_push_i32:\n            if (OPTIMIZE) {\n                /* transform i32(val) neg -> i32(-val) */\n                val = get_i32(bc_buf + pos + 1);\n                if ((val != INT32_MIN && val != 0)\n                &&  code_match(&cc, pos_next, OP_neg, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    if (code_match(&cc, cc.pos, OP_drop, -1)) {\n                        if (cc.line_num >= 0) line_num = cc.line_num;\n                    } else {\n                        add_pc2line_info(s, bc_out.size, line_num);\n                        push_short_int(&bc_out, -val);\n                    }\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* remove push/drop pairs generated by the parser */\n                if (code_match(&cc, pos_next, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* Optimize constant tests: `if (0)`, `if (1)`, `if (!0)`... */\n                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {\n                    val = (val != 0);\n                    goto has_constant_test;\n                }\n                add_pc2line_info(s, bc_out.size, line_num);\n                push_short_int(&bc_out, val);\n                break;\n            }\n            goto no_change;\n\n        case OP_push_bigint_i32:\n            if (OPTIMIZE) {\n                /* transform i32(val) neg -> i32(-val) */\n                val = get_i32(bc_buf + pos + 1);\n                if (val != INT32_MIN\n                &&  code_match(&cc, pos_next, OP_neg, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    if (code_match(&cc, cc.pos, OP_drop, -1)) {\n                        if (cc.line_num >= 0) line_num = cc.line_num;\n                    } else {\n                        add_pc2line_info(s, bc_out.size, line_num);\n                        dbuf_putc(&bc_out, OP_push_bigint_i32);\n                        dbuf_put_u32(&bc_out, -val);\n                    }\n                    pos_next = cc.pos;\n                    break;\n                }\n            }\n            goto no_change;\n\n#if SHORT_OPCODES\n        case OP_push_const:\n        case OP_fclosure:\n            if (OPTIMIZE) {\n                int idx = get_u32(bc_buf + pos + 1);\n                if (idx < 256) {\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_push_const8 + op - OP_push_const);\n                    dbuf_putc(&bc_out, idx);\n                    break;\n                }\n            }\n            goto no_change;\n\n        case OP_get_field:\n            if (OPTIMIZE) {\n                JSAtom atom = get_u32(bc_buf + pos + 1);\n                if (atom == JS_ATOM_length) {\n                    JS_FreeAtom(ctx, atom);\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_get_length);\n                    break;\n                }\n            }\n            goto no_change;\n#endif\n        case OP_push_atom_value:\n            if (OPTIMIZE) {\n                JSAtom atom = get_u32(bc_buf + pos + 1);\n                /* remove push/drop pairs generated by the parser */\n                if (code_match(&cc, pos_next, OP_drop, -1)) {\n                    JS_FreeAtom(ctx, atom);\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    pos_next = cc.pos;\n                    break;\n                }\n#if SHORT_OPCODES\n                if (atom == JS_ATOM_empty_string) {\n                    JS_FreeAtom(ctx, atom);\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_push_empty_string);\n                    break;\n                }\n#endif\n            }\n            goto no_change;\n\n        case OP_to_propkey:\n            if (OPTIMIZE) {\n                /* remove redundant to_propkey opcodes when storing simple data */\n                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_put_array_el, -1)\n                ||  code_match(&cc, pos_next, M3(OP_push_i32, OP_push_const, OP_push_atom_value), OP_put_array_el, -1)\n                ||  code_match(&cc, pos_next, M4(OP_undefined, OP_null, OP_push_true, OP_push_false), OP_put_array_el, -1)) {\n                    break;\n                }\n            }\n            goto no_change;\n\n        case OP_undefined:\n            if (OPTIMIZE) {\n                /* remove push/drop pairs generated by the parser */\n                if (code_match(&cc, pos_next, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* transform undefined return -> return_undefined */\n                if (code_match(&cc, pos_next, OP_return, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_return_undef);\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* transform undefined if_true(l1)/if_false(l1) -> nop/goto(l1) */\n                if (code_match(&cc, pos_next, M2(OP_if_false, OP_if_true), -1)) {\n                    val = 0;\n                    goto has_constant_test;\n                }\n#if SHORT_OPCODES\n                /* transform undefined strict_eq -> is_undefined */\n                if (code_match(&cc, pos_next, OP_strict_eq, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_is_undefined);\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* transform undefined strict_neq if_false/if_true -> is_undefined if_true/if_false */\n                if (code_match(&cc, pos_next, OP_strict_neq, M2(OP_if_false, OP_if_true), -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_is_undefined);\n                    pos_next = cc.pos;\n                    label = cc.label;\n                    op = cc.op ^ OP_if_false ^ OP_if_true;\n                    goto has_label;\n                }\n#endif\n            }\n            goto no_change;\n\n        case OP_insert2:\n            if (OPTIMIZE) {\n                /* Transformation:\n                   insert2 put_field(a) drop -> put_field(a)\n                */\n                if (code_match(&cc, pos_next, OP_put_field, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_put_field);\n                    dbuf_put_u32(&bc_out, cc.atom);\n                    pos_next = cc.pos;\n                    break;\n                }\n            }\n            goto no_change;\n\n        case OP_dup:\n            if (OPTIMIZE) {\n                /* Transformation: dup put_x(n) drop -> put_x(n) */\n                int op1, line2 = -1;\n                /* Transformation: dup put_x(n) -> set_x(n) */\n                if (code_match(&cc, pos_next, M4(OP_put_loc, OP_put_loc_check, OP_put_arg, OP_put_var_ref), -1, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    op1 = cc.op + 1;  /* put_x -> set_x */\n                    pos_next = cc.pos;\n                    if (code_match(&cc, cc.pos, OP_drop, -1)) {\n                        if (cc.line_num >= 0) line_num = cc.line_num;\n                        op1 -= 1; /* set_x drop -> put_x */\n                        pos_next = cc.pos;\n                        if (code_match(&cc, cc.pos, op1 - 1, cc.idx, -1)) {\n                            line2 = cc.line_num; /* delay line number update */\n                            op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */\n                            pos_next = cc.pos;\n                        }\n                    }\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    put_short_code(&bc_out, op1, cc.idx);\n                    if (line2 >= 0) line_num = line2;\n                    break;\n                }\n            }\n            goto no_change;\n\n        case OP_get_loc:\n            if (OPTIMIZE) {\n                /* transformation:\n                   get_loc(n) post_dec put_loc(n) drop -> dec_loc(n)\n                   get_loc(n) post_inc put_loc(n) drop -> inc_loc(n)\n                   get_loc(n) dec dup put_loc(n) drop -> dec_loc(n)\n                   get_loc(n) inc dup put_loc(n) drop -> inc_loc(n)\n                 */\n                int idx;\n                idx = get_u16(bc_buf + pos + 1);\n                if (idx >= 256)\n                    goto no_change;\n                if (code_match(&cc, pos_next, M2(OP_post_dec, OP_post_inc), OP_put_loc, idx, OP_drop, -1) ||\n                    code_match(&cc, pos_next, M2(OP_dec, OP_inc), OP_dup, OP_put_loc, idx, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, (cc.op == OP_inc || cc.op == OP_post_inc) ? OP_inc_loc : OP_dec_loc);\n                    dbuf_putc(&bc_out, idx);\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* transformation:\n                   get_loc(n) push_atom_value(x) add dup put_loc(n) drop -> push_atom_value(x) add_loc(n)\n                 */\n                if (code_match(&cc, pos_next, OP_push_atom_value, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n#if SHORT_OPCODES\n                    if (cc.atom == JS_ATOM_empty_string) {\n                        JS_FreeAtom(ctx, cc.atom);\n                        dbuf_putc(&bc_out, OP_push_empty_string);\n                    } else\n#endif\n                    {\n                        dbuf_putc(&bc_out, OP_push_atom_value);\n                        dbuf_put_u32(&bc_out, cc.atom);\n                    }\n                    dbuf_putc(&bc_out, OP_add_loc);\n                    dbuf_putc(&bc_out, idx);\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* transformation:\n                   get_loc(n) push_i32(x) add dup put_loc(n) drop -> push_i32(x) add_loc(n)\n                 */\n                if (code_match(&cc, pos_next, OP_push_i32, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    push_short_int(&bc_out, cc.label);\n                    dbuf_putc(&bc_out, OP_add_loc);\n                    dbuf_putc(&bc_out, idx);\n                    pos_next = cc.pos;\n                    break;\n                }\n                /* transformation: XXX: also do these:\n                   get_loc(n) get_loc(x) add dup put_loc(n) drop -> get_loc(x) add_loc(n)\n                   get_loc(n) get_arg(x) add dup put_loc(n) drop -> get_arg(x) add_loc(n)\n                   get_loc(n) get_var_ref(x) add dup put_loc(n) drop -> get_var_ref(x) add_loc(n)\n                 */\n                if (code_match(&cc, pos_next, M3(OP_get_loc, OP_get_arg, OP_get_var_ref), -1, OP_add, OP_dup, OP_put_loc, idx, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    put_short_code(&bc_out, cc.op, cc.idx);\n                    dbuf_putc(&bc_out, OP_add_loc);\n                    dbuf_putc(&bc_out, idx);\n                    pos_next = cc.pos;\n                    break;\n                }\n                add_pc2line_info(s, bc_out.size, line_num);\n                put_short_code(&bc_out, op, idx);\n                break;\n            }\n            goto no_change;\n#if SHORT_OPCODES\n        case OP_get_arg:\n        case OP_get_var_ref:\n            if (OPTIMIZE) {\n                int idx;\n                idx = get_u16(bc_buf + pos + 1);\n                add_pc2line_info(s, bc_out.size, line_num);\n                put_short_code(&bc_out, op, idx);\n                break;\n            }\n            goto no_change;\n#endif\n        case OP_put_loc:\n        case OP_put_loc_check:\n        case OP_put_arg:\n        case OP_put_var_ref:\n            if (OPTIMIZE) {\n                /* transformation: put_x(n) get_x(n) -> set_x(n) */\n                int idx;\n                idx = get_u16(bc_buf + pos + 1);\n                if (code_match(&cc, pos_next, op - 1, idx, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    put_short_code(&bc_out, op + 1, idx);\n                    pos_next = cc.pos;\n                    break;\n                }\n                add_pc2line_info(s, bc_out.size, line_num);\n                put_short_code(&bc_out, op, idx);\n                break;\n            }\n            goto no_change;\n\n        case OP_post_inc:\n        case OP_post_dec:\n            if (OPTIMIZE) {\n                /* transformation:\n                   post_inc put_x drop -> inc put_x\n                   post_inc perm3 put_field drop -> inc put_field\n                   post_inc perm4 put_array_el drop -> inc put_array_el\n                 */\n                int op1, idx;\n                if (code_match(&cc, pos_next, M3(OP_put_loc, OP_put_arg, OP_put_var_ref), -1, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    op1 = cc.op;\n                    idx = cc.idx;\n                    pos_next = cc.pos;\n                    if (code_match(&cc, cc.pos, op1 - 1, idx, -1)) {\n                        if (cc.line_num >= 0) line_num = cc.line_num;\n                        op1 += 1;   /* put_x(n) get_x(n) -> set_x(n) */\n                        pos_next = cc.pos;\n                    }\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));\n                    put_short_code(&bc_out, op1, idx);\n                    break;\n                }\n                if (code_match(&cc, pos_next, OP_perm3, OP_put_field, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));\n                    dbuf_putc(&bc_out, OP_put_field);\n                    dbuf_put_u32(&bc_out, cc.atom);\n                    pos_next = cc.pos;\n                    break;\n                }\n                if (code_match(&cc, pos_next, OP_perm4, OP_put_array_el, OP_drop, -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    add_pc2line_info(s, bc_out.size, line_num);\n                    dbuf_putc(&bc_out, OP_dec + (op - OP_post_dec));\n                    dbuf_putc(&bc_out, OP_put_array_el);\n                    pos_next = cc.pos;\n                    break;\n                }\n            }\n            goto no_change;\n\n#if SHORT_OPCODES\n        case OP_typeof:\n            if (OPTIMIZE) {\n                /* simplify typeof tests */\n                if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) {\n                    if (cc.line_num >= 0) line_num = cc.line_num;\n                    int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq;\n                    int op2 = -1;\n                    switch (cc.atom) {\n                    case JS_ATOM_undefined:\n                        op2 = OP_typeof_is_undefined;\n                        break;\n                    case JS_ATOM_function:\n                        op2 = OP_typeof_is_function;\n                        break;\n                    }\n                    if (op2 >= 0) {\n                        /* transform typeof(s) == \"<type>\" into is_<type> */\n                        if (op1 == OP_strict_eq) {\n                            add_pc2line_info(s, bc_out.size, line_num);\n                            dbuf_putc(&bc_out, op2);\n                            JS_FreeAtom(ctx, cc.atom);\n                            pos_next = cc.pos;\n                            break;\n                        }\n                        if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) {\n                            /* transform typeof(s) != \"<type>\" if_false into is_<type> if_true */\n                            if (cc.line_num >= 0) line_num = cc.line_num;\n                            add_pc2line_info(s, bc_out.size, line_num);\n                            dbuf_putc(&bc_out, op2);\n                            JS_FreeAtom(ctx, cc.atom);\n                            pos_next = cc.pos;\n                            label = cc.label;\n                            op = OP_if_true;\n                            goto has_label;\n                        }\n                    }\n                }\n            }\n            goto no_change;\n#endif\n\n        default:\n        no_change:\n            add_pc2line_info(s, bc_out.size, line_num);\n            dbuf_put(&bc_out, bc_buf + pos, len);\n            break;\n        }\n    }\n\n    /* check that there were no missing labels */\n    for(i = 0; i < s->label_count; i++) {\n        assert(label_slots[i].first_reloc == NULL);\n    }\n#if SHORT_OPCODES\n    if (OPTIMIZE) {\n        /* more jump optimizations */\n        int patch_offsets = 0;\n        for (i = 0, jp = s->jump_slots; i < s->jump_count; i++, jp++) {\n            LabelSlot *ls;\n            JumpSlot *jp1;\n            int j, pos, diff, delta;\n\n            delta = 3;\n            switch (op = jp->op) {\n            case OP_goto16:\n                delta = 1;\n                /* fall thru */\n            case OP_if_false:\n            case OP_if_true:\n            case OP_goto:\n                pos = jp->pos;\n                diff = s->label_slots[jp->label].addr - pos;\n                if (diff >= -128 && diff <= 127 + delta) {\n                    //put_u8(bc_out.buf + pos, diff);\n                    jp->size = 1;\n                    if (op == OP_goto16) {\n                        bc_out.buf[pos - 1] = jp->op = OP_goto8;\n                    } else {\n                        bc_out.buf[pos - 1] = jp->op = OP_if_false8 + (op - OP_if_false);\n                    }\n                    goto shrink;\n                } else\n                if (diff == (int16_t)diff && op == OP_goto) {\n                    //put_u16(bc_out.buf + pos, diff);\n                    jp->size = 2;\n                    delta = 2;\n                    bc_out.buf[pos - 1] = jp->op = OP_goto16;\n                shrink:\n                    /* XXX: should reduce complexity, using 2 finger copy scheme */\n                    memmove(bc_out.buf + pos + jp->size, bc_out.buf + pos + jp->size + delta,\n                            bc_out.size - pos - jp->size - delta);\n                    bc_out.size -= delta;\n                    patch_offsets++;\n                    for (j = 0, ls = s->label_slots; j < s->label_count; j++, ls++) {\n                        if (ls->addr > pos)\n                            ls->addr -= delta;\n                    }\n                    for (j = i + 1, jp1 = jp + 1; j < s->jump_count; j++, jp1++) {\n                        if (jp1->pos > pos)\n                            jp1->pos -= delta;\n                    }\n                    for (j = 0; j < s->line_number_count; j++) {\n                        if (s->line_number_slots[j].pc > pos)\n                            s->line_number_slots[j].pc -= delta;\n                    }\n                    continue;\n                }\n                break;\n            }\n        }\n        if (patch_offsets) {\n            JumpSlot *jp1;\n            int j;\n            for (j = 0, jp1 = s->jump_slots; j < s->jump_count; j++, jp1++) {\n                int diff1 = s->label_slots[jp1->label].addr - jp1->pos;\n                switch (jp1->size) {\n                case 1:\n                    put_u8(bc_out.buf + jp1->pos, diff1);\n                    break;\n                case 2:\n                    put_u16(bc_out.buf + jp1->pos, diff1);\n                    break;\n                case 4:\n                    put_u32(bc_out.buf + jp1->pos, diff1);\n                    break;\n                }\n            }\n        }\n    }\n    js_free(ctx, s->jump_slots);\n    s->jump_slots = NULL;\n#endif\n    js_free(ctx, s->label_slots);\n    s->label_slots = NULL;\n    /* XXX: should delay until copying to runtime bytecode function */\n    compute_pc2line_info(s);\n    js_free(ctx, s->line_number_slots);\n    s->line_number_slots = NULL;\n    /* set the new byte code */\n    dbuf_free(&s->byte_code);\n    s->byte_code = bc_out;\n    s->use_short_opcodes = TRUE;\n    if (dbuf_error(&s->byte_code)) {\n        JS_ThrowOutOfMemory(ctx);\n        return -1;\n    }\n    return 0;\n fail:\n    /* XXX: not safe */\n    dbuf_free(&bc_out);\n    return -1;\n}\n\n/* compute the maximum stack size needed by the function */\n\ntypedef struct StackSizeState {\n    int bc_len;\n    int stack_len_max;\n    uint16_t *stack_level_tab;\n    int32_t *catch_pos_tab;\n    int *pc_stack;\n    int pc_stack_len;\n    int pc_stack_size;\n} StackSizeState;\n\n/* 'op' is only used for error indication */\nstatic __exception int ss_check(JSContext *ctx, StackSizeState *s,\n                                int pos, int op, int stack_len, int catch_pos)\n{\n    if ((unsigned)pos >= s->bc_len) {\n        JS_ThrowInternalError(ctx, \"bytecode buffer overflow (op=%d, pc=%d)\", op, pos);\n        return -1;\n    }\n    if (stack_len > s->stack_len_max) {\n        s->stack_len_max = stack_len;\n        if (s->stack_len_max > JS_STACK_SIZE_MAX) {\n            JS_ThrowInternalError(ctx, \"stack overflow (op=%d, pc=%d)\", op, pos);\n            return -1;\n        }\n    }\n    if (s->stack_level_tab[pos] != 0xffff) {\n        /* already explored: check that the stack size is consistent */\n        if (s->stack_level_tab[pos] != stack_len) {\n            JS_ThrowInternalError(ctx, \"inconsistent stack size: %d %d (pc=%d)\",\n                                  s->stack_level_tab[pos], stack_len, pos);\n            return -1;\n        } else if (s->catch_pos_tab[pos] != catch_pos) {\n            JS_ThrowInternalError(ctx, \"inconsistent catch position: %d %d (pc=%d)\",\n                                  s->catch_pos_tab[pos], catch_pos, pos);\n            return -1;\n        } else {\n            return 0;\n        }\n    }\n\n    /* mark as explored and store the stack size */\n    s->stack_level_tab[pos] = stack_len;\n    s->catch_pos_tab[pos] = catch_pos;\n\n    /* queue the new PC to explore */\n    if (js_resize_array(ctx, (void **)&s->pc_stack, sizeof(s->pc_stack[0]),\n                        &s->pc_stack_size, s->pc_stack_len + 1))\n        return -1;\n    s->pc_stack[s->pc_stack_len++] = pos;\n    return 0;\n}\n\nstatic __exception int compute_stack_size(JSContext *ctx,\n                                          JSFunctionDef *fd,\n                                          int *pstack_size)\n{\n    StackSizeState s_s, *s = &s_s;\n    int i, diff, n_pop, pos_next, stack_len, pos, op, catch_pos, catch_level;\n    const JSOpCode *oi;\n    const uint8_t *bc_buf;\n\n    bc_buf = fd->byte_code.buf;\n    s->bc_len = fd->byte_code.size;\n    /* bc_len > 0 */\n    s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) *\n                                   s->bc_len);\n    if (!s->stack_level_tab)\n        return -1;\n    for(i = 0; i < s->bc_len; i++)\n        s->stack_level_tab[i] = 0xffff;\n    s->pc_stack = NULL;\n    s->catch_pos_tab = js_malloc(ctx, sizeof(s->catch_pos_tab[0]) *\n                                   s->bc_len);\n    if (!s->catch_pos_tab)\n        goto fail;\n\n    s->stack_len_max = 0;\n    s->pc_stack_len = 0;\n    s->pc_stack_size = 0;\n\n    /* breadth-first graph exploration */\n    if (ss_check(ctx, s, 0, OP_invalid, 0, -1))\n        goto fail;\n\n    while (s->pc_stack_len > 0) {\n        pos = s->pc_stack[--s->pc_stack_len];\n        stack_len = s->stack_level_tab[pos];\n        catch_pos = s->catch_pos_tab[pos];\n        op = bc_buf[pos];\n        if (op == 0 || op >= OP_COUNT) {\n            JS_ThrowInternalError(ctx, \"invalid opcode (op=%d, pc=%d)\", op, pos);\n            goto fail;\n        }\n        oi = &short_opcode_info(op);\n#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 64)\n        printf(\"%5d: %10s %5d %5d\\n\", pos, oi->name, stack_len, catch_pos);\n#endif\n        pos_next = pos + oi->size;\n        if (pos_next > s->bc_len) {\n            JS_ThrowInternalError(ctx, \"bytecode buffer overflow (op=%d, pc=%d)\", op, pos);\n            goto fail;\n        }\n        n_pop = oi->n_pop;\n        /* call pops a variable number of arguments */\n        if (oi->fmt == OP_FMT_npop || oi->fmt == OP_FMT_npop_u16) {\n            n_pop += get_u16(bc_buf + pos + 1);\n        } else {\n#if SHORT_OPCODES\n            if (oi->fmt == OP_FMT_npopx) {\n                n_pop += op - OP_call0;\n            }\n#endif\n        }\n\n        if (stack_len < n_pop) {\n            JS_ThrowInternalError(ctx, \"stack underflow (op=%d, pc=%d)\", op, pos);\n            goto fail;\n        }\n        stack_len += oi->n_push - n_pop;\n        if (stack_len > s->stack_len_max) {\n            s->stack_len_max = stack_len;\n            if (s->stack_len_max > JS_STACK_SIZE_MAX) {\n                JS_ThrowInternalError(ctx, \"stack overflow (op=%d, pc=%d)\", op, pos);\n                goto fail;\n            }\n        }\n        switch(op) {\n        case OP_tail_call:\n        case OP_tail_call_method:\n        case OP_return:\n        case OP_return_undef:\n        case OP_return_async:\n        case OP_throw:\n        case OP_throw_error:\n        case OP_ret:\n            goto done_insn;\n        case OP_goto:\n            diff = get_u32(bc_buf + pos + 1);\n            pos_next = pos + 1 + diff;\n            break;\n#if SHORT_OPCODES\n        case OP_goto16:\n            diff = (int16_t)get_u16(bc_buf + pos + 1);\n            pos_next = pos + 1 + diff;\n            break;\n        case OP_goto8:\n            diff = (int8_t)bc_buf[pos + 1];\n            pos_next = pos + 1 + diff;\n            break;\n        case OP_if_true8:\n        case OP_if_false8:\n            diff = (int8_t)bc_buf[pos + 1];\n            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))\n                goto fail;\n            break;\n#endif\n        case OP_if_true:\n        case OP_if_false:\n            diff = get_u32(bc_buf + pos + 1);\n            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))\n                goto fail;\n            break;\n        case OP_gosub:\n            diff = get_u32(bc_buf + pos + 1);\n            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1, catch_pos))\n                goto fail;\n            break;\n        case OP_with_get_var:\n        case OP_with_delete_var:\n            diff = get_u32(bc_buf + pos + 5);\n            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1, catch_pos))\n                goto fail;\n            break;\n        case OP_with_make_ref:\n        case OP_with_get_ref:\n            diff = get_u32(bc_buf + pos + 5);\n            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2, catch_pos))\n                goto fail;\n            break;\n        case OP_with_put_var:\n            diff = get_u32(bc_buf + pos + 5);\n            if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1, catch_pos))\n                goto fail;\n            break;\n        case OP_catch:\n            diff = get_u32(bc_buf + pos + 1);\n            if (ss_check(ctx, s, pos + 1 + diff, op, stack_len, catch_pos))\n                goto fail;\n            catch_pos = pos;\n            break;\n        case OP_for_of_start:\n        case OP_for_await_of_start:\n            catch_pos = pos;\n            break;\n            /* we assume the catch offset entry is only removed with\n               some op codes */\n        case OP_drop:\n            catch_level = stack_len;\n            goto check_catch;\n        case OP_nip:\n            catch_level = stack_len - 1;\n            goto check_catch;\n        case OP_nip1:\n            catch_level = stack_len - 1;\n            goto check_catch;\n        case OP_iterator_close:\n            catch_level = stack_len + 2;\n        check_catch:\n            /* Note: for for_of_start/for_await_of_start we consider\n               the catch offset is on the first stack entry instead of\n               the thirst */\n            if (catch_pos >= 0) {\n                int level;\n                level = s->stack_level_tab[catch_pos];\n                if (bc_buf[catch_pos] != OP_catch)\n                    level++; /* for_of_start, for_wait_of_start */\n                /* catch_level = stack_level before op_catch is executed ? */\n                if (catch_level == level) {\n                    catch_pos = s->catch_pos_tab[catch_pos];\n                }\n            }\n            break;\n        case OP_nip_catch:\n            if (catch_pos < 0) {\n                JS_ThrowInternalError(ctx, \"nip_catch: no catch op (pc=%d)\", pos);\n                goto fail;\n            }\n            stack_len = s->stack_level_tab[catch_pos];\n            if (bc_buf[catch_pos] != OP_catch)\n                stack_len++; /* for_of_start, for_wait_of_start */\n            stack_len++; /* no stack overflow is possible by construction */\n            catch_pos = s->catch_pos_tab[catch_pos];\n            break;\n        default:\n            break;\n        }\n        if (ss_check(ctx, s, pos_next, op, stack_len, catch_pos))\n            goto fail;\n    done_insn: ;\n    }\n    js_free(ctx, s->pc_stack);\n    js_free(ctx, s->catch_pos_tab);\n    js_free(ctx, s->stack_level_tab);\n    *pstack_size = s->stack_len_max;\n    return 0;\n fail:\n    js_free(ctx, s->pc_stack);\n    js_free(ctx, s->catch_pos_tab);\n    js_free(ctx, s->stack_level_tab);\n    *pstack_size = 0;\n    return -1;\n}\n\nstatic int add_global_variables(JSContext *ctx, JSFunctionDef *fd)\n{\n    int i, idx;\n    JSModuleDef *m = fd->module;\n    JSExportEntry *me;\n    JSGlobalVar *hf;\n    BOOL need_global_closures;\n    \n    /* Script: add the defined global variables. In the non strict\n       direct eval not in global scope, the global variables are\n       created in the enclosing scope so they are not created as\n       variable references.\n\n       In modules, the imported global variables were added as closure\n       global variables in js_parse_import().\n    */\n    need_global_closures = TRUE;\n    if (fd->eval_type == JS_EVAL_TYPE_DIRECT && !(fd->js_mode & JS_MODE_STRICT)) {\n        /* XXX: add a flag ? */\n        for(idx = 0; idx < fd->closure_var_count; idx++) {\n            JSClosureVar *cv = &fd->closure_var[idx];\n            if (cv->var_name == JS_ATOM__var_ ||\n                cv->var_name == JS_ATOM__arg_var_) {\n                need_global_closures = FALSE;\n                break;\n            }\n        }\n    }\n\n    if (need_global_closures) {\n        JSClosureTypeEnum closure_type;\n        if (fd->module)\n            closure_type = JS_CLOSURE_MODULE_DECL;\n        else\n            closure_type = JS_CLOSURE_GLOBAL_DECL;\n        for(i = 0; i < fd->global_var_count; i++) {\n            JSVarKindEnum var_kind;\n            hf = &fd->global_vars[i];\n            if (hf->cpool_idx >= 0 && !hf->is_lexical) {\n                var_kind = JS_VAR_GLOBAL_FUNCTION_DECL;\n            } else {\n                var_kind = JS_VAR_NORMAL;\n            }\n            if (add_closure_var(ctx, fd, closure_type, i, hf->var_name, hf->is_const,\n                                hf->is_lexical, var_kind) < 0)\n                return -1;\n        }\n    }\n\n    if (fd->module) {\n        /* resolve the variable names of the local exports */\n        for(i = 0; i < m->export_entries_count; i++) {\n            me = &m->export_entries[i];\n            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {\n                idx = find_closure_var(ctx, fd, me->local_name);\n                if (idx < 0) {\n                    JS_ThrowSyntaxErrorAtom(ctx, \"exported variable '%s' does not exist\",\n                                            me->local_name);\n                    return -1;\n                }\n                me->u.local.var_idx = idx;\n            }\n        }\n    }\n    return 0;\n}\n\n/* create a function object from a function definition. The function\n   definition is freed. All the child functions are also created. It\n   must be done this way to resolve all the variables. */\nstatic JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)\n{\n    JSValue func_obj;\n    JSFunctionBytecode *b;\n    struct list_head *el, *el1;\n    int stack_size, scope, idx;\n    int function_size, byte_code_offset, cpool_offset;\n    int closure_var_offset, vardefs_offset;\n    BOOL strip_var_debug;\n    \n    /* recompute scope linkage */\n    for (scope = 0; scope < fd->scope_count; scope++) {\n        fd->scopes[scope].first = -1;\n    }\n    if (fd->has_parameter_expressions) {\n        /* special end of variable list marker for the argument scope */\n        fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;\n    }\n    for (idx = 0; idx < fd->var_count; idx++) {\n        JSVarDef *vd = &fd->vars[idx];\n        vd->scope_next = fd->scopes[vd->scope_level].first;\n        fd->scopes[vd->scope_level].first = idx;\n    }\n    for (scope = 2; scope < fd->scope_count; scope++) {\n        JSVarScope *sd = &fd->scopes[scope];\n        if (sd->first < 0)\n            sd->first = fd->scopes[sd->parent].first;\n    }\n    for (idx = 0; idx < fd->var_count; idx++) {\n        JSVarDef *vd = &fd->vars[idx];\n        if (vd->scope_next < 0 && vd->scope_level > 1) {\n            scope = fd->scopes[vd->scope_level].parent;\n            vd->scope_next = fd->scopes[scope].first;\n        }\n    }\n\n    /* if the function contains an eval call, the closure variables\n       are used to compile the eval and they must be ordered by scope,\n       so it is necessary to create the closure variables before any\n       other variable lookup is done. */\n    if (fd->has_eval_call)\n        add_eval_variables(ctx, fd);\n\n    /* add the module global variables in the closure */\n    if (fd->is_eval) {\n        if (add_global_variables(ctx, fd))\n            goto fail;\n    } \n\n    /* first create all the child functions */\n    list_for_each_safe(el, el1, &fd->child_list) {\n        JSFunctionDef *fd1;\n        int cpool_idx;\n\n        fd1 = list_entry(el, JSFunctionDef, link);\n        cpool_idx = fd1->parent_cpool_idx;\n        func_obj = js_create_function(ctx, fd1);\n        if (JS_IsException(func_obj))\n            goto fail;\n        /* save it in the constant pool */\n        assert(cpool_idx >= 0);\n        fd->cpool[cpool_idx] = func_obj;\n    }\n\n#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 4)\n    if (!fd->strip_debug) {\n        printf(\"pass 1\\n\");\n        dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,\n                       NULL, fd->args, fd->arg_count, fd->vars, fd->var_count,\n                       fd->closure_var, fd->closure_var_count,\n                       fd->cpool, fd->cpool_count, fd->source,\n                       fd->label_slots, NULL);\n        printf(\"\\n\");\n    }\n#endif\n\n    if (resolve_variables(ctx, fd))\n        goto fail;\n\n#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 2)\n    if (!fd->strip_debug) {\n        printf(\"pass 2\\n\");\n        dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,\n                       NULL, fd->args, fd->arg_count, fd->vars, fd->var_count,\n                       fd->closure_var, fd->closure_var_count,\n                       fd->cpool, fd->cpool_count, fd->source,\n                       fd->label_slots, NULL);\n        printf(\"\\n\");\n    }\n#endif\n\n    if (resolve_labels(ctx, fd))\n        goto fail;\n\n    if (compute_stack_size(ctx, fd, &stack_size) < 0)\n        goto fail;\n\n    if (fd->strip_debug) {\n        function_size = offsetof(JSFunctionBytecode, debug);\n    } else {\n        function_size = sizeof(*b);\n    }\n    cpool_offset = function_size;\n    function_size += fd->cpool_count * sizeof(*fd->cpool);\n    vardefs_offset = function_size;\n    function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);\n    closure_var_offset = function_size;\n    function_size += fd->closure_var_count * sizeof(*fd->closure_var);\n    byte_code_offset = function_size;\n    function_size += fd->byte_code.size;\n\n    b = js_mallocz(ctx, function_size);\n    if (!b)\n        goto fail;\n    b->header.ref_count = 1;\n\n    b->byte_code_buf = (void *)((uint8_t*)b + byte_code_offset);\n    b->byte_code_len = fd->byte_code.size;\n    memcpy(b->byte_code_buf, fd->byte_code.buf, fd->byte_code.size);\n    js_free(ctx, fd->byte_code.buf);\n    fd->byte_code.buf = NULL;\n\n    strip_var_debug = fd->strip_debug && !fd->has_eval_call; /* XXX: check */\n    b->func_name = fd->func_name;\n    if (fd->arg_count + fd->var_count > 0) {\n        int i;\n        b->vardefs = (void *)((uint8_t*)b + vardefs_offset);\n        for(i = 0; i < fd->arg_count; i++) {\n            JSVarDef *vd = &fd->args[i];\n            JSBytecodeVarDef *vd1 = &b->vardefs[i];\n            if (strip_var_debug) {\n                JS_FreeAtom(ctx, vd->var_name);\n                vd1->var_name = JS_ATOM_NULL;\n            } else {\n                vd1->var_name = vd->var_name;\n            }\n            vd1->has_scope = (vd->scope_level != 0);\n            vd1->scope_next = vd->scope_next;\n            vd1->is_const = vd->is_const;\n            vd1->is_lexical = vd->is_lexical;\n            vd1->is_captured = vd->is_captured;\n            vd1->var_kind = vd->var_kind;\n            vd1->var_ref_idx = vd->var_ref_idx;\n        }\n        \n        for(i = 0; i < fd->var_count; i++) {\n            JSVarDef *vd = &fd->vars[i];\n            JSBytecodeVarDef *vd1 = &b->vardefs[i + fd->arg_count];\n            if (strip_var_debug) {\n                JS_FreeAtom(ctx, vd->var_name);\n                vd1->var_name = JS_ATOM_NULL;\n            } else {\n                vd1->var_name = vd->var_name;\n            }\n            vd1->has_scope = (vd->scope_level != 0);\n            vd1->scope_next = vd->scope_next;\n            vd1->is_const = vd->is_const;\n            vd1->is_lexical = vd->is_lexical;\n            vd1->is_captured = vd->is_captured;\n            vd1->var_kind = vd->var_kind;\n            vd1->var_ref_idx = vd->var_ref_idx;\n        }\n        b->var_count = fd->var_count;\n        b->arg_count = fd->arg_count;\n        b->defined_arg_count = fd->defined_arg_count;\n        b->var_ref_count = fd->var_ref_count;\n        js_free(ctx, fd->args);\n        js_free(ctx, fd->vars);\n    }\n    b->cpool_count = fd->cpool_count;\n    if (b->cpool_count) {\n        b->cpool = (void *)((uint8_t*)b + cpool_offset);\n        memcpy(b->cpool, fd->cpool, b->cpool_count * sizeof(*b->cpool));\n    }\n    js_free(ctx, fd->cpool);\n    fd->cpool = NULL;\n\n    b->stack_size = stack_size;\n\n    if (fd->strip_debug) {\n        JS_FreeAtom(ctx, fd->filename);\n        dbuf_free(&fd->pc2line);    // probably useless\n    } else {\n        /* XXX: source and pc2line info should be packed at the end of the\n           JSFunctionBytecode structure, avoiding allocation overhead\n         */\n        b->has_debug = 1;\n        b->debug.filename = fd->filename;\n\n        //DynBuf pc2line;\n        //compute_pc2line_info(fd, &pc2line);\n        //js_free(ctx, fd->line_number_slots)\n        b->debug.pc2line_buf = js_realloc(ctx, fd->pc2line.buf, fd->pc2line.size);\n        if (!b->debug.pc2line_buf)\n            b->debug.pc2line_buf = fd->pc2line.buf;\n        b->debug.pc2line_len = fd->pc2line.size;\n        b->debug.source = fd->source;\n        b->debug.source_len = fd->source_len;\n    }\n    if (fd->scopes != fd->def_scope_array)\n        js_free(ctx, fd->scopes);\n\n    b->closure_var_count = fd->closure_var_count;\n    if (b->closure_var_count) {\n        if (strip_var_debug) {\n            int i;\n            for(i = 0; i < fd->closure_var_count; i++) {\n                JSClosureVar *cv = &fd->closure_var[i];\n                if (cv->closure_type != JS_CLOSURE_GLOBAL_REF &&\n                    cv->closure_type != JS_CLOSURE_GLOBAL_DECL &&\n                    cv->closure_type != JS_CLOSURE_GLOBAL &&\n                    cv->closure_type != JS_CLOSURE_MODULE_DECL &&\n                    cv->closure_type != JS_CLOSURE_MODULE_IMPORT) {\n                    JS_FreeAtom(ctx, cv->var_name);\n                    cv->var_name = JS_ATOM_NULL;\n                }\n            }\n        }\n        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);\n        memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));\n    }\n    js_free(ctx, fd->closure_var);\n    fd->closure_var = NULL;\n\n    b->has_prototype = fd->has_prototype;\n    b->has_simple_parameter_list = fd->has_simple_parameter_list;\n    b->js_mode = fd->js_mode;\n    b->is_derived_class_constructor = fd->is_derived_class_constructor;\n    b->func_kind = fd->func_kind;\n    b->need_home_object = (fd->home_object_var_idx >= 0 ||\n                           fd->need_home_object);\n    b->new_target_allowed = fd->new_target_allowed;\n    b->super_call_allowed = fd->super_call_allowed;\n    b->super_allowed = fd->super_allowed;\n    b->arguments_allowed = fd->arguments_allowed;\n    b->is_direct_or_indirect_eval = (fd->eval_type == JS_EVAL_TYPE_DIRECT ||\n                                     fd->eval_type == JS_EVAL_TYPE_INDIRECT);\n    b->realm = JS_DupContext(ctx);\n\n    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);\n\n#if defined(DUMP_BYTECODE) && (DUMP_BYTECODE & 1)\n    if (!fd->strip_debug) {\n        js_dump_function_bytecode(ctx, b);\n    }\n#endif\n\n    if (fd->parent) {\n        /* remove from parent list */\n        list_del(&fd->link);\n    }\n\n    js_free(ctx, fd);\n    return JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);\n fail:\n    js_free_function_def(ctx, fd);\n    return JS_EXCEPTION;\n}\n\nstatic void free_function_bytecode(JSRuntime *rt, JSFunctionBytecode *b)\n{\n    int i;\n\n#if 0\n    {\n        char buf[ATOM_GET_STR_BUF_SIZE];\n        printf(\"freeing %s\\n\",\n               JS_AtomGetStrRT(rt, buf, sizeof(buf), b->func_name));\n    }\n#endif\n    if (b->byte_code_buf)\n        free_bytecode_atoms(rt, b->byte_code_buf, b->byte_code_len, TRUE);\n\n    if (b->vardefs) {\n        for(i = 0; i < b->arg_count + b->var_count; i++) {\n            JS_FreeAtomRT(rt, b->vardefs[i].var_name);\n        }\n    }\n    for(i = 0; i < b->cpool_count; i++)\n        JS_FreeValueRT(rt, b->cpool[i]);\n\n    for(i = 0; i < b->closure_var_count; i++) {\n        JSClosureVar *cv = &b->closure_var[i];\n        JS_FreeAtomRT(rt, cv->var_name);\n    }\n    if (b->realm)\n        JS_FreeContext(b->realm);\n\n    JS_FreeAtomRT(rt, b->func_name);\n    if (b->has_debug) {\n        JS_FreeAtomRT(rt, b->debug.filename);\n        js_free_rt(rt, b->debug.pc2line_buf);\n        js_free_rt(rt, b->debug.source);\n    }\n\n    remove_gc_object(&b->header);\n    if (rt->gc_phase == JS_GC_PHASE_REMOVE_CYCLES && b->header.ref_count != 0) {\n        list_add_tail(&b->header.link, &rt->gc_zero_ref_count_list);\n    } else {\n        js_free_rt(rt, b);\n    }\n}\n\nstatic __exception int js_parse_directives(JSParseState *s)\n{\n    char str[20];\n    JSParsePos pos;\n    BOOL has_semi;\n\n    if (s->token.val != TOK_STRING)\n        return 0;\n\n    js_parse_get_pos(s, &pos);\n\n    while(s->token.val == TOK_STRING) {\n        /* Copy actual source string representation */\n        snprintf(str, sizeof str, \"%.*s\",\n                 (int)(s->buf_ptr - s->token.ptr - 2), s->token.ptr + 1);\n\n        if (next_token(s))\n            return -1;\n\n        has_semi = FALSE;\n        switch (s->token.val) {\n        case ';':\n            if (next_token(s))\n                return -1;\n            has_semi = TRUE;\n            break;\n        case '}':\n        case TOK_EOF:\n            has_semi = TRUE;\n            break;\n        case TOK_NUMBER:\n        case TOK_STRING:\n        case TOK_TEMPLATE:\n        case TOK_IDENT:\n        case TOK_REGEXP:\n        case TOK_DEC:\n        case TOK_INC:\n        case TOK_NULL:\n        case TOK_FALSE:\n        case TOK_TRUE:\n        case TOK_IF:\n        case TOK_RETURN:\n        case TOK_VAR:\n        case TOK_THIS:\n        case TOK_DELETE:\n        case TOK_TYPEOF:\n        case TOK_NEW:\n        case TOK_DO:\n        case TOK_WHILE:\n        case TOK_FOR:\n        case TOK_SWITCH:\n        case TOK_THROW:\n        case TOK_TRY:\n        case TOK_FUNCTION:\n        case TOK_DEBUGGER:\n        case TOK_WITH:\n        case TOK_CLASS:\n        case TOK_CONST:\n        case TOK_ENUM:\n        case TOK_EXPORT:\n        case TOK_IMPORT:\n        case TOK_SUPER:\n        case TOK_INTERFACE:\n        case TOK_LET:\n        case TOK_PACKAGE:\n        case TOK_PRIVATE:\n        case TOK_PROTECTED:\n        case TOK_PUBLIC:\n        case TOK_STATIC:\n            /* automatic insertion of ';' */\n            if (s->got_lf)\n                has_semi = TRUE;\n            break;\n        default:\n            break;\n        }\n        if (!has_semi)\n            break;\n        if (!strcmp(str, \"use strict\")) {\n            s->cur_func->has_use_strict = TRUE;\n            s->cur_func->js_mode |= JS_MODE_STRICT;\n        }\n    }\n    return js_parse_seek_token(s, &pos);\n}\n\n/* return TRUE if the keyword is forbidden only in strict mode */\nstatic BOOL is_strict_future_keyword(JSAtom atom)\n{\n    return (atom >= JS_ATOM_LAST_KEYWORD + 1 && atom <= JS_ATOM_LAST_STRICT_KEYWORD);\n}\n\nstatic int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,\n                                         JSAtom func_name)\n{\n    JSAtom name;\n    int i, idx;\n\n    if (fd->js_mode & JS_MODE_STRICT) {\n        if (!fd->has_simple_parameter_list && fd->has_use_strict) {\n            return js_parse_error(s, \"\\\"use strict\\\" not allowed in function with default or destructuring parameter\");\n        }\n        if (func_name == JS_ATOM_eval || func_name == JS_ATOM_arguments ||\n            is_strict_future_keyword(func_name)) {\n            return js_parse_error(s, \"invalid function name in strict code\");\n        }\n        for (idx = 0; idx < fd->arg_count; idx++) {\n            name = fd->args[idx].var_name;\n\n            if (name == JS_ATOM_eval || name == JS_ATOM_arguments ||\n                is_strict_future_keyword(name)) {\n                return js_parse_error(s, \"invalid argument name in strict code\");\n            }\n        }\n    }\n    /* check async_generator case */\n    if ((fd->js_mode & JS_MODE_STRICT)\n    ||  !fd->has_simple_parameter_list\n    ||  (fd->func_type == JS_PARSE_FUNC_METHOD && fd->func_kind == JS_FUNC_ASYNC)\n    ||  fd->func_type == JS_PARSE_FUNC_ARROW\n    ||  fd->func_type == JS_PARSE_FUNC_METHOD) {\n        for (idx = 0; idx < fd->arg_count; idx++) {\n            name = fd->args[idx].var_name;\n            if (name != JS_ATOM_NULL) {\n                for (i = 0; i < idx; i++) {\n                    if (fd->args[i].var_name == name)\n                        goto duplicate;\n                }\n                /* Check if argument name duplicates a destructuring parameter */\n                /* XXX: should have a flag for such variables */\n                for (i = 0; i < fd->var_count; i++) {\n                    if (fd->vars[i].var_name == name &&\n                        fd->vars[i].scope_level == 0)\n                        goto duplicate;\n                }\n            }\n        }\n    }\n    return 0;\n\nduplicate:\n    return js_parse_error(s, \"duplicate argument names not allowed in this context\");\n}\n\n/* create a function to initialize class fields */\nstatic JSFunctionDef *js_parse_function_class_fields_init(JSParseState *s)\n{\n    JSFunctionDef *fd;\n\n    fd = js_new_function_def(s->ctx, s->cur_func, FALSE, FALSE,\n                             s->filename, s->buf_start,\n                             &s->get_line_col_cache);\n    if (!fd)\n        return NULL;\n    fd->func_name = JS_ATOM_NULL;\n    fd->has_prototype = FALSE;\n    fd->has_home_object = TRUE;\n\n    fd->has_arguments_binding = FALSE;\n    fd->has_this_binding = TRUE;\n    fd->is_derived_class_constructor = FALSE;\n    fd->new_target_allowed = TRUE;\n    fd->super_call_allowed = FALSE;\n    fd->super_allowed = fd->has_home_object;\n    fd->arguments_allowed = FALSE;\n\n    fd->func_kind = JS_FUNC_NORMAL;\n    fd->func_type = JS_PARSE_FUNC_METHOD;\n    return fd;\n}\n\n/* func_name must be JS_ATOM_NULL for JS_PARSE_FUNC_STATEMENT and\n   JS_PARSE_FUNC_EXPR, JS_PARSE_FUNC_ARROW and JS_PARSE_FUNC_VAR */\nstatic __exception int js_parse_function_decl2(JSParseState *s,\n                                               JSParseFunctionEnum func_type,\n                                               JSFunctionKindEnum func_kind,\n                                               JSAtom func_name,\n                                               const uint8_t *ptr,\n                                               JSParseExportEnum export_flag,\n                                               JSFunctionDef **pfd)\n{\n    JSContext *ctx = s->ctx;\n    JSFunctionDef *fd = s->cur_func;\n    BOOL is_expr;\n    int func_idx, lexical_func_idx = -1;\n    BOOL has_opt_arg;\n    BOOL create_func_var = FALSE;\n\n    is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&\n               func_type != JS_PARSE_FUNC_VAR);\n\n    if (func_type == JS_PARSE_FUNC_STATEMENT ||\n        func_type == JS_PARSE_FUNC_VAR ||\n        func_type == JS_PARSE_FUNC_EXPR) {\n        if (func_kind == JS_FUNC_NORMAL &&\n            token_is_pseudo_keyword(s, JS_ATOM_async) &&\n            peek_token(s, TRUE) != '\\n') {\n            if (next_token(s))\n                return -1;\n            func_kind = JS_FUNC_ASYNC;\n        }\n        if (next_token(s))\n            return -1;\n        if (s->token.val == '*') {\n            if (next_token(s))\n                return -1;\n            func_kind |= JS_FUNC_GENERATOR;\n        }\n\n        if (s->token.val == TOK_IDENT) {\n            if (s->token.u.ident.is_reserved ||\n                (s->token.u.ident.atom == JS_ATOM_yield &&\n                 func_type == JS_PARSE_FUNC_EXPR &&\n                 (func_kind & JS_FUNC_GENERATOR)) ||\n                (s->token.u.ident.atom == JS_ATOM_await &&\n                 ((func_type == JS_PARSE_FUNC_EXPR &&\n                   (func_kind & JS_FUNC_ASYNC)) ||\n                  func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT))) {\n                return js_parse_error_reserved_identifier(s);\n            }\n        }\n        if (s->token.val == TOK_IDENT ||\n            (((s->token.val == TOK_YIELD && !(fd->js_mode & JS_MODE_STRICT)) ||\n             (s->token.val == TOK_AWAIT && !s->is_module)) &&\n             func_type == JS_PARSE_FUNC_EXPR)) {\n            func_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n            if (next_token(s)) {\n                JS_FreeAtom(ctx, func_name);\n                return -1;\n            }\n        } else {\n            if (func_type != JS_PARSE_FUNC_EXPR &&\n                export_flag != JS_PARSE_EXPORT_DEFAULT) {\n                return js_parse_error(s, \"function name expected\");\n            }\n        }\n    } else if (func_type != JS_PARSE_FUNC_ARROW) {\n        func_name = JS_DupAtom(ctx, func_name);\n    }\n\n    if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&\n        (func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {\n        JSGlobalVar *hf;\n        hf = find_global_var(fd, func_name);\n        /* XXX: should check scope chain */\n        if (hf && hf->scope_level == fd->scope_level) {\n            js_parse_error(s, \"invalid redefinition of global identifier in module code\");\n            JS_FreeAtom(ctx, func_name);\n            return -1;\n        }\n    }\n\n    if (func_type == JS_PARSE_FUNC_VAR) {\n        if (!(fd->js_mode & JS_MODE_STRICT)\n        && func_kind == JS_FUNC_NORMAL\n        &&  find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0\n        &&  !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))\n        &&  !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {\n            create_func_var = TRUE;\n        }\n        /* Create the lexical name here so that the function closure\n           contains it */\n        if (fd->is_eval &&\n            (fd->eval_type == JS_EVAL_TYPE_GLOBAL ||\n             fd->eval_type == JS_EVAL_TYPE_MODULE) &&\n            fd->scope_level == fd->body_scope) {\n            /* avoid creating a lexical variable in the global\n               scope. XXX: check annex B */\n            JSGlobalVar *hf;\n            hf = find_global_var(fd, func_name);\n            /* XXX: should check scope chain */\n            if (hf && hf->scope_level == fd->scope_level) {\n                js_parse_error(s, \"invalid redefinition of global identifier\");\n                JS_FreeAtom(ctx, func_name);\n                return -1;\n            }\n        } else {\n            /* Always create a lexical name, fail if at the same scope as\n               existing name */\n            /* Lexical variable will be initialized upon entering scope */\n            lexical_func_idx = define_var(s, fd, func_name,\n                                          func_kind != JS_FUNC_NORMAL ?\n                                          JS_VAR_DEF_NEW_FUNCTION_DECL :\n                                          JS_VAR_DEF_FUNCTION_DECL);\n            if (lexical_func_idx < 0) {\n                JS_FreeAtom(ctx, func_name);\n                return -1;\n            }\n        }\n    }\n\n    fd = js_new_function_def(ctx, fd, FALSE, is_expr,\n                             s->filename, ptr,\n                             &s->get_line_col_cache);\n    if (!fd) {\n        JS_FreeAtom(ctx, func_name);\n        return -1;\n    }\n    if (pfd)\n        *pfd = fd;\n    s->cur_func = fd;\n    fd->func_name = func_name;\n    /* XXX: test !fd->is_generator is always false */\n    fd->has_prototype = (func_type == JS_PARSE_FUNC_STATEMENT ||\n                         func_type == JS_PARSE_FUNC_VAR ||\n                         func_type == JS_PARSE_FUNC_EXPR) &&\n                        func_kind == JS_FUNC_NORMAL;\n    fd->has_home_object = (func_type == JS_PARSE_FUNC_METHOD ||\n                           func_type == JS_PARSE_FUNC_GETTER ||\n                           func_type == JS_PARSE_FUNC_SETTER ||\n                           func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||\n                           func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);\n    fd->has_arguments_binding = (func_type != JS_PARSE_FUNC_ARROW &&\n                                 func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT);\n    fd->has_this_binding = fd->has_arguments_binding;\n    fd->is_derived_class_constructor = (func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR);\n    if (func_type == JS_PARSE_FUNC_ARROW) {\n        fd->new_target_allowed = fd->parent->new_target_allowed;\n        fd->super_call_allowed = fd->parent->super_call_allowed;\n        fd->super_allowed = fd->parent->super_allowed;\n        fd->arguments_allowed = fd->parent->arguments_allowed;\n    } else if (func_type == JS_PARSE_FUNC_CLASS_STATIC_INIT) {\n        fd->new_target_allowed = TRUE; // although new.target === undefined\n        fd->super_call_allowed = FALSE;\n        fd->super_allowed = TRUE;\n        fd->arguments_allowed = FALSE;\n    } else {\n        fd->new_target_allowed = TRUE;\n        fd->super_call_allowed = fd->is_derived_class_constructor;\n        fd->super_allowed = fd->has_home_object;\n        fd->arguments_allowed = TRUE;\n    }\n\n    /* fd->in_function_body == FALSE prevents yield/await during the parsing\n       of the arguments in generator/async functions. They are parsed as\n       regular identifiers for other function kinds. */\n    fd->func_kind = func_kind;\n    fd->func_type = func_type;\n\n    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR ||\n        func_type == JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {\n        /* error if not invoked as a constructor */\n        emit_op(s, OP_check_ctor);\n    }\n\n    if (func_type == JS_PARSE_FUNC_CLASS_CONSTRUCTOR) {\n        emit_class_field_init(s);\n    }\n\n    /* parse arguments */\n    fd->has_simple_parameter_list = TRUE;\n    fd->has_parameter_expressions = FALSE;\n    has_opt_arg = FALSE;\n    if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {\n        JSAtom name;\n        if (s->token.u.ident.is_reserved) {\n            js_parse_error_reserved_identifier(s);\n            goto fail;\n        }\n        name = s->token.u.ident.atom;\n        if (add_arg(ctx, fd, name) < 0)\n            goto fail;\n        fd->defined_arg_count = 1;\n    } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {\n        if (s->token.val == '(') {\n            int skip_bits;\n            /* if there is an '=' inside the parameter list, we\n               consider there is a parameter expression inside */\n            js_parse_skip_parens_token(s, &skip_bits, FALSE);\n            if (skip_bits & SKIP_HAS_ASSIGNMENT)\n                fd->has_parameter_expressions = TRUE;\n            if (next_token(s))\n                goto fail;\n        } else {\n            if (js_parse_expect(s, '('))\n                goto fail;\n        }\n\n        if (fd->has_parameter_expressions) {\n            fd->scope_level = -1; /* force no parent scope */\n            if (push_scope(s) < 0)\n                return -1;\n        }\n\n        while (s->token.val != ')') {\n            JSAtom name;\n            BOOL rest = FALSE;\n            int idx, has_initializer;\n\n            if (s->token.val == TOK_ELLIPSIS) {\n                if (func_type == JS_PARSE_FUNC_SETTER)\n                    goto fail_accessor;\n                fd->has_simple_parameter_list = FALSE;\n                rest = TRUE;\n                if (next_token(s))\n                    goto fail;\n            }\n            if (s->token.val == '[' || s->token.val == '{') {\n                fd->has_simple_parameter_list = FALSE;\n                if (rest) {\n                    emit_op(s, OP_rest);\n                    emit_u16(s, fd->arg_count);\n                } else {\n                    /* unnamed arg for destructuring */\n                    idx = add_arg(ctx, fd, JS_ATOM_NULL);\n                    emit_op(s, OP_get_arg);\n                    emit_u16(s, idx);\n                }\n                has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE, FALSE);\n                if (has_initializer < 0)\n                    goto fail;\n                if (has_initializer)\n                    has_opt_arg = TRUE;\n                if (!has_opt_arg)\n                    fd->defined_arg_count++;\n            } else if (s->token.val == TOK_IDENT) {\n                if (s->token.u.ident.is_reserved) {\n                    js_parse_error_reserved_identifier(s);\n                    goto fail;\n                }\n                name = s->token.u.ident.atom;\n                if (name == JS_ATOM_yield && fd->func_kind == JS_FUNC_GENERATOR) {\n                    js_parse_error_reserved_identifier(s);\n                    goto fail;\n                }\n                if (fd->has_parameter_expressions) {\n                    if (js_parse_check_duplicate_parameter(s, name))\n                        goto fail;\n                    if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)\n                        goto fail;\n                }\n                /* XXX: could avoid allocating an argument if rest is true */\n                idx = add_arg(ctx, fd, name);\n                if (idx < 0)\n                    goto fail;\n                if (next_token(s))\n                    goto fail;\n                if (rest) {\n                    emit_op(s, OP_rest);\n                    emit_u16(s, idx);\n                    if (fd->has_parameter_expressions) {\n                        emit_op(s, OP_dup);\n                        emit_op(s, OP_scope_put_var_init);\n                        emit_atom(s, name);\n                        emit_u16(s, fd->scope_level);\n                    }\n                    emit_op(s, OP_put_arg);\n                    emit_u16(s, idx);\n                    fd->has_simple_parameter_list = FALSE;\n                    has_opt_arg = TRUE;\n                } else if (s->token.val == '=') {\n                    int label;\n\n                    fd->has_simple_parameter_list = FALSE;\n                    has_opt_arg = TRUE;\n\n                    if (next_token(s))\n                        goto fail;\n\n                    label = new_label(s);\n                    emit_op(s, OP_get_arg);\n                    emit_u16(s, idx);\n                    emit_op(s, OP_dup);\n                    emit_op(s, OP_undefined);\n                    emit_op(s, OP_strict_eq);\n                    emit_goto(s, OP_if_false, label);\n                    emit_op(s, OP_drop);\n                    if (js_parse_assign_expr(s))\n                        goto fail;\n                    set_object_name(s, name);\n                    emit_op(s, OP_dup);\n                    emit_op(s, OP_put_arg);\n                    emit_u16(s, idx);\n                    emit_label(s, label);\n                    emit_op(s, OP_scope_put_var_init);\n                    emit_atom(s, name);\n                    emit_u16(s, fd->scope_level);\n                } else {\n                    if (!has_opt_arg) {\n                        fd->defined_arg_count++;\n                    }\n                    if (fd->has_parameter_expressions) {\n                        /* copy the argument to the argument scope */\n                        emit_op(s, OP_get_arg);\n                        emit_u16(s, idx);\n                        emit_op(s, OP_scope_put_var_init);\n                        emit_atom(s, name);\n                        emit_u16(s, fd->scope_level);\n                    }\n                }\n            } else {\n                js_parse_error(s, \"missing formal parameter\");\n                goto fail;\n            }\n            if (rest && s->token.val != ')') {\n                js_parse_expect(s, ')');\n                goto fail;\n            }\n            if (s->token.val == ')')\n                break;\n            if (js_parse_expect(s, ','))\n                goto fail;\n        }\n        if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||\n            (func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {\n        fail_accessor:\n            js_parse_error(s, \"invalid number of arguments for getter or setter\");\n            goto fail;\n        }\n    }\n\n    if (fd->has_parameter_expressions) {\n        int idx;\n\n        /* Copy the variables in the argument scope to the variable\n           scope (see FunctionDeclarationInstantiation() in spec). The\n           normal arguments are already present, so no need to copy\n           them. */\n        idx = fd->scopes[fd->scope_level].first;\n        while (idx >= 0) {\n            JSVarDef *vd = &fd->vars[idx];\n            if (vd->scope_level != fd->scope_level)\n                break;\n            if (find_var(ctx, fd, vd->var_name) < 0) {\n                if (add_var(ctx, fd, vd->var_name) < 0)\n                    goto fail;\n                vd = &fd->vars[idx]; /* fd->vars may have been reallocated */\n                emit_op(s, OP_scope_get_var);\n                emit_atom(s, vd->var_name);\n                emit_u16(s, fd->scope_level);\n                emit_op(s, OP_scope_put_var);\n                emit_atom(s, vd->var_name);\n                emit_u16(s, 0);\n            }\n            idx = vd->scope_next;\n        }\n\n        /* the argument scope has no parent, hence we don't use pop_scope(s) */\n        emit_op(s, OP_leave_scope);\n        emit_u16(s, fd->scope_level);\n\n        /* set the variable scope as the current scope */\n        fd->scope_level = 0;\n        fd->scope_first = fd->scopes[fd->scope_level].first;\n    }\n\n    if (next_token(s))\n        goto fail;\n\n    /* generator function: yield after the parameters are evaluated */\n    if (func_kind == JS_FUNC_GENERATOR ||\n        func_kind == JS_FUNC_ASYNC_GENERATOR)\n        emit_op(s, OP_initial_yield);\n\n    /* in generators, yield expression is forbidden during the parsing\n       of the arguments */\n    fd->in_function_body = TRUE;\n    push_scope(s);  /* enter body scope */\n    fd->body_scope = fd->scope_level;\n\n    if (s->token.val == TOK_ARROW && func_type == JS_PARSE_FUNC_ARROW) {\n        if (next_token(s))\n            goto fail;\n\n        if (s->token.val != '{') {\n            if (js_parse_function_check_names(s, fd, func_name))\n                goto fail;\n\n            if (js_parse_assign_expr(s))\n                goto fail;\n\n            if (func_kind != JS_FUNC_NORMAL)\n                emit_op(s, OP_return_async);\n            else\n                emit_op(s, OP_return);\n\n            if (!fd->strip_source) {\n                /* save the function source code */\n                /* the end of the function source code is after the last\n                   token of the function source stored into s->last_ptr */\n                fd->source_len = s->last_ptr - ptr;\n                fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);\n                if (!fd->source)\n                    goto fail;\n            }\n            goto done;\n        }\n    }\n\n    if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {\n        if (js_parse_expect(s, '{'))\n            goto fail;\n    }\n\n    if (js_parse_directives(s))\n        goto fail;\n\n    /* in strict_mode, check function and argument names */\n    if (js_parse_function_check_names(s, fd, func_name))\n        goto fail;\n\n    while (s->token.val != '}') {\n        if (js_parse_source_element(s))\n            goto fail;\n    }\n    if (!fd->strip_source) {\n        /* save the function source code */\n        fd->source_len = s->buf_ptr - ptr;\n        fd->source = js_strndup(ctx, (const char *)ptr, fd->source_len);\n        if (!fd->source)\n            goto fail;\n    }\n\n    if (next_token(s)) {\n        /* consume the '}' */\n        goto fail;\n    }\n\n    /* in case there is no return, add one */\n    if (js_is_live_code(s)) {\n        emit_return(s, FALSE);\n    }\n done:\n    s->cur_func = fd->parent;\n\n    /* Reparse identifiers after the function is terminated so that\n       the token is parsed in the englobing function. It could be done\n       by just using next_token() here for normal functions, but it is\n       necessary for arrow functions with an expression body. */\n    reparse_ident_token(s);\n\n    /* create the function object */\n    {\n        int idx;\n        JSAtom func_name = fd->func_name;\n\n        /* the real object will be set at the end of the compilation */\n        idx = cpool_add(s, JS_NULL);\n        fd->parent_cpool_idx = idx;\n\n        if (is_expr) {\n            /* for constructors, no code needs to be generated here */\n            if (func_type != JS_PARSE_FUNC_CLASS_CONSTRUCTOR &&\n                func_type != JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR) {\n                /* OP_fclosure creates the function object from the bytecode\n                   and adds the scope information */\n                emit_op(s, OP_fclosure);\n                emit_u32(s, idx);\n                if (func_name == JS_ATOM_NULL) {\n                    emit_op(s, OP_set_name);\n                    emit_u32(s, JS_ATOM_NULL);\n                }\n            }\n        } else if (func_type == JS_PARSE_FUNC_VAR) {\n            emit_op(s, OP_fclosure);\n            emit_u32(s, idx);\n            if (create_func_var) {\n                if (s->cur_func->is_global_var) {\n                    JSGlobalVar *hf;\n                    /* the global variable must be defined at the start of the\n                       function */\n                    hf = add_global_var(ctx, s->cur_func, func_name);\n                    if (!hf)\n                        goto fail;\n                    /* it is considered as defined at the top level\n                       (needed for annex B.3.3.4 and B.3.3.5\n                       checks) */\n                    hf->scope_level = 0;\n                    hf->force_init = ((s->cur_func->js_mode & JS_MODE_STRICT) != 0);\n                    /* store directly into global var, bypass lexical scope */\n                    emit_op(s, OP_dup);\n                    emit_op(s, OP_scope_put_var);\n                    emit_atom(s, func_name);\n                    emit_u16(s, 0);\n                } else {\n                    /* do not call define_var to bypass lexical scope check */\n                    func_idx = find_var(ctx, s->cur_func, func_name);\n                    if (func_idx < 0) {\n                        func_idx = add_var(ctx, s->cur_func, func_name);\n                        if (func_idx < 0)\n                            goto fail;\n                    }\n                    /* store directly into local var, bypass lexical catch scope */\n                    emit_op(s, OP_dup);\n                    emit_op(s, OP_scope_put_var);\n                    emit_atom(s, func_name);\n                    emit_u16(s, 0);\n                }\n            }\n            if (lexical_func_idx >= 0) {\n                /* lexical variable will be initialized upon entering scope */\n                s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;\n                emit_op(s, OP_drop);\n            } else {\n                /* store function object into its lexical name */\n                /* XXX: could use OP_put_loc directly */\n                emit_op(s, OP_scope_put_var_init);\n                emit_atom(s, func_name);\n                emit_u16(s, s->cur_func->scope_level);\n            }\n        } else {\n            if (!s->cur_func->is_global_var) {\n                int var_idx = define_var(s, s->cur_func, func_name, JS_VAR_DEF_VAR);\n\n                if (var_idx < 0)\n                    goto fail;\n                /* the variable will be assigned at the top of the function */\n                if (var_idx & ARGUMENT_VAR_OFFSET) {\n                    s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;\n                } else {\n                    s->cur_func->vars[var_idx].func_pool_idx = idx;\n                }\n            } else {\n                JSAtom func_var_name;\n                JSGlobalVar *hf;\n                if (func_name == JS_ATOM_NULL)\n                    func_var_name = JS_ATOM__default_; /* export default */\n                else\n                    func_var_name = func_name;\n                /* the variable will be assigned at the top of the function */\n                hf = add_global_var(ctx, s->cur_func, func_var_name);\n                if (!hf)\n                    goto fail;\n                hf->cpool_idx = idx;\n                if (export_flag != JS_PARSE_EXPORT_NONE) {\n                    if (!add_export_entry(s, s->cur_func->module, func_var_name,\n                                          export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))\n                        goto fail;\n                }\n            }\n        }\n    }\n    return 0;\n fail:\n    s->cur_func = fd->parent;\n    js_free_function_def(ctx, fd);\n    if (pfd)\n        *pfd = NULL;\n    return -1;\n}\n\nstatic __exception int js_parse_function_decl(JSParseState *s,\n                                              JSParseFunctionEnum func_type,\n                                              JSFunctionKindEnum func_kind,\n                                              JSAtom func_name,\n                                              const uint8_t *ptr)\n{\n    return js_parse_function_decl2(s, func_type, func_kind, func_name, ptr,\n                                   JS_PARSE_EXPORT_NONE, NULL);\n}\n\nstatic __exception int js_parse_program(JSParseState *s)\n{\n    JSFunctionDef *fd = s->cur_func;\n    int idx;\n\n    if (next_token(s))\n        return -1;\n\n    if (js_parse_directives(s))\n        return -1;\n\n    fd->is_global_var = (fd->eval_type == JS_EVAL_TYPE_GLOBAL) ||\n        (fd->eval_type == JS_EVAL_TYPE_MODULE) ||\n        !(fd->js_mode & JS_MODE_STRICT);\n\n    if (!s->is_module) {\n        /* hidden variable for the return value */\n        fd->eval_ret_idx = idx = add_var(s->ctx, fd, JS_ATOM__ret_);\n        if (idx < 0)\n            return -1;\n    }\n\n    while (s->token.val != TOK_EOF) {\n        if (js_parse_source_element(s))\n            return -1;\n    }\n\n    if (!s->is_module) {\n        /* return the value of the hidden variable eval_ret_idx  */\n        if (fd->func_kind == JS_FUNC_ASYNC) {\n            /* wrap the return value in an object so that promises can\n               be safely returned */\n            emit_op(s, OP_object);\n            emit_op(s, OP_dup);\n\n            emit_op(s, OP_get_loc);\n            emit_u16(s, fd->eval_ret_idx);\n\n            emit_op(s, OP_put_field);\n            emit_atom(s, JS_ATOM_value);\n        } else {\n            emit_op(s, OP_get_loc);\n            emit_u16(s, fd->eval_ret_idx);\n        }\n        emit_return(s, TRUE);\n    } else {\n        emit_return(s, FALSE);\n    }\n\n    return 0;\n}\n\nstatic void js_parse_init(JSContext *ctx, JSParseState *s,\n                          const char *input, size_t input_len,\n                          const char *filename)\n{\n    memset(s, 0, sizeof(*s));\n    s->ctx = ctx;\n    s->filename = filename;\n    s->buf_start = s->buf_ptr = (const uint8_t *)input;\n    s->buf_end = s->buf_ptr + input_len;\n    s->token.val = ' ';\n    s->token.ptr = s->buf_ptr;\n\n    s->get_line_col_cache.ptr = s->buf_start;\n    s->get_line_col_cache.buf_start = s->buf_start;\n    s->get_line_col_cache.line_num = 0;\n    s->get_line_col_cache.col_num = 0;\n}\n\nstatic JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,\n                                       JSValueConst this_obj,\n                                       JSVarRef **var_refs, JSStackFrame *sf)\n{\n    JSValue ret_val;\n    uint32_t tag;\n\n    tag = JS_VALUE_GET_TAG(fun_obj);\n    if (tag == JS_TAG_FUNCTION_BYTECODE) {\n        fun_obj = js_closure(ctx, fun_obj, var_refs, sf, TRUE);\n        if (JS_IsException(fun_obj))\n            return JS_EXCEPTION;\n        ret_val = JS_CallFree(ctx, fun_obj, this_obj, 0, NULL);\n    } else if (tag == JS_TAG_MODULE) {\n        JSModuleDef *m;\n        m = JS_VALUE_GET_PTR(fun_obj);\n        /* the module refcount should be >= 2 */\n        JS_FreeValue(ctx, fun_obj);\n        if (js_create_module_function(ctx, m) < 0)\n            goto fail;\n        if (js_link_module(ctx, m) < 0)\n            goto fail;\n        ret_val = js_evaluate_module(ctx, m);\n        if (JS_IsException(ret_val)) {\n        fail:\n            return JS_EXCEPTION;\n        }\n    } else {\n        JS_FreeValue(ctx, fun_obj);\n        ret_val = JS_ThrowTypeError(ctx, \"bytecode function expected\");\n    }\n    return ret_val;\n}\n\nJSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj)\n{\n    return JS_EvalFunctionInternal(ctx, fun_obj, ctx->global_obj, NULL, NULL);\n}\n\n/* 'input' must be zero terminated i.e. input[input_len] = '\\0'. */\nstatic JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,\n                                 const char *input, size_t input_len,\n                                 const char *filename, int flags, int scope_idx)\n{\n    JSParseState s1, *s = &s1;\n    int err, js_mode, eval_type;\n    JSValue fun_obj, ret_val;\n    JSStackFrame *sf;\n    JSVarRef **var_refs;\n    JSFunctionBytecode *b;\n    JSFunctionDef *fd;\n    JSModuleDef *m;\n\n    js_parse_init(ctx, s, input, input_len, filename);\n    skip_shebang(&s->buf_ptr, s->buf_end);\n\n    eval_type = flags & JS_EVAL_TYPE_MASK;\n    m = NULL;\n    if (eval_type == JS_EVAL_TYPE_DIRECT) {\n        JSObject *p;\n        sf = ctx->rt->current_stack_frame;\n        assert(sf != NULL);\n        assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT);\n        p = JS_VALUE_GET_OBJ(sf->cur_func);\n        assert(js_class_has_bytecode(p->class_id));\n        b = p->u.func.function_bytecode;\n        var_refs = p->u.func.var_refs;\n        js_mode = b->js_mode;\n    } else {\n        sf = NULL;\n        b = NULL;\n        var_refs = NULL;\n        js_mode = 0;\n        if (flags & JS_EVAL_FLAG_STRICT)\n            js_mode |= JS_MODE_STRICT;\n        if (eval_type == JS_EVAL_TYPE_MODULE) {\n            JSAtom module_name = JS_NewAtom(ctx, filename);\n            if (module_name == JS_ATOM_NULL)\n                return JS_EXCEPTION;\n            m = js_new_module_def(ctx, module_name);\n            if (!m)\n                return JS_EXCEPTION;\n            js_mode |= JS_MODE_STRICT;\n        }\n    }\n    fd = js_new_function_def(ctx, NULL, TRUE, FALSE, filename,\n                             s->buf_start, &s->get_line_col_cache);\n    if (!fd)\n        goto fail1;\n    s->cur_func = fd;\n    fd->eval_type = eval_type;\n    fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);\n    if (eval_type == JS_EVAL_TYPE_DIRECT) {\n        fd->new_target_allowed = b->new_target_allowed;\n        fd->super_call_allowed = b->super_call_allowed;\n        fd->super_allowed = b->super_allowed;\n        fd->arguments_allowed = b->arguments_allowed;\n    } else {\n        fd->new_target_allowed = FALSE;\n        fd->super_call_allowed = FALSE;\n        fd->super_allowed = FALSE;\n        fd->arguments_allowed = TRUE;\n    }\n    fd->js_mode = js_mode;\n    fd->func_name = JS_DupAtom(ctx, JS_ATOM__eval_);\n    if (b) {\n        if (add_closure_variables(ctx, fd, b, scope_idx))\n            goto fail;\n    }\n    fd->module = m;\n    if (m != NULL || (flags & JS_EVAL_FLAG_ASYNC)) {\n        fd->in_function_body = TRUE;\n        fd->func_kind = JS_FUNC_ASYNC;\n    }\n    s->is_module = (m != NULL);\n    s->allow_html_comments = !s->is_module;\n\n    push_scope(s); /* body scope */\n    fd->body_scope = fd->scope_level;\n\n    err = js_parse_program(s);\n    if (err) {\n    fail:\n        free_token(s, &s->token);\n        js_free_function_def(ctx, fd);\n        goto fail1;\n    }\n\n    if (m != NULL)\n        m->has_tla = fd->has_await;\n\n    /* create the function object and all the enclosed functions */\n    fun_obj = js_create_function(ctx, fd);\n    if (JS_IsException(fun_obj))\n        goto fail1;\n    /* Could add a flag to avoid resolution if necessary */\n    if (m) {\n        m->func_obj = fun_obj;\n        if (js_resolve_module(ctx, m) < 0)\n            goto fail1;\n        fun_obj = JS_NewModuleValue(ctx, m);\n    }\n    if (flags & JS_EVAL_FLAG_COMPILE_ONLY) {\n        ret_val = fun_obj;\n    } else {\n        ret_val = JS_EvalFunctionInternal(ctx, fun_obj, this_obj, var_refs, sf);\n    }\n    return ret_val;\n fail1:\n    /* XXX: should free all the unresolved dependencies */\n    if (m)\n        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));\n    return JS_EXCEPTION;\n}\n\n/* the indirection is needed to make 'eval' optional */\nstatic JSValue JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,\n                               const char *input, size_t input_len,\n                               const char *filename, int flags, int scope_idx)\n{\n    BOOL backtrace_barrier = ((flags & JS_EVAL_FLAG_BACKTRACE_BARRIER) != 0);\n    int saved_js_mode = 0;\n    JSValue ret;\n    \n    if (unlikely(!ctx->eval_internal)) {\n        return JS_ThrowTypeError(ctx, \"eval is not supported\");\n    }\n    if (backtrace_barrier && ctx->rt->current_stack_frame) {\n        saved_js_mode = ctx->rt->current_stack_frame->js_mode;\n        ctx->rt->current_stack_frame->js_mode |= JS_MODE_BACKTRACE_BARRIER;\n    }\n    ret = ctx->eval_internal(ctx, this_obj, input, input_len, filename,\n                             flags, scope_idx);\n    if (backtrace_barrier && ctx->rt->current_stack_frame)\n        ctx->rt->current_stack_frame->js_mode = saved_js_mode;\n    return ret;\n}\n\nstatic JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,\n                             JSValueConst val, int flags, int scope_idx)\n{\n    JSValue ret;\n    const char *str;\n    size_t len;\n\n    if (!JS_IsString(val))\n        return JS_DupValue(ctx, val);\n    str = JS_ToCStringLen(ctx, &len, val);\n    if (!str)\n        return JS_EXCEPTION;\n    ret = JS_EvalInternal(ctx, this_obj, str, len, \"<input>\", flags, scope_idx);\n    JS_FreeCString(ctx, str);\n    return ret;\n\n}\n\nJSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,\n                    const char *input, size_t input_len,\n                    const char *filename, int eval_flags)\n{\n    int eval_type = eval_flags & JS_EVAL_TYPE_MASK;\n    JSValue ret;\n\n    assert(eval_type == JS_EVAL_TYPE_GLOBAL ||\n           eval_type == JS_EVAL_TYPE_MODULE);\n    ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,\n                          eval_flags, -1);\n    return ret;\n}\n\nJSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,\n                const char *filename, int eval_flags)\n{\n    return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,\n                       eval_flags);\n}\n\nint JS_ResolveModule(JSContext *ctx, JSValueConst obj)\n{\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {\n        JSModuleDef *m = JS_VALUE_GET_PTR(obj);\n        if (js_resolve_module(ctx, m) < 0) {\n            js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED);\n            return -1;\n        }\n    }\n    return 0;\n}\n\n/*******************************************************************/\n/* object list */\n\ntypedef struct {\n    JSObject *obj;\n    uint32_t hash_next; /* -1 if no next entry */\n} JSObjectListEntry;\n\n/* XXX: reuse it to optimize weak references */\ntypedef struct {\n    JSObjectListEntry *object_tab;\n    int object_count;\n    int object_size;\n    uint32_t *hash_table;\n    uint32_t hash_size;\n} JSObjectList;\n\nstatic void js_object_list_init(JSObjectList *s)\n{\n    memset(s, 0, sizeof(*s));\n}\n\nstatic uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)\n{\n    return ((uintptr_t)p * 3163) & (hash_size - 1);\n}\n\nstatic int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,\n                                 uint32_t new_hash_size)\n{\n    JSObjectListEntry *e;\n    uint32_t i, h, *new_hash_table;\n\n    new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);\n    if (!new_hash_table)\n        return -1;\n    js_free(ctx, s->hash_table);\n    s->hash_table = new_hash_table;\n    s->hash_size = new_hash_size;\n\n    for(i = 0; i < s->hash_size; i++) {\n        s->hash_table[i] = -1;\n    }\n    for(i = 0; i < s->object_count; i++) {\n        e = &s->object_tab[i];\n        h = js_object_list_get_hash(e->obj, s->hash_size);\n        e->hash_next = s->hash_table[h];\n        s->hash_table[h] = i;\n    }\n    return 0;\n}\n\n/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if\n   memory error */\nstatic int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)\n{\n    JSObjectListEntry *e;\n    uint32_t h, new_hash_size;\n\n    if (js_resize_array(ctx, (void *)&s->object_tab,\n                        sizeof(s->object_tab[0]),\n                        &s->object_size, s->object_count + 1))\n        return -1;\n    if (unlikely((s->object_count + 1) >= s->hash_size)) {\n        new_hash_size = max_uint32(s->hash_size, 4);\n        while (new_hash_size <= s->object_count)\n            new_hash_size *= 2;\n        if (js_object_list_resize_hash(ctx, s, new_hash_size))\n            return -1;\n    }\n    e = &s->object_tab[s->object_count++];\n    h = js_object_list_get_hash(obj, s->hash_size);\n    e->obj = obj;\n    e->hash_next = s->hash_table[h];\n    s->hash_table[h] = s->object_count - 1;\n    return 0;\n}\n\n/* return -1 if not present or the object index */\nstatic int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)\n{\n    JSObjectListEntry *e;\n    uint32_t h, p;\n\n    /* must test empty size because there is no hash table */\n    if (s->object_count == 0)\n        return -1;\n    h = js_object_list_get_hash(obj, s->hash_size);\n    p = s->hash_table[h];\n    while (p != -1) {\n        e = &s->object_tab[p];\n        if (e->obj == obj)\n            return p;\n        p = e->hash_next;\n    }\n    return -1;\n}\n\nstatic void js_object_list_end(JSContext *ctx, JSObjectList *s)\n{\n    js_free(ctx, s->object_tab);\n    js_free(ctx, s->hash_table);\n}\n\n/*******************************************************************/\n/* binary object writer & reader */\n\ntypedef enum BCTagEnum {\n    BC_TAG_NULL = 1,\n    BC_TAG_UNDEFINED,\n    BC_TAG_BOOL_FALSE,\n    BC_TAG_BOOL_TRUE,\n    BC_TAG_INT32,\n    BC_TAG_FLOAT64,\n    BC_TAG_STRING,\n    BC_TAG_OBJECT,\n    BC_TAG_ARRAY,\n    BC_TAG_BIG_INT,\n    BC_TAG_TEMPLATE_OBJECT,\n    BC_TAG_FUNCTION_BYTECODE,\n    BC_TAG_MODULE,\n    BC_TAG_TYPED_ARRAY,\n    BC_TAG_ARRAY_BUFFER,\n    BC_TAG_SHARED_ARRAY_BUFFER,\n    BC_TAG_DATE,\n    BC_TAG_OBJECT_VALUE,\n    BC_TAG_OBJECT_REFERENCE,\n} BCTagEnum;\n\n#define BC_VERSION 5\n\ntypedef struct BCWriterState {\n    JSContext *ctx;\n    DynBuf dbuf;\n    BOOL allow_bytecode : 8;\n    BOOL allow_sab : 8;\n    BOOL allow_reference : 8;\n    uint32_t first_atom;\n    uint32_t *atom_to_idx;\n    int atom_to_idx_size;\n    JSAtom *idx_to_atom;\n    int idx_to_atom_count;\n    int idx_to_atom_size;\n    uint8_t **sab_tab;\n    int sab_tab_len;\n    int sab_tab_size;\n    /* list of referenced objects (used if allow_reference = TRUE) */\n    JSObjectList object_list;\n} BCWriterState;\n\n#ifdef DUMP_READ_OBJECT\nstatic const char * const bc_tag_str[] = {\n    \"invalid\",\n    \"null\",\n    \"undefined\",\n    \"false\",\n    \"true\",\n    \"int32\",\n    \"float64\",\n    \"string\",\n    \"object\",\n    \"array\",\n    \"bigint\",\n    \"template\",\n    \"function\",\n    \"module\",\n    \"TypedArray\",\n    \"ArrayBuffer\",\n    \"SharedArrayBuffer\",\n    \"Date\",\n    \"ObjectValue\",\n    \"ObjectReference\",\n};\n#endif\n\nstatic inline BOOL is_be(void)\n{\n    union {\n        uint16_t a;\n        uint8_t  b;\n    } u = {0x100};\n    return u.b;\n}\n\nstatic void bc_put_u8(BCWriterState *s, uint8_t v)\n{\n    dbuf_putc(&s->dbuf, v);\n}\n\nstatic void bc_put_u16(BCWriterState *s, uint16_t v)\n{\n    if (is_be())\n        v = bswap16(v);\n    dbuf_put_u16(&s->dbuf, v);\n}\n\nstatic __maybe_unused void bc_put_u32(BCWriterState *s, uint32_t v)\n{\n    if (is_be())\n        v = bswap32(v);\n    dbuf_put_u32(&s->dbuf, v);\n}\n\nstatic void bc_put_u64(BCWriterState *s, uint64_t v)\n{\n    if (is_be())\n        v = bswap64(v);\n    dbuf_put(&s->dbuf, (uint8_t *)&v, sizeof(v));\n}\n\nstatic void bc_put_leb128(BCWriterState *s, uint32_t v)\n{\n    dbuf_put_leb128(&s->dbuf, v);\n}\n\nstatic void bc_put_sleb128(BCWriterState *s, int32_t v)\n{\n    dbuf_put_sleb128(&s->dbuf, v);\n}\n\nstatic void bc_set_flags(uint32_t *pflags, int *pidx, uint32_t val, int n)\n{\n    *pflags = *pflags | (val << *pidx);\n    *pidx += n;\n}\n\nstatic int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom)\n{\n    uint32_t v;\n\n    if (atom < s->first_atom || __JS_AtomIsTaggedInt(atom)) {\n        *pres = atom;\n        return 0;\n    }\n    atom -= s->first_atom;\n    if (atom < s->atom_to_idx_size && s->atom_to_idx[atom] != 0) {\n        *pres = s->atom_to_idx[atom];\n        return 0;\n    }\n    if (atom >= s->atom_to_idx_size) {\n        int old_size, i;\n        old_size = s->atom_to_idx_size;\n        if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,\n                            sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,\n                            atom + 1))\n            return -1;\n        /* XXX: could add a specific js_resize_array() function to do it */\n        for(i = old_size; i < s->atom_to_idx_size; i++)\n            s->atom_to_idx[i] = 0;\n    }\n    if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,\n                        sizeof(s->idx_to_atom[0]),\n                        &s->idx_to_atom_size, s->idx_to_atom_count + 1))\n        goto fail;\n\n    v = s->idx_to_atom_count++;\n    s->idx_to_atom[v] = atom + s->first_atom;\n    v += s->first_atom;\n    s->atom_to_idx[atom] = v;\n    *pres = v;\n    return 0;\n fail:\n    *pres = 0;\n    return -1;\n}\n\nstatic int bc_put_atom(BCWriterState *s, JSAtom atom)\n{\n    uint32_t v;\n\n    if (__JS_AtomIsTaggedInt(atom)) {\n        v = (__JS_AtomToUInt32(atom) << 1) | 1;\n    } else {\n        if (bc_atom_to_idx(s, &v, atom))\n            return -1;\n        v <<= 1;\n    }\n    bc_put_leb128(s, v);\n    return 0;\n}\n\nstatic void bc_byte_swap(uint8_t *bc_buf, int bc_len)\n{\n    int pos, len, op, fmt;\n\n    pos = 0;\n    while (pos < bc_len) {\n        op = bc_buf[pos];\n        len = short_opcode_info(op).size;\n        fmt = short_opcode_info(op).fmt;\n        switch(fmt) {\n        case OP_FMT_u16:\n        case OP_FMT_i16:\n        case OP_FMT_label16:\n        case OP_FMT_npop:\n        case OP_FMT_loc:\n        case OP_FMT_arg:\n        case OP_FMT_var_ref:\n            put_u16(bc_buf + pos + 1,\n                    bswap16(get_u16(bc_buf + pos + 1)));\n            break;\n        case OP_FMT_i32:\n        case OP_FMT_u32:\n        case OP_FMT_const:\n        case OP_FMT_label:\n        case OP_FMT_atom:\n        case OP_FMT_atom_u8:\n            put_u32(bc_buf + pos + 1,\n                    bswap32(get_u32(bc_buf + pos + 1)));\n            break;\n        case OP_FMT_atom_u16:\n        case OP_FMT_label_u16:\n            put_u32(bc_buf + pos + 1,\n                    bswap32(get_u32(bc_buf + pos + 1)));\n            put_u16(bc_buf + pos + 1 + 4,\n                    bswap16(get_u16(bc_buf + pos + 1 + 4)));\n            break;\n        case OP_FMT_atom_label_u8:\n        case OP_FMT_atom_label_u16:\n            put_u32(bc_buf + pos + 1,\n                    bswap32(get_u32(bc_buf + pos + 1)));\n            put_u32(bc_buf + pos + 1 + 4,\n                    bswap32(get_u32(bc_buf + pos + 1 + 4)));\n            if (fmt == OP_FMT_atom_label_u16) {\n                put_u16(bc_buf + pos + 1 + 4 + 4,\n                        bswap16(get_u16(bc_buf + pos + 1 + 4 + 4)));\n            }\n            break;\n        case OP_FMT_npop_u16:\n            put_u16(bc_buf + pos + 1,\n                    bswap16(get_u16(bc_buf + pos + 1)));\n            put_u16(bc_buf + pos + 1 + 2,\n                    bswap16(get_u16(bc_buf + pos + 1 + 2)));\n            break;\n        default:\n            break;\n        }\n        pos += len;\n    }\n}\n\nstatic int JS_WriteFunctionBytecode(BCWriterState *s,\n                                    const uint8_t *bc_buf1, int bc_len)\n{\n    int pos, len, op;\n    JSAtom atom;\n    uint8_t *bc_buf;\n    uint32_t val;\n\n    bc_buf = js_malloc(s->ctx, bc_len);\n    if (!bc_buf)\n        return -1;\n    memcpy(bc_buf, bc_buf1, bc_len);\n\n    pos = 0;\n    while (pos < bc_len) {\n        op = bc_buf[pos];\n        len = short_opcode_info(op).size;\n        switch(short_opcode_info(op).fmt) {\n        case OP_FMT_atom:\n        case OP_FMT_atom_u8:\n        case OP_FMT_atom_u16:\n        case OP_FMT_atom_label_u8:\n        case OP_FMT_atom_label_u16:\n            atom = get_u32(bc_buf + pos + 1);\n            if (bc_atom_to_idx(s, &val, atom))\n                goto fail;\n            put_u32(bc_buf + pos + 1, val);\n            break;\n        default:\n            break;\n        }\n        pos += len;\n    }\n\n    if (is_be())\n        bc_byte_swap(bc_buf, bc_len);\n\n    dbuf_put(&s->dbuf, bc_buf, bc_len);\n\n    js_free(s->ctx, bc_buf);\n    return 0;\n fail:\n    js_free(s->ctx, bc_buf);\n    return -1;\n}\n\nstatic void JS_WriteString(BCWriterState *s, JSString *p)\n{\n    int i;\n    bc_put_leb128(s, ((uint32_t)p->len << 1) | p->is_wide_char);\n    if (p->is_wide_char) {\n        for(i = 0; i < p->len; i++)\n            bc_put_u16(s, p->u.str16[i]);\n    } else {\n        dbuf_put(&s->dbuf, p->u.str8, p->len);\n    }\n}\n\nstatic int JS_WriteBigInt(BCWriterState *s, JSValueConst obj)\n{\n    JSBigIntBuf buf;\n    JSBigInt *p;\n    uint32_t len, i;\n    js_limb_t v, b;\n    int shift;\n    \n    bc_put_u8(s, BC_TAG_BIG_INT);\n\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_SHORT_BIG_INT)\n        p = js_bigint_set_short(&buf, obj);\n    else\n        p = JS_VALUE_GET_PTR(obj);\n    if (p->len == 1 && p->tab[0] == 0) {\n        /* zero case */\n        len = 0;\n    } else {\n        /* compute the length of the two's complement representation\n           in bytes */\n        len = p->len * (JS_LIMB_BITS / 8);\n        v = p->tab[p->len - 1];\n        shift = JS_LIMB_BITS - 8;\n        while (shift > 0) {\n            b = (v >> shift) & 0xff;\n            if (b != 0x00 && b != 0xff)\n                break;\n            if ((b & 1) != ((v >> (shift - 1)) & 1))\n                break;\n            shift -= 8;\n            len--;\n        }\n    }\n    bc_put_leb128(s, len);\n    if (len > 0) {\n        for(i = 0; i < (len / (JS_LIMB_BITS / 8)); i++) {\n#if JS_LIMB_BITS == 32\n            bc_put_u32(s, p->tab[i]);\n#else\n            bc_put_u64(s, p->tab[i]);\n#endif\n        }\n        for(i = 0; i < len % (JS_LIMB_BITS / 8); i++) {\n            bc_put_u8(s, (p->tab[p->len - 1] >> (i * 8)) & 0xff);\n        }\n    }\n    return 0;\n}\n\nstatic int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);\n\nstatic int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)\n{\n    JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);\n    uint32_t flags;\n    int idx, i;\n\n    bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);\n    flags = idx = 0;\n    bc_set_flags(&flags, &idx, b->has_prototype, 1);\n    bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);\n    bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);\n    bc_set_flags(&flags, &idx, b->need_home_object, 1);\n    bc_set_flags(&flags, &idx, b->func_kind, 2);\n    bc_set_flags(&flags, &idx, b->new_target_allowed, 1);\n    bc_set_flags(&flags, &idx, b->super_call_allowed, 1);\n    bc_set_flags(&flags, &idx, b->super_allowed, 1);\n    bc_set_flags(&flags, &idx, b->arguments_allowed, 1);\n    bc_set_flags(&flags, &idx, b->has_debug, 1);\n    bc_set_flags(&flags, &idx, b->is_direct_or_indirect_eval, 1);\n    assert(idx <= 16);\n    bc_put_u16(s, flags);\n    bc_put_u8(s, b->js_mode);\n    bc_put_atom(s, b->func_name);\n\n    bc_put_leb128(s, b->arg_count);\n    bc_put_leb128(s, b->var_count);\n    bc_put_leb128(s, b->defined_arg_count);\n    bc_put_leb128(s, b->stack_size);\n    bc_put_leb128(s, b->var_ref_count);\n    bc_put_leb128(s, b->closure_var_count);\n    bc_put_leb128(s, b->cpool_count);\n    bc_put_leb128(s, b->byte_code_len);\n    if (b->vardefs) {\n        bc_put_leb128(s, b->arg_count + b->var_count);\n        for(i = 0; i < b->arg_count + b->var_count; i++) {\n            JSBytecodeVarDef *vd = &b->vardefs[i];\n            bc_put_atom(s, vd->var_name);\n            bc_put_leb128(s, vd->scope_next + 1);\n            bc_put_leb128(s, vd->var_ref_idx);\n            flags = idx = 0;\n            bc_set_flags(&flags, &idx, vd->var_kind, 4);\n            bc_set_flags(&flags, &idx, vd->is_const, 1);\n            bc_set_flags(&flags, &idx, vd->is_lexical, 1);\n            bc_set_flags(&flags, &idx, vd->is_captured, 1);\n            bc_set_flags(&flags, &idx, vd->has_scope, 1);\n            assert(idx <= 8);\n            bc_put_u8(s, flags);\n        }\n    } else {\n        bc_put_leb128(s, 0);\n    }\n\n    for(i = 0; i < b->closure_var_count; i++) {\n        JSClosureVar *cv = &b->closure_var[i];\n        bc_put_atom(s, cv->var_name);\n        bc_put_leb128(s, cv->var_idx);\n        flags = idx = 0;\n        bc_set_flags(&flags, &idx, cv->closure_type, 3);\n        bc_set_flags(&flags, &idx, cv->is_const, 1);\n        bc_set_flags(&flags, &idx, cv->is_lexical, 1);\n        bc_set_flags(&flags, &idx, cv->var_kind, 4);\n        assert(idx <= 16);\n        bc_put_u16(s, flags);\n    }\n\n    if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))\n        goto fail;\n\n    if (b->has_debug) {\n        bc_put_atom(s, b->debug.filename);\n        bc_put_leb128(s, b->debug.pc2line_len);\n        dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);\n        if (b->debug.source) {\n            bc_put_leb128(s, b->debug.source_len);\n            dbuf_put(&s->dbuf, (uint8_t *)b->debug.source, b->debug.source_len);\n        } else {\n            bc_put_leb128(s, 0);\n        }\n    }\n\n    for(i = 0; i < b->cpool_count; i++) {\n        if (JS_WriteObjectRec(s, b->cpool[i]))\n            goto fail;\n    }\n    return 0;\n fail:\n    return -1;\n}\n\nstatic int JS_WriteModule(BCWriterState *s, JSValueConst obj)\n{\n    JSModuleDef *m = JS_VALUE_GET_PTR(obj);\n    int i;\n\n    bc_put_u8(s, BC_TAG_MODULE);\n    bc_put_atom(s, m->module_name);\n\n    bc_put_leb128(s, m->req_module_entries_count);\n    for(i = 0; i < m->req_module_entries_count; i++) {\n        JSReqModuleEntry *rme = &m->req_module_entries[i];\n        bc_put_atom(s, rme->module_name);\n        if (JS_WriteObjectRec(s, rme->attributes))\n            goto fail;\n    }\n\n    bc_put_leb128(s, m->export_entries_count);\n    for(i = 0; i < m->export_entries_count; i++) {\n        JSExportEntry *me = &m->export_entries[i];\n        bc_put_u8(s, me->export_type);\n        if (me->export_type == JS_EXPORT_TYPE_LOCAL) {\n            bc_put_leb128(s, me->u.local.var_idx);\n        } else {\n            bc_put_leb128(s, me->u.req_module_idx);\n            bc_put_atom(s, me->local_name);\n        }\n        bc_put_atom(s, me->export_name);\n    }\n\n    bc_put_leb128(s, m->star_export_entries_count);\n    for(i = 0; i < m->star_export_entries_count; i++) {\n        JSStarExportEntry *se = &m->star_export_entries[i];\n        bc_put_leb128(s, se->req_module_idx);\n    }\n\n    bc_put_leb128(s, m->import_entries_count);\n    for(i = 0; i < m->import_entries_count; i++) {\n        JSImportEntry *mi = &m->import_entries[i];\n        bc_put_leb128(s, mi->var_idx);\n        bc_put_u8(s, mi->is_star);\n        bc_put_atom(s, mi->import_name);\n        bc_put_leb128(s, mi->req_module_idx);\n    }\n\n    bc_put_u8(s, m->has_tla);\n\n    if (JS_WriteObjectRec(s, m->func_obj))\n        goto fail;\n    return 0;\n fail:\n    return -1;\n}\n\n/* XXX: be compatible with the structured clone algorithm */\nstatic int JS_WriteArray(BCWriterState *s, JSValueConst obj)\n{\n    JSContext *ctx = s->ctx;\n    JSObject *p = JS_VALUE_GET_OBJ(obj);\n    uint32_t i, len;\n    int ret;\n    BOOL is_template;\n    JSShapeProperty *prs;\n    JSProperty *pr;\n    \n    if (s->allow_bytecode && !p->extensible) {\n        /* not extensible array: we consider it is a\n           template when we are saving bytecode */\n        bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);\n        is_template = TRUE;\n    } else {\n        bc_put_u8(s, BC_TAG_ARRAY);\n        is_template = FALSE;\n    }\n    if (js_get_length32(ctx, &len, obj)) /* no side effect */\n        goto fail;\n    bc_put_leb128(s, len);\n    if (p->fast_array) {\n        for(i = 0; i < p->u.array.count; i++) {\n            ret = JS_WriteObjectRec(s, p->u.array.u.values[i]);\n            if (ret)\n                goto fail;\n        }\n        for(i = p->u.array.count; i < len; i++) {\n            ret = JS_WriteObjectRec(s, JS_UNDEFINED);\n            if (ret)\n                goto fail;\n        }\n    } else {\n        for(i = 0; i < len; i++) {\n            JSAtom atom;\n            atom = JS_NewAtomUInt32(ctx, i);\n            if (atom == JS_ATOM_NULL)\n                goto fail;\n            prs = find_own_property(&pr, p, atom);\n            JS_FreeAtom(ctx, atom);\n            if (prs && (prs->flags & JS_PROP_ENUMERABLE)) {\n                if (prs->flags & JS_PROP_TMASK) {\n                    JS_ThrowTypeError(ctx, \"only value properties are supported\");\n                    goto fail;\n                }\n                ret = JS_WriteObjectRec(s, pr->u.value);\n                if (ret)\n                    goto fail;\n            } else {\n                ret = JS_WriteObjectRec(s, JS_UNDEFINED);\n                if (ret)\n                    goto fail;\n            }\n        }\n    }\n    if (is_template) {\n        /* the 'raw' property is not enumerable */\n        prs = find_own_property(&pr, p, JS_ATOM_raw);\n        if (prs) {\n            if (prs->flags & JS_PROP_TMASK) {\n                JS_ThrowTypeError(ctx, \"only value properties are supported\");\n                goto fail;\n            }\n            ret = JS_WriteObjectRec(s, pr->u.value);\n            if (ret)\n                goto fail;\n        } else {\n            ret = JS_WriteObjectRec(s, JS_UNDEFINED);\n            if (ret)\n                goto fail;\n        }\n    }\n    return 0;\n fail:\n    return -1;\n}\n\nstatic int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(obj);\n    uint32_t i, prop_count;\n    JSShape *sh;\n    JSShapeProperty *pr;\n    int pass;\n    JSAtom atom;\n\n    bc_put_u8(s, BC_TAG_OBJECT);\n    prop_count = 0;\n    sh = p->shape;\n    for(pass = 0; pass < 2; pass++) {\n        if (pass == 1)\n            bc_put_leb128(s, prop_count);\n        for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {\n            atom = pr->atom;\n            if (atom != JS_ATOM_NULL &&\n                JS_AtomIsString(s->ctx, atom) &&\n                (pr->flags & JS_PROP_ENUMERABLE)) {\n                if (pr->flags & JS_PROP_TMASK) {\n                    JS_ThrowTypeError(s->ctx, \"only value properties are supported\");\n                    goto fail;\n                }\n                if (pass == 0) {\n                    prop_count++;\n                } else {\n                    bc_put_atom(s, atom);\n                    if (JS_WriteObjectRec(s, p->prop[i].u.value))\n                        goto fail;\n                }\n            }\n        }\n    }\n    return 0;\n fail:\n    return -1;\n}\n\nstatic int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(obj);\n    JSTypedArray *ta = p->u.typed_array;\n\n    bc_put_u8(s, BC_TAG_TYPED_ARRAY);\n    bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);\n    bc_put_leb128(s, p->u.array.count);\n    bc_put_leb128(s, ta->offset);\n    if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))\n        return -1;\n    return 0;\n}\n\nstatic int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(obj);\n    JSArrayBuffer *abuf = p->u.array_buffer;\n    if (abuf->detached) {\n        JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);\n        return -1;\n    }\n    bc_put_u8(s, BC_TAG_ARRAY_BUFFER);\n    bc_put_leb128(s, abuf->byte_length);\n    bc_put_leb128(s, abuf->max_byte_length);\n    dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);\n    return 0;\n}\n\nstatic int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(obj);\n    JSArrayBuffer *abuf = p->u.array_buffer;\n    assert(!abuf->detached); /* SharedArrayBuffer are never detached */\n    bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);\n    bc_put_leb128(s, abuf->byte_length);\n    bc_put_leb128(s, abuf->max_byte_length);\n    bc_put_u64(s, (uintptr_t)abuf->data);\n    if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),\n                        &s->sab_tab_size, s->sab_tab_len + 1))\n        return -1;\n    /* keep the SAB pointer so that the user can clone it or free it */\n    s->sab_tab[s->sab_tab_len++] = abuf->data;\n    return 0;\n}\n\nstatic int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)\n{\n    uint32_t tag;\n\n    if (js_check_stack_overflow(s->ctx->rt, 0)) {\n        JS_ThrowStackOverflow(s->ctx);\n        return -1;\n    }\n\n    tag = JS_VALUE_GET_NORM_TAG(obj);\n    switch(tag) {\n    case JS_TAG_NULL:\n        bc_put_u8(s, BC_TAG_NULL);\n        break;\n    case JS_TAG_UNDEFINED:\n        bc_put_u8(s, BC_TAG_UNDEFINED);\n        break;\n    case JS_TAG_BOOL:\n        bc_put_u8(s, BC_TAG_BOOL_FALSE + JS_VALUE_GET_INT(obj));\n        break;\n    case JS_TAG_INT:\n        bc_put_u8(s, BC_TAG_INT32);\n        bc_put_sleb128(s, JS_VALUE_GET_INT(obj));\n        break;\n    case JS_TAG_FLOAT64:\n        {\n            JSFloat64Union u;\n            bc_put_u8(s, BC_TAG_FLOAT64);\n            u.d = JS_VALUE_GET_FLOAT64(obj);\n            bc_put_u64(s, u.u64);\n        }\n        break;\n    case JS_TAG_STRING:\n        {\n            JSString *p = JS_VALUE_GET_STRING(obj);\n            bc_put_u8(s, BC_TAG_STRING);\n            JS_WriteString(s, p);\n        }\n        break;\n    case JS_TAG_STRING_ROPE:\n        {\n            JSValue str;\n            str = JS_ToString(s->ctx, obj);\n            if (JS_IsException(str))\n                goto fail;\n            JS_WriteObjectRec(s, str);\n            JS_FreeValue(s->ctx, str);\n        }\n        break;\n    case JS_TAG_FUNCTION_BYTECODE:\n        if (!s->allow_bytecode)\n            goto invalid_tag;\n        if (JS_WriteFunctionTag(s, obj))\n            goto fail;\n        break;\n    case JS_TAG_MODULE:\n        if (!s->allow_bytecode)\n            goto invalid_tag;\n        if (JS_WriteModule(s, obj))\n            goto fail;\n        break;\n    case JS_TAG_OBJECT:\n        {\n            JSObject *p = JS_VALUE_GET_OBJ(obj);\n            int ret, idx;\n\n            if (s->allow_reference) {\n                idx = js_object_list_find(s->ctx, &s->object_list, p);\n                if (idx >= 0) {\n                    bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);\n                    bc_put_leb128(s, idx);\n                    break;\n                } else {\n                    if (js_object_list_add(s->ctx, &s->object_list, p))\n                        goto fail;\n                }\n            } else {\n                if (p->tmp_mark) {\n                    JS_ThrowTypeError(s->ctx, \"circular reference\");\n                    goto fail;\n                }\n                p->tmp_mark = 1;\n            }\n            switch(p->class_id) {\n            case JS_CLASS_ARRAY:\n                ret = JS_WriteArray(s, obj);\n                break;\n            case JS_CLASS_OBJECT:\n                ret = JS_WriteObjectTag(s, obj);\n                break;\n            case JS_CLASS_ARRAY_BUFFER:\n                ret = JS_WriteArrayBuffer(s, obj);\n                break;\n            case JS_CLASS_SHARED_ARRAY_BUFFER:\n                if (!s->allow_sab)\n                    goto invalid_tag;\n                ret = JS_WriteSharedArrayBuffer(s, obj);\n                break;\n            case JS_CLASS_DATE:\n                bc_put_u8(s, BC_TAG_DATE);\n                ret = JS_WriteObjectRec(s, p->u.object_data);\n                break;\n            case JS_CLASS_NUMBER:\n            case JS_CLASS_STRING:\n            case JS_CLASS_BOOLEAN:\n            case JS_CLASS_BIG_INT:\n                bc_put_u8(s, BC_TAG_OBJECT_VALUE);\n                ret = JS_WriteObjectRec(s, p->u.object_data);\n                break;\n            default:\n                if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                    p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n                    ret = JS_WriteTypedArray(s, obj);\n                } else {\n                    JS_ThrowTypeError(s->ctx, \"unsupported object class\");\n                    ret = -1;\n                }\n                break;\n            }\n            p->tmp_mark = 0;\n            if (ret)\n                goto fail;\n        }\n        break;\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        if (JS_WriteBigInt(s, obj))\n            goto fail;\n        break;\n    default:\n    invalid_tag:\n        JS_ThrowInternalError(s->ctx, \"unsupported tag (%d)\", tag);\n        goto fail;\n    }\n    return 0;\n\n fail:\n    return -1;\n}\n\n/* create the atom table */\nstatic int JS_WriteObjectAtoms(BCWriterState *s)\n{\n    JSRuntime *rt = s->ctx->rt;\n    DynBuf dbuf1;\n    int i, atoms_size;\n\n    dbuf1 = s->dbuf;\n    js_dbuf_init(s->ctx, &s->dbuf);\n    bc_put_u8(s, BC_VERSION);\n\n    bc_put_leb128(s, s->idx_to_atom_count);\n    for(i = 0; i < s->idx_to_atom_count; i++) {\n        JSAtomStruct *p = rt->atom_array[s->idx_to_atom[i]];\n        JS_WriteString(s, p);\n    }\n    /* XXX: should check for OOM in above phase */\n\n    /* move the atoms at the start */\n    /* XXX: could just append dbuf1 data, but it uses more memory if\n       dbuf1 is larger than dbuf */\n    atoms_size = s->dbuf.size;\n    if (dbuf_claim(&dbuf1, atoms_size))\n        goto fail;\n    memmove(dbuf1.buf + atoms_size, dbuf1.buf, dbuf1.size);\n    memcpy(dbuf1.buf, s->dbuf.buf, atoms_size);\n    dbuf1.size += atoms_size;\n    dbuf_free(&s->dbuf);\n    s->dbuf = dbuf1;\n    return 0;\n fail:\n    dbuf_free(&dbuf1);\n    return -1;\n}\n\nuint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,\n                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len)\n{\n    BCWriterState ss, *s = &ss;\n\n    memset(s, 0, sizeof(*s));\n    s->ctx = ctx;\n    s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);\n    s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);\n    s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);\n    /* XXX: could use a different version when bytecode is included */\n    if (s->allow_bytecode)\n        s->first_atom = JS_ATOM_END;\n    else\n        s->first_atom = 1;\n    js_dbuf_init(ctx, &s->dbuf);\n    js_object_list_init(&s->object_list);\n\n    if (JS_WriteObjectRec(s, obj))\n        goto fail;\n    if (JS_WriteObjectAtoms(s))\n        goto fail;\n    js_object_list_end(ctx, &s->object_list);\n    js_free(ctx, s->atom_to_idx);\n    js_free(ctx, s->idx_to_atom);\n    *psize = s->dbuf.size;\n    if (psab_tab)\n        *psab_tab = s->sab_tab;\n    if (psab_tab_len)\n        *psab_tab_len = s->sab_tab_len;\n    return s->dbuf.buf;\n fail:\n    js_object_list_end(ctx, &s->object_list);\n    js_free(ctx, s->atom_to_idx);\n    js_free(ctx, s->idx_to_atom);\n    dbuf_free(&s->dbuf);\n    *psize = 0;\n    if (psab_tab)\n        *psab_tab = NULL;\n    if (psab_tab_len)\n        *psab_tab_len = 0;\n    return NULL;\n}\n\nuint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,\n                        int flags)\n{\n    return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);\n}\n\ntypedef struct BCReaderState {\n    JSContext *ctx;\n    const uint8_t *buf_start, *ptr, *buf_end;\n    uint32_t first_atom;\n    uint32_t idx_to_atom_count;\n    JSAtom *idx_to_atom;\n    int error_state;\n    BOOL allow_sab : 8;\n    BOOL allow_bytecode : 8;\n    BOOL is_rom_data : 8;\n    BOOL allow_reference : 8;\n    /* object references */\n    JSObject **objects;\n    int objects_count;\n    int objects_size;\n\n#ifdef DUMP_READ_OBJECT\n    const uint8_t *ptr_last;\n    int level;\n#endif\n} BCReaderState;\n\n#ifdef DUMP_READ_OBJECT\nstatic void __attribute__((format(printf, 2, 3))) bc_read_trace(BCReaderState *s, const char *fmt, ...) {\n    va_list ap;\n    int i, n, n0;\n\n    if (!s->ptr_last)\n        s->ptr_last = s->buf_start;\n\n    n = n0 = 0;\n    if (s->ptr > s->ptr_last || s->ptr == s->buf_start) {\n        n0 = printf(\"%04x: \", (int)(s->ptr_last - s->buf_start));\n        n += n0;\n    }\n    for (i = 0; s->ptr_last < s->ptr; i++) {\n        if ((i & 7) == 0 && i > 0) {\n            printf(\"\\n%*s\", n0, \"\");\n            n = n0;\n        }\n        n += printf(\" %02x\", *s->ptr_last++);\n    }\n    if (*fmt == '}')\n        s->level--;\n    if (n < 32 + s->level * 2) {\n        printf(\"%*s\", 32 + s->level * 2 - n, \"\");\n    }\n    va_start(ap, fmt);\n    vfprintf(stdout, fmt, ap);\n    va_end(ap);\n    if (strchr(fmt, '{'))\n        s->level++;\n}\n#else\n#define bc_read_trace(...)\n#endif\n\nstatic int bc_read_error_end(BCReaderState *s)\n{\n    if (!s->error_state) {\n        JS_ThrowSyntaxError(s->ctx, \"read after the end of the buffer\");\n    }\n    return s->error_state = -1;\n}\n\nstatic int bc_get_u8(BCReaderState *s, uint8_t *pval)\n{\n    if (unlikely(s->buf_end - s->ptr < 1)) {\n        *pval = 0; /* avoid warning */\n        return bc_read_error_end(s);\n    }\n    *pval = *s->ptr++;\n    return 0;\n}\n\nstatic int bc_get_u16(BCReaderState *s, uint16_t *pval)\n{\n    uint16_t v;\n    if (unlikely(s->buf_end - s->ptr < 2)) {\n        *pval = 0; /* avoid warning */\n        return bc_read_error_end(s);\n    }\n    v = get_u16(s->ptr);\n    if (is_be())\n        v = bswap16(v);\n    *pval = v;\n    s->ptr += 2;\n    return 0;\n}\n\nstatic __maybe_unused int bc_get_u32(BCReaderState *s, uint32_t *pval)\n{\n    uint32_t v;\n    if (unlikely(s->buf_end - s->ptr < 4)) {\n        *pval = 0; /* avoid warning */\n        return bc_read_error_end(s);\n    }\n    v = get_u32(s->ptr);\n    if (is_be())\n        v = bswap32(v);\n    *pval = v;\n    s->ptr += 4;\n    return 0;\n}\n\nstatic int bc_get_u64(BCReaderState *s, uint64_t *pval)\n{\n    uint64_t v;\n    if (unlikely(s->buf_end - s->ptr < 8)) {\n        *pval = 0; /* avoid warning */\n        return bc_read_error_end(s);\n    }\n    v = get_u64(s->ptr);\n    if (is_be())\n        v = bswap64(v);\n    *pval = v;\n    s->ptr += 8;\n    return 0;\n}\n\nstatic int bc_get_leb128(BCReaderState *s, uint32_t *pval)\n{\n    int ret;\n    ret = get_leb128(pval, s->ptr, s->buf_end);\n    if (unlikely(ret < 0))\n        return bc_read_error_end(s);\n    s->ptr += ret;\n    return 0;\n}\n\nstatic int bc_get_sleb128(BCReaderState *s, int32_t *pval)\n{\n    int ret;\n    ret = get_sleb128(pval, s->ptr, s->buf_end);\n    if (unlikely(ret < 0))\n        return bc_read_error_end(s);\n    s->ptr += ret;\n    return 0;\n}\n\n/* XXX: used to read an `int` with a positive value */\nstatic int bc_get_leb128_int(BCReaderState *s, int *pval)\n{\n    return bc_get_leb128(s, (uint32_t *)pval);\n}\n\nstatic int bc_get_leb128_u16(BCReaderState *s, uint16_t *pval)\n{\n    uint32_t val;\n    if (bc_get_leb128(s, &val)) {\n        *pval = 0;\n        return -1;\n    }\n    *pval = val;\n    return 0;\n}\n\nstatic int bc_get_buf(BCReaderState *s, uint8_t *buf, uint32_t buf_len)\n{\n    if (buf_len != 0) {\n        if (unlikely(!buf || s->buf_end - s->ptr < buf_len))\n            return bc_read_error_end(s);\n        memcpy(buf, s->ptr, buf_len);\n        s->ptr += buf_len;\n    }\n    return 0;\n}\n\nstatic int bc_idx_to_atom(BCReaderState *s, JSAtom *patom, uint32_t idx)\n{\n    JSAtom atom;\n\n    if (__JS_AtomIsTaggedInt(idx)) {\n        atom = idx;\n    } else if (idx < s->first_atom) {\n        atom = JS_DupAtom(s->ctx, idx);\n    } else {\n        idx -= s->first_atom;\n        if (idx >= s->idx_to_atom_count) {\n            JS_ThrowSyntaxError(s->ctx, \"invalid atom index (pos=%u)\",\n                                (unsigned int)(s->ptr - s->buf_start));\n            *patom = JS_ATOM_NULL;\n            return s->error_state = -1;\n        }\n        atom = JS_DupAtom(s->ctx, s->idx_to_atom[idx]);\n    }\n    *patom = atom;\n    return 0;\n}\n\nstatic int bc_get_atom(BCReaderState *s, JSAtom *patom)\n{\n    uint32_t v;\n    if (bc_get_leb128(s, &v))\n        return -1;\n    if (v & 1) {\n        *patom = __JS_AtomFromUInt32(v >> 1);\n        return 0;\n    } else {\n        return bc_idx_to_atom(s, patom, v >> 1);\n    }\n}\n\nstatic JSString *JS_ReadString(BCReaderState *s)\n{\n    uint32_t len;\n    size_t size;\n    BOOL is_wide_char;\n    JSString *p;\n\n    if (bc_get_leb128(s, &len))\n        return NULL;\n    is_wide_char = len & 1;\n    len >>= 1;\n    if (len > JS_STRING_LEN_MAX) {\n        JS_ThrowInternalError(s->ctx, \"string too long\");\n        return NULL;\n    }\n    p = js_alloc_string(s->ctx, len, is_wide_char);\n    if (!p) {\n        s->error_state = -1;\n        return NULL;\n    }\n    size = (size_t)len << is_wide_char;\n    if ((s->buf_end - s->ptr) < size) {\n        bc_read_error_end(s);\n        js_free_string(s->ctx->rt, p);\n        return NULL;\n    }\n    memcpy(p->u.str8, s->ptr, size);\n    s->ptr += size;\n    if (is_wide_char) {\n        if (is_be()) {\n            uint32_t i;\n            for (i = 0; i < len; i++)\n                p->u.str16[i] = bswap16(p->u.str16[i]);\n        }\n    } else {\n        p->u.str8[size] = '\\0'; /* add the trailing zero for 8 bit strings */\n    }\n#ifdef DUMP_READ_OBJECT\n    JS_DumpString(s->ctx->rt, p); printf(\"\\n\");\n#endif\n    return p;\n}\n\nstatic uint32_t bc_get_flags(uint32_t flags, int *pidx, int n)\n{\n    uint32_t val;\n    /* XXX: this does not work for n == 32 */\n    val = (flags >> *pidx) & ((1U << n) - 1);\n    *pidx += n;\n    return val;\n}\n\nstatic int JS_ReadFunctionBytecode(BCReaderState *s, JSFunctionBytecode *b,\n                                   int byte_code_offset, uint32_t bc_len)\n{\n    uint8_t *bc_buf;\n    int pos, len, op;\n    JSAtom atom;\n    uint32_t idx;\n\n    if (s->is_rom_data) {\n        /* directly use the input buffer */\n        if (unlikely(s->buf_end - s->ptr < bc_len))\n            return bc_read_error_end(s);\n        bc_buf = (uint8_t *)s->ptr;\n        s->ptr += bc_len;\n    } else {\n        bc_buf = (void *)((uint8_t*)b + byte_code_offset);\n        if (bc_get_buf(s, bc_buf, bc_len))\n            return -1;\n    }\n    b->byte_code_buf = bc_buf;\n\n    if (is_be())\n        bc_byte_swap(bc_buf, bc_len);\n\n    pos = 0;\n    while (pos < bc_len) {\n        op = bc_buf[pos];\n        len = short_opcode_info(op).size;\n        switch(short_opcode_info(op).fmt) {\n        case OP_FMT_atom:\n        case OP_FMT_atom_u8:\n        case OP_FMT_atom_u16:\n        case OP_FMT_atom_label_u8:\n        case OP_FMT_atom_label_u16:\n            idx = get_u32(bc_buf + pos + 1);\n            if (s->is_rom_data) {\n                /* just increment the reference count of the atom */\n                JS_DupAtom(s->ctx, (JSAtom)idx);\n            } else {\n                if (bc_idx_to_atom(s, &atom, idx)) {\n                    /* Note: the atoms will be freed up to this position */\n                    b->byte_code_len = pos;\n                    return -1;\n                }\n                put_u32(bc_buf + pos + 1, atom);\n#ifdef DUMP_READ_OBJECT\n                bc_read_trace(s, \"at %d, fixup atom: \", pos + 1); print_atom(s->ctx, atom); printf(\"\\n\");\n#endif\n            }\n            break;\n        default:\n            break;\n        }\n        pos += len;\n    }\n    return 0;\n}\n\nstatic JSValue JS_ReadBigInt(BCReaderState *s)\n{\n    JSValue obj = JS_UNDEFINED;\n    uint32_t len, i, n;\n    JSBigInt *p;\n    js_limb_t v;\n    uint8_t v8;\n    \n    if (bc_get_leb128(s, &len))\n        goto fail;\n    bc_read_trace(s, \"len=%\" PRId64 \"\\n\", (int64_t)len);\n    if (len == 0) {\n        /* zero case */\n        bc_read_trace(s, \"}\\n\");\n        return __JS_NewShortBigInt(s->ctx, 0);\n    }\n    p = js_bigint_new(s->ctx, (len - 1) / (JS_LIMB_BITS / 8) + 1);\n    if (!p)\n        goto fail;\n    for(i = 0; i < len / (JS_LIMB_BITS / 8); i++) {\n#if JS_LIMB_BITS == 32\n        if (bc_get_u32(s, &v))\n            goto fail;\n#else\n        if (bc_get_u64(s, &v))\n            goto fail;\n#endif\n        p->tab[i] = v;\n    }\n    n = len % (JS_LIMB_BITS / 8);\n    if (n != 0) {\n        int shift;\n        v = 0;\n        for(i = 0; i < n; i++) {\n            if (bc_get_u8(s, &v8))\n                goto fail;\n            v |= (js_limb_t)v8 << (i * 8);\n        }\n        shift = JS_LIMB_BITS - n * 8;\n        /* extend the sign */\n        if (shift != 0) {\n            v = (js_slimb_t)(v << shift) >> shift;\n        }\n        p->tab[p->len - 1] = v;\n    }\n    bc_read_trace(s, \"}\\n\");\n    return JS_CompactBigInt(s->ctx, p);\n fail:\n    JS_FreeValue(s->ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadObjectRec(BCReaderState *s);\n\nstatic int BC_add_object_ref1(BCReaderState *s, JSObject *p)\n{\n    if (s->allow_reference) {\n        if (js_resize_array(s->ctx, (void *)&s->objects,\n                            sizeof(s->objects[0]),\n                            &s->objects_size, s->objects_count + 1))\n            return -1;\n        s->objects[s->objects_count++] = p;\n    }\n    return 0;\n}\n\nstatic int BC_add_object_ref(BCReaderState *s, JSValueConst obj)\n{\n    return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));\n}\n\nstatic JSValue JS_ReadFunctionTag(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSFunctionBytecode bc, *b;\n    JSValue obj = JS_UNDEFINED;\n    uint16_t v16;\n    uint8_t v8;\n    int idx, i, local_count;\n    int function_size, cpool_offset, byte_code_offset;\n    int closure_var_offset, vardefs_offset;\n\n    memset(&bc, 0, sizeof(bc));\n    bc.header.ref_count = 1;\n    //bc.gc_header.mark = 0;\n\n    if (bc_get_u16(s, &v16))\n        goto fail;\n    idx = 0;\n    bc.has_prototype = bc_get_flags(v16, &idx, 1);\n    bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);\n    bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);\n    bc.need_home_object = bc_get_flags(v16, &idx, 1);\n    bc.func_kind = bc_get_flags(v16, &idx, 2);\n    bc.new_target_allowed = bc_get_flags(v16, &idx, 1);\n    bc.super_call_allowed = bc_get_flags(v16, &idx, 1);\n    bc.super_allowed = bc_get_flags(v16, &idx, 1);\n    bc.arguments_allowed = bc_get_flags(v16, &idx, 1);\n    bc.has_debug = bc_get_flags(v16, &idx, 1);\n    bc.is_direct_or_indirect_eval = bc_get_flags(v16, &idx, 1);\n    bc.read_only_bytecode = s->is_rom_data;\n    if (bc_get_u8(s, &v8))\n        goto fail;\n    bc.js_mode = v8;\n    if (bc_get_atom(s, &bc.func_name))  //@ atom leak if failure\n        goto fail;\n    if (bc_get_leb128_u16(s, &bc.arg_count))\n        goto fail;\n    if (bc_get_leb128_u16(s, &bc.var_count))\n        goto fail;\n    if (bc_get_leb128_u16(s, &bc.defined_arg_count))\n        goto fail;\n    if (bc_get_leb128_u16(s, &bc.stack_size))\n        goto fail;\n    if (bc_get_leb128_u16(s, &bc.var_ref_count))\n        goto fail;\n    if (bc_get_leb128_int(s, &bc.closure_var_count))\n        goto fail;\n    if (bc_get_leb128_int(s, &bc.cpool_count))\n        goto fail;\n    if (bc_get_leb128_int(s, &bc.byte_code_len))\n        goto fail;\n    if (bc_get_leb128_int(s, &local_count))\n        goto fail;\n\n    if (bc.has_debug) {\n        function_size = sizeof(*b);\n    } else {\n        function_size = offsetof(JSFunctionBytecode, debug);\n    }\n    cpool_offset = function_size;\n    function_size += bc.cpool_count * sizeof(*bc.cpool);\n    vardefs_offset = function_size;\n    function_size += local_count * sizeof(*bc.vardefs);\n    closure_var_offset = function_size;\n    function_size += bc.closure_var_count * sizeof(*bc.closure_var);\n    byte_code_offset = function_size;\n    if (!bc.read_only_bytecode) {\n        function_size += bc.byte_code_len;\n    }\n\n    b = js_mallocz(ctx, function_size);\n    if (!b)\n        return JS_EXCEPTION;\n\n    memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));\n    b->header.ref_count = 1;\n    if (local_count != 0) {\n        b->vardefs = (void *)((uint8_t*)b + vardefs_offset);\n    }\n    if (b->closure_var_count != 0) {\n        b->closure_var = (void *)((uint8_t*)b + closure_var_offset);\n    }\n    if (b->cpool_count != 0) {\n        b->cpool = (void *)((uint8_t*)b + cpool_offset);\n    }\n\n    add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);\n\n    obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);\n\n#ifdef DUMP_READ_OBJECT\n    bc_read_trace(s, \"name: \"); print_atom(s->ctx, b->func_name); printf(\"\\n\");\n#endif\n    bc_read_trace(s, \"args=%d vars=%d defargs=%d closures=%d cpool=%d\\n\",\n                  b->arg_count, b->var_count, b->defined_arg_count,\n                  b->closure_var_count, b->cpool_count);\n    bc_read_trace(s, \"stack=%d bclen=%d locals=%d\\n\",\n                  b->stack_size, b->byte_code_len, local_count);\n\n    if (local_count != 0) {\n        bc_read_trace(s, \"vars {\\n\");\n        for(i = 0; i < local_count; i++) {\n            JSBytecodeVarDef *vd = &b->vardefs[i];\n            if (bc_get_atom(s, &vd->var_name))\n                goto fail;\n            if (bc_get_leb128_int(s, &vd->scope_next))\n                goto fail;\n            vd->scope_next--;\n            if (bc_get_leb128_u16(s, &vd->var_ref_idx))\n                goto fail;\n            if (bc_get_u8(s, &v8))\n                goto fail;\n            idx = 0;\n            vd->var_kind = bc_get_flags(v8, &idx, 4);\n            vd->is_const = bc_get_flags(v8, &idx, 1);\n            vd->is_lexical = bc_get_flags(v8, &idx, 1);\n            vd->is_captured = bc_get_flags(v8, &idx, 1);\n            vd->has_scope = bc_get_flags(v8, &idx, 1);\n#ifdef DUMP_READ_OBJECT\n            bc_read_trace(s, \"name: \"); print_atom(s->ctx, vd->var_name); printf(\"\\n\");\n#endif\n        }\n        bc_read_trace(s, \"}\\n\");\n    }\n    if (b->closure_var_count != 0) {\n        bc_read_trace(s, \"closure vars {\\n\");\n        for(i = 0; i < b->closure_var_count; i++) {\n            JSClosureVar *cv = &b->closure_var[i];\n            int var_idx;\n            if (bc_get_atom(s, &cv->var_name))\n                goto fail;\n            if (bc_get_leb128_int(s, &var_idx))\n                goto fail;\n            cv->var_idx = var_idx;\n            if (bc_get_u16(s, &v16))\n                goto fail;\n            idx = 0;\n            cv->closure_type = bc_get_flags(v16, &idx, 3);\n            cv->is_const = bc_get_flags(v16, &idx, 1);\n            cv->is_lexical = bc_get_flags(v16, &idx, 1);\n            cv->var_kind = bc_get_flags(v16, &idx, 4);\n#ifdef DUMP_READ_OBJECT\n            bc_read_trace(s, \"name: \"); print_atom(s->ctx, cv->var_name); printf(\"\\n\");\n#endif\n        }\n        bc_read_trace(s, \"}\\n\");\n    }\n    {\n        bc_read_trace(s, \"bytecode {\\n\");\n        if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))\n            goto fail;\n        bc_read_trace(s, \"}\\n\");\n    }\n    if (b->has_debug) {\n        /* read optional debug information */\n        bc_read_trace(s, \"debug {\\n\");\n        if (bc_get_atom(s, &b->debug.filename))\n            goto fail;\n#ifdef DUMP_READ_OBJECT\n        bc_read_trace(s, \"filename: \"); print_atom(s->ctx, b->debug.filename); printf(\"\\n\");\n#endif\n        if (bc_get_leb128_int(s, &b->debug.pc2line_len))\n            goto fail;\n        if (b->debug.pc2line_len) {\n            b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);\n            if (!b->debug.pc2line_buf)\n                goto fail;\n            if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))\n                goto fail;\n        }\n        if (bc_get_leb128_int(s, &b->debug.source_len))\n            goto fail;\n        if (b->debug.source_len) {\n            bc_read_trace(s, \"source: %d bytes\\n\", b->source_len);\n            b->debug.source = js_mallocz(ctx, b->debug.source_len);\n            if (!b->debug.source)\n                goto fail;\n            if (bc_get_buf(s, (uint8_t *)b->debug.source, b->debug.source_len))\n                goto fail;\n        }\n        bc_read_trace(s, \"}\\n\");\n    }\n    if (b->cpool_count != 0) {\n        bc_read_trace(s, \"cpool {\\n\");\n        for(i = 0; i < b->cpool_count; i++) {\n            JSValue val;\n            val = JS_ReadObjectRec(s);\n            if (JS_IsException(val))\n                goto fail;\n            b->cpool[i] = val;\n        }\n        bc_read_trace(s, \"}\\n\");\n    }\n    b->realm = JS_DupContext(ctx);\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadModule(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSValue obj;\n    JSModuleDef *m = NULL;\n    JSAtom module_name;\n    int i;\n    uint8_t v8;\n\n    if (bc_get_atom(s, &module_name))\n        goto fail;\n#ifdef DUMP_READ_OBJECT\n    bc_read_trace(s, \"name: \"); print_atom(s->ctx, module_name); printf(\"\\n\");\n#endif\n    m = js_new_module_def(ctx, module_name);\n    if (!m)\n        goto fail;\n    obj = JS_NewModuleValue(ctx, m);\n    if (bc_get_leb128_int(s, &m->req_module_entries_count))\n        goto fail;\n    if (m->req_module_entries_count != 0) {\n        m->req_module_entries_size = m->req_module_entries_count;\n        m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);\n        if (!m->req_module_entries)\n            goto fail;\n        for(i = 0; i < m->req_module_entries_count; i++) {\n            JSReqModuleEntry *rme = &m->req_module_entries[i];\n            JSValue val;\n            if (bc_get_atom(s, &rme->module_name))\n                goto fail;\n            val = JS_ReadObjectRec(s);\n            if (JS_IsException(val))\n                goto fail;\n            rme->attributes = val;\n        }\n    }\n\n    if (bc_get_leb128_int(s, &m->export_entries_count))\n        goto fail;\n    if (m->export_entries_count != 0) {\n        m->export_entries_size = m->export_entries_count;\n        m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);\n        if (!m->export_entries)\n            goto fail;\n        for(i = 0; i < m->export_entries_count; i++) {\n            JSExportEntry *me = &m->export_entries[i];\n            if (bc_get_u8(s, &v8))\n                goto fail;\n            me->export_type = v8;\n            if (me->export_type == JS_EXPORT_TYPE_LOCAL) {\n                if (bc_get_leb128_int(s, &me->u.local.var_idx))\n                    goto fail;\n            } else {\n                if (bc_get_leb128_int(s, &me->u.req_module_idx))\n                    goto fail;\n                if (bc_get_atom(s, &me->local_name))\n                    goto fail;\n            }\n            if (bc_get_atom(s, &me->export_name))\n                goto fail;\n        }\n    }\n\n    if (bc_get_leb128_int(s, &m->star_export_entries_count))\n        goto fail;\n    if (m->star_export_entries_count != 0) {\n        m->star_export_entries_size = m->star_export_entries_count;\n        m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);\n        if (!m->star_export_entries)\n            goto fail;\n        for(i = 0; i < m->star_export_entries_count; i++) {\n            JSStarExportEntry *se = &m->star_export_entries[i];\n            if (bc_get_leb128_int(s, &se->req_module_idx))\n                goto fail;\n        }\n    }\n\n    if (bc_get_leb128_int(s, &m->import_entries_count))\n        goto fail;\n    if (m->import_entries_count != 0) {\n        m->import_entries_size = m->import_entries_count;\n        m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);\n        if (!m->import_entries)\n            goto fail;\n        for(i = 0; i < m->import_entries_count; i++) {\n            JSImportEntry *mi = &m->import_entries[i];\n            uint8_t v8;\n            if (bc_get_leb128_int(s, &mi->var_idx))\n                goto fail;\n            if (bc_get_u8(s, &v8))\n                goto fail;\n            mi->is_star = (v8 != 0);\n            if (bc_get_atom(s, &mi->import_name))\n                goto fail;\n            if (bc_get_leb128_int(s, &mi->req_module_idx))\n                goto fail;\n        }\n    }\n\n    if (bc_get_u8(s, &v8))\n        goto fail;\n    m->has_tla = (v8 != 0);\n\n    m->func_obj = JS_ReadObjectRec(s);\n    if (JS_IsException(m->func_obj))\n        goto fail;\n    return obj;\n fail:\n    if (m) {\n        JS_FreeValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));\n    }\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadObjectTag(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSValue obj;\n    uint32_t prop_count, i;\n    JSAtom atom;\n    JSValue val;\n    int ret;\n\n    obj = JS_NewObject(ctx);\n    if (BC_add_object_ref(s, obj))\n        goto fail;\n    if (bc_get_leb128(s, &prop_count))\n        goto fail;\n    for(i = 0; i < prop_count; i++) {\n        if (bc_get_atom(s, &atom))\n            goto fail;\n#ifdef DUMP_READ_OBJECT\n        bc_read_trace(s, \"propname: \"); print_atom(s->ctx, atom); printf(\"\\n\");\n#endif\n        val = JS_ReadObjectRec(s);\n        if (JS_IsException(val)) {\n            JS_FreeAtom(ctx, atom);\n            goto fail;\n        }\n        ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);\n        JS_FreeAtom(ctx, atom);\n        if (ret < 0)\n            goto fail;\n    }\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadArray(BCReaderState *s, int tag)\n{\n    JSContext *ctx = s->ctx;\n    JSValue obj;\n    uint32_t len, i;\n    JSValue val;\n    int ret, prop_flags;\n    BOOL is_template;\n\n    obj = JS_NewArray(ctx);\n    if (BC_add_object_ref(s, obj))\n        goto fail;\n    is_template = (tag == BC_TAG_TEMPLATE_OBJECT);\n    if (bc_get_leb128(s, &len))\n        goto fail;\n    for(i = 0; i < len; i++) {\n        val = JS_ReadObjectRec(s);\n        if (JS_IsException(val))\n            goto fail;\n        if (is_template)\n            prop_flags = JS_PROP_ENUMERABLE;\n        else\n            prop_flags = JS_PROP_C_W_E;\n        ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,\n                                           prop_flags);\n        if (ret < 0)\n            goto fail;\n    }\n    if (is_template) {\n        val = JS_ReadObjectRec(s);\n        if (JS_IsException(val))\n            goto fail;\n        if (!JS_IsUndefined(val)) {\n            ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);\n            if (ret < 0)\n                goto fail;\n        }\n        JS_PreventExtensions(ctx, obj);\n    }\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadTypedArray(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;\n    uint8_t array_tag;\n    JSValueConst args[3];\n    uint32_t offset, len, idx;\n\n    if (bc_get_u8(s, &array_tag))\n        return JS_EXCEPTION;\n    if (array_tag >= JS_TYPED_ARRAY_COUNT)\n        return JS_ThrowTypeError(ctx, \"invalid typed array\");\n    if (bc_get_leb128(s, &len))\n        return JS_EXCEPTION;\n    if (bc_get_leb128(s, &offset))\n        return JS_EXCEPTION;\n    /* XXX: this hack could be avoided if the typed array could be\n       created before the array buffer */\n    idx = s->objects_count;\n    if (BC_add_object_ref1(s, NULL))\n        goto fail;\n    array_buffer = JS_ReadObjectRec(s);\n    if (JS_IsException(array_buffer))\n        return JS_EXCEPTION;\n    if (!js_get_array_buffer(ctx, array_buffer)) {\n        JS_FreeValue(ctx, array_buffer);\n        return JS_EXCEPTION;\n    }\n    args[0] = array_buffer;\n    args[1] = JS_NewInt64(ctx, offset);\n    args[2] = JS_NewInt64(ctx, len);\n    obj = js_typed_array_constructor(ctx, JS_UNDEFINED,\n                                     3, args,\n                                     JS_CLASS_UINT8C_ARRAY + array_tag);\n    if (JS_IsException(obj))\n        goto fail;\n    if (s->allow_reference) {\n        s->objects[idx] = JS_VALUE_GET_OBJ(obj);\n    }\n    JS_FreeValue(ctx, array_buffer);\n    return obj;\n fail:\n    JS_FreeValue(ctx, array_buffer);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadArrayBuffer(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    uint32_t byte_length, max_byte_length;\n    uint64_t max_byte_length_u64, *pmax_byte_length = NULL;\n    JSValue obj;\n\n    if (bc_get_leb128(s, &byte_length))\n        return JS_EXCEPTION;\n    if (bc_get_leb128(s, &max_byte_length))\n        return JS_EXCEPTION;\n    if (max_byte_length < byte_length)\n        return JS_ThrowTypeError(ctx, \"invalid array buffer\");\n    if (max_byte_length != UINT32_MAX) {\n        max_byte_length_u64 = max_byte_length;\n        pmax_byte_length = &max_byte_length_u64;\n    }\n    if (unlikely(s->buf_end - s->ptr < byte_length)) {\n        bc_read_error_end(s);\n        return JS_EXCEPTION;\n    }\n    // makes a copy of the input\n    obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED,\n                                       byte_length, pmax_byte_length,\n                                       JS_CLASS_ARRAY_BUFFER,\n                                       (uint8_t*)s->ptr,\n                                       js_array_buffer_free, NULL,\n                                       /*alloc_flag*/TRUE);\n    if (JS_IsException(obj))\n        goto fail;\n    if (BC_add_object_ref(s, obj))\n        goto fail;\n    s->ptr += byte_length;\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    uint32_t byte_length, max_byte_length;\n    uint64_t max_byte_length_u64, *pmax_byte_length = NULL;\n    uint8_t *data_ptr;\n    JSValue obj;\n    uint64_t u64;\n\n    if (bc_get_leb128(s, &byte_length))\n        return JS_EXCEPTION;\n    if (bc_get_leb128(s, &max_byte_length))\n        return JS_EXCEPTION;\n    if (max_byte_length < byte_length)\n        return JS_ThrowTypeError(ctx, \"invalid array buffer\");\n    if (max_byte_length != UINT32_MAX) {\n        max_byte_length_u64 = max_byte_length;\n        pmax_byte_length = &max_byte_length_u64;\n    }\n    if (bc_get_u64(s, &u64))\n        return JS_EXCEPTION;\n    data_ptr = (uint8_t *)(uintptr_t)u64;\n    /* the SharedArrayBuffer is cloned */\n    obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED,\n                                       byte_length, pmax_byte_length,\n                                       JS_CLASS_SHARED_ARRAY_BUFFER,\n                                       data_ptr,\n                                       NULL, NULL, FALSE);\n    if (JS_IsException(obj))\n        goto fail;\n    if (BC_add_object_ref(s, obj))\n        goto fail;\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadDate(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSValue val, obj = JS_UNDEFINED;\n\n    val = JS_ReadObjectRec(s);\n    if (JS_IsException(val))\n        goto fail;\n    if (!JS_IsNumber(val)) {\n        JS_ThrowTypeError(ctx, \"Number tag expected for date\");\n        goto fail;\n    }\n    obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],\n                                 JS_CLASS_DATE);\n    if (JS_IsException(obj))\n        goto fail;\n    if (BC_add_object_ref(s, obj))\n        goto fail;\n    JS_SetObjectData(ctx, obj, val);\n    return obj;\n fail:\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadObjectValue(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSValue val, obj = JS_UNDEFINED;\n\n    val = JS_ReadObjectRec(s);\n    if (JS_IsException(val))\n        goto fail;\n    obj = JS_ToObject(ctx, val);\n    if (JS_IsException(obj))\n        goto fail;\n    if (BC_add_object_ref(s, obj))\n        goto fail;\n    JS_FreeValue(ctx, val);\n    return obj;\n fail:\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_ReadObjectRec(BCReaderState *s)\n{\n    JSContext *ctx = s->ctx;\n    uint8_t tag;\n    JSValue obj = JS_UNDEFINED;\n\n    if (js_check_stack_overflow(ctx->rt, 0))\n        return JS_ThrowStackOverflow(ctx);\n\n    if (bc_get_u8(s, &tag))\n        return JS_EXCEPTION;\n\n    bc_read_trace(s, \"%s {\\n\", bc_tag_str[tag]);\n\n    switch(tag) {\n    case BC_TAG_NULL:\n        obj = JS_NULL;\n        break;\n    case BC_TAG_UNDEFINED:\n        obj = JS_UNDEFINED;\n        break;\n    case BC_TAG_BOOL_FALSE:\n    case BC_TAG_BOOL_TRUE:\n        obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);\n        break;\n    case BC_TAG_INT32:\n        {\n            int32_t val;\n            if (bc_get_sleb128(s, &val))\n                return JS_EXCEPTION;\n            bc_read_trace(s, \"%d\\n\", val);\n            obj = JS_NewInt32(ctx, val);\n        }\n        break;\n    case BC_TAG_FLOAT64:\n        {\n            JSFloat64Union u;\n            if (bc_get_u64(s, &u.u64))\n                return JS_EXCEPTION;\n            bc_read_trace(s, \"%g\\n\", u.d);\n            obj = __JS_NewFloat64(ctx, u.d);\n        }\n        break;\n    case BC_TAG_STRING:\n        {\n            JSString *p;\n            p = JS_ReadString(s);\n            if (!p)\n                return JS_EXCEPTION;\n            obj = JS_MKPTR(JS_TAG_STRING, p);\n        }\n        break;\n    case BC_TAG_FUNCTION_BYTECODE:\n        if (!s->allow_bytecode)\n            goto invalid_tag;\n        obj = JS_ReadFunctionTag(s);\n        break;\n    case BC_TAG_MODULE:\n        if (!s->allow_bytecode)\n            goto invalid_tag;\n        obj = JS_ReadModule(s);\n        break;\n    case BC_TAG_OBJECT:\n        obj = JS_ReadObjectTag(s);\n        break;\n    case BC_TAG_ARRAY:\n    case BC_TAG_TEMPLATE_OBJECT:\n        obj = JS_ReadArray(s, tag);\n        break;\n    case BC_TAG_TYPED_ARRAY:\n        obj = JS_ReadTypedArray(s);\n        break;\n    case BC_TAG_ARRAY_BUFFER:\n        obj = JS_ReadArrayBuffer(s);\n        break;\n    case BC_TAG_SHARED_ARRAY_BUFFER:\n        if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)\n            goto invalid_tag;\n        obj = JS_ReadSharedArrayBuffer(s);\n        break;\n    case BC_TAG_DATE:\n        obj = JS_ReadDate(s);\n        break;\n    case BC_TAG_OBJECT_VALUE:\n        obj = JS_ReadObjectValue(s);\n        break;\n    case BC_TAG_BIG_INT:\n        obj = JS_ReadBigInt(s);\n        break;\n    case BC_TAG_OBJECT_REFERENCE:\n        {\n            uint32_t val;\n            if (!s->allow_reference)\n                return JS_ThrowSyntaxError(ctx, \"object references are not allowed\");\n            if (bc_get_leb128(s, &val))\n                return JS_EXCEPTION;\n            bc_read_trace(s, \"%u\\n\", val);\n            if (val >= s->objects_count) {\n                return JS_ThrowSyntaxError(ctx, \"invalid object reference (%u >= %u)\",\n                                           val, s->objects_count);\n            }\n            obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));\n        }\n        break;\n    default:\n    invalid_tag:\n        return JS_ThrowSyntaxError(ctx, \"invalid tag (tag=%d pos=%u)\",\n                                   tag, (unsigned int)(s->ptr - s->buf_start));\n    }\n    bc_read_trace(s, \"}\\n\");\n    return obj;\n}\n\nstatic int JS_ReadObjectAtoms(BCReaderState *s)\n{\n    uint8_t v8;\n    JSString *p;\n    int i;\n    JSAtom atom;\n\n    if (bc_get_u8(s, &v8))\n        return -1;\n    if (v8 != BC_VERSION) {\n        JS_ThrowSyntaxError(s->ctx, \"invalid version (%d expected=%d)\",\n                            v8, BC_VERSION);\n        return -1;\n    }\n    if (bc_get_leb128(s, &s->idx_to_atom_count))\n        return -1;\n\n    bc_read_trace(s, \"%d atom indexes {\\n\", s->idx_to_atom_count);\n\n    if (s->idx_to_atom_count != 0) {\n        s->idx_to_atom = js_mallocz(s->ctx, s->idx_to_atom_count *\n                                    sizeof(s->idx_to_atom[0]));\n        if (!s->idx_to_atom)\n            return s->error_state = -1;\n    }\n    for(i = 0; i < s->idx_to_atom_count; i++) {\n        p = JS_ReadString(s);\n        if (!p)\n            return -1;\n        atom = JS_NewAtomStr(s->ctx, p);\n        if (atom == JS_ATOM_NULL)\n            return s->error_state = -1;\n        s->idx_to_atom[i] = atom;\n        if (s->is_rom_data && (atom != (i + s->first_atom)))\n            s->is_rom_data = FALSE; /* atoms must be relocated */\n    }\n    bc_read_trace(s, \"}\\n\");\n    return 0;\n}\n\nstatic void bc_reader_free(BCReaderState *s)\n{\n    int i;\n    if (s->idx_to_atom) {\n        for(i = 0; i < s->idx_to_atom_count; i++) {\n            JS_FreeAtom(s->ctx, s->idx_to_atom[i]);\n        }\n        js_free(s->ctx, s->idx_to_atom);\n    }\n    js_free(s->ctx, s->objects);\n}\n\nJSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,\n                       int flags)\n{\n    BCReaderState ss, *s = &ss;\n    JSValue obj;\n\n    ctx->binary_object_count += 1;\n    ctx->binary_object_size += buf_len;\n\n    memset(s, 0, sizeof(*s));\n    s->ctx = ctx;\n    s->buf_start = buf;\n    s->buf_end = buf + buf_len;\n    s->ptr = buf;\n    s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);\n    s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);\n    s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);\n    s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);\n    if (s->allow_bytecode)\n        s->first_atom = JS_ATOM_END;\n    else\n        s->first_atom = 1;\n    if (JS_ReadObjectAtoms(s)) {\n        obj = JS_EXCEPTION;\n    } else {\n        obj = JS_ReadObjectRec(s);\n    }\n    bc_reader_free(s);\n    return obj;\n}\n\n/*******************************************************************/\n/* runtime functions & objects */\n\nstatic JSValue js_string_constructor(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv);\nstatic JSValue js_boolean_constructor(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv);\nstatic JSValue js_number_constructor(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv);\n\nstatic int check_function(JSContext *ctx, JSValueConst obj)\n{\n    if (likely(JS_IsFunction(ctx, obj)))\n        return 0;\n    JS_ThrowTypeError(ctx, \"not a function\");\n    return -1;\n}\n\nstatic int check_exception_free(JSContext *ctx, JSValue obj)\n{\n    JS_FreeValue(ctx, obj);\n    return JS_IsException(obj);\n}\n\nstatic JSAtom find_atom(JSContext *ctx, const char *name)\n{\n    JSAtom atom;\n    int len;\n\n    if (*name == '[') {\n        name++;\n        len = strlen(name) - 1;\n        /* We assume 8 bit non null strings, which is the case for these\n           symbols */\n        for(atom = JS_ATOM_Symbol_toPrimitive; atom < JS_ATOM_END; atom++) {\n            JSAtomStruct *p = ctx->rt->atom_array[atom];\n            JSString *str = p;\n            if (str->len == len && !memcmp(str->u.str8, name, len))\n                return JS_DupAtom(ctx, atom);\n        }\n        abort();\n    } else {\n        atom = JS_NewAtom(ctx, name);\n    }\n    return atom;\n}\n\nstatic JSValue JS_NewObjectProtoList(JSContext *ctx, JSValueConst proto,\n                                     const JSCFunctionListEntry *fields, int n_fields)\n{\n    JSValue obj;\n    obj = JS_NewObjectProtoClassAlloc(ctx, proto, JS_CLASS_OBJECT, n_fields);\n    if (JS_IsException(obj))\n        return obj;\n    if (JS_SetPropertyFunctionList(ctx, obj, fields, n_fields)) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    return obj;\n}\n\nstatic JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,\n                                               JSAtom atom, void *opaque)\n{\n    const JSCFunctionListEntry *e = opaque;\n    JSValue val, proto;\n\n    switch(e->def_type) {\n    case JS_DEF_CFUNC:\n        val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,\n                               e->name, e->u.func.length, e->u.func.cproto, e->magic);\n        break;\n    case JS_DEF_PROP_STRING:\n        val = JS_NewAtomString(ctx, e->u.str);\n        break;\n    case JS_DEF_OBJECT:\n        /* XXX: could add a flag */\n        if (atom == JS_ATOM_Symbol_unscopables)\n            proto = JS_NULL;\n        else\n            proto = ctx->class_proto[JS_CLASS_OBJECT];\n        val = JS_NewObjectProtoList(ctx, proto,\n                                    e->u.prop_list.tab, e->u.prop_list.len);\n        break;\n    default:\n        abort();\n    }\n    return val;\n}\n\nstatic int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,\n                                          JSAtom atom,\n                                          const JSCFunctionListEntry *e)\n{\n    JSValue val;\n    int prop_flags = e->prop_flags;\n\n    switch(e->def_type) {\n    case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */\n        {\n            JSAtom atom1 = find_atom(ctx, e->u.alias.name);\n            switch (e->u.alias.base) {\n            case -1:\n                val = JS_GetProperty(ctx, obj, atom1);\n                break;\n            case 0:\n                val = JS_GetProperty(ctx, ctx->global_obj, atom1);\n                break;\n            case 1:\n                val = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], atom1);\n                break;\n            default:\n                abort();\n            }\n            JS_FreeAtom(ctx, atom1);\n            if (JS_IsException(val))\n                return -1;\n            if (atom == JS_ATOM_Symbol_toPrimitive) {\n                /* Symbol.toPrimitive functions are not writable */\n                prop_flags = JS_PROP_CONFIGURABLE;\n            } else if (atom == JS_ATOM_Symbol_hasInstance) {\n                /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */\n                prop_flags = 0;\n            }\n        }\n        break;\n    case JS_DEF_CFUNC:\n        if (atom == JS_ATOM_Symbol_toPrimitive) {\n            /* Symbol.toPrimitive functions are not writable */\n            prop_flags = JS_PROP_CONFIGURABLE;\n        } else if (atom == JS_ATOM_Symbol_hasInstance) {\n            /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */\n            prop_flags = 0;\n        }\n        if (JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,\n                                      (void *)e, prop_flags) < 0)\n            return -1;\n        return 0;\n    case JS_DEF_CGETSET: /* XXX: use autoinit again ? */\n    case JS_DEF_CGETSET_MAGIC:\n        {\n            JSValue getter, setter;\n            char buf[64];\n\n            getter = JS_UNDEFINED;\n            if (e->u.getset.get.generic) {\n                snprintf(buf, sizeof(buf), \"get %s\", e->name);\n                getter = JS_NewCFunction2(ctx, e->u.getset.get.generic,\n                                          buf, 0, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_getter_magic : JS_CFUNC_getter,\n                                          e->magic);\n                if (JS_IsException(getter))\n                    return -1;\n            }\n            setter = JS_UNDEFINED;\n            if (e->u.getset.set.generic) {\n                snprintf(buf, sizeof(buf), \"set %s\", e->name);\n                setter = JS_NewCFunction2(ctx, e->u.getset.set.generic,\n                                          buf, 1, e->def_type == JS_DEF_CGETSET_MAGIC ? JS_CFUNC_setter_magic : JS_CFUNC_setter,\n                                          e->magic);\n                if (JS_IsException(setter)) {\n                    JS_FreeValue(ctx, getter);\n                    return -1;\n                }\n            }\n            if (JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags) < 0)\n                return -1;\n            return 0;\n        }\n        break;\n    case JS_DEF_PROP_INT32:\n        val = JS_NewInt32(ctx, e->u.i32);\n        break;\n    case JS_DEF_PROP_INT64:\n        val = JS_NewInt64(ctx, e->u.i64);\n        break;\n    case JS_DEF_PROP_DOUBLE:\n        val = __JS_NewFloat64(ctx, e->u.f64);\n        break;\n    case JS_DEF_PROP_UNDEFINED:\n        val = JS_UNDEFINED;\n        break;\n    case JS_DEF_PROP_ATOM:\n        val = JS_AtomToValue(ctx, e->u.i32);\n        break;\n    case JS_DEF_PROP_BOOL:\n        val = JS_NewBool(ctx, e->u.i32);\n        break;\n    case JS_DEF_PROP_STRING:\n    case JS_DEF_OBJECT:\n        if (JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,\n                                      (void *)e, prop_flags) < 0)\n            return -1;\n        return 0;\n    default:\n        abort();\n    }\n    if (JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags) < 0)\n        return -1;\n    return 0;\n}\n\nint JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,\n                               const JSCFunctionListEntry *tab, int len)\n{\n    int i, ret;\n\n    for (i = 0; i < len; i++) {\n        const JSCFunctionListEntry *e = &tab[i];\n        JSAtom atom = find_atom(ctx, e->name);\n        if (atom == JS_ATOM_NULL)\n            return -1;\n        ret = JS_InstantiateFunctionListItem(ctx, obj, atom, e);\n        JS_FreeAtom(ctx, atom);\n        if (ret)\n            return -1;\n    }\n    return 0;\n}\n\nint JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,\n                           const JSCFunctionListEntry *tab, int len)\n{\n    int i;\n    for(i = 0; i < len; i++) {\n        if (JS_AddModuleExport(ctx, m, tab[i].name))\n            return -1;\n    }\n    return 0;\n}\n\nint JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,\n                           const JSCFunctionListEntry *tab, int len)\n{\n    int i;\n    JSValue val;\n\n    for(i = 0; i < len; i++) {\n        const JSCFunctionListEntry *e = &tab[i];\n        switch(e->def_type) {\n        case JS_DEF_CFUNC:\n            val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,\n                                   e->name, e->u.func.length, e->u.func.cproto, e->magic);\n            break;\n        case JS_DEF_PROP_STRING:\n            val = JS_NewString(ctx, e->u.str);\n            break;\n        case JS_DEF_PROP_INT32:\n            val = JS_NewInt32(ctx, e->u.i32);\n            break;\n        case JS_DEF_PROP_INT64:\n            val = JS_NewInt64(ctx, e->u.i64);\n            break;\n        case JS_DEF_PROP_DOUBLE:\n            val = __JS_NewFloat64(ctx, e->u.f64);\n            break;\n        case JS_DEF_OBJECT:\n            val = JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_OBJECT],\n                                        e->u.prop_list.tab, e->u.prop_list.len);\n            break;\n        default:\n            abort();\n        }\n        if (JS_SetModuleExport(ctx, m, e->name, val))\n            return -1;\n    }\n    return 0;\n}\n\n/* Note: 'func_obj' is not necessarily a constructor */\nstatic int JS_SetConstructor2(JSContext *ctx,\n                              JSValueConst func_obj,\n                              JSValueConst proto,\n                              int proto_flags, int ctor_flags)\n{\n    if (JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype,\n                               JS_DupValue(ctx, proto), proto_flags) < 0)\n        return -1;\n    if (JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor,\n                               JS_DupValue(ctx, func_obj),\n                               ctor_flags) < 0)\n        return -1;\n    set_cycle_flag(ctx, func_obj);\n    set_cycle_flag(ctx, proto);\n    return 0;\n}\n\n/* return 0 if OK, -1 if exception */\nint JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,\n                      JSValueConst proto)\n{\n    return JS_SetConstructor2(ctx, func_obj, proto,\n                              0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n}\n\n#define JS_NEW_CTOR_NO_GLOBAL   (1 << 0) /* don't create a global binding */\n#define JS_NEW_CTOR_PROTO_CLASS (1 << 1) /* the prototype class is 'class_id' instead of JS_CLASS_OBJECT */\n#define JS_NEW_CTOR_PROTO_EXIST (1 << 2) /* the prototype is already defined */\n#define JS_NEW_CTOR_READONLY    (1 << 3) /* read-only constructor field */\n\n/* Return the constructor and. Define it as a global variable unless\n   JS_NEW_CTOR_NO_GLOBAL is set. The new class inherit from\n   parent_ctor if it is not JS_UNDEFINED. if class_id is != -1,\n   class_proto[class_id] is set. */\nstatic JSValue JS_NewCConstructor(JSContext *ctx, int class_id, const char *name,\n                                  JSCFunction *func, int length, JSCFunctionEnum cproto, int magic,\n                                  JSValueConst parent_ctor,\n                                  const JSCFunctionListEntry *ctor_fields, int n_ctor_fields,\n                                  const JSCFunctionListEntry *proto_fields, int n_proto_fields,\n                                  int flags)\n{\n    JSValue ctor = JS_UNDEFINED, proto, parent_proto;\n    int proto_class_id, proto_flags, ctor_flags;\n\n    proto_flags = 0;\n    if (flags & JS_NEW_CTOR_READONLY) {\n        ctor_flags = JS_PROP_CONFIGURABLE;\n    } else {\n        ctor_flags = JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE;\n    }\n    \n    if (JS_IsUndefined(parent_ctor)) {\n        parent_proto = JS_DupValue(ctx, ctx->class_proto[JS_CLASS_OBJECT]);\n        parent_ctor = ctx->function_proto;\n    } else {\n        parent_proto = JS_GetProperty(ctx, parent_ctor, JS_ATOM_prototype);\n        if (JS_IsException(parent_proto))\n            return JS_EXCEPTION;\n    }\n    \n    if (flags & JS_NEW_CTOR_PROTO_EXIST) {\n        proto = JS_DupValue(ctx, ctx->class_proto[class_id]);\n    } else {\n        if (flags & JS_NEW_CTOR_PROTO_CLASS)\n            proto_class_id = class_id;\n        else\n            proto_class_id = JS_CLASS_OBJECT;\n        /* one additional field: constructor */\n        proto = JS_NewObjectProtoClassAlloc(ctx, parent_proto, proto_class_id,\n                                            n_proto_fields + 1);\n        if (JS_IsException(proto))\n            goto fail;\n        if (class_id >= 0)\n            ctx->class_proto[class_id] = JS_DupValue(ctx, proto);\n    }\n    if (JS_SetPropertyFunctionList(ctx, proto, proto_fields, n_proto_fields))\n        goto fail;\n\n    /* additional fields: name, length, prototype */\n    ctor = JS_NewCFunction3(ctx, func, name, length, cproto, magic, parent_ctor,\n                            n_ctor_fields + 3);\n    if (JS_IsException(ctor))\n        goto fail;\n    if (JS_SetPropertyFunctionList(ctx, ctor, ctor_fields, n_ctor_fields))\n        goto fail;\n    if (!(flags & JS_NEW_CTOR_NO_GLOBAL)) {\n        if (JS_DefinePropertyValueStr(ctx, ctx->global_obj, name,\n                                      JS_DupValue(ctx, ctor),\n                                      JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)\n            goto fail;\n    }\n    JS_SetConstructor2(ctx, ctor, proto, proto_flags, ctor_flags);\n\n    JS_FreeValue(ctx, proto);\n    JS_FreeValue(ctx, parent_proto);\n    return ctor;\n fail:\n    JS_FreeValue(ctx, proto);\n    JS_FreeValue(ctx, parent_proto);\n    JS_FreeValue(ctx, ctor);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_global_eval(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    return JS_EvalObject(ctx, ctx->global_obj, argv[0], JS_EVAL_TYPE_INDIRECT, -1);\n}\n\nstatic JSValue js_global_isNaN(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    double d;\n\n    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, isnan(d));\n}\n\nstatic JSValue js_global_isFinite(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    double d;\n    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, isfinite(d));\n}\n\n/* Object class */\n\nstatic JSValue JS_ToObject(JSContext *ctx, JSValueConst val)\n{\n    int tag = JS_VALUE_GET_NORM_TAG(val);\n    JSValue obj;\n\n    switch(tag) {\n    default:\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n        return JS_ThrowTypeError(ctx, \"cannot convert to object\");\n    case JS_TAG_OBJECT:\n    case JS_TAG_EXCEPTION:\n        return JS_DupValue(ctx, val);\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);\n        goto set_value;\n    case JS_TAG_INT:\n    case JS_TAG_FLOAT64:\n        obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);\n        goto set_value;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        /* XXX: should call the string constructor */\n        {\n            JSValue str;\n            str = JS_ToString(ctx, val); /* ensure that we never store a rope */\n            if (JS_IsException(str))\n                return JS_EXCEPTION;\n            obj = JS_NewObjectClass(ctx, JS_CLASS_STRING);\n            if (!JS_IsException(obj)) {\n                JS_DefinePropertyValue(ctx, obj, JS_ATOM_length,\n                                       JS_NewInt32(ctx, JS_VALUE_GET_STRING(str)->len), 0);\n                JS_SetObjectData(ctx, obj, JS_DupValue(ctx, str));\n            }\n            JS_FreeValue(ctx, str);\n            return obj;\n        }\n    case JS_TAG_BOOL:\n        obj = JS_NewObjectClass(ctx, JS_CLASS_BOOLEAN);\n        goto set_value;\n    case JS_TAG_SYMBOL:\n        obj = JS_NewObjectClass(ctx, JS_CLASS_SYMBOL);\n    set_value:\n        if (!JS_IsException(obj))\n            JS_SetObjectData(ctx, obj, JS_DupValue(ctx, val));\n        return obj;\n    }\n}\n\nstatic JSValue JS_ToObjectFree(JSContext *ctx, JSValue val)\n{\n    JSValue obj = JS_ToObject(ctx, val);\n    JS_FreeValue(ctx, val);\n    return obj;\n}\n\nstatic int js_obj_to_desc(JSContext *ctx, JSPropertyDescriptor *d,\n                          JSValueConst desc)\n{\n    JSValue val, getter, setter;\n    int flags;\n\n    if (!JS_IsObject(desc)) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        return -1;\n    }\n    flags = 0;\n    val = JS_UNDEFINED;\n    getter = JS_UNDEFINED;\n    setter = JS_UNDEFINED;\n    if (JS_HasProperty(ctx, desc, JS_ATOM_enumerable)) {\n        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_enumerable);\n        if (JS_IsException(prop))\n            goto fail;\n        flags |= JS_PROP_HAS_ENUMERABLE;\n        if (JS_ToBoolFree(ctx, prop))\n            flags |= JS_PROP_ENUMERABLE;\n    }\n    if (JS_HasProperty(ctx, desc, JS_ATOM_configurable)) {\n        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_configurable);\n        if (JS_IsException(prop))\n            goto fail;\n        flags |= JS_PROP_HAS_CONFIGURABLE;\n        if (JS_ToBoolFree(ctx, prop))\n            flags |= JS_PROP_CONFIGURABLE;\n    }\n    if (JS_HasProperty(ctx, desc, JS_ATOM_value)) {\n        flags |= JS_PROP_HAS_VALUE;\n        val = JS_GetProperty(ctx, desc, JS_ATOM_value);\n        if (JS_IsException(val))\n            goto fail;\n    }\n    if (JS_HasProperty(ctx, desc, JS_ATOM_writable)) {\n        JSValue prop = JS_GetProperty(ctx, desc, JS_ATOM_writable);\n        if (JS_IsException(prop))\n            goto fail;\n        flags |= JS_PROP_HAS_WRITABLE;\n        if (JS_ToBoolFree(ctx, prop))\n            flags |= JS_PROP_WRITABLE;\n    }\n    if (JS_HasProperty(ctx, desc, JS_ATOM_get)) {\n        flags |= JS_PROP_HAS_GET;\n        getter = JS_GetProperty(ctx, desc, JS_ATOM_get);\n        if (JS_IsException(getter) ||\n            !(JS_IsUndefined(getter) || JS_IsFunction(ctx, getter))) {\n            JS_ThrowTypeError(ctx, \"invalid getter\");\n            goto fail;\n        }\n    }\n    if (JS_HasProperty(ctx, desc, JS_ATOM_set)) {\n        flags |= JS_PROP_HAS_SET;\n        setter = JS_GetProperty(ctx, desc, JS_ATOM_set);\n        if (JS_IsException(setter) ||\n            !(JS_IsUndefined(setter) || JS_IsFunction(ctx, setter))) {\n            JS_ThrowTypeError(ctx, \"invalid setter\");\n            goto fail;\n        }\n    }\n    if ((flags & (JS_PROP_HAS_SET | JS_PROP_HAS_GET)) &&\n        (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {\n        JS_ThrowTypeError(ctx, \"cannot have setter/getter and value or writable\");\n        goto fail;\n    }\n    d->flags = flags;\n    d->value = val;\n    d->getter = getter;\n    d->setter = setter;\n    return 0;\n fail:\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, getter);\n    JS_FreeValue(ctx, setter);\n    return -1;\n}\n\nstatic __exception int JS_DefinePropertyDesc(JSContext *ctx, JSValueConst obj,\n                                             JSAtom prop, JSValueConst desc,\n                                             int flags)\n{\n    JSPropertyDescriptor d;\n    int ret;\n\n    if (js_obj_to_desc(ctx, &d, desc) < 0)\n        return -1;\n\n    ret = JS_DefineProperty(ctx, obj, prop,\n                            d.value, d.getter, d.setter, d.flags | flags);\n    js_free_desc(ctx, &d);\n    return ret;\n}\n\nstatic __exception int JS_ObjectDefineProperties(JSContext *ctx,\n                                                 JSValueConst obj,\n                                                 JSValueConst properties)\n{\n    JSValue props, desc;\n    JSObject *p;\n    JSPropertyEnum *atoms;\n    uint32_t len, i;\n    int ret = -1;\n\n    if (!JS_IsObject(obj)) {\n        JS_ThrowTypeErrorNotAnObject(ctx);\n        return -1;\n    }\n    desc = JS_UNDEFINED;\n    props = JS_ToObject(ctx, properties);\n    if (JS_IsException(props))\n        return -1;\n    p = JS_VALUE_GET_OBJ(props);\n    /* XXX: not done in the same order as the spec */\n    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)\n        goto exception;\n    for(i = 0; i < len; i++) {\n        JS_FreeValue(ctx, desc);\n        desc = JS_GetProperty(ctx, props, atoms[i].atom);\n        if (JS_IsException(desc))\n            goto exception;\n        if (JS_DefinePropertyDesc(ctx, obj, atoms[i].atom, desc, JS_PROP_THROW) < 0)\n            goto exception;\n    }\n    ret = 0;\n\nexception:\n    JS_FreePropertyEnum(ctx, atoms, len);\n    JS_FreeValue(ctx, props);\n    JS_FreeValue(ctx, desc);\n    return ret;\n}\n\nstatic JSValue js_object_constructor(JSContext *ctx, JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue ret;\n    if (!JS_IsUndefined(new_target) &&\n        JS_VALUE_GET_OBJ(new_target) !=\n        JS_VALUE_GET_OBJ(JS_GetActiveFunction(ctx))) {\n        ret = js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);\n    } else {\n        int tag = JS_VALUE_GET_NORM_TAG(argv[0]);\n        switch(tag) {\n        case JS_TAG_NULL:\n        case JS_TAG_UNDEFINED:\n            ret = JS_NewObject(ctx);\n            break;\n        default:\n            ret = JS_ToObject(ctx, argv[0]);\n            break;\n        }\n    }\n    return ret;\n}\n\nstatic JSValue js_object_create(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValueConst proto, props;\n    JSValue obj;\n\n    proto = argv[0];\n    if (!JS_IsObject(proto) && !JS_IsNull(proto))\n        return JS_ThrowTypeError(ctx, \"not a prototype\");\n    obj = JS_NewObjectProto(ctx, proto);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    props = argv[1];\n    if (!JS_IsUndefined(props)) {\n        if (JS_ObjectDefineProperties(ctx, obj, props)) {\n            JS_FreeValue(ctx, obj);\n            return JS_EXCEPTION;\n        }\n    }\n    return obj;\n}\n\nstatic JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv, int magic)\n{\n    JSValueConst val;\n\n    val = argv[0];\n    if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT) {\n        /* ES6 feature non compatible with ES5.1: primitive types are\n           accepted */\n        if (magic || JS_VALUE_GET_TAG(val) == JS_TAG_NULL ||\n            JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)\n            return JS_ThrowTypeErrorNotAnObject(ctx);\n    }\n    return JS_GetPrototype(ctx, val);\n}\n\nstatic JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv)\n{\n    JSValueConst obj;\n    obj = argv[0];\n    if (JS_SetPrototypeInternal(ctx, obj, argv[1], TRUE) < 0)\n        return JS_EXCEPTION;\n    return JS_DupValue(ctx, obj);\n}\n\n/* magic = 1 if called as Reflect.defineProperty */\nstatic JSValue js_object_defineProperty(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv, int magic)\n{\n    JSValueConst obj, prop, desc;\n    int ret, flags;\n    JSAtom atom;\n\n    obj = argv[0];\n    prop = argv[1];\n    desc = argv[2];\n\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    atom = JS_ValueToAtom(ctx, prop);\n    if (unlikely(atom == JS_ATOM_NULL))\n        return JS_EXCEPTION;\n    flags = 0;\n    if (!magic)\n        flags |= JS_PROP_THROW;\n    ret = JS_DefinePropertyDesc(ctx, obj, atom, desc, flags);\n    JS_FreeAtom(ctx, atom);\n    if (ret < 0) {\n        return JS_EXCEPTION;\n    } else if (magic) {\n        return JS_NewBool(ctx, ret);\n    } else {\n        return JS_DupValue(ctx, obj);\n    }\n}\n\nstatic JSValue js_object_defineProperties(JSContext *ctx, JSValueConst this_val,\n                                          int argc, JSValueConst *argv)\n{\n    // defineProperties(obj, properties)\n    JSValueConst obj = argv[0];\n\n    if (JS_ObjectDefineProperties(ctx, obj, argv[1]))\n        return JS_EXCEPTION;\n    else\n        return JS_DupValue(ctx, obj);\n}\n\n/* magic = 1 if called as __defineSetter__ */\nstatic JSValue js_object___defineGetter__(JSContext *ctx, JSValueConst this_val,\n                                          int argc, JSValueConst *argv, int magic)\n{\n    JSValue obj;\n    JSValueConst prop, value, get, set;\n    int ret, flags;\n    JSAtom atom;\n\n    prop = argv[0];\n    value = argv[1];\n\n    obj = JS_ToObject(ctx, this_val);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n\n    if (check_function(ctx, value)) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    atom = JS_ValueToAtom(ctx, prop);\n    if (unlikely(atom == JS_ATOM_NULL)) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    flags = JS_PROP_THROW |\n        JS_PROP_HAS_ENUMERABLE | JS_PROP_ENUMERABLE |\n        JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE;\n    if (magic) {\n        get = JS_UNDEFINED;\n        set = value;\n        flags |= JS_PROP_HAS_SET;\n    } else {\n        get = value;\n        set = JS_UNDEFINED;\n        flags |= JS_PROP_HAS_GET;\n    }\n    ret = JS_DefineProperty(ctx, obj, atom, JS_UNDEFINED, get, set, flags);\n    JS_FreeValue(ctx, obj);\n    JS_FreeAtom(ctx, atom);\n    if (ret < 0) {\n        return JS_EXCEPTION;\n    } else {\n        return JS_UNDEFINED;\n    }\n}\n\nstatic JSValue js_object_getOwnPropertyDescriptor(JSContext *ctx, JSValueConst this_val,\n                                                  int argc, JSValueConst *argv, int magic)\n{\n    JSValueConst prop;\n    JSAtom atom;\n    JSValue ret, obj;\n    JSPropertyDescriptor desc;\n    int res, flags;\n\n    if (magic) {\n        /* Reflect.getOwnPropertyDescriptor case */\n        if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)\n            return JS_ThrowTypeErrorNotAnObject(ctx);\n        obj = JS_DupValue(ctx, argv[0]);\n    } else {\n        obj = JS_ToObject(ctx, argv[0]);\n        if (JS_IsException(obj))\n            return obj;\n    }\n    prop = argv[1];\n    atom = JS_ValueToAtom(ctx, prop);\n    if (unlikely(atom == JS_ATOM_NULL))\n        goto exception;\n    ret = JS_UNDEFINED;\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), atom);\n        if (res < 0)\n            goto exception;\n        if (res) {\n            ret = JS_NewObject(ctx);\n            if (JS_IsException(ret))\n                goto exception1;\n            flags = JS_PROP_C_W_E | JS_PROP_THROW;\n            if (desc.flags & JS_PROP_GETSET) {\n                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, desc.getter), flags) < 0\n                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, desc.setter), flags) < 0)\n                    goto exception1;\n            } else {\n                if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, desc.value), flags) < 0\n                ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,\n                                           JS_NewBool(ctx, desc.flags & JS_PROP_WRITABLE), flags) < 0)\n                    goto exception1;\n            }\n            if (JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,\n                                       JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE), flags) < 0\n            ||  JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,\n                                       JS_NewBool(ctx, desc.flags & JS_PROP_CONFIGURABLE), flags) < 0)\n                goto exception1;\n            js_free_desc(ctx, &desc);\n        }\n    }\n    JS_FreeAtom(ctx, atom);\n    JS_FreeValue(ctx, obj);\n    return ret;\n\nexception1:\n    js_free_desc(ctx, &desc);\n    JS_FreeValue(ctx, ret);\nexception:\n    JS_FreeAtom(ctx, atom);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst this_val,\n                                                   int argc, JSValueConst *argv)\n{\n    //getOwnPropertyDescriptors(obj)\n    JSValue obj, r;\n    JSObject *p;\n    JSPropertyEnum *props;\n    uint32_t len, i;\n\n    r = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, argv[0]);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n\n    p = JS_VALUE_GET_OBJ(obj);\n    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p,\n                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))\n        goto exception;\n    r = JS_NewObject(ctx);\n    if (JS_IsException(r))\n        goto exception;\n    for(i = 0; i < len; i++) {\n        JSValue atomValue, desc;\n        JSValueConst args[2];\n\n        atomValue = JS_AtomToValue(ctx, props[i].atom);\n        if (JS_IsException(atomValue))\n            goto exception;\n        args[0] = obj;\n        args[1] = atomValue;\n        desc = js_object_getOwnPropertyDescriptor(ctx, JS_UNDEFINED, 2, args, 0);\n        JS_FreeValue(ctx, atomValue);\n        if (JS_IsException(desc))\n            goto exception;\n        if (!JS_IsUndefined(desc)) {\n            if (JS_DefinePropertyValue(ctx, r, props[i].atom, desc,\n                                       JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception;\n        }\n    }\n    JS_FreePropertyEnum(ctx, props, len);\n    JS_FreeValue(ctx, obj);\n    return r;\n\nexception:\n    JS_FreePropertyEnum(ctx, props, len);\n    JS_FreeValue(ctx, obj);\n    JS_FreeValue(ctx, r);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_GetOwnPropertyNames2(JSContext *ctx, JSValueConst obj1,\n                                       int flags, int kind)\n{\n    JSValue obj, r, val, key, value;\n    JSObject *p;\n    JSPropertyEnum *atoms;\n    uint32_t len, i, j;\n\n    r = JS_UNDEFINED;\n    val = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, obj1);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, flags & ~JS_GPN_ENUM_ONLY))\n        goto exception;\n    r = JS_NewArray(ctx);\n    if (JS_IsException(r))\n        goto exception;\n    for(j = i = 0; i < len; i++) {\n        JSAtom atom = atoms[i].atom;\n        if (flags & JS_GPN_ENUM_ONLY) {\n            JSPropertyDescriptor desc;\n            int res;\n\n            /* Check if property is still enumerable */\n            res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);\n            if (res < 0)\n                goto exception;\n            if (!res)\n                continue;\n            js_free_desc(ctx, &desc);\n            if (!(desc.flags & JS_PROP_ENUMERABLE))\n                continue;\n        }\n        switch(kind) {\n        default:\n        case JS_ITERATOR_KIND_KEY:\n            val = JS_AtomToValue(ctx, atom);\n            if (JS_IsException(val))\n                goto exception;\n            break;\n        case JS_ITERATOR_KIND_VALUE:\n            val = JS_GetProperty(ctx, obj, atom);\n            if (JS_IsException(val))\n                goto exception;\n            break;\n        case JS_ITERATOR_KIND_KEY_AND_VALUE:\n            val = JS_NewArray(ctx);\n            if (JS_IsException(val))\n                goto exception;\n            key = JS_AtomToValue(ctx, atom);\n            if (JS_IsException(key))\n                goto exception1;\n            if (JS_CreateDataPropertyUint32(ctx, val, 0, key, JS_PROP_THROW) < 0)\n                goto exception1;\n            value = JS_GetProperty(ctx, obj, atom);\n            if (JS_IsException(value))\n                goto exception1;\n            if (JS_CreateDataPropertyUint32(ctx, val, 1, value, JS_PROP_THROW) < 0)\n                goto exception1;\n            break;\n        }\n        if (JS_CreateDataPropertyUint32(ctx, r, j++, val, 0) < 0)\n            goto exception;\n    }\n    goto done;\n\nexception1:\n    JS_FreeValue(ctx, val);\nexception:\n    JS_FreeValue(ctx, r);\n    r = JS_EXCEPTION;\ndone:\n    JS_FreePropertyEnum(ctx, atoms, len);\n    JS_FreeValue(ctx, obj);\n    return r;\n}\n\nstatic JSValue js_object_getOwnPropertyNames(JSContext *ctx, JSValueConst this_val,\n                                             int argc, JSValueConst *argv)\n{\n    return JS_GetOwnPropertyNames2(ctx, argv[0],\n                                   JS_GPN_STRING_MASK, JS_ITERATOR_KIND_KEY);\n}\n\nstatic JSValue js_object_getOwnPropertySymbols(JSContext *ctx, JSValueConst this_val,\n                                             int argc, JSValueConst *argv)\n{\n    return JS_GetOwnPropertyNames2(ctx, argv[0],\n                                   JS_GPN_SYMBOL_MASK, JS_ITERATOR_KIND_KEY);\n}\n\nstatic JSValue js_object_keys(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int kind)\n{\n    return JS_GetOwnPropertyNames2(ctx, argv[0],\n                                   JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK, kind);\n}\n\nstatic JSValue js_object_isExtensible(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv, int reflect)\n{\n    JSValueConst obj;\n    int ret;\n\n    obj = argv[0];\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {\n        if (reflect)\n            return JS_ThrowTypeErrorNotAnObject(ctx);\n        else\n            return JS_FALSE;\n    }\n    ret = JS_IsExtensible(ctx, obj);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val,\n                                           int argc, JSValueConst *argv, int reflect)\n{\n    JSValueConst obj;\n    int ret;\n\n    obj = argv[0];\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) {\n        if (reflect)\n            return JS_ThrowTypeErrorNotAnObject(ctx);\n        else\n            return JS_DupValue(ctx, obj);\n    }\n    ret = JS_PreventExtensions(ctx, obj);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    if (reflect) {\n        return JS_NewBool(ctx, ret);\n    } else {\n        if (!ret)\n            return JS_ThrowTypeError(ctx, \"proxy preventExtensions handler returned false\");\n        return JS_DupValue(ctx, obj);\n    }\n}\n\nstatic JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv)\n{\n    JSValue obj;\n    JSAtom atom;\n    JSObject *p;\n    BOOL ret;\n\n    atom = JS_ValueToAtom(ctx, argv[0]); /* must be done first */\n    if (unlikely(atom == JS_ATOM_NULL))\n        return JS_EXCEPTION;\n    obj = JS_ToObject(ctx, this_val);\n    if (JS_IsException(obj)) {\n        JS_FreeAtom(ctx, atom);\n        return obj;\n    }\n    p = JS_VALUE_GET_OBJ(obj);\n    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);\n    JS_FreeAtom(ctx, atom);\n    JS_FreeValue(ctx, obj);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_object_hasOwn(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue obj;\n    JSAtom atom;\n    JSObject *p;\n    BOOL ret;\n\n    obj = JS_ToObject(ctx, argv[0]);\n    if (JS_IsException(obj))\n        return obj;\n    atom = JS_ValueToAtom(ctx, argv[1]);\n    if (unlikely(atom == JS_ATOM_NULL)) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    p = JS_VALUE_GET_OBJ(obj);\n    ret = JS_GetOwnPropertyInternal(ctx, NULL, p, atom);\n    JS_FreeAtom(ctx, atom);\n    JS_FreeValue(ctx, obj);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_object_valueOf(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    return JS_ToObject(ctx, this_val);\n}\n\nstatic JSValue js_object_toString(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValue obj, tag;\n    int is_array;\n    JSAtom atom;\n    JSObject *p;\n\n    if (JS_IsNull(this_val)) {\n        tag = js_new_string8(ctx, \"Null\");\n    } else if (JS_IsUndefined(this_val)) {\n        tag = js_new_string8(ctx, \"Undefined\");\n    } else {\n        obj = JS_ToObject(ctx, this_val);\n        if (JS_IsException(obj))\n            return obj;\n        is_array = JS_IsArray(ctx, obj);\n        if (is_array < 0) {\n            JS_FreeValue(ctx, obj);\n            return JS_EXCEPTION;\n        }\n        if (is_array) {\n            atom = JS_ATOM_Array;\n        } else if (JS_IsFunction(ctx, obj)) {\n            atom = JS_ATOM_Function;\n        } else {\n            p = JS_VALUE_GET_OBJ(obj);\n            switch(p->class_id) {\n            case JS_CLASS_STRING:\n            case JS_CLASS_ARGUMENTS:\n            case JS_CLASS_MAPPED_ARGUMENTS:\n            case JS_CLASS_ERROR:\n            case JS_CLASS_BOOLEAN:\n            case JS_CLASS_NUMBER:\n            case JS_CLASS_DATE:\n            case JS_CLASS_REGEXP:\n                atom = ctx->rt->class_array[p->class_id].class_name;\n                break;\n            default:\n                atom = JS_ATOM_Object;\n                break;\n            }\n        }\n        tag = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_toStringTag);\n        JS_FreeValue(ctx, obj);\n        if (JS_IsException(tag))\n            return JS_EXCEPTION;\n        if (!JS_IsString(tag)) {\n            JS_FreeValue(ctx, tag);\n            tag = JS_AtomToString(ctx, atom);\n        }\n    }\n    return JS_ConcatString3(ctx, \"[object \", tag, \"]\");\n}\n\nstatic JSValue js_object_toLocaleString(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv)\n{\n    return JS_Invoke(ctx, this_val, JS_ATOM_toString, 0, NULL);\n}\n\nstatic JSValue js_object_assign(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    // Object.assign(obj, source1)\n    JSValue obj, s;\n    int i;\n\n    s = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, argv[0]);\n    if (JS_IsException(obj))\n        goto exception;\n    for (i = 1; i < argc; i++) {\n        if (!JS_IsNull(argv[i]) && !JS_IsUndefined(argv[i])) {\n            s = JS_ToObject(ctx, argv[i]);\n            if (JS_IsException(s))\n                goto exception;\n            if (JS_CopyDataProperties(ctx, obj, s, JS_UNDEFINED, TRUE))\n                goto exception;\n            JS_FreeValue(ctx, s);\n        }\n    }\n    return obj;\nexception:\n    JS_FreeValue(ctx, obj);\n    JS_FreeValue(ctx, s);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int freeze_flag)\n{\n    JSValueConst obj = argv[0];\n    JSObject *p;\n    JSPropertyEnum *props;\n    uint32_t len, i;\n    int flags, desc_flags, res;\n\n    if (!JS_IsObject(obj))\n        return JS_DupValue(ctx, obj);\n\n    res = JS_PreventExtensions(ctx, obj);\n    if (res < 0)\n        return JS_EXCEPTION;\n    if (!res) {\n        return JS_ThrowTypeError(ctx, \"proxy preventExtensions handler returned false\");\n    }\n\n    p = JS_VALUE_GET_OBJ(obj);\n    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;\n    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))\n        return JS_EXCEPTION;\n\n    for(i = 0; i < len; i++) {\n        JSPropertyDescriptor desc;\n        JSAtom prop = props[i].atom;\n\n        desc_flags = JS_PROP_THROW | JS_PROP_HAS_CONFIGURABLE;\n        if (freeze_flag) {\n            res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);\n            if (res < 0)\n                goto exception;\n            if (res) {\n                if (desc.flags & JS_PROP_WRITABLE)\n                    desc_flags |= JS_PROP_HAS_WRITABLE;\n                js_free_desc(ctx, &desc);\n            }\n        }\n        if (JS_DefineProperty(ctx, obj, prop, JS_UNDEFINED,\n                              JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0)\n            goto exception;\n    }\n    JS_FreePropertyEnum(ctx, props, len);\n    return JS_DupValue(ctx, obj);\n\n exception:\n    JS_FreePropertyEnum(ctx, props, len);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv, int is_frozen)\n{\n    JSValueConst obj = argv[0];\n    JSObject *p;\n    JSPropertyEnum *props;\n    uint32_t len, i;\n    int flags, res;\n\n    if (!JS_IsObject(obj))\n        return JS_TRUE;\n\n    p = JS_VALUE_GET_OBJ(obj);\n    flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK;\n    if (JS_GetOwnPropertyNamesInternal(ctx, &props, &len, p, flags))\n        return JS_EXCEPTION;\n\n    for(i = 0; i < len; i++) {\n        JSPropertyDescriptor desc;\n        JSAtom prop = props[i].atom;\n\n        res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);\n        if (res < 0)\n            goto exception;\n        if (res) {\n            js_free_desc(ctx, &desc);\n            if ((desc.flags & JS_PROP_CONFIGURABLE)\n            ||  (is_frozen && (desc.flags & JS_PROP_WRITABLE))) {\n                res = FALSE;\n                goto done;\n            }\n        }\n    }\n    res = JS_IsExtensible(ctx, obj);\n    if (res < 0)\n        return JS_EXCEPTION;\n    res ^= 1;\ndone:\n    JS_FreePropertyEnum(ctx, props, len);\n    return JS_NewBool(ctx, res);\n\nexception:\n    JS_FreePropertyEnum(ctx, props, len);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_object_fromEntries(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue obj, iter, next_method = JS_UNDEFINED;\n    JSValueConst iterable;\n    BOOL done;\n\n    /*  RequireObjectCoercible() not necessary because it is tested in\n        JS_GetIterator() by JS_GetProperty() */\n    iterable = argv[0];\n\n    obj = JS_NewObject(ctx);\n    if (JS_IsException(obj))\n        return obj;\n\n    iter = JS_GetIterator(ctx, iterable, FALSE);\n    if (JS_IsException(iter))\n        goto fail;\n    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next_method))\n        goto fail;\n\n    for(;;) {\n        JSValue key, value, item;\n        item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto fail;\n        if (done)\n            break;\n\n        key = JS_UNDEFINED;\n        value = JS_UNDEFINED;\n        if (!JS_IsObject(item)) {\n            JS_ThrowTypeErrorNotAnObject(ctx);\n            goto fail1;\n        }\n        key = JS_GetPropertyUint32(ctx, item, 0);\n        if (JS_IsException(key))\n            goto fail1;\n        value = JS_GetPropertyUint32(ctx, item, 1);\n        if (JS_IsException(value)) {\n            JS_FreeValue(ctx, key);\n            goto fail1;\n        }\n        if (JS_DefinePropertyValueValue(ctx, obj, key, value,\n                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0) {\n        fail1:\n            JS_FreeValue(ctx, item);\n            goto fail;\n        }\n        JS_FreeValue(ctx, item);\n    }\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    return obj;\n fail:\n    if (JS_IsObject(iter)) {\n        /* close the iterator object, preserving pending exception */\n        JS_IteratorClose(ctx, iter, TRUE);\n    }\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_object_is(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    return JS_NewBool(ctx, js_same_value(ctx, argv[0], argv[1]));\n}\n\nstatic JSValue JS_SpeciesConstructor(JSContext *ctx, JSValueConst obj,\n                                     JSValueConst defaultConstructor)\n{\n    JSValue ctor, species;\n\n    if (!JS_IsObject(obj))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);\n    if (JS_IsException(ctor))\n        return ctor;\n    if (JS_IsUndefined(ctor))\n        return JS_DupValue(ctx, defaultConstructor);\n    if (!JS_IsObject(ctor)) {\n        JS_FreeValue(ctx, ctor);\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    }\n    species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);\n    JS_FreeValue(ctx, ctor);\n    if (JS_IsException(species))\n        return species;\n    if (JS_IsUndefined(species) || JS_IsNull(species))\n        return JS_DupValue(ctx, defaultConstructor);\n    if (!JS_IsConstructor(ctx, species)) {\n        JS_ThrowTypeErrorNotAConstructor(ctx, species);\n        JS_FreeValue(ctx, species);\n        return JS_EXCEPTION;\n    }\n    return species;\n}\n\nstatic JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val)\n{\n    JSValue val, ret;\n\n    val = JS_ToObject(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    ret = JS_GetPrototype(ctx, val);\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val,\n                                       JSValueConst proto)\n{\n    if (JS_IsUndefined(this_val) || JS_IsNull(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    if (!JS_IsObject(proto) && !JS_IsNull(proto))\n        return JS_UNDEFINED;\n    if (JS_SetPrototypeInternal(ctx, this_val, proto, TRUE) < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_UNDEFINED;\n}\n\nstatic JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JSValue obj, v1;\n    JSValueConst v;\n    int res;\n\n    v = argv[0];\n    if (!JS_IsObject(v))\n        return JS_FALSE;\n    obj = JS_ToObject(ctx, this_val);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    v1 = JS_DupValue(ctx, v);\n    for(;;) {\n        v1 = JS_GetPrototypeFree(ctx, v1);\n        if (JS_IsException(v1))\n            goto exception;\n        if (JS_IsNull(v1)) {\n            res = FALSE;\n            break;\n        }\n        if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {\n            res = TRUE;\n            break;\n        }\n        /* avoid infinite loop (possible with proxies) */\n        if (js_poll_interrupts(ctx))\n            goto exception;\n    }\n    JS_FreeValue(ctx, v1);\n    JS_FreeValue(ctx, obj);\n    return JS_NewBool(ctx, res);\n\nexception:\n    JS_FreeValue(ctx, v1);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_object_propertyIsEnumerable(JSContext *ctx, JSValueConst this_val,\n                                              int argc, JSValueConst *argv)\n{\n    JSValue obj = JS_UNDEFINED, res = JS_EXCEPTION;\n    JSAtom prop;\n    JSPropertyDescriptor desc;\n    int has_prop;\n\n    prop = JS_ValueToAtom(ctx, argv[0]);\n    if (unlikely(prop == JS_ATOM_NULL))\n        goto exception;\n    obj = JS_ToObject(ctx, this_val);\n    if (JS_IsException(obj))\n        goto exception;\n\n    has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);\n    if (has_prop < 0)\n        goto exception;\n    if (has_prop) {\n        res = JS_NewBool(ctx, desc.flags & JS_PROP_ENUMERABLE);\n        js_free_desc(ctx, &desc);\n    } else {\n        res = JS_FALSE;\n    }\n\nexception:\n    JS_FreeAtom(ctx, prop);\n    JS_FreeValue(ctx, obj);\n    return res;\n}\n\nstatic JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val,\n                                          int argc, JSValueConst *argv, int setter)\n{\n    JSValue obj, res = JS_EXCEPTION;\n    JSAtom prop = JS_ATOM_NULL;\n    JSPropertyDescriptor desc;\n    int has_prop;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (JS_IsException(obj))\n        goto exception;\n    prop = JS_ValueToAtom(ctx, argv[0]);\n    if (unlikely(prop == JS_ATOM_NULL))\n        goto exception;\n\n    for (;;) {\n        has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);\n        if (has_prop < 0)\n            goto exception;\n        if (has_prop) {\n            if (desc.flags & JS_PROP_GETSET)\n                res = JS_DupValue(ctx, setter ? desc.setter : desc.getter);\n            else\n                res = JS_UNDEFINED;\n            js_free_desc(ctx, &desc);\n            break;\n        }\n        obj = JS_GetPrototypeFree(ctx, obj);\n        if (JS_IsException(obj))\n            goto exception;\n        if (JS_IsNull(obj)) {\n            res = JS_UNDEFINED;\n            break;\n        }\n        /* avoid infinite loop (possible with proxies) */\n        if (js_poll_interrupts(ctx))\n            goto exception;\n    }\n\nexception:\n    JS_FreeAtom(ctx, prop);\n    JS_FreeValue(ctx, obj);\n    return res;\n}\n\nstatic const JSCFunctionListEntry js_object_funcs[] = {\n    JS_CFUNC_DEF(\"create\", 2, js_object_create ),\n    JS_CFUNC_MAGIC_DEF(\"getPrototypeOf\", 1, js_object_getPrototypeOf, 0 ),\n    JS_CFUNC_DEF(\"setPrototypeOf\", 2, js_object_setPrototypeOf ),\n    JS_CFUNC_MAGIC_DEF(\"defineProperty\", 3, js_object_defineProperty, 0 ),\n    JS_CFUNC_DEF(\"defineProperties\", 2, js_object_defineProperties ),\n    JS_CFUNC_DEF(\"getOwnPropertyNames\", 1, js_object_getOwnPropertyNames ),\n    JS_CFUNC_DEF(\"getOwnPropertySymbols\", 1, js_object_getOwnPropertySymbols ),\n    JS_CFUNC_MAGIC_DEF(\"groupBy\", 2, js_object_groupBy, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"keys\", 1, js_object_keys, JS_ITERATOR_KIND_KEY ),\n    JS_CFUNC_MAGIC_DEF(\"values\", 1, js_object_keys, JS_ITERATOR_KIND_VALUE ),\n    JS_CFUNC_MAGIC_DEF(\"entries\", 1, js_object_keys, JS_ITERATOR_KIND_KEY_AND_VALUE ),\n    JS_CFUNC_MAGIC_DEF(\"isExtensible\", 1, js_object_isExtensible, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"preventExtensions\", 1, js_object_preventExtensions, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"getOwnPropertyDescriptor\", 2, js_object_getOwnPropertyDescriptor, 0 ),\n    JS_CFUNC_DEF(\"getOwnPropertyDescriptors\", 1, js_object_getOwnPropertyDescriptors ),\n    JS_CFUNC_DEF(\"is\", 2, js_object_is ),\n    JS_CFUNC_DEF(\"assign\", 2, js_object_assign ),\n    JS_CFUNC_MAGIC_DEF(\"seal\", 1, js_object_seal, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"freeze\", 1, js_object_seal, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"isSealed\", 1, js_object_isSealed, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"isFrozen\", 1, js_object_isSealed, 1 ),\n    JS_CFUNC_DEF(\"fromEntries\", 1, js_object_fromEntries ),\n    JS_CFUNC_DEF(\"hasOwn\", 2, js_object_hasOwn ),\n};\n\nstatic const JSCFunctionListEntry js_object_proto_funcs[] = {\n    JS_CFUNC_DEF(\"toString\", 0, js_object_toString ),\n    JS_CFUNC_DEF(\"toLocaleString\", 0, js_object_toLocaleString ),\n    JS_CFUNC_DEF(\"valueOf\", 0, js_object_valueOf ),\n    JS_CFUNC_DEF(\"hasOwnProperty\", 1, js_object_hasOwnProperty ),\n    JS_CFUNC_DEF(\"isPrototypeOf\", 1, js_object_isPrototypeOf ),\n    JS_CFUNC_DEF(\"propertyIsEnumerable\", 1, js_object_propertyIsEnumerable ),\n    JS_CGETSET_DEF(\"__proto__\", js_object_get___proto__, js_object_set___proto__ ),\n    JS_CFUNC_MAGIC_DEF(\"__defineGetter__\", 2, js_object___defineGetter__, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"__defineSetter__\", 2, js_object___defineGetter__, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"__lookupGetter__\", 1, js_object___lookupGetter__, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"__lookupSetter__\", 1, js_object___lookupGetter__, 1 ),\n};\n\n/* Function class */\n\nstatic JSValue js_function_proto(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    return JS_UNDEFINED;\n}\n\n/* XXX: add a specific eval mode so that Function(\"}), ({\") is rejected */\nstatic JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,\n                                       int argc, JSValueConst *argv, int magic)\n{\n    JSFunctionKindEnum func_kind = magic;\n    int i, n, ret;\n    JSValue s, proto, obj = JS_UNDEFINED;\n    StringBuffer b_s, *b = &b_s;\n\n    string_buffer_init(ctx, b, 0);\n    string_buffer_putc8(b, '(');\n\n    if (func_kind == JS_FUNC_ASYNC || func_kind == JS_FUNC_ASYNC_GENERATOR) {\n        string_buffer_puts8(b, \"async \");\n    }\n    string_buffer_puts8(b, \"function\");\n\n    if (func_kind == JS_FUNC_GENERATOR || func_kind == JS_FUNC_ASYNC_GENERATOR) {\n        string_buffer_putc8(b, '*');\n    }\n    string_buffer_puts8(b, \" anonymous(\");\n\n    n = argc - 1;\n    for(i = 0; i < n; i++) {\n        if (i != 0) {\n            string_buffer_putc8(b, ',');\n        }\n        if (string_buffer_concat_value(b, argv[i]))\n            goto fail;\n    }\n    string_buffer_puts8(b, \"\\n) {\\n\");\n    if (n >= 0) {\n        if (string_buffer_concat_value(b, argv[n]))\n            goto fail;\n    }\n    string_buffer_puts8(b, \"\\n})\");\n    s = string_buffer_end(b);\n    if (JS_IsException(s))\n        goto fail1;\n\n    obj = JS_EvalObject(ctx, ctx->global_obj, s, JS_EVAL_TYPE_INDIRECT, -1);\n    JS_FreeValue(ctx, s);\n    if (JS_IsException(obj))\n        goto fail1;\n    if (!JS_IsUndefined(new_target)) {\n        /* set the prototype */\n        proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);\n        if (JS_IsException(proto))\n            goto fail1;\n        if (!JS_IsObject(proto)) {\n            JSContext *realm;\n            JS_FreeValue(ctx, proto);\n            realm = JS_GetFunctionRealm(ctx, new_target);\n            if (!realm)\n                goto fail1;\n            proto = JS_DupValue(ctx, realm->class_proto[func_kind_to_class_id[func_kind]]);\n        }\n        ret = JS_SetPrototypeInternal(ctx, obj, proto, TRUE);\n        JS_FreeValue(ctx, proto);\n        if (ret < 0)\n            goto fail1;\n    }\n    return obj;\n\n fail:\n    string_buffer_free(b);\n fail1:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic __exception int js_get_length32(JSContext *ctx, uint32_t *pres,\n                                       JSValueConst obj)\n{\n    JSValue len_val;\n    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);\n    if (JS_IsException(len_val)) {\n        *pres = 0;\n        return -1;\n    }\n    return JS_ToUint32Free(ctx, pres, len_val);\n}\n\nstatic __exception int js_get_length64(JSContext *ctx, int64_t *pres,\n                                       JSValueConst obj)\n{\n    JSValue len_val;\n    len_val = JS_GetProperty(ctx, obj, JS_ATOM_length);\n    if (JS_IsException(len_val)) {\n        *pres = 0;\n        return -1;\n    }\n    return JS_ToLengthFree(ctx, pres, len_val);\n}\n\nstatic void free_arg_list(JSContext *ctx, JSValue *tab, uint32_t len)\n{\n    uint32_t i;\n    for(i = 0; i < len; i++) {\n        JS_FreeValue(ctx, tab[i]);\n    }\n    js_free(ctx, tab);\n}\n\n/* XXX: should use ValueArray */\nstatic JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,\n                               JSValueConst array_arg)\n{\n    uint32_t len, i;\n    int64_t len64;\n    JSValue *tab, ret;\n    JSObject *p;\n\n    if (JS_VALUE_GET_TAG(array_arg) != JS_TAG_OBJECT) {\n        JS_ThrowTypeError(ctx, \"not a object\");\n        return NULL;\n    }\n    if (js_get_length64(ctx, &len64, array_arg))\n        return NULL;\n    if (len64 > JS_MAX_LOCAL_VARS) {\n        // XXX: check for stack overflow?\n        JS_ThrowRangeError(ctx, \"too many arguments in function call (only %d allowed)\",\n                           JS_MAX_LOCAL_VARS);\n        return NULL;\n    }\n    len = len64;\n    /* avoid allocating 0 bytes */\n    tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));\n    if (!tab)\n        return NULL;\n    p = JS_VALUE_GET_OBJ(array_arg);\n    if ((p->class_id == JS_CLASS_ARRAY || p->class_id == JS_CLASS_ARGUMENTS || p->class_id == JS_CLASS_MAPPED_ARGUMENTS) &&\n        p->fast_array &&\n        len == p->u.array.count) {\n        if (p->class_id == JS_CLASS_MAPPED_ARGUMENTS) {\n            for(i = 0; i < len; i++) {\n                tab[i] = JS_DupValue(ctx, *p->u.array.u.var_refs[i]->pvalue);\n            }\n        } else {\n            for(i = 0; i < len; i++) {\n                tab[i] = JS_DupValue(ctx, p->u.array.u.values[i]);\n            }\n        }\n    } else {\n        for(i = 0; i < len; i++) {\n            ret = JS_GetPropertyUint32(ctx, array_arg, i);\n            if (JS_IsException(ret)) {\n                free_arg_list(ctx, tab, i);\n                return NULL;\n            }\n            tab[i] = ret;\n        }\n    }\n    *plen = len;\n    return tab;\n}\n\n/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =\n   Reflect.apply */\nstatic JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv, int magic)\n{\n    JSValueConst this_arg, array_arg;\n    uint32_t len;\n    JSValue *tab, ret;\n\n    if (check_function(ctx, this_val))\n        return JS_EXCEPTION;\n    this_arg = argv[0];\n    array_arg = argv[1];\n    if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||\n         JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {\n        return JS_Call(ctx, this_val, this_arg, 0, NULL);\n    }\n    tab = build_arg_list(ctx, &len, array_arg);\n    if (!tab)\n        return JS_EXCEPTION;\n    if (magic & 1) {\n        ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);\n    } else {\n        ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);\n    }\n    free_arg_list(ctx, tab, len);\n    return ret;\n}\n\nstatic JSValue js_function_call(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    if (argc <= 0) {\n        return JS_Call(ctx, this_val, JS_UNDEFINED, 0, NULL);\n    } else {\n        return JS_Call(ctx, this_val, argv[0], argc - 1, argv + 1);\n    }\n}\n\nstatic JSValue js_function_bind(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSBoundFunction *bf;\n    JSValue func_obj, name1, len_val;\n    JSObject *p;\n    int arg_count, i, ret;\n\n    if (check_function(ctx, this_val))\n        return JS_EXCEPTION;\n\n    func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,\n                                 JS_CLASS_BOUND_FUNCTION);\n    if (JS_IsException(func_obj))\n        return JS_EXCEPTION;\n    p = JS_VALUE_GET_OBJ(func_obj);\n    p->is_constructor = JS_IsConstructor(ctx, this_val);\n    arg_count = max_int(0, argc - 1);\n    bf = js_malloc(ctx, sizeof(*bf) + arg_count * sizeof(JSValue));\n    if (!bf)\n        goto exception;\n    bf->func_obj = JS_DupValue(ctx, this_val);\n    bf->this_val = JS_DupValue(ctx, argv[0]);\n    bf->argc = arg_count;\n    for(i = 0; i < arg_count; i++) {\n        bf->argv[i] = JS_DupValue(ctx, argv[i + 1]);\n    }\n    p->u.bound_function = bf;\n\n    /* XXX: the spec could be simpler by only using GetOwnProperty */\n    ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length);\n    if (ret < 0)\n        goto exception;\n    if (!ret) {\n        len_val = JS_NewInt32(ctx, 0);\n    } else {\n        len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length);\n        if (JS_IsException(len_val))\n            goto exception;\n        if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) {\n            /* most common case */\n            int len1 = JS_VALUE_GET_INT(len_val);\n            if (len1 <= arg_count)\n                len1 = 0;\n            else\n                len1 -= arg_count;\n            len_val = JS_NewInt32(ctx, len1);\n        } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) {\n            double d = JS_VALUE_GET_FLOAT64(len_val);\n            if (isnan(d)) {\n                d = 0.0;\n            } else {\n                d = trunc(d);\n                if (d <= (double)arg_count)\n                    d = 0.0;\n                else\n                    d -= (double)arg_count; /* also converts -0 to +0 */\n            }\n            len_val = JS_NewFloat64(ctx, d);\n        } else {\n            JS_FreeValue(ctx, len_val);\n            len_val = JS_NewInt32(ctx, 0);\n        }\n    }\n    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length,\n                           len_val, JS_PROP_CONFIGURABLE);\n\n    name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name);\n    if (JS_IsException(name1))\n        goto exception;\n    if (!JS_IsString(name1)) {\n        JS_FreeValue(ctx, name1);\n        name1 = JS_AtomToString(ctx, JS_ATOM_empty_string);\n    }\n    name1 = JS_ConcatString3(ctx, \"bound \", name1, \"\");\n    if (JS_IsException(name1))\n        goto exception;\n    JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1,\n                           JS_PROP_CONFIGURABLE);\n    return func_obj;\n exception:\n    JS_FreeValue(ctx, func_obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_function_toString(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv)\n{\n    JSObject *p;\n    JSFunctionKindEnum func_kind = JS_FUNC_NORMAL;\n\n    if (check_function(ctx, this_val))\n        return JS_EXCEPTION;\n\n    p = JS_VALUE_GET_OBJ(this_val);\n    if (js_class_has_bytecode(p->class_id)) {\n        JSFunctionBytecode *b = p->u.func.function_bytecode;\n        if (b->has_debug && b->debug.source) {\n            return JS_NewStringLen(ctx, b->debug.source, b->debug.source_len);\n        }\n        func_kind = b->func_kind;\n    }\n    {\n        JSValue name;\n        const char *pref, *suff;\n\n        switch(func_kind) {\n        default:\n        case JS_FUNC_NORMAL:\n            pref = \"function \";\n            break;\n        case JS_FUNC_GENERATOR:\n            pref = \"function *\";\n            break;\n        case JS_FUNC_ASYNC:\n            pref = \"async function \";\n            break;\n        case JS_FUNC_ASYNC_GENERATOR:\n            pref = \"async function *\";\n            break;\n        }\n        suff = \"() {\\n    [native code]\\n}\";\n        name = JS_GetProperty(ctx, this_val, JS_ATOM_name);\n        if (JS_IsUndefined(name))\n            name = JS_AtomToString(ctx, JS_ATOM_empty_string);\n        return JS_ConcatString3(ctx, pref, name, suff);\n    }\n}\n\nstatic JSValue js_function_hasInstance(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    int ret;\n    ret = JS_OrdinaryIsInstanceOf(ctx, argv[0], this_val);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic const JSCFunctionListEntry js_function_proto_funcs[] = {\n    JS_CFUNC_DEF(\"call\", 1, js_function_call ),\n    JS_CFUNC_MAGIC_DEF(\"apply\", 2, js_function_apply, 0 ),\n    JS_CFUNC_DEF(\"bind\", 1, js_function_bind ),\n    JS_CFUNC_DEF(\"toString\", 0, js_function_toString ),\n    JS_CFUNC_DEF(\"[Symbol.hasInstance]\", 1, js_function_hasInstance ),\n    JS_CGETSET_DEF(\"fileName\", js_function_proto_fileName, NULL ),\n    JS_CGETSET_MAGIC_DEF(\"lineNumber\", js_function_proto_lineNumber, NULL, 0 ),\n    JS_CGETSET_MAGIC_DEF(\"columnNumber\", js_function_proto_lineNumber, NULL, 1 ),\n};\n\n/* Error class */\n\nstatic JSValue iterator_to_array(JSContext *ctx, JSValueConst items)\n{\n    JSValue iter, next_method = JS_UNDEFINED;\n    JSValue v, r = JS_UNDEFINED;\n    int64_t k;\n    BOOL done;\n\n    iter = JS_GetIterator(ctx, items, FALSE);\n    if (JS_IsException(iter))\n        goto exception;\n    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next_method))\n        goto exception;\n    r = JS_NewArray(ctx);\n    if (JS_IsException(r))\n        goto exception;\n    for (k = 0;; k++) {\n        v = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);\n        if (JS_IsException(v))\n            goto exception_close;\n        if (done)\n            break;\n        if (JS_DefinePropertyValueInt64(ctx, r, k, v,\n                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n            goto exception_close;\n    }\n done:\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    return r;\n exception_close:\n    JS_IteratorClose(ctx, iter, TRUE);\n exception:\n    JS_FreeValue(ctx, r);\n    r = JS_EXCEPTION;\n    goto done;\n}\n\nstatic JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target,\n                                    int argc, JSValueConst *argv, int magic)\n{\n    JSValue obj, msg, proto;\n    JSValueConst message, options;\n    int arg_index;\n\n    if (JS_IsUndefined(new_target))\n        new_target = JS_GetActiveFunction(ctx);\n    proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);\n    if (JS_IsException(proto))\n        return proto;\n    if (!JS_IsObject(proto)) {\n        JSContext *realm;\n        JSValueConst proto1;\n\n        JS_FreeValue(ctx, proto);\n        realm = JS_GetFunctionRealm(ctx, new_target);\n        if (!realm)\n            return JS_EXCEPTION;\n        if (magic < 0) {\n            proto1 = realm->class_proto[JS_CLASS_ERROR];\n        } else {\n            proto1 = realm->native_error_proto[magic];\n        }\n        proto = JS_DupValue(ctx, proto1);\n    }\n    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_ERROR);\n    JS_FreeValue(ctx, proto);\n    if (JS_IsException(obj))\n        return obj;\n    arg_index = (magic == JS_AGGREGATE_ERROR);\n\n    message = argv[arg_index++];\n    if (!JS_IsUndefined(message)) {\n        msg = JS_ToString(ctx, message);\n        if (unlikely(JS_IsException(msg)))\n            goto exception;\n        JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,\n                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n    }\n\n    if (arg_index < argc) {\n        options = argv[arg_index];\n        if (JS_IsObject(options)) {\n            int present = JS_HasProperty(ctx, options, JS_ATOM_cause);\n            if (present < 0)\n                goto exception;\n            if (present) {\n                JSValue cause = JS_GetProperty(ctx, options, JS_ATOM_cause);\n                if (JS_IsException(cause))\n                    goto exception;\n                JS_DefinePropertyValue(ctx, obj, JS_ATOM_cause, cause,\n                                       JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n            }\n        }\n    }\n\n    if (magic == JS_AGGREGATE_ERROR) {\n        JSValue error_list = iterator_to_array(ctx, argv[0]);\n        if (JS_IsException(error_list))\n            goto exception;\n        JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,\n                               JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n    }\n\n    /* skip the Error() function in the backtrace */\n    build_backtrace(ctx, obj, NULL, 0, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);\n    return obj;\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue name, msg;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    name = JS_GetProperty(ctx, this_val, JS_ATOM_name);\n    if (JS_IsUndefined(name))\n        name = JS_AtomToString(ctx, JS_ATOM_Error);\n    else\n        name = JS_ToStringFree(ctx, name);\n    if (JS_IsException(name))\n        return JS_EXCEPTION;\n\n    msg = JS_GetProperty(ctx, this_val, JS_ATOM_message);\n    if (JS_IsUndefined(msg))\n        msg = JS_AtomToString(ctx, JS_ATOM_empty_string);\n    else\n        msg = JS_ToStringFree(ctx, msg);\n    if (JS_IsException(msg)) {\n        JS_FreeValue(ctx, name);\n        return JS_EXCEPTION;\n    }\n    if (!JS_IsEmptyString(name) && !JS_IsEmptyString(msg))\n        name = JS_ConcatString3(ctx, \"\", name, \": \");\n    return JS_ConcatString(ctx, name, msg);\n}\n\nstatic const JSCFunctionListEntry js_error_proto_funcs[] = {\n    JS_CFUNC_DEF(\"toString\", 0, js_error_toString ),\n    JS_PROP_STRING_DEF(\"name\", \"Error\", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\n    JS_PROP_STRING_DEF(\"message\", \"\", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\n};\n\n/* 2 entries for each native error class */\n/* Note: we use an atom to avoid the autoinit definition which does\n   not work in get_prop_string() */\nstatic const JSCFunctionListEntry js_native_error_proto_funcs[] = {\n#define DEF(name) \\\n    JS_PROP_ATOM_DEF(\"name\", name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\\\n    JS_PROP_STRING_DEF(\"message\", \"\", JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\n    \n    DEF(JS_ATOM_EvalError)\n    DEF(JS_ATOM_RangeError)\n    DEF(JS_ATOM_ReferenceError)\n    DEF(JS_ATOM_SyntaxError)\n    DEF(JS_ATOM_TypeError)\n    DEF(JS_ATOM_URIError)\n    DEF(JS_ATOM_InternalError)\n    DEF(JS_ATOM_AggregateError)\n#undef DEF    \n};\n\nstatic JSValue js_error_isError(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    return JS_NewBool(ctx, JS_IsError(ctx, argv[0]));\n}\n\nstatic const JSCFunctionListEntry js_error_funcs[] = {\n    JS_CFUNC_DEF(\"isError\", 1, js_error_isError),\n};\n\n/* AggregateError */\n\n/* used by C code. */\nstatic JSValue js_aggregate_error_constructor(JSContext *ctx,\n                                              JSValueConst errors)\n{\n    JSValue obj;\n\n    obj = JS_NewObjectProtoClass(ctx,\n                                 ctx->native_error_proto[JS_AGGREGATE_ERROR],\n                                 JS_CLASS_ERROR);\n    if (JS_IsException(obj))\n        return obj;\n    JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),\n                           JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n    return obj;\n}\n\n/* Array */\n\nstatic int JS_CopySubArray(JSContext *ctx,\n                           JSValueConst obj, int64_t to_pos,\n                           int64_t from_pos, int64_t count, int dir)\n{\n    JSObject *p;\n    int64_t i, from, to, len;\n    JSValue val;\n    int fromPresent;\n\n    p = NULL;\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        p = JS_VALUE_GET_OBJ(obj);\n        if (p->class_id != JS_CLASS_ARRAY || !p->fast_array) {\n            p = NULL;\n        }\n    }\n\n    for (i = 0; i < count; ) {\n        if (dir < 0) {\n            from = from_pos + count - i - 1;\n            to = to_pos + count - i - 1;\n        } else {\n            from = from_pos + i;\n            to = to_pos + i;\n        }\n        if (p && p->fast_array &&\n            from >= 0 && from < (len = p->u.array.count)  &&\n            to >= 0 && to < len) {\n            int64_t l, j;\n            /* Fast path for fast arrays. Since we don't look at the\n               prototype chain, we can optimize only the cases where\n               all the elements are present in the array. */\n            l = count - i;\n            if (dir < 0) {\n                l = min_int64(l, from + 1);\n                l = min_int64(l, to + 1);\n                for(j = 0; j < l; j++) {\n                    set_value(ctx, &p->u.array.u.values[to - j],\n                              JS_DupValue(ctx, p->u.array.u.values[from - j]));\n                }\n            } else {\n                l = min_int64(l, len - from);\n                l = min_int64(l, len - to);\n                for(j = 0; j < l; j++) {\n                    set_value(ctx, &p->u.array.u.values[to + j],\n                              JS_DupValue(ctx, p->u.array.u.values[from + j]));\n                }\n            }\n            i += l;\n        } else {\n            fromPresent = JS_TryGetPropertyInt64(ctx, obj, from, &val);\n            if (fromPresent < 0)\n                goto exception;\n\n            if (fromPresent) {\n                if (JS_SetPropertyInt64(ctx, obj, to, val) < 0)\n                    goto exception;\n            } else {\n                if (JS_DeletePropertyInt64(ctx, obj, to, JS_PROP_THROW) < 0)\n                    goto exception;\n            }\n            i++;\n        }\n    }\n    return 0;\n\n exception:\n    return -1;\n}\n\nstatic JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,\n                                    int argc, JSValueConst *argv)\n{\n    JSValue obj;\n    int i;\n\n    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_ARRAY);\n    if (JS_IsException(obj))\n        return obj;\n    if (argc == 1 && JS_IsNumber(argv[0])) {\n        uint32_t len;\n        if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))\n            goto fail;\n        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)\n            goto fail;\n    } else {\n        for(i = 0; i < argc; i++) {\n            if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0)\n                goto fail;\n        }\n    }\n    return obj;\nfail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_from(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    // from(items, mapfn = void 0, this_arg = void 0)\n    JSValueConst items = argv[0], mapfn, this_arg;\n    JSValueConst args[2];\n    JSValue iter, r, v, v2, arrayLike, next_method, enum_obj;\n    int64_t k, len;\n    int done, mapping;\n\n    mapping = FALSE;\n    mapfn = JS_UNDEFINED;\n    this_arg = JS_UNDEFINED;\n    r = JS_UNDEFINED;\n    arrayLike = JS_UNDEFINED;\n    iter = JS_UNDEFINED;\n    enum_obj = JS_UNDEFINED;\n    next_method = JS_UNDEFINED;\n\n    if (argc > 1) {\n        mapfn = argv[1];\n        if (!JS_IsUndefined(mapfn)) {\n            if (check_function(ctx, mapfn))\n                goto exception;\n            mapping = 1;\n            if (argc > 2)\n                this_arg = argv[2];\n        }\n    }\n    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);\n    if (JS_IsException(iter))\n        goto exception;\n    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {\n        if (!JS_IsFunction(ctx, iter)) {\n            JS_ThrowTypeError(ctx, \"value is not iterable\");\n            goto exception;\n        }\n        if (JS_IsConstructor(ctx, this_val))\n            r = JS_CallConstructor(ctx, this_val, 0, NULL);\n        else\n            r = JS_NewArray(ctx);\n        if (JS_IsException(r))\n            goto exception;\n        enum_obj = JS_GetIterator2(ctx, items, iter);\n        if (JS_IsException(enum_obj))\n            goto exception;\n        next_method = JS_GetProperty(ctx, enum_obj, JS_ATOM_next);\n        if (JS_IsException(next_method))\n            goto exception;\n        for (k = 0;; k++) {\n            v = JS_IteratorNext(ctx, enum_obj, next_method, 0, NULL, &done);\n            if (JS_IsException(v))\n                goto exception;\n            if (done)\n                break;\n            if (mapping) {\n                args[0] = v;\n                args[1] = JS_NewInt32(ctx, k);\n                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);\n                JS_FreeValue(ctx, v);\n                v = v2;\n                if (JS_IsException(v))\n                    goto exception_close;\n            }\n            if (JS_DefinePropertyValueInt64(ctx, r, k, v,\n                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception_close;\n        }\n    } else {\n        arrayLike = JS_ToObject(ctx, items);\n        if (JS_IsException(arrayLike))\n            goto exception;\n        if (js_get_length64(ctx, &len, arrayLike) < 0)\n            goto exception;\n        v = JS_NewInt64(ctx, len);\n        args[0] = v;\n        if (JS_IsConstructor(ctx, this_val)) {\n            r = JS_CallConstructor(ctx, this_val, 1, args);\n        } else {\n            r = js_array_constructor(ctx, JS_UNDEFINED, 1, args);\n        }\n        JS_FreeValue(ctx, v);\n        if (JS_IsException(r))\n            goto exception;\n        for(k = 0; k < len; k++) {\n            v = JS_GetPropertyInt64(ctx, arrayLike, k);\n            if (JS_IsException(v))\n                goto exception;\n            if (mapping) {\n                args[0] = v;\n                args[1] = JS_NewInt32(ctx, k);\n                v2 = JS_Call(ctx, mapfn, this_arg, 2, args);\n                JS_FreeValue(ctx, v);\n                v = v2;\n                if (JS_IsException(v))\n                    goto exception;\n            }\n            if (JS_DefinePropertyValueInt64(ctx, r, k, v,\n                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception;\n        }\n    }\n    if (JS_SetProperty(ctx, r, JS_ATOM_length, JS_NewUint32(ctx, k)) < 0)\n        goto exception;\n    goto done;\n\n exception_close:\n    JS_IteratorClose(ctx, enum_obj, TRUE);\n exception:\n    JS_FreeValue(ctx, r);\n    r = JS_EXCEPTION;\n done:\n    JS_FreeValue(ctx, arrayLike);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, enum_obj);\n    JS_FreeValue(ctx, next_method);\n    return r;\n}\n\nstatic JSValue js_array_of(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    JSValue obj, args[1];\n    int i;\n\n    if (JS_IsConstructor(ctx, this_val)) {\n        args[0] = JS_NewInt32(ctx, argc);\n        obj = JS_CallConstructor(ctx, this_val, 1, (JSValueConst *)args);\n    } else {\n        obj = JS_NewArray(ctx);\n    }\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    for(i = 0; i < argc; i++) {\n        if (JS_CreateDataPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i]),\n                                        JS_PROP_THROW) < 0) {\n            goto fail;\n        }\n    }\n    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, argc)) < 0) {\n    fail:\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    return obj;\n}\n\nstatic JSValue js_array_isArray(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    int ret;\n    ret = JS_IsArray(ctx, argv[0]);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_get_this(JSContext *ctx,\n                           JSValueConst this_val)\n{\n    return JS_DupValue(ctx, this_val);\n}\n\nstatic JSValue JS_ArraySpeciesCreate(JSContext *ctx, JSValueConst obj,\n                                     JSValueConst len_val)\n{\n    JSValue ctor, ret, species;\n    int res;\n    JSContext *realm;\n\n    res = JS_IsArray(ctx, obj);\n    if (res < 0)\n        return JS_EXCEPTION;\n    if (!res)\n        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);\n    ctor = JS_GetProperty(ctx, obj, JS_ATOM_constructor);\n    if (JS_IsException(ctor))\n        return ctor;\n    if (JS_IsConstructor(ctx, ctor)) {\n        /* legacy web compatibility */\n        realm = JS_GetFunctionRealm(ctx, ctor);\n        if (!realm) {\n            JS_FreeValue(ctx, ctor);\n            return JS_EXCEPTION;\n        }\n        if (realm != ctx &&\n            js_same_value(ctx, ctor, realm->array_ctor)) {\n            JS_FreeValue(ctx, ctor);\n            ctor = JS_UNDEFINED;\n        }\n    }\n    if (JS_IsObject(ctor)) {\n        species = JS_GetProperty(ctx, ctor, JS_ATOM_Symbol_species);\n        JS_FreeValue(ctx, ctor);\n        if (JS_IsException(species))\n            return species;\n        ctor = species;\n        if (JS_IsNull(ctor))\n            ctor = JS_UNDEFINED;\n    }\n    if (JS_IsUndefined(ctor)) {\n        return js_array_constructor(ctx, JS_UNDEFINED, 1, &len_val);\n    } else {\n        ret = JS_CallConstructor(ctx, ctor, 1, &len_val);\n        JS_FreeValue(ctx, ctor);\n        return ret;\n    }\n}\n\nstatic const JSCFunctionListEntry js_array_funcs[] = {\n    JS_CFUNC_DEF(\"isArray\", 1, js_array_isArray ),\n    JS_CFUNC_DEF(\"from\", 1, js_array_from ),\n    JS_CFUNC_DEF(\"of\", 0, js_array_of ),\n    JS_CGETSET_DEF(\"[Symbol.species]\", js_get_this, NULL ),\n};\n\nstatic int JS_isConcatSpreadable(JSContext *ctx, JSValueConst obj)\n{\n    JSValue val;\n\n    if (!JS_IsObject(obj))\n        return FALSE;\n    val = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_isConcatSpreadable);\n    if (JS_IsException(val))\n        return -1;\n    if (!JS_IsUndefined(val))\n        return JS_ToBoolFree(ctx, val);\n    return JS_IsArray(ctx, obj);\n}\n\nstatic JSValue js_array_at(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    JSValue obj, ret;\n    int64_t len, idx;\n    JSValue *arrp;\n    uint32_t count;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    if (JS_ToInt64Sat(ctx, &idx, argv[0]))\n        goto exception;\n\n    if (idx < 0)\n        idx = len + idx;\n    if (idx < 0 || idx >= len) {\n        ret = JS_UNDEFINED;\n    } else if (js_get_fast_array(ctx, obj, &arrp, &count) && idx < count) {\n        ret = JS_DupValue(ctx, arrp[idx]);\n    } else {\n        int present = JS_TryGetPropertyInt64(ctx, obj, idx, &ret);\n        if (present < 0)\n            goto exception;\n        if (!present)\n            ret = JS_UNDEFINED;\n    }\n    JS_FreeValue(ctx, obj);\n    return ret;\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_with(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    JSValue arr, obj, ret, *arrp, *pval;\n    JSObject *p;\n    int64_t i, len, idx;\n    uint32_t count32;\n\n    ret = JS_EXCEPTION;\n    arr = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    if (JS_ToInt64Sat(ctx, &idx, argv[0]))\n        goto exception;\n\n    if (idx < 0)\n        idx = len + idx;\n\n    if (idx < 0 || idx >= len) {\n        JS_ThrowRangeError(ctx, \"invalid array index: %\" PRId64, idx);\n        goto exception;\n    }\n\n    arr = js_allocate_fast_array(ctx, len);\n    if (JS_IsException(arr))\n        goto exception;\n\n    p = JS_VALUE_GET_OBJ(arr);\n    i = 0;\n    pval = p->u.array.u.values;\n    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {\n        for (; i < idx; i++, pval++)\n            *pval = JS_DupValue(ctx, arrp[i]);\n        *pval = JS_DupValue(ctx, argv[1]);\n        for (i++, pval++; i < len; i++, pval++)\n            *pval = JS_DupValue(ctx, arrp[i]);\n    } else {\n        for (; i < idx; i++, pval++)\n            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))\n                goto fill_and_fail;\n        *pval = JS_DupValue(ctx, argv[1]);\n        for (i++, pval++; i < len; i++, pval++) {\n            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {\n            fill_and_fail:\n                for (; i < len; i++, pval++)\n                    *pval = JS_UNDEFINED;\n                goto exception;\n            }\n        }\n    }\n\n    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)\n        goto exception;\n\n    ret = arr;\n    arr = JS_UNDEFINED;\n\nexception:\n    JS_FreeValue(ctx, arr);\n    JS_FreeValue(ctx, obj);\n    return ret;\n}\n\nstatic JSValue js_array_concat(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    JSValue obj, arr, val;\n    JSValueConst e;\n    int64_t len, k, n;\n    int i, res;\n\n    arr = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (JS_IsException(obj))\n        goto exception;\n\n    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));\n    if (JS_IsException(arr))\n        goto exception;\n    n = 0;\n    for (i = -1; i < argc; i++) {\n        if (i < 0)\n            e = obj;\n        else\n            e = argv[i];\n\n        res = JS_isConcatSpreadable(ctx, e);\n        if (res < 0)\n            goto exception;\n        if (res) {\n            if (js_get_length64(ctx, &len, e))\n                goto exception;\n            if (n + len > MAX_SAFE_INTEGER) {\n                JS_ThrowTypeError(ctx, \"Array loo long\");\n                goto exception;\n            }\n            for (k = 0; k < len; k++, n++) {\n                res = JS_TryGetPropertyInt64(ctx, e, k, &val);\n                if (res < 0)\n                    goto exception;\n                if (res) {\n                    if (JS_DefinePropertyValueInt64(ctx, arr, n, val,\n                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                        goto exception;\n                }\n            }\n        } else {\n            if (n >= MAX_SAFE_INTEGER) {\n                JS_ThrowTypeError(ctx, \"Array loo long\");\n                goto exception;\n            }\n            if (JS_DefinePropertyValueInt64(ctx, arr, n, JS_DupValue(ctx, e),\n                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception;\n            n++;\n        }\n    }\n    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)\n        goto exception;\n\n    JS_FreeValue(ctx, obj);\n    return arr;\n\nexception:\n    JS_FreeValue(ctx, arr);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\n#define special_every    0\n#define special_some     1\n#define special_forEach  2\n#define special_map      3\n#define special_filter   4\n#define special_TA       8\n\nstatic JSValue js_typed_array___speciesCreate(JSContext *ctx,\n                                              JSValueConst this_val,\n                                              int argc, JSValueConst *argv);\n\nstatic JSValue js_array_every(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int special)\n{\n    JSValue obj, val, index_val, res, ret;\n    JSValueConst args[3];\n    JSValueConst func, this_arg;\n    int64_t len, k, n;\n    int present;\n\n    ret = JS_UNDEFINED;\n    val = JS_UNDEFINED;\n    if (special & special_TA) {\n        obj = JS_DupValue(ctx, this_val);\n        len = js_typed_array_get_length_unsafe(ctx, obj);\n        if (len < 0)\n            goto exception;\n    } else {\n        obj = JS_ToObject(ctx, this_val);\n        if (js_get_length64(ctx, &len, obj))\n            goto exception;\n    }\n    func = argv[0];\n    this_arg = JS_UNDEFINED;\n    if (argc > 1)\n        this_arg = argv[1];\n\n    if (check_function(ctx, func))\n        goto exception;\n\n    switch (special) {\n    case special_every:\n    case special_every | special_TA:\n        ret = JS_TRUE;\n        break;\n    case special_some:\n    case special_some | special_TA:\n        ret = JS_FALSE;\n        break;\n    case special_map:\n        /* XXX: JS_ArraySpeciesCreate should take int64_t */\n        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt64(ctx, len));\n        if (JS_IsException(ret))\n            goto exception;\n        break;\n    case special_filter:\n        ret = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));\n        if (JS_IsException(ret))\n            goto exception;\n        break;\n    case special_map | special_TA:\n        args[0] = obj;\n        args[1] = JS_NewInt32(ctx, len);\n        ret = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);\n        if (JS_IsException(ret))\n            goto exception;\n        break;\n    case special_filter | special_TA:\n        ret = JS_NewArray(ctx);\n        if (JS_IsException(ret))\n            goto exception;\n        break;\n    }\n    n = 0;\n\n    for(k = 0; k < len; k++) {\n        if (special & special_TA) {\n            val = JS_GetPropertyInt64(ctx, obj, k);\n            if (JS_IsException(val))\n                goto exception;\n            present = TRUE;\n        } else {\n            present = JS_TryGetPropertyInt64(ctx, obj, k, &val);\n            if (present < 0)\n                goto exception;\n        }\n        if (present) {\n            index_val = JS_NewInt64(ctx, k);\n            if (JS_IsException(index_val))\n                goto exception;\n            args[0] = val;\n            args[1] = index_val;\n            args[2] = obj;\n            res = JS_Call(ctx, func, this_arg, 3, args);\n            JS_FreeValue(ctx, index_val);\n            if (JS_IsException(res))\n                goto exception;\n            switch (special) {\n            case special_every:\n            case special_every | special_TA:\n                if (!JS_ToBoolFree(ctx, res)) {\n                    ret = JS_FALSE;\n                    goto done;\n                }\n                break;\n            case special_some:\n            case special_some | special_TA:\n                if (JS_ToBoolFree(ctx, res)) {\n                    ret = JS_TRUE;\n                    goto done;\n                }\n                break;\n            case special_map:\n                if (JS_DefinePropertyValueInt64(ctx, ret, k, res,\n                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                    goto exception;\n                break;\n            case special_map | special_TA:\n                if (JS_SetPropertyValue(ctx, ret, JS_NewInt32(ctx, k), res, JS_PROP_THROW) < 0)\n                    goto exception;\n                break;\n            case special_filter:\n            case special_filter | special_TA:\n                if (JS_ToBoolFree(ctx, res)) {\n                    if (JS_DefinePropertyValueInt64(ctx, ret, n++, JS_DupValue(ctx, val),\n                                                    JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                        goto exception;\n                }\n                break;\n            default:\n                JS_FreeValue(ctx, res);\n                break;\n            }\n            JS_FreeValue(ctx, val);\n            val = JS_UNDEFINED;\n        }\n    }\ndone:\n    if (special == (special_filter | special_TA)) {\n        JSValue arr;\n        args[0] = obj;\n        args[1] = JS_NewInt32(ctx, n);\n        arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);\n        if (JS_IsException(arr))\n            goto exception;\n        args[0] = ret;\n        res = JS_Invoke(ctx, arr, JS_ATOM_set, 1, args);\n        if (check_exception_free(ctx, res)) {\n            JS_FreeValue(ctx, arr);\n            goto exception;\n        }\n        JS_FreeValue(ctx, ret);\n        ret = arr;\n    }\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, obj);\n    return ret;\n\nexception:\n    JS_FreeValue(ctx, ret);\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\n#define special_reduce       0\n#define special_reduceRight  1\n\nstatic JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv, int special)\n{\n    JSValue obj, val, index_val, acc, acc1;\n    JSValueConst args[4];\n    JSValueConst func;\n    int64_t len, k, k1;\n    int present;\n\n    acc = JS_UNDEFINED;\n    val = JS_UNDEFINED;\n    if (special & special_TA) {\n        obj = JS_DupValue(ctx, this_val);\n        len = js_typed_array_get_length_unsafe(ctx, obj);\n        if (len < 0)\n            goto exception;\n    } else {\n        obj = JS_ToObject(ctx, this_val);\n        if (js_get_length64(ctx, &len, obj))\n            goto exception;\n    }\n    func = argv[0];\n\n    if (check_function(ctx, func))\n        goto exception;\n\n    k = 0;\n    if (argc > 1) {\n        acc = JS_DupValue(ctx, argv[1]);\n    } else {\n        for(;;) {\n            if (k >= len) {\n                JS_ThrowTypeError(ctx, \"empty array\");\n                goto exception;\n            }\n            k1 = (special & special_reduceRight) ? len - k - 1 : k;\n            k++;\n            if (special & special_TA) {\n                acc = JS_GetPropertyInt64(ctx, obj, k1);\n                if (JS_IsException(acc))\n                    goto exception;\n                break;\n            } else {\n                present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);\n                if (present < 0)\n                    goto exception;\n                if (present)\n                    break;\n            }\n        }\n    }\n    for (; k < len; k++) {\n        k1 = (special & special_reduceRight) ? len - k - 1 : k;\n        if (special & special_TA) {\n            val = JS_GetPropertyInt64(ctx, obj, k1);\n            if (JS_IsException(val))\n                goto exception;\n            present = TRUE;\n        } else {\n            present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);\n            if (present < 0)\n                goto exception;\n        }\n        if (present) {\n            index_val = JS_NewInt64(ctx, k1);\n            if (JS_IsException(index_val))\n                goto exception;\n            args[0] = acc;\n            args[1] = val;\n            args[2] = index_val;\n            args[3] = obj;\n            acc1 = JS_Call(ctx, func, JS_UNDEFINED, 4, args);\n            JS_FreeValue(ctx, index_val);\n            JS_FreeValue(ctx, val);\n            val = JS_UNDEFINED;\n            if (JS_IsException(acc1))\n                goto exception;\n            JS_FreeValue(ctx, acc);\n            acc = acc1;\n        }\n    }\n    JS_FreeValue(ctx, obj);\n    return acc;\n\nexception:\n    JS_FreeValue(ctx, acc);\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_fill(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    JSValue obj;\n    int64_t len, start, end;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    start = 0;\n    if (argc > 1 && !JS_IsUndefined(argv[1])) {\n        if (JS_ToInt64Clamp(ctx, &start, argv[1], 0, len, len))\n            goto exception;\n    }\n\n    end = len;\n    if (argc > 2 && !JS_IsUndefined(argv[2])) {\n        if (JS_ToInt64Clamp(ctx, &end, argv[2], 0, len, len))\n            goto exception;\n    }\n\n    /* XXX: should special case fast arrays */\n    while (start < end) {\n        if (JS_SetPropertyInt64(ctx, obj, start,\n                                JS_DupValue(ctx, argv[0])) < 0)\n            goto exception;\n        start++;\n    }\n    return obj;\n\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_includes(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue obj, val;\n    int64_t len, n;\n    JSValue *arrp;\n    uint32_t count;\n    int res;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    res = FALSE;\n    if (len > 0) {\n        n = 0;\n        if (argc > 1) {\n            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))\n                goto exception;\n        }\n        if (js_get_fast_array(ctx, obj, &arrp, &count)) {\n            for (; n < count; n++) {\n                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),\n                                  JS_DupValue(ctx, arrp[n]),\n                                  JS_EQ_SAME_VALUE_ZERO)) {\n                    res = TRUE;\n                    goto done;\n                }\n            }\n        }\n        for (; n < len; n++) {\n            val = JS_GetPropertyInt64(ctx, obj, n);\n            if (JS_IsException(val))\n                goto exception;\n            if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val,\n                              JS_EQ_SAME_VALUE_ZERO)) {\n                res = TRUE;\n                break;\n            }\n        }\n    }\n done:\n    JS_FreeValue(ctx, obj);\n    return JS_NewBool(ctx, res);\n\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_indexOf(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue obj, val;\n    int64_t len, n, res;\n    JSValue *arrp;\n    uint32_t count;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    res = -1;\n    if (len > 0) {\n        n = 0;\n        if (argc > 1) {\n            if (JS_ToInt64Clamp(ctx, &n, argv[1], 0, len, len))\n                goto exception;\n        }\n        if (js_get_fast_array(ctx, obj, &arrp, &count)) {\n            for (; n < count; n++) {\n                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]),\n                                  JS_DupValue(ctx, arrp[n]), JS_EQ_STRICT)) {\n                    res = n;\n                    goto done;\n                }\n            }\n        }\n        for (; n < len; n++) {\n            int present = JS_TryGetPropertyInt64(ctx, obj, n, &val);\n            if (present < 0)\n                goto exception;\n            if (present) {\n                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {\n                    res = n;\n                    break;\n                }\n            }\n        }\n    }\n done:\n    JS_FreeValue(ctx, obj);\n    return JS_NewInt64(ctx, res);\n\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_lastIndexOf(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv)\n{\n    JSValue obj, val;\n    int64_t len, n, res;\n    int present;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    res = -1;\n    if (len > 0) {\n        n = len - 1;\n        if (argc > 1) {\n            if (JS_ToInt64Clamp(ctx, &n, argv[1], -1, len - 1, len))\n                goto exception;\n        }\n        /* XXX: should special case fast arrays */\n        for (; n >= 0; n--) {\n            present = JS_TryGetPropertyInt64(ctx, obj, n, &val);\n            if (present < 0)\n                goto exception;\n            if (present) {\n                if (js_strict_eq2(ctx, JS_DupValue(ctx, argv[0]), val, JS_EQ_STRICT)) {\n                    res = n;\n                    break;\n                }\n            }\n        }\n    }\n    JS_FreeValue(ctx, obj);\n    return JS_NewInt64(ctx, res);\n\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nenum {\n    ArrayFind,\n    ArrayFindIndex,\n    ArrayFindLast,\n    ArrayFindLastIndex,\n};\n\nstatic JSValue js_array_find(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv, int mode)\n{\n    JSValueConst func, this_arg;\n    JSValueConst args[3];\n    JSValue obj, val, index_val, res;\n    int64_t len, k, end;\n    int dir;\n\n    index_val = JS_UNDEFINED;\n    val = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    func = argv[0];\n    if (check_function(ctx, func))\n        goto exception;\n\n    this_arg = JS_UNDEFINED;\n    if (argc > 1)\n        this_arg = argv[1];\n\n    k = 0;\n    dir = 1;\n    end = len;\n    if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {\n        k = len - 1;\n        dir = -1;\n        end = -1;\n    }\n\n    // TODO(bnoordhuis) add fast path for fast arrays\n    for(; k != end; k += dir) {\n        index_val = JS_NewInt64(ctx, k);\n        if (JS_IsException(index_val))\n            goto exception;\n        val = JS_GetPropertyValue(ctx, obj, index_val);\n        if (JS_IsException(val))\n            goto exception;\n        args[0] = val;\n        args[1] = index_val;\n        args[2] = this_val;\n        res = JS_Call(ctx, func, this_arg, 3, args);\n        if (JS_IsException(res))\n            goto exception;\n        if (JS_ToBoolFree(ctx, res)) {\n            if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {\n                JS_FreeValue(ctx, val);\n                JS_FreeValue(ctx, obj);\n                return index_val;\n            } else {\n                JS_FreeValue(ctx, index_val);\n                JS_FreeValue(ctx, obj);\n                return val;\n            }\n        }\n        JS_FreeValue(ctx, val);\n        JS_FreeValue(ctx, index_val);\n    }\n    JS_FreeValue(ctx, obj);\n    if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)\n        return JS_NewInt32(ctx, -1);\n    else\n        return JS_UNDEFINED;\n\nexception:\n    JS_FreeValue(ctx, index_val);\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_toString(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue obj, method, ret;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    method = JS_GetProperty(ctx, obj, JS_ATOM_join);\n    if (JS_IsException(method)) {\n        ret = JS_EXCEPTION;\n    } else\n    if (!JS_IsFunction(ctx, method)) {\n        /* Use intrinsic Object.prototype.toString */\n        JS_FreeValue(ctx, method);\n        ret = js_object_toString(ctx, obj, 0, NULL);\n    } else {\n        ret = JS_CallFree(ctx, method, obj, 0, NULL);\n    }\n    JS_FreeValue(ctx, obj);\n    return ret;\n}\n\nstatic JSValue js_array_join(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv, int toLocaleString)\n{\n    JSValue obj, sep = JS_UNDEFINED, el;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p = NULL;\n    int64_t i, n;\n    int c;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &n, obj))\n        goto exception;\n\n    c = ',';    /* default separator */\n    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {\n        sep = JS_ToString(ctx, argv[0]);\n        if (JS_IsException(sep))\n            goto exception;\n        p = JS_VALUE_GET_STRING(sep);\n        if (p->len == 1 && !p->is_wide_char)\n            c = p->u.str8[0];\n        else\n            c = -1;\n    }\n    string_buffer_init(ctx, b, 0);\n\n    for(i = 0; i < n; i++) {\n        if (i > 0) {\n            if (c >= 0) {\n                string_buffer_putc8(b, c);\n            } else {\n                string_buffer_concat(b, p, 0, p->len);\n            }\n        }\n        el = JS_GetPropertyUint32(ctx, obj, i);\n        if (JS_IsException(el))\n            goto fail;\n        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {\n            if (toLocaleString) {\n                el = JS_ToLocaleStringFree(ctx, el);\n            }\n            if (string_buffer_concat_value_free(b, el))\n                goto fail;\n        }\n    }\n    JS_FreeValue(ctx, sep);\n    JS_FreeValue(ctx, obj);\n    return string_buffer_end(b);\n\nfail:\n    string_buffer_free(b);\n    JS_FreeValue(ctx, sep);\nexception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_pop(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv, int shift)\n{\n    JSValue obj, res = JS_UNDEFINED;\n    int64_t len, newLen;\n    JSValue *arrp;\n    uint32_t count32;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n    newLen = 0;\n    if (len > 0) {\n        newLen = len - 1;\n        /* Special case fast arrays */\n        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {\n            JSObject *p = JS_VALUE_GET_OBJ(obj);\n            if (shift) {\n                res = arrp[0];\n                memmove(arrp, arrp + 1, (count32 - 1) * sizeof(*arrp));\n                p->u.array.count--;\n            } else {\n                res = arrp[count32 - 1];\n                p->u.array.count--;\n            }\n        } else {\n            if (shift) {\n                res = JS_GetPropertyInt64(ctx, obj, 0);\n                if (JS_IsException(res))\n                    goto exception;\n                if (JS_CopySubArray(ctx, obj, 0, 1, len - 1, +1))\n                    goto exception;\n            } else {\n                res = JS_GetPropertyInt64(ctx, obj, newLen);\n                if (JS_IsException(res))\n                    goto exception;\n            }\n            if (JS_DeletePropertyInt64(ctx, obj, newLen, JS_PROP_THROW) < 0)\n                goto exception;\n        }\n    }\n    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)\n        goto exception;\n\n    JS_FreeValue(ctx, obj);\n    return res;\n\n exception:\n    JS_FreeValue(ctx, res);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_push(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv, int unshift)\n{\n    JSValue obj;\n    int i;\n    int64_t len, from, newLen;\n\n    if (likely(JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT && !unshift)) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (likely(p->class_id == JS_CLASS_ARRAY && p->fast_array &&\n                   can_extend_fast_array(p) &&\n                   JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT &&\n                   JS_VALUE_GET_INT(p->prop[0].u.value) == p->u.array.count &&\n                   (get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE) != 0)) {\n            /* fast case */\n            uint32_t new_len;\n            new_len = p->u.array.count + argc;\n            if (likely(new_len <= INT32_MAX)) {\n                if (unlikely(new_len > p->u.array.u1.size)) {\n                    if (expand_fast_array(ctx, p, new_len))\n                        return JS_EXCEPTION;\n                }\n                for(i = 0; i < argc; i++)\n                    p->u.array.u.values[p->u.array.count + i] = JS_DupValue(ctx, argv[i]);\n                p->prop[0].u.value = JS_NewInt32(ctx, new_len);\n                p->u.array.count = new_len;\n                return JS_NewInt32(ctx, new_len);\n            }\n        }\n    }\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n    newLen = len + argc;\n    if (newLen > MAX_SAFE_INTEGER) {\n        JS_ThrowTypeError(ctx, \"Array loo long\");\n        goto exception;\n    }\n    from = len;\n    if (unshift && argc > 0) {\n        if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))\n            goto exception;\n        from = 0;\n    }\n    for(i = 0; i < argc; i++) {\n        if (JS_SetPropertyInt64(ctx, obj, from + i,\n                                JS_DupValue(ctx, argv[i])) < 0)\n            goto exception;\n    }\n    if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)\n        goto exception;\n\n    JS_FreeValue(ctx, obj);\n    return JS_NewInt64(ctx, newLen);\n\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_reverse(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue obj, lval, hval;\n    JSValue *arrp;\n    int64_t len, l, h;\n    int l_present, h_present;\n    uint32_t count32;\n\n    lval = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    /* Special case fast arrays */\n    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {\n        uint32_t ll, hh;\n\n        if (count32 > 1) {\n            for (ll = 0, hh = count32 - 1; ll < hh; ll++, hh--) {\n                lval = arrp[ll];\n                arrp[ll] = arrp[hh];\n                arrp[hh] = lval;\n            }\n        }\n        return obj;\n    }\n\n    for (l = 0, h = len - 1; l < h; l++, h--) {\n        l_present = JS_TryGetPropertyInt64(ctx, obj, l, &lval);\n        if (l_present < 0)\n            goto exception;\n        h_present = JS_TryGetPropertyInt64(ctx, obj, h, &hval);\n        if (h_present < 0)\n            goto exception;\n        if (h_present) {\n            if (JS_SetPropertyInt64(ctx, obj, l, hval) < 0)\n                goto exception;\n\n            if (l_present) {\n                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {\n                    lval = JS_UNDEFINED;\n                    goto exception;\n                }\n                lval = JS_UNDEFINED;\n            } else {\n                if (JS_DeletePropertyInt64(ctx, obj, h, JS_PROP_THROW) < 0)\n                    goto exception;\n            }\n        } else {\n            if (l_present) {\n                if (JS_DeletePropertyInt64(ctx, obj, l, JS_PROP_THROW) < 0)\n                    goto exception;\n                if (JS_SetPropertyInt64(ctx, obj, h, lval) < 0) {\n                    lval = JS_UNDEFINED;\n                    goto exception;\n                }\n                lval = JS_UNDEFINED;\n            }\n        }\n    }\n    return obj;\n\n exception:\n    JS_FreeValue(ctx, lval);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\n// Note: a.toReversed() is a.slice().reverse() with the twist that a.slice()\n// leaves holes in sparse arrays intact whereas a.toReversed() replaces them\n// with undefined, thus in effect creating a dense array.\n// Does not use Array[@@species], always returns a base Array.\nstatic JSValue js_array_toReversed(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue arr, obj, ret, *arrp, *pval;\n    JSObject *p;\n    int64_t i, len;\n    uint32_t count32;\n\n    ret = JS_EXCEPTION;\n    arr = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    arr = js_allocate_fast_array(ctx, len);\n    if (JS_IsException(arr))\n        goto exception;\n\n    if (len > 0) {\n        p = JS_VALUE_GET_OBJ(arr);\n\n        i = len - 1;\n        pval = p->u.array.u.values;\n        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {\n            for (; i >= 0; i--, pval++)\n                *pval = JS_DupValue(ctx, arrp[i]);\n        } else {\n            // Query order is observable; test262 expects descending order.\n            for (; i >= 0; i--, pval++) {\n                if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {\n                    // Exception; initialize remaining elements.\n                    for (; i >= 0; i--, pval++)\n                        *pval = JS_UNDEFINED;\n                    goto exception;\n                }\n            }\n        }\n\n        if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)\n            goto exception;\n    }\n\n    ret = arr;\n    arr = JS_UNDEFINED;\n\nexception:\n    JS_FreeValue(ctx, arr);\n    JS_FreeValue(ctx, obj);\n    return ret;\n}\n\nstatic JSValue js_array_slice(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int splice)\n{\n    JSValue obj, arr, val, len_val;\n    int64_t len, start, k, final, n, count, del_count, new_len;\n    int kPresent;\n    JSValue *arrp;\n    uint32_t count32, i, item_count;\n\n    arr = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))\n        goto exception;\n\n    if (splice) {\n        if (argc == 0) {\n            item_count = 0;\n            del_count = 0;\n        } else\n        if (argc == 1) {\n            item_count = 0;\n            del_count = len - start;\n        } else {\n            item_count = argc - 2;\n            if (JS_ToInt64Clamp(ctx, &del_count, argv[1], 0, len - start, 0))\n                goto exception;\n        }\n        if (len + item_count - del_count > MAX_SAFE_INTEGER) {\n            JS_ThrowTypeError(ctx, \"Array loo long\");\n            goto exception;\n        }\n        count = del_count;\n    } else {\n        item_count = 0; /* avoid warning */\n        final = len;\n        if (!JS_IsUndefined(argv[1])) {\n            if (JS_ToInt64Clamp(ctx, &final, argv[1], 0, len, len))\n                goto exception;\n        }\n        count = max_int64(final - start, 0);\n    }\n    len_val = JS_NewInt64(ctx, count);\n    arr = JS_ArraySpeciesCreate(ctx, obj, len_val);\n    JS_FreeValue(ctx, len_val);\n    if (JS_IsException(arr))\n        goto exception;\n\n    k = start;\n    final = start + count;\n    n = 0;\n    /* The fast array test on arr ensures that\n       JS_CreateDataPropertyUint32() won't modify obj in case arr is\n       an exotic object */\n    /* Special case fast arrays */\n    if (js_get_fast_array(ctx, obj, &arrp, &count32) &&\n        js_is_fast_array(ctx, arr)) {\n        /* XXX: should share code with fast array constructor */\n        for (; k < final && k < count32; k++, n++) {\n            if (JS_CreateDataPropertyUint32(ctx, arr, n, JS_DupValue(ctx, arrp[k]), JS_PROP_THROW) < 0)\n                goto exception;\n        }\n    }\n    /* Copy the remaining elements if any (handle case of inherited properties) */\n    for (; k < final; k++, n++) {\n        kPresent = JS_TryGetPropertyInt64(ctx, obj, k, &val);\n        if (kPresent < 0)\n            goto exception;\n        if (kPresent) {\n            if (JS_CreateDataPropertyUint32(ctx, arr, n, val, JS_PROP_THROW) < 0)\n                goto exception;\n        }\n    }\n    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, n)) < 0)\n        goto exception;\n\n    if (splice) {\n        new_len = len + item_count - del_count;\n        if (item_count != del_count) {\n            if (JS_CopySubArray(ctx, obj, start + item_count,\n                                start + del_count, len - (start + del_count),\n                                item_count <= del_count ? +1 : -1) < 0)\n                goto exception;\n\n            for (k = len; k-- > new_len; ) {\n                if (JS_DeletePropertyInt64(ctx, obj, k, JS_PROP_THROW) < 0)\n                    goto exception;\n            }\n        }\n        for (i = 0; i < item_count; i++) {\n            if (JS_SetPropertyInt64(ctx, obj, start + i, JS_DupValue(ctx, argv[i + 2])) < 0)\n                goto exception;\n        }\n        if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, new_len)) < 0)\n            goto exception;\n    }\n    JS_FreeValue(ctx, obj);\n    return arr;\n\n exception:\n    JS_FreeValue(ctx, obj);\n    JS_FreeValue(ctx, arr);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_toSpliced(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValue arr, obj, ret, *arrp, *pval, *last;\n    JSObject *p;\n    int64_t i, j, len, newlen, start, add, del;\n    uint32_t count32;\n\n    pval = NULL;\n    last = NULL;\n    ret = JS_EXCEPTION;\n    arr = JS_UNDEFINED;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    start = 0;\n    if (argc > 0)\n        if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))\n            goto exception;\n\n    del = 0;\n    if (argc > 0)\n        del = len - start;\n    if (argc > 1)\n        if (JS_ToInt64Clamp(ctx, &del, argv[1], 0, del, 0))\n            goto exception;\n\n    add = 0;\n    if (argc > 2)\n        add = argc - 2;\n\n    newlen = len + add - del;\n    if (newlen > MAX_SAFE_INTEGER) {\n        JS_ThrowTypeError(ctx, \"invalid array length\");\n        goto exception;\n    }\n\n    arr = js_allocate_fast_array(ctx, newlen);\n    if (JS_IsException(arr))\n        goto exception;\n\n    if (newlen <= 0)\n        goto done;\n\n    p = JS_VALUE_GET_OBJ(arr);\n    pval = &p->u.array.u.values[0];\n    last = &p->u.array.u.values[newlen];\n\n    if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {\n        for (i = 0; i < start; i++, pval++)\n            *pval = JS_DupValue(ctx, arrp[i]);\n        for (j = 0; j < add; j++, pval++)\n            *pval = JS_DupValue(ctx, argv[2 + j]);\n        for (i += del; i < len; i++, pval++)\n            *pval = JS_DupValue(ctx, arrp[i]);\n    } else {\n        for (i = 0; i < start; i++, pval++)\n            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))\n                goto exception;\n        for (j = 0; j < add; j++, pval++)\n            *pval = JS_DupValue(ctx, argv[2 + j]);\n        for (i += del; i < len; i++, pval++)\n            if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval))\n                goto exception;\n    }\n\n    assert(pval == last);\n\n    if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, newlen)) < 0)\n        goto exception;\n\ndone:\n    ret = arr;\n    arr = JS_UNDEFINED;\n\nexception:\n    while (pval != last)\n        *pval++ = JS_UNDEFINED;\n\n    JS_FreeValue(ctx, arr);\n    JS_FreeValue(ctx, obj);\n    return ret;\n}\n\nstatic JSValue js_array_copyWithin(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue obj;\n    int64_t len, from, to, final, count;\n\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    if (JS_ToInt64Clamp(ctx, &to, argv[0], 0, len, len))\n        goto exception;\n\n    if (JS_ToInt64Clamp(ctx, &from, argv[1], 0, len, len))\n        goto exception;\n\n    final = len;\n    if (argc > 2 && !JS_IsUndefined(argv[2])) {\n        if (JS_ToInt64Clamp(ctx, &final, argv[2], 0, len, len))\n            goto exception;\n    }\n\n    count = min_int64(final - from, len - to);\n\n    if (JS_CopySubArray(ctx, obj, to, from, count,\n                        (from < to && to < from + count) ? -1 : +1))\n        goto exception;\n\n    return obj;\n\n exception:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,\n                                   JSValueConst source, int64_t sourceLen,\n                                   int64_t targetIndex, int depth,\n                                   JSValueConst mapperFunction,\n                                   JSValueConst thisArg)\n{\n    JSValue element;\n    int64_t sourceIndex, elementLen;\n    int present, is_array;\n\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        JS_ThrowStackOverflow(ctx);\n        return -1;\n    }\n\n    for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {\n        present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);\n        if (present < 0)\n            return -1;\n        if (!present)\n            continue;\n        if (!JS_IsUndefined(mapperFunction)) {\n            JSValueConst args[3] = { element, JS_NewInt64(ctx, sourceIndex), source };\n            element = JS_Call(ctx, mapperFunction, thisArg, 3, args);\n            JS_FreeValue(ctx, (JSValue)args[0]);\n            JS_FreeValue(ctx, (JSValue)args[1]);\n            if (JS_IsException(element))\n                return -1;\n        }\n        if (depth > 0) {\n            is_array = JS_IsArray(ctx, element);\n            if (is_array < 0)\n                goto fail;\n            if (is_array) {\n                if (js_get_length64(ctx, &elementLen, element) < 0)\n                    goto fail;\n                targetIndex = JS_FlattenIntoArray(ctx, target, element,\n                                                  elementLen, targetIndex,\n                                                  depth - 1,\n                                                  JS_UNDEFINED, JS_UNDEFINED);\n                if (targetIndex < 0)\n                    goto fail;\n                JS_FreeValue(ctx, element);\n                continue;\n            }\n        }\n        if (targetIndex >= MAX_SAFE_INTEGER) {\n            JS_ThrowTypeError(ctx, \"Array too long\");\n            goto fail;\n        }\n        if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,\n                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n            return -1;\n        targetIndex++;\n    }\n    return targetIndex;\n\nfail:\n    JS_FreeValue(ctx, element);\n    return -1;\n}\n\nstatic JSValue js_array_flatten(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv, int map)\n{\n    JSValue obj, arr;\n    JSValueConst mapperFunction, thisArg;\n    int64_t sourceLen;\n    int depthNum;\n\n    arr = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &sourceLen, obj))\n        goto exception;\n\n    depthNum = 1;\n    mapperFunction = JS_UNDEFINED;\n    thisArg = JS_UNDEFINED;\n    if (map) {\n        mapperFunction = argv[0];\n        if (argc > 1) {\n            thisArg = argv[1];\n        }\n        if (check_function(ctx, mapperFunction))\n            goto exception;\n    } else {\n        if (argc > 0 && !JS_IsUndefined(argv[0])) {\n            if (JS_ToInt32Sat(ctx, &depthNum, argv[0]) < 0)\n                goto exception;\n        }\n    }\n    arr = JS_ArraySpeciesCreate(ctx, obj, JS_NewInt32(ctx, 0));\n    if (JS_IsException(arr))\n        goto exception;\n    if (JS_FlattenIntoArray(ctx, arr, obj, sourceLen, 0, depthNum,\n                            mapperFunction, thisArg) < 0)\n        goto exception;\n    JS_FreeValue(ctx, obj);\n    return arr;\n\nexception:\n    JS_FreeValue(ctx, obj);\n    JS_FreeValue(ctx, arr);\n    return JS_EXCEPTION;\n}\n\n/* Array sort */\n\ntypedef struct ValueSlot {\n    JSValue val;\n    JSString *str;\n    int64_t pos;\n} ValueSlot;\n\nstruct array_sort_context {\n    JSContext *ctx;\n    int exception;\n    int has_method;\n    JSValueConst method;\n};\n\nstatic int js_array_cmp_generic(const void *a, const void *b, void *opaque) {\n    struct array_sort_context *psc = opaque;\n    JSContext *ctx = psc->ctx;\n    JSValueConst argv[2];\n    JSValue res;\n    ValueSlot *ap = (ValueSlot *)(void *)a;\n    ValueSlot *bp = (ValueSlot *)(void *)b;\n    int cmp;\n\n    if (psc->exception)\n        return 0;\n\n    if (psc->has_method) {\n        /* custom sort function is specified as returning 0 for identical\n         * objects: avoid method call overhead.\n         */\n        if (!memcmp(&ap->val, &bp->val, sizeof(ap->val)))\n            goto cmp_same;\n        argv[0] = ap->val;\n        argv[1] = bp->val;\n        res = JS_Call(ctx, psc->method, JS_UNDEFINED, 2, argv);\n        if (JS_IsException(res))\n            goto exception;\n        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {\n            int val = JS_VALUE_GET_INT(res);\n            cmp = (val > 0) - (val < 0);\n        } else {\n            double val;\n            if (JS_ToFloat64Free(ctx, &val, res) < 0)\n                goto exception;\n            cmp = (val > 0) - (val < 0);\n        }\n    } else {\n        /* Not supposed to bypass ToString even for identical objects as\n         * tested in test262/test/built-ins/Array/prototype/sort/bug_596_1.js\n         */\n        if (!ap->str) {\n            JSValue str = JS_ToString(ctx, ap->val);\n            if (JS_IsException(str))\n                goto exception;\n            ap->str = JS_VALUE_GET_STRING(str);\n        }\n        if (!bp->str) {\n            JSValue str = JS_ToString(ctx, bp->val);\n            if (JS_IsException(str))\n                goto exception;\n            bp->str = JS_VALUE_GET_STRING(str);\n        }\n        cmp = js_string_compare(ctx, ap->str, bp->str);\n    }\n    if (cmp != 0)\n        return cmp;\ncmp_same:\n    /* make sort stable: compare array offsets */\n    return (ap->pos > bp->pos) - (ap->pos < bp->pos);\n\nexception:\n    psc->exception = 1;\n    return 0;\n}\n\nstatic JSValue js_array_sort(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    struct array_sort_context asc = { ctx, 0, 0, argv[0] };\n    JSValue obj = JS_UNDEFINED;\n    ValueSlot *array = NULL;\n    size_t array_size = 0, pos = 0, n = 0;\n    int64_t i, len, undefined_count = 0;\n    int present;\n\n    if (!JS_IsUndefined(asc.method)) {\n        if (check_function(ctx, asc.method))\n            goto exception;\n        asc.has_method = 1;\n    }\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    /* XXX: should special case fast arrays */\n    for (i = 0; i < len; i++) {\n        if (pos >= array_size) {\n            size_t new_size, slack;\n            ValueSlot *new_array;\n            new_size = (array_size + (array_size >> 1) + 31) & ~15;\n            new_array = js_realloc2(ctx, array, new_size * sizeof(*array), &slack);\n            if (new_array == NULL)\n                goto exception;\n            new_size += slack / sizeof(*new_array);\n            array = new_array;\n            array_size = new_size;\n        }\n        present = JS_TryGetPropertyInt64(ctx, obj, i, &array[pos].val);\n        if (present < 0)\n            goto exception;\n        if (present == 0)\n            continue;\n        if (JS_IsUndefined(array[pos].val)) {\n            undefined_count++;\n            continue;\n        }\n        array[pos].str = NULL;\n        array[pos].pos = i;\n        pos++;\n    }\n    rqsort(array, pos, sizeof(*array), js_array_cmp_generic, &asc);\n    if (asc.exception)\n        goto exception;\n\n    /* XXX: should special case fast arrays */\n    while (n < pos) {\n        if (array[n].str)\n            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));\n        if (array[n].pos == n) {\n            JS_FreeValue(ctx, array[n].val);\n        } else {\n            if (JS_SetPropertyInt64(ctx, obj, n, array[n].val) < 0) {\n                n++;\n                goto exception;\n            }\n        }\n        n++;\n    }\n    js_free(ctx, array);\n    for (i = n; undefined_count-- > 0; i++) {\n        if (JS_SetPropertyInt64(ctx, obj, i, JS_UNDEFINED) < 0)\n            goto fail;\n    }\n    for (; i < len; i++) {\n        if (JS_DeletePropertyInt64(ctx, obj, i, JS_PROP_THROW) < 0)\n            goto fail;\n    }\n    return obj;\n\nexception:\n    for (; n < pos; n++) {\n        JS_FreeValue(ctx, array[n].val);\n        if (array[n].str)\n            JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, array[n].str));\n    }\n    js_free(ctx, array);\nfail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\n// Note: a.toSorted() is a.slice().sort() with the twist that a.slice()\n// leaves holes in sparse arrays intact whereas a.toSorted() replaces them\n// with undefined, thus in effect creating a dense array.\n// Does not use Array[@@species], always returns a base Array.\nstatic JSValue js_array_toSorted(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue arr, obj, ret, *arrp, *pval;\n    JSObject *p;\n    int64_t i, len;\n    uint32_t count32;\n    int ok;\n\n    ok = JS_IsUndefined(argv[0]) || JS_IsFunction(ctx, argv[0]);\n    if (!ok)\n        return JS_ThrowTypeError(ctx, \"not a function\");\n\n    ret = JS_EXCEPTION;\n    arr = JS_UNDEFINED;\n    obj = JS_ToObject(ctx, this_val);\n    if (js_get_length64(ctx, &len, obj))\n        goto exception;\n\n    arr = js_allocate_fast_array(ctx, len);\n    if (JS_IsException(arr))\n        goto exception;\n\n    if (len > 0) {\n        p = JS_VALUE_GET_OBJ(arr);\n        i = 0;\n        pval = p->u.array.u.values;\n        if (js_get_fast_array(ctx, obj, &arrp, &count32) && count32 == len) {\n            for (; i < len; i++, pval++)\n                *pval = JS_DupValue(ctx, arrp[i]);\n        } else {\n            for (; i < len; i++, pval++) {\n                if (-1 == JS_TryGetPropertyInt64(ctx, obj, i, pval)) {\n                    for (; i < len; i++, pval++)\n                        *pval = JS_UNDEFINED;\n                    goto exception;\n                }\n            }\n        }\n\n        if (JS_SetProperty(ctx, arr, JS_ATOM_length, JS_NewInt64(ctx, len)) < 0)\n            goto exception;\n    }\n\n    ret = js_array_sort(ctx, arr, argc, argv);\n    if (JS_IsException(ret))\n        goto exception;\n    JS_FreeValue(ctx, ret);\n\n    ret = arr;\n    arr = JS_UNDEFINED;\n\nexception:\n    JS_FreeValue(ctx, arr);\n    JS_FreeValue(ctx, obj);\n    return ret;\n}\n\ntypedef struct JSArrayIteratorData {\n    JSValue obj;\n    JSIteratorKindEnum kind;\n    uint32_t idx;\n} JSArrayIteratorData;\n\nstatic void js_array_iterator_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSArrayIteratorData *it = p->u.array_iterator_data;\n    if (it) {\n        JS_FreeValueRT(rt, it->obj);\n        js_free_rt(rt, it);\n    }\n}\n\nstatic void js_array_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                   JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSArrayIteratorData *it = p->u.array_iterator_data;\n    if (it) {\n        JS_MarkValue(rt, it->obj, mark_func);\n    }\n}\n\nstatic JSValue js_create_array_iterator(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv, int magic)\n{\n    JSValue enum_obj, arr;\n    JSArrayIteratorData *it;\n    JSIteratorKindEnum kind;\n    int class_id;\n\n    kind = magic & 3;\n    if (magic & 4) {\n        /* string iterator case */\n        arr = JS_ToStringCheckObject(ctx, this_val);\n        class_id = JS_CLASS_STRING_ITERATOR;\n    } else {\n        arr = JS_ToObject(ctx, this_val);\n        class_id = JS_CLASS_ARRAY_ITERATOR;\n    }\n    if (JS_IsException(arr))\n        goto fail;\n    enum_obj = JS_NewObjectClass(ctx, class_id);\n    if (JS_IsException(enum_obj))\n        goto fail;\n    it = js_malloc(ctx, sizeof(*it));\n    if (!it)\n        goto fail1;\n    it->obj = arr;\n    it->kind = kind;\n    it->idx = 0;\n    JS_SetOpaque(enum_obj, it);\n    return enum_obj;\n fail1:\n    JS_FreeValue(ctx, enum_obj);\n fail:\n    JS_FreeValue(ctx, arr);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_array_iterator_next(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv,\n                                      BOOL *pdone, int magic)\n{\n    JSArrayIteratorData *it;\n    uint32_t len, idx;\n    JSValue val, obj;\n    JSObject *p;\n\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_ITERATOR);\n    if (!it)\n        goto fail1;\n    if (JS_IsUndefined(it->obj))\n        goto done;\n    p = JS_VALUE_GET_OBJ(it->obj);\n    if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n        p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n        if (typed_array_is_oob(p)) {\n            JS_ThrowTypeErrorArrayBufferOOB(ctx);\n            goto fail1;\n        }\n        len = p->u.array.count;\n    } else {\n        if (js_get_length32(ctx, &len, it->obj)) {\n        fail1:\n            *pdone = FALSE;\n            return JS_EXCEPTION;\n        }\n    }\n    idx = it->idx;\n    if (idx >= len) {\n        JS_FreeValue(ctx, it->obj);\n        it->obj = JS_UNDEFINED;\n    done:\n        *pdone = TRUE;\n        return JS_UNDEFINED;\n    }\n    it->idx = idx + 1;\n    *pdone = FALSE;\n    if (it->kind == JS_ITERATOR_KIND_KEY) {\n        return JS_NewUint32(ctx, idx);\n    } else {\n        val = JS_GetPropertyUint32(ctx, it->obj, idx);\n        if (JS_IsException(val))\n            return JS_EXCEPTION;\n        if (it->kind == JS_ITERATOR_KIND_VALUE) {\n            return val;\n        } else {\n            JSValueConst args[2];\n            JSValue num;\n            num = JS_NewUint32(ctx, idx);\n            args[0] = num;\n            args[1] = val;\n            obj = js_create_array(ctx, 2, args);\n            JS_FreeValue(ctx, val);\n            JS_FreeValue(ctx, num);\n            return obj;\n        }\n    }\n}\n\n/* Iterator Wrap */\n\ntypedef struct JSIteratorWrapData {\n    JSValue wrapped_iter;\n    JSValue wrapped_next;\n} JSIteratorWrapData;\n\nstatic void js_iterator_wrap_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSIteratorWrapData *it = p->u.iterator_wrap_data;\n    if (it) {\n        JS_FreeValueRT(rt, it->wrapped_iter);\n        JS_FreeValueRT(rt, it->wrapped_next);\n        js_free_rt(rt, it);\n    }\n}\n\nstatic void js_iterator_wrap_mark(JSRuntime *rt, JSValueConst val,\n                                  JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSIteratorWrapData *it = p->u.iterator_wrap_data;\n    if (it) {\n        JS_MarkValue(rt, it->wrapped_iter, mark_func);\n        JS_MarkValue(rt, it->wrapped_next, mark_func);\n    }\n}\n\nstatic JSValue js_iterator_wrap_next(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv,\n                                     int *pdone, int magic)\n{\n    JSIteratorWrapData *it;\n    JSValue method, ret;\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_WRAP);\n    if (!it)\n        return JS_EXCEPTION;\n    if (magic == GEN_MAGIC_NEXT) {\n        return JS_IteratorNext(ctx, it->wrapped_iter, it->wrapped_next, 0, NULL, pdone);\n    } else {\n        method = JS_GetProperty(ctx, it->wrapped_iter, JS_ATOM_return);\n        if (JS_IsException(method))\n            return JS_EXCEPTION;\n        if (JS_IsNull(method) || JS_IsUndefined(method)) {\n            *pdone = TRUE;\n            return JS_UNDEFINED;\n        }\n        ret = JS_IteratorNext2(ctx, it->wrapped_iter, method, 0, NULL, pdone);\n        JS_FreeValue(ctx, method);\n        return ret;\n    }\n}\n\nstatic const JSCFunctionListEntry js_iterator_wrap_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_iterator_wrap_next, GEN_MAGIC_NEXT ),\n    JS_ITERATOR_NEXT_DEF(\"return\", 0, js_iterator_wrap_next, GEN_MAGIC_RETURN ),\n};\n\n/* Iterator */\n\nstatic JSValue js_iterator_constructor_getset(JSContext *ctx,\n                                              JSValueConst this_val,\n                                              int argc, JSValueConst *argv,\n                                              int magic,\n                                              JSValue *func_data)\n{\n    int ret;\n\n    if (argc > 0) { // if setter\n        if (!JS_IsObject(argv[0]))\n            return JS_ThrowTypeErrorNotAnObject(ctx);\n        ret = JS_DefinePropertyValue(ctx, this_val, JS_ATOM_constructor,\n                                     JS_DupValue(ctx, argv[0]),\n                                     JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n        if (ret < 0)\n            return JS_EXCEPTION;\n        return JS_UNDEFINED;\n    } else {\n        return JS_DupValue(ctx, func_data[0]);\n    }\n}\n\nstatic JSValue js_iterator_constructor(JSContext *ctx, JSValueConst new_target,\n                                       int argc, JSValueConst *argv)\n{\n    JSObject *p;\n\n    if (JS_TAG_OBJECT != JS_VALUE_GET_TAG(new_target))\n        return JS_ThrowTypeError(ctx, \"constructor requires 'new'\");\n    p = JS_VALUE_GET_OBJ(new_target);\n    if (p->class_id == JS_CLASS_C_FUNCTION &&\n        p->u.cfunc.c_function.generic == js_iterator_constructor) {\n        return JS_ThrowTypeError(ctx, \"abstract class not constructable\");\n    }\n    return js_create_from_ctor(ctx, new_target, JS_CLASS_ITERATOR);\n}\n\n// note: deliberately doesn't use space-saving bit fields for\n// |index|, |count| and |running| because tcc miscompiles them\ntypedef struct JSIteratorConcatData {\n    int index, count;             // elements (not pairs!) in values[] array\n    BOOL running;\n    JSValue iter, next, values[]; // array of (object, method) pairs\n} JSIteratorConcatData;\n\nstatic void js_iterator_concat_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSIteratorConcatData *it = p->u.iterator_concat_data;\n    if (it) {\n        JS_FreeValueRT(rt, it->iter);\n        JS_FreeValueRT(rt, it->next);\n        for (int i = it->index; i < it->count; i++)\n            JS_FreeValueRT(rt, it->values[i]);\n        js_free_rt(rt, it);\n    }\n}\n\nstatic void js_iterator_concat_mark(JSRuntime *rt, JSValueConst val,\n                                    JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSIteratorConcatData *it = p->u.iterator_concat_data;\n    if (it) {\n        JS_MarkValue(rt, it->iter, mark_func);\n        JS_MarkValue(rt, it->next, mark_func);\n        for (int i = it->index; i < it->count; i++)\n            JS_MarkValue(rt, it->values[i], mark_func);\n    }\n}\n\nstatic JSValue js_iterator_concat_next(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv,\n                                       int *pdone, int magic)\n{\n    JSValue iter, item, next, val, *obj, *meth, ret;\n    JSIteratorConcatData *it;\n    int done;\n\n    *pdone = FALSE;\n\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_CONCAT);\n    if (!it)\n        return JS_EXCEPTION;\n    if (it->running)\n        return JS_ThrowTypeError(ctx, \"already running\");\n\n    it->running = TRUE;\n    for(;;) {\n        if (it->index >= it->count) {\n            *pdone = TRUE;\n            ret = JS_UNDEFINED;\n            break;\n        }\n        obj = &it->values[it->index + 0];\n        meth = &it->values[it->index + 1];\n        iter = it->iter;\n        if (JS_IsUndefined(iter)) {\n            iter = JS_GetIterator2(ctx, *obj, *meth);\n            if (JS_IsException(iter))\n                goto fail;\n            it->iter = iter;\n        }\n        next = it->next;\n        if (JS_IsUndefined(next)) {\n            next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n            if (JS_IsException(next))\n                goto fail;\n            it->next = next;\n        }\n        item = JS_IteratorNext2(ctx, iter, next, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto fail;\n        if (done == 0) {\n            ret = item;\n            break;\n        } else if (done == 2) {\n            val = JS_GetProperty(ctx, item, JS_ATOM_done);\n            if (JS_IsException(val)) {\n                JS_FreeValue(ctx, item);\n            fail:\n                ret = JS_EXCEPTION;\n                break;\n            }\n            done = JS_ToBoolFree(ctx, val);\n            if (done)\n                goto done_next;\n            ret = JS_GetProperty(ctx, item, JS_ATOM_value);\n            JS_FreeValue(ctx, item);\n            break;\n        } else {\n        done_next:\n            JS_FreeValue(ctx, item);\n            JS_FreeValue(ctx, iter);\n            JS_FreeValue(ctx, next);\n            it->iter = JS_UNDEFINED;\n            it->next = JS_UNDEFINED;\n            JS_FreeValue(ctx, *meth);\n            JS_FreeValue(ctx, *obj);\n            it->index += 2;\n        }\n    }\n    it->running = FALSE;\n    return ret;\n}\n\nstatic JSValue js_iterator_concat_return(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    JSIteratorConcatData *it;\n    JSValue ret;\n\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_CONCAT);\n    if (!it)\n        return JS_EXCEPTION;\n    if (it->running)\n        return JS_ThrowTypeError(ctx, \"already running\");\n    ret = JS_UNDEFINED;\n    if (!JS_IsUndefined(it->iter)) {\n        it->running = TRUE;\n        ret = JS_GetProperty(ctx, it->iter, JS_ATOM_return);\n        if (JS_IsException(ret)) {\n            it->running = FALSE;\n            return JS_EXCEPTION;\n        }\n        ret = JS_CallFree(ctx, ret, it->iter, 0, NULL);\n        it->running = FALSE;\n    }\n    while (it->index < it->count)\n        JS_FreeValue(ctx, it->values[it->index++]);\n    JS_FreeValue(ctx, it->iter);\n    JS_FreeValue(ctx, it->next);\n    it->iter = JS_UNDEFINED;\n    it->next = JS_UNDEFINED;\n    return ret;\n}\n\nstatic const JSCFunctionListEntry js_iterator_concat_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_iterator_concat_next, 0 ),\n    JS_CFUNC_DEF(\"return\", 0, js_iterator_concat_return ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Iterator Concat\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic JSValue js_iterator_concat(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSIteratorConcatData *it;\n    JSValue obj, method;\n\n    it = js_malloc(ctx, sizeof(*it) + 2*argc * sizeof(it->values[0]));\n    if (!it)\n        return JS_EXCEPTION;\n    it->running = FALSE;\n    it->index = 0;\n    it->count = 0;\n    it->iter = JS_UNDEFINED;\n    it->next = JS_UNDEFINED;\n    for (int i = 0; i < argc; i++) {\n        JSValueConst obj = argv[i];\n        if (!JS_IsObject(obj)) {\n            JS_ThrowTypeErrorNotAnObject(ctx);\n            goto fail;\n        }\n        method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);\n        if (JS_IsException(method))\n            goto fail;\n        if (!JS_IsFunction(ctx, method)) {\n            JS_ThrowTypeError(ctx, \"not a function\");\n            JS_FreeValue(ctx, method);\n            goto fail;\n        }\n        it->values[it->count++] = JS_DupValue(ctx, obj);\n        it->values[it->count++] = method;\n    }\n    obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_CONCAT);\n    if (JS_IsException(obj))\n        goto fail;\n    JS_SetOpaque(obj, it);\n    return obj;\nfail:\n    for (int i = 0; i < it->count; i++)\n        JS_FreeValue(ctx, it->values[i]);\n    js_free(ctx, it);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_iterator_from(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValueConst obj = argv[0];\n    JSValue method, iter, wrapper;\n    JSIteratorWrapData *it;\n    int ret;\n\n    if (!JS_IsObject(obj)) {\n        if (!JS_IsString(obj))\n            return JS_ThrowTypeError(ctx, \"Iterator.from called on non-object\");\n    }\n    method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);\n    if (JS_IsException(method))\n        return JS_EXCEPTION;\n    if (JS_IsNull(method) || JS_IsUndefined(method)) {\n        iter = JS_DupValue(ctx, obj);\n    } else {\n        iter = JS_GetIterator2(ctx, obj, method);\n        JS_FreeValue(ctx, method);\n        if (JS_IsException(iter))\n            return JS_EXCEPTION;\n    }\n\n    wrapper = JS_UNDEFINED;\n    method = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(method))\n        goto fail;\n\n    ret = JS_OrdinaryIsInstanceOf(ctx, iter, ctx->iterator_ctor);\n    if (ret < 0)\n        goto fail;\n    if (ret) {\n        JS_FreeValue(ctx, method);\n        return iter;\n    }\n    \n    wrapper = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_WRAP);\n    if (JS_IsException(wrapper))\n        goto fail;\n    it = js_malloc(ctx, sizeof(*it));\n    if (!it)\n        goto fail;\n    it->wrapped_iter = iter;\n    it->wrapped_next = method;\n    JS_SetOpaque(wrapper, it);\n    return wrapper;\n\n fail:\n    JS_FreeValue(ctx, method);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, wrapper);\n    return JS_EXCEPTION;\n}\n\ntypedef enum JSIteratorHelperKindEnum {\n    JS_ITERATOR_HELPER_KIND_DROP,\n    JS_ITERATOR_HELPER_KIND_EVERY,\n    JS_ITERATOR_HELPER_KIND_FILTER,\n    JS_ITERATOR_HELPER_KIND_FIND,\n    JS_ITERATOR_HELPER_KIND_FLAT_MAP,\n    JS_ITERATOR_HELPER_KIND_FOR_EACH,\n    JS_ITERATOR_HELPER_KIND_MAP,\n    JS_ITERATOR_HELPER_KIND_SOME,\n    JS_ITERATOR_HELPER_KIND_TAKE,\n} JSIteratorHelperKindEnum;\n\ntypedef struct JSIteratorHelperData {\n    JSValue obj;\n    JSValue next;\n    JSValue func; // predicate (filter) or mapper (flatMap, map)\n    JSValue inner; // innerValue (flatMap)\n    int64_t count; // limit (drop, take) or counter (filter, map, flatMap)\n    JSIteratorHelperKindEnum kind : 8;\n    uint8_t executing : 1;\n    uint8_t done : 1;\n} JSIteratorHelperData;\n\nstatic JSValue js_create_iterator_helper(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv, int magic)\n{\n    JSValueConst func;\n    JSValue obj, method;\n    int64_t count;\n    JSIteratorHelperData *it;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    func = JS_UNDEFINED;\n    count = 0;\n\n    switch(magic) {\n    case JS_ITERATOR_HELPER_KIND_DROP:\n    case JS_ITERATOR_HELPER_KIND_TAKE:\n        {\n            JSValue v;\n            double dlimit;\n            v = JS_ToNumber(ctx, argv[0]);\n            if (JS_IsException(v))\n                goto fail;\n            // Check for Infinity.\n            if (JS_ToFloat64(ctx, &dlimit, v)) {\n                JS_FreeValue(ctx, v);\n                goto fail;\n            }\n            if (isnan(dlimit)) {\n                JS_FreeValue(ctx, v);\n                goto range_error;\n            }\n            if (!isfinite(dlimit)) {\n                JS_FreeValue(ctx, v);\n                if (dlimit < 0)\n                    goto range_error;\n                else\n                    count = MAX_SAFE_INTEGER;\n            } else {\n                v = JS_ToIntegerFree(ctx, v);\n                if (JS_IsException(v))\n                    goto fail;\n                if (JS_ToInt64Free(ctx, &count, v))\n                    goto fail;\n            }\n            if (count < 0)\n                goto range_error;\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_FILTER:\n    case JS_ITERATOR_HELPER_KIND_FLAT_MAP:\n    case JS_ITERATOR_HELPER_KIND_MAP:\n        {\n            func = argv[0];\n            if (check_function(ctx, func))\n                goto fail;\n        }\n        break;\n    default:\n        abort();\n        break;\n    }\n\n    method = JS_GetProperty(ctx, this_val, JS_ATOM_next);\n    if (JS_IsException(method))\n        goto fail;\n    obj = JS_NewObjectClass(ctx, JS_CLASS_ITERATOR_HELPER);\n    if (JS_IsException(obj)) {\n        JS_FreeValue(ctx, method);\n        goto fail;\n    }\n    it = js_malloc(ctx, sizeof(*it));\n    if (!it) {\n        JS_FreeValue(ctx, obj);\n        JS_FreeValue(ctx, method);\n        goto fail;\n    }\n    it->kind = magic;\n    it->obj = JS_DupValue(ctx, this_val);\n    it->func = JS_DupValue(ctx, func);\n    it->next = method;\n    it->inner = JS_UNDEFINED;\n    it->count = count;\n    it->executing = 0;\n    it->done = 0;\n    JS_SetOpaque(obj, it);\n    return obj;\nrange_error:\n    JS_ThrowRangeError(ctx, \"must be positive\");\nfail:\n    JS_IteratorClose(ctx, this_val, TRUE);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_iterator_proto_func(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv, int magic)\n{\n    JSValue item, method, ret, func, index_val, r;\n    JSValueConst args[2];\n    int64_t idx;\n    int done;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    func = JS_UNDEFINED;\n    method = JS_UNDEFINED;\n    \n    if (check_function(ctx, argv[0]))\n        goto fail;\n    func = JS_DupValue(ctx, argv[0]);\n    method = JS_GetProperty(ctx, this_val, JS_ATOM_next);\n    if (JS_IsException(method))\n        goto fail_no_close;\n\n    r = JS_UNDEFINED;\n\n    switch(magic) {\n    case JS_ITERATOR_HELPER_KIND_EVERY:\n        {\n            r = JS_TRUE;\n            for (idx = 0; /*empty*/; idx++) {\n                item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);\n                if (JS_IsException(item))\n                    goto fail_no_close;\n                if (done)\n                    break;\n                index_val = JS_NewInt64(ctx, idx);\n                args[0] = item;\n                args[1] = index_val;\n                ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);\n                JS_FreeValue(ctx, item);\n                JS_FreeValue(ctx, index_val);\n                if (JS_IsException(ret))\n                    goto fail;\n                if (!JS_ToBoolFree(ctx, ret)) {\n                    if (JS_IteratorClose(ctx, this_val, FALSE) < 0)\n                        r = JS_EXCEPTION;\n                    else\n                        r = JS_FALSE;\n                    break;\n                }\n                index_val = JS_UNDEFINED;\n                ret = JS_UNDEFINED;\n                item = JS_UNDEFINED;\n            }\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_FIND:\n        {\n            for (idx = 0; /*empty*/; idx++) {\n                item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);\n                if (JS_IsException(item))\n                    goto fail_no_close;\n                if (done)\n                    break;\n                index_val = JS_NewInt64(ctx, idx);\n                args[0] = item;\n                args[1] = index_val;\n                ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);\n                JS_FreeValue(ctx, index_val);\n                if (JS_IsException(ret)) {\n                    JS_FreeValue(ctx, item);\n                    goto fail;\n                }\n                if (JS_ToBoolFree(ctx, ret)) {\n                    if (JS_IteratorClose(ctx, this_val, FALSE) < 0) {\n                        JS_FreeValue(ctx, item);\n                        r = JS_EXCEPTION;\n                    } else {\n                        r = item;\n                    }\n                    break;\n                }\n                JS_FreeValue(ctx, item);\n                index_val = JS_UNDEFINED;\n                ret = JS_UNDEFINED;\n                item = JS_UNDEFINED;\n            }\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_FOR_EACH:\n        {\n            for (idx = 0; /*empty*/; idx++) {\n                item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);\n                if (JS_IsException(item))\n                    goto fail_no_close;\n                if (done)\n                    break;\n                index_val = JS_NewInt64(ctx, idx);\n                args[0] = item;\n                args[1] = index_val;\n                ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);\n                JS_FreeValue(ctx, item);\n                JS_FreeValue(ctx, index_val);\n                if (JS_IsException(ret))\n                    goto fail;\n                JS_FreeValue(ctx, ret);\n                index_val = JS_UNDEFINED;\n                ret = JS_UNDEFINED;\n                item = JS_UNDEFINED;\n            }\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_SOME:\n        {\n            r = JS_FALSE;\n            for (idx = 0; /*empty*/; idx++) {\n                item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);\n                if (JS_IsException(item))\n                    goto fail_no_close;\n                if (done)\n                    break;\n                index_val = JS_NewInt64(ctx, idx);\n                args[0] = item;\n                args[1] = index_val;\n                ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);\n                JS_FreeValue(ctx, item);\n                JS_FreeValue(ctx, index_val);\n                if (JS_IsException(ret))\n                    goto fail;\n                if (JS_ToBoolFree(ctx, ret)) {\n                    if (JS_IteratorClose(ctx, this_val, FALSE) < 0)\n                        r = JS_EXCEPTION;\n                    else\n                        r = JS_TRUE;\n                    break;\n                }\n                index_val = JS_UNDEFINED;\n                ret = JS_UNDEFINED;\n                item = JS_UNDEFINED;\n            }\n        }\n        break;\n    default:\n        abort();\n        break;\n    }\n\n    JS_FreeValue(ctx, func);\n    JS_FreeValue(ctx, method);\n    return r;\n fail:\n    JS_IteratorClose(ctx, this_val, TRUE);\n fail_no_close:\n    JS_FreeValue(ctx, func);\n    JS_FreeValue(ctx, method);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_iterator_proto_reduce(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv)\n{\n    JSValue item, method, ret, func, index_val, acc;\n    JSValueConst args[3];\n    int64_t idx;\n    int done;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    acc = JS_UNDEFINED;\n    func = JS_UNDEFINED;\n    method = JS_UNDEFINED;\n    if (check_function(ctx, argv[0]))\n        goto exception;\n    func = JS_DupValue(ctx, argv[0]);\n    method = JS_GetProperty(ctx, this_val, JS_ATOM_next);\n    if (JS_IsException(method))\n        goto exception;\n    if (argc > 1) {\n        acc = JS_DupValue(ctx, argv[1]);\n        idx = 0;\n    } else {\n        acc = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);\n        if (JS_IsException(acc))\n            goto exception_no_close;\n        if (done) {\n            JS_ThrowTypeError(ctx, \"empty iterator\");\n            goto exception;\n        }\n        idx = 1;\n    }\n    for (/* empty */; /*empty*/; idx++) {\n        item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto exception_no_close;\n        if (done)\n            break;\n        index_val = JS_NewInt64(ctx, idx);\n        args[0] = acc;\n        args[1] = item;\n        args[2] = index_val;\n        ret = JS_Call(ctx, func, JS_UNDEFINED, countof(args), args);\n        JS_FreeValue(ctx, item);\n        JS_FreeValue(ctx, index_val);\n        if (JS_IsException(ret))\n            goto exception;\n        JS_FreeValue(ctx, acc);\n        acc = ret;\n        index_val = JS_UNDEFINED;\n        ret = JS_UNDEFINED;\n        item = JS_UNDEFINED;\n    }\n    JS_FreeValue(ctx, func);\n    JS_FreeValue(ctx, method);\n    return acc;\n exception:\n    JS_IteratorClose(ctx, this_val, TRUE);\n exception_no_close:\n    JS_FreeValue(ctx, acc);\n    JS_FreeValue(ctx, func);\n    JS_FreeValue(ctx, method);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_iterator_proto_toArray(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    JSValue item, method, result;\n    int64_t idx;\n    int done;\n\n    result = JS_UNDEFINED;\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    method = JS_GetProperty(ctx, this_val, JS_ATOM_next);\n    if (JS_IsException(method))\n        return JS_EXCEPTION;\n    result = JS_NewArray(ctx);\n    if (JS_IsException(result))\n        goto exception;\n    for (idx = 0; /*empty*/; idx++) {\n        item = JS_IteratorNext(ctx, this_val, method, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto exception;\n        if (done)\n            break;\n        if (JS_DefinePropertyValueInt64(ctx, result, idx, item,\n                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n            goto exception;\n    }\n    if (JS_SetProperty(ctx, result, JS_ATOM_length, JS_NewUint32(ctx, idx)) < 0)\n        goto exception;\n    JS_FreeValue(ctx, method);\n    return result;\nexception:\n    JS_FreeValue(ctx, result);\n    JS_FreeValue(ctx, method);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_iterator_proto_iterator(JSContext *ctx, JSValueConst this_val,\n                                          int argc, JSValueConst *argv)\n{\n    return JS_DupValue(ctx, this_val);\n}\n\nstatic JSValue js_iterator_proto_get_toStringTag(JSContext *ctx, JSValueConst this_val)\n{\n    return JS_AtomToString(ctx, JS_ATOM_Iterator);\n}\n\nstatic JSValue js_iterator_proto_set_toStringTag(JSContext *ctx, JSValueConst this_val, JSValueConst val)\n{\n    int res;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_ITERATOR]))\n        return JS_ThrowTypeError(ctx, \"Cannot assign to read only property\");\n    res = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_Symbol_toStringTag);\n    if (res < 0)\n        return JS_EXCEPTION;\n    if (res) {\n        if (JS_SetProperty(ctx, this_val, JS_ATOM_Symbol_toStringTag, JS_DupValue(ctx, val)) < 0)\n            return JS_EXCEPTION;\n    } else {\n        if (JS_DefinePropertyValue(ctx, this_val, JS_ATOM_Symbol_toStringTag, JS_DupValue(ctx, val), JS_PROP_C_W_E) < 0)\n            return JS_EXCEPTION;\n    }\n    return JS_UNDEFINED;\n}\n\n/* Iterator Helper */\n\nstatic void js_iterator_helper_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSIteratorHelperData *it = p->u.iterator_helper_data;\n    if (it) {\n        JS_FreeValueRT(rt, it->obj);\n        JS_FreeValueRT(rt, it->func);\n        JS_FreeValueRT(rt, it->next);\n        JS_FreeValueRT(rt, it->inner);\n        js_free_rt(rt, it);\n    }\n}\n\nstatic void js_iterator_helper_mark(JSRuntime *rt, JSValueConst val,\n                                   JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSIteratorHelperData *it = p->u.iterator_helper_data;\n    if (it) {\n        JS_MarkValue(rt, it->obj, mark_func);\n        JS_MarkValue(rt, it->func, mark_func);\n        JS_MarkValue(rt, it->next, mark_func);\n        JS_MarkValue(rt, it->inner, mark_func);\n    }\n}\n\nstatic JSValue js_iterator_helper_next(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv,\n                                      int *pdone, int magic)\n{\n    JSIteratorHelperData *it;\n    JSValue ret;\n\n    *pdone = FALSE;\n\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_ITERATOR_HELPER);\n    if (!it)\n        return JS_EXCEPTION;\n    if (it->executing)\n        return JS_ThrowTypeError(ctx, \"cannot invoke a running iterator\");\n    if (it->done) {\n        *pdone = TRUE;\n        return JS_UNDEFINED;\n    }\n\n    it->executing = 1;\n\n    switch (it->kind) {\n    case JS_ITERATOR_HELPER_KIND_DROP:\n        {\n            JSValue item, method;\n            if (magic == GEN_MAGIC_NEXT) {\n                method = JS_DupValue(ctx, it->next);\n            } else {\n                method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);\n                if (JS_IsException(method))\n                    goto fail;\n            }\n            while (it->count > 0) {\n                it->count--;\n                item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);\n                if (JS_IsException(item)) {\n                    JS_FreeValue(ctx, method);\n                    goto fail_no_close;\n                }\n                JS_FreeValue(ctx, item);\n                if (magic == GEN_MAGIC_RETURN)\n                    *pdone = TRUE;\n                if (*pdone) {\n                    JS_FreeValue(ctx, method);\n                    ret = JS_UNDEFINED;\n                    goto done;\n                }\n            }\n\n            item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);\n            JS_FreeValue(ctx, method);\n            if (JS_IsException(item))\n                goto fail_no_close;\n            ret = item;\n            goto done;\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_FILTER:\n        {\n            JSValue item, method, selected, index_val;\n            JSValueConst args[2];\n            if (magic == GEN_MAGIC_NEXT) {\n                method = JS_DupValue(ctx, it->next);\n            } else {\n                method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);\n                if (JS_IsException(method))\n                    goto fail;\n            }\n        filter_again:\n            item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);\n            if (JS_IsException(item)) {\n                JS_FreeValue(ctx, method);\n                goto fail_no_close;\n            }\n            if (*pdone || magic == GEN_MAGIC_RETURN) {\n                JS_FreeValue(ctx, method);\n                ret = item;\n                goto done;\n            }\n            index_val = JS_NewInt64(ctx, it->count++);\n            args[0] = item;\n            args[1] = index_val;\n            selected = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);\n            JS_FreeValue(ctx, index_val);\n            if (JS_IsException(selected)) {\n                JS_FreeValue(ctx, item);\n                JS_FreeValue(ctx, method);\n                goto fail;\n            }\n            if (JS_ToBoolFree(ctx, selected)) {\n                JS_FreeValue(ctx, method);\n                ret = item;\n                goto done;\n            }\n            JS_FreeValue(ctx, item);\n            goto filter_again;\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_FLAT_MAP:\n        {\n            JSValue item, method, index_val, iter;\n            JSValueConst args[2];\n        flat_map_again:\n            if (JS_IsUndefined(it->inner)) {\n                if (magic == GEN_MAGIC_NEXT) {\n                    method = JS_DupValue(ctx, it->next);\n                } else {\n                    method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);\n                    if (JS_IsException(method))\n                        goto fail;\n                }\n                item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);\n                JS_FreeValue(ctx, method);\n                if (JS_IsException(item))\n                    goto fail_no_close;\n                if (*pdone || magic == GEN_MAGIC_RETURN) {\n                    ret = item;\n                    goto done;\n                }\n                index_val = JS_NewInt64(ctx, it->count++);\n                args[0] = item;\n                args[1] = index_val;\n                ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);\n                JS_FreeValue(ctx, item);\n                JS_FreeValue(ctx, index_val);\n                if (JS_IsException(ret))\n                    goto fail;\n                if (!JS_IsObject(ret)) {\n                    JS_FreeValue(ctx, ret);\n                    JS_ThrowTypeError(ctx, \"not an object\");\n                    goto fail;\n                }\n                method = JS_GetProperty(ctx, ret, JS_ATOM_Symbol_iterator);\n                if (JS_IsException(method)) {\n                    JS_FreeValue(ctx, ret);\n                    goto fail;\n                }\n                if (JS_IsNull(method) || JS_IsUndefined(method)) {\n                    JS_FreeValue(ctx, method);\n                    iter = ret;\n                } else {\n                    iter = JS_GetIterator2(ctx, ret, method);\n                    JS_FreeValue(ctx, method);\n                    JS_FreeValue(ctx, ret);\n                    if (JS_IsException(iter))\n                        goto fail;\n                }\n\n                it->inner = iter;\n            }\n\n            if (magic == GEN_MAGIC_NEXT)\n                method = JS_GetProperty(ctx, it->inner, JS_ATOM_next);\n            else\n                method = JS_GetProperty(ctx, it->inner, JS_ATOM_return);\n            if (JS_IsException(method)) {\n            inner_fail:\n                JS_IteratorClose(ctx, it->inner, FALSE);\n                JS_FreeValue(ctx, it->inner);\n                it->inner = JS_UNDEFINED;\n                goto fail;\n            }\n            if (magic == GEN_MAGIC_RETURN && (JS_IsUndefined(method) || JS_IsNull(method))) {\n                goto inner_end;\n            } else {\n                item = JS_IteratorNext(ctx, it->inner, method, 0, NULL, pdone);\n                JS_FreeValue(ctx, method);\n                if (JS_IsException(item))\n                    goto inner_fail;\n            }\n            if (*pdone) {\n            inner_end:\n                *pdone = FALSE; // The outer iterator must continue.\n                JS_IteratorClose(ctx, it->inner, FALSE);\n                JS_FreeValue(ctx, it->inner);\n                it->inner = JS_UNDEFINED;\n                goto flat_map_again;\n            }\n            ret = item;\n            goto done;\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_MAP:\n        {\n            JSValue item, method, index_val;\n            JSValueConst args[2];\n            if (magic == GEN_MAGIC_NEXT) {\n                method = JS_DupValue(ctx, it->next);\n            } else {\n                method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);\n                if (JS_IsException(method))\n                    goto fail;\n            }\n            item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);\n            JS_FreeValue(ctx, method);\n            if (JS_IsException(item))\n                goto fail_no_close;\n            if (*pdone || magic == GEN_MAGIC_RETURN) {\n                ret = item;\n                goto done;\n            }\n            index_val = JS_NewInt64(ctx, it->count++);\n            args[0] = item;\n            args[1] = index_val;\n            ret = JS_Call(ctx, it->func, JS_UNDEFINED, countof(args), args);\n            JS_FreeValue(ctx, index_val);\n            if (JS_IsException(ret))\n                goto fail;\n            goto done;\n        }\n        break;\n    case JS_ITERATOR_HELPER_KIND_TAKE:\n        {\n            JSValue item, method;\n            if (it->count > 0) {\n                if (magic == GEN_MAGIC_NEXT) {\n                    method = JS_DupValue(ctx, it->next);\n                } else {\n                    method = JS_GetProperty(ctx, it->obj, JS_ATOM_return);\n                    if (JS_IsException(method))\n                        goto fail;\n                }\n                it->count--;\n                item = JS_IteratorNext(ctx, it->obj, method, 0, NULL, pdone);\n                JS_FreeValue(ctx, method);\n                if (JS_IsException(item))\n                    goto fail_no_close;\n                ret = item;\n                goto done;\n            }\n\n            *pdone = TRUE;\n            if (JS_IteratorClose(ctx, it->obj, FALSE))\n                ret = JS_EXCEPTION;\n            else\n                ret = JS_UNDEFINED;\n            goto done;\n        }\n        break;\n    default:\n        abort();\n    }\n\n done:\n    it->done = magic == GEN_MAGIC_NEXT ? *pdone : 1;\n    it->executing = 0;\n    return ret;\n fail:\n    /* close the iterator object, preserving pending exception */\n    JS_IteratorClose(ctx, it->obj, TRUE);\n fail_no_close:\n    ret = JS_EXCEPTION;\n    goto done;\n}\n\nstatic const JSCFunctionListEntry js_iterator_funcs[] = {\n    JS_CFUNC_DEF(\"concat\", 0, js_iterator_concat ),\n    JS_CFUNC_DEF(\"from\", 1, js_iterator_from ),\n};\n\nstatic const JSCFunctionListEntry js_iterator_proto_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"drop\", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_DROP ),\n    JS_CFUNC_MAGIC_DEF(\"filter\", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FILTER ),\n    JS_CFUNC_MAGIC_DEF(\"flatMap\", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_FLAT_MAP ),\n    JS_CFUNC_MAGIC_DEF(\"map\", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_MAP ),\n    JS_CFUNC_MAGIC_DEF(\"take\", 1, js_create_iterator_helper, JS_ITERATOR_HELPER_KIND_TAKE ),\n    JS_CFUNC_MAGIC_DEF(\"every\", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_EVERY ),\n    JS_CFUNC_MAGIC_DEF(\"find\", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FIND),\n    JS_CFUNC_MAGIC_DEF(\"forEach\", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_FOR_EACH ),\n    JS_CFUNC_MAGIC_DEF(\"some\", 1, js_iterator_proto_func, JS_ITERATOR_HELPER_KIND_SOME ),\n    JS_CFUNC_DEF(\"reduce\", 1, js_iterator_proto_reduce ),\n    JS_CFUNC_DEF(\"toArray\", 0, js_iterator_proto_toArray ),\n    JS_CFUNC_DEF(\"[Symbol.iterator]\", 0, js_iterator_proto_iterator ),\n    JS_CGETSET_DEF(\"[Symbol.toStringTag]\", js_iterator_proto_get_toStringTag, js_iterator_proto_set_toStringTag),\n};\n\nstatic const JSCFunctionListEntry js_iterator_helper_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_iterator_helper_next, GEN_MAGIC_NEXT ),\n    JS_ITERATOR_NEXT_DEF(\"return\", 0, js_iterator_helper_next, GEN_MAGIC_RETURN ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Iterator Helper\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_array_unscopables_funcs[] = {\n    JS_PROP_BOOL_DEF(\"at\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"copyWithin\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"entries\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"fill\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"find\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"findIndex\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"findLast\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"findLastIndex\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"flat\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"flatMap\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"includes\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"keys\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"toReversed\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"toSorted\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"toSpliced\", TRUE, JS_PROP_C_W_E),\n    JS_PROP_BOOL_DEF(\"values\", TRUE, JS_PROP_C_W_E),\n};\n\nstatic const JSCFunctionListEntry js_array_proto_funcs[] = {\n    JS_CFUNC_DEF(\"at\", 1, js_array_at ),\n    JS_CFUNC_DEF(\"with\", 2, js_array_with ),\n    JS_CFUNC_DEF(\"concat\", 1, js_array_concat ),\n    JS_CFUNC_MAGIC_DEF(\"every\", 1, js_array_every, special_every ),\n    JS_CFUNC_MAGIC_DEF(\"some\", 1, js_array_every, special_some ),\n    JS_CFUNC_MAGIC_DEF(\"forEach\", 1, js_array_every, special_forEach ),\n    JS_CFUNC_MAGIC_DEF(\"map\", 1, js_array_every, special_map ),\n    JS_CFUNC_MAGIC_DEF(\"filter\", 1, js_array_every, special_filter ),\n    JS_CFUNC_MAGIC_DEF(\"reduce\", 1, js_array_reduce, special_reduce ),\n    JS_CFUNC_MAGIC_DEF(\"reduceRight\", 1, js_array_reduce, special_reduceRight ),\n    JS_CFUNC_DEF(\"fill\", 1, js_array_fill ),\n    JS_CFUNC_MAGIC_DEF(\"find\", 1, js_array_find, ArrayFind ),\n    JS_CFUNC_MAGIC_DEF(\"findIndex\", 1, js_array_find, ArrayFindIndex ),\n    JS_CFUNC_MAGIC_DEF(\"findLast\", 1, js_array_find, ArrayFindLast ),\n    JS_CFUNC_MAGIC_DEF(\"findLastIndex\", 1, js_array_find, ArrayFindLastIndex ),\n    JS_CFUNC_DEF(\"indexOf\", 1, js_array_indexOf ),\n    JS_CFUNC_DEF(\"lastIndexOf\", 1, js_array_lastIndexOf ),\n    JS_CFUNC_DEF(\"includes\", 1, js_array_includes ),\n    JS_CFUNC_MAGIC_DEF(\"join\", 1, js_array_join, 0 ),\n    JS_CFUNC_DEF(\"toString\", 0, js_array_toString ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleString\", 0, js_array_join, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"pop\", 0, js_array_pop, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"push\", 1, js_array_push, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"shift\", 0, js_array_pop, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"unshift\", 1, js_array_push, 1 ),\n    JS_CFUNC_DEF(\"reverse\", 0, js_array_reverse ),\n    JS_CFUNC_DEF(\"toReversed\", 0, js_array_toReversed ),\n    JS_CFUNC_DEF(\"sort\", 1, js_array_sort ),\n    JS_CFUNC_DEF(\"toSorted\", 1, js_array_toSorted ),\n    JS_CFUNC_MAGIC_DEF(\"slice\", 2, js_array_slice, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"splice\", 2, js_array_slice, 1 ),\n    JS_CFUNC_DEF(\"toSpliced\", 2, js_array_toSpliced ),\n    JS_CFUNC_DEF(\"copyWithin\", 2, js_array_copyWithin ),\n    JS_CFUNC_MAGIC_DEF(\"flatMap\", 1, js_array_flatten, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"flat\", 0, js_array_flatten, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"values\", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),\n    JS_ALIAS_DEF(\"[Symbol.iterator]\", \"values\" ),\n    JS_CFUNC_MAGIC_DEF(\"keys\", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),\n    JS_CFUNC_MAGIC_DEF(\"entries\", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),\n    JS_OBJECT_DEF(\"[Symbol.unscopables]\", js_array_unscopables_funcs, countof(js_array_unscopables_funcs), JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_array_iterator_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_array_iterator_next, 0 ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Array Iterator\", JS_PROP_CONFIGURABLE ),\n};\n\n/* Number */\n\nstatic JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue val, obj;\n    if (argc == 0) {\n        val = JS_NewInt32(ctx, 0);\n    } else {\n        val = JS_ToNumeric(ctx, argv[0]);\n        if (JS_IsException(val))\n            return val;\n        switch(JS_VALUE_GET_TAG(val)) {\n        case JS_TAG_SHORT_BIG_INT:\n            val = JS_NewInt64(ctx, JS_VALUE_GET_SHORT_BIG_INT(val));\n            if (JS_IsException(val))\n                return val;\n            break;\n        case JS_TAG_BIG_INT:\n            {\n                JSBigInt *p = JS_VALUE_GET_PTR(val);\n                double d;\n                d = js_bigint_to_float64(ctx, p);\n                JS_FreeValue(ctx, val);\n                val = JS_NewFloat64(ctx, d);\n            }\n            break;\n        default:\n            break;\n        }\n    }\n    if (!JS_IsUndefined(new_target)) {\n        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);\n        if (!JS_IsException(obj))\n            JS_SetObjectData(ctx, obj, val);\n        return obj;\n    } else {\n        return val;\n    }\n}\n\n#if 0\nstatic JSValue js_number___toInteger(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    return JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[0]));\n}\n\nstatic JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv)\n{\n    int64_t v;\n    if (JS_ToLengthFree(ctx, &v, JS_DupValue(ctx, argv[0])))\n        return JS_EXCEPTION;\n    return JS_NewInt64(ctx, v);\n}\n#endif\n\nstatic JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    if (!JS_IsNumber(argv[0]))\n        return JS_FALSE;\n    return js_global_isNaN(ctx, this_val, argc, argv);\n}\n\nstatic JSValue js_number_isFinite(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    if (!JS_IsNumber(argv[0]))\n        return JS_FALSE;\n    return js_global_isFinite(ctx, this_val, argc, argv);\n}\n\nstatic JSValue js_number_isInteger(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    int ret;\n    ret = JS_NumberIsInteger(ctx, argv[0]);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    double d;\n    if (!JS_IsNumber(argv[0]))\n        return JS_FALSE;\n    if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, is_safe_integer(d));\n}\n\nstatic const JSCFunctionListEntry js_number_funcs[] = {\n    /* global ParseInt and parseFloat should be defined already or delayed */\n    JS_ALIAS_BASE_DEF(\"parseInt\", \"parseInt\", 0 ),\n    JS_ALIAS_BASE_DEF(\"parseFloat\", \"parseFloat\", 0 ),\n    JS_CFUNC_DEF(\"isNaN\", 1, js_number_isNaN ),\n    JS_CFUNC_DEF(\"isFinite\", 1, js_number_isFinite ),\n    JS_CFUNC_DEF(\"isInteger\", 1, js_number_isInteger ),\n    JS_CFUNC_DEF(\"isSafeInteger\", 1, js_number_isSafeInteger ),\n    JS_PROP_DOUBLE_DEF(\"MAX_VALUE\", 1.7976931348623157e+308, 0 ),\n    JS_PROP_DOUBLE_DEF(\"MIN_VALUE\", 5e-324, 0 ),\n    JS_PROP_DOUBLE_DEF(\"NaN\", NAN, 0 ),\n    JS_PROP_DOUBLE_DEF(\"NEGATIVE_INFINITY\", -INFINITY, 0 ),\n    JS_PROP_DOUBLE_DEF(\"POSITIVE_INFINITY\", INFINITY, 0 ),\n    JS_PROP_DOUBLE_DEF(\"EPSILON\", 2.220446049250313e-16, 0 ), /* ES6 */\n    JS_PROP_DOUBLE_DEF(\"MAX_SAFE_INTEGER\", 9007199254740991.0, 0 ), /* ES6 */\n    JS_PROP_DOUBLE_DEF(\"MIN_SAFE_INTEGER\", -9007199254740991.0, 0 ), /* ES6 */\n    //JS_CFUNC_DEF(\"__toInteger\", 1, js_number___toInteger ),\n    //JS_CFUNC_DEF(\"__toLength\", 1, js_number___toLength ),\n};\n\nstatic JSValue js_thisNumberValue(JSContext *ctx, JSValueConst this_val)\n{\n    if (JS_IsNumber(this_val))\n        return JS_DupValue(ctx, this_val);\n\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (p->class_id == JS_CLASS_NUMBER) {\n            if (JS_IsNumber(p->u.object_data))\n                return JS_DupValue(ctx, p->u.object_data);\n        }\n    }\n    return JS_ThrowTypeError(ctx, \"not a number\");\n}\n\nstatic JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    return js_thisNumberValue(ctx, this_val);\n}\n\nstatic int js_get_radix(JSContext *ctx, JSValueConst val)\n{\n    int radix;\n    if (JS_ToInt32Sat(ctx, &radix, val))\n        return -1;\n    if (radix < 2 || radix > 36) {\n        JS_ThrowRangeError(ctx, \"radix must be between 2 and 36\");\n        return -1;\n    }\n    return radix;\n}\n\nstatic JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv, int magic)\n{\n    JSValue val;\n    int base, flags;\n    double d;\n\n    val = js_thisNumberValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    if (magic || JS_IsUndefined(argv[0])) {\n        base = 10;\n    } else {\n        base = js_get_radix(ctx, argv[0]);\n        if (base < 0)\n            goto fail;\n    }\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_INT) {\n        char buf1[70];\n        int len;\n        len = i64toa_radix(buf1, JS_VALUE_GET_INT(val), base);\n        return js_new_string8_len(ctx, buf1, len);\n    }\n    if (JS_ToFloat64Free(ctx, &d, val))\n        return JS_EXCEPTION;\n    flags = JS_DTOA_FORMAT_FREE;\n    if (base != 10)\n        flags |= JS_DTOA_EXP_DISABLED;\n    return js_dtoa2(ctx, d, base, 0, flags);\n fail:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_number_toFixed(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue val;\n    int f, flags;\n    double d;\n\n    val = js_thisNumberValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    if (JS_ToFloat64Free(ctx, &d, val))\n        return JS_EXCEPTION;\n    if (JS_ToInt32Sat(ctx, &f, argv[0]))\n        return JS_EXCEPTION;\n    if (f < 0 || f > 100)\n        return JS_ThrowRangeError(ctx, \"invalid number of digits\");\n    if (fabs(d) >= 1e21)\n        flags = JS_DTOA_FORMAT_FREE;\n    else\n        flags = JS_DTOA_FORMAT_FRAC;\n    return js_dtoa2(ctx, d, 10, f, flags);\n}\n\nstatic JSValue js_number_toExponential(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JSValue val;\n    int f, flags;\n    double d;\n\n    val = js_thisNumberValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    if (JS_ToFloat64Free(ctx, &d, val))\n        return JS_EXCEPTION;\n    if (JS_ToInt32Sat(ctx, &f, argv[0]))\n        return JS_EXCEPTION;\n    if (!isfinite(d)) {\n        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));\n    }\n    if (JS_IsUndefined(argv[0])) {\n        flags = JS_DTOA_FORMAT_FREE;\n        f = 0;\n    } else {\n        if (f < 0 || f > 100)\n            return JS_ThrowRangeError(ctx, \"invalid number of digits\");\n        f++;\n        flags = JS_DTOA_FORMAT_FIXED;\n    }\n    return js_dtoa2(ctx, d, 10, f, flags | JS_DTOA_EXP_ENABLED);\n}\n\nstatic JSValue js_number_toPrecision(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue val;\n    int p;\n    double d;\n\n    val = js_thisNumberValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    if (JS_ToFloat64Free(ctx, &d, val))\n        return JS_EXCEPTION;\n    if (JS_IsUndefined(argv[0]))\n        goto to_string;\n    if (JS_ToInt32Sat(ctx, &p, argv[0]))\n        return JS_EXCEPTION;\n    if (!isfinite(d)) {\n    to_string:\n        return JS_ToStringFree(ctx,  __JS_NewFloat64(ctx, d));\n    }\n    if (p < 1 || p > 100)\n        return JS_ThrowRangeError(ctx, \"invalid number of digits\");\n    return js_dtoa2(ctx, d, 10, p, JS_DTOA_FORMAT_FIXED);\n}\n\nstatic const JSCFunctionListEntry js_number_proto_funcs[] = {\n    JS_CFUNC_DEF(\"toExponential\", 1, js_number_toExponential ),\n    JS_CFUNC_DEF(\"toFixed\", 1, js_number_toFixed ),\n    JS_CFUNC_DEF(\"toPrecision\", 1, js_number_toPrecision ),\n    JS_CFUNC_MAGIC_DEF(\"toString\", 1, js_number_toString, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleString\", 0, js_number_toString, 1 ),\n    JS_CFUNC_DEF(\"valueOf\", 0, js_number_valueOf ),\n};\n\nstatic JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    const char *str, *p;\n    int radix, flags;\n    JSValue ret;\n\n    str = JS_ToCString(ctx, argv[0]);\n    if (!str)\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &radix, argv[1])) {\n        JS_FreeCString(ctx, str);\n        return JS_EXCEPTION;\n    }\n    if (radix != 0 && (radix < 2 || radix > 36)) {\n        ret = JS_NAN;\n    } else {\n        p = str;\n        p += skip_spaces(p);\n        flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;\n        ret = js_atof(ctx, p, NULL, radix, flags);\n    }\n    JS_FreeCString(ctx, str);\n    return ret;\n}\n\nstatic JSValue js_parseFloat(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    const char *str, *p;\n    JSValue ret;\n\n    str = JS_ToCString(ctx, argv[0]);\n    if (!str)\n        return JS_EXCEPTION;\n    p = str;\n    p += skip_spaces(p);\n    ret = js_atof(ctx, p, NULL, 10, 0);\n    JS_FreeCString(ctx, str);\n    return ret;\n}\n\n/* Boolean */\nstatic JSValue js_boolean_constructor(JSContext *ctx, JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue val, obj;\n    val = JS_NewBool(ctx, JS_ToBool(ctx, argv[0]));\n    if (!JS_IsUndefined(new_target)) {\n        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_BOOLEAN);\n        if (!JS_IsException(obj))\n            JS_SetObjectData(ctx, obj, val);\n        return obj;\n    } else {\n        return val;\n    }\n}\n\nstatic JSValue js_thisBooleanValue(JSContext *ctx, JSValueConst this_val)\n{\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_BOOL)\n        return JS_DupValue(ctx, this_val);\n\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (p->class_id == JS_CLASS_BOOLEAN) {\n            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_BOOL)\n                return p->u.object_data;\n        }\n    }\n    return JS_ThrowTypeError(ctx, \"not a boolean\");\n}\n\nstatic JSValue js_boolean_toString(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue val = js_thisBooleanValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    return JS_AtomToString(ctx, JS_VALUE_GET_BOOL(val) ?\n                       JS_ATOM_true : JS_ATOM_false);\n}\n\nstatic JSValue js_boolean_valueOf(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    return js_thisBooleanValue(ctx, this_val);\n}\n\nstatic const JSCFunctionListEntry js_boolean_proto_funcs[] = {\n    JS_CFUNC_DEF(\"toString\", 0, js_boolean_toString ),\n    JS_CFUNC_DEF(\"valueOf\", 0, js_boolean_valueOf ),\n};\n\n/* String */\n\nstatic int js_string_get_own_property(JSContext *ctx,\n                                      JSPropertyDescriptor *desc,\n                                      JSValueConst obj, JSAtom prop)\n{\n    JSObject *p;\n    JSString *p1;\n    uint32_t idx, ch;\n\n    /* This is a class exotic method: obj class_id is JS_CLASS_STRING */\n    if (__JS_AtomIsTaggedInt(prop)) {\n        p = JS_VALUE_GET_OBJ(obj);\n        if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {\n            p1 = JS_VALUE_GET_STRING(p->u.object_data);\n            idx = __JS_AtomToUInt32(prop);\n            if (idx < p1->len) {\n                if (desc) {\n                    ch = string_get(p1, idx);\n                    desc->flags = JS_PROP_ENUMERABLE;\n                    desc->value = js_new_string_char(ctx, ch);\n                    desc->getter = JS_UNDEFINED;\n                    desc->setter = JS_UNDEFINED;\n                }\n                return TRUE;\n            }\n        }\n    }\n    return FALSE;\n}\n\nstatic int js_string_define_own_property(JSContext *ctx,\n                                         JSValueConst this_obj,\n                                         JSAtom prop, JSValueConst val,\n                                         JSValueConst getter,\n                                         JSValueConst setter, int flags)\n{\n    uint32_t idx;\n    JSObject *p;\n    JSString *p1, *p2;\n\n    if (__JS_AtomIsTaggedInt(prop)) {\n        idx = __JS_AtomToUInt32(prop);\n        p = JS_VALUE_GET_OBJ(this_obj);\n        if (JS_VALUE_GET_TAG(p->u.object_data) != JS_TAG_STRING)\n            goto def;\n        p1 = JS_VALUE_GET_STRING(p->u.object_data);\n        if (idx >= p1->len)\n            goto def;\n        if (!check_define_prop_flags(JS_PROP_ENUMERABLE, flags))\n            goto fail;\n        /* check that the same value is configured */\n        if (flags & JS_PROP_HAS_VALUE) {\n            if (JS_VALUE_GET_TAG(val) != JS_TAG_STRING)\n                goto fail;\n            p2 = JS_VALUE_GET_STRING(val);\n            if (p2->len != 1)\n                goto fail;\n            if (string_get(p1, idx) != string_get(p2, 0)) {\n            fail:\n                return JS_ThrowTypeErrorOrFalse(ctx, flags, \"property is not configurable\");\n            }\n        }\n        return TRUE;\n    } else {\n    def:\n        return JS_DefineProperty(ctx, this_obj, prop, val, getter, setter,\n                                 flags | JS_PROP_NO_EXOTIC);\n    }\n}\n\nstatic int js_string_delete_property(JSContext *ctx,\n                                     JSValueConst obj, JSAtom prop)\n{\n    uint32_t idx;\n\n    if (__JS_AtomIsTaggedInt(prop)) {\n        idx = __JS_AtomToUInt32(prop);\n        if (idx < js_string_obj_get_length(ctx, obj)) {\n            return FALSE;\n        }\n    }\n    return TRUE;\n}\n\nstatic const JSClassExoticMethods js_string_exotic_methods = {\n    .get_own_property = js_string_get_own_property,\n    .define_own_property = js_string_define_own_property,\n    .delete_property = js_string_delete_property,\n};\n\nstatic JSValue js_string_constructor(JSContext *ctx, JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue val, obj;\n    if (argc == 0) {\n        val = JS_AtomToString(ctx, JS_ATOM_empty_string);\n    } else {\n        if (JS_IsUndefined(new_target) && JS_IsSymbol(argv[0])) {\n            JSAtomStruct *p = JS_VALUE_GET_PTR(argv[0]);\n            val = JS_ConcatString3(ctx, \"Symbol(\", JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p)), \")\");\n        } else {\n            val = JS_ToString(ctx, argv[0]);\n        }\n        if (JS_IsException(val))\n            return val;\n    }\n    if (!JS_IsUndefined(new_target)) {\n        JSString *p1 = JS_VALUE_GET_STRING(val);\n\n        obj = js_create_from_ctor(ctx, new_target, JS_CLASS_STRING);\n        if (JS_IsException(obj)) {\n            JS_FreeValue(ctx, val);\n        } else {\n            JS_SetObjectData(ctx, obj, val);\n            JS_DefinePropertyValue(ctx, obj, JS_ATOM_length, JS_NewInt32(ctx, p1->len), 0);\n        }\n        return obj;\n    } else {\n        return val;\n    }\n}\n\nstatic JSValue js_thisStringValue(JSContext *ctx, JSValueConst this_val)\n{\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING ||\n        JS_VALUE_GET_TAG(this_val) == JS_TAG_STRING_ROPE)\n        return JS_DupValue(ctx, this_val);\n\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (p->class_id == JS_CLASS_STRING) {\n            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING)\n                return JS_DupValue(ctx, p->u.object_data);\n        }\n    }\n    return JS_ThrowTypeError(ctx, \"not a string\");\n}\n\nstatic JSValue js_string_fromCharCode(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv)\n{\n    int i;\n    StringBuffer b_s, *b = &b_s;\n\n    string_buffer_init(ctx, b, argc);\n\n    for(i = 0; i < argc; i++) {\n        int32_t c;\n        if (JS_ToInt32(ctx, &c, argv[i]) || string_buffer_putc16(b, c & 0xffff)) {\n            string_buffer_free(b);\n            return JS_EXCEPTION;\n        }\n    }\n    return string_buffer_end(b);\n}\n\nstatic JSValue js_string_fromCodePoint(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    double d;\n    int i, c;\n    StringBuffer b_s, *b = &b_s;\n\n    /* XXX: could pre-compute string length if all arguments are JS_TAG_INT */\n\n    if (string_buffer_init(ctx, b, argc))\n        goto fail;\n    for(i = 0; i < argc; i++) {\n        if (JS_VALUE_GET_TAG(argv[i]) == JS_TAG_INT) {\n            c = JS_VALUE_GET_INT(argv[i]);\n            if (c < 0 || c > 0x10ffff)\n                goto range_error;\n        } else {\n            if (JS_ToFloat64(ctx, &d, argv[i]))\n                goto fail;\n            if (isnan(d) || d < 0 || d > 0x10ffff || (c = (int)d) != d)\n                goto range_error;\n        }\n        if (string_buffer_putc(b, c))\n            goto fail;\n    }\n    return string_buffer_end(b);\n\n range_error:\n    JS_ThrowRangeError(ctx, \"invalid code point\");\n fail:\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_string_raw(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    // raw(temp,...a)\n    JSValue cooked, val, raw;\n    StringBuffer b_s, *b = &b_s;\n    int64_t i, n;\n\n    string_buffer_init(ctx, b, 0);\n    raw = JS_UNDEFINED;\n    cooked = JS_ToObject(ctx, argv[0]);\n    if (JS_IsException(cooked))\n        goto exception;\n    raw = JS_ToObjectFree(ctx, JS_GetProperty(ctx, cooked, JS_ATOM_raw));\n    if (JS_IsException(raw))\n        goto exception;\n    if (js_get_length64(ctx, &n, raw) < 0)\n        goto exception;\n\n    for (i = 0; i < n; i++) {\n        val = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, raw, i));\n        if (JS_IsException(val))\n            goto exception;\n        string_buffer_concat_value_free(b, val);\n        if (i < n - 1 && i + 1 < argc) {\n            if (string_buffer_concat_value(b, argv[i + 1]))\n                goto exception;\n        }\n    }\n    JS_FreeValue(ctx, cooked);\n    JS_FreeValue(ctx, raw);\n    return string_buffer_end(b);\n\nexception:\n    JS_FreeValue(ctx, cooked);\n    JS_FreeValue(ctx, raw);\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\n/* only used in test262 */\nJSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    uint32_t start, end, i, n;\n    StringBuffer b_s, *b = &b_s;\n\n    if (JS_ToUint32(ctx, &start, argv[0]) ||\n        JS_ToUint32(ctx, &end, argv[1]))\n        return JS_EXCEPTION;\n    end = min_uint32(end, 0x10ffff + 1);\n\n    if (start > end) {\n        start = end;\n    }\n    n = end - start;\n    if (end > 0x10000) {\n        n += end - max_uint32(start, 0x10000);\n    }\n    if (string_buffer_init2(ctx, b, n, end >= 0x100))\n        return JS_EXCEPTION;\n    for(i = start; i < end; i++) {\n        string_buffer_putc(b, i);\n    }\n    return string_buffer_end(b);\n}\n\n#if 0\nstatic JSValue js_string___isSpace(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    int c;\n    if (JS_ToInt32(ctx, &c, argv[0]))\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, lre_is_space(c));\n}\n#endif\n\nstatic JSValue js_string_charCodeAt(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue val, ret;\n    JSString *p;\n    int idx, c;\n\n    val = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    p = JS_VALUE_GET_STRING(val);\n    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {\n        JS_FreeValue(ctx, val);\n        return JS_EXCEPTION;\n    }\n    if (idx < 0 || idx >= p->len) {\n        ret = JS_NAN;\n    } else {\n        c = string_get(p, idx);\n        ret = JS_NewInt32(ctx, c);\n    }\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic JSValue js_string_charAt(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv, int is_at)\n{\n    JSValue val, ret;\n    JSString *p;\n    int idx, c;\n\n    val = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    p = JS_VALUE_GET_STRING(val);\n    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {\n        JS_FreeValue(ctx, val);\n        return JS_EXCEPTION;\n    }\n    if (idx < 0 && is_at)\n        idx += p->len;\n    if (idx < 0 || idx >= p->len) {\n        if (is_at)\n            ret = JS_UNDEFINED;\n        else\n            ret = JS_AtomToString(ctx, JS_ATOM_empty_string);\n    } else {\n        c = string_get(p, idx);\n        ret = js_new_string_char(ctx, c);\n    }\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic JSValue js_string_codePointAt(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue val, ret;\n    JSString *p;\n    int idx, c;\n\n    val = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    p = JS_VALUE_GET_STRING(val);\n    if (JS_ToInt32Sat(ctx, &idx, argv[0])) {\n        JS_FreeValue(ctx, val);\n        return JS_EXCEPTION;\n    }\n    if (idx < 0 || idx >= p->len) {\n        ret = JS_UNDEFINED;\n    } else {\n        c = string_getc(p, &idx);\n        ret = JS_NewInt32(ctx, c);\n    }\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic JSValue js_string_concat(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue r;\n    int i;\n\n    /* XXX: Use more efficient method */\n    /* XXX: This method is OK if r has a single refcount */\n    /* XXX: should use string_buffer? */\n    r = JS_ToStringCheckObject(ctx, this_val);\n    for (i = 0; i < argc; i++) {\n        if (JS_IsException(r))\n            break;\n        r = JS_ConcatString(ctx, r, JS_DupValue(ctx, argv[i]));\n    }\n    return r;\n}\n\nstatic int string_cmp(JSString *p1, JSString *p2, int x1, int x2, int len)\n{\n    int i, c1, c2;\n    for (i = 0; i < len; i++) {\n        if ((c1 = string_get(p1, x1 + i)) != (c2 = string_get(p2, x2 + i)))\n            return c1 - c2;\n    }\n    return 0;\n}\n\nstatic int string_indexof_char(JSString *p, int c, int from)\n{\n    /* assuming 0 <= from <= p->len */\n    int i, len = p->len;\n    if (p->is_wide_char) {\n        for (i = from; i < len; i++) {\n            if (p->u.str16[i] == c)\n                return i;\n        }\n    } else {\n        if ((c & ~0xff) == 0) {\n            for (i = from; i < len; i++) {\n                if (p->u.str8[i] == (uint8_t)c)\n                    return i;\n            }\n        }\n    }\n    return -1;\n}\n\nstatic int string_indexof(JSString *p1, JSString *p2, int from)\n{\n    /* assuming 0 <= from <= p1->len */\n    int c, i, j, len1 = p1->len, len2 = p2->len;\n    if (len2 == 0)\n        return from;\n    for (i = from, c = string_get(p2, 0); i + len2 <= len1; i = j + 1) {\n        j = string_indexof_char(p1, c, i);\n        if (j < 0 || j + len2 > len1)\n            break;\n        if (!string_cmp(p1, p2, j + 1, 1, len2 - 1))\n            return j;\n    }\n    return -1;\n}\n\nstatic int64_t string_advance_index(JSString *p, int64_t index, BOOL unicode)\n{\n    if (!unicode || index >= p->len || !p->is_wide_char) {\n        index++;\n    } else {\n        int index32 = (int)index;\n        string_getc(p, &index32);\n        index = index32;\n    }\n    return index;\n}\n\n/* return the position of the first invalid character in the string or\n   -1 if none */\nstatic int js_string_find_invalid_codepoint(JSString *p)\n{\n    int i;\n    if (!p->is_wide_char)\n        return -1;\n    for(i = 0; i < p->len; i++) {\n        uint32_t c = p->u.str16[i];\n        if (is_surrogate(c)) {\n            if (is_hi_surrogate(c) && (i + 1) < p->len\n            &&  is_lo_surrogate(p->u.str16[i + 1])) {\n                i++;\n            } else {\n                return i;\n            }\n        }\n    }\n    return -1;\n}\n\nstatic JSValue js_string_isWellFormed(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv)\n{\n    JSValue str;\n    JSString *p;\n    BOOL ret;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return JS_EXCEPTION;\n    p = JS_VALUE_GET_STRING(str);\n    ret = (js_string_find_invalid_codepoint(p) < 0);\n    JS_FreeValue(ctx, str);\n    return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_string_toWellFormed(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv)\n{\n    JSValue str, ret;\n    JSString *p;\n    int i;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return JS_EXCEPTION;\n\n    p = JS_VALUE_GET_STRING(str);\n    /* avoid reallocating the string if it is well-formed */\n    i = js_string_find_invalid_codepoint(p);\n    if (i < 0)\n        return str;\n\n    ret = js_new_string16_len(ctx, p->u.str16, p->len);\n    JS_FreeValue(ctx, str);\n    if (JS_IsException(ret))\n        return JS_EXCEPTION;\n\n    p = JS_VALUE_GET_STRING(ret);\n    for (; i < p->len; i++) {\n        uint32_t c = p->u.str16[i];\n        if (is_surrogate(c)) {\n            if (is_hi_surrogate(c) && (i + 1) < p->len\n            &&  is_lo_surrogate(p->u.str16[i + 1])) {\n                i++;\n            } else {\n                p->u.str16[i] = 0xFFFD;\n            }\n        }\n    }\n    return ret;\n}\n\nstatic JSValue js_string_indexOf(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv, int lastIndexOf)\n{\n    JSValue str, v;\n    int i, len, v_len, pos, start, stop, ret, inc;\n    JSString *p;\n    JSString *p1;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return str;\n    v = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(v))\n        goto fail;\n    p = JS_VALUE_GET_STRING(str);\n    p1 = JS_VALUE_GET_STRING(v);\n    len = p->len;\n    v_len = p1->len;\n    if (lastIndexOf) {\n        pos = len - v_len;\n        if (argc > 1) {\n            double d;\n            if (JS_ToFloat64(ctx, &d, argv[1]))\n                goto fail;\n            if (!isnan(d)) {\n                if (d <= 0)\n                    pos = 0;\n                else if (d < pos)\n                    pos = d;\n            }\n        }\n        start = pos;\n        stop = 0;\n        inc = -1;\n    } else {\n        pos = 0;\n        if (argc > 1) {\n            if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))\n                goto fail;\n        }\n        start = pos;\n        stop = len - v_len;\n        inc = 1;\n    }\n    ret = -1;\n    if (len >= v_len && inc * (stop - start) >= 0) {\n        for (i = start;; i += inc) {\n            if (!string_cmp(p, p1, i, 0, v_len)) {\n                ret = i;\n                break;\n            }\n            if (i == stop)\n                break;\n        }\n    }\n    JS_FreeValue(ctx, str);\n    JS_FreeValue(ctx, v);\n    return JS_NewInt32(ctx, ret);\n\nfail:\n    JS_FreeValue(ctx, str);\n    JS_FreeValue(ctx, v);\n    return JS_EXCEPTION;\n}\n\n/* return < 0 if exception or TRUE/FALSE */\nstatic int js_is_regexp(JSContext *ctx, JSValueConst obj);\n\nstatic JSValue js_string_includes(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv, int magic)\n{\n    JSValue str, v = JS_UNDEFINED;\n    int i, len, v_len, pos, start, stop, ret;\n    JSString *p;\n    JSString *p1;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return str;\n    ret = js_is_regexp(ctx, argv[0]);\n    if (ret) {\n        if (ret > 0)\n            JS_ThrowTypeError(ctx, \"regexp not supported\");\n        goto fail;\n    }\n    v = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(v))\n        goto fail;\n    p = JS_VALUE_GET_STRING(str);\n    p1 = JS_VALUE_GET_STRING(v);\n    len = p->len;\n    v_len = p1->len;\n    pos = (magic == 2) ? len : 0;\n    if (argc > 1 && !JS_IsUndefined(argv[1])) {\n        if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))\n            goto fail;\n    }\n    len -= v_len;\n    ret = 0;\n    if (magic == 0) {\n        start = pos;\n        stop = len;\n    } else {\n        if (magic == 1) {\n            if (pos > len)\n                goto done;\n        } else {\n            pos -= v_len;\n        }\n        start = stop = pos;\n    }\n    if (start >= 0 && start <= stop) {\n        for (i = start;; i++) {\n            if (!string_cmp(p, p1, i, 0, v_len)) {\n                ret = 1;\n                break;\n            }\n            if (i == stop)\n                break;\n        }\n    }\n done:\n    JS_FreeValue(ctx, str);\n    JS_FreeValue(ctx, v);\n    return JS_NewBool(ctx, ret);\n\nfail:\n    JS_FreeValue(ctx, str);\n    JS_FreeValue(ctx, v);\n    return JS_EXCEPTION;\n}\n\nstatic int check_regexp_g_flag(JSContext *ctx, JSValueConst regexp)\n{\n    int ret;\n    JSValue flags;\n\n    ret = js_is_regexp(ctx, regexp);\n    if (ret < 0)\n        return -1;\n    if (ret) {\n        flags = JS_GetProperty(ctx, regexp, JS_ATOM_flags);\n        if (JS_IsException(flags))\n            return -1;\n        if (JS_IsUndefined(flags) || JS_IsNull(flags)) {\n            JS_ThrowTypeError(ctx, \"cannot convert to object\");\n            return -1;\n        }\n        flags = JS_ToStringFree(ctx, flags);\n        if (JS_IsException(flags))\n            return -1;\n        ret = string_indexof_char(JS_VALUE_GET_STRING(flags), 'g', 0);\n        JS_FreeValue(ctx, flags);\n        if (ret < 0) {\n            JS_ThrowTypeError(ctx, \"regexp must have the 'g' flag\");\n            return -1;\n        }\n    }\n    return 0;\n}\n\nstatic JSValue js_string_match(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv, int atom)\n{\n    // match(rx), search(rx), matchAll(rx)\n    // atom is JS_ATOM_Symbol_match, JS_ATOM_Symbol_search, or JS_ATOM_Symbol_matchAll\n    JSValueConst O = this_val, regexp = argv[0], args[2];\n    JSValue matcher, S, rx, result, str;\n    int args_len;\n\n    if (JS_IsUndefined(O) || JS_IsNull(O))\n        return JS_ThrowTypeError(ctx, \"cannot convert to object\");\n\n    if (JS_IsObject(regexp)) {\n        matcher = JS_GetProperty(ctx, regexp, atom);\n        if (JS_IsException(matcher))\n            return JS_EXCEPTION;\n        if (atom == JS_ATOM_Symbol_matchAll) {\n            if (check_regexp_g_flag(ctx, regexp) < 0) {\n                JS_FreeValue(ctx, matcher);\n                return JS_EXCEPTION;\n            }\n        }\n        if (!JS_IsUndefined(matcher) && !JS_IsNull(matcher)) {\n            return JS_CallFree(ctx, matcher, regexp, 1, &O);\n        }\n    }\n    S = JS_ToString(ctx, O);\n    if (JS_IsException(S))\n        return JS_EXCEPTION;\n    args_len = 1;\n    args[0] = regexp;\n    str = JS_UNDEFINED;\n    if (atom == JS_ATOM_Symbol_matchAll) {\n        str = js_new_string8(ctx, \"g\");\n        if (JS_IsException(str))\n            goto fail;\n        args[args_len++] = (JSValueConst)str;\n    }\n    rx = JS_CallConstructor(ctx, ctx->regexp_ctor, args_len, args);\n    JS_FreeValue(ctx, str);\n    if (JS_IsException(rx)) {\n    fail:\n        JS_FreeValue(ctx, S);\n        return JS_EXCEPTION;\n    }\n    result = JS_InvokeFree(ctx, rx, atom, 1, (JSValueConst *)&S);\n    JS_FreeValue(ctx, S);\n    return result;\n}\n\n/* if captures != NULL, captures_val and matched are ignored. Otherwise,\n   captures_len is ignored */\nstatic int js_string_GetSubstitution(JSContext *ctx,\n                                     StringBuffer *b,\n                                     JSValueConst matched,\n                                     JSString *sp,\n                                     uint32_t position,\n                                     JSValueConst captures_val,\n                                     JSValueConst namedCaptures,\n                                     JSValueConst rep,\n                                     uint8_t **captures,\n                                     uint32_t captures_len)\n{\n    JSValue capture, name, s;\n    uint32_t len, matched_len;\n    int i, j, j0, k, k1, shift;\n    int c, c1;\n    JSString *rp;\n\n    if (JS_VALUE_GET_TAG(rep) != JS_TAG_STRING) {\n        JS_ThrowTypeError(ctx, \"not a string\");\n        goto exception;\n    }\n    shift = sp->is_wide_char;\n    rp = JS_VALUE_GET_STRING(rep);\n\n    if (captures) {\n        matched_len = (captures[1] - captures[0]) >> shift;\n    } else {\n        captures_len = 0;\n        if (!JS_IsUndefined(captures_val)) {\n            if (js_get_length32(ctx, &captures_len, captures_val))\n                goto exception;\n        }\n        if (js_get_length32(ctx, &matched_len, matched))\n            goto exception;\n    }\n\n    len = rp->len;\n    i = 0;\n    for(;;) {\n        j = string_indexof_char(rp, '$', i);\n        if (j < 0 || j + 1 >= len)\n            break;\n        string_buffer_concat(b, rp, i, j);\n        j0 = j++;\n        c = string_get(rp, j++);\n        if (c == '$') {\n            string_buffer_putc8(b, '$');\n        } else if (c == '&') {\n            if (captures) {\n                string_buffer_concat(b, sp, position, position + matched_len);\n            } else {\n                if (string_buffer_concat_value(b, matched))\n                    goto exception;\n            }\n        } else if (c == '`') {\n            string_buffer_concat(b, sp, 0, position);\n        } else if (c == '\\'') {\n            string_buffer_concat(b, sp, position + matched_len, sp->len);\n        } else if (c >= '0' && c <= '9') {\n            k = c - '0';\n            if (j < len) {\n                c1 = string_get(rp, j);\n                if (c1 >= '0' && c1 <= '9') {\n                    /* This behavior is specified in ES6 and refined in ECMA 2019 */\n                    /* ECMA 2019 does not have the extra test, but\n                       Test262 S15.5.4.11_A3_T1..3 require this behavior */\n                    k1 = k * 10 + c1 - '0';\n                    if (k1 >= 1 && k1 < captures_len) {\n                        k = k1;\n                        j++;\n                    }\n                }\n            }\n            if (k >= 1 && k < captures_len) {\n                if (captures) {\n                    int start, end;\n                    if (captures[2 * k] && captures[2 * k + 1]) {\n                        start = (captures[2 * k] - sp->u.str8) >> shift;\n                        end = (captures[2 * k + 1] - sp->u.str8) >> shift;\n                        string_buffer_concat(b, sp, start, end);\n                    }\n                } else {\n                    s = JS_GetPropertyInt64(ctx, captures_val, k);\n                    if (JS_IsException(s))\n                        goto exception;\n                    if (!JS_IsUndefined(s)) {\n                        if (string_buffer_concat_value_free(b, s))\n                            goto exception;\n                    }\n                }\n            } else {\n                goto norep;\n            }\n        } else if (c == '<' && !JS_IsUndefined(namedCaptures)) {\n            k = string_indexof_char(rp, '>', j);\n            if (k < 0)\n                goto norep;\n            name = js_sub_string(ctx, rp, j, k);\n            if (JS_IsException(name))\n                goto exception;\n            capture = JS_GetPropertyValue(ctx, namedCaptures, name);\n            if (JS_IsException(capture))\n                goto exception;\n            if (!JS_IsUndefined(capture)) {\n                if (string_buffer_concat_value_free(b, capture))\n                    goto exception;\n            }\n            j = k + 1;\n        } else {\n        norep:\n            string_buffer_concat(b, rp, j0, j);\n        }\n        i = j;\n    }\n    string_buffer_concat(b, rp, i, rp->len);\n    return 0;\nexception:\n    return -1;\n}\n\nstatic JSValue js_string_replace(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv,\n                                 int is_replaceAll)\n{\n    // replace(rx, rep)\n    JSValueConst O = this_val, searchValue = argv[0], replaceValue = argv[1];\n    JSValueConst args[3];\n    JSValue str, search_str, replaceValue_str, repl_str;\n    JSString *sp, *searchp;\n    StringBuffer b_s, *b = &b_s;\n    int pos, functionalReplace, endOfLastMatch;\n    BOOL is_first;\n\n    if (JS_IsUndefined(O) || JS_IsNull(O))\n        return JS_ThrowTypeError(ctx, \"cannot convert to object\");\n\n    search_str = JS_UNDEFINED;\n    replaceValue_str = JS_UNDEFINED;\n    repl_str = JS_UNDEFINED;\n\n    if (JS_IsObject(searchValue)) {\n        JSValue replacer;\n        if (is_replaceAll) {\n            if (check_regexp_g_flag(ctx, searchValue) < 0)\n                return JS_EXCEPTION;\n        }\n        replacer = JS_GetProperty(ctx, searchValue, JS_ATOM_Symbol_replace);\n        if (JS_IsException(replacer))\n            return JS_EXCEPTION;\n        if (!JS_IsUndefined(replacer) && !JS_IsNull(replacer)) {\n            args[0] = O;\n            args[1] = replaceValue;\n            return JS_CallFree(ctx, replacer, searchValue, 2, args);\n        }\n    }\n    string_buffer_init(ctx, b, 0);\n\n    str = JS_ToString(ctx, O);\n    if (JS_IsException(str))\n        goto exception;\n    search_str = JS_ToString(ctx, searchValue);\n    if (JS_IsException(search_str))\n        goto exception;\n    functionalReplace = JS_IsFunction(ctx, replaceValue);\n    if (!functionalReplace) {\n        replaceValue_str = JS_ToString(ctx, replaceValue);\n        if (JS_IsException(replaceValue_str))\n            goto exception;\n    }\n\n    sp = JS_VALUE_GET_STRING(str);\n    searchp = JS_VALUE_GET_STRING(search_str);\n    endOfLastMatch = 0;\n    is_first = TRUE;\n    for(;;) {\n        if (unlikely(searchp->len == 0)) {\n            if (is_first)\n                pos = 0;\n            else if (endOfLastMatch >= sp->len)\n                pos = -1;\n            else\n                pos = endOfLastMatch + 1;\n        } else {\n            pos = string_indexof(sp, searchp, endOfLastMatch);\n        }\n        if (pos < 0) {\n            if (is_first) {\n                string_buffer_free(b);\n                JS_FreeValue(ctx, search_str);\n                JS_FreeValue(ctx, replaceValue_str);\n                return str;\n            } else {\n                break;\n            }\n        }\n\n        string_buffer_concat(b, sp, endOfLastMatch, pos);\n\n        if (functionalReplace) {\n            args[0] = search_str;\n            args[1] = JS_NewInt32(ctx, pos);\n            args[2] = str;\n            repl_str = JS_ToStringFree(ctx, JS_Call(ctx, replaceValue, JS_UNDEFINED, 3, args));\n            if (JS_IsException(repl_str))\n                goto exception;\n            string_buffer_concat_value_free(b, repl_str);\n        } else {\n            if (js_string_GetSubstitution(ctx, b, search_str, sp, pos,\n                                          JS_UNDEFINED, JS_UNDEFINED, replaceValue_str,\n                                          NULL, 0)) {\n                goto exception;\n            }\n        }\n\n        endOfLastMatch = pos + searchp->len;\n        is_first = FALSE;\n        if (!is_replaceAll)\n            break;\n    }\n    string_buffer_concat(b, sp, endOfLastMatch, sp->len);\n    JS_FreeValue(ctx, search_str);\n    JS_FreeValue(ctx, replaceValue_str);\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n\nexception:\n    string_buffer_free(b);\n    JS_FreeValue(ctx, search_str);\n    JS_FreeValue(ctx, replaceValue_str);\n    JS_FreeValue(ctx, str);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_string_split(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    // split(sep, limit)\n    JSValueConst O = this_val, separator = argv[0], limit = argv[1];\n    JSValueConst args[2];\n    JSValue S, A, R, T;\n    uint32_t lim, lengthA;\n    int64_t p, q, s, r, e;\n    JSString *sp, *rp;\n\n    if (JS_IsUndefined(O) || JS_IsNull(O))\n        return JS_ThrowTypeError(ctx, \"cannot convert to object\");\n\n    S = JS_UNDEFINED;\n    A = JS_UNDEFINED;\n    R = JS_UNDEFINED;\n\n    if (JS_IsObject(separator)) {\n        JSValue splitter;\n        splitter = JS_GetProperty(ctx, separator, JS_ATOM_Symbol_split);\n        if (JS_IsException(splitter))\n            return JS_EXCEPTION;\n        if (!JS_IsUndefined(splitter) && !JS_IsNull(splitter)) {\n            args[0] = O;\n            args[1] = limit;\n            return JS_CallFree(ctx, splitter, separator, 2, args);\n        }\n    }\n    S = JS_ToString(ctx, O);\n    if (JS_IsException(S))\n        goto exception;\n    A = JS_NewArray(ctx);\n    if (JS_IsException(A))\n        goto exception;\n    lengthA = 0;\n    if (JS_IsUndefined(limit)) {\n        lim = 0xffffffff;\n    } else {\n        if (JS_ToUint32(ctx, &lim, limit) < 0)\n            goto exception;\n    }\n    sp = JS_VALUE_GET_STRING(S);\n    s = sp->len;\n    R = JS_ToString(ctx, separator);\n    if (JS_IsException(R))\n        goto exception;\n    rp = JS_VALUE_GET_STRING(R);\n    r = rp->len;\n    p = 0;\n    if (lim == 0)\n        goto done;\n    if (JS_IsUndefined(separator))\n        goto add_tail;\n    if (s == 0) {\n        if (r != 0)\n            goto add_tail;\n        goto done;\n    }\n    for (q = p; (q += !r) <= s - r - !r; q = p = e + r) {\n        e = string_indexof(sp, rp, q);\n        if (e < 0)\n            break;\n        T = js_sub_string(ctx, sp, p, e);\n        if (JS_IsException(T))\n            goto exception;\n        if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T, 0) < 0)\n            goto exception;\n        if (lengthA == lim)\n            goto done;\n    }\nadd_tail:\n    T = js_sub_string(ctx, sp, p, s);\n    if (JS_IsException(T))\n        goto exception;\n    if (JS_CreateDataPropertyUint32(ctx, A, lengthA++, T,0 ) < 0)\n        goto exception;\ndone:\n    JS_FreeValue(ctx, S);\n    JS_FreeValue(ctx, R);\n    return A;\n\nexception:\n    JS_FreeValue(ctx, A);\n    JS_FreeValue(ctx, S);\n    JS_FreeValue(ctx, R);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_string_substring(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue str, ret;\n    int a, b, start, end;\n    JSString *p;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return str;\n    p = JS_VALUE_GET_STRING(str);\n    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, p->len, 0)) {\n        JS_FreeValue(ctx, str);\n        return JS_EXCEPTION;\n    }\n    b = p->len;\n    if (!JS_IsUndefined(argv[1])) {\n        if (JS_ToInt32Clamp(ctx, &b, argv[1], 0, p->len, 0)) {\n            JS_FreeValue(ctx, str);\n            return JS_EXCEPTION;\n        }\n    }\n    if (a < b) {\n        start = a;\n        end = b;\n    } else {\n        start = b;\n        end = a;\n    }\n    ret = js_sub_string(ctx, p, start, end);\n    JS_FreeValue(ctx, str);\n    return ret;\n}\n\nstatic JSValue js_string_substr(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue str, ret;\n    int a, len, n;\n    JSString *p;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return str;\n    p = JS_VALUE_GET_STRING(str);\n    len = p->len;\n    if (JS_ToInt32Clamp(ctx, &a, argv[0], 0, len, len)) {\n        JS_FreeValue(ctx, str);\n        return JS_EXCEPTION;\n    }\n    n = len - a;\n    if (!JS_IsUndefined(argv[1])) {\n        if (JS_ToInt32Clamp(ctx, &n, argv[1], 0, len - a, 0)) {\n            JS_FreeValue(ctx, str);\n            return JS_EXCEPTION;\n        }\n    }\n    ret = js_sub_string(ctx, p, a, a + n);\n    JS_FreeValue(ctx, str);\n    return ret;\n}\n\nstatic JSValue js_string_slice(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    JSValue str, ret;\n    int len, start, end;\n    JSString *p;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return str;\n    p = JS_VALUE_GET_STRING(str);\n    len = p->len;\n    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len)) {\n        JS_FreeValue(ctx, str);\n        return JS_EXCEPTION;\n    }\n    end = len;\n    if (!JS_IsUndefined(argv[1])) {\n        if (JS_ToInt32Clamp(ctx, &end, argv[1], 0, len, len)) {\n            JS_FreeValue(ctx, str);\n            return JS_EXCEPTION;\n        }\n    }\n    ret = js_sub_string(ctx, p, start, max_int(end, start));\n    JS_FreeValue(ctx, str);\n    return ret;\n}\n\nstatic JSValue js_string_pad(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv, int padEnd)\n{\n    JSValue str, v = JS_UNDEFINED;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p, *p1 = NULL;\n    int n, len, c = ' ';\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        goto fail1;\n    if (JS_ToInt32Sat(ctx, &n, argv[0]))\n        goto fail2;\n    p = JS_VALUE_GET_STRING(str);\n    len = p->len;\n    if (len >= n)\n        return str;\n    if (argc > 1 && !JS_IsUndefined(argv[1])) {\n        v = JS_ToString(ctx, argv[1]);\n        if (JS_IsException(v))\n            goto fail2;\n        p1 = JS_VALUE_GET_STRING(v);\n        if (p1->len == 0) {\n            JS_FreeValue(ctx, v);\n            return str;\n        }\n        if (p1->len == 1) {\n            c = string_get(p1, 0);\n            p1 = NULL;\n        }\n    }\n    if (n > JS_STRING_LEN_MAX) {\n        JS_ThrowRangeError(ctx, \"invalid string length\");\n        goto fail3;\n    }\n    if (string_buffer_init(ctx, b, n))\n        goto fail3;\n    n -= len;\n    if (padEnd) {\n        if (string_buffer_concat(b, p, 0, len))\n            goto fail;\n    }\n    if (p1) {\n        while (n > 0) {\n            int chunk = min_int(n, p1->len);\n            if (string_buffer_concat(b, p1, 0, chunk))\n                goto fail;\n            n -= chunk;\n        }\n    } else {\n        if (string_buffer_fill(b, c, n))\n            goto fail;\n    }\n    if (!padEnd) {\n        if (string_buffer_concat(b, p, 0, len))\n            goto fail;\n    }\n    JS_FreeValue(ctx, v);\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n\nfail:\n    string_buffer_free(b);\nfail3:\n    JS_FreeValue(ctx, v);\nfail2:\n    JS_FreeValue(ctx, str);\nfail1:\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_string_repeat(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue str;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p;\n    int64_t val;\n    int n, len;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        goto fail;\n    if (JS_ToInt64Sat(ctx, &val, argv[0]))\n        goto fail;\n    if (val < 0 || val > 2147483647) {\n        JS_ThrowRangeError(ctx, \"invalid repeat count\");\n        goto fail;\n    }\n    n = val;\n    p = JS_VALUE_GET_STRING(str);\n    len = p->len;\n    if (len == 0 || n == 1)\n        return str;\n    // XXX: potential arithmetic overflow\n    if (val * len > JS_STRING_LEN_MAX) {\n        JS_ThrowRangeError(ctx, \"invalid string length\");\n        goto fail;\n    }\n    if (string_buffer_init2(ctx, b, n * len, p->is_wide_char))\n        goto fail;\n    if (len == 1) {\n        string_buffer_fill(b, string_get(p, 0), n);\n    } else {\n        while (n-- > 0) {\n            string_buffer_concat(b, p, 0, len);\n        }\n    }\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n\nfail:\n    JS_FreeValue(ctx, str);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_string_trim(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int magic)\n{\n    JSValue str, ret;\n    int a, b, len;\n    JSString *p;\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return str;\n    p = JS_VALUE_GET_STRING(str);\n    a = 0;\n    b = len = p->len;\n    if (magic & 1) {\n        while (a < len && lre_is_space(string_get(p, a)))\n            a++;\n    }\n    if (magic & 2) {\n        while (b > a && lre_is_space(string_get(p, b - 1)))\n            b--;\n    }\n    ret = js_sub_string(ctx, p, a, b);\n    JS_FreeValue(ctx, str);\n    return ret;\n}\n\n/* return 0 if before the first char */\nstatic int string_prevc(JSString *p, int *pidx)\n{\n    int idx, c, c1;\n\n    idx = *pidx;\n    if (idx <= 0)\n        return 0;\n    idx--;\n    if (p->is_wide_char) {\n        c = p->u.str16[idx];\n        if (is_lo_surrogate(c) && idx > 0) {\n            c1 = p->u.str16[idx - 1];\n            if (is_hi_surrogate(c1)) {\n                c = from_surrogate(c1, c);\n                idx--;\n            }\n        }\n    } else {\n        c = p->u.str8[idx];\n    }\n    *pidx = idx;\n    return c;\n}\n\nstatic BOOL test_final_sigma(JSString *p, int sigma_pos)\n{\n    int k, c1;\n\n    /* before C: skip case ignorable chars and check there is\n       a cased letter */\n    k = sigma_pos;\n    for(;;) {\n        c1 = string_prevc(p, &k);\n        if (!lre_is_case_ignorable(c1))\n            break;\n    }\n    if (!lre_is_cased(c1))\n        return FALSE;\n\n    /* after C: skip case ignorable chars and check there is\n       no cased letter */\n    k = sigma_pos + 1;\n    for(;;) {\n        if (k >= p->len)\n            return TRUE;\n        c1 = string_getc(p, &k);\n        if (!lre_is_case_ignorable(c1))\n            break;\n    }\n    return !lre_is_cased(c1);\n}\n\nstatic JSValue js_string_toLowerCase(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv, int to_lower)\n{\n    JSValue val;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p;\n    int i, c, j, l;\n    uint32_t res[LRE_CC_RES_LEN_MAX];\n\n    val = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    p = JS_VALUE_GET_STRING(val);\n    if (p->len == 0)\n        return val;\n    if (string_buffer_init(ctx, b, p->len))\n        goto fail;\n    for(i = 0; i < p->len;) {\n        c = string_getc(p, &i);\n        if (c == 0x3a3 && to_lower && test_final_sigma(p, i - 1)) {\n            res[0] = 0x3c2; /* final sigma */\n            l = 1;\n        } else {\n            l = lre_case_conv(res, c, to_lower);\n        }\n        for(j = 0; j < l; j++) {\n            if (string_buffer_putc(b, res[j]))\n                goto fail;\n        }\n    }\n    JS_FreeValue(ctx, val);\n    return string_buffer_end(b);\n fail:\n    JS_FreeValue(ctx, val);\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\n#ifdef CONFIG_ALL_UNICODE\n\n/* return (-1, NULL) if exception, otherwise (len, buf) */\nstatic int JS_ToUTF32String(JSContext *ctx, uint32_t **pbuf, JSValueConst val1)\n{\n    JSValue val;\n    JSString *p;\n    uint32_t *buf;\n    int i, j, len;\n\n    val = JS_ToString(ctx, val1);\n    if (JS_IsException(val))\n        return -1;\n    p = JS_VALUE_GET_STRING(val);\n    len = p->len;\n    /* UTF32 buffer length is len minus the number of correct surrogates pairs */\n    buf = js_malloc(ctx, sizeof(buf[0]) * max_int(len, 1));\n    if (!buf) {\n        JS_FreeValue(ctx, val);\n        goto fail;\n    }\n    for(i = j = 0; i < len;)\n        buf[j++] = string_getc(p, &i);\n    JS_FreeValue(ctx, val);\n    *pbuf = buf;\n    return j;\n fail:\n    *pbuf = NULL;\n    return -1;\n}\n\nstatic JSValue JS_NewUTF32String(JSContext *ctx, const uint32_t *buf, int len)\n{\n    int i;\n    StringBuffer b_s, *b = &b_s;\n    if (string_buffer_init(ctx, b, len))\n        return JS_EXCEPTION;\n    for(i = 0; i < len; i++) {\n        if (string_buffer_putc(b, buf[i]))\n            goto fail;\n    }\n    return string_buffer_end(b);\n fail:\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\nstatic int js_string_normalize1(JSContext *ctx, uint32_t **pout_buf,\n                                JSValueConst val,\n                                UnicodeNormalizationEnum n_type)\n{\n    int buf_len, out_len;\n    uint32_t *buf, *out_buf;\n\n    buf_len = JS_ToUTF32String(ctx, &buf, val);\n    if (buf_len < 0)\n        return -1;\n    out_len = unicode_normalize(&out_buf, buf, buf_len, n_type,\n                                ctx->rt, (DynBufReallocFunc *)js_realloc_rt);\n    js_free(ctx, buf);\n    if (out_len < 0)\n        return -1;\n    *pout_buf = out_buf;\n    return out_len;\n}\n\nstatic JSValue js_string_normalize(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    const char *form, *p;\n    size_t form_len;\n    int is_compat, out_len;\n    UnicodeNormalizationEnum n_type;\n    JSValue val;\n    uint32_t *out_buf;\n\n    val = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n\n    if (argc == 0 || JS_IsUndefined(argv[0])) {\n        n_type = UNICODE_NFC;\n    } else {\n        form = JS_ToCStringLen(ctx, &form_len, argv[0]);\n        if (!form)\n            goto fail1;\n        p = form;\n        if (p[0] != 'N' || p[1] != 'F')\n            goto bad_form;\n        p += 2;\n        is_compat = FALSE;\n        if (*p == 'K') {\n            is_compat = TRUE;\n            p++;\n        }\n        if (*p == 'C' || *p == 'D') {\n            n_type = UNICODE_NFC + is_compat * 2 + (*p - 'C');\n            if ((p + 1 - form) != form_len)\n                goto bad_form;\n        } else {\n        bad_form:\n            JS_FreeCString(ctx, form);\n            JS_ThrowRangeError(ctx, \"bad normalization form\");\n        fail1:\n            JS_FreeValue(ctx, val);\n            return JS_EXCEPTION;\n        }\n        JS_FreeCString(ctx, form);\n    }\n\n    out_len = js_string_normalize1(ctx, &out_buf, val, n_type);\n    JS_FreeValue(ctx, val);\n    if (out_len < 0)\n        return JS_EXCEPTION;\n    val = JS_NewUTF32String(ctx, out_buf, out_len);\n    js_free(ctx, out_buf);\n    return val;\n}\n\n/* return < 0, 0 or > 0 */\nstatic int js_UTF32_compare(const uint32_t *buf1, int buf1_len,\n                            const uint32_t *buf2, int buf2_len)\n{\n    int i, len, c, res;\n    len = min_int(buf1_len, buf2_len);\n    for(i = 0; i < len; i++) {\n        /* Note: range is limited so a subtraction is valid */\n        c = buf1[i] - buf2[i];\n        if (c != 0)\n            return c;\n    }\n    if (buf1_len == buf2_len)\n        res = 0;\n    else if (buf1_len < buf2_len)\n        res = -1;\n    else\n        res = 1;\n    return res;\n}\n\nstatic JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JSValue a, b;\n    int cmp, a_len, b_len;\n    uint32_t *a_buf, *b_buf;\n\n    a = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(a))\n        return JS_EXCEPTION;\n    b = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(b)) {\n        JS_FreeValue(ctx, a);\n        return JS_EXCEPTION;\n    }\n    a_len = js_string_normalize1(ctx, &a_buf, a, UNICODE_NFC);\n    JS_FreeValue(ctx, a);\n    if (a_len < 0) {\n        JS_FreeValue(ctx, b);\n        return JS_EXCEPTION;\n    }\n\n    b_len = js_string_normalize1(ctx, &b_buf, b, UNICODE_NFC);\n    JS_FreeValue(ctx, b);\n    if (b_len < 0) {\n        js_free(ctx, a_buf);\n        return JS_EXCEPTION;\n    }\n    cmp = js_UTF32_compare(a_buf, a_len, b_buf, b_len);\n    js_free(ctx, a_buf);\n    js_free(ctx, b_buf);\n    return JS_NewInt32(ctx, cmp);\n}\n#else /* CONFIG_ALL_UNICODE */\nstatic JSValue js_string_localeCompare(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JSValue a, b;\n    int cmp;\n\n    a = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(a))\n        return JS_EXCEPTION;\n    b = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(b)) {\n        JS_FreeValue(ctx, a);\n        return JS_EXCEPTION;\n    }\n    cmp = js_string_compare(ctx, JS_VALUE_GET_STRING(a), JS_VALUE_GET_STRING(b));\n    JS_FreeValue(ctx, a);\n    JS_FreeValue(ctx, b);\n    return JS_NewInt32(ctx, cmp);\n}\n#endif /* !CONFIG_ALL_UNICODE */\n\n/* also used for String.prototype.valueOf */\nstatic JSValue js_string_toString(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    return js_thisStringValue(ctx, this_val);\n}\n\n/* String Iterator */\n\nstatic JSValue js_string_iterator_next(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv,\n                                       BOOL *pdone, int magic)\n{\n    JSArrayIteratorData *it;\n    uint32_t idx, c, start;\n    JSString *p;\n\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_STRING_ITERATOR);\n    if (!it) {\n        *pdone = FALSE;\n        return JS_EXCEPTION;\n    }\n    if (JS_IsUndefined(it->obj))\n        goto done;\n    p = JS_VALUE_GET_STRING(it->obj);\n    idx = it->idx;\n    if (idx >= p->len) {\n        JS_FreeValue(ctx, it->obj);\n        it->obj = JS_UNDEFINED;\n    done:\n        *pdone = TRUE;\n        return JS_UNDEFINED;\n    }\n\n    start = idx;\n    c = string_getc(p, (int *)&idx);\n    it->idx = idx;\n    *pdone = FALSE;\n    if (c <= 0xffff) {\n        return js_new_string_char(ctx, c);\n    } else {\n        return js_new_string16_len(ctx, p->u.str16 + start, 2);\n    }\n}\n\n/* ES6 Annex B 2.3.2 etc. */\nenum {\n    magic_string_anchor,\n    magic_string_big,\n    magic_string_blink,\n    magic_string_bold,\n    magic_string_fixed,\n    magic_string_fontcolor,\n    magic_string_fontsize,\n    magic_string_italics,\n    magic_string_link,\n    magic_string_small,\n    magic_string_strike,\n    magic_string_sub,\n    magic_string_sup,\n};\n\nstatic JSValue js_string_CreateHTML(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv, int magic)\n{\n    JSValue str;\n    const JSString *p;\n    StringBuffer b_s, *b = &b_s;\n    static struct { const char *tag, *attr; } const defs[] = {\n        { \"a\", \"name\" }, { \"big\", NULL }, { \"blink\", NULL }, { \"b\", NULL },\n        { \"tt\", NULL }, { \"font\", \"color\" }, { \"font\", \"size\" }, { \"i\", NULL },\n        { \"a\", \"href\" }, { \"small\", NULL }, { \"strike\", NULL },\n        { \"sub\", NULL }, { \"sup\", NULL },\n    };\n\n    str = JS_ToStringCheckObject(ctx, this_val);\n    if (JS_IsException(str))\n        return JS_EXCEPTION;\n    string_buffer_init(ctx, b, 7);\n    string_buffer_putc8(b, '<');\n    string_buffer_puts8(b, defs[magic].tag);\n    if (defs[magic].attr) {\n        // r += \" \" + attr + \"=\\\"\" + value + \"\\\"\";\n        JSValue value;\n        int i;\n\n        string_buffer_putc8(b, ' ');\n        string_buffer_puts8(b, defs[magic].attr);\n        string_buffer_puts8(b, \"=\\\"\");\n        value = JS_ToStringCheckObject(ctx, argv[0]);\n        if (JS_IsException(value)) {\n            JS_FreeValue(ctx, str);\n            string_buffer_free(b);\n            return JS_EXCEPTION;\n        }\n        p = JS_VALUE_GET_STRING(value);\n        for (i = 0; i < p->len; i++) {\n            int c = string_get(p, i);\n            if (c == '\"') {\n                string_buffer_puts8(b, \"&quot;\");\n            } else {\n                string_buffer_putc16(b, c);\n            }\n        }\n        JS_FreeValue(ctx, value);\n        string_buffer_putc8(b, '\\\"');\n    }\n    // return r + \">\" + str + \"</\" + tag + \">\";\n    string_buffer_putc8(b, '>');\n    string_buffer_concat_value_free(b, str);\n    string_buffer_puts8(b, \"</\");\n    string_buffer_puts8(b, defs[magic].tag);\n    string_buffer_putc8(b, '>');\n    return string_buffer_end(b);\n}\n\nstatic const JSCFunctionListEntry js_string_funcs[] = {\n    JS_CFUNC_DEF(\"fromCharCode\", 1, js_string_fromCharCode ),\n    JS_CFUNC_DEF(\"fromCodePoint\", 1, js_string_fromCodePoint ),\n    JS_CFUNC_DEF(\"raw\", 1, js_string_raw ),\n};\n\nstatic const JSCFunctionListEntry js_string_proto_funcs[] = {\n    JS_PROP_INT32_DEF(\"length\", 0, JS_PROP_CONFIGURABLE ),\n    JS_CFUNC_MAGIC_DEF(\"at\", 1, js_string_charAt, 1 ),\n    JS_CFUNC_DEF(\"charCodeAt\", 1, js_string_charCodeAt ),\n    JS_CFUNC_MAGIC_DEF(\"charAt\", 1, js_string_charAt, 0 ),\n    JS_CFUNC_DEF(\"concat\", 1, js_string_concat ),\n    JS_CFUNC_DEF(\"codePointAt\", 1, js_string_codePointAt ),\n    JS_CFUNC_DEF(\"isWellFormed\", 0, js_string_isWellFormed ),\n    JS_CFUNC_DEF(\"toWellFormed\", 0, js_string_toWellFormed ),\n    JS_CFUNC_MAGIC_DEF(\"indexOf\", 1, js_string_indexOf, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"lastIndexOf\", 1, js_string_indexOf, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"includes\", 1, js_string_includes, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"endsWith\", 1, js_string_includes, 2 ),\n    JS_CFUNC_MAGIC_DEF(\"startsWith\", 1, js_string_includes, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"match\", 1, js_string_match, JS_ATOM_Symbol_match ),\n    JS_CFUNC_MAGIC_DEF(\"matchAll\", 1, js_string_match, JS_ATOM_Symbol_matchAll ),\n    JS_CFUNC_MAGIC_DEF(\"search\", 1, js_string_match, JS_ATOM_Symbol_search ),\n    JS_CFUNC_DEF(\"split\", 2, js_string_split ),\n    JS_CFUNC_DEF(\"substring\", 2, js_string_substring ),\n    JS_CFUNC_DEF(\"substr\", 2, js_string_substr ),\n    JS_CFUNC_DEF(\"slice\", 2, js_string_slice ),\n    JS_CFUNC_DEF(\"repeat\", 1, js_string_repeat ),\n    JS_CFUNC_MAGIC_DEF(\"replace\", 2, js_string_replace, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"replaceAll\", 2, js_string_replace, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"padEnd\", 1, js_string_pad, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"padStart\", 1, js_string_pad, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"trim\", 0, js_string_trim, 3 ),\n    JS_CFUNC_MAGIC_DEF(\"trimEnd\", 0, js_string_trim, 2 ),\n    JS_ALIAS_DEF(\"trimRight\", \"trimEnd\" ),\n    JS_CFUNC_MAGIC_DEF(\"trimStart\", 0, js_string_trim, 1 ),\n    JS_ALIAS_DEF(\"trimLeft\", \"trimStart\" ),\n    JS_CFUNC_DEF(\"toString\", 0, js_string_toString ),\n    JS_CFUNC_DEF(\"valueOf\", 0, js_string_toString ),\n    JS_CFUNC_MAGIC_DEF(\"toLowerCase\", 0, js_string_toLowerCase, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"toUpperCase\", 0, js_string_toLowerCase, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleLowerCase\", 0, js_string_toLowerCase, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleUpperCase\", 0, js_string_toLowerCase, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"[Symbol.iterator]\", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE | 4 ),\n    /* ES6 Annex B 2.3.2 etc. */\n    JS_CFUNC_MAGIC_DEF(\"anchor\", 1, js_string_CreateHTML, magic_string_anchor ),\n    JS_CFUNC_MAGIC_DEF(\"big\", 0, js_string_CreateHTML, magic_string_big ),\n    JS_CFUNC_MAGIC_DEF(\"blink\", 0, js_string_CreateHTML, magic_string_blink ),\n    JS_CFUNC_MAGIC_DEF(\"bold\", 0, js_string_CreateHTML, magic_string_bold ),\n    JS_CFUNC_MAGIC_DEF(\"fixed\", 0, js_string_CreateHTML, magic_string_fixed ),\n    JS_CFUNC_MAGIC_DEF(\"fontcolor\", 1, js_string_CreateHTML, magic_string_fontcolor ),\n    JS_CFUNC_MAGIC_DEF(\"fontsize\", 1, js_string_CreateHTML, magic_string_fontsize ),\n    JS_CFUNC_MAGIC_DEF(\"italics\", 0, js_string_CreateHTML, magic_string_italics ),\n    JS_CFUNC_MAGIC_DEF(\"link\", 1, js_string_CreateHTML, magic_string_link ),\n    JS_CFUNC_MAGIC_DEF(\"small\", 0, js_string_CreateHTML, magic_string_small ),\n    JS_CFUNC_MAGIC_DEF(\"strike\", 0, js_string_CreateHTML, magic_string_strike ),\n    JS_CFUNC_MAGIC_DEF(\"sub\", 0, js_string_CreateHTML, magic_string_sub ),\n    JS_CFUNC_MAGIC_DEF(\"sup\", 0, js_string_CreateHTML, magic_string_sup ),\n};\n\nstatic const JSCFunctionListEntry js_string_iterator_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_string_iterator_next, 0 ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"String Iterator\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_string_proto_normalize[] = {\n#ifdef CONFIG_ALL_UNICODE\n    JS_CFUNC_DEF(\"normalize\", 0, js_string_normalize ),\n#endif\n    JS_CFUNC_DEF(\"localeCompare\", 1, js_string_localeCompare ),\n};\n\nint JS_AddIntrinsicStringNormalize(JSContext *ctx)\n{\n    return JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_STRING], js_string_proto_normalize,\n                                      countof(js_string_proto_normalize));\n}\n\n/* Math */\n\n/* precondition: a and b are not NaN */\nstatic double js_fmin(double a, double b)\n{\n    if (a == 0 && b == 0) {\n        JSFloat64Union a1, b1;\n        a1.d = a;\n        b1.d = b;\n        a1.u64 |= b1.u64;\n        return a1.d;\n    } else {\n        return fmin(a, b);\n    }\n}\n\n/* precondition: a and b are not NaN */\nstatic double js_fmax(double a, double b)\n{\n    if (a == 0 && b == 0) {\n        JSFloat64Union a1, b1;\n        a1.d = a;\n        b1.d = b;\n        a1.u64 &= b1.u64;\n        return a1.d;\n    } else {\n        return fmax(a, b);\n    }\n}\n\nstatic JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv, int magic)\n{\n    BOOL is_max = magic;\n    double r, a;\n    int i;\n    uint32_t tag;\n\n    if (unlikely(argc == 0)) {\n        return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);\n    }\n\n    tag = JS_VALUE_GET_TAG(argv[0]);\n    if (tag == JS_TAG_INT) {\n        int a1, r1 = JS_VALUE_GET_INT(argv[0]);\n        for(i = 1; i < argc; i++) {\n            tag = JS_VALUE_GET_TAG(argv[i]);\n            if (tag != JS_TAG_INT) {\n                r = r1;\n                goto generic_case;\n            }\n            a1 = JS_VALUE_GET_INT(argv[i]);\n            if (is_max)\n                r1 = max_int(r1, a1);\n            else\n                r1 = min_int(r1, a1);\n\n        }\n        return JS_NewInt32(ctx, r1);\n    } else {\n        if (JS_ToFloat64(ctx, &r, argv[0]))\n            return JS_EXCEPTION;\n        i = 1;\n    generic_case:\n        while (i < argc) {\n            if (JS_ToFloat64(ctx, &a, argv[i]))\n                return JS_EXCEPTION;\n            if (!isnan(r)) {\n                if (isnan(a)) {\n                    r = a;\n                } else {\n                    if (is_max)\n                        r = js_fmax(r, a);\n                    else\n                        r = js_fmin(r, a);\n                }\n            }\n            i++;\n        }\n        return JS_NewFloat64(ctx, r);\n    }\n}\n\nstatic double js_math_sign(double a)\n{\n    if (isnan(a) || a == 0.0)\n        return a;\n    if (a < 0)\n        return -1;\n    else\n        return 1;\n}\n\nstatic double js_math_round(double a)\n{\n    JSFloat64Union u;\n    uint64_t frac_mask, one;\n    unsigned int e, s;\n\n    u.d = a;\n    e = (u.u64 >> 52) & 0x7ff;\n    if (e < 1023) {\n        /* abs(a) < 1 */\n        if (e == (1023 - 1) && u.u64 != 0xbfe0000000000000) {\n            /* abs(a) > 0.5 or a = 0.5: return +/-1.0 */\n            u.u64 = (u.u64 & ((uint64_t)1 << 63)) | ((uint64_t)1023 << 52);\n        } else {\n            /* return +/-0.0 */\n            u.u64 &= (uint64_t)1 << 63;\n        }\n    } else if (e < (1023 + 52)) {\n        s = u.u64 >> 63;\n        one = (uint64_t)1 << (52 - (e - 1023));\n        frac_mask = one - 1;\n        u.u64 += (one >> 1) - s;\n        u.u64 &= ~frac_mask; /* truncate to an integer */\n    }\n    /* otherwise: abs(a) >= 2^52, or NaN, +/-Infinity: no change */\n    return u.d;\n}\n\nstatic JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    double r, a;\n    int i;\n\n    r = 0;\n    if (argc > 0) {\n        if (JS_ToFloat64(ctx, &r, argv[0]))\n            return JS_EXCEPTION;\n        if (argc == 1) {\n            r = fabs(r);\n        } else {\n            /* use the built-in function to minimize precision loss */\n            for (i = 1; i < argc; i++) {\n                if (JS_ToFloat64(ctx, &a, argv[i]))\n                    return JS_EXCEPTION;\n                r = hypot(r, a);\n            }\n        }\n    }\n    return JS_NewFloat64(ctx, r);\n}\n\nstatic double js_math_f16round(double a)\n{\n    return fromfp16(tofp16(a));\n}\n\nstatic double js_math_fround(double a)\n{\n    return (float)a;\n}\n\nstatic JSValue js_math_imul(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    uint32_t a, b, c;\n    int32_t d;\n\n    if (JS_ToUint32(ctx, &a, argv[0]))\n        return JS_EXCEPTION;\n    if (JS_ToUint32(ctx, &b, argv[1]))\n        return JS_EXCEPTION;\n    c = a * b;\n    memcpy(&d, &c, sizeof(d));\n    return JS_NewInt32(ctx, d);\n}\n\nstatic JSValue js_math_clz32(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    uint32_t a, r;\n\n    if (JS_ToUint32(ctx, &a, argv[0]))\n        return JS_EXCEPTION;\n    if (a == 0)\n        r = 32;\n    else\n        r = clz32(a);\n    return JS_NewInt32(ctx, r);\n}\n\ntypedef enum {\n    SUM_PRECISE_STATE_FINITE,\n    SUM_PRECISE_STATE_INFINITY,\n    SUM_PRECISE_STATE_MINUS_INFINITY, /* must be after SUM_PRECISE_STATE_INFINITY */\n    SUM_PRECISE_STATE_NAN, /* must be after SUM_PRECISE_STATE_MINUS_INFINITY */\n} SumPreciseStateEnum;\n\n#define SP_LIMB_BITS 56\n#define SP_RND_BITS (SP_LIMB_BITS - 53)\n/* we add one extra limb to avoid having to test for overflows during the sum */\n#define SUM_PRECISE_ACC_LEN 39\n\n#define SUM_PRECISE_COUNTER_INIT 250\n\ntypedef struct {\n    SumPreciseStateEnum state;\n    uint32_t counter;\n    int n_limbs; /* 'acc' contains n_limbs and is not necessarily\n                    acc[n_limb - 1] may be 0. 0 indicates minus zero\n                    result when state = SUM_PRECISE_STATE_FINITE */\n    int64_t acc[SUM_PRECISE_ACC_LEN];\n} SumPreciseState;\n\nstatic void sum_precise_init(SumPreciseState *s)\n{\n    memset(s->acc, 0, sizeof(s->acc));\n    s->state = SUM_PRECISE_STATE_FINITE;\n    s->counter = SUM_PRECISE_COUNTER_INIT;\n    s->n_limbs = 0;\n}\n\nstatic void sum_precise_renorm(SumPreciseState *s)\n{\n    int64_t v, carry;\n    int i;\n    \n    carry = 0;\n    for(i = 0; i < s->n_limbs; i++) {\n        v = s->acc[i] + carry;\n        s->acc[i] = v & (((uint64_t)1 << SP_LIMB_BITS) - 1);\n        carry = v >> SP_LIMB_BITS;\n    }\n    /* we add a failsafe but it should be never reached in a\n       reasonnable amount of time */\n    if (carry != 0 && s->n_limbs < SUM_PRECISE_ACC_LEN)\n        s->acc[s->n_limbs++] = carry;\n}\n\nstatic void sum_precise_add(SumPreciseState *s, double d)\n{\n    uint64_t a, m, a0, a1;\n    int sgn, e, p;\n    unsigned int shift;\n    \n    a = float64_as_uint64(d);\n    sgn = a >> 63;\n    e = (a >> 52) & ((1 << 11) - 1);\n    m = a & (((uint64_t)1 << 52) - 1);\n    if (unlikely(e == 2047)) {\n        if (m == 0) {\n            /* +/- infinity */\n            if (s->state == SUM_PRECISE_STATE_NAN ||\n                (s->state == SUM_PRECISE_STATE_MINUS_INFINITY && !sgn) ||\n                (s->state == SUM_PRECISE_STATE_INFINITY && sgn)) {\n                s->state = SUM_PRECISE_STATE_NAN;\n            } else {\n                s->state = SUM_PRECISE_STATE_INFINITY + sgn;\n            }\n        } else {\n            /* NaN */\n            s->state = SUM_PRECISE_STATE_NAN;\n        }\n    } else if (e == 0) {\n        if (likely(m == 0)) {\n            /* zero */\n            if (s->n_limbs == 0 && !sgn)\n                s->n_limbs = 1;\n        } else {\n            /* subnormal */\n            p = 0;\n            shift = 0;\n            goto add;\n        }\n    } else {\n        /* Note: we sum even if state != SUM_PRECISE_STATE_FINITE to\n           avoid tests */\n        m |= (uint64_t)1 << 52;\n        shift = e - 1;\n        /* 'p' is the position of a0 in acc. The division is normally\n           implementation as a multiplication by the compiler. */\n        p = shift / SP_LIMB_BITS;\n        shift %= SP_LIMB_BITS;\n    add:\n        a0 = (m << shift) & (((uint64_t)1 << SP_LIMB_BITS) - 1);\n        a1 = m >> (SP_LIMB_BITS - shift);\n        if (!sgn) {\n            s->acc[p] += a0;\n            s->acc[p + 1] += a1;\n        } else {\n            s->acc[p] -= a0;\n            s->acc[p + 1] -= a1;\n        }\n        s->n_limbs = max_int(s->n_limbs, p + 2);\n\n        if (unlikely(--s->counter == 0)) {\n            s->counter = SUM_PRECISE_COUNTER_INIT;\n            sum_precise_renorm(s);\n        }\n    }\n}\n\nstatic double sum_precise_get_result(SumPreciseState *s)\n{\n    int n, shift, e, p, is_neg;\n    uint64_t m, addend;\n        \n    if (s->state != SUM_PRECISE_STATE_FINITE) {\n        switch(s->state) {\n        default:\n        case SUM_PRECISE_STATE_INFINITY:\n            return INFINITY;\n        case SUM_PRECISE_STATE_MINUS_INFINITY:\n            return -INFINITY;\n        case SUM_PRECISE_STATE_NAN:\n            return NAN;\n        }\n    }\n\n    sum_precise_renorm(s);\n\n    /* extract the sign and absolute value */\n#if 0\n    {\n        int i;\n        printf(\"len=%d:\", s->n_limbs);\n        for(i = s->n_limbs - 1; i >= 0; i--)\n            printf(\" %014lx\", s->acc[i]);\n        printf(\"\\n\");\n    }\n#endif\n    n = s->n_limbs;\n    /* minus zero result */\n    if (n == 0)\n        return -0.0;\n    \n    /* normalize */\n    while (n > 0 && s->acc[n - 1] == 0)\n        n--;\n    /* zero result. The spec tells it is always positive in the finite case */\n    if (n == 0)\n        return 0.0;\n    is_neg = (s->acc[n - 1] < 0);\n    if (is_neg) {\n        uint64_t v, carry;\n        int i;\n        /* negate */\n        /* XXX: do it only when needed */\n        carry = 1;\n        for(i = 0; i < n - 1; i++) {\n            v = (((uint64_t)1 << SP_LIMB_BITS) - 1) - s->acc[i] + carry;\n            carry = v >> SP_LIMB_BITS;\n            s->acc[i] = v & (((uint64_t)1 << SP_LIMB_BITS) - 1);\n        }\n        s->acc[n - 1] = -s->acc[n - 1] + carry - 1;\n        while (n > 1 && s->acc[n - 1] == 0)\n            n--;\n    }\n    /* subnormal case */\n    if (n == 1 && s->acc[0] < ((uint64_t)1 << 52))\n        return uint64_as_float64(((uint64_t)is_neg << 63) | s->acc[0]); \n    /* normal case */\n    e = n * SP_LIMB_BITS;\n    p = n - 1;\n    m = s->acc[p];\n    shift = clz64(m) - (64 - SP_LIMB_BITS);\n    e = e - shift - 52;\n    if (shift != 0) {\n        m <<= shift;\n        if (p > 0) {\n            int shift1;\n            uint64_t nz;\n            p--;\n            shift1 = SP_LIMB_BITS - shift;\n            nz = s->acc[p] & (((uint64_t)1 << shift1) - 1);\n            m = m | (s->acc[p] >> shift1) | (nz != 0);\n        }\n    }\n    if ((m & ((1 << SP_RND_BITS) - 1)) == (1 << (SP_RND_BITS - 1))) {\n        /* see if the LSB part is non zero for the final rounding  */\n        while (p > 0) {\n            p--;\n            if (s->acc[p] != 0) {\n                m |= 1;\n                break;\n            }\n        }\n    }\n    /* rounding to nearest with ties to even */\n    addend = (1 << (SP_RND_BITS - 1)) - 1 + ((m >> SP_RND_BITS) & 1);\n    m = (m + addend) >> SP_RND_BITS;\n    /* handle overflow in the rounding */\n    if (m == ((uint64_t)1 << 53))\n        e++;\n    if (unlikely(e >= 2047)) {\n        /* infinity */\n        return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)2047 << 52));\n    } else {\n        m &= (((uint64_t)1 << 52) - 1);\n        return uint64_as_float64(((uint64_t)is_neg << 63) | ((uint64_t)e << 52) | m);\n    }\n}\n\nstatic JSValue js_math_sumPrecise(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValue iter, next, item, ret;\n    uint32_t tag;\n    int done;\n    double d;\n    SumPreciseState s_s, *s = &s_s;\n\n    iter = JS_GetIterator(ctx, argv[0], FALSE);\n    if (JS_IsException(iter))\n        return JS_EXCEPTION;\n    ret = JS_EXCEPTION;\n    next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next))\n        goto fail;\n    sum_precise_init(s);\n    for (;;) {\n        item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto fail;\n        if (done)\n            break;\n        tag = JS_VALUE_GET_TAG(item);\n        if (JS_TAG_IS_FLOAT64(tag)) {\n            d = JS_VALUE_GET_FLOAT64(item);\n        } else if (tag == JS_TAG_INT) {\n            d = JS_VALUE_GET_INT(item);\n        } else {\n            JS_FreeValue(ctx, item);\n            JS_ThrowTypeError(ctx, \"not a number\");\n            JS_IteratorClose(ctx, iter, TRUE);\n            goto fail;\n        }\n        sum_precise_add(s, d);\n    }\n    ret = __JS_NewFloat64(ctx, sum_precise_get_result(s));\nfail:\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return ret;\n}\n\n/* xorshift* random number generator by Marsaglia */\nstatic uint64_t xorshift64star(uint64_t *pstate)\n{\n    uint64_t x;\n    x = *pstate;\n    x ^= x >> 12;\n    x ^= x << 25;\n    x ^= x >> 27;\n    *pstate = x;\n    return x * 0x2545F4914F6CDD1D;\n}\n\nstatic void js_random_init(JSContext *ctx)\n{\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    ctx->random_state = ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;\n    /* the state must be non zero */\n    if (ctx->random_state == 0)\n        ctx->random_state = 1;\n}\n\nstatic JSValue js_math_random(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSFloat64Union u;\n    uint64_t v;\n\n    v = xorshift64star(&ctx->random_state);\n    /* 1.0 <= u.d < 2 */\n    u.u64 = ((uint64_t)0x3ff << 52) | (v >> 12);\n    return __JS_NewFloat64(ctx, u.d - 1.0);\n}\n\nstatic const JSCFunctionListEntry js_math_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"min\", 2, js_math_min_max, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"max\", 2, js_math_min_max, 1 ),\n    JS_CFUNC_SPECIAL_DEF(\"abs\", 1, f_f, fabs ),\n    JS_CFUNC_SPECIAL_DEF(\"floor\", 1, f_f, floor ),\n    JS_CFUNC_SPECIAL_DEF(\"ceil\", 1, f_f, ceil ),\n    JS_CFUNC_SPECIAL_DEF(\"round\", 1, f_f, js_math_round ),\n    JS_CFUNC_SPECIAL_DEF(\"sqrt\", 1, f_f, sqrt ),\n\n    JS_CFUNC_SPECIAL_DEF(\"acos\", 1, f_f, acos ),\n    JS_CFUNC_SPECIAL_DEF(\"asin\", 1, f_f, asin ),\n    JS_CFUNC_SPECIAL_DEF(\"atan\", 1, f_f, atan ),\n    JS_CFUNC_SPECIAL_DEF(\"atan2\", 2, f_f_f, atan2 ),\n    JS_CFUNC_SPECIAL_DEF(\"cos\", 1, f_f, cos ),\n    JS_CFUNC_SPECIAL_DEF(\"exp\", 1, f_f, exp ),\n    JS_CFUNC_SPECIAL_DEF(\"log\", 1, f_f, log ),\n    JS_CFUNC_SPECIAL_DEF(\"pow\", 2, f_f_f, js_pow ),\n    JS_CFUNC_SPECIAL_DEF(\"sin\", 1, f_f, sin ),\n    JS_CFUNC_SPECIAL_DEF(\"tan\", 1, f_f, tan ),\n    /* ES6 */\n    JS_CFUNC_SPECIAL_DEF(\"trunc\", 1, f_f, trunc ),\n    JS_CFUNC_SPECIAL_DEF(\"sign\", 1, f_f, js_math_sign ),\n    JS_CFUNC_SPECIAL_DEF(\"cosh\", 1, f_f, cosh ),\n    JS_CFUNC_SPECIAL_DEF(\"sinh\", 1, f_f, sinh ),\n    JS_CFUNC_SPECIAL_DEF(\"tanh\", 1, f_f, tanh ),\n    JS_CFUNC_SPECIAL_DEF(\"acosh\", 1, f_f, acosh ),\n    JS_CFUNC_SPECIAL_DEF(\"asinh\", 1, f_f, asinh ),\n    JS_CFUNC_SPECIAL_DEF(\"atanh\", 1, f_f, atanh ),\n    JS_CFUNC_SPECIAL_DEF(\"expm1\", 1, f_f, expm1 ),\n    JS_CFUNC_SPECIAL_DEF(\"log1p\", 1, f_f, log1p ),\n    JS_CFUNC_SPECIAL_DEF(\"log2\", 1, f_f, log2 ),\n    JS_CFUNC_SPECIAL_DEF(\"log10\", 1, f_f, log10 ),\n    JS_CFUNC_SPECIAL_DEF(\"cbrt\", 1, f_f, cbrt ),\n    JS_CFUNC_DEF(\"hypot\", 2, js_math_hypot ),\n    JS_CFUNC_DEF(\"random\", 0, js_math_random ),\n    JS_CFUNC_SPECIAL_DEF(\"f16round\", 1, f_f, js_math_f16round ),\n    JS_CFUNC_SPECIAL_DEF(\"fround\", 1, f_f, js_math_fround ),\n    JS_CFUNC_DEF(\"imul\", 2, js_math_imul ),\n    JS_CFUNC_DEF(\"clz32\", 1, js_math_clz32 ),\n    JS_CFUNC_DEF(\"sumPrecise\", 1, js_math_sumPrecise ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Math\", JS_PROP_CONFIGURABLE ),\n    JS_PROP_DOUBLE_DEF(\"E\", 2.718281828459045, 0 ),\n    JS_PROP_DOUBLE_DEF(\"LN10\", 2.302585092994046, 0 ),\n    JS_PROP_DOUBLE_DEF(\"LN2\", 0.6931471805599453, 0 ),\n    JS_PROP_DOUBLE_DEF(\"LOG2E\", 1.4426950408889634, 0 ),\n    JS_PROP_DOUBLE_DEF(\"LOG10E\", 0.4342944819032518, 0 ),\n    JS_PROP_DOUBLE_DEF(\"PI\", 3.141592653589793, 0 ),\n    JS_PROP_DOUBLE_DEF(\"SQRT1_2\", 0.7071067811865476, 0 ),\n    JS_PROP_DOUBLE_DEF(\"SQRT2\", 1.4142135623730951, 0 ),\n};\n\nstatic const JSCFunctionListEntry js_math_obj[] = {\n    JS_OBJECT_DEF(\"Math\", js_math_funcs, countof(js_math_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\n};\n\n/* Date */\n\n/* OS dependent. d = argv[0] is in ms from 1970. Return the difference\n   between UTC time and local time 'd' in minutes */\nstatic int getTimezoneOffset(int64_t time)\n{\n    time_t ti;\n    int res;\n\n    time /= 1000; /* convert to seconds */\n    if (sizeof(time_t) == 4) {\n        /* on 32-bit systems, we need to clamp the time value to the\n           range of `time_t`. This is better than truncating values to\n           32 bits and hopefully provides the same result as 64-bit\n           implementation of localtime_r.\n         */\n        if ((time_t)-1 < 0) {\n            if (time < INT32_MIN) {\n                time = INT32_MIN;\n            } else if (time > INT32_MAX) {\n                time = INT32_MAX;\n            }\n        } else {\n            if (time < 0) {\n                time = 0;\n            } else if (time > UINT32_MAX) {\n                time = UINT32_MAX;\n            }\n        }\n    }\n    ti = time;\n#if defined(_WIN32)\n    {\n        struct tm *tm;\n        time_t gm_ti, loc_ti;\n\n        tm = gmtime(&ti);\n        if (!tm)\n            return 0;\n        gm_ti = mktime(tm);\n\n        tm = localtime(&ti);\n        if (!tm)\n            return 0;\n        loc_ti = mktime(tm);\n\n        res = (gm_ti - loc_ti) / 60;\n    }\n#else\n    {\n        struct tm tm;\n        localtime_r(&ti, &tm);\n        res = -tm.tm_gmtoff / 60;\n    }\n#endif\n    return res;\n}\n\n#if 0\nstatic JSValue js___date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,\n                                           int argc, JSValueConst *argv)\n{\n    double dd;\n\n    if (JS_ToFloat64(ctx, &dd, argv[0]))\n        return JS_EXCEPTION;\n    if (isnan(dd))\n        return __JS_NewFloat64(ctx, dd);\n    else\n        return JS_NewInt32(ctx, getTimezoneOffset((int64_t)dd));\n}\n\nstatic JSValue js_get_prototype_from_ctor(JSContext *ctx, JSValueConst ctor,\n                                          JSValueConst def_proto)\n{\n    JSValue proto;\n    proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);\n    if (JS_IsException(proto))\n        return proto;\n    if (!JS_IsObject(proto)) {\n        JS_FreeValue(ctx, proto);\n        proto = JS_DupValue(ctx, def_proto);\n    }\n    return proto;\n}\n\n/* create a new date object */\nstatic JSValue js___date_create(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue obj, proto;\n    proto = js_get_prototype_from_ctor(ctx, argv[0], argv[1]);\n    if (JS_IsException(proto))\n        return proto;\n    obj = JS_NewObjectProtoClass(ctx, proto, JS_CLASS_DATE);\n    JS_FreeValue(ctx, proto);\n    if (!JS_IsException(obj))\n        JS_SetObjectData(ctx, obj, JS_DupValue(ctx, argv[2]));\n    return obj;\n}\n#endif\n\n/* RegExp */\n\nstatic void js_regexp_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSRegExp *re = &p->u.regexp;\n    if (re->bytecode != NULL)\n        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->bytecode));\n    if (re->pattern != NULL)\n        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_STRING, re->pattern));\n}\n\n/* create a string containing the RegExp bytecode */\nstatic JSValue js_compile_regexp(JSContext *ctx, JSValueConst pattern,\n                                 JSValueConst flags)\n{\n    const char *str;\n    int re_flags, mask;\n    uint8_t *re_bytecode_buf;\n    size_t i, len;\n    int re_bytecode_len;\n    JSValue ret;\n    char error_msg[64];\n\n    re_flags = 0;\n    if (!JS_IsUndefined(flags)) {\n        str = JS_ToCStringLen(ctx, &len, flags);\n        if (!str)\n            return JS_EXCEPTION;\n        /* XXX: re_flags = LRE_FLAG_OCTAL unless strict mode? */\n        for (i = 0; i < len; i++) {\n            switch(str[i]) {\n            case 'd':\n                mask = LRE_FLAG_INDICES;\n                break;\n            case 'g':\n                mask = LRE_FLAG_GLOBAL;\n                break;\n            case 'i':\n                mask = LRE_FLAG_IGNORECASE;\n                break;\n            case 'm':\n                mask = LRE_FLAG_MULTILINE;\n                break;\n            case 's':\n                mask = LRE_FLAG_DOTALL;\n                break;\n            case 'u':\n                mask = LRE_FLAG_UNICODE;\n                break;\n            case 'v':\n                mask = LRE_FLAG_UNICODE_SETS;\n                break;\n            case 'y':\n                mask = LRE_FLAG_STICKY;\n                break;\n            default:\n                goto bad_flags;\n            }\n            if ((re_flags & mask) != 0) {\n            bad_flags:\n                JS_FreeCString(ctx, str);\n                goto bad_flags1;\n            }\n            re_flags |= mask;\n        }\n        JS_FreeCString(ctx, str);\n    }\n\n    /* 'u' and 'v' cannot be both set */\n    if ((re_flags & LRE_FLAG_UNICODE_SETS) && (re_flags & LRE_FLAG_UNICODE)) {\n    bad_flags1:\n        return JS_ThrowSyntaxError(ctx, \"invalid regular expression flags\");\n    }\n    \n    str = JS_ToCStringLen2(ctx, &len, pattern, !(re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)));\n    if (!str)\n        return JS_EXCEPTION;\n    re_bytecode_buf = lre_compile(&re_bytecode_len, error_msg,\n                                  sizeof(error_msg), str, len, re_flags, ctx);\n    JS_FreeCString(ctx, str);\n    if (!re_bytecode_buf) {\n        JS_ThrowSyntaxError(ctx, \"%s\", error_msg);\n        return JS_EXCEPTION;\n    }\n\n    ret = js_new_string8_len(ctx, (const char *)re_bytecode_buf, re_bytecode_len);\n    js_free(ctx, re_bytecode_buf);\n    return ret;\n}\n\n/* fast regexp creation */\nstatic JSValue JS_NewRegexp(JSContext *ctx, JSValue pattern, JSValue bc)\n{\n    JSValue obj;\n    JSProperty props[1];\n    JSObject *p;\n    JSRegExp *re;\n\n    /* sanity check */\n    if (unlikely(JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||\n                 JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING)) {\n        JS_ThrowTypeError(ctx, \"string expected\");\n        goto fail;\n    }\n    props[0].u.value = JS_NewInt32(ctx, 0); /* lastIndex */\n    obj = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->regexp_shape), JS_CLASS_REGEXP, props);\n    if (JS_IsException(obj))\n        goto fail;\n    p = JS_VALUE_GET_OBJ(obj);\n    re = &p->u.regexp;\n    re->pattern = JS_VALUE_GET_STRING(pattern);\n    re->bytecode = JS_VALUE_GET_STRING(bc);\n    return obj;\n fail:\n    JS_FreeValue(ctx, bc);\n    JS_FreeValue(ctx, pattern);\n    return JS_EXCEPTION;\n}\n\n/* set the RegExp fields */\nstatic JSValue js_regexp_set_internal(JSContext *ctx,\n                                      JSValue obj,\n                                      JSValue pattern, JSValue bc)\n{\n    JSObject *p;\n    JSRegExp *re;\n\n    /* sanity check */\n    if (unlikely(JS_VALUE_GET_TAG(bc) != JS_TAG_STRING ||\n                 JS_VALUE_GET_TAG(pattern) != JS_TAG_STRING)) {\n        JS_ThrowTypeError(ctx, \"string expected\");\n        JS_FreeValue(ctx, obj);\n        JS_FreeValue(ctx, bc);\n        JS_FreeValue(ctx, pattern);\n        return JS_EXCEPTION;\n    }\n\n    p = JS_VALUE_GET_OBJ(obj);\n    re = &p->u.regexp;\n    re->pattern = JS_VALUE_GET_STRING(pattern);\n    re->bytecode = JS_VALUE_GET_STRING(bc);\n    /* Note: cannot fail because the field is preallocated */\n    JS_DefinePropertyValue(ctx, obj, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0),\n                           JS_PROP_WRITABLE);\n    return obj;\n}\n\nstatic JSRegExp *js_get_regexp(JSContext *ctx, JSValueConst obj, BOOL throw_error)\n{\n    if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(obj);\n        if (p->class_id == JS_CLASS_REGEXP)\n            return &p->u.regexp;\n    }\n    if (throw_error) {\n        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);\n    }\n    return NULL;\n}\n\n/* return < 0 if exception or TRUE/FALSE */\nstatic int js_is_regexp(JSContext *ctx, JSValueConst obj)\n{\n    JSValue m;\n\n    if (!JS_IsObject(obj))\n        return FALSE;\n    m = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_match);\n    if (JS_IsException(m))\n        return -1;\n    if (!JS_IsUndefined(m))\n        return JS_ToBoolFree(ctx, m);\n    return js_get_regexp(ctx, obj, FALSE) != NULL;\n}\n\nstatic JSValue js_regexp_constructor(JSContext *ctx, JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue pattern, flags, bc, val, obj = JS_UNDEFINED;\n    JSValueConst pat, flags1;\n    JSRegExp *re;\n    int pat_is_regexp;\n\n    pat = argv[0];\n    flags1 = argv[1];\n    pat_is_regexp = js_is_regexp(ctx, pat);\n    if (pat_is_regexp < 0)\n        return JS_EXCEPTION;\n    if (JS_IsUndefined(new_target)) {\n        /* called as a function */\n        new_target = JS_GetActiveFunction(ctx);\n        if (pat_is_regexp && JS_IsUndefined(flags1)) {\n            JSValue ctor;\n            BOOL res;\n            ctor = JS_GetProperty(ctx, pat, JS_ATOM_constructor);\n            if (JS_IsException(ctor))\n                return ctor;\n            res = js_same_value(ctx, ctor, new_target);\n            JS_FreeValue(ctx, ctor);\n            if (res)\n                return JS_DupValue(ctx, pat);\n        }\n    }\n    re = js_get_regexp(ctx, pat, FALSE);\n    flags = JS_UNDEFINED;\n    if (re) {\n        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));\n        if (JS_IsUndefined(flags1)) {\n            bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));\n            obj = js_create_from_ctor(ctx, new_target, JS_CLASS_REGEXP);\n            if (JS_IsException(obj))\n                goto fail;\n            goto no_compilation;\n        } else {\n            flags = JS_DupValue(ctx, flags1);\n        }\n    } else {\n        if (pat_is_regexp) {\n            pattern = JS_GetProperty(ctx, pat, JS_ATOM_source);\n            if (JS_IsException(pattern))\n                goto fail;\n            if (JS_IsUndefined(flags1)) {\n                flags = JS_GetProperty(ctx, pat, JS_ATOM_flags);\n                if (JS_IsException(flags))\n                    goto fail;\n            } else {\n                flags = JS_DupValue(ctx, flags1);\n            }\n        } else {\n            pattern = JS_DupValue(ctx, pat);\n            flags = JS_DupValue(ctx, flags1);\n        }\n        if (JS_IsUndefined(pattern)) {\n            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);\n        } else {\n            val = pattern;\n            pattern = JS_ToString(ctx, val);\n            JS_FreeValue(ctx, val);\n            if (JS_IsException(pattern))\n                goto fail;\n        }\n    }\n    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_REGEXP);\n    if (JS_IsException(obj))\n        goto fail;\n    bc = js_compile_regexp(ctx, pattern, flags);\n    if (JS_IsException(bc))\n        goto fail;\n    JS_FreeValue(ctx, flags);\n no_compilation:\n    return js_regexp_set_internal(ctx, obj, pattern, bc);\n fail:\n    JS_FreeValue(ctx, pattern);\n    JS_FreeValue(ctx, flags);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_regexp_compile(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSRegExp *re1, *re;\n    JSValueConst pattern1, flags1;\n    JSValue bc, pattern;\n\n    re = js_get_regexp(ctx, this_val, TRUE);\n    if (!re)\n        return JS_EXCEPTION;\n    pattern1 = argv[0];\n    flags1 = argv[1];\n    re1 = js_get_regexp(ctx, pattern1, FALSE);\n    if (re1) {\n        if (!JS_IsUndefined(flags1))\n            return JS_ThrowTypeError(ctx, \"flags must be undefined\");\n        pattern = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->pattern));\n        bc = JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, re1->bytecode));\n    } else {\n        bc = JS_UNDEFINED;\n        if (JS_IsUndefined(pattern1))\n            pattern = JS_AtomToString(ctx, JS_ATOM_empty_string);\n        else\n            pattern = JS_ToString(ctx, pattern1);\n        if (JS_IsException(pattern))\n            goto fail;\n        bc = js_compile_regexp(ctx, pattern, flags1);\n        if (JS_IsException(bc))\n            goto fail;\n    }\n    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->pattern));\n    JS_FreeValue(ctx, JS_MKPTR(JS_TAG_STRING, re->bytecode));\n    re->pattern = JS_VALUE_GET_STRING(pattern);\n    re->bytecode = JS_VALUE_GET_STRING(bc);\n    if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,\n                       JS_NewInt32(ctx, 0)) < 0)\n        return JS_EXCEPTION;\n    return JS_DupValue(ctx, this_val);\n fail:\n    JS_FreeValue(ctx, pattern);\n    JS_FreeValue(ctx, bc);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_regexp_get_source(JSContext *ctx, JSValueConst this_val)\n{\n    JSRegExp *re;\n    JSString *p;\n    StringBuffer b_s, *b = &b_s;\n    int i, n, c, c2, bra;\n\n    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))\n        goto empty_regex;\n\n    re = js_get_regexp(ctx, this_val, TRUE);\n    if (!re)\n        return JS_EXCEPTION;\n\n    p = re->pattern;\n\n    if (p->len == 0) {\n    empty_regex:\n        return js_new_string8(ctx, \"(?:)\");\n    }\n    string_buffer_init2(ctx, b, p->len, p->is_wide_char);\n\n    /* Escape '/' and newline sequences as needed */\n    bra = 0;\n    for (i = 0, n = p->len; i < n;) {\n        c2 = -1;\n        switch (c = string_get(p, i++)) {\n        case '\\\\':\n            if (i < n)\n                c2 = string_get(p, i++);\n            break;\n        case ']':\n            bra = 0;\n            break;\n        case '[':\n            if (!bra) {\n                if (i < n && string_get(p, i) == ']')\n                    c2 = string_get(p, i++);\n                bra = 1;\n            }\n            break;\n        case '\\n':\n            c = '\\\\';\n            c2 = 'n';\n            break;\n        case '\\r':\n            c = '\\\\';\n            c2 = 'r';\n            break;\n        case '/':\n            if (!bra) {\n                c = '\\\\';\n                c2 = '/';\n            }\n            break;\n        }\n        string_buffer_putc16(b, c);\n        if (c2 >= 0)\n            string_buffer_putc16(b, c2);\n    }\n    return string_buffer_end(b);\n}\n\nstatic JSValue js_regexp_get_flag(JSContext *ctx, JSValueConst this_val, int mask)\n{\n    JSRegExp *re;\n    int flags;\n\n    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    re = js_get_regexp(ctx, this_val, FALSE);\n    if (!re) {\n        if (js_same_value(ctx, this_val, ctx->class_proto[JS_CLASS_REGEXP]))\n            return JS_UNDEFINED;\n        else\n            return JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_REGEXP);\n    }\n\n    flags = lre_get_flags(re->bytecode->u.str8);\n    return JS_NewBool(ctx, flags & mask);\n}\n\n#define RE_FLAG_COUNT 8\n\nstatic JSValue js_regexp_get_flags(JSContext *ctx, JSValueConst this_val)\n{\n    char str[RE_FLAG_COUNT], *p = str;\n    int res, i;\n    static const int flag_atom[RE_FLAG_COUNT] = {\n        JS_ATOM_hasIndices,\n        JS_ATOM_global,\n        JS_ATOM_ignoreCase,\n        JS_ATOM_multiline,\n        JS_ATOM_dotAll,\n        JS_ATOM_unicode,\n        JS_ATOM_unicodeSets,\n        JS_ATOM_sticky,\n    };\n    static const char flag_char[RE_FLAG_COUNT] = { 'd', 'g', 'i', 'm', 's', 'u', 'v', 'y' };\n    \n    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    for(i = 0; i < RE_FLAG_COUNT; i++) {\n        res = JS_ToBoolFree(ctx, JS_GetProperty(ctx, this_val, flag_atom[i]));\n        if (res < 0)\n            goto exception;\n        if (res)\n            *p++ = flag_char[i];\n    }\n    return JS_NewStringLen(ctx, str, p - str);\n\nexception:\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_regexp_toString(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValue pattern, flags;\n    StringBuffer b_s, *b = &b_s;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    string_buffer_init(ctx, b, 0);\n    string_buffer_putc8(b, '/');\n    pattern = JS_GetProperty(ctx, this_val, JS_ATOM_source);\n    if (string_buffer_concat_value_free(b, pattern))\n        goto fail;\n    string_buffer_putc8(b, '/');\n    flags = JS_GetProperty(ctx, this_val, JS_ATOM_flags);\n    if (string_buffer_concat_value_free(b, flags))\n        goto fail;\n    return string_buffer_end(b);\n\nfail:\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\nint lre_check_stack_overflow(void *opaque, size_t alloca_size)\n{\n    JSContext *ctx = opaque;\n    return js_check_stack_overflow(ctx->rt, alloca_size);\n}\n\nint lre_check_timeout(void *opaque)\n{\n    JSContext *ctx = opaque;\n    JSRuntime *rt = ctx->rt;\n    return (rt->interrupt_handler && \n            rt->interrupt_handler(rt, rt->interrupt_opaque));\n}\n\nvoid *lre_realloc(void *opaque, void *ptr, size_t size)\n{\n    JSContext *ctx = opaque;\n    /* No JS exception is raised here */\n    return js_realloc_rt(ctx->rt, ptr, size);\n}\n\nstatic JSValue js_regexp_escape(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue str;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p;\n    uint32_t c, i;\n    char s[16];\n\n    if (!JS_IsString(argv[0]))\n        return JS_ThrowTypeError(ctx, \"not a string\");\n    str = JS_ToString(ctx, argv[0]); /* must call it to linearlize ropes */\n    if (JS_IsException(str))\n        return JS_EXCEPTION;\n    p = JS_VALUE_GET_STRING(str);\n    string_buffer_init2(ctx, b, 0, p->is_wide_char);\n    for (i = 0; i < p->len; i++) {\n        c = string_get(p, i);\n        if (c < 33) {\n            if (c >= 9 && c <= 13) {\n                string_buffer_putc8(b, '\\\\');\n                string_buffer_putc8(b, \"tnvfr\"[c - 9]);\n            } else {\n                goto hex2;\n            }\n        } else if (c < 128) {\n            if ((c >= '0' && c <= '9')\n             || (c >= 'A' && c <= 'Z')\n             || (c >= 'a' && c <= 'z')) {\n                if (i == 0)\n                    goto hex2;\n            } else if (strchr(\",-=<>#&!%:;@~'`\\\"\", c)) {\n                goto hex2;\n            } else if (c != '_') {\n                string_buffer_putc8(b, '\\\\');\n            }\n            string_buffer_putc8(b, c);\n        } else if (c < 256) {\n        hex2:\n            snprintf(s, sizeof(s), \"\\\\x%02x\", c);\n            string_buffer_puts8(b, s);\n        } else if (is_surrogate(c) || lre_is_space(c)) {\n            snprintf(s, sizeof(s), \"\\\\u%04x\", c);\n            string_buffer_puts8(b, s);\n        } else {\n            string_buffer_putc16(b, c);\n        }\n    }\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n}\n\n/* this_val must be of JS_CLASS_REGEXP */\nstatic force_inline int js_regexp_get_lastIndex(JSContext *ctx, int64_t *plast_index,\n                                                JSValueConst this_val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(this_val);\n    \n    /* lastIndex is always the first property (it is not configurable) */\n    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT)) {\n        *plast_index = max_int(JS_VALUE_GET_INT(p->prop[0].u.value), 0);\n        return 0;\n    } else {\n        return JS_ToLengthFree(ctx, plast_index, JS_DupValue(ctx, p->prop[0].u.value));\n    }\n}\n\n/* this_val must be of JS_CLASS_REGEXP */\nstatic force_inline int js_regexp_set_lastIndex(JSContext *ctx, JSValueConst this_val,\n                                                int last_index)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(this_val);\n    \n    /* lastIndex is always the first property (it is not configurable) */\n    if (likely(JS_VALUE_GET_TAG(p->prop[0].u.value) == JS_TAG_INT &&\n               (get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE))) {\n        set_value(ctx, &p->prop[0].u.value, JS_NewInt32(ctx, last_index));\n    } else {\n        if (JS_SetProperty(ctx, this_val, JS_ATOM_lastIndex,\n                           JS_NewInt32(ctx, last_index)) < 0)\n            return -1;\n    }\n    return 0;\n}\n\nstatic JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);\n    JSString *str;\n    JSValue t, ret, str_val, obj, groups;\n    JSValue indices, indices_groups;\n    uint8_t *re_bytecode;\n    uint8_t **capture, *str_buf;\n    int rc, capture_count, shift, i, re_flags, alloc_count;\n    int64_t last_index;\n    const char *group_name_ptr;\n    JSObject *p_obj;\n    JSAtom group_name;\n    \n    if (!re)\n        return JS_EXCEPTION;\n\n    str_val = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str_val))\n        return JS_EXCEPTION;\n\n    ret = JS_EXCEPTION;\n    obj = JS_NULL;\n    groups = JS_UNDEFINED;\n    indices = JS_UNDEFINED;\n    indices_groups = JS_UNDEFINED;\n    capture = NULL;\n    group_name = JS_ATOM_NULL;\n    \n    if (js_regexp_get_lastIndex(ctx, &last_index, this_val))\n        goto fail;\n\n    re_bytecode = re->bytecode->u.str8;\n    re_flags = lre_get_flags(re_bytecode);\n    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {\n        last_index = 0;\n    }\n    str = JS_VALUE_GET_STRING(str_val);\n    alloc_count = lre_get_alloc_count(re_bytecode);\n    if (alloc_count > 0) {\n        capture = js_malloc(ctx, sizeof(capture[0]) * alloc_count);\n        if (!capture)\n            goto fail;\n    }\n    capture_count = lre_get_capture_count(re_bytecode);\n    shift = str->is_wide_char;\n    str_buf = str->u.str8;\n    if (last_index > str->len) {\n        rc = 2;\n    } else {\n        rc = lre_exec(capture, re_bytecode,\n                      str_buf, last_index, str->len,\n                      shift, ctx);\n    }\n    if (rc != 1) {\n        if (rc >= 0) {\n            if (rc == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {\n                if (js_regexp_set_lastIndex(ctx, this_val, 0) < 0)\n                    goto fail;\n            }\n        } else {\n            if (rc == LRE_RET_TIMEOUT) {\n                JS_ThrowInterrupted(ctx);\n            } else {\n                JS_ThrowInternalError(ctx, \"out of memory in regexp execution\");\n            }\n            goto fail;\n        }\n    } else {\n        int prop_flags;\n        JSProperty props[4];\n        \n        if (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) {\n            if (js_regexp_set_lastIndex(ctx, this_val,\n                                        (capture[1] - str_buf) >> shift) < 0)\n                goto fail;\n        }\n        prop_flags = JS_PROP_C_W_E | JS_PROP_THROW;\n        group_name_ptr = lre_get_groupnames(re_bytecode);\n        if (group_name_ptr) {\n            groups = JS_NewObjectProto(ctx, JS_NULL);\n            if (JS_IsException(groups))\n                goto fail;\n        }\n        if (re_flags & LRE_FLAG_INDICES) {\n            indices = JS_NewArray(ctx);\n            if (JS_IsException(indices))\n                goto fail;\n            if (group_name_ptr) {\n                indices_groups = JS_NewObjectProto(ctx, JS_NULL);\n                if (JS_IsException(indices_groups))\n                    goto fail;\n            }\n        }\n\n        props[0].u.value = JS_NewInt32(ctx, capture_count); /* length */\n        props[1].u.value = JS_NewInt32(ctx, (capture[0] - str_buf) >> shift); /* index */\n        props[2].u.value = str_val; /* input */\n        props[3].u.value = JS_DupValue(ctx, groups); /* groups */\n\n        str_val = JS_UNDEFINED;\n        obj = JS_NewObjectFromShape(ctx, js_dup_shape(ctx->regexp_result_shape),\n                                    JS_CLASS_ARRAY, props);\n        if (JS_IsException(obj))\n            goto fail;\n\n        p_obj = JS_VALUE_GET_OBJ(obj);\n        if (expand_fast_array(ctx, p_obj, capture_count))\n            goto fail;\n        \n        for(i = 0; i < capture_count; i++) {\n            uint8_t **match = &capture[2 * i];\n            int start = -1;\n            int end = -1;\n            JSValue val;\n\n            if (group_name_ptr && i > 0) {\n                if (*group_name_ptr) {\n                    /* XXX: slow, should create a shape when the regexp is\n                       compiled */\n                    group_name = JS_NewAtom(ctx, group_name_ptr);\n                    if (group_name == JS_ATOM_NULL)\n                        goto fail;\n                }\n                group_name_ptr += strlen(group_name_ptr) + LRE_GROUP_NAME_TRAILER_LEN;\n            }\n\n            if (match[0] && match[1]) {\n                start = (match[0] - str_buf) >> shift;\n                end = (match[1] - str_buf) >> shift;\n            }\n\n            if (!JS_IsUndefined(indices)) {\n                val = JS_UNDEFINED;\n                if (start != -1) {\n                    val = JS_NewArray(ctx);\n                    if (JS_IsException(val))\n                        goto fail;\n                    if (JS_DefinePropertyValueUint32(ctx, val, 0,\n                                                     JS_NewInt32(ctx, start),\n                                                     prop_flags) < 0) {\n                        JS_FreeValue(ctx, val);\n                        goto fail;\n                    }\n                    if (JS_DefinePropertyValueUint32(ctx, val, 1,\n                                                     JS_NewInt32(ctx, end),\n                                                     prop_flags) < 0) {\n                        JS_FreeValue(ctx, val);\n                        goto fail;\n                    }\n                }\n                if (group_name != JS_ATOM_NULL) {\n                    /* JS_HasProperty() cannot fail here */\n                    if (!JS_IsUndefined(val) ||\n                        !JS_HasProperty(ctx, indices_groups, group_name)) {\n                        if (JS_DefinePropertyValue(ctx, indices_groups,\n                                                   group_name, JS_DupValue(ctx, val), prop_flags) < 0) {\n                            JS_FreeValue(ctx, val);\n                            goto fail;\n                        }\n                    }\n                }\n                if (JS_DefinePropertyValueUint32(ctx, indices, i, val,\n                                                 prop_flags) < 0) {\n                    goto fail;\n                }\n            }\n\n            val = JS_UNDEFINED;\n            if (start != -1) {\n                val = js_sub_string(ctx, str, start, end);\n                if (JS_IsException(val))\n                    goto fail;\n            }\n\n            if (group_name != JS_ATOM_NULL) {\n                /* JS_HasProperty() cannot fail here */\n                if (!JS_IsUndefined(val) ||\n                    !JS_HasProperty(ctx, groups, group_name)) {\n                    if (JS_DefinePropertyValue(ctx, groups, group_name,\n                                               JS_DupValue(ctx, val),\n                                               prop_flags) < 0) {\n                        JS_FreeValue(ctx, val);\n                        goto fail;\n                    }\n                }\n                JS_FreeAtom(ctx, group_name);\n                group_name = JS_ATOM_NULL;\n            }\n            p_obj->u.array.u.values[p_obj->u.array.count++] = val;\n        }\n\n        if (!JS_IsUndefined(indices)) {\n            t = indices_groups, indices_groups = JS_UNDEFINED;\n            if (JS_DefinePropertyValue(ctx, indices, JS_ATOM_groups,\n                                       t, prop_flags) < 0) {\n                goto fail;\n            }\n            t = indices, indices = JS_UNDEFINED;\n            if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_indices,\n                                       t, prop_flags) < 0) {\n                goto fail;\n            }\n        }\n    }\n    ret = obj;\n    obj = JS_UNDEFINED;\nfail:\n    JS_FreeAtom(ctx, group_name);\n    JS_FreeValue(ctx, indices_groups);\n    JS_FreeValue(ctx, indices);\n    JS_FreeValue(ctx, str_val);\n    JS_FreeValue(ctx, groups);\n    JS_FreeValue(ctx, obj);\n    js_free(ctx, capture);\n    return ret;\n}\n\n/* XXX: add group names support */\nstatic JSValue js_regexp_replace(JSContext *ctx, JSValueConst this_val, JSValueConst arg,\n                                 JSValueConst rep_val)\n{\n    JSRegExp *re = js_get_regexp(ctx, this_val, TRUE);\n    JSString *str;\n    JSValue str_val;\n    uint8_t *re_bytecode;\n    int ret;\n    uint8_t **capture, *str_buf;\n    int capture_count, alloc_count, shift, re_flags;\n    int next_src_pos, start, end;\n    int64_t last_index;\n    StringBuffer b_s, *b = &b_s;\n    JSString *rp = JS_VALUE_GET_STRING(rep_val);\n    const char *group_name_ptr;\n    BOOL fullUnicode;\n    \n    if (!re)\n        return JS_EXCEPTION;\n    re_bytecode = re->bytecode->u.str8;\n    group_name_ptr = lre_get_groupnames(re_bytecode);\n    if (group_name_ptr)\n        return JS_UNDEFINED; /* group names are not supported yet */\n    \n    string_buffer_init(ctx, b, 0);\n\n    capture = NULL;\n    str_val = JS_ToString(ctx, arg);\n    if (JS_IsException(str_val))\n        goto fail;\n    str = JS_VALUE_GET_STRING(str_val);\n    re_flags = lre_get_flags(re_bytecode);\n\n    if (re_flags & LRE_FLAG_GLOBAL) {\n        if (js_regexp_set_lastIndex(ctx, this_val, 0))\n            goto fail;\n    }\n    if ((re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY)) == 0) {\n        last_index = 0;\n    } else {\n        if (js_regexp_get_lastIndex(ctx, &last_index, this_val))\n            goto fail;\n    }\n    alloc_count = lre_get_alloc_count(re_bytecode);\n    if (alloc_count > 0) {\n        capture = js_malloc(ctx, sizeof(capture[0]) * alloc_count);\n        if (!capture)\n            goto fail;\n    }\n    capture_count = lre_get_capture_count(re_bytecode);\n    fullUnicode = ((re_flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0);\n    shift = str->is_wide_char;\n    str_buf = str->u.str8;\n    next_src_pos = 0;\n    for (;;) {\n        if (last_index > str->len) {\n            ret = 0;\n        } else {\n            ret = lre_exec(capture, re_bytecode,\n                           str_buf, last_index, str->len, shift, ctx);\n        }\n        if (ret != 1) {\n            if (ret >= 0) {\n                if (ret == 2 || (re_flags & (LRE_FLAG_GLOBAL | LRE_FLAG_STICKY))) {\n                    if (js_regexp_set_lastIndex(ctx, this_val, 0) < 0)\n                        goto fail;\n                }\n            } else {\n                if (ret == LRE_RET_TIMEOUT) {\n                    JS_ThrowInterrupted(ctx);\n                } else {\n                    JS_ThrowInternalError(ctx, \"out of memory in regexp execution\");\n                }\n                goto fail;\n            }\n            break;\n        }\n        start = (capture[0] - str_buf) >> shift;\n        end = (capture[1] - str_buf) >> shift;\n        last_index = end;\n        if (next_src_pos < start) {\n            if (string_buffer_concat(b, str, next_src_pos, start))\n                goto fail;\n        }\n        if (rp->len != 0) {\n            if (js_string_GetSubstitution(ctx, b, JS_UNDEFINED, str, start,\n                                          JS_UNDEFINED, JS_UNDEFINED, rep_val,\n                                          capture, capture_count)) {\n                goto fail;\n            }\n        }\n        next_src_pos = end;\n        if (!(re_flags & LRE_FLAG_GLOBAL)) {\n            if (re_flags & LRE_FLAG_STICKY) {\n                if (js_regexp_set_lastIndex(ctx, this_val, end) < 0)\n                    goto fail;\n            }\n            break;\n        }\n        if (end == start) {\n            end = string_advance_index(str, end, fullUnicode);\n        }\n        last_index = end;\n    }\n    if (string_buffer_concat(b, str, next_src_pos, str->len))\n        goto fail;\n    JS_FreeValue(ctx, str_val);\n    js_free(ctx, capture);\n    return string_buffer_end(b);\nfail:\n    JS_FreeValue(ctx, str_val);\n    js_free(ctx, capture);\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue JS_RegExpExec(JSContext *ctx, JSValueConst r, JSValueConst s)\n{\n    JSValue method, ret;\n\n    method = JS_GetProperty(ctx, r, JS_ATOM_exec);\n    if (JS_IsException(method))\n        return method;\n    if (JS_IsFunction(ctx, method)) {\n        ret = JS_CallFree(ctx, method, r, 1, &s);\n        if (JS_IsException(ret))\n            return ret;\n        if (!JS_IsObject(ret) && !JS_IsNull(ret)) {\n            JS_FreeValue(ctx, ret);\n            return JS_ThrowTypeError(ctx, \"RegExp exec method must return an object or null\");\n        }\n        return ret;\n    }\n    JS_FreeValue(ctx, method);\n    return js_regexp_exec(ctx, r, 1, &s);\n}\n\nstatic JSValue js_regexp_test(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSValue val;\n    BOOL ret;\n\n    val = JS_RegExpExec(ctx, this_val, argv[0]);\n    if (JS_IsException(val))\n        return JS_EXCEPTION;\n    ret = !JS_IsNull(val);\n    JS_FreeValue(ctx, val);\n    return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_regexp_Symbol_match(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv)\n{\n    // [Symbol.match](str)\n    JSValueConst rx = this_val;\n    JSValue A, S, flags, result, matchStr;\n    int global, n, fullUnicode, isEmpty;\n    JSString *p;\n\n    if (!JS_IsObject(rx))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    A = JS_UNDEFINED;\n    flags = JS_UNDEFINED;\n    result = JS_UNDEFINED;\n    matchStr = JS_UNDEFINED;\n    S = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(S))\n        goto exception;\n\n    flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);\n    if (JS_IsException(flags))\n        goto exception;\n    flags = JS_ToStringFree(ctx, flags);\n    if (JS_IsException(flags))\n        goto exception;\n    p = JS_VALUE_GET_STRING(flags);\n\n    global = (-1 != string_indexof_char(p, 'g', 0));\n    if (!global) {\n        A = JS_RegExpExec(ctx, rx, S);\n    } else {\n        fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||\n                       string_indexof_char(p, 'v', 0) >= 0);\n\n        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)\n            goto exception;\n        A = JS_NewArray(ctx);\n        if (JS_IsException(A))\n            goto exception;\n        n = 0;\n        for(;;) {\n            JS_FreeValue(ctx, result);\n            result = JS_RegExpExec(ctx, rx, S);\n            if (JS_IsException(result))\n                goto exception;\n            if (JS_IsNull(result))\n                break;\n            matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));\n            if (JS_IsException(matchStr))\n                goto exception;\n            isEmpty = JS_IsEmptyString(matchStr);\n            if (JS_DefinePropertyValueInt64(ctx, A, n++, matchStr, JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception;\n            if (isEmpty) {\n                int64_t thisIndex, nextIndex;\n                if (JS_ToLengthFree(ctx, &thisIndex,\n                                    JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)\n                    goto exception;\n                p = JS_VALUE_GET_STRING(S);\n                nextIndex = string_advance_index(p, thisIndex, fullUnicode);\n                if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)\n                    goto exception;\n            }\n        }\n        if (n == 0) {\n            JS_FreeValue(ctx, A);\n            A = JS_NULL;\n        }\n    }\n    JS_FreeValue(ctx, result);\n    JS_FreeValue(ctx, flags);\n    JS_FreeValue(ctx, S);\n    return A;\n\nexception:\n    JS_FreeValue(ctx, A);\n    JS_FreeValue(ctx, result);\n    JS_FreeValue(ctx, flags);\n    JS_FreeValue(ctx, S);\n    return JS_EXCEPTION;\n}\n\ntypedef struct JSRegExpStringIteratorData {\n    JSValue iterating_regexp;\n    JSValue iterated_string;\n    BOOL global;\n    BOOL unicode;\n    BOOL done;\n} JSRegExpStringIteratorData;\n\nstatic void js_regexp_string_iterator_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;\n    if (it) {\n        JS_FreeValueRT(rt, it->iterating_regexp);\n        JS_FreeValueRT(rt, it->iterated_string);\n        js_free_rt(rt, it);\n    }\n}\n\nstatic void js_regexp_string_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                           JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSRegExpStringIteratorData *it = p->u.regexp_string_iterator_data;\n    if (it) {\n        JS_MarkValue(rt, it->iterating_regexp, mark_func);\n        JS_MarkValue(rt, it->iterated_string, mark_func);\n    }\n}\n\nstatic JSValue js_regexp_string_iterator_next(JSContext *ctx,\n                                              JSValueConst this_val,\n                                              int argc, JSValueConst *argv,\n                                              BOOL *pdone, int magic)\n{\n    JSRegExpStringIteratorData *it;\n    JSValueConst R, S;\n    JSValue matchStr = JS_UNDEFINED, match = JS_UNDEFINED;\n    JSString *sp;\n\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_REGEXP_STRING_ITERATOR);\n    if (!it)\n        goto exception;\n    if (it->done) {\n        *pdone = TRUE;\n        return JS_UNDEFINED;\n    }\n    R = it->iterating_regexp;\n    S = it->iterated_string;\n    match = JS_RegExpExec(ctx, R, S);\n    if (JS_IsException(match))\n        goto exception;\n    if (JS_IsNull(match)) {\n        it->done = TRUE;\n        *pdone = TRUE;\n        return JS_UNDEFINED;\n    } else if (it->global) {\n        matchStr = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, match, 0));\n        if (JS_IsException(matchStr))\n            goto exception;\n        if (JS_IsEmptyString(matchStr)) {\n            int64_t thisIndex, nextIndex;\n            if (JS_ToLengthFree(ctx, &thisIndex,\n                                JS_GetProperty(ctx, R, JS_ATOM_lastIndex)) < 0)\n                goto exception;\n            sp = JS_VALUE_GET_STRING(S);\n            nextIndex = string_advance_index(sp, thisIndex, it->unicode);\n            if (JS_SetProperty(ctx, R, JS_ATOM_lastIndex,\n                               JS_NewInt64(ctx, nextIndex)) < 0)\n                goto exception;\n        }\n        JS_FreeValue(ctx, matchStr);\n    } else {\n        it->done = TRUE;\n    }\n    *pdone = FALSE;\n    return match;\n exception:\n    JS_FreeValue(ctx, match);\n    JS_FreeValue(ctx, matchStr);\n    *pdone = FALSE;\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_regexp_Symbol_matchAll(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    // [Symbol.matchAll](str)\n    JSValueConst R = this_val;\n    JSValue S, C, flags, matcher, iter;\n    JSValueConst args[2];\n    JSString *strp;\n    int64_t lastIndex;\n    JSRegExpStringIteratorData *it;\n\n    if (!JS_IsObject(R))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    C = JS_UNDEFINED;\n    flags = JS_UNDEFINED;\n    matcher = JS_UNDEFINED;\n    iter = JS_UNDEFINED;\n\n    S = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(S))\n        goto exception;\n    C = JS_SpeciesConstructor(ctx, R, ctx->regexp_ctor);\n    if (JS_IsException(C))\n        goto exception;\n    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, R, JS_ATOM_flags));\n    if (JS_IsException(flags))\n        goto exception;\n    args[0] = R;\n    args[1] = flags;\n    matcher = JS_CallConstructor(ctx, C, 2, args);\n    if (JS_IsException(matcher))\n        goto exception;\n    if (JS_ToLengthFree(ctx, &lastIndex,\n                        JS_GetProperty(ctx, R, JS_ATOM_lastIndex)))\n        goto exception;\n    if (JS_SetProperty(ctx, matcher, JS_ATOM_lastIndex,\n                       JS_NewInt64(ctx, lastIndex)) < 0)\n        goto exception;\n\n    iter = JS_NewObjectClass(ctx, JS_CLASS_REGEXP_STRING_ITERATOR);\n    if (JS_IsException(iter))\n        goto exception;\n    it = js_malloc(ctx, sizeof(*it));\n    if (!it)\n        goto exception;\n    it->iterating_regexp = matcher;\n    it->iterated_string = S;\n    strp = JS_VALUE_GET_STRING(flags);\n    it->global = string_indexof_char(strp, 'g', 0) >= 0;\n    it->unicode = (string_indexof_char(strp, 'u', 0) >= 0 ||\n                   string_indexof_char(strp, 'v', 0) >= 0);\n    it->done = FALSE;\n    JS_SetOpaque(iter, it);\n\n    JS_FreeValue(ctx, C);\n    JS_FreeValue(ctx, flags);\n    return iter;\n exception:\n    JS_FreeValue(ctx, S);\n    JS_FreeValue(ctx, C);\n    JS_FreeValue(ctx, flags);\n    JS_FreeValue(ctx, matcher);\n    JS_FreeValue(ctx, iter);\n    return JS_EXCEPTION;\n}\n\ntypedef struct ValueBuffer {\n    JSContext *ctx;\n    JSValue *arr;\n    JSValue def[4];\n    int len;\n    int size;\n    int error_status;\n} ValueBuffer;\n\nstatic int value_buffer_init(JSContext *ctx, ValueBuffer *b)\n{\n    b->ctx = ctx;\n    b->len = 0;\n    b->size = 4;\n    b->error_status = 0;\n    b->arr = b->def;\n    return 0;\n}\n\nstatic void value_buffer_free(ValueBuffer *b)\n{\n    while (b->len > 0)\n        JS_FreeValue(b->ctx, b->arr[--b->len]);\n    if (b->arr != b->def)\n        js_free(b->ctx, b->arr);\n    b->arr = b->def;\n    b->size = 4;\n}\n\nstatic int value_buffer_append(ValueBuffer *b, JSValue val)\n{\n    if (b->error_status)\n        return -1;\n\n    if (b->len >= b->size) {\n        int new_size = (b->len + (b->len >> 1) + 31) & ~16;\n        size_t slack;\n        JSValue *new_arr;\n\n        if (b->arr == b->def) {\n            new_arr = js_realloc2(b->ctx, NULL, sizeof(*b->arr) * new_size, &slack);\n            if (new_arr)\n                memcpy(new_arr, b->def, sizeof b->def);\n        } else {\n            new_arr = js_realloc2(b->ctx, b->arr, sizeof(*b->arr) * new_size, &slack);\n        }\n        if (!new_arr) {\n            value_buffer_free(b);\n            JS_FreeValue(b->ctx, val);\n            b->error_status = -1;\n            return -1;\n        }\n        new_size += slack / sizeof(*new_arr);\n        b->arr = new_arr;\n        b->size = new_size;\n    }\n    b->arr[b->len++] = val;\n    return 0;\n}\n\n/* find in 'p' or its prototypes */\nstatic JSShapeProperty *find_property_regexp(JSProperty **ppr,\n                                             JSObject *p, JSAtom atom)\n{\n    JSShapeProperty *prs;\n\n    for(;;) {\n        prs = find_own_property(ppr, p, atom);\n        if (prs)\n            return prs;\n        p = p->shape->proto;\n        if (!p)\n            return NULL;\n        if (p->is_exotic)\n            return NULL;\n    }\n}\n\nstatic BOOL check_regexp_getter(JSContext *ctx,\n                                JSObject *p, JSAtom atom,\n                                JSCFunction *func, int magic)\n{\n    JSProperty *pr;\n    JSShapeProperty *prs;\n\n    prs = find_property_regexp(&pr, p, atom);\n    if (!prs)\n        return FALSE;\n    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_GETSET)\n        return FALSE;\n    return JS_IsCFunction(ctx, JS_MKPTR(JS_TAG_OBJECT, pr->u.getset.getter),\n                          func, magic);\n}\n\nstatic BOOL js_is_standard_regexp(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    JSProperty *pr;\n    JSShapeProperty *prs;\n    JSCFunctionType ft;\n    \n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return FALSE;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (p->class_id != JS_CLASS_REGEXP)\n        return FALSE;\n    /* check that the lastIndex is a number (no side effect while getting it) */\n    prs = find_own_property(&pr, p, JS_ATOM_lastIndex);\n    if (!prs)\n        return FALSE;\n    if (!JS_IsNumber(pr->u.value))\n        return FALSE;\n\n    /* check the 'exec' method. */\n    prs = find_property_regexp(&pr, p, JS_ATOM_exec);\n    if (!prs)\n        return FALSE;\n    if ((prs->flags & JS_PROP_TMASK) != JS_PROP_NORMAL)\n        return FALSE;\n    if (!JS_IsCFunction(ctx, pr->u.value, js_regexp_exec, 0))\n        return FALSE;\n    /* check the flag getters */\n    ft.getter = js_regexp_get_flags;\n    if (!check_regexp_getter(ctx, p, JS_ATOM_flags, ft.generic, 0))\n        return FALSE;\n    ft.getter_magic = js_regexp_get_flag;\n    if (!check_regexp_getter(ctx, p, JS_ATOM_global, ft.generic, LRE_FLAG_GLOBAL))\n        return FALSE;\n    if (!check_regexp_getter(ctx, p, JS_ATOM_unicode, ft.generic, LRE_FLAG_UNICODE))\n        return FALSE;\n    /* XXX: need to check all accessors, need a faster way.  */\n    return TRUE;\n}\n\nstatic JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,\n                                        int argc, JSValueConst *argv)\n{\n    // [Symbol.replace](str, rep)\n    JSValueConst rx = this_val, rep = argv[1];\n    JSValueConst args[6];\n    JSValue flags, str, rep_val, matched, tab, rep_str, namedCaptures, res;\n    JSString *p, *sp;\n    StringBuffer b_s, *b = &b_s;\n    ValueBuffer v_b, *results = &v_b;\n    int nextSourcePosition, n, j, functionalReplace, is_global, fullUnicode;\n    uint32_t nCaptures;\n    int64_t position;\n\n    if (!JS_IsObject(rx))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    string_buffer_init(ctx, b, 0);\n    value_buffer_init(ctx, results);\n\n    rep_val = JS_UNDEFINED;\n    matched = JS_UNDEFINED;\n    tab = JS_UNDEFINED;\n    flags = JS_UNDEFINED;\n    rep_str = JS_UNDEFINED;\n    namedCaptures = JS_UNDEFINED;\n\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        goto exception;\n\n    sp = JS_VALUE_GET_STRING(str);\n    functionalReplace = JS_IsFunction(ctx, rep);\n    if (!functionalReplace) {\n        rep_val = JS_ToString(ctx, rep);\n        if (JS_IsException(rep_val))\n            goto exception;\n    }\n\n    if (!functionalReplace && js_is_standard_regexp(ctx, rx)) {\n        /* use faster version for simple cases */\n        res = js_regexp_replace(ctx, rx, str, rep_val);\n        if (!JS_IsUndefined(res))\n            goto done;\n    }\n    \n    flags = JS_GetProperty(ctx, rx, JS_ATOM_flags);\n    if (JS_IsException(flags))\n        goto exception;\n    flags = JS_ToStringFree(ctx, flags);\n    if (JS_IsException(flags))\n        goto exception;\n    p = JS_VALUE_GET_STRING(flags);\n\n    fullUnicode = 0;\n    is_global = (-1 != string_indexof_char(p, 'g', 0));\n    if (is_global) {\n        fullUnicode = (string_indexof_char(p, 'u', 0) >= 0 ||\n                       string_indexof_char(p, 'v', 0) >= 0);\n        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0)\n            goto exception;\n    }\n\n    for(;;) {\n        JSValue result;\n        result = JS_RegExpExec(ctx, rx, str);\n        if (JS_IsException(result))\n            goto exception;\n        if (JS_IsNull(result))\n            break;\n        if (value_buffer_append(results, result) < 0)\n            goto exception;\n        if (!is_global)\n            break;\n        JS_FreeValue(ctx, matched);\n        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));\n        if (JS_IsException(matched))\n            goto exception;\n        if (JS_IsEmptyString(matched)) {\n            /* always advance of at least one char */\n            int64_t thisIndex, nextIndex;\n            if (JS_ToLengthFree(ctx, &thisIndex, JS_GetProperty(ctx, rx, JS_ATOM_lastIndex)) < 0)\n                goto exception;\n            nextIndex = string_advance_index(sp, thisIndex, fullUnicode);\n            if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt64(ctx, nextIndex)) < 0)\n                goto exception;\n        }\n    }\n    nextSourcePosition = 0;\n    for(j = 0; j < results->len; j++) {\n        JSValueConst result;\n        result = results->arr[j];\n        if (js_get_length32(ctx, &nCaptures, result) < 0)\n            goto exception;\n        JS_FreeValue(ctx, matched);\n        matched = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, result, 0));\n        if (JS_IsException(matched))\n            goto exception;\n        if (JS_ToLengthFree(ctx, &position, JS_GetProperty(ctx, result, JS_ATOM_index)))\n            goto exception;\n        if (position > sp->len)\n            position = sp->len;\n        else if (position < 0)\n            position = 0;\n        /* ignore substition if going backward (can happen\n           with custom regexp object) */\n        JS_FreeValue(ctx, tab);\n        tab = JS_NewArray(ctx);\n        if (JS_IsException(tab))\n            goto exception;\n        if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),\n                                        JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n            goto exception;\n        for(n = 1; n < nCaptures; n++) {\n            JSValue capN;\n            capN = JS_GetPropertyInt64(ctx, result, n);\n            if (JS_IsException(capN))\n                goto exception;\n            if (!JS_IsUndefined(capN)) {\n                capN = JS_ToStringFree(ctx, capN);\n                if (JS_IsException(capN))\n                    goto exception;\n            }\n            if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,\n                                            JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception;\n        }\n        JS_FreeValue(ctx, namedCaptures);\n        namedCaptures = JS_GetProperty(ctx, result, JS_ATOM_groups);\n        if (JS_IsException(namedCaptures))\n            goto exception;\n        if (functionalReplace) {\n            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception;\n            if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                goto exception;\n            if (!JS_IsUndefined(namedCaptures)) {\n                if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                    goto exception;\n            }\n            args[0] = JS_UNDEFINED;\n            args[1] = tab;\n            JS_FreeValue(ctx, rep_str);\n            rep_str = JS_ToStringFree(ctx, js_function_apply(ctx, rep, 2, args, 0));\n        } else {\n            JSValue namedCaptures1;\n            StringBuffer b1_s, *b1 = &b1_s;\n            int ret;\n            \n            if (!JS_IsUndefined(namedCaptures)) {\n                namedCaptures1 = JS_ToObject(ctx, namedCaptures);\n                if (JS_IsException(namedCaptures1))\n                    goto exception;\n            } else {\n                namedCaptures1 = JS_UNDEFINED;\n            }\n            JS_FreeValue(ctx, rep_str);\n            \n            string_buffer_init(ctx, b1, 0);\n            ret = js_string_GetSubstitution(ctx, b1, matched, sp, position,\n                                            tab, namedCaptures1, rep_val,\n                                            NULL, 0);\n            rep_str = string_buffer_end(b1);\n            JS_FreeValue(ctx, namedCaptures1);\n            if (ret)\n                goto exception;\n        }\n        if (JS_IsException(rep_str))\n            goto exception;\n        if (position >= nextSourcePosition) {\n            string_buffer_concat(b, sp, nextSourcePosition, position);\n            string_buffer_concat_value(b, rep_str);\n            nextSourcePosition = position + JS_VALUE_GET_STRING(matched)->len;\n        }\n    }\n    string_buffer_concat(b, sp, nextSourcePosition, sp->len);\n    res = string_buffer_end(b);\n    goto done1;\n\nexception:\n    res = JS_EXCEPTION;\ndone:\n    string_buffer_free(b);\ndone1:\n    value_buffer_free(results);\n    JS_FreeValue(ctx, rep_val);\n    JS_FreeValue(ctx, matched);\n    JS_FreeValue(ctx, flags);\n    JS_FreeValue(ctx, tab);\n    JS_FreeValue(ctx, rep_str);\n    JS_FreeValue(ctx, namedCaptures);\n    JS_FreeValue(ctx, str);\n    return res;\n}\n\nstatic JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JSValueConst rx = this_val;\n    JSValue str, previousLastIndex, currentLastIndex, result, index;\n\n    if (!JS_IsObject(rx))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    result = JS_UNDEFINED;\n    currentLastIndex = JS_UNDEFINED;\n    previousLastIndex = JS_UNDEFINED;\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        goto exception;\n\n    previousLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);\n    if (JS_IsException(previousLastIndex))\n        goto exception;\n\n    if (!js_same_value(ctx, previousLastIndex, JS_NewInt32(ctx, 0))) {\n        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, JS_NewInt32(ctx, 0)) < 0) {\n            goto exception;\n        }\n    }\n    result = JS_RegExpExec(ctx, rx, str);\n    if (JS_IsException(result))\n        goto exception;\n    currentLastIndex = JS_GetProperty(ctx, rx, JS_ATOM_lastIndex);\n    if (JS_IsException(currentLastIndex))\n        goto exception;\n    if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {\n        JS_FreeValue(ctx, previousLastIndex);\n    } else {\n        if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {\n            previousLastIndex = JS_UNDEFINED;\n            goto exception;\n        }\n    }\n    JS_FreeValue(ctx, str);\n    JS_FreeValue(ctx, currentLastIndex);\n\n    if (JS_IsNull(result)) {\n        return JS_NewInt32(ctx, -1);\n    } else {\n        index = JS_GetProperty(ctx, result, JS_ATOM_index);\n        JS_FreeValue(ctx, result);\n        return index;\n    }\n\nexception:\n    JS_FreeValue(ctx, result);\n    JS_FreeValue(ctx, str);\n    JS_FreeValue(ctx, currentLastIndex);\n    JS_FreeValue(ctx, previousLastIndex);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    // [Symbol.split](str, limit)\n    JSValueConst rx = this_val;\n    JSValueConst args[2];\n    JSValue str, ctor, splitter, A, flags, z, sub;\n    JSString *strp;\n    uint32_t lim, size, p, q;\n    int unicodeMatching;\n    int64_t lengthA, e, numberOfCaptures, i;\n\n    if (!JS_IsObject(rx))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    ctor = JS_UNDEFINED;\n    splitter = JS_UNDEFINED;\n    A = JS_UNDEFINED;\n    flags = JS_UNDEFINED;\n    z = JS_UNDEFINED;\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        goto exception;\n    ctor = JS_SpeciesConstructor(ctx, rx, ctx->regexp_ctor);\n    if (JS_IsException(ctor))\n        goto exception;\n    flags = JS_ToStringFree(ctx, JS_GetProperty(ctx, rx, JS_ATOM_flags));\n    if (JS_IsException(flags))\n        goto exception;\n    strp = JS_VALUE_GET_STRING(flags);\n    unicodeMatching = (string_indexof_char(strp, 'u', 0) >= 0 ||\n                       string_indexof_char(strp, 'v', 0) >= 0);\n    if (string_indexof_char(strp, 'y', 0) < 0) {\n        flags = JS_ConcatString3(ctx, \"\", flags, \"y\");\n        if (JS_IsException(flags))\n            goto exception;\n    }\n    args[0] = rx;\n    args[1] = flags;\n    splitter = JS_CallConstructor(ctx, ctor, 2, args);\n    if (JS_IsException(splitter))\n        goto exception;\n    A = JS_NewArray(ctx);\n    if (JS_IsException(A))\n        goto exception;\n    lengthA = 0;\n    if (JS_IsUndefined(argv[1])) {\n        lim = 0xffffffff;\n    } else {\n        if (JS_ToUint32(ctx, &lim, argv[1]) < 0)\n            goto exception;\n        if (lim == 0)\n            goto done;\n    }\n    strp = JS_VALUE_GET_STRING(str);\n    p = q = 0;\n    size = strp->len;\n    if (size == 0) {\n        z = JS_RegExpExec(ctx, splitter, str);\n        if (JS_IsException(z))\n            goto exception;\n        if (JS_IsNull(z))\n            goto add_tail;\n        goto done;\n    }\n    while (q < size) {\n        if (JS_SetProperty(ctx, splitter, JS_ATOM_lastIndex, JS_NewInt32(ctx, q)) < 0)\n            goto exception;\n        JS_FreeValue(ctx, z);\n        z = JS_RegExpExec(ctx, splitter, str);\n        if (JS_IsException(z))\n            goto exception;\n        if (JS_IsNull(z)) {\n            q = string_advance_index(strp, q, unicodeMatching);\n        } else {\n            if (JS_ToLengthFree(ctx, &e, JS_GetProperty(ctx, splitter, JS_ATOM_lastIndex)))\n                goto exception;\n            if (e > size)\n                e = size;\n            if (e == p) {\n                q = string_advance_index(strp, q, unicodeMatching);\n            } else {\n                sub = js_sub_string(ctx, strp, p, q);\n                if (JS_IsException(sub))\n                    goto exception;\n                if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,\n                                                JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                    goto exception;\n                if (lengthA == lim)\n                    goto done;\n                p = e;\n                if (js_get_length64(ctx, &numberOfCaptures, z))\n                    goto exception;\n                for(i = 1; i < numberOfCaptures; i++) {\n                    sub = JS_GetPropertyInt64(ctx, z, i);\n                    if (JS_IsException(sub))\n                        goto exception;\n                    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n                        goto exception;\n                    if (lengthA == lim)\n                        goto done;\n                }\n                q = p;\n            }\n        }\n    }\nadd_tail:\n    if (p > size)\n        p = size;\n    sub = js_sub_string(ctx, strp, p, size);\n    if (JS_IsException(sub))\n        goto exception;\n    if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)\n        goto exception;\n    goto done;\nexception:\n    JS_FreeValue(ctx, A);\n    A = JS_EXCEPTION;\ndone:\n    JS_FreeValue(ctx, str);\n    JS_FreeValue(ctx, ctor);\n    JS_FreeValue(ctx, splitter);\n    JS_FreeValue(ctx, flags);\n    JS_FreeValue(ctx, z);\n    return A;\n}\n\nstatic const JSCFunctionListEntry js_regexp_funcs[] = {\n    JS_CFUNC_DEF(\"escape\", 1, js_regexp_escape ),\n    JS_CGETSET_DEF(\"[Symbol.species]\", js_get_this, NULL ),\n};\n\nstatic const JSCFunctionListEntry js_regexp_proto_funcs[] = {\n    JS_CGETSET_DEF(\"flags\", js_regexp_get_flags, NULL ),\n    JS_CGETSET_DEF(\"source\", js_regexp_get_source, NULL ),\n    JS_CGETSET_MAGIC_DEF(\"global\", js_regexp_get_flag, NULL, LRE_FLAG_GLOBAL ),\n    JS_CGETSET_MAGIC_DEF(\"ignoreCase\", js_regexp_get_flag, NULL, LRE_FLAG_IGNORECASE ),\n    JS_CGETSET_MAGIC_DEF(\"multiline\", js_regexp_get_flag, NULL, LRE_FLAG_MULTILINE ),\n    JS_CGETSET_MAGIC_DEF(\"dotAll\", js_regexp_get_flag, NULL, LRE_FLAG_DOTALL ),\n    JS_CGETSET_MAGIC_DEF(\"unicode\", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE ),\n    JS_CGETSET_MAGIC_DEF(\"unicodeSets\", js_regexp_get_flag, NULL, LRE_FLAG_UNICODE_SETS ),\n    JS_CGETSET_MAGIC_DEF(\"sticky\", js_regexp_get_flag, NULL, LRE_FLAG_STICKY ),\n    JS_CGETSET_MAGIC_DEF(\"hasIndices\", js_regexp_get_flag, NULL, LRE_FLAG_INDICES ),\n    JS_CFUNC_DEF(\"exec\", 1, js_regexp_exec ),\n    JS_CFUNC_DEF(\"compile\", 2, js_regexp_compile ),\n    JS_CFUNC_DEF(\"test\", 1, js_regexp_test ),\n    JS_CFUNC_DEF(\"toString\", 0, js_regexp_toString ),\n    JS_CFUNC_DEF(\"[Symbol.replace]\", 2, js_regexp_Symbol_replace ),\n    JS_CFUNC_DEF(\"[Symbol.match]\", 1, js_regexp_Symbol_match ),\n    JS_CFUNC_DEF(\"[Symbol.matchAll]\", 1, js_regexp_Symbol_matchAll ),\n    JS_CFUNC_DEF(\"[Symbol.search]\", 1, js_regexp_Symbol_search ),\n    JS_CFUNC_DEF(\"[Symbol.split]\", 2, js_regexp_Symbol_split ),\n};\n\nstatic const JSCFunctionListEntry js_regexp_string_iterator_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_regexp_string_iterator_next, 0 ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"RegExp String Iterator\", JS_PROP_CONFIGURABLE ),\n};\n\nvoid JS_AddIntrinsicRegExpCompiler(JSContext *ctx)\n{\n    ctx->compile_regexp = js_compile_regexp;\n}\n\nint JS_AddIntrinsicRegExp(JSContext *ctx)\n{\n    JSValue obj;\n\n    JS_AddIntrinsicRegExpCompiler(ctx);\n\n    obj = JS_NewCConstructor(ctx, JS_CLASS_REGEXP, \"RegExp\",\n                                    js_regexp_constructor, 2, JS_CFUNC_constructor_or_func, 0,\n                                    JS_UNDEFINED,\n                                    js_regexp_funcs, countof(js_regexp_funcs),\n                                    js_regexp_proto_funcs, countof(js_regexp_proto_funcs),\n                                    0);\n    if (JS_IsException(obj))\n        return -1;\n    ctx->regexp_ctor = obj;\n    \n    ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR] =\n        JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR],\n                              js_regexp_string_iterator_proto_funcs,\n                              countof(js_regexp_string_iterator_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_REGEXP_STRING_ITERATOR]))\n        return -1;\n\n    ctx->regexp_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_REGEXP]),\n                                     JS_PROP_INITIAL_HASH_SIZE, 1);\n    if (!ctx->regexp_shape)\n        return -1;\n    if (add_shape_property(ctx, &ctx->regexp_shape, NULL,\n                           JS_ATOM_lastIndex, JS_PROP_WRITABLE))\n        return -1;\n\n    ctx->regexp_result_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),\n                                     JS_PROP_INITIAL_HASH_SIZE, 4);\n    if (!ctx->regexp_result_shape)\n        return -1;\n    if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,\n                           JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH))\n        return -1;\n    if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,\n                           JS_ATOM_index, JS_PROP_C_W_E))\n        return -1;\n    if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,\n                           JS_ATOM_input, JS_PROP_C_W_E))\n        return -1;\n    if (add_shape_property(ctx, &ctx->regexp_result_shape, NULL,\n                           JS_ATOM_groups, JS_PROP_C_W_E))\n        return -1;\n\n    return 0;\n}\n\n/* JSON */\n\nstatic int json_parse_expect(JSParseState *s, int tok)\n{\n    if (s->token.val != tok) {\n        /* XXX: dump token correctly in all cases */\n        return js_parse_error(s, \"expecting '%c'\", tok);\n    }\n    return json_next_token(s);\n}\n\nstatic JSValue json_parse_value(JSParseState *s)\n{\n    JSContext *ctx = s->ctx;\n    JSValue val = JS_NULL;\n    int ret;\n\n    switch(s->token.val) {\n    case '{':\n        {\n            JSValue prop_val;\n            JSAtom prop_name;\n\n            if (json_next_token(s))\n                goto fail;\n            val = JS_NewObject(ctx);\n            if (JS_IsException(val))\n                goto fail;\n            if (s->token.val != '}') {\n                for(;;) {\n                    if (s->token.val == TOK_STRING) {\n                        prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);\n                        if (prop_name == JS_ATOM_NULL)\n                            goto fail;\n                    } else if (s->ext_json && s->token.val == TOK_IDENT) {\n                        prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);\n                    } else {\n                        js_parse_error(s, \"expecting property name\");\n                        goto fail;\n                    }\n                    if (json_next_token(s))\n                        goto fail1;\n                    if (json_parse_expect(s, ':'))\n                        goto fail1;\n                    prop_val = json_parse_value(s);\n                    if (JS_IsException(prop_val)) {\n                    fail1:\n                        JS_FreeAtom(ctx, prop_name);\n                        goto fail;\n                    }\n                    ret = JS_DefinePropertyValue(ctx, val, prop_name,\n                                                 prop_val, JS_PROP_C_W_E);\n                    JS_FreeAtom(ctx, prop_name);\n                    if (ret < 0)\n                        goto fail;\n\n                    if (s->token.val != ',')\n                        break;\n                    if (json_next_token(s))\n                        goto fail;\n                    if (s->ext_json && s->token.val == '}')\n                        break;\n                }\n            }\n            if (json_parse_expect(s, '}'))\n                goto fail;\n        }\n        break;\n    case '[':\n        {\n            JSValue el;\n            uint32_t idx;\n\n            if (json_next_token(s))\n                goto fail;\n            val = JS_NewArray(ctx);\n            if (JS_IsException(val))\n                goto fail;\n            if (s->token.val != ']') {\n                idx = 0;\n                for(;;) {\n                    el = json_parse_value(s);\n                    if (JS_IsException(el))\n                        goto fail;\n                    ret = JS_DefinePropertyValueUint32(ctx, val, idx, el, JS_PROP_C_W_E);\n                    if (ret < 0)\n                        goto fail;\n                    if (s->token.val != ',')\n                        break;\n                    if (json_next_token(s))\n                        goto fail;\n                    idx++;\n                    if (s->ext_json && s->token.val == ']')\n                        break;\n                }\n            }\n            if (json_parse_expect(s, ']'))\n                goto fail;\n        }\n        break;\n    case TOK_STRING:\n        val = JS_DupValue(ctx, s->token.u.str.str);\n        if (json_next_token(s))\n            goto fail;\n        break;\n    case TOK_NUMBER:\n        val = s->token.u.num.val;\n        if (json_next_token(s))\n            goto fail;\n        break;\n    case TOK_IDENT:\n        if (s->token.u.ident.atom == JS_ATOM_false ||\n            s->token.u.ident.atom == JS_ATOM_true) {\n            val = JS_NewBool(ctx, s->token.u.ident.atom == JS_ATOM_true);\n        } else if (s->token.u.ident.atom == JS_ATOM_null) {\n            val = JS_NULL;\n        } else if (s->token.u.ident.atom == JS_ATOM_NaN && s->ext_json) {\n            /* Note: json5 identifier handling is ambiguous e.g. is \n               '{ NaN: 1 }' a valid JSON5 production ? */ \n            val = JS_NewFloat64(s->ctx, NAN);\n        } else if (s->token.u.ident.atom == JS_ATOM_Infinity && s->ext_json) {\n            val = JS_NewFloat64(s->ctx, INFINITY);\n        } else {\n            goto def_token;\n        }\n        if (json_next_token(s))\n            goto fail;\n        break;\n    default:\n    def_token:\n        if (s->token.val == TOK_EOF) {\n            js_parse_error(s, \"Unexpected end of JSON input\");\n        } else {\n            js_parse_error(s, \"unexpected token: '%.*s'\",\n                           (int)(s->buf_ptr - s->token.ptr), s->token.ptr);\n        }\n        goto fail;\n    }\n    return val;\n fail:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\nJSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,\n                      const char *filename, int flags)\n{\n    JSParseState s1, *s = &s1;\n    JSValue val = JS_UNDEFINED;\n\n    js_parse_init(ctx, s, buf, buf_len, filename);\n    s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);\n    if (json_next_token(s))\n        goto fail;\n    val = json_parse_value(s);\n    if (JS_IsException(val))\n        goto fail;\n    if (s->token.val != TOK_EOF) {\n        if (js_parse_error(s, \"unexpected data at the end\"))\n            goto fail;\n    }\n    return val;\n fail:\n    JS_FreeValue(ctx, val);\n    free_token(s, &s->token);\n    return JS_EXCEPTION;\n}\n\nJSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,\n                     const char *filename)\n{\n    return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);\n}\n\nstatic JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,\n                                         JSAtom name, JSValueConst reviver)\n{\n    JSValue val, new_el, name_val, res;\n    JSValueConst args[2];\n    int ret, is_array;\n    uint32_t i, len = 0;\n    JSAtom prop;\n    JSPropertyEnum *atoms = NULL;\n\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        return JS_ThrowStackOverflow(ctx);\n    }\n\n    val = JS_GetProperty(ctx, holder, name);\n    if (JS_IsException(val))\n        return val;\n    if (JS_IsObject(val)) {\n        is_array = JS_IsArray(ctx, val);\n        if (is_array < 0)\n            goto fail;\n        if (is_array) {\n            if (js_get_length32(ctx, &len, val))\n                goto fail;\n        } else {\n            ret = JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, JS_VALUE_GET_OBJ(val), JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);\n            if (ret < 0)\n                goto fail;\n        }\n        for(i = 0; i < len; i++) {\n            if (is_array) {\n                prop = JS_NewAtomUInt32(ctx, i);\n                if (prop == JS_ATOM_NULL)\n                    goto fail;\n            } else {\n                prop = JS_DupAtom(ctx, atoms[i].atom);\n            }\n            new_el = internalize_json_property(ctx, val, prop, reviver);\n            if (JS_IsException(new_el)) {\n                JS_FreeAtom(ctx, prop);\n                goto fail;\n            }\n            if (JS_IsUndefined(new_el)) {\n                ret = JS_DeleteProperty(ctx, val, prop, 0);\n            } else {\n                ret = JS_DefinePropertyValue(ctx, val, prop, new_el, JS_PROP_C_W_E);\n            }\n            JS_FreeAtom(ctx, prop);\n            if (ret < 0)\n                goto fail;\n        }\n    }\n    JS_FreePropertyEnum(ctx, atoms, len);\n    atoms = NULL;\n    name_val = JS_AtomToValue(ctx, name);\n    if (JS_IsException(name_val))\n        goto fail;\n    args[0] = name_val;\n    args[1] = val;\n    res = JS_Call(ctx, reviver, holder, 2, args);\n    JS_FreeValue(ctx, name_val);\n    JS_FreeValue(ctx, val);\n    return res;\n fail:\n    JS_FreePropertyEnum(ctx, atoms, len);\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_json_parse(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    JSValue obj, root;\n    JSValueConst reviver;\n    const char *str;\n    size_t len;\n\n    str = JS_ToCStringLen(ctx, &len, argv[0]);\n    if (!str)\n        return JS_EXCEPTION;\n    obj = JS_ParseJSON(ctx, str, len, \"<input>\");\n    JS_FreeCString(ctx, str);\n    if (JS_IsException(obj))\n        return obj;\n    if (argc > 1 && JS_IsFunction(ctx, argv[1])) {\n        reviver = argv[1];\n        root = JS_NewObject(ctx);\n        if (JS_IsException(root)) {\n            JS_FreeValue(ctx, obj);\n            return JS_EXCEPTION;\n        }\n        if (JS_DefinePropertyValue(ctx, root, JS_ATOM_empty_string, obj,\n                                   JS_PROP_C_W_E) < 0) {\n            JS_FreeValue(ctx, root);\n            return JS_EXCEPTION;\n        }\n        obj = internalize_json_property(ctx, root, JS_ATOM_empty_string,\n                                        reviver);\n        JS_FreeValue(ctx, root);\n    }\n    return obj;\n}\n\ntypedef struct JSONStringifyContext {\n    JSValueConst replacer_func;\n    JSValue stack;\n    JSValue property_list;\n    JSValue gap;\n    JSValue empty;\n    StringBuffer *b;\n} JSONStringifyContext;\n\nstatic int JS_ToQuotedString(JSContext *ctx, StringBuffer *b, JSValueConst val1)\n{\n    JSValue val;\n    JSString *p;\n    int i;\n    uint32_t c;\n    char buf[16];\n\n    val = JS_ToStringCheckObject(ctx, val1);\n    if (JS_IsException(val))\n        return -1;\n    p = JS_VALUE_GET_STRING(val);\n\n    if (string_buffer_putc8(b, '\\\"'))\n        goto fail;\n    for(i = 0; i < p->len; ) {\n        c = string_getc(p, &i);\n        switch(c) {\n        case '\\t':\n            c = 't';\n            goto quote;\n        case '\\r':\n            c = 'r';\n            goto quote;\n        case '\\n':\n            c = 'n';\n            goto quote;\n        case '\\b':\n            c = 'b';\n            goto quote;\n        case '\\f':\n            c = 'f';\n            goto quote;\n        case '\\\"':\n        case '\\\\':\n        quote:\n            if (string_buffer_putc8(b, '\\\\'))\n                goto fail;\n            if (string_buffer_putc8(b, c))\n                goto fail;\n            break;\n        default:\n            if (c < 32 || is_surrogate(c)) {\n                snprintf(buf, sizeof(buf), \"\\\\u%04x\", c);\n                if (string_buffer_puts8(b, buf))\n                    goto fail;\n            } else {\n                if (string_buffer_putc(b, c))\n                    goto fail;\n            }\n            break;\n        }\n    }\n    if (string_buffer_putc8(b, '\\\"'))\n        goto fail;\n    JS_FreeValue(ctx, val);\n    return 0;\n fail:\n    JS_FreeValue(ctx, val);\n    return -1;\n}\n\nstatic int JS_ToQuotedStringFree(JSContext *ctx, StringBuffer *b, JSValue val) {\n    int ret = JS_ToQuotedString(ctx, b, val);\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,\n                             JSValueConst holder, JSValue val, JSValueConst key)\n{\n    JSValue v;\n    JSValueConst args[2];\n\n    /* check for object.toJSON method */\n    /* ECMA specifies this is done only for Object and BigInt */\n    if (JS_IsObject(val) || JS_IsBigInt(ctx, val)) {\n        JSValue f = JS_GetProperty(ctx, val, JS_ATOM_toJSON);\n        if (JS_IsException(f))\n            goto exception;\n        if (JS_IsFunction(ctx, f)) {\n            v = JS_CallFree(ctx, f, val, 1, &key);\n            JS_FreeValue(ctx, val);\n            val = v;\n            if (JS_IsException(val))\n                goto exception;\n        } else {\n            JS_FreeValue(ctx, f);\n        }\n    }\n\n    if (!JS_IsUndefined(jsc->replacer_func)) {\n        args[0] = key;\n        args[1] = val;\n        v = JS_Call(ctx, jsc->replacer_func, holder, 2, args);\n        JS_FreeValue(ctx, val);\n        val = v;\n        if (JS_IsException(val))\n            goto exception;\n    }\n\n    switch (JS_VALUE_GET_NORM_TAG(val)) {\n    case JS_TAG_OBJECT:\n        if (JS_IsFunction(ctx, val))\n            break;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n    case JS_TAG_INT:\n    case JS_TAG_FLOAT64:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n    case JS_TAG_EXCEPTION:\n        return val;\n    default:\n        break;\n    }\n    JS_FreeValue(ctx, val);\n    return JS_UNDEFINED;\n\nexception:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\nstatic int js_json_to_str(JSContext *ctx, JSONStringifyContext *jsc,\n                          JSValueConst holder, JSValue val,\n                          JSValueConst indent)\n{\n    JSValue indent1, sep, sep1, tab, v, prop;\n    JSObject *p;\n    int64_t i, len;\n    int cl, ret;\n    BOOL has_content;\n\n    indent1 = JS_UNDEFINED;\n    sep = JS_UNDEFINED;\n    sep1 = JS_UNDEFINED;\n    tab = JS_UNDEFINED;\n    prop = JS_UNDEFINED;\n\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        JS_ThrowStackOverflow(ctx);\n        goto exception;\n    }\n\n    if (JS_IsObject(val)) {\n        p = JS_VALUE_GET_OBJ(val);\n        cl = p->class_id;\n        if (cl == JS_CLASS_STRING) {\n            val = JS_ToStringFree(ctx, val);\n            if (JS_IsException(val))\n                goto exception;\n            goto concat_primitive;\n        } else if (cl == JS_CLASS_NUMBER) {\n            val = JS_ToNumberFree(ctx, val);\n            if (JS_IsException(val))\n                goto exception;\n            goto concat_primitive;\n        } else if (cl == JS_CLASS_BOOLEAN || cl == JS_CLASS_BIG_INT)\n        {\n            /* This will thow the same error as for the primitive object */\n            set_value(ctx, &val, JS_DupValue(ctx, p->u.object_data));\n            goto concat_primitive;\n        }\n        v = js_array_includes(ctx, jsc->stack, 1, (JSValueConst *)&val);\n        if (JS_IsException(v))\n            goto exception;\n        if (JS_ToBoolFree(ctx, v)) {\n            JS_ThrowTypeError(ctx, \"circular reference\");\n            goto exception;\n        }\n        indent1 = JS_ConcatString(ctx, JS_DupValue(ctx, indent), JS_DupValue(ctx, jsc->gap));\n        if (JS_IsException(indent1))\n            goto exception;\n        if (!JS_IsEmptyString(jsc->gap)) {\n            sep = JS_ConcatString3(ctx, \"\\n\", JS_DupValue(ctx, indent1), \"\");\n            if (JS_IsException(sep))\n                goto exception;\n            sep1 = js_new_string8(ctx, \" \");\n            if (JS_IsException(sep1))\n                goto exception;\n        } else {\n            sep = JS_DupValue(ctx, jsc->empty);\n            sep1 = JS_DupValue(ctx, jsc->empty);\n        }\n        v = js_array_push(ctx, jsc->stack, 1, (JSValueConst *)&val, 0);\n        if (check_exception_free(ctx, v))\n            goto exception;\n        ret = JS_IsArray(ctx, val);\n        if (ret < 0)\n            goto exception;\n        if (ret) {\n            if (js_get_length64(ctx, &len, val))\n                goto exception;\n            string_buffer_putc8(jsc->b, '[');\n            for(i = 0; i < len; i++) {\n                if (i > 0)\n                    string_buffer_putc8(jsc->b, ',');\n                string_buffer_concat_value(jsc->b, sep);\n                v = JS_GetPropertyInt64(ctx, val, i);\n                if (JS_IsException(v))\n                    goto exception;\n                /* XXX: could do this string conversion only when needed */\n                prop = JS_ToStringFree(ctx, JS_NewInt64(ctx, i));\n                if (JS_IsException(prop))\n                    goto exception;\n                v = js_json_check(ctx, jsc, val, v, prop);\n                JS_FreeValue(ctx, prop);\n                prop = JS_UNDEFINED;\n                if (JS_IsException(v))\n                    goto exception;\n                if (JS_IsUndefined(v))\n                    v = JS_NULL;\n                if (js_json_to_str(ctx, jsc, val, v, indent1))\n                    goto exception;\n            }\n            if (len > 0 && !JS_IsEmptyString(jsc->gap)) {\n                string_buffer_putc8(jsc->b, '\\n');\n                string_buffer_concat_value(jsc->b, indent);\n            }\n            string_buffer_putc8(jsc->b, ']');\n        } else {\n            if (!JS_IsUndefined(jsc->property_list))\n                tab = JS_DupValue(ctx, jsc->property_list);\n            else\n                tab = js_object_keys(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val, JS_ITERATOR_KIND_KEY);\n            if (JS_IsException(tab))\n                goto exception;\n            if (js_get_length64(ctx, &len, tab))\n                goto exception;\n            string_buffer_putc8(jsc->b, '{');\n            has_content = FALSE;\n            for(i = 0; i < len; i++) {\n                JS_FreeValue(ctx, prop);\n                prop = JS_GetPropertyInt64(ctx, tab, i);\n                if (JS_IsException(prop))\n                    goto exception;\n                v = JS_GetPropertyValue(ctx, val, JS_DupValue(ctx, prop));\n                if (JS_IsException(v))\n                    goto exception;\n                v = js_json_check(ctx, jsc, val, v, prop);\n                if (JS_IsException(v))\n                    goto exception;\n                if (!JS_IsUndefined(v)) {\n                    if (has_content)\n                        string_buffer_putc8(jsc->b, ',');\n                    string_buffer_concat_value(jsc->b, sep);\n                    if (JS_ToQuotedString(ctx, jsc->b, prop)) {\n                        JS_FreeValue(ctx, v);\n                        goto exception;\n                    }\n                    string_buffer_putc8(jsc->b, ':');\n                    string_buffer_concat_value(jsc->b, sep1);\n                    if (js_json_to_str(ctx, jsc, val, v, indent1))\n                        goto exception;\n                    has_content = TRUE;\n                }\n            }\n            if (has_content && !JS_IsEmptyString(jsc->gap)) {\n                string_buffer_putc8(jsc->b, '\\n');\n                string_buffer_concat_value(jsc->b, indent);\n            }\n            string_buffer_putc8(jsc->b, '}');\n        }\n        if (check_exception_free(ctx, js_array_pop(ctx, jsc->stack, 0, NULL, 0)))\n            goto exception;\n        JS_FreeValue(ctx, val);\n        JS_FreeValue(ctx, tab);\n        JS_FreeValue(ctx, sep);\n        JS_FreeValue(ctx, sep1);\n        JS_FreeValue(ctx, indent1);\n        JS_FreeValue(ctx, prop);\n        return 0;\n    }\n concat_primitive:\n    switch (JS_VALUE_GET_NORM_TAG(val)) {\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        return JS_ToQuotedStringFree(ctx, jsc->b, val);\n    case JS_TAG_FLOAT64:\n        if (!isfinite(JS_VALUE_GET_FLOAT64(val))) {\n            val = JS_NULL;\n        }\n        goto concat_value;\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n    case JS_TAG_NULL:\n    concat_value:\n        return string_buffer_concat_value_free(jsc->b, val);\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        /* reject big numbers: use toJSON method to override */\n        JS_ThrowTypeError(ctx, \"Do not know how to serialize a BigInt\");\n        goto exception;\n    default:\n        JS_FreeValue(ctx, val);\n        return 0;\n    }\n\nexception:\n    JS_FreeValue(ctx, val);\n    JS_FreeValue(ctx, tab);\n    JS_FreeValue(ctx, sep);\n    JS_FreeValue(ctx, sep1);\n    JS_FreeValue(ctx, indent1);\n    JS_FreeValue(ctx, prop);\n    return -1;\n}\n\nJSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,\n                         JSValueConst replacer, JSValueConst space0)\n{\n    StringBuffer b_s;\n    JSONStringifyContext jsc_s, *jsc = &jsc_s;\n    JSValue val, v, space, ret, wrapper;\n    int res;\n    int64_t i, j, n;\n\n    jsc->replacer_func = JS_UNDEFINED;\n    jsc->stack = JS_UNDEFINED;\n    jsc->property_list = JS_UNDEFINED;\n    jsc->gap = JS_UNDEFINED;\n    jsc->b = &b_s;\n    jsc->empty = JS_AtomToString(ctx, JS_ATOM_empty_string);\n    ret = JS_UNDEFINED;\n    wrapper = JS_UNDEFINED;\n\n    string_buffer_init(ctx, jsc->b, 0);\n    jsc->stack = JS_NewArray(ctx);\n    if (JS_IsException(jsc->stack))\n        goto exception;\n    if (JS_IsFunction(ctx, replacer)) {\n        jsc->replacer_func = replacer;\n    } else {\n        res = JS_IsArray(ctx, replacer);\n        if (res < 0)\n            goto exception;\n        if (res) {\n            /* XXX: enumeration is not fully correct */\n            jsc->property_list = JS_NewArray(ctx);\n            if (JS_IsException(jsc->property_list))\n                goto exception;\n            if (js_get_length64(ctx, &n, replacer))\n                goto exception;\n            for (i = j = 0; i < n; i++) {\n                JSValue present;\n                v = JS_GetPropertyInt64(ctx, replacer, i);\n                if (JS_IsException(v))\n                    goto exception;\n                if (JS_IsObject(v)) {\n                    JSObject *p = JS_VALUE_GET_OBJ(v);\n                    if (p->class_id == JS_CLASS_STRING ||\n                        p->class_id == JS_CLASS_NUMBER) {\n                        v = JS_ToStringFree(ctx, v);\n                        if (JS_IsException(v))\n                            goto exception;\n                    } else {\n                        JS_FreeValue(ctx, v);\n                        continue;\n                    }\n                } else if (JS_IsNumber(v)) {\n                    v = JS_ToStringFree(ctx, v);\n                    if (JS_IsException(v))\n                        goto exception;\n                } else if (!JS_IsString(v)) {\n                    JS_FreeValue(ctx, v);\n                    continue;\n                }\n                present = js_array_includes(ctx, jsc->property_list,\n                                            1, (JSValueConst *)&v);\n                if (JS_IsException(present)) {\n                    JS_FreeValue(ctx, v);\n                    goto exception;\n                }\n                if (!JS_ToBoolFree(ctx, present)) {\n                    JS_SetPropertyInt64(ctx, jsc->property_list, j++, v);\n                } else {\n                    JS_FreeValue(ctx, v);\n                }\n            }\n        }\n    }\n    space = JS_DupValue(ctx, space0);\n    if (JS_IsObject(space)) {\n        JSObject *p = JS_VALUE_GET_OBJ(space);\n        if (p->class_id == JS_CLASS_NUMBER) {\n            space = JS_ToNumberFree(ctx, space);\n        } else if (p->class_id == JS_CLASS_STRING) {\n            space = JS_ToStringFree(ctx, space);\n        }\n        if (JS_IsException(space)) {\n            JS_FreeValue(ctx, space);\n            goto exception;\n        }\n    }\n    if (JS_IsNumber(space)) {\n        int n;\n        if (JS_ToInt32Clamp(ctx, &n, space, 0, 10, 0))\n            goto exception;\n        jsc->gap = js_new_string8_len(ctx, \"          \", n);\n    } else if (JS_IsString(space)) {\n        JSString *p = JS_VALUE_GET_STRING(space);\n        jsc->gap = js_sub_string(ctx, p, 0, min_int(p->len, 10));\n    } else {\n        jsc->gap = JS_DupValue(ctx, jsc->empty);\n    }\n    JS_FreeValue(ctx, space);\n    if (JS_IsException(jsc->gap))\n        goto exception;\n    wrapper = JS_NewObject(ctx);\n    if (JS_IsException(wrapper))\n        goto exception;\n    if (JS_DefinePropertyValue(ctx, wrapper, JS_ATOM_empty_string,\n                               JS_DupValue(ctx, obj), JS_PROP_C_W_E) < 0)\n        goto exception;\n    val = JS_DupValue(ctx, obj);\n\n    val = js_json_check(ctx, jsc, wrapper, val, jsc->empty);\n    if (JS_IsException(val))\n        goto exception;\n    if (JS_IsUndefined(val)) {\n        ret = JS_UNDEFINED;\n        goto done1;\n    }\n    if (js_json_to_str(ctx, jsc, wrapper, val, jsc->empty))\n        goto exception;\n\n    ret = string_buffer_end(jsc->b);\n    goto done;\n\nexception:\n    ret = JS_EXCEPTION;\ndone1:\n    string_buffer_free(jsc->b);\ndone:\n    JS_FreeValue(ctx, wrapper);\n    JS_FreeValue(ctx, jsc->empty);\n    JS_FreeValue(ctx, jsc->gap);\n    JS_FreeValue(ctx, jsc->property_list);\n    JS_FreeValue(ctx, jsc->stack);\n    return ret;\n}\n\nstatic JSValue js_json_stringify(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    // stringify(val, replacer, space)\n    return JS_JSONStringify(ctx, argv[0], argv[1], argv[2]);\n}\n\nstatic const JSCFunctionListEntry js_json_funcs[] = {\n    JS_CFUNC_DEF(\"parse\", 2, js_json_parse ),\n    JS_CFUNC_DEF(\"stringify\", 3, js_json_stringify ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"JSON\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_json_obj[] = {\n    JS_OBJECT_DEF(\"JSON\", js_json_funcs, countof(js_json_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\n};\n\nint JS_AddIntrinsicJSON(JSContext *ctx)\n{\n    /* add JSON as autoinit object */\n    return JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_json_obj, countof(js_json_obj));\n}\n\n/* Reflect */\n\nstatic JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);\n}\n\nstatic JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv)\n{\n    JSValueConst func, array_arg, new_target;\n    JSValue *tab, ret;\n    uint32_t len;\n\n    func = argv[0];\n    array_arg = argv[1];\n    if (argc > 2) {\n        new_target = argv[2];\n        if (!JS_IsConstructor(ctx, new_target))\n            return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);\n    } else {\n        new_target = func;\n    }\n    tab = build_arg_list(ctx, &len, array_arg);\n    if (!tab)\n        return JS_EXCEPTION;\n    ret = JS_CallConstructor2(ctx, func, new_target, len, (JSValueConst *)tab);\n    free_arg_list(ctx, tab, len);\n    return ret;\n}\n\nstatic JSValue js_reflect_deleteProperty(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    JSValueConst obj;\n    JSAtom atom;\n    int ret;\n\n    obj = argv[0];\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    atom = JS_ValueToAtom(ctx, argv[1]);\n    if (unlikely(atom == JS_ATOM_NULL))\n        return JS_EXCEPTION;\n    ret = JS_DeleteProperty(ctx, obj, atom, 0);\n    JS_FreeAtom(ctx, atom);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_reflect_get(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSValueConst obj, prop, receiver;\n    JSAtom atom;\n    JSValue ret;\n\n    obj = argv[0];\n    prop = argv[1];\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    if (argc > 2)\n        receiver = argv[2];\n    else\n        receiver = obj;\n    atom = JS_ValueToAtom(ctx, prop);\n    if (unlikely(atom == JS_ATOM_NULL))\n        return JS_EXCEPTION;\n    ret = JS_GetPropertyInternal(ctx, obj, atom, receiver, FALSE);\n    JS_FreeAtom(ctx, atom);\n    return ret;\n}\n\nstatic JSValue js_reflect_has(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSValueConst obj, prop;\n    JSAtom atom;\n    int ret;\n\n    obj = argv[0];\n    prop = argv[1];\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    atom = JS_ValueToAtom(ctx, prop);\n    if (unlikely(atom == JS_ATOM_NULL))\n        return JS_EXCEPTION;\n    ret = JS_HasProperty(ctx, obj, atom);\n    JS_FreeAtom(ctx, atom);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSValueConst obj, prop, val, receiver;\n    int ret;\n    JSAtom atom;\n\n    obj = argv[0];\n    prop = argv[1];\n    val = argv[2];\n    if (argc > 3)\n        receiver = argv[3];\n    else\n        receiver = obj;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    atom = JS_ValueToAtom(ctx, prop);\n    if (unlikely(atom == JS_ATOM_NULL))\n        return JS_EXCEPTION;\n    ret = JS_SetPropertyInternal(ctx, obj, atom,\n                                 JS_DupValue(ctx, val), receiver, 0);\n    JS_FreeAtom(ctx, atom);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_reflect_setPrototypeOf(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    int ret;\n    ret = JS_SetPrototypeInternal(ctx, argv[0], argv[1], FALSE);\n    if (ret < 0)\n        return JS_EXCEPTION;\n    else\n        return JS_NewBool(ctx, ret);\n}\n\nstatic JSValue js_reflect_ownKeys(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    return JS_GetOwnPropertyNames2(ctx, argv[0],\n                                   JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK,\n                                   JS_ITERATOR_KIND_KEY);\n}\n\nstatic const JSCFunctionListEntry js_reflect_funcs[] = {\n    JS_CFUNC_DEF(\"apply\", 3, js_reflect_apply ),\n    JS_CFUNC_DEF(\"construct\", 2, js_reflect_construct ),\n    JS_CFUNC_MAGIC_DEF(\"defineProperty\", 3, js_object_defineProperty, 1 ),\n    JS_CFUNC_DEF(\"deleteProperty\", 2, js_reflect_deleteProperty ),\n    JS_CFUNC_DEF(\"get\", 2, js_reflect_get ),\n    JS_CFUNC_MAGIC_DEF(\"getOwnPropertyDescriptor\", 2, js_object_getOwnPropertyDescriptor, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"getPrototypeOf\", 1, js_object_getPrototypeOf, 1 ),\n    JS_CFUNC_DEF(\"has\", 2, js_reflect_has ),\n    JS_CFUNC_MAGIC_DEF(\"isExtensible\", 1, js_object_isExtensible, 1 ),\n    JS_CFUNC_DEF(\"ownKeys\", 1, js_reflect_ownKeys ),\n    JS_CFUNC_MAGIC_DEF(\"preventExtensions\", 1, js_object_preventExtensions, 1 ),\n    JS_CFUNC_DEF(\"set\", 3, js_reflect_set ),\n    JS_CFUNC_DEF(\"setPrototypeOf\", 2, js_reflect_setPrototypeOf ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Reflect\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_reflect_obj[] = {\n    JS_OBJECT_DEF(\"Reflect\", js_reflect_funcs, countof(js_reflect_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\n};\n\n/* Proxy */\n\nstatic void js_proxy_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);\n    if (s) {\n        JS_FreeValueRT(rt, s->target);\n        JS_FreeValueRT(rt, s->handler);\n        js_free_rt(rt, s);\n    }\n}\n\nstatic void js_proxy_mark(JSRuntime *rt, JSValueConst val,\n                          JS_MarkFunc *mark_func)\n{\n    JSProxyData *s = JS_GetOpaque(val, JS_CLASS_PROXY);\n    if (s) {\n        JS_MarkValue(rt, s->target, mark_func);\n        JS_MarkValue(rt, s->handler, mark_func);\n    }\n}\n\nstatic JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx)\n{\n    return JS_ThrowTypeError(ctx, \"revoked proxy\");\n}\n\nstatic JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod,\n                                     JSValueConst obj, JSAtom name)\n{\n    JSProxyData *s = JS_GetOpaque(obj, JS_CLASS_PROXY);\n    JSValue method;\n\n    /* safer to test recursion in all proxy methods */\n    if (js_check_stack_overflow(ctx->rt, 0)) {\n        JS_ThrowStackOverflow(ctx);\n        return NULL;\n    }\n\n    /* 's' should never be NULL */\n    if (s->is_revoked) {\n        JS_ThrowTypeErrorRevokedProxy(ctx);\n        return NULL;\n    }\n    method = JS_GetProperty(ctx, s->handler, name);\n    if (JS_IsException(method))\n        return NULL;\n    if (JS_IsNull(method))\n        method = JS_UNDEFINED;\n    *pmethod = method;\n    return s;\n}\n\nstatic JSValue js_proxy_get_prototype(JSContext *ctx, JSValueConst obj)\n{\n    JSProxyData *s;\n    JSValue method, ret, proto1;\n    int res;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);\n    if (!s)\n        return JS_EXCEPTION;\n    if (JS_IsUndefined(method))\n        return JS_GetPrototype(ctx, s->target);\n    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);\n    if (JS_IsException(ret))\n        return ret;\n    if (JS_VALUE_GET_TAG(ret) != JS_TAG_NULL &&\n        JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {\n        goto fail;\n    }\n    res = JS_IsExtensible(ctx, s->target);\n    if (res < 0) {\n        JS_FreeValue(ctx, ret);\n        return JS_EXCEPTION;\n    }\n    if (!res) {\n        /* check invariant */\n        proto1 = JS_GetPrototype(ctx, s->target);\n        if (JS_IsException(proto1)) {\n            JS_FreeValue(ctx, ret);\n            return JS_EXCEPTION;\n        }\n        if (!js_same_value(ctx, proto1, ret)) {\n            JS_FreeValue(ctx, proto1);\n        fail:\n            JS_FreeValue(ctx, ret);\n            return JS_ThrowTypeError(ctx, \"proxy: inconsistent prototype\");\n        }\n        JS_FreeValue(ctx, proto1);\n    }\n    return ret;\n}\n\nstatic int js_proxy_set_prototype(JSContext *ctx, JSValueConst obj,\n                                  JSValueConst proto_val)\n{\n    JSProxyData *s;\n    JSValue method, ret, proto1;\n    JSValueConst args[2];\n    BOOL res;\n    int res2;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_setPrototypeOf);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method))\n        return JS_SetPrototypeInternal(ctx, s->target, proto_val, FALSE);\n    args[0] = s->target;\n    args[1] = proto_val;\n    ret = JS_CallFree(ctx, method, s->handler, 2, args);\n    if (JS_IsException(ret))\n        return -1;\n    res = JS_ToBoolFree(ctx, ret);\n    if (!res)\n        return FALSE;\n    res2 = JS_IsExtensible(ctx, s->target);\n    if (res2 < 0)\n        return -1;\n    if (!res2) {\n        proto1 = JS_GetPrototype(ctx, s->target);\n        if (JS_IsException(proto1))\n            return -1;\n        if (!js_same_value(ctx, proto_val, proto1)) {\n            JS_FreeValue(ctx, proto1);\n            JS_ThrowTypeError(ctx, \"proxy: inconsistent prototype\");\n            return -1;\n        }\n        JS_FreeValue(ctx, proto1);\n    }\n    return TRUE;\n}\n\nstatic int js_proxy_is_extensible(JSContext *ctx, JSValueConst obj)\n{\n    JSProxyData *s;\n    JSValue method, ret;\n    BOOL res;\n    int res2;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_isExtensible);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method))\n        return JS_IsExtensible(ctx, s->target);\n    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);\n    if (JS_IsException(ret))\n        return -1;\n    res = JS_ToBoolFree(ctx, ret);\n    res2 = JS_IsExtensible(ctx, s->target);\n    if (res2 < 0)\n        return res2;\n    if (res != res2) {\n        JS_ThrowTypeError(ctx, \"proxy: inconsistent isExtensible\");\n        return -1;\n    }\n    return res;\n}\n\nstatic int js_proxy_prevent_extensions(JSContext *ctx, JSValueConst obj)\n{\n    JSProxyData *s;\n    JSValue method, ret;\n    BOOL res;\n    int res2;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_preventExtensions);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method))\n        return JS_PreventExtensions(ctx, s->target);\n    ret = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);\n    if (JS_IsException(ret))\n        return -1;\n    res = JS_ToBoolFree(ctx, ret);\n    if (res) {\n        res2 = JS_IsExtensible(ctx, s->target);\n        if (res2 < 0)\n            return res2;\n        if (res2) {\n            JS_ThrowTypeError(ctx, \"proxy: inconsistent preventExtensions\");\n            return -1;\n        }\n    }\n    return res;\n}\n\nstatic int js_proxy_has(JSContext *ctx, JSValueConst obj, JSAtom atom)\n{\n    JSProxyData *s;\n    JSValue method, ret1, atom_val;\n    int ret, res;\n    JSObject *p;\n    JSValueConst args[2];\n    BOOL res2;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_has);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method))\n        return JS_HasProperty(ctx, s->target, atom);\n    atom_val = JS_AtomToValue(ctx, atom);\n    if (JS_IsException(atom_val)) {\n        JS_FreeValue(ctx, method);\n        return -1;\n    }\n    args[0] = s->target;\n    args[1] = atom_val;\n    ret1 = JS_CallFree(ctx, method, s->handler, 2, args);\n    JS_FreeValue(ctx, atom_val);\n    if (JS_IsException(ret1))\n        return -1;\n    ret = JS_ToBoolFree(ctx, ret1);\n    if (!ret) {\n        JSPropertyDescriptor desc;\n        p = JS_VALUE_GET_OBJ(s->target);\n        res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom);\n        if (res < 0)\n            return -1;\n        if (res) {\n            res2 = !(desc.flags & JS_PROP_CONFIGURABLE);\n            js_free_desc(ctx, &desc);\n            if (res2 || !p->extensible) {\n                JS_ThrowTypeError(ctx, \"proxy: inconsistent has\");\n                return -1;\n            }\n        }\n    }\n    return ret;\n}\n\nstatic JSValue js_proxy_get(JSContext *ctx, JSValueConst obj, JSAtom atom,\n                            JSValueConst receiver)\n{\n    JSProxyData *s;\n    JSValue method, ret, atom_val;\n    int res;\n    JSValueConst args[3];\n    JSPropertyDescriptor desc;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_get);\n    if (!s)\n        return JS_EXCEPTION;\n    /* Note: recursion is possible thru the prototype of s->target */\n    if (JS_IsUndefined(method))\n        return JS_GetPropertyInternal(ctx, s->target, atom, receiver, FALSE);\n    atom_val = JS_AtomToValue(ctx, atom);\n    if (JS_IsException(atom_val)) {\n        JS_FreeValue(ctx, method);\n        return JS_EXCEPTION;\n    }\n    args[0] = s->target;\n    args[1] = atom_val;\n    args[2] = receiver;\n    ret = JS_CallFree(ctx, method, s->handler, 3, args);\n    JS_FreeValue(ctx, atom_val);\n    if (JS_IsException(ret))\n        return JS_EXCEPTION;\n    res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);\n    if (res < 0) {\n        JS_FreeValue(ctx, ret);\n        return JS_EXCEPTION;\n    }\n    if (res) {\n        if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {\n            if (!js_same_value(ctx, desc.value, ret)) {\n                goto fail;\n            }\n        } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET) {\n            if (JS_IsUndefined(desc.getter) && !JS_IsUndefined(ret)) {\n            fail:\n                js_free_desc(ctx, &desc);\n                JS_FreeValue(ctx, ret);\n                return JS_ThrowTypeError(ctx, \"proxy: inconsistent get\");\n            }\n        }\n        js_free_desc(ctx, &desc);\n    }\n    return ret;\n}\n\nstatic int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,\n                        JSValueConst value, JSValueConst receiver, int flags)\n{\n    JSProxyData *s;\n    JSValue method, ret1, atom_val;\n    int ret, res;\n    JSValueConst args[4];\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_set);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method)) {\n        return JS_SetPropertyInternal(ctx, s->target, atom,\n                                      JS_DupValue(ctx, value), receiver,\n                                      flags);\n    }\n    atom_val = JS_AtomToValue(ctx, atom);\n    if (JS_IsException(atom_val)) {\n        JS_FreeValue(ctx, method);\n        return -1;\n    }\n    args[0] = s->target;\n    args[1] = atom_val;\n    args[2] = value;\n    args[3] = receiver;\n    ret1 = JS_CallFree(ctx, method, s->handler, 4, args);\n    JS_FreeValue(ctx, atom_val);\n    if (JS_IsException(ret1))\n        return -1;\n    ret = JS_ToBoolFree(ctx, ret1);\n    if (ret) {\n        JSPropertyDescriptor desc;\n        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);\n        if (res < 0)\n            return -1;\n        if (res) {\n            if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0) {\n                if (!js_same_value(ctx, desc.value, value)) {\n                    goto fail;\n                }\n            } else if ((desc.flags & (JS_PROP_GETSET | JS_PROP_CONFIGURABLE)) == JS_PROP_GETSET && JS_IsUndefined(desc.setter)) {\n                fail:\n                    js_free_desc(ctx, &desc);\n                    JS_ThrowTypeError(ctx, \"proxy: inconsistent set\");\n                    return -1;\n            }\n            js_free_desc(ctx, &desc);\n        }\n    } else {\n        if ((flags & JS_PROP_THROW) ||\n            ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {\n            JS_ThrowTypeError(ctx, \"proxy: cannot set property\");\n            return -1;\n        }\n    }\n    return ret;\n}\n\nstatic JSValue js_create_desc(JSContext *ctx, JSValueConst val,\n                              JSValueConst getter, JSValueConst setter,\n                              int flags)\n{\n    JSValue ret;\n    ret = JS_NewObject(ctx);\n    if (JS_IsException(ret))\n        return ret;\n    if (flags & JS_PROP_HAS_GET) {\n        JS_DefinePropertyValue(ctx, ret, JS_ATOM_get, JS_DupValue(ctx, getter),\n                               JS_PROP_C_W_E);\n    }\n    if (flags & JS_PROP_HAS_SET) {\n        JS_DefinePropertyValue(ctx, ret, JS_ATOM_set, JS_DupValue(ctx, setter),\n                               JS_PROP_C_W_E);\n    }\n    if (flags & JS_PROP_HAS_VALUE) {\n        JS_DefinePropertyValue(ctx, ret, JS_ATOM_value, JS_DupValue(ctx, val),\n                               JS_PROP_C_W_E);\n    }\n    if (flags & JS_PROP_HAS_WRITABLE) {\n        JS_DefinePropertyValue(ctx, ret, JS_ATOM_writable,\n                               JS_NewBool(ctx, flags & JS_PROP_WRITABLE),\n                               JS_PROP_C_W_E);\n    }\n    if (flags & JS_PROP_HAS_ENUMERABLE) {\n        JS_DefinePropertyValue(ctx, ret, JS_ATOM_enumerable,\n                               JS_NewBool(ctx, flags & JS_PROP_ENUMERABLE),\n                               JS_PROP_C_W_E);\n    }\n    if (flags & JS_PROP_HAS_CONFIGURABLE) {\n        JS_DefinePropertyValue(ctx, ret, JS_ATOM_configurable,\n                               JS_NewBool(ctx, flags & JS_PROP_CONFIGURABLE),\n                               JS_PROP_C_W_E);\n    }\n    return ret;\n}\n\nstatic int js_proxy_get_own_property(JSContext *ctx, JSPropertyDescriptor *pdesc,\n                                     JSValueConst obj, JSAtom prop)\n{\n    JSProxyData *s;\n    JSValue method, trap_result_obj, prop_val;\n    int res, target_desc_ret, ret;\n    JSObject *p;\n    JSValueConst args[2];\n    JSPropertyDescriptor result_desc, target_desc;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_getOwnPropertyDescriptor);\n    if (!s)\n        return -1;\n    p = JS_VALUE_GET_OBJ(s->target);\n    if (JS_IsUndefined(method)) {\n        return JS_GetOwnPropertyInternal(ctx, pdesc, p, prop);\n    }\n    prop_val = JS_AtomToValue(ctx, prop);\n    if (JS_IsException(prop_val)) {\n        JS_FreeValue(ctx, method);\n        return -1;\n    }\n    args[0] = s->target;\n    args[1] = prop_val;\n    trap_result_obj = JS_CallFree(ctx, method, s->handler, 2, args);\n    JS_FreeValue(ctx, prop_val);\n    if (JS_IsException(trap_result_obj))\n        return -1;\n    if (!JS_IsObject(trap_result_obj) && !JS_IsUndefined(trap_result_obj)) {\n        JS_FreeValue(ctx, trap_result_obj);\n        goto fail;\n    }\n    target_desc_ret = JS_GetOwnPropertyInternal(ctx, &target_desc, p, prop);\n    if (target_desc_ret < 0) {\n        JS_FreeValue(ctx, trap_result_obj);\n        return -1;\n    }\n    if (target_desc_ret)\n        js_free_desc(ctx, &target_desc);\n    if (JS_IsUndefined(trap_result_obj)) {\n        if (target_desc_ret) {\n            if (!(target_desc.flags & JS_PROP_CONFIGURABLE) || !p->extensible)\n                goto fail;\n        }\n        ret = FALSE;\n    } else {\n        int flags1, extensible_target;\n        extensible_target = JS_IsExtensible(ctx, s->target);\n        if (extensible_target < 0) {\n            JS_FreeValue(ctx, trap_result_obj);\n            return -1;\n        }\n        res = js_obj_to_desc(ctx, &result_desc, trap_result_obj);\n        JS_FreeValue(ctx, trap_result_obj);\n        if (res < 0)\n            return -1;\n\n        /* convert the result_desc.flags to property flags */\n        if (result_desc.flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {\n            result_desc.flags |= JS_PROP_GETSET;\n        } else {\n            result_desc.flags |= JS_PROP_NORMAL;\n        }\n        result_desc.flags &= (JS_PROP_C_W_E | JS_PROP_TMASK);\n        \n        if (target_desc_ret) {\n            /* convert result_desc.flags to defineProperty flags */\n            flags1 = result_desc.flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE;\n            if (result_desc.flags & JS_PROP_GETSET)\n                flags1 |= JS_PROP_HAS_GET | JS_PROP_HAS_SET;\n            else\n                flags1 |= JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE;\n            /* XXX: not complete check: need to compare value &\n               getter/setter as in defineproperty */\n            if (!check_define_prop_flags(target_desc.flags, flags1))\n                goto fail1;\n        } else {\n            if (!extensible_target)\n                goto fail1;\n        }\n        if (!(result_desc.flags & JS_PROP_CONFIGURABLE)) {\n            if (!target_desc_ret || (target_desc.flags & JS_PROP_CONFIGURABLE))\n                goto fail1;\n            if ((result_desc.flags &\n                 (JS_PROP_GETSET | JS_PROP_WRITABLE)) == 0 &&\n                target_desc_ret &&\n                (target_desc.flags & JS_PROP_WRITABLE) != 0) {\n                /* proxy-missing-checks */\n            fail1:\n                js_free_desc(ctx, &result_desc);\n            fail:\n                JS_ThrowTypeError(ctx, \"proxy: inconsistent getOwnPropertyDescriptor\");\n                return -1;\n            }\n        }\n        ret = TRUE;\n        if (pdesc) {\n            *pdesc = result_desc;\n        } else {\n            js_free_desc(ctx, &result_desc);\n        }\n    }\n    return ret;\n}\n\nstatic int js_proxy_define_own_property(JSContext *ctx, JSValueConst obj,\n                                        JSAtom prop, JSValueConst val,\n                                        JSValueConst getter, JSValueConst setter,\n                                        int flags)\n{\n    JSProxyData *s;\n    JSValue method, ret1, prop_val, desc_val;\n    int res, ret;\n    JSObject *p;\n    JSValueConst args[3];\n    JSPropertyDescriptor desc;\n    BOOL setting_not_configurable;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_defineProperty);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method)) {\n        return JS_DefineProperty(ctx, s->target, prop, val, getter, setter, flags);\n    }\n    prop_val = JS_AtomToValue(ctx, prop);\n    if (JS_IsException(prop_val)) {\n        JS_FreeValue(ctx, method);\n        return -1;\n    }\n    desc_val = js_create_desc(ctx, val, getter, setter, flags);\n    if (JS_IsException(desc_val)) {\n        JS_FreeValue(ctx, prop_val);\n        JS_FreeValue(ctx, method);\n        return -1;\n    }\n    args[0] = s->target;\n    args[1] = prop_val;\n    args[2] = desc_val;\n    ret1 = JS_CallFree(ctx, method, s->handler, 3, args);\n    JS_FreeValue(ctx, prop_val);\n    JS_FreeValue(ctx, desc_val);\n    if (JS_IsException(ret1))\n        return -1;\n    ret = JS_ToBoolFree(ctx, ret1);\n    if (!ret) {\n        if (flags & JS_PROP_THROW) {\n            JS_ThrowTypeError(ctx, \"proxy: defineProperty exception\");\n            return -1;\n        } else {\n            return 0;\n        }\n    }\n    p = JS_VALUE_GET_OBJ(s->target);\n    res = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);\n    if (res < 0)\n        return -1;\n    setting_not_configurable = ((flags & (JS_PROP_HAS_CONFIGURABLE |\n                                          JS_PROP_CONFIGURABLE)) ==\n                                JS_PROP_HAS_CONFIGURABLE);\n    if (!res) {\n        if (!p->extensible || setting_not_configurable)\n            goto fail;\n    } else {\n        if (!check_define_prop_flags(desc.flags, flags))\n            goto fail1;\n        /* do the missing check from check_define_prop_flags() */\n        if (!(desc.flags & JS_PROP_CONFIGURABLE)) {\n            if ((desc.flags & JS_PROP_TMASK) == JS_PROP_GETSET) {\n                if ((flags & JS_PROP_HAS_GET) &&\n                    !js_same_value(ctx, getter, desc.getter)) {\n                    goto fail1;\n                }\n                if ((flags & JS_PROP_HAS_SET) &&\n                    !js_same_value(ctx, setter, desc.setter)) {\n                    goto fail1;\n                }\n            } else if (!(desc.flags & JS_PROP_WRITABLE)) {\n                if ((flags & JS_PROP_HAS_VALUE) &&\n                    !js_same_value(ctx, val, desc.value)) {\n                    goto fail1;\n                }\n            }\n        }\n\n        /* additional checks */\n        if ((desc.flags & JS_PROP_CONFIGURABLE) && setting_not_configurable)\n            goto fail1;\n\n        if ((desc.flags & JS_PROP_TMASK) != JS_PROP_GETSET &&\n            (desc.flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == JS_PROP_WRITABLE &&\n            (flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) == JS_PROP_HAS_WRITABLE) {\n        fail1:\n            js_free_desc(ctx, &desc);\n        fail:\n            JS_ThrowTypeError(ctx, \"proxy: inconsistent defineProperty\");\n            return -1;\n        }\n        js_free_desc(ctx, &desc);\n    }\n    return 1;\n}\n\nstatic int js_proxy_delete_property(JSContext *ctx, JSValueConst obj,\n                                    JSAtom atom)\n{\n    JSProxyData *s;\n    JSValue method, ret, atom_val;\n    int res, res2, is_extensible;\n    JSValueConst args[2];\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_deleteProperty);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method)) {\n        return JS_DeleteProperty(ctx, s->target, atom, 0);\n    }\n    atom_val = JS_AtomToValue(ctx, atom);;\n    if (JS_IsException(atom_val)) {\n        JS_FreeValue(ctx, method);\n        return -1;\n    }\n    args[0] = s->target;\n    args[1] = atom_val;\n    ret = JS_CallFree(ctx, method, s->handler, 2, args);\n    JS_FreeValue(ctx, atom_val);\n    if (JS_IsException(ret))\n        return -1;\n    res = JS_ToBoolFree(ctx, ret);\n    if (res) {\n        JSPropertyDescriptor desc;\n        res2 = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target), atom);\n        if (res2 < 0)\n            return -1;\n        if (res2) {\n            if (!(desc.flags & JS_PROP_CONFIGURABLE))\n                goto fail;\n            is_extensible = JS_IsExtensible(ctx, s->target);\n            if (is_extensible < 0)\n                goto fail1;\n            if (!is_extensible) {\n                /* proxy-missing-checks */\n            fail:\n                JS_ThrowTypeError(ctx, \"proxy: inconsistent deleteProperty\");\n            fail1:\n                js_free_desc(ctx, &desc);\n                return -1;\n            }\n            js_free_desc(ctx, &desc);\n        }\n    }\n    return res;\n}\n\n/* return the index of the property or -1 if not found */\nstatic int find_prop_key(const JSPropertyEnum *tab, int n, JSAtom atom)\n{\n    int i;\n    for(i = 0; i < n; i++) {\n        if (tab[i].atom == atom)\n            return i;\n    }\n    return -1;\n}\n\nstatic int js_proxy_get_own_property_names(JSContext *ctx,\n                                           JSPropertyEnum **ptab,\n                                           uint32_t *plen,\n                                           JSValueConst obj)\n{\n    JSProxyData *s;\n    JSValue method, prop_array, val;\n    uint32_t len, i, len2;\n    JSPropertyEnum *tab, *tab2;\n    JSAtom atom;\n    JSPropertyDescriptor desc;\n    int res, is_extensible, idx;\n\n    s = get_proxy_method(ctx, &method, obj, JS_ATOM_ownKeys);\n    if (!s)\n        return -1;\n    if (JS_IsUndefined(method)) {\n        return JS_GetOwnPropertyNamesInternal(ctx, ptab, plen,\n                                      JS_VALUE_GET_OBJ(s->target),\n                                      JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);\n    }\n    prop_array = JS_CallFree(ctx, method, s->handler, 1, (JSValueConst *)&s->target);\n    if (JS_IsException(prop_array))\n        return -1;\n    tab = NULL;\n    len = 0;\n    tab2 = NULL;\n    len2 = 0;\n    if (js_get_length32(ctx, &len, prop_array))\n        goto fail;\n    if (len > 0) {\n        tab = js_mallocz(ctx, sizeof(tab[0]) * len);\n        if (!tab)\n            goto fail;\n    }\n    for(i = 0; i < len; i++) {\n        val = JS_GetPropertyUint32(ctx, prop_array, i);\n        if (JS_IsException(val))\n            goto fail;\n        if (!JS_IsString(val) && !JS_IsSymbol(val)) {\n            JS_FreeValue(ctx, val);\n            JS_ThrowTypeError(ctx, \"proxy: properties must be strings or symbols\");\n            goto fail;\n        }\n        atom = JS_ValueToAtom(ctx, val);\n        JS_FreeValue(ctx, val);\n        if (atom == JS_ATOM_NULL)\n            goto fail;\n        tab[i].atom = atom;\n        tab[i].is_enumerable = FALSE; /* XXX: redundant? */\n    }\n\n    /* check duplicate properties (XXX: inefficient, could store the\n     * properties an a temporary object to use the hash) */\n    for(i = 1; i < len; i++) {\n        if (find_prop_key(tab, i, tab[i].atom) >= 0) {\n            JS_ThrowTypeError(ctx, \"proxy: duplicate property\");\n            goto fail;\n        }\n    }\n\n    is_extensible = JS_IsExtensible(ctx, s->target);\n    if (is_extensible < 0)\n        goto fail;\n\n    /* check if there are non configurable properties */\n    if (s->is_revoked) {\n        JS_ThrowTypeErrorRevokedProxy(ctx);\n        goto fail;\n    }\n    if (JS_GetOwnPropertyNamesInternal(ctx, &tab2, &len2, JS_VALUE_GET_OBJ(s->target),\n                               JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK))\n        goto fail;\n    for(i = 0; i < len2; i++) {\n        if (s->is_revoked) {\n            JS_ThrowTypeErrorRevokedProxy(ctx);\n            goto fail;\n        }\n        res = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(s->target),\n                                tab2[i].atom);\n        if (res < 0)\n            goto fail;\n        if (res) {  /* safety, property should be found */\n            js_free_desc(ctx, &desc);\n            if (!(desc.flags & JS_PROP_CONFIGURABLE) || !is_extensible) {\n                idx = find_prop_key(tab, len, tab2[i].atom);\n                if (idx < 0) {\n                    JS_ThrowTypeError(ctx, \"proxy: target property must be present in proxy ownKeys\");\n                    goto fail;\n                }\n                /* mark the property as found */\n                if (!is_extensible)\n                    tab[idx].is_enumerable = TRUE;\n            }\n        }\n    }\n    if (!is_extensible) {\n        /* check that all property in 'tab' were checked */\n        for(i = 0; i < len; i++) {\n            if (!tab[i].is_enumerable) {\n                JS_ThrowTypeError(ctx, \"proxy: property not present in target were returned by non extensible proxy\");\n                goto fail;\n            }\n        }\n    }\n\n    JS_FreePropertyEnum(ctx, tab2, len2);\n    JS_FreeValue(ctx, prop_array);\n    *ptab = tab;\n    *plen = len;\n    return 0;\n fail:\n    JS_FreePropertyEnum(ctx, tab2, len2);\n    JS_FreePropertyEnum(ctx, tab, len);\n    JS_FreeValue(ctx, prop_array);\n    return -1;\n}\n\nstatic JSValue js_proxy_call_constructor(JSContext *ctx, JSValueConst func_obj,\n                                         JSValueConst new_target,\n                                         int argc, JSValueConst *argv)\n{\n    JSProxyData *s;\n    JSValue method, arg_array, ret;\n    JSValueConst args[3];\n\n    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_construct);\n    if (!s)\n        return JS_EXCEPTION;\n    if (!JS_IsConstructor(ctx, s->target))\n        return JS_ThrowTypeErrorNotAConstructor(ctx, s->target);\n    if (JS_IsUndefined(method))\n        return JS_CallConstructor2(ctx, s->target, new_target, argc, argv);\n    arg_array = js_create_array(ctx, argc, argv);\n    if (JS_IsException(arg_array)) {\n        ret = JS_EXCEPTION;\n        goto fail;\n    }\n    args[0] = s->target;\n    args[1] = arg_array;\n    args[2] = new_target;\n    ret = JS_Call(ctx, method, s->handler, 3, args);\n    if (!JS_IsException(ret) && JS_VALUE_GET_TAG(ret) != JS_TAG_OBJECT) {\n        JS_FreeValue(ctx, ret);\n        ret = JS_ThrowTypeErrorNotAnObject(ctx);\n    }\n fail:\n    JS_FreeValue(ctx, method);\n    JS_FreeValue(ctx, arg_array);\n    return ret;\n}\n\nstatic JSValue js_proxy_call(JSContext *ctx, JSValueConst func_obj,\n                             JSValueConst this_obj,\n                             int argc, JSValueConst *argv, int flags)\n{\n    JSProxyData *s;\n    JSValue method, arg_array, ret;\n    JSValueConst args[3];\n\n    if (flags & JS_CALL_FLAG_CONSTRUCTOR)\n        return js_proxy_call_constructor(ctx, func_obj, this_obj, argc, argv);\n\n    s = get_proxy_method(ctx, &method, func_obj, JS_ATOM_apply);\n    if (!s)\n        return JS_EXCEPTION;\n    if (!s->is_func) {\n        JS_FreeValue(ctx, method);\n        return JS_ThrowTypeError(ctx, \"not a function\");\n    }\n    if (JS_IsUndefined(method))\n        return JS_Call(ctx, s->target, this_obj, argc, argv);\n    arg_array = js_create_array(ctx, argc, argv);\n    if (JS_IsException(arg_array)) {\n        ret = JS_EXCEPTION;\n        goto fail;\n    }\n    args[0] = s->target;\n    args[1] = this_obj;\n    args[2] = arg_array;\n    ret = JS_Call(ctx, method, s->handler, 3, args);\n fail:\n    JS_FreeValue(ctx, method);\n    JS_FreeValue(ctx, arg_array);\n    return ret;\n}\n\n/* `js_resolve_proxy`: resolve the proxy chain\n   `*pval` is updated with to ultimate proxy target\n   `throw_exception` controls whether exceptions are thown or not\n   - return -1 in case of error\n   - otherwise return 0\n */\nstatic int js_resolve_proxy(JSContext *ctx, JSValueConst *pval, BOOL throw_exception) {\n    int depth = 0;\n    JSObject *p;\n    JSProxyData *s;\n\n    while (JS_VALUE_GET_TAG(*pval) == JS_TAG_OBJECT) {\n        p = JS_VALUE_GET_OBJ(*pval);\n        if (p->class_id != JS_CLASS_PROXY)\n            break;\n        if (depth++ > 1000) {\n            if (throw_exception)\n                JS_ThrowStackOverflow(ctx);\n            return -1;\n        }\n        s = p->u.opaque;\n        if (s->is_revoked) {\n            if (throw_exception)\n                JS_ThrowTypeErrorRevokedProxy(ctx);\n            return -1;\n        }\n        *pval = s->target;\n    }\n    return 0;\n}\n\nstatic const JSClassExoticMethods js_proxy_exotic_methods = {\n    .get_own_property = js_proxy_get_own_property,\n    .define_own_property = js_proxy_define_own_property,\n    .delete_property = js_proxy_delete_property,\n    .get_own_property_names = js_proxy_get_own_property_names,\n    .has_property = js_proxy_has,\n    .get_property = js_proxy_get,\n    .set_property = js_proxy_set,\n    .get_prototype = js_proxy_get_prototype,\n    .set_prototype = js_proxy_set_prototype,\n    .is_extensible = js_proxy_is_extensible,\n    .prevent_extensions = js_proxy_prevent_extensions,\n};\n\nstatic JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv)\n{\n    JSValueConst target, handler;\n    JSValue obj;\n    JSProxyData *s;\n\n    target = argv[0];\n    handler = argv[1];\n    if (JS_VALUE_GET_TAG(target) != JS_TAG_OBJECT ||\n        JS_VALUE_GET_TAG(handler) != JS_TAG_OBJECT)\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_PROXY);\n    if (JS_IsException(obj))\n        return obj;\n    s = js_malloc(ctx, sizeof(JSProxyData));\n    if (!s) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    s->target = JS_DupValue(ctx, target);\n    s->handler = JS_DupValue(ctx, handler);\n    s->is_func = JS_IsFunction(ctx, target);\n    s->is_revoked = FALSE;\n    JS_SetOpaque(obj, s);\n    JS_SetConstructorBit(ctx, obj, JS_IsConstructor(ctx, target));\n    return obj;\n}\n\nstatic JSValue js_proxy_revoke(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv, int magic,\n                               JSValue *func_data)\n{\n    JSProxyData *s = JS_GetOpaque(func_data[0], JS_CLASS_PROXY);\n    if (s) {\n        /* We do not free the handler and target in case they are\n           referenced as constants in the C call stack */\n        s->is_revoked = TRUE;\n        JS_FreeValue(ctx, func_data[0]);\n        func_data[0] = JS_NULL;\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_proxy_revoke_constructor(JSContext *ctx,\n                                           JSValueConst proxy_obj)\n{\n    return JS_NewCFunctionData(ctx, js_proxy_revoke, 0, 0, 1, &proxy_obj);\n}\n\nstatic JSValue js_proxy_revocable(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue proxy_obj, revoke_obj = JS_UNDEFINED, obj;\n\n    proxy_obj = js_proxy_constructor(ctx, JS_UNDEFINED, argc, argv);\n    if (JS_IsException(proxy_obj))\n        goto fail;\n    revoke_obj = js_proxy_revoke_constructor(ctx, proxy_obj);\n    if (JS_IsException(revoke_obj))\n        goto fail;\n    obj = JS_NewObject(ctx);\n    if (JS_IsException(obj))\n        goto fail;\n    // XXX: exceptions?\n    JS_DefinePropertyValue(ctx, obj, JS_ATOM_proxy, proxy_obj, JS_PROP_C_W_E);\n    JS_DefinePropertyValue(ctx, obj, JS_ATOM_revoke, revoke_obj, JS_PROP_C_W_E);\n    return obj;\n fail:\n    JS_FreeValue(ctx, proxy_obj);\n    JS_FreeValue(ctx, revoke_obj);\n    return JS_EXCEPTION;\n}\n\nstatic const JSCFunctionListEntry js_proxy_funcs[] = {\n    JS_CFUNC_DEF(\"revocable\", 2, js_proxy_revocable ),\n};\n\nstatic const JSClassShortDef js_proxy_class_def[] = {\n    { JS_ATOM_Object, js_proxy_finalizer, js_proxy_mark }, /* JS_CLASS_PROXY */\n};\n\nint JS_AddIntrinsicProxy(JSContext *ctx)\n{\n    JSRuntime *rt = ctx->rt;\n    JSValue obj1;\n\n    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROXY)) {\n        if (init_class_range(rt, js_proxy_class_def, JS_CLASS_PROXY,\n                             countof(js_proxy_class_def)))\n            return -1;\n        rt->class_array[JS_CLASS_PROXY].exotic = &js_proxy_exotic_methods;\n        rt->class_array[JS_CLASS_PROXY].call = js_proxy_call;\n    }\n\n    /* additional fields: name, length */\n    obj1 = JS_NewCFunction3(ctx, js_proxy_constructor, \"Proxy\", 2,\n                            JS_CFUNC_constructor, 0,\n                            ctx->function_proto, countof(js_proxy_funcs) + 2);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_SetConstructorBit(ctx, obj1, TRUE);\n    if (JS_SetPropertyFunctionList(ctx, obj1, js_proxy_funcs,\n                                   countof(js_proxy_funcs)))\n        goto fail;\n    if (JS_DefinePropertyValueStr(ctx, ctx->global_obj, \"Proxy\",\n                                  obj1, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE) < 0)\n        goto fail;\n    return 0;\n fail:\n    JS_FreeValue(ctx, obj1);\n    return -1;\n}\n\n/* Symbol */\n\nstatic JSValue js_symbol_constructor(JSContext *ctx, JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue str;\n    JSString *p;\n\n    if (!JS_IsUndefined(new_target))\n        return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);\n    if (argc == 0 || JS_IsUndefined(argv[0])) {\n        p = NULL;\n    } else {\n        str = JS_ToString(ctx, argv[0]);\n        if (JS_IsException(str))\n            return JS_EXCEPTION;\n        p = JS_VALUE_GET_STRING(str);\n    }\n    return JS_NewSymbol(ctx, p, JS_ATOM_TYPE_SYMBOL);\n}\n\nstatic JSValue js_thisSymbolValue(JSContext *ctx, JSValueConst this_val)\n{\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_SYMBOL)\n        return JS_DupValue(ctx, this_val);\n\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (p->class_id == JS_CLASS_SYMBOL) {\n            if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_SYMBOL)\n                return JS_DupValue(ctx, p->u.object_data);\n        }\n    }\n    return JS_ThrowTypeError(ctx, \"not a symbol\");\n}\n\nstatic JSValue js_symbol_toString(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValue val, ret;\n    val = js_thisSymbolValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    /* XXX: use JS_ToStringInternal() with a flags */\n    ret = js_string_constructor(ctx, JS_UNDEFINED, 1, (JSValueConst *)&val);\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic JSValue js_symbol_valueOf(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    return js_thisSymbolValue(ctx, this_val);\n}\n\nstatic JSValue js_symbol_get_description(JSContext *ctx, JSValueConst this_val)\n{\n    JSValue val, ret;\n    JSAtomStruct *p;\n\n    val = js_thisSymbolValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    p = JS_VALUE_GET_PTR(val);\n    if (p->len == 0 && p->is_wide_char != 0) {\n        ret = JS_UNDEFINED;\n    } else {\n        ret = JS_AtomToString(ctx, js_get_atom_index(ctx->rt, p));\n    }\n    JS_FreeValue(ctx, val);\n    return ret;\n}\n\nstatic const JSCFunctionListEntry js_symbol_proto_funcs[] = {\n    JS_CFUNC_DEF(\"toString\", 0, js_symbol_toString ),\n    JS_CFUNC_DEF(\"valueOf\", 0, js_symbol_valueOf ),\n    // XXX: should have writable: false\n    JS_CFUNC_DEF(\"[Symbol.toPrimitive]\", 1, js_symbol_valueOf ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Symbol\", JS_PROP_CONFIGURABLE ),\n    JS_CGETSET_DEF(\"description\", js_symbol_get_description, NULL ),\n};\n\nstatic JSValue js_symbol_for(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    JSValue str;\n\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        return JS_EXCEPTION;\n    return JS_NewSymbol(ctx, JS_VALUE_GET_STRING(str), JS_ATOM_TYPE_GLOBAL_SYMBOL);\n}\n\nstatic JSValue js_symbol_keyFor(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSAtomStruct *p;\n\n    if (!JS_IsSymbol(argv[0]))\n        return JS_ThrowTypeError(ctx, \"not a symbol\");\n    p = JS_VALUE_GET_PTR(argv[0]);\n    if (p->atom_type != JS_ATOM_TYPE_GLOBAL_SYMBOL)\n        return JS_UNDEFINED;\n    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_STRING, p));\n}\n\nstatic const JSCFunctionListEntry js_symbol_funcs[] = {\n    JS_CFUNC_DEF(\"for\", 1, js_symbol_for ),\n    JS_CFUNC_DEF(\"keyFor\", 1, js_symbol_keyFor ),\n    JS_PROP_ATOM_DEF(\"toPrimitive\", JS_ATOM_Symbol_toPrimitive, 0),\n    JS_PROP_ATOM_DEF(\"iterator\", JS_ATOM_Symbol_iterator, 0),\n    JS_PROP_ATOM_DEF(\"match\", JS_ATOM_Symbol_match, 0),\n    JS_PROP_ATOM_DEF(\"matchAll\", JS_ATOM_Symbol_matchAll, 0),\n    JS_PROP_ATOM_DEF(\"replace\", JS_ATOM_Symbol_replace, 0),\n    JS_PROP_ATOM_DEF(\"search\", JS_ATOM_Symbol_search, 0),\n    JS_PROP_ATOM_DEF(\"split\", JS_ATOM_Symbol_split, 0),\n    JS_PROP_ATOM_DEF(\"toStringTag\", JS_ATOM_Symbol_toStringTag, 0),\n    JS_PROP_ATOM_DEF(\"isConcatSpreadable\", JS_ATOM_Symbol_isConcatSpreadable, 0),\n    JS_PROP_ATOM_DEF(\"hasInstance\", JS_ATOM_Symbol_hasInstance, 0),\n    JS_PROP_ATOM_DEF(\"species\", JS_ATOM_Symbol_species, 0),\n    JS_PROP_ATOM_DEF(\"unscopables\", JS_ATOM_Symbol_unscopables, 0),\n    JS_PROP_ATOM_DEF(\"asyncIterator\", JS_ATOM_Symbol_asyncIterator, 0),\n};\n\n/* Set/Map/WeakSet/WeakMap */\n\nstatic BOOL js_weakref_is_target(JSValueConst val)\n{\n    switch (JS_VALUE_GET_TAG(val)) {\n    case JS_TAG_OBJECT:\n        return TRUE;\n    case JS_TAG_SYMBOL:\n        {\n            JSAtomStruct *p = JS_VALUE_GET_PTR(val);\n            if (p->atom_type == JS_ATOM_TYPE_SYMBOL &&\n                p->hash != JS_ATOM_HASH_PRIVATE)\n                return TRUE;\n        }\n        break;\n    default:\n        break;\n    }\n    return FALSE;\n}\n\n/* JS_UNDEFINED is considered as a live weakref */\n/* XXX: add a specific JSWeakRef value type ? */\nstatic BOOL js_weakref_is_live(JSValueConst val)\n{\n    int *pref_count;\n    if (JS_IsUndefined(val))\n        return TRUE;\n    pref_count = JS_VALUE_GET_PTR(val);\n    return (*pref_count != 0);\n}\n\n/* 'val' can be JS_UNDEFINED */\nstatic void js_weakref_free(JSRuntime *rt, JSValue val)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(val);\n        assert(p->weakref_count >= 1);\n        p->weakref_count--;\n        /* 'mark' is tested to avoid freeing the object structure when\n           it is about to be freed in a cycle or in\n           free_zero_refcount() */\n        if (p->weakref_count == 0 && p->header.ref_count == 0 &&\n            p->header.mark == 0) {\n            js_free_rt(rt, p);\n        }\n    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {\n        JSString *p = JS_VALUE_GET_STRING(val);\n        assert(p->hash >= 1);\n        p->hash--;\n        if (p->hash == 0 && p->header.ref_count == 0) {\n            /* can remove the dummy structure */\n            js_free_rt(rt, p);\n        }\n    }\n}\n\n/* val must be an object, a symbol or undefined (see\n   js_weakref_is_target). */\nstatic JSValue js_weakref_new(JSContext *ctx, JSValueConst val)\n{\n    if (JS_VALUE_GET_TAG(val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(val);\n        p->weakref_count++;\n    } else if (JS_VALUE_GET_TAG(val) == JS_TAG_SYMBOL) {\n        JSString *p = JS_VALUE_GET_STRING(val);\n        /* XXX: could return an exception if too many references */\n        assert(p->hash < JS_ATOM_HASH_MASK - 2);\n        p->hash++;\n    } else {\n        assert(JS_IsUndefined(val));\n    }\n    return (JSValue)val;\n}\n\n#define MAGIC_SET (1 << 0)\n#define MAGIC_WEAK (1 << 1)\n\nstatic JSValue js_map_constructor(JSContext *ctx, JSValueConst new_target,\n                                  int argc, JSValueConst *argv, int magic)\n{\n    JSMapState *s;\n    JSValue obj, adder = JS_UNDEFINED, iter = JS_UNDEFINED, next_method = JS_UNDEFINED;\n    JSValueConst arr;\n    BOOL is_set, is_weak;\n\n    is_set = magic & MAGIC_SET;\n    is_weak = ((magic & MAGIC_WEAK) != 0);\n    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_MAP + magic);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s)\n        goto fail;\n    init_list_head(&s->records);\n    s->is_weak = is_weak;\n    if (is_weak) {\n        s->weakref_header.weakref_type = JS_WEAKREF_TYPE_MAP;\n        list_add_tail(&s->weakref_header.link, &ctx->rt->weakref_list);\n    }\n    JS_SetOpaque(obj, s);\n    s->hash_bits = 1;\n    s->hash_size = 1U << s->hash_bits;\n    s->hash_table = js_mallocz(ctx, sizeof(s->hash_table[0]) * s->hash_size);\n    if (!s->hash_table)\n        goto fail;\n    s->record_count_threshold = 4;\n\n    arr = JS_UNDEFINED;\n    if (argc > 0)\n        arr = argv[0];\n    if (!JS_IsUndefined(arr) && !JS_IsNull(arr)) {\n        JSValue item, ret;\n        BOOL done;\n\n        adder = JS_GetProperty(ctx, obj, is_set ? JS_ATOM_add : JS_ATOM_set);\n        if (JS_IsException(adder))\n            goto fail;\n        if (!JS_IsFunction(ctx, adder)) {\n            JS_ThrowTypeError(ctx, \"set/add is not a function\");\n            goto fail;\n        }\n\n        iter = JS_GetIterator(ctx, arr, FALSE);\n        if (JS_IsException(iter))\n            goto fail;\n        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);\n        if (JS_IsException(next_method))\n            goto fail;\n\n        for(;;) {\n            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);\n            if (JS_IsException(item))\n                goto fail;\n            if (done)\n                break;\n            if (is_set) {\n                ret = JS_Call(ctx, adder, obj, 1, (JSValueConst *)&item);\n                if (JS_IsException(ret)) {\n                    JS_FreeValue(ctx, item);\n                    goto fail_close;\n                }\n            } else {\n                JSValue key, value;\n                JSValueConst args[2];\n                key = JS_UNDEFINED;\n                value = JS_UNDEFINED;\n                if (!JS_IsObject(item)) {\n                    JS_ThrowTypeErrorNotAnObject(ctx);\n                    goto fail1;\n                }\n                key = JS_GetPropertyUint32(ctx, item, 0);\n                if (JS_IsException(key))\n                    goto fail1;\n                value = JS_GetPropertyUint32(ctx, item, 1);\n                if (JS_IsException(value))\n                    goto fail1;\n                args[0] = key;\n                args[1] = value;\n                ret = JS_Call(ctx, adder, obj, 2, args);\n                if (JS_IsException(ret)) {\n                fail1:\n                    JS_FreeValue(ctx, item);\n                    JS_FreeValue(ctx, key);\n                    JS_FreeValue(ctx, value);\n                    goto fail_close;\n                }\n                JS_FreeValue(ctx, key);\n                JS_FreeValue(ctx, value);\n            }\n            JS_FreeValue(ctx, ret);\n            JS_FreeValue(ctx, item);\n        }\n        JS_FreeValue(ctx, next_method);\n        JS_FreeValue(ctx, iter);\n        JS_FreeValue(ctx, adder);\n    }\n    return obj;\n fail_close:\n    /* close the iterator object, preserving pending exception */\n    JS_IteratorClose(ctx, iter, TRUE);\n fail:\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, adder);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\n/* XXX: could normalize strings to speed up comparison */\nstatic JSValue map_normalize_key(JSContext *ctx, JSValue key)\n{\n    uint32_t tag = JS_VALUE_GET_TAG(key);\n    /* convert -0.0 to +0.0 */\n    if (JS_TAG_IS_FLOAT64(tag) && JS_VALUE_GET_FLOAT64(key) == 0.0) {\n        key = JS_NewInt32(ctx, 0);\n    }\n    return key;\n}\n\nstatic JSValueConst map_normalize_key_const(JSContext *ctx, JSValueConst key)\n{\n    return (JSValueConst)map_normalize_key(ctx, (JSValue)key);\n}\n\n/* hash multipliers, same as the Linux kernel (see Knuth vol 3,\n   section 6.4, exercise 9) */\n#define HASH_MUL32 0x61C88647\n#define HASH_MUL64 UINT64_C(0x61C8864680B583EB)\n\nstatic uint32_t map_hash32(uint32_t a, int hash_bits)\n{\n    return (a * HASH_MUL32) >> (32 - hash_bits);\n}\n\nstatic uint32_t map_hash64(uint64_t a, int hash_bits)\n{\n    return (a * HASH_MUL64) >> (64 - hash_bits);\n}\n\nstatic uint32_t map_hash_pointer(uintptr_t a, int hash_bits)\n{\n#ifdef JS_PTR64\n    return map_hash64(a, hash_bits);\n#else\n    return map_hash32(a, hash_bits);\n#endif\n}\n\n/* XXX: better hash ? */\n/* precondition: 1 <= hash_bits <= 32 */\nstatic uint32_t map_hash_key(JSValueConst key, int hash_bits)\n{\n    uint32_t tag = JS_VALUE_GET_NORM_TAG(key);\n    uint32_t h;\n    double d;\n    JSBigInt *p;\n    JSBigIntBuf buf;\n    \n    switch(tag) {\n    case JS_TAG_BOOL:\n        h = map_hash32(JS_VALUE_GET_INT(key) ^ JS_TAG_BOOL, hash_bits);\n        break;\n    case JS_TAG_STRING:\n        h = map_hash32(hash_string(JS_VALUE_GET_STRING(key), 0) ^ JS_TAG_STRING, hash_bits);\n        break;\n    case JS_TAG_STRING_ROPE:\n        h = map_hash32(hash_string_rope(key, 0) ^ JS_TAG_STRING, hash_bits);\n        break;\n    case JS_TAG_OBJECT:\n    case JS_TAG_SYMBOL:\n        h = map_hash_pointer((uintptr_t)JS_VALUE_GET_PTR(key) ^ tag, hash_bits);\n        break;\n    case JS_TAG_INT:\n        d = JS_VALUE_GET_INT(key);\n        goto hash_float64;\n    case JS_TAG_FLOAT64:\n        d = JS_VALUE_GET_FLOAT64(key);\n        /* normalize the NaN */\n        if (isnan(d))\n            d = JS_FLOAT64_NAN;\n    hash_float64:\n        h = map_hash64(float64_as_uint64(d) ^ JS_TAG_FLOAT64, hash_bits);\n        break;\n    case JS_TAG_SHORT_BIG_INT:\n        p = js_bigint_set_short(&buf, key);\n        goto hash_bigint;\n    case JS_TAG_BIG_INT:\n        p = JS_VALUE_GET_PTR(key);\n    hash_bigint:\n        {\n            int i;\n            h = 1;\n            for(i = p->len - 1; i >= 0; i--) {\n                h = h * 263 + p->tab[i];\n            }\n            /* the final step is necessary otherwise h mod n only\n               depends of p->tab[i] mod n */\n            h = map_hash32(h ^ JS_TAG_BIG_INT, hash_bits);\n        }\n        break;\n    default:\n        h = 0;\n        break;\n    }\n    return h;\n}\n\nstatic JSMapRecord *map_find_record(JSContext *ctx, JSMapState *s,\n                                    JSValueConst key)\n{\n    JSMapRecord *mr;\n    uint32_t h;\n    h = map_hash_key(key, s->hash_bits);\n    for(mr = s->hash_table[h]; mr != NULL; mr = mr->hash_next) {\n        if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {\n            /* cannot match */\n        } else {\n            if (js_same_value_zero(ctx, mr->key, key))\n                return mr;\n        }\n    }\n    return NULL;\n}\n\nstatic void map_hash_resize(JSContext *ctx, JSMapState *s)\n{\n    uint32_t new_hash_size, h;\n    int new_hash_bits;\n    struct list_head *el;\n    JSMapRecord *mr, **new_hash_table;\n\n    /* XXX: no reporting of memory allocation failure */\n    new_hash_bits = min_int(s->hash_bits + 1, 31);\n    new_hash_size = 1U << new_hash_bits;\n    new_hash_table = js_realloc(ctx, s->hash_table,\n                                sizeof(new_hash_table[0]) * new_hash_size);\n    if (!new_hash_table)\n        return;\n\n    memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);\n\n    list_for_each(el, &s->records) {\n        mr = list_entry(el, JSMapRecord, link);\n        if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {\n        } else {\n            h = map_hash_key(mr->key, new_hash_bits);\n            mr->hash_next = new_hash_table[h];\n            new_hash_table[h] = mr;\n        }\n    }\n    s->hash_table = new_hash_table;\n    s->hash_bits = new_hash_bits;\n    s->hash_size = new_hash_size;\n    s->record_count_threshold = new_hash_size * 2;\n}\n\nstatic JSMapRecord *map_add_record(JSContext *ctx, JSMapState *s,\n                                   JSValueConst key)\n{\n    uint32_t h;\n    JSMapRecord *mr;\n\n    mr = js_malloc(ctx, sizeof(*mr));\n    if (!mr)\n        return NULL;\n    mr->ref_count = 1;\n    mr->empty = FALSE;\n    if (s->is_weak) {\n        mr->key = js_weakref_new(ctx, key);\n    } else {\n        mr->key = JS_DupValue(ctx, key);\n    }\n    h = map_hash_key(key, s->hash_bits);\n    mr->hash_next = s->hash_table[h];\n    s->hash_table[h] = mr;\n    list_add_tail(&mr->link, &s->records);\n    s->record_count++;\n    if (s->record_count >= s->record_count_threshold) {\n        map_hash_resize(ctx, s);\n    }\n    return mr;\n}\n\nstatic JSMapRecord *set_add_record(JSContext *ctx, JSMapState *s,\n                                   JSValueConst key)\n{\n    JSMapRecord *mr;\n    mr = map_add_record(ctx, s, key);\n    if (!mr)\n        return NULL;\n    mr->value = JS_UNDEFINED;\n    return mr;\n}\n\n/* warning: the record must be removed from the hash table before */\nstatic void map_delete_record_internal(JSRuntime *rt, JSMapState *s, JSMapRecord *mr)\n{\n    if (mr->empty)\n        return;\n    \n    if (s->is_weak) {\n        js_weakref_free(rt, mr->key);\n    } else {\n        JS_FreeValueRT(rt, mr->key);\n    }\n    JS_FreeValueRT(rt, mr->value);\n    if (--mr->ref_count == 0) {\n        list_del(&mr->link);\n        js_free_rt(rt, mr);\n    } else {\n        /* keep a zombie record for iterators */\n        mr->empty = TRUE;\n        mr->key = JS_UNDEFINED;\n        mr->value = JS_UNDEFINED;\n    }\n    s->record_count--;\n}\n\nstatic void map_decref_record(JSRuntime *rt, JSMapRecord *mr)\n{\n    if (--mr->ref_count == 0) {\n        /* the record can be safely removed */\n        assert(mr->empty);\n        list_del(&mr->link);\n        js_free_rt(rt, mr);\n    }\n}\n\nstatic void map_delete_weakrefs(JSRuntime *rt, JSWeakRefHeader *wh)\n{\n    JSMapState *s = container_of(wh, JSMapState, weakref_header);\n    struct list_head *el, *el1;\n    JSMapRecord *mr1, **pmr;\n    uint32_t h;\n\n    list_for_each_safe(el, el1, &s->records) {\n        JSMapRecord *mr = list_entry(el, JSMapRecord, link);\n        if (!js_weakref_is_live(mr->key)) {\n\n            /* even if key is not live it can be hashed as a pointer */\n            h = map_hash_key(mr->key, s->hash_bits);\n            pmr = &s->hash_table[h];\n            for(;;) {\n                mr1 = *pmr;\n                /* the entry may already be removed from the hash\n                   table if the map was resized */\n                if (mr1 == NULL)\n                    goto done; \n                if (mr1 == mr)\n                    break;\n                pmr = &mr1->hash_next;\n            }\n            /* remove from the hash table */\n            *pmr = mr1->hash_next;\n        done:\n            map_delete_record_internal(rt, s, mr);\n        }\n    }\n}\n\nstatic JSValue js_map_set(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv, int magic)\n{\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    JSMapRecord *mr;\n    JSValueConst key, value;\n\n    if (!s)\n        return JS_EXCEPTION;\n    key = map_normalize_key_const(ctx, argv[0]);\n    if (s->is_weak && !js_weakref_is_target(key))\n        return JS_ThrowTypeError(ctx, \"invalid value used as %s key\", (magic & MAGIC_SET) ? \"WeakSet\" : \"WeakMap\");\n    if (magic & MAGIC_SET)\n        value = JS_UNDEFINED;\n    else\n        value = argv[1];\n    mr = map_find_record(ctx, s, key);\n    if (mr) {\n        JS_FreeValue(ctx, mr->value);\n    } else {\n        mr = map_add_record(ctx, s, key);\n        if (!mr)\n            return JS_EXCEPTION;\n    }\n    mr->value = JS_DupValue(ctx, value);\n    return JS_DupValue(ctx, this_val);\n}\n\nstatic JSValue js_map_get(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv, int magic)\n{\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    JSMapRecord *mr;\n    JSValueConst key;\n\n    if (!s)\n        return JS_EXCEPTION;\n    key = map_normalize_key_const(ctx, argv[0]);\n    mr = map_find_record(ctx, s, key);\n    if (!mr)\n        return JS_UNDEFINED;\n    else\n        return JS_DupValue(ctx, mr->value);\n}\n\n/* return JS_TRUE or JS_FALSE */\nstatic JSValue map_delete_record(JSContext *ctx, JSMapState *s, JSValueConst key)\n{\n    JSMapRecord *mr, **pmr;\n    uint32_t h;\n\n    key = map_normalize_key_const(ctx, key);\n    \n    h = map_hash_key(key, s->hash_bits);\n    pmr = &s->hash_table[h];\n    for(;;) {\n        mr = *pmr;\n        if (mr == NULL)\n            return JS_FALSE;\n        if (mr->empty || (s->is_weak && !js_weakref_is_live(mr->key))) {\n            /* not valid */\n        } else {\n            if (js_same_value_zero(ctx, mr->key, key))\n                break;\n        }\n        pmr = &mr->hash_next;\n    }\n\n    /* remove from the hash table */\n    *pmr = mr->hash_next;\n    \n    map_delete_record_internal(ctx->rt, s, mr);\n    return JS_TRUE;\n}\n\nstatic JSValue js_map_getOrInsert(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv, int magic)\n{\n    BOOL computed = magic & 1;\n    JSClassID class_id = magic >> 1;\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, class_id);\n    JSMapRecord *mr;\n    JSValueConst key;\n    JSValue value;\n\n    if (!s)\n        return JS_EXCEPTION;\n    if (computed && !JS_IsFunction(ctx, argv[1]))\n        return JS_ThrowTypeError(ctx, \"not a function\");\n    key = map_normalize_key_const(ctx, argv[0]);\n    if (s->is_weak && !js_weakref_is_target(key))\n        return JS_ThrowTypeError(ctx, \"invalid value used as WeakMap key\");\n    mr = map_find_record(ctx, s, key);\n    if (!mr) {\n        if (computed) {\n            value = JS_Call(ctx, argv[1], JS_UNDEFINED, 1, &key);\n            if (JS_IsException(value))\n                return JS_EXCEPTION;\n            map_delete_record(ctx, s, key);\n        } else {\n            value = JS_DupValue(ctx, argv[1]);\n        }\n        mr = map_add_record(ctx, s, key);\n        if (!mr) {\n            JS_FreeValue(ctx, value);\n            return JS_EXCEPTION;\n        }\n        mr->value = value;\n    }\n    return JS_DupValue(ctx, mr->value);\n}\n\nstatic JSValue js_map_has(JSContext *ctx, JSValueConst this_val,\n                          int argc, JSValueConst *argv, int magic)\n{\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    JSMapRecord *mr;\n    JSValueConst key;\n\n    if (!s)\n        return JS_EXCEPTION;\n    key = map_normalize_key_const(ctx, argv[0]);\n    mr = map_find_record(ctx, s, key);\n    return JS_NewBool(ctx, mr != NULL);\n}\n\nstatic JSValue js_map_delete(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv, int magic)\n{\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    if (!s)\n        return JS_EXCEPTION;\n    return map_delete_record(ctx, s, argv[0]);\n}\n\nstatic JSValue js_map_clear(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv, int magic)\n{\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    struct list_head *el, *el1;\n    JSMapRecord *mr;\n\n    if (!s)\n        return JS_EXCEPTION;\n\n    /* remove from the hash table */\n    memset(s->hash_table, 0, sizeof(s->hash_table[0]) * s->hash_size);\n    \n    list_for_each_safe(el, el1, &s->records) {\n        mr = list_entry(el, JSMapRecord, link);\n        map_delete_record_internal(ctx->rt, s, mr);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_map_get_size(JSContext *ctx, JSValueConst this_val, int magic)\n{\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    if (!s)\n        return JS_EXCEPTION;\n    return JS_NewUint32(ctx, s->record_count);\n}\n\nstatic JSValue js_map_forEach(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int magic)\n{\n    JSMapState *s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    JSValueConst func, this_arg;\n    JSValue ret, args[3];\n    struct list_head *el;\n    JSMapRecord *mr;\n\n    if (!s)\n        return JS_EXCEPTION;\n    func = argv[0];\n    if (argc > 1)\n        this_arg = argv[1];\n    else\n        this_arg = JS_UNDEFINED;\n    if (check_function(ctx, func))\n        return JS_EXCEPTION;\n    /* Note: the list can be modified while traversing it, but the\n       current element is locked */\n    el = s->records.next;\n    while (el != &s->records) {\n        mr = list_entry(el, JSMapRecord, link);\n        if (!mr->empty) {\n            mr->ref_count++;\n            /* must duplicate in case the record is deleted */\n            args[1] = JS_DupValue(ctx, mr->key);\n            if (magic)\n                args[0] = args[1];\n            else\n                args[0] = JS_DupValue(ctx, mr->value);\n            args[2] = (JSValue)this_val;\n            ret = JS_Call(ctx, func, this_arg, 3, (JSValueConst *)args);\n            JS_FreeValue(ctx, args[0]);\n            if (!magic)\n                JS_FreeValue(ctx, args[1]);\n            el = el->next;\n            map_decref_record(ctx->rt, mr);\n            if (JS_IsException(ret))\n                return ret;\n            JS_FreeValue(ctx, ret);\n        } else {\n            el = el->next;\n        }\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_object_groupBy(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv, int is_map)\n{\n    JSValueConst cb, args[2];\n    JSValue res, iter, next, groups, key, v, prop;\n    JSAtom key_atom = JS_ATOM_NULL;\n    int64_t idx;\n    BOOL done;\n\n    // \"is function?\" check must be observed before argv[0] is accessed\n    cb = argv[1];\n    if (check_function(ctx, cb))\n        return JS_EXCEPTION;\n\n    iter = JS_GetIterator(ctx, argv[0], /*is_async*/FALSE);\n    if (JS_IsException(iter))\n        return JS_EXCEPTION;\n\n    key = JS_UNDEFINED;\n    key_atom = JS_ATOM_NULL;\n    v = JS_UNDEFINED;\n    prop = JS_UNDEFINED;\n    groups = JS_UNDEFINED;\n\n    next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next))\n        goto exception;\n\n    if (is_map) {\n        groups = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, 0);\n    } else {\n        groups = JS_NewObjectProto(ctx, JS_NULL);\n    }\n    if (JS_IsException(groups))\n        goto exception;\n\n    for (idx = 0; ; idx++) {\n        if (idx >= MAX_SAFE_INTEGER) {\n            JS_ThrowTypeError(ctx, \"too many elements\");\n            goto iterator_close_exception;\n        }\n        v = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n        if (JS_IsException(v))\n            goto exception;\n        if (done)\n            break; // v is JS_UNDEFINED\n\n        args[0] = v;\n        args[1] = JS_NewInt64(ctx, idx);\n        key = JS_Call(ctx, cb, ctx->global_obj, 2, args);\n        if (JS_IsException(key))\n            goto iterator_close_exception;\n\n        if (is_map) {\n            prop = js_map_get(ctx, groups, 1, (JSValueConst *)&key, 0);\n        } else {\n            key_atom = JS_ValueToAtom(ctx, key);\n            JS_FreeValue(ctx, key);\n            key = JS_UNDEFINED;\n            if (key_atom == JS_ATOM_NULL)\n                goto iterator_close_exception;\n            prop = JS_GetProperty(ctx, groups, key_atom);\n        }\n        if (JS_IsException(prop))\n            goto exception;\n\n        if (JS_IsUndefined(prop)) {\n            prop = JS_NewArray(ctx);\n            if (JS_IsException(prop))\n                goto exception;\n            if (is_map) {\n                args[0] = key;\n                args[1] = prop;\n                res = js_map_set(ctx, groups, 2, args, 0);\n                if (JS_IsException(res))\n                    goto exception;\n                JS_FreeValue(ctx, res);\n            } else {\n                prop = JS_DupValue(ctx, prop);\n                if (JS_DefinePropertyValue(ctx, groups, key_atom, prop,\n                                           JS_PROP_C_W_E) < 0) {\n                    goto exception;\n                }\n            }\n        }\n        res = js_array_push(ctx, prop, 1, (JSValueConst *)&v, /*unshift*/0);\n        if (JS_IsException(res))\n            goto exception;\n        // res is an int64\n\n        JS_FreeValue(ctx, prop);\n        JS_FreeValue(ctx, key);\n        JS_FreeAtom(ctx, key_atom);\n        JS_FreeValue(ctx, v);\n        prop = JS_UNDEFINED;\n        key = JS_UNDEFINED;\n        key_atom = JS_ATOM_NULL;\n        v = JS_UNDEFINED;\n    }\n\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return groups;\n\n iterator_close_exception:\n    JS_IteratorClose(ctx, iter, TRUE);\n exception:\n    JS_FreeAtom(ctx, key_atom);\n    JS_FreeValue(ctx, prop);\n    JS_FreeValue(ctx, key);\n    JS_FreeValue(ctx, v);\n    JS_FreeValue(ctx, groups);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return JS_EXCEPTION;\n}\n\nstatic void js_map_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p;\n    JSMapState *s;\n    struct list_head *el, *el1;\n    JSMapRecord *mr;\n\n    p = JS_VALUE_GET_OBJ(val);\n    s = p->u.map_state;\n    if (s) {\n        /* if the object is deleted we are sure that no iterator is\n           using it */\n        list_for_each_safe(el, el1, &s->records) {\n            mr = list_entry(el, JSMapRecord, link);\n            if (!mr->empty) {\n                if (s->is_weak)\n                    js_weakref_free(rt, mr->key);\n                else\n                    JS_FreeValueRT(rt, mr->key);\n                JS_FreeValueRT(rt, mr->value);\n            }\n            js_free_rt(rt, mr);\n        }\n        js_free_rt(rt, s->hash_table);\n        if (s->is_weak) {\n            list_del(&s->weakref_header.link);\n        }\n        js_free_rt(rt, s);\n    }\n}\n\nstatic void js_map_mark(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSMapState *s;\n    struct list_head *el;\n    JSMapRecord *mr;\n\n    s = p->u.map_state;\n    if (s) {\n        list_for_each(el, &s->records) {\n            mr = list_entry(el, JSMapRecord, link);\n            if (!s->is_weak)\n                JS_MarkValue(rt, mr->key, mark_func);\n            JS_MarkValue(rt, mr->value, mark_func);\n        }\n    }\n}\n\n/* Map Iterator */\n\ntypedef struct JSMapIteratorData {\n    JSValue obj;\n    JSIteratorKindEnum kind;\n    JSMapRecord *cur_record;\n} JSMapIteratorData;\n\nstatic void js_map_iterator_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p;\n    JSMapIteratorData *it;\n\n    p = JS_VALUE_GET_OBJ(val);\n    it = p->u.map_iterator_data;\n    if (it) {\n        /* During the GC sweep phase the Map finalizer may be\n           called before the Map iterator finalizer */\n        if (JS_IsLiveObject(rt, it->obj) && it->cur_record) {\n            map_decref_record(rt, it->cur_record);\n        }\n        JS_FreeValueRT(rt, it->obj);\n        js_free_rt(rt, it);\n    }\n}\n\nstatic void js_map_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                 JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSMapIteratorData *it;\n    it = p->u.map_iterator_data;\n    if (it) {\n        /* the record is already marked by the object */\n        JS_MarkValue(rt, it->obj, mark_func);\n    }\n}\n\nstatic JSValue js_create_map_iterator(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv, int magic)\n{\n    JSIteratorKindEnum kind;\n    JSMapState *s;\n    JSMapIteratorData *it;\n    JSValue enum_obj;\n\n    kind = magic >> 2;\n    magic &= 3;\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP + magic);\n    if (!s)\n        return JS_EXCEPTION;\n    enum_obj = JS_NewObjectClass(ctx, JS_CLASS_MAP_ITERATOR + magic);\n    if (JS_IsException(enum_obj))\n        goto fail;\n    it = js_malloc(ctx, sizeof(*it));\n    if (!it) {\n        JS_FreeValue(ctx, enum_obj);\n        goto fail;\n    }\n    it->obj = JS_DupValue(ctx, this_val);\n    it->kind = kind;\n    it->cur_record = NULL;\n    JS_SetOpaque(enum_obj, it);\n    return enum_obj;\n fail:\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_map_iterator_next(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv,\n                                    BOOL *pdone, int magic)\n{\n    JSMapIteratorData *it;\n    JSMapState *s;\n    JSMapRecord *mr;\n    struct list_head *el;\n\n    it = JS_GetOpaque2(ctx, this_val, JS_CLASS_MAP_ITERATOR + magic);\n    if (!it) {\n        *pdone = FALSE;\n        return JS_EXCEPTION;\n    }\n    if (JS_IsUndefined(it->obj))\n        goto done;\n    s = JS_GetOpaque(it->obj, JS_CLASS_MAP + magic);\n    assert(s != NULL);\n    if (!it->cur_record) {\n        el = s->records.next;\n    } else {\n        mr = it->cur_record;\n        el = mr->link.next;\n        map_decref_record(ctx->rt, mr); /* the record can be freed here */\n    }\n    for(;;) {\n        if (el == &s->records) {\n            /* no more record  */\n            it->cur_record = NULL;\n            JS_FreeValue(ctx, it->obj);\n            it->obj = JS_UNDEFINED;\n        done:\n            /* end of enumeration */\n            *pdone = TRUE;\n            return JS_UNDEFINED;\n        }\n        mr = list_entry(el, JSMapRecord, link);\n        if (!mr->empty)\n            break;\n        /* get the next record */\n        el = mr->link.next;\n    }\n\n    /* lock the record so that it won't be freed */\n    mr->ref_count++;\n    it->cur_record = mr;\n    *pdone = FALSE;\n\n    if (it->kind == JS_ITERATOR_KIND_KEY) {\n        return JS_DupValue(ctx, mr->key);\n    } else {\n        JSValueConst args[2];\n        args[0] = mr->key;\n        if (magic)\n            args[1] = mr->key;\n        else\n            args[1] = mr->value;\n        if (it->kind == JS_ITERATOR_KIND_VALUE) {\n            return JS_DupValue(ctx, args[1]);\n        } else {\n            return js_create_array(ctx, 2, args);\n        }\n    }\n}\n\nstatic int get_set_record(JSContext *ctx, JSValueConst obj,\n                          int64_t *psize, JSValue *phas, JSValue *pkeys)\n{\n    JSMapState *s;\n    int64_t size;\n    JSValue has = JS_UNDEFINED, keys = JS_UNDEFINED;\n    \n    s = JS_GetOpaque(obj, JS_CLASS_SET);\n    if (s) {\n        size = s->record_count;\n    } else {\n        JSValue v;\n        double d;\n\n        v = JS_GetProperty(ctx, obj, JS_ATOM_size);\n        if (JS_IsException(v))\n            goto exception;\n        if (JS_ToFloat64Free(ctx, &d, v) < 0)\n            goto exception;\n        if (isnan(d)) {\n            JS_ThrowTypeError(ctx, \".size is not a number\");\n            goto exception;\n        }\n        if (d < INT64_MIN)\n            size = INT64_MIN;\n        else if (d >= 0x1p63) /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */\n            size = INT64_MAX;\n        else\n            size = (int64_t)d;\n        if (size < 0) {\n            JS_ThrowRangeError(ctx, \".size must be positive\");\n            goto exception;\n        }\n    }\n\n    has = JS_GetProperty(ctx, obj, JS_ATOM_has);\n    if (JS_IsException(has))\n        goto exception;\n    if (JS_IsUndefined(has)) {\n        JS_ThrowTypeError(ctx, \".has is undefined\");\n        goto exception;\n    }\n    if (!JS_IsFunction(ctx, has)) {\n        JS_ThrowTypeError(ctx, \".has is not a function\");\n        goto exception;\n    }\n\n    keys = JS_GetProperty(ctx, obj, JS_ATOM_keys);\n    if (JS_IsException(keys))\n        goto exception;\n    if (JS_IsUndefined(keys)) {\n        JS_ThrowTypeError(ctx, \".keys is undefined\");\n        goto exception;\n    }\n    if (!JS_IsFunction(ctx, keys)) {\n        JS_ThrowTypeError(ctx, \".keys is not a function\");\n        goto exception;\n    }\n    *psize = size;\n    *phas = has;\n    *pkeys = keys;\n    return 0;\n\n exception:\n    JS_FreeValue(ctx, has);\n    JS_FreeValue(ctx, keys);\n    *psize = 0;\n    *phas = JS_UNDEFINED;\n    *pkeys = JS_UNDEFINED;\n    return -1;\n}\n\n/* copy 'this_val' in a new set without side effects */\nstatic JSValue js_copy_set(JSContext *ctx, JSValueConst this_val)\n{\n    JSValue newset;\n    JSMapState *s, *t;\n    struct list_head *el;\n    JSMapRecord *mr;\n   \n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n\n    newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);\n    if (JS_IsException(newset))\n        return JS_EXCEPTION;\n    t = JS_GetOpaque(newset, JS_CLASS_SET);\n\n    // can't clone this_val using js_map_constructor(),\n    // test262 mandates we don't call the .add method\n    list_for_each(el, &s->records) {\n        mr = list_entry(el, JSMapRecord, link);\n        if (mr->empty)\n            continue;\n        if (!set_add_record(ctx, t, mr->key))\n            goto exception;\n    }\n    return newset;\n exception:\n    JS_FreeValue(ctx, newset);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_set_isDisjointFrom(JSContext *ctx, JSValueConst this_val,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue item, iter, keys, has, next, rv, rval;\n    int done;\n    BOOL found;\n    JSMapState *s;\n    int64_t size;\n    int ok;\n\n    iter = JS_UNDEFINED;\n    next = JS_UNDEFINED;\n    rval = JS_EXCEPTION;\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n    if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)\n        goto exception;\n    if (s->record_count <= size) {\n        iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);\n        if (JS_IsException(iter))\n            goto exception;\n        found = FALSE;\n        do {\n            item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);\n            if (JS_IsException(item))\n                goto exception;\n            if (done) // item is JS_UNDEFINED\n                break;\n            rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);\n            JS_FreeValue(ctx, item);\n            ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION\n            if (ok < 0)\n                goto exception;\n            found = (ok > 0);\n        } while (!found);\n    } else {\n        iter = JS_Call(ctx, keys, argv[0], 0, NULL);\n        if (JS_IsException(iter))\n            goto exception;\n        next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n        if (JS_IsException(next))\n            goto exception;\n        found = FALSE;\n        for(;;) {\n            item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n            if (JS_IsException(item))\n                goto exception;\n            if (done) // item is JS_UNDEFINED\n                break;\n            item = map_normalize_key(ctx, item);\n            found = (NULL != map_find_record(ctx, s, item));\n            JS_FreeValue(ctx, item);\n            if (found) {\n                JS_IteratorClose(ctx, iter, FALSE);\n                break;\n            }\n        }\n    }\n    rval = !found ? JS_TRUE : JS_FALSE;\nexception:\n    JS_FreeValue(ctx, has);\n    JS_FreeValue(ctx, keys);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return rval;\n}\n\nstatic JSValue js_set_isSubsetOf(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue item, iter, keys, has, next, rv, rval;\n    BOOL found;\n    JSMapState *s;\n    int64_t size;\n    int done, ok;\n\n    iter = JS_UNDEFINED;\n    next = JS_UNDEFINED;\n    rval = JS_EXCEPTION;\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n    if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)\n        goto exception;\n    found = FALSE;\n    if (s->record_count > size)\n        goto fini;\n    iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);\n    if (JS_IsException(iter))\n        goto exception;\n    found = TRUE;\n    do {\n        item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);\n        if (JS_IsException(item))\n            goto exception;\n        if (done) // item is JS_UNDEFINED\n            break;\n        rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);\n        JS_FreeValue(ctx, item);\n        ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION\n        if (ok < 0)\n            goto exception;\n        found = (ok > 0);\n    } while (found);\nfini:\n    rval = found ? JS_TRUE : JS_FALSE;\nexception:\n    JS_FreeValue(ctx, has);\n    JS_FreeValue(ctx, keys);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return rval;\n}\n\nstatic JSValue js_set_isSupersetOf(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue item, iter, keys, has, next, rval;\n    int done;\n    BOOL found;\n    JSMapState *s;\n    int64_t size;\n\n    iter = JS_UNDEFINED;\n    next = JS_UNDEFINED;\n    rval = JS_EXCEPTION;\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n    if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)\n        goto exception;\n    found = FALSE;\n    if (s->record_count < size)\n        goto fini;\n    iter = JS_Call(ctx, keys, argv[0], 0, NULL);\n    if (JS_IsException(iter))\n        goto exception;\n    next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next))\n        goto exception;\n    found = TRUE;\n    for(;;) {\n        item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto exception;\n        if (done) // item is JS_UNDEFINED\n            break;\n        item = map_normalize_key(ctx, item);\n        found = (NULL != map_find_record(ctx, s, item));\n        JS_FreeValue(ctx, item);\n        if (!found) {\n            JS_IteratorClose(ctx, iter, FALSE);\n            break;\n        }\n    }\nfini:\n    rval = found ? JS_TRUE : JS_FALSE;\nexception:\n    JS_FreeValue(ctx, has);\n    JS_FreeValue(ctx, keys);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return rval;\n}\n\nstatic JSValue js_set_intersection(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue newset, item, iter, keys, has, next, rv;\n    JSMapState *s, *t;\n    JSMapRecord *mr;\n    int64_t size;\n    int done, ok;\n\n    iter = JS_UNDEFINED;\n    next = JS_UNDEFINED;\n    newset = JS_UNDEFINED;\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n    if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)\n        goto exception;\n    if (s->record_count > size) {\n        iter = JS_Call(ctx, keys, argv[0], 0, NULL);\n        if (JS_IsException(iter))\n            goto exception;\n        next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n        if (JS_IsException(next))\n            goto exception;\n        newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);\n        if (JS_IsException(newset))\n            goto exception;\n        t = JS_GetOpaque(newset, JS_CLASS_SET);\n        for (;;) {\n            item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n            if (JS_IsException(item))\n                goto exception;\n            if (done) // item is JS_UNDEFINED\n                break;\n            item = map_normalize_key(ctx, item);\n            if (!map_find_record(ctx, s, item)) {\n                JS_FreeValue(ctx, item);\n            } else if (map_find_record(ctx, t, item)) {\n                JS_FreeValue(ctx, item); // no duplicates\n            } else {\n                mr = set_add_record(ctx, t, item);\n                JS_FreeValue(ctx, item);\n                if (!mr)\n                    goto exception;\n            }\n        }\n    } else {\n        iter = js_create_map_iterator(ctx, this_val, 0, NULL, MAGIC_SET);\n        if (JS_IsException(iter))\n            goto exception;\n        newset = js_map_constructor(ctx, JS_UNDEFINED, 0, NULL, MAGIC_SET);\n        if (JS_IsException(newset))\n            goto exception;\n        t = JS_GetOpaque(newset, JS_CLASS_SET);\n        for (;;) {\n            item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);\n            if (JS_IsException(item))\n                goto exception;\n            if (done) // item is JS_UNDEFINED\n                break;\n            rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);\n            ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION\n            if (ok > 0) {\n                item = map_normalize_key(ctx, item);\n                if (map_find_record(ctx, t, item)) {\n                    JS_FreeValue(ctx, item); // no duplicates\n                } else {\n                    mr = set_add_record(ctx, t, item);\n                    JS_FreeValue(ctx, item);\n                    if (!mr)\n                        goto exception;\n                }\n            } else {\n                JS_FreeValue(ctx, item);\n                if (ok < 0)\n                    goto exception;\n            }\n        }\n    }\n    goto fini;\nexception:\n    JS_FreeValue(ctx, newset);\n    newset = JS_EXCEPTION;\nfini:\n    JS_FreeValue(ctx, has);\n    JS_FreeValue(ctx, keys);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return newset;\n}\n\nstatic JSValue js_set_difference(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue newset, item, iter, keys, has, next, rv;\n    JSMapState *s, *t;\n    int64_t size;\n    int done;\n    int ok;\n\n    iter = JS_UNDEFINED;\n    next = JS_UNDEFINED;\n    newset = JS_UNDEFINED;\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n    if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)\n        goto exception;\n\n    newset = js_copy_set(ctx, this_val);\n    if (JS_IsException(newset))\n        goto exception;\n    t = JS_GetOpaque(newset, JS_CLASS_SET);\n    \n    if (s->record_count <= size) {\n        iter = js_create_map_iterator(ctx, newset, 0, NULL, MAGIC_SET);\n        if (JS_IsException(iter))\n            goto exception;\n        for (;;) {\n            item = js_map_iterator_next(ctx, iter, 0, NULL, &done, MAGIC_SET);\n            if (JS_IsException(item))\n                goto exception;\n            if (done) // item is JS_UNDEFINED\n                break;\n            rv = JS_Call(ctx, has, argv[0], 1, (JSValueConst *)&item);\n            ok = JS_ToBoolFree(ctx, rv); // returns -1 if rv is JS_EXCEPTION\n            if (ok < 0) {\n                JS_FreeValue(ctx, item);\n                goto exception;\n            }\n            if (ok) {\n                map_delete_record(ctx, t, item);\n            }\n            JS_FreeValue(ctx, item);\n        }\n    } else {\n        iter = JS_Call(ctx, keys, argv[0], 0, NULL);\n        if (JS_IsException(iter))\n            goto exception;\n        next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n        if (JS_IsException(next))\n            goto exception;\n        for (;;) {\n            item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n            if (JS_IsException(item))\n                goto exception;\n            if (done) // item is JS_UNDEFINED\n                break;\n            map_delete_record(ctx, t, item);\n            JS_FreeValue(ctx, item);\n        }\n    }\n    goto fini;\nexception:\n    JS_FreeValue(ctx, newset);\n    newset = JS_EXCEPTION;\nfini:\n    JS_FreeValue(ctx, has);\n    JS_FreeValue(ctx, keys);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, next);\n    return newset;\n}\n\nstatic JSValue js_set_symmetricDifference(JSContext *ctx, JSValueConst this_val,\n                                          int argc, JSValueConst *argv)\n{\n    JSValue newset, item, iter, next, has, keys;\n    JSMapState *s, *t;\n    JSMapRecord *mr;\n    int64_t size;\n    int done;\n    BOOL present;\n\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n    if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)\n        return JS_EXCEPTION;\n    JS_FreeValue(ctx, has);\n\n    next = JS_UNDEFINED;\n    newset = JS_UNDEFINED;\n    iter = JS_Call(ctx, keys, argv[0], 0, NULL);\n    if (JS_IsException(iter))\n        goto exception;\n    next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next))\n        goto exception;\n    newset = js_copy_set(ctx, this_val);\n    if (JS_IsException(newset))\n        goto exception;\n    t = JS_GetOpaque(newset, JS_CLASS_SET);\n    for (;;) {\n        item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto exception;\n        if (done) // item is JS_UNDEFINED\n            break;\n        // note the subtlety here: due to mutating iterators, it's\n        // possible for keys to disappear during iteration; test262\n        // still expects us to maintain insertion order though, so\n        // we first check |this|, then |new|; |new| is a copy of |this|\n        // - if item exists in |this|, delete (if it exists) from |new|\n        // - if item misses in |this| and |new|, add to |new|\n        // - if item exists in |new| but misses in |this|, *don't* add it,\n        //   mutating iterator erased it\n        item = map_normalize_key(ctx, item);\n        present = (NULL != map_find_record(ctx, s, item));\n        mr = map_find_record(ctx, t, item);\n        if (present) {\n            map_delete_record(ctx, t, item);\n            JS_FreeValue(ctx, item);\n        } else if (mr) {\n            JS_FreeValue(ctx, item);\n        } else {\n            mr = set_add_record(ctx, t, item);\n            JS_FreeValue(ctx, item);\n            if (!mr)\n                goto exception;\n        }\n    }\n    goto fini;\nexception:\n    JS_FreeValue(ctx, newset);\n    newset = JS_EXCEPTION;\nfini:\n    JS_FreeValue(ctx, next);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, keys);\n    return newset;\n}\n\nstatic JSValue js_set_union(JSContext *ctx, JSValueConst this_val,\n                            int argc, JSValueConst *argv)\n{\n    JSValue newset, item, iter, next, has, keys, rv;\n    JSMapState *s;\n    int64_t size;\n    int done;\n\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_SET);\n    if (!s)\n        return JS_EXCEPTION;\n    if (get_set_record(ctx, argv[0], &size, &has, &keys) < 0)\n        return JS_EXCEPTION;\n    JS_FreeValue(ctx, has);\n\n    next = JS_UNDEFINED;\n    newset = JS_UNDEFINED;\n    iter = JS_Call(ctx, keys, argv[0], 0, NULL);\n    if (JS_IsException(iter))\n        goto exception;\n    next = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next))\n        goto exception;\n\n    newset = js_copy_set(ctx, this_val);\n    if (JS_IsException(newset))\n        goto exception;\n\n    for (;;) {\n        item = JS_IteratorNext(ctx, iter, next, 0, NULL, &done);\n        if (JS_IsException(item))\n            goto exception;\n        if (done) // item is JS_UNDEFINED\n            break;\n        rv = js_map_set(ctx, newset, 1, (JSValueConst *)&item, MAGIC_SET);\n        JS_FreeValue(ctx, item);\n        if (JS_IsException(rv))\n            goto exception;\n        JS_FreeValue(ctx, rv);\n    }\n    goto fini;\nexception:\n    JS_FreeValue(ctx, newset);\n    newset = JS_EXCEPTION;\nfini:\n    JS_FreeValue(ctx, next);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, keys);\n    return newset;\n}\n\nstatic const JSCFunctionListEntry js_map_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"groupBy\", 2, js_object_groupBy, 1 ),\n    JS_CGETSET_DEF(\"[Symbol.species]\", js_get_this, NULL ),\n};\n\nstatic const JSCFunctionListEntry js_map_proto_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"set\", 2, js_map_set, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"get\", 1, js_map_get, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"getOrInsert\", 2, js_map_getOrInsert,\n                       (JS_CLASS_MAP << 1) | /*computed*/FALSE ),\n    JS_CFUNC_MAGIC_DEF(\"getOrInsertComputed\", 2, js_map_getOrInsert,\n                       (JS_CLASS_MAP << 1) | /*computed*/TRUE ),\n    JS_CFUNC_MAGIC_DEF(\"has\", 1, js_map_has, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"delete\", 1, js_map_delete, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"clear\", 0, js_map_clear, 0 ),\n    JS_CGETSET_MAGIC_DEF(\"size\", js_map_get_size, NULL, 0),\n    JS_CFUNC_MAGIC_DEF(\"forEach\", 1, js_map_forEach, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"values\", 0, js_create_map_iterator, (JS_ITERATOR_KIND_VALUE << 2) | 0 ),\n    JS_CFUNC_MAGIC_DEF(\"keys\", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | 0 ),\n    JS_CFUNC_MAGIC_DEF(\"entries\", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | 0 ),\n    JS_ALIAS_DEF(\"[Symbol.iterator]\", \"entries\" ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Map\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_map_iterator_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_map_iterator_next, 0 ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Map Iterator\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_set_proto_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"add\", 1, js_map_set, MAGIC_SET ),\n    JS_CFUNC_MAGIC_DEF(\"has\", 1, js_map_has, MAGIC_SET ),\n    JS_CFUNC_MAGIC_DEF(\"delete\", 1, js_map_delete, MAGIC_SET ),\n    JS_CFUNC_MAGIC_DEF(\"clear\", 0, js_map_clear, MAGIC_SET ),\n    JS_CGETSET_MAGIC_DEF(\"size\", js_map_get_size, NULL, MAGIC_SET ),\n    JS_CFUNC_MAGIC_DEF(\"forEach\", 1, js_map_forEach, MAGIC_SET ),\n    JS_CFUNC_DEF(\"isDisjointFrom\", 1, js_set_isDisjointFrom ),\n    JS_CFUNC_DEF(\"isSubsetOf\", 1, js_set_isSubsetOf ),\n    JS_CFUNC_DEF(\"isSupersetOf\", 1, js_set_isSupersetOf ),\n    JS_CFUNC_DEF(\"intersection\", 1, js_set_intersection ),\n    JS_CFUNC_DEF(\"difference\", 1, js_set_difference ),\n    JS_CFUNC_DEF(\"symmetricDifference\", 1, js_set_symmetricDifference ),\n    JS_CFUNC_DEF(\"union\", 1, js_set_union ),\n    JS_CFUNC_MAGIC_DEF(\"values\", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY << 2) | MAGIC_SET ),\n    JS_ALIAS_DEF(\"keys\", \"values\" ),\n    JS_ALIAS_DEF(\"[Symbol.iterator]\", \"values\" ),\n    JS_CFUNC_MAGIC_DEF(\"entries\", 0, js_create_map_iterator, (JS_ITERATOR_KIND_KEY_AND_VALUE << 2) | MAGIC_SET ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Set\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_set_iterator_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 0, js_map_iterator_next, MAGIC_SET ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Set Iterator\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_weak_map_proto_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"set\", 2, js_map_set, MAGIC_WEAK ),\n    JS_CFUNC_MAGIC_DEF(\"get\", 1, js_map_get, MAGIC_WEAK ),\n    JS_CFUNC_MAGIC_DEF(\"getOrInsert\", 2, js_map_getOrInsert,\n                       (JS_CLASS_WEAKMAP << 1) | /*computed*/FALSE ),\n    JS_CFUNC_MAGIC_DEF(\"getOrInsertComputed\", 2, js_map_getOrInsert,\n                       (JS_CLASS_WEAKMAP << 1) | /*computed*/TRUE ),\n    JS_CFUNC_MAGIC_DEF(\"has\", 1, js_map_has, MAGIC_WEAK ),\n    JS_CFUNC_MAGIC_DEF(\"delete\", 1, js_map_delete, MAGIC_WEAK ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"WeakMap\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_weak_set_proto_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"add\", 1, js_map_set, MAGIC_SET | MAGIC_WEAK ),\n    JS_CFUNC_MAGIC_DEF(\"has\", 1, js_map_has, MAGIC_SET | MAGIC_WEAK ),\n    JS_CFUNC_MAGIC_DEF(\"delete\", 1, js_map_delete, MAGIC_SET | MAGIC_WEAK ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"WeakSet\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry * const js_map_proto_funcs_ptr[6] = {\n    js_map_proto_funcs,\n    js_set_proto_funcs,\n    js_weak_map_proto_funcs,\n    js_weak_set_proto_funcs,\n    js_map_iterator_proto_funcs,\n    js_set_iterator_proto_funcs,\n};\n\nstatic const uint8_t js_map_proto_funcs_count[6] = {\n    countof(js_map_proto_funcs),\n    countof(js_set_proto_funcs),\n    countof(js_weak_map_proto_funcs),\n    countof(js_weak_set_proto_funcs),\n    countof(js_map_iterator_proto_funcs),\n    countof(js_set_iterator_proto_funcs),\n};\n\nint JS_AddIntrinsicMapSet(JSContext *ctx)\n{\n    int i;\n    JSValue obj1;\n    char buf[ATOM_GET_STR_BUF_SIZE];\n\n    for(i = 0; i < 4; i++) {\n        JSCFunctionType ft;\n        const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),\n                                         JS_ATOM_Map + i);\n        ft.constructor_magic = js_map_constructor;\n        obj1 = JS_NewCConstructor(ctx, JS_CLASS_MAP + i, name,\n                                  ft.generic, 0, JS_CFUNC_constructor_magic, i,\n                                  JS_UNDEFINED,\n                                  js_map_funcs, i < 2 ? countof(js_map_funcs) : 0,\n                                  js_map_proto_funcs_ptr[i], js_map_proto_funcs_count[i],\n                                  0);\n        if (JS_IsException(obj1))\n            return -1;\n        JS_FreeValue(ctx, obj1);\n    }\n\n    for(i = 0; i < 2; i++) {\n        ctx->class_proto[JS_CLASS_MAP_ITERATOR + i] =\n            JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], \n                                  js_map_proto_funcs_ptr[i + 4],\n                                  js_map_proto_funcs_count[i + 4]);\n        if (JS_IsException(ctx->class_proto[JS_CLASS_MAP_ITERATOR + i]))\n            return -1;\n    }\n    return 0;\n}\n\n/* Generator */\nstatic const JSCFunctionListEntry js_generator_function_proto_funcs[] = {\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"GeneratorFunction\", JS_PROP_CONFIGURABLE),\n};\n\nstatic const JSCFunctionListEntry js_generator_proto_funcs[] = {\n    JS_ITERATOR_NEXT_DEF(\"next\", 1, js_generator_next, GEN_MAGIC_NEXT ),\n    JS_ITERATOR_NEXT_DEF(\"return\", 1, js_generator_next, GEN_MAGIC_RETURN ),\n    JS_ITERATOR_NEXT_DEF(\"throw\", 1, js_generator_next, GEN_MAGIC_THROW ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Generator\", JS_PROP_CONFIGURABLE),\n};\n\n/* Promise */\n\ntypedef struct JSPromiseData {\n    JSPromiseStateEnum promise_state;\n    /* 0=fulfill, 1=reject, list of JSPromiseReactionData.link */\n    struct list_head promise_reactions[2];\n    BOOL is_handled; /* Note: only useful to debug */\n    JSValue promise_result;\n} JSPromiseData;\n\ntypedef struct JSPromiseFunctionDataResolved {\n    int ref_count;\n    BOOL already_resolved;\n} JSPromiseFunctionDataResolved;\n\ntypedef struct JSPromiseFunctionData {\n    JSValue promise;\n    JSPromiseFunctionDataResolved *presolved;\n} JSPromiseFunctionData;\n\ntypedef struct JSPromiseReactionData {\n    struct list_head link; /* not used in promise_reaction_job */\n    JSValue resolving_funcs[2];\n    JSValue handler;\n} JSPromiseReactionData;\n\nJSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise)\n{\n    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);\n    if (!s)\n        return -1;\n    return s->promise_state;\n}\n\nJSValue JS_PromiseResult(JSContext *ctx, JSValue promise)\n{\n    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);\n    if (!s)\n        return JS_UNDEFINED;\n    return JS_DupValue(ctx, s->promise_result);\n}\n\nstatic int js_create_resolving_functions(JSContext *ctx, JSValue *args,\n                                         JSValueConst promise);\n\nstatic void promise_reaction_data_free(JSRuntime *rt,\n                                       JSPromiseReactionData *rd)\n{\n    JS_FreeValueRT(rt, rd->resolving_funcs[0]);\n    JS_FreeValueRT(rt, rd->resolving_funcs[1]);\n    JS_FreeValueRT(rt, rd->handler);\n    js_free_rt(rt, rd);\n}\n\nstatic JSValue promise_reaction_job(JSContext *ctx, int argc,\n                                    JSValueConst *argv)\n{\n    JSValueConst handler, arg, func;\n    JSValue res, res2;\n    BOOL is_reject;\n\n    assert(argc == 5);\n    handler = argv[2];\n    is_reject = JS_ToBool(ctx, argv[3]);\n    arg = argv[4];\n#ifdef DUMP_PROMISE\n    printf(\"promise_reaction_job: is_reject=%d\\n\", is_reject);\n#endif\n\n    if (JS_IsUndefined(handler)) {\n        if (is_reject) {\n            res = JS_Throw(ctx, JS_DupValue(ctx, arg));\n        } else {\n            res = JS_DupValue(ctx, arg);\n        }\n    } else {\n        res = JS_Call(ctx, handler, JS_UNDEFINED, 1, &arg);\n    }\n    is_reject = JS_IsException(res);\n    if (is_reject)\n        res = JS_GetException(ctx);\n    func = argv[is_reject];\n    /* as an extension, we support undefined as value to avoid\n       creating a dummy promise in the 'await' implementation of async\n       functions */\n    if (!JS_IsUndefined(func)) {\n        res2 = JS_Call(ctx, func, JS_UNDEFINED,\n                       1, (JSValueConst *)&res);\n    } else {\n        res2 = JS_UNDEFINED;\n    }\n    JS_FreeValue(ctx, res);\n\n    return res2;\n}\n\nvoid JS_SetHostPromiseRejectionTracker(JSRuntime *rt,\n                                       JSHostPromiseRejectionTracker *cb,\n                                       void *opaque)\n{\n    rt->host_promise_rejection_tracker = cb;\n    rt->host_promise_rejection_tracker_opaque = opaque;\n}\n\nstatic void fulfill_or_reject_promise(JSContext *ctx, JSValueConst promise,\n                                      JSValueConst value, BOOL is_reject)\n{\n    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);\n    struct list_head *el, *el1;\n    JSPromiseReactionData *rd;\n    JSValueConst args[5];\n\n    if (!s || s->promise_state != JS_PROMISE_PENDING)\n        return; /* should never happen */\n    set_value(ctx, &s->promise_result, JS_DupValue(ctx, value));\n    s->promise_state = JS_PROMISE_FULFILLED + is_reject;\n#ifdef DUMP_PROMISE\n    printf(\"fulfill_or_reject_promise: is_reject=%d\\n\", is_reject);\n#endif\n    if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {\n        JSRuntime *rt = ctx->rt;\n        if (rt->host_promise_rejection_tracker) {\n            rt->host_promise_rejection_tracker(ctx, promise, value, FALSE,\n                                               rt->host_promise_rejection_tracker_opaque);\n        }\n    }\n\n    list_for_each_safe(el, el1, &s->promise_reactions[is_reject]) {\n        rd = list_entry(el, JSPromiseReactionData, link);\n        args[0] = rd->resolving_funcs[0];\n        args[1] = rd->resolving_funcs[1];\n        args[2] = rd->handler;\n        args[3] = JS_NewBool(ctx, is_reject);\n        args[4] = value;\n        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);\n        list_del(&rd->link);\n        promise_reaction_data_free(ctx->rt, rd);\n    }\n\n    list_for_each_safe(el, el1, &s->promise_reactions[1 - is_reject]) {\n        rd = list_entry(el, JSPromiseReactionData, link);\n        list_del(&rd->link);\n        promise_reaction_data_free(ctx->rt, rd);\n    }\n}\n\nstatic void reject_promise(JSContext *ctx, JSValueConst promise,\n                           JSValueConst value)\n{\n    fulfill_or_reject_promise(ctx, promise, value, TRUE);\n}\n\nstatic JSValue js_promise_resolve_thenable_job(JSContext *ctx,\n                                               int argc, JSValueConst *argv)\n{\n    JSValueConst promise, thenable, then;\n    JSValue args[2], res;\n\n#ifdef DUMP_PROMISE\n    printf(\"js_promise_resolve_thenable_job\\n\");\n#endif\n    assert(argc == 3);\n    promise = argv[0];\n    thenable = argv[1];\n    then = argv[2];\n    if (js_create_resolving_functions(ctx, args, promise) < 0)\n        return JS_EXCEPTION;\n    res = JS_Call(ctx, then, thenable, 2, (JSValueConst *)args);\n    if (JS_IsException(res)) {\n        JSValue error = JS_GetException(ctx);\n        res = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);\n        JS_FreeValue(ctx, error);\n    }\n    JS_FreeValue(ctx, args[0]);\n    JS_FreeValue(ctx, args[1]);\n    return res;\n}\n\nstatic void js_promise_resolve_function_free_resolved(JSRuntime *rt,\n                                                      JSPromiseFunctionDataResolved *sr)\n{\n    if (--sr->ref_count == 0) {\n        js_free_rt(rt, sr);\n    }\n}\n\nstatic int js_create_resolving_functions(JSContext *ctx,\n                                         JSValue *resolving_funcs,\n                                         JSValueConst promise)\n\n{\n    JSValue obj;\n    JSPromiseFunctionData *s;\n    JSPromiseFunctionDataResolved *sr;\n    int i, ret;\n\n    sr = js_malloc(ctx, sizeof(*sr));\n    if (!sr)\n        return -1;\n    sr->ref_count = 1;\n    sr->already_resolved = FALSE; /* must be shared between the two functions */\n    ret = 0;\n    for(i = 0; i < 2; i++) {\n        obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,\n                                     JS_CLASS_PROMISE_RESOLVE_FUNCTION + i);\n        if (JS_IsException(obj))\n            goto fail;\n        s = js_malloc(ctx, sizeof(*s));\n        if (!s) {\n            JS_FreeValue(ctx, obj);\n        fail:\n\n            if (i != 0)\n                JS_FreeValue(ctx, resolving_funcs[0]);\n            ret = -1;\n            break;\n        }\n        sr->ref_count++;\n        s->presolved = sr;\n        s->promise = JS_DupValue(ctx, promise);\n        JS_SetOpaque(obj, s);\n        js_function_set_properties(ctx, obj, JS_ATOM_empty_string, 1);\n        resolving_funcs[i] = obj;\n    }\n    js_promise_resolve_function_free_resolved(ctx->rt, sr);\n    return ret;\n}\n\nstatic void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;\n    if (s) {\n        js_promise_resolve_function_free_resolved(rt, s->presolved);\n        JS_FreeValueRT(rt, s->promise);\n        js_free_rt(rt, s);\n    }\n}\n\nstatic void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,\n                                             JS_MarkFunc *mark_func)\n{\n    JSPromiseFunctionData *s = JS_VALUE_GET_OBJ(val)->u.promise_function_data;\n    if (s) {\n        JS_MarkValue(rt, s->promise, mark_func);\n    }\n}\n\nstatic JSValue js_promise_resolve_function_call(JSContext *ctx,\n                                                JSValueConst func_obj,\n                                                JSValueConst this_val,\n                                                int argc, JSValueConst *argv,\n                                                int flags)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(func_obj);\n    JSPromiseFunctionData *s;\n    JSValueConst resolution, args[3];\n    JSValue then;\n    BOOL is_reject;\n\n    s = p->u.promise_function_data;\n    if (!s || s->presolved->already_resolved)\n        return JS_UNDEFINED;\n    s->presolved->already_resolved = TRUE;\n    is_reject = p->class_id - JS_CLASS_PROMISE_RESOLVE_FUNCTION;\n    if (argc > 0)\n        resolution = argv[0];\n    else\n        resolution = JS_UNDEFINED;\n#ifdef DUMP_PROMISE\n    printf(\"js_promise_resolving_function_call: is_reject=%d \", is_reject);\n    JS_DumpValue(ctx, \"resolution\", resolution);\n    printf(\"\\n\");\n#endif\n    if (is_reject || !JS_IsObject(resolution)) {\n        goto done;\n    } else if (js_same_value(ctx, resolution, s->promise)) {\n        JS_ThrowTypeError(ctx, \"promise self resolution\");\n        goto fail_reject;\n    }\n    then = JS_GetProperty(ctx, resolution, JS_ATOM_then);\n    if (JS_IsException(then)) {\n        JSValue error;\n    fail_reject:\n        error = JS_GetException(ctx);\n        reject_promise(ctx, s->promise, error);\n        JS_FreeValue(ctx, error);\n    } else if (!JS_IsFunction(ctx, then)) {\n        JS_FreeValue(ctx, then);\n    done:\n        fulfill_or_reject_promise(ctx, s->promise, resolution, is_reject);\n    } else {\n        args[0] = s->promise;\n        args[1] = resolution;\n        args[2] = then;\n        JS_EnqueueJob(ctx, js_promise_resolve_thenable_job, 3, args);\n        JS_FreeValue(ctx, then);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic void js_promise_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);\n    struct list_head *el, *el1;\n    int i;\n\n    if (!s)\n        return;\n    for(i = 0; i < 2; i++) {\n        list_for_each_safe(el, el1, &s->promise_reactions[i]) {\n            JSPromiseReactionData *rd =\n                list_entry(el, JSPromiseReactionData, link);\n            promise_reaction_data_free(rt, rd);\n        }\n    }\n    JS_FreeValueRT(rt, s->promise_result);\n    js_free_rt(rt, s);\n}\n\nstatic void js_promise_mark(JSRuntime *rt, JSValueConst val,\n                            JS_MarkFunc *mark_func)\n{\n    JSPromiseData *s = JS_GetOpaque(val, JS_CLASS_PROMISE);\n    struct list_head *el;\n    int i;\n\n    if (!s)\n        return;\n    for(i = 0; i < 2; i++) {\n        list_for_each(el, &s->promise_reactions[i]) {\n            JSPromiseReactionData *rd =\n                list_entry(el, JSPromiseReactionData, link);\n            JS_MarkValue(rt, rd->resolving_funcs[0], mark_func);\n            JS_MarkValue(rt, rd->resolving_funcs[1], mark_func);\n            JS_MarkValue(rt, rd->handler, mark_func);\n        }\n    }\n    JS_MarkValue(rt, s->promise_result, mark_func);\n}\n\nstatic JSValue js_promise_constructor(JSContext *ctx, JSValueConst new_target,\n                                      int argc, JSValueConst *argv)\n{\n    JSValueConst executor;\n    JSValue obj;\n    JSPromiseData *s;\n    JSValue args[2], ret;\n    int i;\n\n    executor = argv[0];\n    if (check_function(ctx, executor))\n        return JS_EXCEPTION;\n    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_PROMISE);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s)\n        goto fail;\n    s->promise_state = JS_PROMISE_PENDING;\n    s->is_handled = FALSE;\n    for(i = 0; i < 2; i++)\n        init_list_head(&s->promise_reactions[i]);\n    s->promise_result = JS_UNDEFINED;\n    JS_SetOpaque(obj, s);\n    if (js_create_resolving_functions(ctx, args, obj))\n        goto fail;\n    ret = JS_Call(ctx, executor, JS_UNDEFINED, 2, (JSValueConst *)args);\n    if (JS_IsException(ret)) {\n        JSValue ret2, error;\n        error = JS_GetException(ctx);\n        ret2 = JS_Call(ctx, args[1], JS_UNDEFINED, 1, (JSValueConst *)&error);\n        JS_FreeValue(ctx, error);\n        if (JS_IsException(ret2))\n            goto fail1;\n        JS_FreeValue(ctx, ret2);\n    }\n    JS_FreeValue(ctx, ret);\n    JS_FreeValue(ctx, args[0]);\n    JS_FreeValue(ctx, args[1]);\n    return obj;\n fail1:\n    JS_FreeValue(ctx, args[0]);\n    JS_FreeValue(ctx, args[1]);\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_promise_executor(JSContext *ctx,\n                                   JSValueConst this_val,\n                                   int argc, JSValueConst *argv,\n                                   int magic, JSValue *func_data)\n{\n    int i;\n\n    for(i = 0; i < 2; i++) {\n        if (!JS_IsUndefined(func_data[i]))\n            return JS_ThrowTypeError(ctx, \"resolving function already set\");\n        func_data[i] = JS_DupValue(ctx, argv[i]);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_promise_executor_new(JSContext *ctx)\n{\n    JSValueConst func_data[2];\n\n    func_data[0] = JS_UNDEFINED;\n    func_data[1] = JS_UNDEFINED;\n    return JS_NewCFunctionData(ctx, js_promise_executor, 2,\n                               0, 2, func_data);\n}\n\nstatic JSValue js_new_promise_capability(JSContext *ctx,\n                                         JSValue *resolving_funcs,\n                                         JSValueConst ctor)\n{\n    JSValue executor, result_promise;\n    JSCFunctionDataRecord *s;\n    int i;\n\n    executor = js_promise_executor_new(ctx);\n    if (JS_IsException(executor))\n        return executor;\n\n    if (JS_IsUndefined(ctor)) {\n        result_promise = js_promise_constructor(ctx, ctor, 1,\n                                                (JSValueConst *)&executor);\n    } else {\n        result_promise = JS_CallConstructor(ctx, ctor, 1,\n                                            (JSValueConst *)&executor);\n    }\n    if (JS_IsException(result_promise))\n        goto fail;\n    s = JS_GetOpaque(executor, JS_CLASS_C_FUNCTION_DATA);\n    for(i = 0; i < 2; i++) {\n        if (check_function(ctx, s->data[i]))\n            goto fail;\n    }\n    for(i = 0; i < 2; i++)\n        resolving_funcs[i] = JS_DupValue(ctx, s->data[i]);\n    JS_FreeValue(ctx, executor);\n    return result_promise;\n fail:\n    JS_FreeValue(ctx, executor);\n    JS_FreeValue(ctx, result_promise);\n    return JS_EXCEPTION;\n}\n\nJSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs)\n{\n    return js_new_promise_capability(ctx, resolving_funcs, JS_UNDEFINED);\n}\n\nstatic JSValue js_promise_resolve(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv, int magic)\n{\n    JSValue result_promise, resolving_funcs[2], ret;\n    BOOL is_reject = magic;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    if (!is_reject && JS_GetOpaque(argv[0], JS_CLASS_PROMISE)) {\n        JSValue ctor;\n        BOOL is_same;\n        ctor = JS_GetProperty(ctx, argv[0], JS_ATOM_constructor);\n        if (JS_IsException(ctor))\n            return ctor;\n        is_same = js_same_value(ctx, ctor, this_val);\n        JS_FreeValue(ctx, ctor);\n        if (is_same)\n            return JS_DupValue(ctx, argv[0]);\n    }\n    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);\n    if (JS_IsException(result_promise))\n        return result_promise;\n    ret = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, argv);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    if (JS_IsException(ret)) {\n        JS_FreeValue(ctx, result_promise);\n        return ret;\n    }\n    JS_FreeValue(ctx, ret);\n    return result_promise;\n}\n\nstatic JSValue js_promise_withResolvers(JSContext *ctx,\n                                        JSValueConst this_val,\n                                        int argc, JSValueConst *argv)\n{\n    JSValue result_promise, resolving_funcs[2], obj;\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);\n    if (JS_IsException(result_promise))\n        return result_promise;\n    obj = JS_NewObject(ctx);\n    if (JS_IsException(obj))\n        goto exception;\n    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_promise, result_promise,\n                               JS_PROP_C_W_E) < 0) {\n        goto exception;\n    }\n    result_promise = JS_UNDEFINED;\n    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_resolve, resolving_funcs[0],\n                               JS_PROP_C_W_E) < 0) {\n        goto exception;\n    }\n    resolving_funcs[0] = JS_UNDEFINED;\n    if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_reject, resolving_funcs[1],\n                               JS_PROP_C_W_E) < 0) {\n        goto exception;\n    }\n    return obj;\nexception:\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    JS_FreeValue(ctx, result_promise);\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_promise_try(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    JSValue result_promise, resolving_funcs[2], ret, ret2;\n    BOOL is_reject = 0;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);\n    if (JS_IsException(result_promise))\n        return result_promise;\n    ret = JS_Call(ctx, argv[0], JS_UNDEFINED, argc - 1, argv + 1);\n    if (JS_IsException(ret)) {\n        is_reject = 1;\n        ret = JS_GetException(ctx);\n    }\n    ret2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED, 1, (JSValueConst *)&ret);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    JS_FreeValue(ctx, ret);\n    if (JS_IsException(ret2)) {\n        JS_FreeValue(ctx, result_promise);\n        return ret2;\n    }\n    JS_FreeValue(ctx, ret2);\n    return result_promise;\n}\n\nstatic __exception int remainingElementsCount_add(JSContext *ctx,\n                                                  JSValueConst resolve_element_env,\n                                                  int addend)\n{\n    JSValue val;\n    int remainingElementsCount;\n\n    val = JS_GetPropertyUint32(ctx, resolve_element_env, 0);\n    if (JS_IsException(val))\n        return -1;\n    if (JS_ToInt32Free(ctx, &remainingElementsCount, val))\n        return -1;\n    remainingElementsCount += addend;\n    if (JS_SetPropertyUint32(ctx, resolve_element_env, 0,\n                             JS_NewInt32(ctx, remainingElementsCount)) < 0)\n        return -1;\n    return (remainingElementsCount == 0);\n}\n\n#define PROMISE_MAGIC_all        0\n#define PROMISE_MAGIC_allSettled 1\n#define PROMISE_MAGIC_any        2\n\nstatic JSValue js_promise_all_resolve_element(JSContext *ctx,\n                                              JSValueConst this_val,\n                                              int argc, JSValueConst *argv,\n                                              int magic,\n                                              JSValue *func_data)\n{\n    int resolve_type = magic & 3;\n    int is_reject = magic & 4;\n    BOOL alreadyCalled = JS_ToBool(ctx, func_data[0]);\n    JSValueConst values = func_data[2];\n    JSValueConst resolve = func_data[3];\n    JSValueConst resolve_element_env = func_data[4];\n    JSValue ret, obj;\n    int is_zero, index;\n\n    if (JS_ToInt32(ctx, &index, func_data[1]))\n        return JS_EXCEPTION;\n    if (alreadyCalled)\n        return JS_UNDEFINED;\n    func_data[0] = JS_NewBool(ctx, TRUE);\n\n    if (resolve_type == PROMISE_MAGIC_allSettled) {\n        JSValue str;\n\n        obj = JS_NewObject(ctx);\n        if (JS_IsException(obj))\n            return JS_EXCEPTION;\n        str = js_new_string8(ctx, is_reject ? \"rejected\" : \"fulfilled\");\n        if (JS_IsException(str))\n            goto fail1;\n        if (JS_DefinePropertyValue(ctx, obj, JS_ATOM_status,\n                                   str,\n                                   JS_PROP_C_W_E) < 0)\n            goto fail1;\n        if (JS_DefinePropertyValue(ctx, obj,\n                                   is_reject ? JS_ATOM_reason : JS_ATOM_value,\n                                   JS_DupValue(ctx, argv[0]),\n                                   JS_PROP_C_W_E) < 0) {\n        fail1:\n            JS_FreeValue(ctx, obj);\n            return JS_EXCEPTION;\n        }\n    } else {\n        obj = JS_DupValue(ctx, argv[0]);\n    }\n    if (JS_DefinePropertyValueUint32(ctx, values, index,\n                                     obj, JS_PROP_C_W_E) < 0)\n        return JS_EXCEPTION;\n\n    is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);\n    if (is_zero < 0)\n        return JS_EXCEPTION;\n    if (is_zero) {\n        if (resolve_type == PROMISE_MAGIC_any) {\n            JSValue error;\n            error = js_aggregate_error_constructor(ctx, values);\n            if (JS_IsException(error))\n                return JS_EXCEPTION;\n            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&error);\n            JS_FreeValue(ctx, error);\n        } else {\n            ret = JS_Call(ctx, resolve, JS_UNDEFINED, 1, (JSValueConst *)&values);\n        }\n        if (JS_IsException(ret))\n            return ret;\n        JS_FreeValue(ctx, ret);\n    }\n    return JS_UNDEFINED;\n}\n\n/* magic = 0: Promise.all 1: Promise.allSettled */\nstatic JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int magic)\n{\n    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;\n    JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;\n    JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;\n    JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;\n    JSValueConst then_args[2], resolve_element_data[5];\n    BOOL done;\n    int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);\n    if (JS_IsException(result_promise))\n        return result_promise;\n    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);\n    if (JS_IsException(promise_resolve) ||\n        check_function(ctx, promise_resolve))\n        goto fail_reject;\n    iter = JS_GetIterator(ctx, argv[0], FALSE);\n    if (JS_IsException(iter)) {\n        JSValue error;\n    fail_reject:\n        error = JS_GetException(ctx);\n        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,\n                       (JSValueConst *)&error);\n        JS_FreeValue(ctx, error);\n        if (JS_IsException(ret))\n            goto fail;\n        JS_FreeValue(ctx, ret);\n    } else {\n        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);\n        if (JS_IsException(next_method))\n            goto fail_reject;\n        values = JS_NewArray(ctx);\n        if (JS_IsException(values))\n            goto fail_reject;\n        resolve_element_env = JS_NewArray(ctx);\n        if (JS_IsException(resolve_element_env))\n            goto fail_reject;\n        /* remainingElementsCount field */\n        if (JS_DefinePropertyValueUint32(ctx, resolve_element_env, 0,\n                                         JS_NewInt32(ctx, 1),\n                                         JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)\n            goto fail_reject;\n\n        index = 0;\n        for(;;) {\n            /* XXX: conformance: should close the iterator if error on 'done'\n               access, but not on 'value' access */\n            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);\n            if (JS_IsException(item))\n                goto fail_reject;\n            if (done)\n                break;\n            next_promise = JS_Call(ctx, promise_resolve,\n                                   this_val, 1, (JSValueConst *)&item);\n            JS_FreeValue(ctx, item);\n            if (JS_IsException(next_promise)) {\n            fail_reject1:\n                JS_IteratorClose(ctx, iter, TRUE);\n                goto fail_reject;\n            }\n            resolve_element_data[0] = JS_NewBool(ctx, FALSE);\n            resolve_element_data[1] = (JSValueConst)JS_NewInt32(ctx, index);\n            resolve_element_data[2] = values;\n            resolve_element_data[3] = resolving_funcs[is_promise_any];\n            resolve_element_data[4] = resolve_element_env;\n            resolve_element =\n                JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,\n                                    magic, 5, resolve_element_data);\n            if (JS_IsException(resolve_element)) {\n                JS_FreeValue(ctx, next_promise);\n                goto fail_reject1;\n            }\n\n            if (magic == PROMISE_MAGIC_allSettled) {\n                reject_element =\n                    JS_NewCFunctionData(ctx, js_promise_all_resolve_element, 1,\n                                        magic | 4, 5, resolve_element_data);\n                if (JS_IsException(reject_element)) {\n                    JS_FreeValue(ctx, next_promise);\n                    goto fail_reject1;\n                }\n            } else if (magic == PROMISE_MAGIC_any) {\n                if (JS_DefinePropertyValueUint32(ctx, values, index,\n                                                 JS_UNDEFINED, JS_PROP_C_W_E) < 0)\n                    goto fail_reject1;\n                reject_element = resolve_element;\n                resolve_element = JS_DupValue(ctx, resolving_funcs[0]);\n            } else {\n                reject_element = JS_DupValue(ctx, resolving_funcs[1]);\n            }\n\n            if (remainingElementsCount_add(ctx, resolve_element_env, 1) < 0) {\n                JS_FreeValue(ctx, next_promise);\n                JS_FreeValue(ctx, resolve_element);\n                JS_FreeValue(ctx, reject_element);\n                goto fail_reject1;\n            }\n\n            then_args[0] = resolve_element;\n            then_args[1] = reject_element;\n            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2, then_args);\n            JS_FreeValue(ctx, resolve_element);\n            JS_FreeValue(ctx, reject_element);\n            if (check_exception_free(ctx, ret))\n                goto fail_reject1;\n            index++;\n        }\n\n        is_zero = remainingElementsCount_add(ctx, resolve_element_env, -1);\n        if (is_zero < 0)\n            goto fail_reject;\n        if (is_zero) {\n            if (magic == PROMISE_MAGIC_any) {\n                JSValue error;\n                error = js_aggregate_error_constructor(ctx, values);\n                if (JS_IsException(error))\n                    goto fail_reject;\n                JS_FreeValue(ctx, values);\n                values = error;\n            }\n            ret = JS_Call(ctx, resolving_funcs[is_promise_any], JS_UNDEFINED,\n                          1, (JSValueConst *)&values);\n            if (check_exception_free(ctx, ret))\n                goto fail_reject;\n        }\n    }\n done:\n    JS_FreeValue(ctx, promise_resolve);\n    JS_FreeValue(ctx, resolve_element_env);\n    JS_FreeValue(ctx, values);\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    return result_promise;\n fail:\n    JS_FreeValue(ctx, result_promise);\n    result_promise = JS_EXCEPTION;\n    goto done;\n}\n\nstatic JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    JSValue result_promise, resolving_funcs[2], item, next_promise, ret;\n    JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;\n    JSValue promise_resolve = JS_UNDEFINED;\n    BOOL done;\n\n    if (!JS_IsObject(this_val))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n    result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);\n    if (JS_IsException(result_promise))\n        return result_promise;\n    promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);\n    if (JS_IsException(promise_resolve) ||\n        check_function(ctx, promise_resolve))\n        goto fail_reject;\n    iter = JS_GetIterator(ctx, argv[0], FALSE);\n    if (JS_IsException(iter)) {\n        JSValue error;\n    fail_reject:\n        error = JS_GetException(ctx);\n        ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, 1,\n                       (JSValueConst *)&error);\n        JS_FreeValue(ctx, error);\n        if (JS_IsException(ret))\n            goto fail;\n        JS_FreeValue(ctx, ret);\n    } else {\n        next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);\n        if (JS_IsException(next_method))\n            goto fail_reject;\n\n        for(;;) {\n            /* XXX: conformance: should close the iterator if error on 'done'\n               access, but not on 'value' access */\n            item = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);\n            if (JS_IsException(item))\n                goto fail_reject;\n            if (done)\n                break;\n            next_promise = JS_Call(ctx, promise_resolve,\n                                   this_val, 1, (JSValueConst *)&item);\n            JS_FreeValue(ctx, item);\n            if (JS_IsException(next_promise)) {\n            fail_reject1:\n                JS_IteratorClose(ctx, iter, TRUE);\n                goto fail_reject;\n            }\n            ret = JS_InvokeFree(ctx, next_promise, JS_ATOM_then, 2,\n                                (JSValueConst *)resolving_funcs);\n            if (check_exception_free(ctx, ret))\n                goto fail_reject1;\n        }\n    }\n done:\n    JS_FreeValue(ctx, promise_resolve);\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    return result_promise;\n fail:\n    //JS_FreeValue(ctx, next_method); // why not???\n    JS_FreeValue(ctx, result_promise);\n    result_promise = JS_EXCEPTION;\n    goto done;\n}\n\nstatic __exception int perform_promise_then(JSContext *ctx,\n                                            JSValueConst promise,\n                                            JSValueConst *resolve_reject,\n                                            JSValueConst *cap_resolving_funcs)\n{\n    JSPromiseData *s = JS_GetOpaque(promise, JS_CLASS_PROMISE);\n    JSPromiseReactionData *rd_array[2], *rd;\n    int i, j;\n\n    rd_array[0] = NULL;\n    rd_array[1] = NULL;\n    for(i = 0; i < 2; i++) {\n        JSValueConst handler;\n        rd = js_mallocz(ctx, sizeof(*rd));\n        if (!rd) {\n            if (i == 1)\n                promise_reaction_data_free(ctx->rt, rd_array[0]);\n            return -1;\n        }\n        for(j = 0; j < 2; j++)\n            rd->resolving_funcs[j] = JS_DupValue(ctx, cap_resolving_funcs[j]);\n        handler = resolve_reject[i];\n        if (!JS_IsFunction(ctx, handler))\n            handler = JS_UNDEFINED;\n        rd->handler = JS_DupValue(ctx, handler);\n        rd_array[i] = rd;\n    }\n\n    if (s->promise_state == JS_PROMISE_PENDING) {\n        for(i = 0; i < 2; i++)\n            list_add_tail(&rd_array[i]->link, &s->promise_reactions[i]);\n    } else {\n        JSValueConst args[5];\n        if (s->promise_state == JS_PROMISE_REJECTED && !s->is_handled) {\n            JSRuntime *rt = ctx->rt;\n            if (rt->host_promise_rejection_tracker) {\n                rt->host_promise_rejection_tracker(ctx, promise, s->promise_result,\n                                                   TRUE, rt->host_promise_rejection_tracker_opaque);\n            }\n        }\n        i = s->promise_state - JS_PROMISE_FULFILLED;\n        rd = rd_array[i];\n        args[0] = rd->resolving_funcs[0];\n        args[1] = rd->resolving_funcs[1];\n        args[2] = rd->handler;\n        args[3] = JS_NewBool(ctx, i);\n        args[4] = s->promise_result;\n        JS_EnqueueJob(ctx, promise_reaction_job, 5, args);\n        for(i = 0; i < 2; i++)\n            promise_reaction_data_free(ctx->rt, rd_array[i]);\n    }\n    s->is_handled = TRUE;\n    return 0;\n}\n\nstatic JSValue js_promise_then(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    JSValue ctor, result_promise, resolving_funcs[2];\n    JSPromiseData *s;\n    int i, ret;\n\n    s = JS_GetOpaque2(ctx, this_val, JS_CLASS_PROMISE);\n    if (!s)\n        return JS_EXCEPTION;\n\n    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);\n    if (JS_IsException(ctor))\n        return ctor;\n    result_promise = js_new_promise_capability(ctx, resolving_funcs, ctor);\n    JS_FreeValue(ctx, ctor);\n    if (JS_IsException(result_promise))\n        return result_promise;\n    ret = perform_promise_then(ctx, this_val, argv,\n                               (JSValueConst *)resolving_funcs);\n    for(i = 0; i < 2; i++)\n        JS_FreeValue(ctx, resolving_funcs[i]);\n    if (ret) {\n        JS_FreeValue(ctx, result_promise);\n        return JS_EXCEPTION;\n    }\n    return result_promise;\n}\n\nstatic JSValue js_promise_catch(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValueConst args[2];\n    args[0] = JS_UNDEFINED;\n    args[1] = argv[0];\n    return JS_Invoke(ctx, this_val, JS_ATOM_then, 2, args);\n}\n\nstatic JSValue js_promise_finally_value_thunk(JSContext *ctx, JSValueConst this_val,\n                                              int argc, JSValueConst *argv,\n                                              int magic, JSValue *func_data)\n{\n    return JS_DupValue(ctx, func_data[0]);\n}\n\nstatic JSValue js_promise_finally_thrower(JSContext *ctx, JSValueConst this_val,\n                                          int argc, JSValueConst *argv,\n                                          int magic, JSValue *func_data)\n{\n    return JS_Throw(ctx, JS_DupValue(ctx, func_data[0]));\n}\n\nstatic JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_val,\n                                            int argc, JSValueConst *argv,\n                                            int magic, JSValue *func_data)\n{\n    JSValueConst ctor = func_data[0];\n    JSValueConst onFinally = func_data[1];\n    JSValue res, promise, ret, then_func;\n\n    res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);\n    if (JS_IsException(res))\n        return res;\n    promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);\n    JS_FreeValue(ctx, res);\n    if (JS_IsException(promise))\n        return promise;\n    if (magic == 0) {\n        then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,\n                                        0, 1, argv);\n    } else {\n        then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,\n                                        0, 1, argv);\n    }\n    if (JS_IsException(then_func)) {\n        JS_FreeValue(ctx, promise);\n        return then_func;\n    }\n    ret = JS_InvokeFree(ctx, promise, JS_ATOM_then, 1, (JSValueConst *)&then_func);\n    JS_FreeValue(ctx, then_func);\n    return ret;\n}\n\nstatic JSValue js_promise_finally(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValueConst onFinally = argv[0];\n    JSValue ctor, ret;\n    JSValue then_funcs[2];\n    JSValueConst func_data[2];\n    int i;\n\n    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);\n    if (JS_IsException(ctor))\n        return ctor;\n    if (!JS_IsFunction(ctx, onFinally)) {\n        then_funcs[0] = JS_DupValue(ctx, onFinally);\n        then_funcs[1] = JS_DupValue(ctx, onFinally);\n    } else {\n        func_data[0] = ctor;\n        func_data[1] = onFinally;\n        for(i = 0; i < 2; i++) {\n            then_funcs[i] = JS_NewCFunctionData(ctx, js_promise_then_finally_func, 1, i, 2, func_data);\n            if (JS_IsException(then_funcs[i])) {\n                if (i == 1)\n                    JS_FreeValue(ctx, then_funcs[0]);\n                JS_FreeValue(ctx, ctor);\n                return JS_EXCEPTION;\n            }\n        }\n    }\n    JS_FreeValue(ctx, ctor);\n    ret = JS_Invoke(ctx, this_val, JS_ATOM_then, 2, (JSValueConst *)then_funcs);\n    JS_FreeValue(ctx, then_funcs[0]);\n    JS_FreeValue(ctx, then_funcs[1]);\n    return ret;\n}\n\nstatic const JSCFunctionListEntry js_promise_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"resolve\", 1, js_promise_resolve, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"reject\", 1, js_promise_resolve, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"all\", 1, js_promise_all, PROMISE_MAGIC_all ),\n    JS_CFUNC_MAGIC_DEF(\"allSettled\", 1, js_promise_all, PROMISE_MAGIC_allSettled ),\n    JS_CFUNC_MAGIC_DEF(\"any\", 1, js_promise_all, PROMISE_MAGIC_any ),\n    JS_CFUNC_DEF(\"try\", 1, js_promise_try ),\n    JS_CFUNC_DEF(\"race\", 1, js_promise_race ),\n    JS_CFUNC_DEF(\"withResolvers\", 0, js_promise_withResolvers ),\n    JS_CGETSET_DEF(\"[Symbol.species]\", js_get_this, NULL),\n};\n\nstatic const JSCFunctionListEntry js_promise_proto_funcs[] = {\n    JS_CFUNC_DEF(\"then\", 2, js_promise_then ),\n    JS_CFUNC_DEF(\"catch\", 1, js_promise_catch ),\n    JS_CFUNC_DEF(\"finally\", 1, js_promise_finally ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Promise\", JS_PROP_CONFIGURABLE ),\n};\n\n/* AsyncFunction */\nstatic const JSCFunctionListEntry js_async_function_proto_funcs[] = {\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"AsyncFunction\", JS_PROP_CONFIGURABLE ),\n};\n\n/* AsyncIteratorPrototype */\n\nstatic const JSCFunctionListEntry js_async_iterator_proto_funcs[] = {\n    JS_CFUNC_DEF(\"[Symbol.asyncIterator]\", 0, js_iterator_proto_iterator ),\n};\n\n/* AsyncFromSyncIteratorPrototype */\n\ntypedef struct JSAsyncFromSyncIteratorData {\n    JSValue sync_iter;\n    JSValue next_method;\n} JSAsyncFromSyncIteratorData;\n\nstatic void js_async_from_sync_iterator_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSAsyncFromSyncIteratorData *s =\n        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);\n    if (s) {\n        JS_FreeValueRT(rt, s->sync_iter);\n        JS_FreeValueRT(rt, s->next_method);\n        js_free_rt(rt, s);\n    }\n}\n\nstatic void js_async_from_sync_iterator_mark(JSRuntime *rt, JSValueConst val,\n                                             JS_MarkFunc *mark_func)\n{\n    JSAsyncFromSyncIteratorData *s =\n        JS_GetOpaque(val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);\n    if (s) {\n        JS_MarkValue(rt, s->sync_iter, mark_func);\n        JS_MarkValue(rt, s->next_method, mark_func);\n    }\n}\n\nstatic JSValue JS_CreateAsyncFromSyncIterator(JSContext *ctx,\n                                              JSValueConst sync_iter)\n{\n    JSValue async_iter, next_method;\n    JSAsyncFromSyncIteratorData *s;\n\n    next_method = JS_GetProperty(ctx, sync_iter, JS_ATOM_next);\n    if (JS_IsException(next_method))\n        return JS_EXCEPTION;\n    async_iter = JS_NewObjectClass(ctx, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);\n    if (JS_IsException(async_iter)) {\n        JS_FreeValue(ctx, next_method);\n        return async_iter;\n    }\n    s = js_mallocz(ctx, sizeof(*s));\n    if (!s) {\n        JS_FreeValue(ctx, async_iter);\n        JS_FreeValue(ctx, next_method);\n        return JS_EXCEPTION;\n    }\n    s->sync_iter = JS_DupValue(ctx, sync_iter);\n    s->next_method = next_method;\n    JS_SetOpaque(async_iter, s);\n    return async_iter;\n}\n\nstatic JSValue js_async_from_sync_iterator_unwrap(JSContext *ctx,\n                                                  JSValueConst this_val,\n                                                  int argc, JSValueConst *argv,\n                                                  int magic, JSValue *func_data)\n{\n    return js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]),\n                                     JS_ToBool(ctx, func_data[0]));\n}\n\nstatic JSValue js_async_from_sync_iterator_unwrap_func_create(JSContext *ctx,\n                                                              BOOL done)\n{\n    JSValueConst func_data[1];\n\n    func_data[0] = (JSValueConst)JS_NewBool(ctx, done);\n    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_unwrap,\n                               1, 0, 1, func_data);\n}\n\nstatic JSValue js_async_from_sync_iterator_close_wrap(JSContext *ctx,\n                                                      JSValueConst this_val,\n                                                      int argc, JSValueConst *argv,\n                                                      int magic, JSValue *func_data)\n{\n    JS_Throw(ctx, JS_DupValue(ctx, argv[0]));\n    JS_IteratorClose(ctx, func_data[0], TRUE);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_async_from_sync_iterator_close_wrap_func_create(JSContext *ctx, JSValueConst sync_iter)\n{\n    return JS_NewCFunctionData(ctx, js_async_from_sync_iterator_close_wrap,\n                               1, 0, 1, &sync_iter);\n}\n\nstatic JSValue js_async_from_sync_iterator_next(JSContext *ctx, JSValueConst this_val,\n                                                int argc, JSValueConst *argv,\n                                                int magic)\n{\n    JSValue promise, resolving_funcs[2], value, err, method;\n    JSAsyncFromSyncIteratorData *s;\n    int done;\n    int is_reject;\n\n    promise = JS_NewPromiseCapability(ctx, resolving_funcs);\n    if (JS_IsException(promise))\n        return JS_EXCEPTION;\n    s = JS_GetOpaque(this_val, JS_CLASS_ASYNC_FROM_SYNC_ITERATOR);\n    if (!s) {\n        JS_ThrowTypeError(ctx, \"not an Async-from-Sync Iterator\");\n        goto reject;\n    }\n\n    if (magic == GEN_MAGIC_NEXT) {\n        method = JS_DupValue(ctx, s->next_method);\n    } else {\n        method = JS_GetProperty(ctx, s->sync_iter,\n                                magic == GEN_MAGIC_RETURN ? JS_ATOM_return :\n                                JS_ATOM_throw);\n        if (JS_IsException(method))\n            goto reject;\n        if (JS_IsUndefined(method) || JS_IsNull(method)) {\n            if (magic == GEN_MAGIC_RETURN) {\n                err = js_create_iterator_result(ctx, JS_DupValue(ctx, argv[0]), TRUE);\n                is_reject = 0;\n                goto done_resolve;\n            } else {\n                if (JS_IteratorClose(ctx, s->sync_iter, FALSE))\n                    goto reject;\n                JS_ThrowTypeError(ctx, \"throw is not a method\");\n                goto reject;\n            }\n        }\n    }\n    value = JS_IteratorNext2(ctx, s->sync_iter, method,\n                             argc >= 1 ? 1 : 0, argv, &done);\n    JS_FreeValue(ctx, method);\n    if (JS_IsException(value))\n        goto reject;\n    if (done == 2) {\n        JSValue obj = value;\n        value = JS_IteratorGetCompleteValue(ctx, obj, &done);\n        JS_FreeValue(ctx, obj);\n        if (JS_IsException(value))\n            goto reject;\n    }\n    \n    if (JS_IsException(value))\n        goto reject;\n    {\n        JSValue value_wrapper_promise, resolve_reject[2];\n        int res;\n\n        value_wrapper_promise = js_promise_resolve(ctx, ctx->promise_ctor,\n                                                   1, (JSValueConst *)&value, 0);\n        if (JS_IsException(value_wrapper_promise)) {\n            JSValue res2;\n            JS_FreeValue(ctx, value);\n            if (magic != GEN_MAGIC_RETURN && !done) {\n                JS_IteratorClose(ctx, s->sync_iter, TRUE);\n            }\n        reject:\n            err = JS_GetException(ctx);\n            is_reject = 1;\n        done_resolve:\n            res2 = JS_Call(ctx, resolving_funcs[is_reject], JS_UNDEFINED,\n                           1, (JSValueConst *)&err);\n            JS_FreeValue(ctx, err);\n            JS_FreeValue(ctx, res2);\n            JS_FreeValue(ctx, resolving_funcs[0]);\n            JS_FreeValue(ctx, resolving_funcs[1]);\n            return promise;\n        }\n\n        resolve_reject[0] =\n            js_async_from_sync_iterator_unwrap_func_create(ctx, done);\n        if (JS_IsException(resolve_reject[0])) {\n            JS_FreeValue(ctx, value_wrapper_promise);\n            goto fail;\n        }\n        if (done || magic == GEN_MAGIC_RETURN) {\n            resolve_reject[1] = JS_UNDEFINED;\n        } else {\n            resolve_reject[1] =\n                js_async_from_sync_iterator_close_wrap_func_create(ctx, s->sync_iter);\n            if (JS_IsException(resolve_reject[1])) {\n                JS_FreeValue(ctx, value_wrapper_promise);\n                JS_FreeValue(ctx, resolve_reject[0]);\n                goto fail;\n            }\n        }\n        JS_FreeValue(ctx, value);\n        res = perform_promise_then(ctx, value_wrapper_promise,\n                                   (JSValueConst *)resolve_reject,\n                                   (JSValueConst *)resolving_funcs);\n        JS_FreeValue(ctx, resolve_reject[0]);\n        JS_FreeValue(ctx, resolve_reject[1]);\n        JS_FreeValue(ctx, value_wrapper_promise);\n        JS_FreeValue(ctx, resolving_funcs[0]);\n        JS_FreeValue(ctx, resolving_funcs[1]);\n        if (res) {\n            JS_FreeValue(ctx, promise);\n            return JS_EXCEPTION;\n        }\n    }\n    return promise;\n fail:\n    JS_FreeValue(ctx, value);\n    JS_FreeValue(ctx, resolving_funcs[0]);\n    JS_FreeValue(ctx, resolving_funcs[1]);\n    JS_FreeValue(ctx, promise);\n    return JS_EXCEPTION;\n}\n\nstatic const JSCFunctionListEntry js_async_from_sync_iterator_proto_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"next\", 1, js_async_from_sync_iterator_next, GEN_MAGIC_NEXT ),\n    JS_CFUNC_MAGIC_DEF(\"return\", 1, js_async_from_sync_iterator_next, GEN_MAGIC_RETURN ),\n    JS_CFUNC_MAGIC_DEF(\"throw\", 1, js_async_from_sync_iterator_next, GEN_MAGIC_THROW ),\n};\n\n/* AsyncGeneratorFunction */\n\nstatic const JSCFunctionListEntry js_async_generator_function_proto_funcs[] = {\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"AsyncGeneratorFunction\", JS_PROP_CONFIGURABLE ),\n};\n\n/* AsyncGenerator prototype */\n\nstatic const JSCFunctionListEntry js_async_generator_proto_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"next\", 1, js_async_generator_next, GEN_MAGIC_NEXT ),\n    JS_CFUNC_MAGIC_DEF(\"return\", 1, js_async_generator_next, GEN_MAGIC_RETURN ),\n    JS_CFUNC_MAGIC_DEF(\"throw\", 1, js_async_generator_next, GEN_MAGIC_THROW ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"AsyncGenerator\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic JSClassShortDef const js_async_class_def[] = {\n    { JS_ATOM_Promise, js_promise_finalizer, js_promise_mark },                      /* JS_CLASS_PROMISE */\n    { JS_ATOM_PromiseResolveFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_RESOLVE_FUNCTION */\n    { JS_ATOM_PromiseRejectFunction, js_promise_resolve_function_finalizer, js_promise_resolve_function_mark }, /* JS_CLASS_PROMISE_REJECT_FUNCTION */\n    { JS_ATOM_AsyncFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_FUNCTION */\n    { JS_ATOM_AsyncFunctionResolve, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_RESOLVE */\n    { JS_ATOM_AsyncFunctionReject, js_async_function_resolve_finalizer, js_async_function_resolve_mark }, /* JS_CLASS_ASYNC_FUNCTION_REJECT */\n    { JS_ATOM_empty_string, js_async_from_sync_iterator_finalizer, js_async_from_sync_iterator_mark }, /* JS_CLASS_ASYNC_FROM_SYNC_ITERATOR */\n    { JS_ATOM_AsyncGeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark },  /* JS_CLASS_ASYNC_GENERATOR_FUNCTION */\n    { JS_ATOM_AsyncGenerator, js_async_generator_finalizer, js_async_generator_mark },  /* JS_CLASS_ASYNC_GENERATOR */\n};\n\nint JS_AddIntrinsicPromise(JSContext *ctx)\n{\n    JSRuntime *rt = ctx->rt;\n    JSValue obj1;\n    JSCFunctionType ft;\n\n    if (!JS_IsRegisteredClass(rt, JS_CLASS_PROMISE)) {\n        if (init_class_range(rt, js_async_class_def, JS_CLASS_PROMISE,\n                             countof(js_async_class_def)))\n            return -1;\n        rt->class_array[JS_CLASS_PROMISE_RESOLVE_FUNCTION].call = js_promise_resolve_function_call;\n        rt->class_array[JS_CLASS_PROMISE_REJECT_FUNCTION].call = js_promise_resolve_function_call;\n        rt->class_array[JS_CLASS_ASYNC_FUNCTION].call = js_async_function_call;\n        rt->class_array[JS_CLASS_ASYNC_FUNCTION_RESOLVE].call = js_async_function_resolve_call;\n        rt->class_array[JS_CLASS_ASYNC_FUNCTION_REJECT].call = js_async_function_resolve_call;\n        rt->class_array[JS_CLASS_ASYNC_GENERATOR_FUNCTION].call = js_async_generator_function_call;\n    }\n\n    /* Promise */\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_PROMISE, \"Promise\",\n                                     js_promise_constructor, 1, JS_CFUNC_constructor, 0,\n                                     JS_UNDEFINED,\n                                     js_promise_funcs, countof(js_promise_funcs),\n                                     js_promise_proto_funcs, countof(js_promise_proto_funcs),\n                                     0);\n    if (JS_IsException(obj1))\n        return -1;\n    ctx->promise_ctor = obj1;\n    \n    /* AsyncFunction */\n    ft.generic_magic = js_function_constructor;\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_ASYNC_FUNCTION, \"AsyncFunction\",\n                                     ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC,\n                                     ctx->function_ctor,\n                                     NULL, 0,\n                                     js_async_function_proto_funcs, countof(js_async_function_proto_funcs),\n                                     JS_NEW_CTOR_NO_GLOBAL | JS_NEW_CTOR_READONLY);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    \n    /* AsyncIteratorPrototype */\n    ctx->async_iterator_proto =\n        JS_NewObjectProtoList(ctx,  ctx->class_proto[JS_CLASS_OBJECT],\n                              js_async_iterator_proto_funcs,\n                              countof(js_async_iterator_proto_funcs));\n    if (JS_IsException(ctx->async_iterator_proto))\n        return -1;\n\n    /* AsyncFromSyncIteratorPrototype */\n    ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR] =\n        JS_NewObjectProtoList(ctx, ctx->async_iterator_proto,\n                              js_async_from_sync_iterator_proto_funcs,\n                              countof(js_async_from_sync_iterator_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_ASYNC_FROM_SYNC_ITERATOR]))\n        return -1;\n    \n    /* AsyncGeneratorPrototype */\n    ctx->class_proto[JS_CLASS_ASYNC_GENERATOR] =\n        JS_NewObjectProtoList(ctx, ctx->async_iterator_proto, \n                              js_async_generator_proto_funcs,\n                              countof(js_async_generator_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_ASYNC_GENERATOR]))\n        return -1;\n\n    /* AsyncGeneratorFunction */\n    ft.generic_magic = js_function_constructor;\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_ASYNC_GENERATOR_FUNCTION, \"AsyncGeneratorFunction\",\n                                     ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_ASYNC_GENERATOR,\n                                     ctx->function_ctor,\n                                     NULL, 0,\n                                     js_async_generator_function_proto_funcs, countof(js_async_generator_function_proto_funcs),\n                                     JS_NEW_CTOR_NO_GLOBAL | JS_NEW_CTOR_READONLY);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n\n    return JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_ASYNC_GENERATOR_FUNCTION],\n                              ctx->class_proto[JS_CLASS_ASYNC_GENERATOR],\n                              JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE);\n}\n\n/* URI handling */\n\nstatic int string_get_hex(JSString *p, int k, int n) {\n    int c = 0, h;\n    while (n-- > 0) {\n        if ((h = from_hex(string_get(p, k++))) < 0)\n            return -1;\n        c = (c << 4) | h;\n    }\n    return c;\n}\n\nstatic int isURIReserved(int c) {\n    return c < 0x100 && memchr(\";/?:@&=+$,#\", c, sizeof(\";/?:@&=+$,#\") - 1) != NULL;\n}\n\nstatic int __attribute__((format(printf, 2, 3))) js_throw_URIError(JSContext *ctx, const char *fmt, ...)\n{\n    va_list ap;\n\n    va_start(ap, fmt);\n    JS_ThrowError(ctx, JS_URI_ERROR, fmt, ap);\n    va_end(ap);\n    return -1;\n}\n\nstatic int hex_decode(JSContext *ctx, JSString *p, int k) {\n    int c;\n\n    if (k >= p->len || string_get(p, k) != '%')\n        return js_throw_URIError(ctx, \"expecting %%\");\n    if (k + 2 >= p->len || (c = string_get_hex(p, k + 1, 2)) < 0)\n        return js_throw_URIError(ctx, \"expecting hex digit\");\n\n    return c;\n}\n\nstatic JSValue js_global_decodeURI(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv, int isComponent)\n{\n    JSValue str;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p;\n    int k, c, c1, n, c_min;\n\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        return str;\n\n    string_buffer_init(ctx, b, 0);\n\n    p = JS_VALUE_GET_STRING(str);\n    for (k = 0; k < p->len;) {\n        c = string_get(p, k);\n        if (c == '%') {\n            c = hex_decode(ctx, p, k);\n            if (c < 0)\n                goto fail;\n            k += 3;\n            if (c < 0x80) {\n                if (!isComponent && isURIReserved(c)) {\n                    c = '%';\n                    k -= 2;\n                }\n            } else {\n                /* Decode URI-encoded UTF-8 sequence */\n                if (c >= 0xc0 && c <= 0xdf) {\n                    n = 1;\n                    c_min = 0x80;\n                    c &= 0x1f;\n                } else if (c >= 0xe0 && c <= 0xef) {\n                    n = 2;\n                    c_min = 0x800;\n                    c &= 0xf;\n                } else if (c >= 0xf0 && c <= 0xf7) {\n                    n = 3;\n                    c_min = 0x10000;\n                    c &= 0x7;\n                } else {\n                    n = 0;\n                    c_min = 1;\n                    c = 0;\n                }\n                while (n-- > 0) {\n                    c1 = hex_decode(ctx, p, k);\n                    if (c1 < 0)\n                        goto fail;\n                    k += 3;\n                    if ((c1 & 0xc0) != 0x80) {\n                        c = 0;\n                        break;\n                    }\n                    c = (c << 6) | (c1 & 0x3f);\n                }\n                if (c < c_min || c > 0x10FFFF || is_surrogate(c)) {\n                    js_throw_URIError(ctx, \"malformed UTF-8\");\n                    goto fail;\n                }\n            }\n        } else {\n            k++;\n        }\n        string_buffer_putc(b, c);\n    }\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n\nfail:\n    JS_FreeValue(ctx, str);\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\nstatic int isUnescaped(int c) {\n    static char const unescaped_chars[] =\n        \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n        \"abcdefghijklmnopqrstuvwxyz\"\n        \"0123456789\"\n        \"@*_+-./\";\n    return c < 0x100 &&\n        memchr(unescaped_chars, c, sizeof(unescaped_chars) - 1);\n}\n\nstatic int isURIUnescaped(int c, int isComponent) {\n    return c < 0x100 &&\n        ((c >= 0x61 && c <= 0x7a) ||\n         (c >= 0x41 && c <= 0x5a) ||\n         (c >= 0x30 && c <= 0x39) ||\n         memchr(\"-_.!~*'()\", c, sizeof(\"-_.!~*'()\") - 1) != NULL ||\n         (!isComponent && isURIReserved(c)));\n}\n\nstatic int encodeURI_hex(StringBuffer *b, int c) {\n    uint8_t buf[6];\n    int n = 0;\n    const char *hex = \"0123456789ABCDEF\";\n\n    buf[n++] = '%';\n    if (c >= 256) {\n        buf[n++] = 'u';\n        buf[n++] = hex[(c >> 12) & 15];\n        buf[n++] = hex[(c >>  8) & 15];\n    }\n    buf[n++] = hex[(c >> 4) & 15];\n    buf[n++] = hex[(c >> 0) & 15];\n    return string_buffer_write8(b, buf, n);\n}\n\nstatic JSValue js_global_encodeURI(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv,\n                                   int isComponent)\n{\n    JSValue str;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p;\n    int k, c, c1;\n\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        return str;\n\n    p = JS_VALUE_GET_STRING(str);\n    string_buffer_init(ctx, b, p->len);\n    for (k = 0; k < p->len;) {\n        c = string_get(p, k);\n        k++;\n        if (isURIUnescaped(c, isComponent)) {\n            string_buffer_putc16(b, c);\n        } else {\n            if (is_lo_surrogate(c)) {\n                js_throw_URIError(ctx, \"invalid character\");\n                goto fail;\n            } else if (is_hi_surrogate(c)) {\n                if (k >= p->len) {\n                    js_throw_URIError(ctx, \"expecting surrogate pair\");\n                    goto fail;\n                }\n                c1 = string_get(p, k);\n                k++;\n                if (!is_lo_surrogate(c1)) {\n                    js_throw_URIError(ctx, \"expecting surrogate pair\");\n                    goto fail;\n                }\n                c = from_surrogate(c, c1);\n            }\n            if (c < 0x80) {\n                encodeURI_hex(b, c);\n            } else {\n                /* XXX: use C UTF-8 conversion ? */\n                if (c < 0x800) {\n                    encodeURI_hex(b, (c >> 6) | 0xc0);\n                } else {\n                    if (c < 0x10000) {\n                        encodeURI_hex(b, (c >> 12) | 0xe0);\n                    } else {\n                        encodeURI_hex(b, (c >> 18) | 0xf0);\n                        encodeURI_hex(b, ((c >> 12) & 0x3f) | 0x80);\n                    }\n                    encodeURI_hex(b, ((c >> 6) & 0x3f) | 0x80);\n                }\n                encodeURI_hex(b, (c & 0x3f) | 0x80);\n            }\n        }\n    }\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n\nfail:\n    JS_FreeValue(ctx, str);\n    string_buffer_free(b);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_global_escape(JSContext *ctx, JSValueConst this_val,\n                                int argc, JSValueConst *argv)\n{\n    JSValue str;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p;\n    int i, len, c;\n\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        return str;\n\n    p = JS_VALUE_GET_STRING(str);\n    string_buffer_init(ctx, b, p->len);\n    for (i = 0, len = p->len; i < len; i++) {\n        c = string_get(p, i);\n        if (isUnescaped(c)) {\n            string_buffer_putc16(b, c);\n        } else {\n            encodeURI_hex(b, c);\n        }\n    }\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n}\n\nstatic JSValue js_global_unescape(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValue str;\n    StringBuffer b_s, *b = &b_s;\n    JSString *p;\n    int i, len, c, n;\n\n    str = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(str))\n        return str;\n\n    string_buffer_init(ctx, b, 0);\n    p = JS_VALUE_GET_STRING(str);\n    for (i = 0, len = p->len; i < len; i++) {\n        c = string_get(p, i);\n        if (c == '%') {\n            if (i + 6 <= len\n            &&  string_get(p, i + 1) == 'u'\n            &&  (n = string_get_hex(p, i + 2, 4)) >= 0) {\n                c = n;\n                i += 6 - 1;\n            } else\n            if (i + 3 <= len\n            &&  (n = string_get_hex(p, i + 1, 2)) >= 0) {\n                c = n;\n                i += 3 - 1;\n            }\n        }\n        string_buffer_putc16(b, c);\n    }\n    JS_FreeValue(ctx, str);\n    return string_buffer_end(b);\n}\n\n/* global object */\n\nstatic const JSCFunctionListEntry js_global_funcs[] = {\n    JS_CFUNC_DEF(\"parseInt\", 2, js_parseInt ),\n    JS_CFUNC_DEF(\"parseFloat\", 1, js_parseFloat ),\n    JS_CFUNC_DEF(\"isNaN\", 1, js_global_isNaN ),\n    JS_CFUNC_DEF(\"isFinite\", 1, js_global_isFinite ),\n\n    JS_CFUNC_MAGIC_DEF(\"decodeURI\", 1, js_global_decodeURI, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"decodeURIComponent\", 1, js_global_decodeURI, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"encodeURI\", 1, js_global_encodeURI, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"encodeURIComponent\", 1, js_global_encodeURI, 1 ),\n    JS_CFUNC_DEF(\"escape\", 1, js_global_escape ),\n    JS_CFUNC_DEF(\"unescape\", 1, js_global_unescape ),\n    JS_PROP_DOUBLE_DEF(\"Infinity\", 1.0 / 0.0, 0 ),\n    JS_PROP_DOUBLE_DEF(\"NaN\", NAN, 0 ),\n    JS_PROP_UNDEFINED_DEF(\"undefined\", 0 ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"global\", JS_PROP_CONFIGURABLE ),\n    JS_CFUNC_DEF(\"eval\", 1, js_global_eval ),\n};\n\n/* Date */\n\nstatic int64_t math_mod(int64_t a, int64_t b) {\n    /* return positive modulo */\n    int64_t m = a % b;\n    return m + (m < 0) * b;\n}\n\nstatic int64_t floor_div(int64_t a, int64_t b) {\n    /* integer division rounding toward -Infinity */\n    int64_t m = a % b;\n    return (a - (m + (m < 0) * b)) / b;\n}\n\nstatic JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv);\n\nstatic __exception int JS_ThisTimeValue(JSContext *ctx, double *valp, JSValueConst this_val)\n{\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data))\n            return JS_ToFloat64(ctx, valp, p->u.object_data);\n    }\n    JS_ThrowTypeError(ctx, \"not a Date object\");\n    return -1;\n}\n\nstatic JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double v)\n{\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (p->class_id == JS_CLASS_DATE) {\n            JS_FreeValue(ctx, p->u.object_data);\n            p->u.object_data = JS_NewFloat64(ctx, v);\n            return JS_DupValue(ctx, p->u.object_data);\n        }\n    }\n    return JS_ThrowTypeError(ctx, \"not a Date object\");\n}\n\nstatic int64_t days_from_year(int64_t y) {\n    return 365 * (y - 1970) + floor_div(y - 1969, 4) -\n        floor_div(y - 1901, 100) + floor_div(y - 1601, 400);\n}\n\nstatic int64_t days_in_year(int64_t y) {\n    return 365 + !(y % 4) - !(y % 100) + !(y % 400);\n}\n\n/* return the year, update days */\nstatic int64_t year_from_days(int64_t *days) {\n    int64_t y, d1, nd, d = *days;\n    y = floor_div(d * 10000, 3652425) + 1970;\n    /* the initial approximation is very good, so only a few\n       iterations are necessary */\n    for(;;) {\n        d1 = d - days_from_year(y);\n        if (d1 < 0) {\n            y--;\n            d1 += days_in_year(y);\n        } else {\n            nd = days_in_year(y);\n            if (d1 < nd)\n                break;\n            d1 -= nd;\n            y++;\n        }\n    }\n    *days = d1;\n    return y;\n}\n\nstatic int const month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\nstatic char const month_names[] = \"JanFebMarAprMayJunJulAugSepOctNovDec\";\nstatic char const day_names[] = \"SunMonTueWedThuFriSat\";\n\nstatic __exception int get_date_fields(JSContext *ctx, JSValueConst obj,\n                                       double fields[minimum_length(9)], int is_local, int force)\n{\n    double dval;\n    int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;\n\n    if (JS_ThisTimeValue(ctx, &dval, obj))\n        return -1;\n\n    if (isnan(dval)) {\n        if (!force)\n            return FALSE; /* NaN */\n        d = 0;        /* initialize all fields to 0 */\n    } else {\n        d = dval;     /* assuming -8.64e15 <= dval <= -8.64e15 */\n        if (is_local) {\n            tz = -getTimezoneOffset(d);\n            d += tz * 60000;\n        }\n    }\n\n    /* result is >= 0, we can use % */\n    h = math_mod(d, 86400000);\n    days = (d - h) / 86400000;\n    ms = h % 1000;\n    h = (h - ms) / 1000;\n    s = h % 60;\n    h = (h - s) / 60;\n    m = h % 60;\n    h = (h - m) / 60;\n    wd = math_mod(days + 4, 7); /* week day */\n    y = year_from_days(&days);\n\n    for(i = 0; i < 11; i++) {\n        md = month_days[i];\n        if (i == 1)\n            md += days_in_year(y) - 365;\n        if (days < md)\n            break;\n        days -= md;\n    }\n    fields[0] = y;\n    fields[1] = i;\n    fields[2] = days + 1;\n    fields[3] = h;\n    fields[4] = m;\n    fields[5] = s;\n    fields[6] = ms;\n    fields[7] = wd;\n    fields[8] = tz;\n    return TRUE;\n}\n\nstatic double time_clip(double t) {\n    if (t >= -8.64e15 && t <= 8.64e15)\n        return trunc(t) + 0.0;  /* convert -0 to +0 */\n    else\n        return NAN;\n}\n\n/* The spec mandates the use of 'double' and it specifies the order\n   of the operations */\nstatic double set_date_fields(double fields[minimum_length(7)], int is_local) {\n    double y, m, dt, ym, mn, day, h, s, milli, time, tv;\n    int yi, mi, i;\n    int64_t days;\n    volatile double temp;  /* enforce evaluation order */\n\n    /* emulate 21.4.1.15 MakeDay ( year, month, date ) */\n    y = fields[0];\n    m = fields[1];\n    dt = fields[2];\n    ym = y + floor(m / 12);\n    mn = fmod(m, 12);\n    if (mn < 0)\n        mn += 12;\n    if (ym < -271821 || ym > 275760)\n        return NAN;\n\n    yi = ym;\n    mi = mn;\n    days = days_from_year(yi);\n    for(i = 0; i < mi; i++) {\n        days += month_days[i];\n        if (i == 1)\n            days += days_in_year(yi) - 365;\n    }\n    day = days + dt - 1;\n\n    /* emulate 21.4.1.14 MakeTime ( hour, min, sec, ms ) */\n    h = fields[3];\n    m = fields[4];\n    s = fields[5];\n    milli = fields[6];\n    /* Use a volatile intermediary variable to ensure order of evaluation\n     * as specified in ECMA. This fixes a test262 error on\n     * test262/test/built-ins/Date/UTC/fp-evaluation-order.js.\n     * Without the volatile qualifier, the compile can generate code\n     * that performs the computation in a different order or with instructions\n     * that produce a different result such as FMA (float multiply and add).\n     */\n    time = h * 3600000;\n    time += (temp = m * 60000);\n    time += (temp = s * 1000);\n    time += milli;\n\n    /* emulate 21.4.1.16 MakeDate ( day, time ) */\n    tv = (temp = day * 86400000) + time;   /* prevent generation of FMA */\n    if (!isfinite(tv))\n        return NAN;\n\n    /* adjust for local time and clip */\n    if (is_local) {\n        int64_t ti = tv < INT64_MIN ? INT64_MIN : tv >= 0x1p63 ? INT64_MAX : (int64_t)tv;\n        tv += getTimezoneOffset(ti) * 60000;\n    }\n    return time_clip(tv);\n}\n\nstatic double set_date_fields_checked(double fields[minimum_length(7)], int is_local)\n{\n    int i;\n    double a;\n    for(i = 0; i < 7; i++) {\n        a = fields[i];\n        if (!isfinite(a))\n            return NAN;\n        fields[i] = trunc(a);\n        if (i == 0 && fields[0] >= 0 && fields[0] < 100)\n            fields[0] += 1900;\n    }\n    return set_date_fields(fields, is_local);\n}\n\nstatic JSValue get_date_field(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int magic)\n{\n    // get_date_field(obj, n, is_local)\n    double fields[9];\n    int res, n, is_local;\n\n    is_local = magic & 0x0F;\n    n = (magic >> 4) & 0x0F;\n    res = get_date_fields(ctx, this_val, fields, is_local, 0);\n    if (res < 0)\n        return JS_EXCEPTION;\n    if (!res)\n        return JS_NAN;\n\n    if (magic & 0x100) {    // getYear\n        fields[0] -= 1900;\n    }\n    return JS_NewFloat64(ctx, fields[n]);\n}\n\nstatic JSValue set_date_field(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv, int magic)\n{\n    // _field(obj, first_field, end_field, args, is_local)\n    double fields[9];\n    int res, first_field, end_field, is_local, i, n, res1;\n    double d, a;\n\n    d = NAN;\n    first_field = (magic >> 8) & 0x0F;\n    end_field = (magic >> 4) & 0x0F;\n    is_local = magic & 0x0F;\n\n    res = get_date_fields(ctx, this_val, fields, is_local, first_field == 0);\n    if (res < 0)\n        return JS_EXCEPTION;\n    res1 = res;\n    \n    // Argument coercion is observable and must be done unconditionally.\n    n = min_int(argc, end_field - first_field);\n    for(i = 0; i < n; i++) {\n        if (JS_ToFloat64(ctx, &a, argv[i]))\n            return JS_EXCEPTION;\n        if (!isfinite(a))\n            res = FALSE;\n        fields[first_field + i] = trunc(a);\n    }\n\n    if (!res1)\n        return JS_NAN; /* thisTimeValue is NaN */\n\n    if (res && argc > 0)\n        d = set_date_fields(fields, is_local);\n\n    return JS_SetThisTimeValue(ctx, this_val, d);\n}\n\n/* fmt:\n   0: toUTCString: \"Tue, 02 Jan 2018 23:04:46 GMT\"\n   1: toString: \"Wed Jan 03 2018 00:05:22 GMT+0100 (CET)\"\n   2: toISOString: \"2018-01-02T23:02:56.927Z\"\n   3: toLocaleString: \"1/2/2018, 11:40:40 PM\"\n   part: 1=date, 2=time 3=all\n   XXX: should use a variant of strftime().\n */\nstatic JSValue get_date_string(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv, int magic)\n{\n    // _string(obj, fmt, part)\n    char buf[64];\n    double fields[9];\n    int res, fmt, part, pos;\n    int y, mon, d, h, m, s, ms, wd, tz;\n\n    fmt = (magic >> 4) & 0x0F;\n    part = magic & 0x0F;\n\n    res = get_date_fields(ctx, this_val, fields, fmt & 1, 0);\n    if (res < 0)\n        return JS_EXCEPTION;\n    if (!res) {\n        if (fmt == 2)\n            return JS_ThrowRangeError(ctx, \"Date value is NaN\");\n        else\n            return js_new_string8(ctx, \"Invalid Date\");\n    }\n\n    y = fields[0];\n    mon = fields[1];\n    d = fields[2];\n    h = fields[3];\n    m = fields[4];\n    s = fields[5];\n    ms = fields[6];\n    wd = fields[7];\n    tz = fields[8];\n\n    pos = 0;\n\n    if (part & 1) { /* date part */\n        switch(fmt) {\n        case 0:\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%.3s, %02d %.3s %0*d \",\n                            day_names + wd * 3, d,\n                            month_names + mon * 3, 4 + (y < 0), y);\n            break;\n        case 1:\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%.3s %.3s %02d %0*d\",\n                            day_names + wd * 3,\n                            month_names + mon * 3, d, 4 + (y < 0), y);\n            if (part == 3) {\n                buf[pos++] = ' ';\n            }\n            break;\n        case 2:\n            if (y >= 0 && y <= 9999) {\n                pos += snprintf(buf + pos, sizeof(buf) - pos,\n                                \"%04d\", y);\n            } else {\n                pos += snprintf(buf + pos, sizeof(buf) - pos,\n                                \"%+07d\", y);\n            }\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"-%02d-%02dT\", mon + 1, d);\n            break;\n        case 3:\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%02d/%02d/%0*d\", mon + 1, d, 4 + (y < 0), y);\n            if (part == 3) {\n                buf[pos++] = ',';\n                buf[pos++] = ' ';\n            }\n            break;\n        }\n    }\n    if (part & 2) { /* time part */\n        switch(fmt) {\n        case 0:\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%02d:%02d:%02d GMT\", h, m, s);\n            break;\n        case 1:\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%02d:%02d:%02d GMT\", h, m, s);\n            if (tz < 0) {\n                buf[pos++] = '-';\n                tz = -tz;\n            } else {\n                buf[pos++] = '+';\n            }\n            /* tz is >= 0, can use % */\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%02d%02d\", tz / 60, tz % 60);\n            /* XXX: tack the time zone code? */\n            break;\n        case 2:\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%02d:%02d:%02d.%03dZ\", h, m, s, ms);\n            break;\n        case 3:\n            pos += snprintf(buf + pos, sizeof(buf) - pos,\n                            \"%02d:%02d:%02d %cM\", (h + 11) % 12 + 1, m, s,\n                            (h < 12) ? 'A' : 'P');\n            break;\n        }\n    }\n    return JS_NewStringLen(ctx, buf, pos);\n}\n\n/* OS dependent: return the UTC time in ms since 1970. */\nstatic int64_t date_now(void) {\n    struct timeval tv;\n    gettimeofday(&tv, NULL);\n    return (int64_t)tv.tv_sec * 1000 + (tv.tv_usec / 1000);\n}\n\nstatic JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,\n                                   int argc, JSValueConst *argv)\n{\n    // Date(y, mon, d, h, m, s, ms)\n    JSValue rv;\n    int i, n;\n    double val;\n\n    if (JS_IsUndefined(new_target)) {\n        /* invoked as function */\n        argc = 0;\n    }\n    n = argc;\n    if (n == 0) {\n        val = date_now();\n    } else if (n == 1) {\n        JSValue v, dv;\n        if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {\n            JSObject *p = JS_VALUE_GET_OBJ(argv[0]);\n            if (p->class_id == JS_CLASS_DATE && JS_IsNumber(p->u.object_data)) {\n                if (JS_ToFloat64(ctx, &val, p->u.object_data))\n                    return JS_EXCEPTION;\n                val = time_clip(val);\n                goto has_val;\n            }\n        }\n        v = JS_ToPrimitive(ctx, argv[0], HINT_NONE);\n        if (JS_IsString(v)) {\n            dv = js_Date_parse(ctx, JS_UNDEFINED, 1, (JSValueConst *)&v);\n            JS_FreeValue(ctx, v);\n            if (JS_IsException(dv))\n                return JS_EXCEPTION;\n            if (JS_ToFloat64Free(ctx, &val, dv))\n                return JS_EXCEPTION;\n        } else {\n            if (JS_ToFloat64Free(ctx, &val, v))\n                return JS_EXCEPTION;\n        }\n        val = time_clip(val);\n    } else {\n        double fields[] = { 0, 0, 1, 0, 0, 0, 0 };\n        if (n > 7)\n            n = 7;\n        for(i = 0; i < n; i++) {\n            if (JS_ToFloat64(ctx, &fields[i], argv[i]))\n                return JS_EXCEPTION;\n        }\n        val = set_date_fields_checked(fields, 1);\n    }\nhas_val:\n#if 0\n    JSValueConst args[3];\n    args[0] = new_target;\n    args[1] = ctx->class_proto[JS_CLASS_DATE];\n    args[2] = JS_NewFloat64(ctx, val);\n    rv = js___date_create(ctx, JS_UNDEFINED, 3, args);\n#else\n    rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);\n    if (!JS_IsException(rv))\n        JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));\n#endif\n    if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {\n        /* invoked as a function, return (new Date()).toString(); */\n        JSValue s;\n        s = get_date_string(ctx, rv, 0, NULL, 0x13);\n        JS_FreeValue(ctx, rv);\n        rv = s;\n    }\n    return rv;\n}\n\nstatic JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    // UTC(y, mon, d, h, m, s, ms)\n    double fields[] = { 0, 0, 1, 0, 0, 0, 0 };\n    int i, n;\n\n    n = argc;\n    if (n == 0)\n        return JS_NAN;\n    if (n > 7)\n        n = 7;\n    for(i = 0; i < n; i++) {\n        if (JS_ToFloat64(ctx, &fields[i], argv[i]))\n            return JS_EXCEPTION;\n    }\n    return JS_NewFloat64(ctx, set_date_fields_checked(fields, 0));\n}\n\n/* Date string parsing */\n\nstatic BOOL string_skip_char(const uint8_t *sp, int *pp, int c) {\n    if (sp[*pp] == c) {\n        *pp += 1;\n        return TRUE;\n    } else {\n        return FALSE;\n    }\n}\n\n/* skip spaces, update offset, return next char */\nstatic int string_skip_spaces(const uint8_t *sp, int *pp) {\n    int c;\n    while ((c = sp[*pp]) == ' ')\n        *pp += 1;\n    return c;\n}\n\n/* skip dashes dots and commas */\nstatic int string_skip_separators(const uint8_t *sp, int *pp) {\n    int c;\n    while ((c = sp[*pp]) == '-' || c == '/' || c == '.' || c == ',')\n        *pp += 1;\n    return c;\n}\n\n/* skip a word, stop on spaces, digits and separators, update offset */\nstatic int string_skip_until(const uint8_t *sp, int *pp, const char *stoplist) {\n    int c;\n    while (!strchr(stoplist, c = sp[*pp]))\n        *pp += 1;\n    return c;\n}\n\n/* parse a numeric field (max_digits = 0 -> no maximum) */\nstatic BOOL string_get_digits(const uint8_t *sp, int *pp, int *pval,\n                              int min_digits, int max_digits)\n{\n    int v = 0;\n    int c, p = *pp, p_start;\n\n    p_start = p;\n    while ((c = sp[p]) >= '0' && c <= '9') {\n        /* arbitrary limit to 9 digits */\n        if (v >= 100000000)\n            return FALSE;\n        v = v * 10 + c - '0';\n        p++;\n        if (p - p_start == max_digits)\n            break;\n    }\n    if (p - p_start < min_digits)\n        return FALSE;\n    *pval = v;\n    *pp = p;\n    return TRUE;\n}\n\nstatic BOOL string_get_milliseconds(const uint8_t *sp, int *pp, int *pval) {\n    /* parse optional fractional part as milliseconds and truncate. */\n    /* spec does not indicate which rounding should be used */\n    int mul = 100, ms = 0, c, p_start, p = *pp;\n\n    c = sp[p];\n    if (c == '.' || c == ',') {\n        p++;\n        p_start = p;\n        while ((c = sp[p]) >= '0' && c <= '9') {\n            ms += (c - '0') * mul;\n            mul /= 10;\n            p++;\n            if (p - p_start == 9)\n                break;\n        }\n        if (p > p_start) {\n            /* only consume the separator if digits are present */\n            *pval = ms;\n            *pp = p;\n        }\n    }\n    return TRUE;\n}\n\nstatic uint8_t upper_ascii(uint8_t c) {\n    return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;\n}\n\nstatic BOOL string_get_tzoffset(const uint8_t *sp, int *pp, int *tzp, BOOL strict) {\n    int tz = 0, sgn, hh, mm, p = *pp;\n\n    sgn = sp[p++];\n    if (sgn == '+' || sgn == '-') {\n        int n = p;\n        if (!string_get_digits(sp, &p, &hh, 1, 0))\n            return FALSE;\n        n = p - n;\n        if (strict && n != 2 && n != 4)\n            return FALSE;\n        while (n > 4) {\n            n -= 2;\n            hh /= 100;\n        }\n        if (n > 2) {\n            mm = hh % 100;\n            hh = hh / 100;\n        } else {\n            mm = 0;\n            if (string_skip_char(sp, &p, ':')) {\n                /* optional separator */\n                if (!string_get_digits(sp, &p, &mm, 2, 2))\n                    return FALSE;\n            } else {\n                if (strict)\n                    return FALSE; /* [+-]HH is not accepted in strict mode */\n            }\n        }\n        if (hh > 23 || mm > 59)\n            return FALSE;\n        tz = hh * 60 + mm;\n        if (sgn != '+')\n            tz = -tz;\n    } else\n    if (sgn != 'Z') {\n        return FALSE;\n    }\n    *pp = p;\n    *tzp = tz;\n    return TRUE;\n}\n\nstatic BOOL string_match(const uint8_t *sp, int *pp, const char *s) {\n    int p = *pp;\n    while (*s != '\\0') {\n        if (upper_ascii(sp[p]) != upper_ascii(*s++))\n            return FALSE;\n        p++;\n    }\n    *pp = p;\n    return TRUE;\n}\n\nstatic int find_abbrev(const uint8_t *sp, int p, const char *list, int count) {\n    int n, i;\n\n    for (n = 0; n < count; n++) {\n        for (i = 0;; i++) {\n            if (upper_ascii(sp[p + i]) != upper_ascii(list[n * 3 + i]))\n                break;\n            if (i == 2)\n                return n;\n        }\n    }\n    return -1;\n}\n\nstatic BOOL string_get_month(const uint8_t *sp, int *pp, int *pval) {\n    int n;\n\n    n = find_abbrev(sp, *pp, month_names, 12);\n    if (n < 0)\n        return FALSE;\n\n    *pval = n + 1;\n    *pp += 3;\n    return TRUE;\n}\n\n/* parse toISOString format */\nstatic BOOL js_date_parse_isostring(const uint8_t *sp, int fields[9], BOOL *is_local) {\n    int sgn, i, p = 0;\n\n    /* initialize fields to the beginning of the Epoch */\n    for (i = 0; i < 9; i++) {\n        fields[i] = (i == 2);\n    }\n    *is_local = FALSE;\n\n    /* year is either yyyy digits or [+-]yyyyyy */\n    sgn = sp[p];\n    if (sgn == '-' || sgn == '+') {\n        p++;\n        if (!string_get_digits(sp, &p, &fields[0], 6, 6))\n            return FALSE;\n        if (sgn == '-') {\n            if (fields[0] == 0)\n                return FALSE; // reject -000000\n            fields[0] = -fields[0];\n        }\n    } else {\n        if (!string_get_digits(sp, &p, &fields[0], 4, 4))\n            return FALSE;\n    }\n    if (string_skip_char(sp, &p, '-')) {\n        if (!string_get_digits(sp, &p, &fields[1], 2, 2))  /* month */\n            return FALSE;\n        if (fields[1] < 1)\n            return FALSE;\n        fields[1] -= 1;\n        if (string_skip_char(sp, &p, '-')) {\n            if (!string_get_digits(sp, &p, &fields[2], 2, 2))  /* day */\n                return FALSE;\n            if (fields[2] < 1)\n                return FALSE;\n        }\n    }\n    if (string_skip_char(sp, &p, 'T')) {\n        *is_local = TRUE;\n        if (!string_get_digits(sp, &p, &fields[3], 2, 2)  /* hour */\n        ||  !string_skip_char(sp, &p, ':')\n        ||  !string_get_digits(sp, &p, &fields[4], 2, 2)) {  /* minute */\n            fields[3] = 100;  // reject unconditionally\n            return TRUE;\n        }\n        if (string_skip_char(sp, &p, ':')) {\n            if (!string_get_digits(sp, &p, &fields[5], 2, 2))  /* second */\n                return FALSE;\n            string_get_milliseconds(sp, &p, &fields[6]);\n        }\n    }\n    /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */\n    if (sp[p]) {\n        *is_local = FALSE;\n        if (!string_get_tzoffset(sp, &p, &fields[8], TRUE))\n            return FALSE;\n    }\n    /* error if extraneous characters */\n    return sp[p] == '\\0';\n}\n\nstatic struct {\n    char name[6];\n    int16_t offset;\n} const js_tzabbr[] = {\n    { \"GMT\",   0 },         // Greenwich Mean Time\n    { \"UTC\",   0 },         // Coordinated Universal Time\n    { \"UT\",    0 },         // Universal Time\n    { \"Z\",     0 },         // Zulu Time\n    { \"EDT\",  -4 * 60 },    // Eastern Daylight Time\n    { \"EST\",  -5 * 60 },    // Eastern Standard Time\n    { \"CDT\",  -5 * 60 },    // Central Daylight Time\n    { \"CST\",  -6 * 60 },    // Central Standard Time\n    { \"MDT\",  -6 * 60 },    // Mountain Daylight Time\n    { \"MST\",  -7 * 60 },    // Mountain Standard Time\n    { \"PDT\",  -7 * 60 },    // Pacific Daylight Time\n    { \"PST\",  -8 * 60 },    // Pacific Standard Time\n    { \"WET\",  +0 * 60 },    // Western European Time\n    { \"WEST\", +1 * 60 },    // Western European Summer Time\n    { \"CET\",  +1 * 60 },    // Central European Time\n    { \"CEST\", +2 * 60 },    // Central European Summer Time\n    { \"EET\",  +2 * 60 },    // Eastern European Time\n    { \"EEST\", +3 * 60 },    // Eastern European Summer Time\n};\n\nstatic BOOL string_get_tzabbr(const uint8_t *sp, int *pp, int *offset) {\n    for (size_t i = 0; i < countof(js_tzabbr); i++) {\n        if (string_match(sp, pp, js_tzabbr[i].name)) {\n            *offset = js_tzabbr[i].offset;\n            return TRUE;\n        }\n    }\n    return FALSE;\n}\n\n/* parse toString, toUTCString and other formats */\nstatic BOOL js_date_parse_otherstring(const uint8_t *sp,\n                                      int fields[minimum_length(9)],\n                                      BOOL *is_local) {\n    int c, i, val, p = 0, p_start;\n    int num[3];\n    BOOL has_year = FALSE;\n    BOOL has_mon = FALSE;\n    BOOL has_time = FALSE;\n    int num_index = 0;\n\n    /* initialize fields to the beginning of 2001-01-01 */\n    fields[0] = 2001;\n    fields[1] = 1;\n    fields[2] = 1;\n    for (i = 3; i < 9; i++) {\n        fields[i] = 0;\n    }\n    *is_local = TRUE;\n\n    while (string_skip_spaces(sp, &p)) {\n        p_start = p;\n        if ((c = sp[p]) == '+' || c == '-') {\n            if (has_time && string_get_tzoffset(sp, &p, &fields[8], FALSE)) {\n                *is_local = FALSE;\n            } else {\n                p++;\n                if (string_get_digits(sp, &p, &val, 1, 0)) {\n                    if (c == '-') {\n                        if (val == 0)\n                            return FALSE;\n                        val = -val;\n                    }\n                    fields[0] = val;\n                    has_year = TRUE;\n                }\n            }\n        } else\n        if (string_get_digits(sp, &p, &val, 1, 0)) {\n            if (string_skip_char(sp, &p, ':')) {\n                /* time part */\n                fields[3] = val;\n                if (!string_get_digits(sp, &p, &fields[4], 1, 2))\n                    return FALSE;\n                if (string_skip_char(sp, &p, ':')) {\n                    if (!string_get_digits(sp, &p, &fields[5], 1, 2))\n                        return FALSE;\n                    string_get_milliseconds(sp, &p, &fields[6]);\n                }\n                has_time = TRUE;\n                if ((sp[p] == '+' || sp[p] == '-') &&\n                    string_get_tzoffset(sp, &p, &fields[8], FALSE)) {\n                    *is_local = FALSE;\n                }\n            } else {\n                if (p - p_start > 2 && !has_year) {\n                    fields[0] = val;\n                    has_year = TRUE;\n                } else\n                if ((val < 1 || val > 31) && !has_year) {\n                    fields[0] = val + (val < 100) * 1900 + (val < 50) * 100;\n                    has_year = TRUE;\n                } else {\n                    if (num_index == 3)\n                        return FALSE;\n                    num[num_index++] = val;\n                }\n            }\n        } else\n        if (string_get_month(sp, &p, &fields[1])) {\n            has_mon = TRUE;\n            string_skip_until(sp, &p, \"0123456789 -/(\");\n        } else\n        if (has_time && string_match(sp, &p, \"PM\")) {\n            if (fields[3] < 12)\n                fields[3] += 12;\n            continue;\n        } else\n        if (has_time && string_match(sp, &p, \"AM\")) {\n            if (fields[3] == 12)\n                fields[3] -= 12;\n            continue;\n        } else\n        if (string_get_tzabbr(sp, &p, &fields[8])) {\n            *is_local = FALSE;\n            continue;\n        } else\n        if (c == '(') {  /* skip parenthesized phrase */\n            int level = 0;\n            while ((c = sp[p]) != '\\0') {\n                p++;\n                level += (c == '(');\n                level -= (c == ')');\n                if (!level)\n                    break;\n            }\n            if (level > 0)\n                return FALSE;\n        } else\n        if (c == ')') {\n            return FALSE;\n        } else {\n            if (has_year + has_mon + has_time + num_index)\n                return FALSE;\n            /* skip a word */\n            string_skip_until(sp, &p, \" -/(\");\n        }\n        string_skip_separators(sp, &p);\n    }\n    if (num_index + has_year + has_mon > 3)\n        return FALSE;\n\n    switch (num_index) {\n    case 0:\n        if (!has_year)\n            return FALSE;\n        break;\n    case 1:\n        if (has_mon)\n            fields[2] = num[0];\n        else\n            fields[1] = num[0];\n        break;\n    case 2:\n        if (has_year) {\n            fields[1] = num[0];\n            fields[2] = num[1];\n        } else\n        if (has_mon) {\n            fields[0] = num[1] + (num[1] < 100) * 1900 + (num[1] < 50) * 100;\n            fields[2] = num[0];\n        } else {\n            fields[1] = num[0];\n            fields[2] = num[1];\n        }\n        break;\n    case 3:\n        fields[0] = num[2] + (num[2] < 100) * 1900 + (num[2] < 50) * 100;\n        fields[1] = num[0];\n        fields[2] = num[1];\n        break;\n    default:\n        return FALSE;\n    }\n    if (fields[1] < 1 || fields[2] < 1)\n        return FALSE;\n    fields[1] -= 1;\n    return TRUE;\n}\n\nstatic JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    JSValue s, rv;\n    int fields[9];\n    double fields1[9];\n    double d;\n    int i, c;\n    JSString *sp;\n    uint8_t buf[128];\n    BOOL is_local;\n\n    rv = JS_NAN;\n\n    s = JS_ToString(ctx, argv[0]);\n    if (JS_IsException(s))\n        return JS_EXCEPTION;\n\n    sp = JS_VALUE_GET_STRING(s);\n    /* convert the string as a byte array */\n    for (i = 0; i < sp->len && i < (int)countof(buf) - 1; i++) {\n        c = string_get(sp, i);\n        if (c > 255)\n            c = (c == 0x2212) ? '-' : 'x';\n        buf[i] = c;\n    }\n    buf[i] = '\\0';\n    if (js_date_parse_isostring(buf, fields, &is_local)\n    ||  js_date_parse_otherstring(buf, fields, &is_local)) {\n        static int const field_max[6] = { 0, 11, 31, 24, 59, 59 };\n        BOOL valid = TRUE;\n        /* check field maximum values */\n        for (i = 1; i < 6; i++) {\n            if (fields[i] > field_max[i])\n                valid = FALSE;\n        }\n        /* special case 24:00:00.000 */\n        if (fields[3] == 24 && (fields[4] | fields[5] | fields[6]))\n            valid = FALSE;\n        if (valid) {\n            for(i = 0; i < 7; i++)\n                fields1[i] = fields[i];\n            d = set_date_fields(fields1, is_local) - fields[8] * 60000;\n            rv = JS_NewFloat64(ctx, d);\n        }\n    }\n    JS_FreeValue(ctx, s);\n    return rv;\n}\n\nstatic JSValue js_Date_now(JSContext *ctx, JSValueConst this_val,\n                           int argc, JSValueConst *argv)\n{\n    // now()\n    return JS_NewInt64(ctx, date_now());\n}\n\nstatic JSValue js_date_Symbol_toPrimitive(JSContext *ctx, JSValueConst this_val,\n                                          int argc, JSValueConst *argv)\n{\n    // Symbol_toPrimitive(hint)\n    JSValueConst obj = this_val;\n    JSAtom hint = JS_ATOM_NULL;\n    int hint_num;\n\n    if (!JS_IsObject(obj))\n        return JS_ThrowTypeErrorNotAnObject(ctx);\n\n    if (JS_IsString(argv[0])) {\n        hint = JS_ValueToAtom(ctx, argv[0]);\n        if (hint == JS_ATOM_NULL)\n            return JS_EXCEPTION;\n        JS_FreeAtom(ctx, hint);\n    }\n    switch (hint) {\n    case JS_ATOM_number:\n    case JS_ATOM_integer:\n        hint_num = HINT_NUMBER;\n        break;\n    case JS_ATOM_string:\n    case JS_ATOM_default:\n        hint_num = HINT_STRING;\n        break;\n    default:\n        return JS_ThrowTypeError(ctx, \"invalid hint\");\n    }\n    return JS_ToPrimitive(ctx, obj, hint_num | HINT_FORCE_ORDINARY);\n}\n\nstatic JSValue js_date_getTimezoneOffset(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    // getTimezoneOffset()\n    double v;\n\n    if (JS_ThisTimeValue(ctx, &v, this_val))\n        return JS_EXCEPTION;\n    if (isnan(v))\n        return JS_NAN;\n    else\n        /* assuming -8.64e15 <= v <= -8.64e15 */\n        return JS_NewInt64(ctx, getTimezoneOffset((int64_t)trunc(v)));\n}\n\nstatic JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    // getTime()\n    double v;\n\n    if (JS_ThisTimeValue(ctx, &v, this_val))\n        return JS_EXCEPTION;\n    return JS_NewFloat64(ctx, v);\n}\n\nstatic JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    // setTime(v)\n    double v;\n\n    if (JS_ThisTimeValue(ctx, &v, this_val) || JS_ToFloat64(ctx, &v, argv[0]))\n        return JS_EXCEPTION;\n    return JS_SetThisTimeValue(ctx, this_val, time_clip(v));\n}\n\nstatic JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,\n                               int argc, JSValueConst *argv)\n{\n    // setYear(y)\n    double y;\n    JSValueConst args[1];\n\n    if (JS_ThisTimeValue(ctx, &y, this_val) || JS_ToFloat64(ctx, &y, argv[0]))\n        return JS_EXCEPTION;\n    y = +y;\n    if (isfinite(y)) {\n        y = trunc(y);\n        if (y >= 0 && y < 100)\n            y += 1900;\n    }\n    args[0] = JS_NewFloat64(ctx, y);\n    return set_date_field(ctx, this_val, 1, args, 0x011);\n}\n\nstatic JSValue js_date_toJSON(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    // toJSON(key)\n    JSValue obj, tv, method, rv;\n    double d;\n\n    rv = JS_EXCEPTION;\n    tv = JS_UNDEFINED;\n\n    obj = JS_ToObject(ctx, this_val);\n    tv = JS_ToPrimitive(ctx, obj, HINT_NUMBER);\n    if (JS_IsException(tv))\n        goto exception;\n    if (JS_IsNumber(tv)) {\n        if (JS_ToFloat64(ctx, &d, tv) < 0)\n            goto exception;\n        if (!isfinite(d)) {\n            rv = JS_NULL;\n            goto done;\n        }\n    }\n    method = JS_GetPropertyStr(ctx, obj, \"toISOString\");\n    if (JS_IsException(method))\n        goto exception;\n    if (!JS_IsFunction(ctx, method)) {\n        JS_ThrowTypeError(ctx, \"object needs toISOString method\");\n        JS_FreeValue(ctx, method);\n        goto exception;\n    }\n    rv = JS_CallFree(ctx, method, obj, 0, NULL);\nexception:\ndone:\n    JS_FreeValue(ctx, obj);\n    JS_FreeValue(ctx, tv);\n    return rv;\n}\n\nstatic const JSCFunctionListEntry js_date_funcs[] = {\n    JS_CFUNC_DEF(\"now\", 0, js_Date_now ),\n    JS_CFUNC_DEF(\"parse\", 1, js_Date_parse ),\n    JS_CFUNC_DEF(\"UTC\", 7, js_Date_UTC ),\n};\n\nstatic const JSCFunctionListEntry js_date_proto_funcs[] = {\n    JS_CFUNC_DEF(\"valueOf\", 0, js_date_getTime ),\n    JS_CFUNC_MAGIC_DEF(\"toString\", 0, get_date_string, 0x13 ),\n    JS_CFUNC_DEF(\"[Symbol.toPrimitive]\", 1, js_date_Symbol_toPrimitive ),\n    JS_CFUNC_MAGIC_DEF(\"toUTCString\", 0, get_date_string, 0x03 ),\n    JS_ALIAS_DEF(\"toGMTString\", \"toUTCString\" ),\n    JS_CFUNC_MAGIC_DEF(\"toISOString\", 0, get_date_string, 0x23 ),\n    JS_CFUNC_MAGIC_DEF(\"toDateString\", 0, get_date_string, 0x11 ),\n    JS_CFUNC_MAGIC_DEF(\"toTimeString\", 0, get_date_string, 0x12 ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleString\", 0, get_date_string, 0x33 ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleDateString\", 0, get_date_string, 0x31 ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleTimeString\", 0, get_date_string, 0x32 ),\n    JS_CFUNC_DEF(\"getTimezoneOffset\", 0, js_date_getTimezoneOffset ),\n    JS_CFUNC_DEF(\"getTime\", 0, js_date_getTime ),\n    JS_CFUNC_MAGIC_DEF(\"getYear\", 0, get_date_field, 0x101 ),\n    JS_CFUNC_MAGIC_DEF(\"getFullYear\", 0, get_date_field, 0x01 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCFullYear\", 0, get_date_field, 0x00 ),\n    JS_CFUNC_MAGIC_DEF(\"getMonth\", 0, get_date_field, 0x11 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCMonth\", 0, get_date_field, 0x10 ),\n    JS_CFUNC_MAGIC_DEF(\"getDate\", 0, get_date_field, 0x21 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCDate\", 0, get_date_field, 0x20 ),\n    JS_CFUNC_MAGIC_DEF(\"getHours\", 0, get_date_field, 0x31 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCHours\", 0, get_date_field, 0x30 ),\n    JS_CFUNC_MAGIC_DEF(\"getMinutes\", 0, get_date_field, 0x41 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCMinutes\", 0, get_date_field, 0x40 ),\n    JS_CFUNC_MAGIC_DEF(\"getSeconds\", 0, get_date_field, 0x51 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCSeconds\", 0, get_date_field, 0x50 ),\n    JS_CFUNC_MAGIC_DEF(\"getMilliseconds\", 0, get_date_field, 0x61 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCMilliseconds\", 0, get_date_field, 0x60 ),\n    JS_CFUNC_MAGIC_DEF(\"getDay\", 0, get_date_field, 0x71 ),\n    JS_CFUNC_MAGIC_DEF(\"getUTCDay\", 0, get_date_field, 0x70 ),\n    JS_CFUNC_DEF(\"setTime\", 1, js_date_setTime ),\n    JS_CFUNC_MAGIC_DEF(\"setMilliseconds\", 1, set_date_field, 0x671 ),\n    JS_CFUNC_MAGIC_DEF(\"setUTCMilliseconds\", 1, set_date_field, 0x670 ),\n    JS_CFUNC_MAGIC_DEF(\"setSeconds\", 2, set_date_field, 0x571 ),\n    JS_CFUNC_MAGIC_DEF(\"setUTCSeconds\", 2, set_date_field, 0x570 ),\n    JS_CFUNC_MAGIC_DEF(\"setMinutes\", 3, set_date_field, 0x471 ),\n    JS_CFUNC_MAGIC_DEF(\"setUTCMinutes\", 3, set_date_field, 0x470 ),\n    JS_CFUNC_MAGIC_DEF(\"setHours\", 4, set_date_field, 0x371 ),\n    JS_CFUNC_MAGIC_DEF(\"setUTCHours\", 4, set_date_field, 0x370 ),\n    JS_CFUNC_MAGIC_DEF(\"setDate\", 1, set_date_field, 0x231 ),\n    JS_CFUNC_MAGIC_DEF(\"setUTCDate\", 1, set_date_field, 0x230 ),\n    JS_CFUNC_MAGIC_DEF(\"setMonth\", 2, set_date_field, 0x131 ),\n    JS_CFUNC_MAGIC_DEF(\"setUTCMonth\", 2, set_date_field, 0x130 ),\n    JS_CFUNC_DEF(\"setYear\", 1, js_date_setYear ),\n    JS_CFUNC_MAGIC_DEF(\"setFullYear\", 3, set_date_field, 0x031 ),\n    JS_CFUNC_MAGIC_DEF(\"setUTCFullYear\", 3, set_date_field, 0x030 ),\n    JS_CFUNC_DEF(\"toJSON\", 1, js_date_toJSON ),\n};\n\nJSValue JS_NewDate(JSContext *ctx, double epoch_ms)\n{\n    JSValue obj = js_create_from_ctor(ctx, JS_UNDEFINED, JS_CLASS_DATE);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    JS_SetObjectData(ctx, obj, __JS_NewFloat64(ctx, time_clip(epoch_ms)));\n    return obj;\n}\n\nint JS_AddIntrinsicDate(JSContext *ctx)\n{\n    JSValue obj;\n\n    /* Date */\n    obj = JS_NewCConstructor(ctx, JS_CLASS_DATE, \"Date\",\n                                    js_date_constructor, 7, JS_CFUNC_constructor_or_func, 0,\n                                    JS_UNDEFINED,\n                                    js_date_funcs, countof(js_date_funcs),\n                                    js_date_proto_funcs, countof(js_date_proto_funcs),\n                                    0);\n    if (JS_IsException(obj))\n        return -1;\n    JS_FreeValue(ctx, obj);\n    return 0;\n}\n\n/* eval */\n\nint JS_AddIntrinsicEval(JSContext *ctx)\n{\n    ctx->eval_internal = __JS_EvalInternal;\n    return 0;\n}\n\n/* BigInt */\n\nstatic JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)\n{\n    uint32_t tag;\n\n redo:\n    tag = JS_VALUE_GET_NORM_TAG(val);\n    switch(tag) {\n    case JS_TAG_INT:\n    case JS_TAG_BOOL:\n        val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));\n        break;\n    case JS_TAG_SHORT_BIG_INT:\n    case JS_TAG_BIG_INT:\n        break;\n    case JS_TAG_FLOAT64:\n        {\n            double d = JS_VALUE_GET_FLOAT64(val);\n            JSBigInt *r;\n            int res;\n            r = js_bigint_from_float64(ctx, &res, d);\n            if (!r) {\n                if (res == 0) {\n                    val = JS_EXCEPTION;\n                } else if (res == 1) {\n                    val = JS_ThrowRangeError(ctx, \"cannot convert to BigInt: not an integer\");\n                } else {\n                    val = JS_ThrowRangeError(ctx, \"cannot convert NaN or Infinity to BigInt\");                }\n            } else {\n                val = JS_CompactBigInt(ctx, r);\n            }\n        }\n        break;\n    case JS_TAG_STRING:\n    case JS_TAG_STRING_ROPE:\n        val = JS_StringToBigIntErr(ctx, val);\n        break;\n    case JS_TAG_OBJECT:\n        val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);\n        if (JS_IsException(val))\n            break;\n        goto redo;\n    case JS_TAG_NULL:\n    case JS_TAG_UNDEFINED:\n    default:\n        JS_FreeValue(ctx, val);\n        return JS_ThrowTypeError(ctx, \"cannot convert to BigInt\");\n    }\n    return val;\n}\n\nstatic JSValue js_bigint_constructor(JSContext *ctx,\n                                     JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    if (!JS_IsUndefined(new_target))\n        return JS_ThrowTypeErrorNotAConstructor(ctx, new_target);\n    return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));\n}\n\nstatic JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)\n{\n    if (JS_IsBigInt(ctx, this_val))\n        return JS_DupValue(ctx, this_val);\n\n    if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {\n        JSObject *p = JS_VALUE_GET_OBJ(this_val);\n        if (p->class_id == JS_CLASS_BIG_INT) {\n            if (JS_IsBigInt(ctx, p->u.object_data))\n                return JS_DupValue(ctx, p->u.object_data);\n        }\n    }\n    return JS_ThrowTypeError(ctx, \"not a BigInt\");\n}\n\nstatic JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValue val;\n    int base;\n    JSValue ret;\n\n    val = js_thisBigIntValue(ctx, this_val);\n    if (JS_IsException(val))\n        return val;\n    if (argc == 0 || JS_IsUndefined(argv[0])) {\n        base = 10;\n    } else {\n        base = js_get_radix(ctx, argv[0]);\n        if (base < 0)\n            goto fail;\n    }\n    ret = js_bigint_to_string1(ctx, val, base);\n    JS_FreeValue(ctx, val);\n    return ret;\n fail:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_bigint_valueOf(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    return js_thisBigIntValue(ctx, this_val);\n}\n\nstatic JSValue js_bigint_asUintN(JSContext *ctx,\n                                  JSValueConst this_val,\n                                  int argc, JSValueConst *argv, int asIntN)\n{\n    uint64_t bits;\n    JSValue res, a;\n    \n    if (JS_ToIndex(ctx, &bits, argv[0]))\n        return JS_EXCEPTION;\n    a = JS_ToBigInt(ctx, argv[1]);\n    if (JS_IsException(a))\n        return JS_EXCEPTION;\n    if (bits == 0) {\n        JS_FreeValue(ctx, a);\n        res = __JS_NewShortBigInt(ctx, 0);\n    } else if (JS_VALUE_GET_TAG(a) == JS_TAG_SHORT_BIG_INT) {\n        /* fast case */\n        if (bits >= JS_SHORT_BIG_INT_BITS) {\n            res = a;\n        } else {\n            uint64_t v;\n            int shift;\n            shift = 64 - bits;\n            v = JS_VALUE_GET_SHORT_BIG_INT(a);\n            v = v << shift;\n            if (asIntN)\n                v = (int64_t)v >> shift;\n            else\n                v = v >> shift;\n            res = __JS_NewShortBigInt(ctx, v);\n        }\n    } else {\n        JSBigInt *r, *p = JS_VALUE_GET_PTR(a);\n        if (bits >= p->len * JS_LIMB_BITS) {\n            res = a;\n        } else {\n            int len, shift, i;\n            js_limb_t v;\n            len = (bits + JS_LIMB_BITS - 1) / JS_LIMB_BITS;\n            r = js_bigint_new(ctx, len);\n            if (!r) {\n                JS_FreeValue(ctx, a);\n                return JS_EXCEPTION;\n            }\n            r->len = len;\n            for(i = 0; i < len - 1; i++)\n                r->tab[i] = p->tab[i];\n            shift = (-bits) & (JS_LIMB_BITS - 1);\n            /* 0 <= shift <= JS_LIMB_BITS - 1 */\n            v = p->tab[len - 1] << shift;\n            if (asIntN)\n                v = (js_slimb_t)v >> shift;\n            else\n                v = v >> shift;\n            r->tab[len - 1] = v;\n            r = js_bigint_normalize(ctx, r);\n            JS_FreeValue(ctx, a);\n            res = JS_CompactBigInt(ctx, r);\n        }\n    }\n    return res;\n}\n\nstatic const JSCFunctionListEntry js_bigint_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"asUintN\", 2, js_bigint_asUintN, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"asIntN\", 2, js_bigint_asUintN, 1 ),\n};\n\nstatic const JSCFunctionListEntry js_bigint_proto_funcs[] = {\n    JS_CFUNC_DEF(\"toString\", 0, js_bigint_toString ),\n    JS_CFUNC_DEF(\"valueOf\", 0, js_bigint_valueOf ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"BigInt\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic int JS_AddIntrinsicBigInt(JSContext *ctx)\n{\n    JSValue obj1;\n\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_BIG_INT, \"BigInt\",\n                                     js_bigint_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                                     JS_UNDEFINED,\n                                     js_bigint_funcs, countof(js_bigint_funcs),\n                                     js_bigint_proto_funcs, countof(js_bigint_proto_funcs),\n                                     0);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    return 0;\n}\n\n/* Minimum amount of objects to be able to compile code and display\n   error messages. */\nstatic int JS_AddIntrinsicBasicObjects(JSContext *ctx)\n{\n    JSValue obj;\n    JSCFunctionType ft;\n    int i;\n\n    /* warning: ordering is tricky */\n    ctx->class_proto[JS_CLASS_OBJECT] =\n        JS_NewObjectProtoClassAlloc(ctx, JS_NULL, JS_CLASS_OBJECT,\n                                    countof(js_object_proto_funcs) + 1);\n    if (JS_IsException(ctx->class_proto[JS_CLASS_OBJECT]))\n        return -1;\n    JS_SetImmutablePrototype(ctx, ctx->class_proto[JS_CLASS_OBJECT]);\n\n    /* 2 more properties: caller and arguments */\n    ctx->function_proto = JS_NewCFunction3(ctx, js_function_proto, \"\", 0,\n                                           JS_CFUNC_generic, 0,\n                                           ctx->class_proto[JS_CLASS_OBJECT],\n                                           countof(js_function_proto_funcs) + 3 + 2);\n    if (JS_IsException(ctx->function_proto))\n        return -1;\n    ctx->class_proto[JS_CLASS_BYTECODE_FUNCTION] = JS_DupValue(ctx, ctx->function_proto);\n\n    ctx->global_obj = JS_NewObjectProtoClassAlloc(ctx, ctx->class_proto[JS_CLASS_OBJECT],\n                                                  JS_CLASS_GLOBAL_OBJECT, 64);\n    if (JS_IsException(ctx->global_obj))\n        return -1;\n    {\n        JSObject *p;\n        obj = JS_NewObjectProtoClassAlloc(ctx, JS_NULL, JS_CLASS_OBJECT, 4);\n        p = JS_VALUE_GET_OBJ(ctx->global_obj);\n        p->u.global_object.uninitialized_vars = obj;\n    }\n    ctx->global_var_obj = JS_NewObjectProtoClassAlloc(ctx, JS_NULL,\n                                                      JS_CLASS_OBJECT, 16);\n    if (JS_IsException(ctx->global_var_obj))\n        return -1;\n\n    /* Error */\n    ft.generic_magic = js_error_constructor;\n    obj = JS_NewCConstructor(ctx, JS_CLASS_ERROR, \"Error\",\n                                    ft.generic, 1, JS_CFUNC_constructor_or_func_magic, -1,\n                                    JS_UNDEFINED,\n                                    js_error_funcs, countof(js_error_funcs),\n                                    js_error_proto_funcs, countof(js_error_proto_funcs),\n                                    0);\n    if (JS_IsException(obj))\n        return -1;\n\n    for(i = 0; i < JS_NATIVE_ERROR_COUNT; i++) {\n        JSValue func_obj;\n        const JSCFunctionListEntry *funcs;\n        int n_args;\n        char buf[ATOM_GET_STR_BUF_SIZE];\n        const char *name = JS_AtomGetStr(ctx, buf, sizeof(buf),\n                                         JS_ATOM_EvalError + i);\n        n_args = 1 + (i == JS_AGGREGATE_ERROR);\n        funcs = js_native_error_proto_funcs + 2 * i;\n        func_obj = JS_NewCConstructor(ctx, -1, name,\n                                      ft.generic, n_args, JS_CFUNC_constructor_or_func_magic, i,\n                                      obj,\n                                      NULL, 0,\n                                      funcs, 2,\n                                      0);\n        if (JS_IsException(func_obj)) {\n            JS_FreeValue(ctx, obj);\n            return -1;\n        }\n        ctx->native_error_proto[i] = JS_GetProperty(ctx, func_obj, JS_ATOM_prototype);\n        JS_FreeValue(ctx, func_obj);\n        if (JS_IsException(ctx->native_error_proto[i])) {\n            JS_FreeValue(ctx, obj);\n            return -1;\n        }\n    }\n    JS_FreeValue(ctx, obj);\n\n    /* Array */\n    obj = JS_NewCConstructor(ctx, JS_CLASS_ARRAY, \"Array\",\n                                    js_array_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                                    JS_UNDEFINED,\n                                    js_array_funcs, countof(js_array_funcs),\n                                    js_array_proto_funcs, countof(js_array_proto_funcs),\n                                    JS_NEW_CTOR_PROTO_CLASS);\n    if (JS_IsException(obj))\n        return -1;\n    ctx->array_ctor = obj;\n\n    {\n        JSObject *p = JS_VALUE_GET_OBJ(ctx->class_proto[JS_CLASS_ARRAY]);\n        p->is_std_array_prototype = TRUE;\n    }\n    \n    ctx->array_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_ARRAY]),\n                                     JS_PROP_INITIAL_HASH_SIZE, 1);\n    if (!ctx->array_shape)\n        return -1;\n    if (add_shape_property(ctx, &ctx->array_shape, NULL,\n                           JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_LENGTH))\n        return -1;\n\n    ctx->arguments_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_OBJECT]),\n                                         JS_PROP_INITIAL_HASH_SIZE, 3);\n    if (!ctx->arguments_shape)\n        return -1;\n    if (add_shape_property(ctx, &ctx->arguments_shape, NULL,\n                           JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))\n        return -1;\n    if (add_shape_property(ctx, &ctx->arguments_shape, NULL,\n                           JS_ATOM_Symbol_iterator, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))\n        return -1;\n    if (add_shape_property(ctx, &ctx->arguments_shape, NULL,\n                           JS_ATOM_callee, JS_PROP_GETSET))\n        return -1;\n\n    ctx->mapped_arguments_shape = js_new_shape2(ctx, get_proto_obj(ctx->class_proto[JS_CLASS_OBJECT]),\n                                         JS_PROP_INITIAL_HASH_SIZE, 3);\n    if (!ctx->mapped_arguments_shape)\n        return -1;\n    if (add_shape_property(ctx, &ctx->mapped_arguments_shape, NULL,\n                           JS_ATOM_length, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))\n        return -1;\n    if (add_shape_property(ctx, &ctx->mapped_arguments_shape, NULL,\n                           JS_ATOM_Symbol_iterator, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))\n        return -1;\n    if (add_shape_property(ctx, &ctx->mapped_arguments_shape, NULL,\n                           JS_ATOM_callee, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE))\n        return -1;\n    \n    return 0;\n}\n\nint JS_AddIntrinsicBaseObjects(JSContext *ctx)\n{\n    JSValue obj1, obj2;\n    JSCFunctionType ft;\n\n    ctx->throw_type_error = JS_NewCFunction(ctx, js_throw_type_error, NULL, 0);\n    if (JS_IsException(ctx->throw_type_error))\n        return -1;\n    /* add caller and arguments properties to throw a TypeError */\n    if (JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_caller, JS_UNDEFINED,\n                          ctx->throw_type_error, ctx->throw_type_error,\n                          JS_PROP_HAS_GET | JS_PROP_HAS_SET |\n                          JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE) < 0)\n        return -1;\n    if (JS_DefineProperty(ctx, ctx->function_proto, JS_ATOM_arguments, JS_UNDEFINED,\n                          ctx->throw_type_error, ctx->throw_type_error,\n                          JS_PROP_HAS_GET | JS_PROP_HAS_SET |\n                          JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE) < 0)\n        return -1;\n    JS_FreeValue(ctx, js_object_seal(ctx, JS_UNDEFINED, 1, (JSValueConst *)&ctx->throw_type_error, 1));\n\n    /* Object */\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_OBJECT, \"Object\",\n                              js_object_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                              JS_UNDEFINED,\n                              js_object_funcs, countof(js_object_funcs),\n                              js_object_proto_funcs, countof(js_object_proto_funcs),\n                              JS_NEW_CTOR_PROTO_EXIST);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    \n    /* Function */\n    ft.generic_magic = js_function_constructor;\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_BYTECODE_FUNCTION, \"Function\",\n                              ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_NORMAL,\n                              JS_UNDEFINED,\n                              NULL, 0,\n                              js_function_proto_funcs, countof(js_function_proto_funcs),\n                              JS_NEW_CTOR_PROTO_EXIST);\n    if (JS_IsException(obj1))\n        return -1;\n    ctx->function_ctor = obj1;\n\n    /* Iterator */\n    obj2 = JS_NewCConstructor(ctx, JS_CLASS_ITERATOR, \"Iterator\",\n                                     js_iterator_constructor, 0, JS_CFUNC_constructor_or_func, 0,\n                                     JS_UNDEFINED,\n                                     js_iterator_funcs, countof(js_iterator_funcs),\n                                     js_iterator_proto_funcs, countof(js_iterator_proto_funcs),\n                                     0);\n    if (JS_IsException(obj2))\n        return -1;\n    // quirk: Iterator.prototype.constructor is an accessor property\n    // TODO(bnoordhuis) mildly inefficient because JS_NewGlobalCConstructor\n    // first creates a .constructor value property that we then replace with\n    // an accessor\n    obj1 = JS_NewCFunctionData(ctx, js_iterator_constructor_getset,\n                               0, 0, 1, (JSValueConst *)&obj2);\n    if (JS_IsException(obj1)) {\n        JS_FreeValue(ctx, obj2);\n        return -1;\n    }\n    if (JS_DefineProperty(ctx, ctx->class_proto[JS_CLASS_ITERATOR],\n                          JS_ATOM_constructor, JS_UNDEFINED,\n                          obj1, obj1,\n                          JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_CONFIGURABLE) < 0) {\n        JS_FreeValue(ctx, obj2);\n        JS_FreeValue(ctx, obj1);\n        return -1;\n    }\n    JS_FreeValue(ctx, obj1);\n    ctx->iterator_ctor = obj2;\n    \n    ctx->class_proto[JS_CLASS_ITERATOR_CONCAT] =\n        JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], \n                              js_iterator_concat_proto_funcs,\n                              countof(js_iterator_concat_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_ITERATOR_CONCAT]))\n        return -1;\n    ctx->class_proto[JS_CLASS_ITERATOR_HELPER] =\n        JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], \n                              js_iterator_helper_proto_funcs,\n                              countof(js_iterator_helper_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_ITERATOR_HELPER]))\n        return -1;\n                       \n    ctx->class_proto[JS_CLASS_ITERATOR_WRAP] =\n        JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], \n                              js_iterator_wrap_proto_funcs,\n                              countof(js_iterator_wrap_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_ITERATOR_WRAP]))\n        return -1;\n\n    /* needed to initialize arguments[Symbol.iterator] */\n    ctx->array_proto_values =\n        JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_values);\n    if (JS_IsException(ctx->array_proto_values))\n        return -1;\n\n    ctx->class_proto[JS_CLASS_ARRAY_ITERATOR] =\n        JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], \n                              js_array_iterator_proto_funcs,\n                              countof(js_array_iterator_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_ARRAY_ITERATOR]))\n        return -1;\n\n    /* parseFloat and parseInteger must be defined before Number\n       because of the Number.parseFloat and Number.parseInteger\n       aliases */\n    if (JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_global_funcs,\n                                   countof(js_global_funcs)))\n        return -1;\n\n    /* Number */\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_NUMBER, \"Number\",\n                                     js_number_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                                     JS_UNDEFINED,\n                                     js_number_funcs, countof(js_number_funcs),\n                                     js_number_proto_funcs, countof(js_number_proto_funcs),\n                                     JS_NEW_CTOR_PROTO_CLASS);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    if (JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_NUMBER], JS_NewInt32(ctx, 0)))\n        return -1;\n    \n    /* Boolean */\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_BOOLEAN, \"Boolean\",\n                                     js_boolean_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                                     JS_UNDEFINED,\n                                     NULL, 0,\n                                     js_boolean_proto_funcs, countof(js_boolean_proto_funcs),\n                                     JS_NEW_CTOR_PROTO_CLASS);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    if (JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_BOOLEAN], JS_NewBool(ctx, FALSE)))\n        return -1;\n\n    /* String */\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_STRING, \"String\",\n                                     js_string_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                                     JS_UNDEFINED,\n                                     js_string_funcs, countof(js_string_funcs),\n                                     js_string_proto_funcs, countof(js_string_proto_funcs),\n                                     JS_NEW_CTOR_PROTO_CLASS);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    if (JS_SetObjectData(ctx, ctx->class_proto[JS_CLASS_STRING], JS_AtomToString(ctx, JS_ATOM_empty_string)))\n        return -1;\n\n    ctx->class_proto[JS_CLASS_STRING_ITERATOR] =\n        JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR], \n                              js_string_iterator_proto_funcs,\n                              countof(js_string_iterator_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_STRING_ITERATOR]))\n        return -1;\n\n    /* Math: create as autoinit object */\n    js_random_init(ctx);\n    if (JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_math_obj, countof(js_math_obj)))\n        return -1;\n\n    /* ES6 Reflect: create as autoinit object */\n    if (JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_reflect_obj, countof(js_reflect_obj)))\n        return -1;\n\n    /* ES6 Symbol */\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_SYMBOL, \"Symbol\",\n                                     js_symbol_constructor, 0, JS_CFUNC_constructor_or_func, 0,\n                                     JS_UNDEFINED,\n                                     js_symbol_funcs, countof(js_symbol_funcs),\n                                     js_symbol_proto_funcs, countof(js_symbol_proto_funcs),\n                                     0);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    \n    /* ES6 Generator */\n    ctx->class_proto[JS_CLASS_GENERATOR] =\n        JS_NewObjectProtoList(ctx, ctx->class_proto[JS_CLASS_ITERATOR],\n                              js_generator_proto_funcs,\n                              countof(js_generator_proto_funcs));\n    if (JS_IsException(ctx->class_proto[JS_CLASS_GENERATOR]))\n        return -1;\n\n    ft.generic_magic = js_function_constructor;\n    obj1 = JS_NewCConstructor(ctx, JS_CLASS_GENERATOR_FUNCTION, \"GeneratorFunction\",\n                                     ft.generic, 1, JS_CFUNC_constructor_or_func_magic, JS_FUNC_GENERATOR,\n                                     ctx->function_ctor,\n                                     NULL, 0,\n                                     js_generator_function_proto_funcs,\n                                     countof(js_generator_function_proto_funcs),\n                                     JS_NEW_CTOR_NO_GLOBAL | JS_NEW_CTOR_READONLY);\n    if (JS_IsException(obj1))\n        return -1;\n    JS_FreeValue(ctx, obj1);\n    if (JS_SetConstructor2(ctx, ctx->class_proto[JS_CLASS_GENERATOR_FUNCTION],\n                           ctx->class_proto[JS_CLASS_GENERATOR],\n                           JS_PROP_CONFIGURABLE, JS_PROP_CONFIGURABLE))\n        return -1;\n    \n    /* global properties */\n    ctx->eval_obj = JS_GetProperty(ctx, ctx->global_obj, JS_ATOM_eval);\n    if (JS_IsException(ctx->eval_obj))\n        return -1;\n    \n    if (JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_globalThis,\n                               JS_DupValue(ctx, ctx->global_obj),\n                               JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE) < 0)\n        return -1;\n\n    /* BigInt */\n    if (JS_AddIntrinsicBigInt(ctx))\n        return -1;\n    return 0;\n}\n\n/* Typed Arrays */\n\nstatic uint8_t const typed_array_size_log2[JS_TYPED_ARRAY_COUNT] = {\n    0, 0, 0, 1, 1, 2, 2,\n    3, 3,                   // BigInt64Array, BigUint64Array\n    1, 2, 3                 // Float16Array, Float32Array, Float64Array\n};\n\nstatic JSValue js_array_buffer_constructor3(JSContext *ctx,\n                                            JSValueConst new_target,\n                                            uint64_t len, uint64_t *max_len,\n                                            JSClassID class_id,\n                                            uint8_t *buf,\n                                            JSFreeArrayBufferDataFunc *free_func,\n                                            void *opaque, BOOL alloc_flag)\n{\n    JSRuntime *rt = ctx->rt;\n    JSValue obj;\n    JSArrayBuffer *abuf = NULL;\n    uint64_t sab_alloc_len;\n\n    if (!alloc_flag && buf && max_len && free_func != js_array_buffer_free) {\n        // not observable from JS land, only through C API misuse;\n        // JS code cannot create externally managed buffers directly\n        return JS_ThrowInternalError(ctx,\n                                     \"resizable ArrayBuffers not supported \"\n                                     \"for externally managed buffers\");\n    }\n    obj = js_create_from_ctor(ctx, new_target, class_id);\n    if (JS_IsException(obj))\n        return obj;\n    /* XXX: we are currently limited to 2 GB */\n    if (len > INT32_MAX) {\n        JS_ThrowRangeError(ctx, \"invalid array buffer length\");\n        goto fail;\n    }\n    if (max_len && *max_len > INT32_MAX) {\n        JS_ThrowRangeError(ctx, \"invalid max array buffer length\");\n        goto fail;\n    }\n    abuf = js_malloc(ctx, sizeof(*abuf));\n    if (!abuf)\n        goto fail;\n    abuf->byte_length = len;\n    abuf->max_byte_length = max_len ? *max_len : -1;\n    if (alloc_flag) {\n        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&\n            rt->sab_funcs.sab_alloc) {\n            // TOOD(bnoordhuis) resizing backing memory for SABs atomically\n            // is hard so we cheat and allocate |maxByteLength| bytes upfront\n            sab_alloc_len = max_len ? *max_len : len;\n            abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,\n                                                 max_int(sab_alloc_len, 1));\n            if (!abuf->data)\n                goto fail;\n            memset(abuf->data, 0, sab_alloc_len);\n        } else {\n            /* the allocation must be done after the object creation */\n            abuf->data = js_mallocz(ctx, max_int(len, 1));\n            if (!abuf->data)\n                goto fail;\n        }\n    } else {\n        if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&\n            rt->sab_funcs.sab_dup) {\n            rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);\n        }\n        abuf->data = buf;\n    }\n    init_list_head(&abuf->array_list);\n    abuf->detached = FALSE;\n    abuf->shared = (class_id == JS_CLASS_SHARED_ARRAY_BUFFER);\n    abuf->opaque = opaque;\n    abuf->free_func = free_func;\n    if (alloc_flag && buf)\n        memcpy(abuf->data, buf, len);\n    JS_SetOpaque(obj, abuf);\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    js_free(ctx, abuf);\n    return JS_EXCEPTION;\n}\n\nstatic void js_array_buffer_free(JSRuntime *rt, void *opaque, void *ptr)\n{\n    js_free_rt(rt, ptr);\n}\n\nstatic JSValue js_array_buffer_constructor2(JSContext *ctx,\n                                            JSValueConst new_target,\n                                            uint64_t len, uint64_t *max_len,\n                                            JSClassID class_id)\n{\n    return js_array_buffer_constructor3(ctx, new_target, len, max_len, class_id,\n                                        NULL, js_array_buffer_free, NULL,\n                                        TRUE);\n}\n\nstatic JSValue js_array_buffer_constructor1(JSContext *ctx,\n                                            JSValueConst new_target,\n                                            uint64_t len, uint64_t *max_len)\n{\n    return js_array_buffer_constructor2(ctx, new_target, len, max_len,\n                                        JS_CLASS_ARRAY_BUFFER);\n}\n\nJSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,\n                          JSFreeArrayBufferDataFunc *free_func, void *opaque,\n                          BOOL is_shared)\n{\n    JSClassID class_id =\n        is_shared ? JS_CLASS_SHARED_ARRAY_BUFFER : JS_CLASS_ARRAY_BUFFER;\n    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL, class_id,\n                                        buf, free_func, opaque, FALSE);\n}\n\n/* create a new ArrayBuffer of length 'len' and copy 'buf' to it */\nJSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len)\n{\n    return js_array_buffer_constructor3(ctx, JS_UNDEFINED, len, NULL,\n                                        JS_CLASS_ARRAY_BUFFER,\n                                        (uint8_t *)buf,\n                                        js_array_buffer_free, NULL,\n                                        TRUE);\n}\n\nstatic JSValue js_array_buffer_constructor0(JSContext *ctx, JSValueConst new_target,\n                                            int argc, JSValueConst *argv,\n                                            JSClassID class_id)\n {\n    uint64_t len, max_len, *pmax_len = NULL;\n    JSValue obj, val;\n    int64_t i;\n\n     if (JS_ToIndex(ctx, &len, argv[0]))\n         return JS_EXCEPTION;\n    if (argc < 2)\n        goto next;\n    if (!JS_IsObject(argv[1]))\n        goto next;\n    obj = JS_ToObject(ctx, argv[1]);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    val = JS_GetProperty(ctx, obj, JS_ATOM_maxByteLength);\n    JS_FreeValue(ctx, obj);\n    if (JS_IsException(val))\n        return JS_EXCEPTION;\n    if (JS_IsUndefined(val))\n        goto next;\n    if (JS_ToInt64Free(ctx, &i, val))\n        return JS_EXCEPTION;\n    // don't have to check i < 0 because len >= 0\n    if (len > i || i > MAX_SAFE_INTEGER)\n        return JS_ThrowRangeError(ctx, \"invalid array buffer max length\");\n    max_len = i;\n    pmax_len = &max_len;\nnext:\n    return js_array_buffer_constructor2(ctx, new_target, len, pmax_len,\n                                        class_id);\n}\n\nstatic JSValue js_array_buffer_constructor(JSContext *ctx,\n                                           JSValueConst new_target,\n                                           int argc, JSValueConst *argv)\n{\n    return js_array_buffer_constructor0(ctx, new_target, argc, argv,\n                                        JS_CLASS_ARRAY_BUFFER);\n}\n\nstatic JSValue js_shared_array_buffer_constructor(JSContext *ctx,\n                                                  JSValueConst new_target,\n                                                  int argc, JSValueConst *argv)\n{\n    return js_array_buffer_constructor0(ctx, new_target, argc, argv,\n                                        JS_CLASS_SHARED_ARRAY_BUFFER);\n}\n\n/* also used for SharedArrayBuffer */\nstatic void js_array_buffer_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSArrayBuffer *abuf = p->u.array_buffer;\n    struct list_head *el, *el1;\n\n    if (abuf) {\n        /* The ArrayBuffer finalizer may be called before the typed\n           array finalizers using it, so abuf->array_list is not\n           necessarily empty. */\n        list_for_each_safe(el, el1, &abuf->array_list) {\n            JSTypedArray *ta;\n            JSObject *p1;\n\n            ta = list_entry(el, JSTypedArray, link);\n            ta->link.prev = NULL;\n            ta->link.next = NULL;\n            p1 = ta->obj;\n            /* Note: the typed array length and offset fields are not modified */\n            if (p1->class_id != JS_CLASS_DATAVIEW) {\n                p1->u.array.count = 0;\n                p1->u.array.u.ptr = NULL;\n            }\n        }\n        if (abuf->shared && rt->sab_funcs.sab_free) {\n            rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);\n        } else {\n            if (abuf->free_func)\n                abuf->free_func(rt, abuf->opaque, abuf->data);\n        }\n        js_free_rt(rt, abuf);\n    }\n}\n\nstatic JSValue js_array_buffer_isView(JSContext *ctx,\n                                      JSValueConst this_val,\n                                      int argc, JSValueConst *argv)\n{\n    JSObject *p;\n    BOOL res;\n    res = FALSE;\n    if (JS_VALUE_GET_TAG(argv[0]) == JS_TAG_OBJECT) {\n        p = JS_VALUE_GET_OBJ(argv[0]);\n        if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n            p->class_id <= JS_CLASS_DATAVIEW) {\n            res = TRUE;\n        }\n    }\n    return JS_NewBool(ctx, res);\n}\n\nstatic const JSCFunctionListEntry js_array_buffer_funcs[] = {\n    JS_CFUNC_DEF(\"isView\", 1, js_array_buffer_isView ),\n    JS_CGETSET_DEF(\"[Symbol.species]\", js_get_this, NULL ),\n};\n\nstatic JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx)\n{\n    return JS_ThrowTypeError(ctx, \"ArrayBuffer is detached\");\n}\n\nstatic JSValue JS_ThrowTypeErrorArrayBufferOOB(JSContext *ctx)\n{\n    return JS_ThrowTypeError(ctx, \"ArrayBuffer is detached or resized\");\n}\n\n// #sec-get-arraybuffer.prototype.detached\nstatic JSValue js_array_buffer_get_detached(JSContext *ctx,\n                                                 JSValueConst this_val)\n{\n    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER);\n    if (!abuf)\n        return JS_EXCEPTION;\n    if (abuf->shared)\n        return JS_ThrowTypeError(ctx, \"detached called on SharedArrayBuffer\");\n    return JS_NewBool(ctx, abuf->detached);\n}\n\nstatic JSValue js_array_buffer_get_byteLength(JSContext *ctx,\n                                              JSValueConst this_val,\n                                              int class_id)\n{\n    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);\n    if (!abuf)\n        return JS_EXCEPTION;\n    /* return 0 if detached */\n    return JS_NewUint32(ctx, abuf->byte_length);\n}\n\nstatic JSValue js_array_buffer_get_maxByteLength(JSContext *ctx,\n                                                 JSValueConst this_val,\n                                                 int class_id)\n{\n    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);\n    if (!abuf)\n        return JS_EXCEPTION;\n    if (array_buffer_is_resizable(abuf))\n        return JS_NewUint32(ctx, abuf->max_byte_length);\n    return JS_NewUint32(ctx, abuf->byte_length);\n}\n\nstatic JSValue js_array_buffer_get_resizable(JSContext *ctx,\n                                             JSValueConst this_val,\n                                             int class_id)\n{\n    JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);\n    if (!abuf)\n        return JS_EXCEPTION;\n    return JS_NewBool(ctx, array_buffer_is_resizable(abuf));\n}\n\nstatic void js_array_buffer_update_typed_arrays(JSArrayBuffer *abuf)\n{\n    uint32_t size_log2, size_elem;\n    struct list_head *el;\n    JSTypedArray *ta;\n    JSObject *p;\n    uint8_t *data;\n    int64_t len;\n\n    len = abuf->byte_length;\n    data = abuf->data;\n    // update lengths of all typed arrays backed by this array buffer\n    list_for_each(el, &abuf->array_list) {\n        ta = list_entry(el, JSTypedArray, link);\n        p = ta->obj;\n        if (p->class_id == JS_CLASS_DATAVIEW) {\n            if (ta->track_rab) {\n                if (ta->offset < len)\n                    ta->length = len - ta->offset;\n                else\n                    ta->length = 0;\n            }\n        } else {\n            p->u.array.count = 0;\n            p->u.array.u.ptr = NULL;\n            size_log2 = typed_array_size_log2(p->class_id);\n            size_elem = 1 << size_log2;\n            if (ta->track_rab) {\n                if (len >= (int64_t)ta->offset + size_elem) {\n                    p->u.array.count = (len - ta->offset) >> size_log2;\n                    p->u.array.u.ptr = &data[ta->offset];\n                }\n            } else {\n                if (len >= (int64_t)ta->offset + ta->length) {\n                    p->u.array.count = ta->length >> size_log2;\n                    p->u.array.u.ptr = &data[ta->offset];\n                }\n            }\n        }\n    }\n    \n}\n\nvoid JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj)\n{\n    JSArrayBuffer *abuf = JS_GetOpaque(obj, JS_CLASS_ARRAY_BUFFER);\n\n    if (!abuf || abuf->detached)\n        return;\n    if (abuf->free_func)\n        abuf->free_func(ctx->rt, abuf->opaque, abuf->data);\n    abuf->data = NULL;\n    abuf->byte_length = 0;\n    abuf->detached = TRUE;\n    js_array_buffer_update_typed_arrays(abuf);\n}\n\n/* get an ArrayBuffer or SharedArrayBuffer */\nstatic JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        goto fail;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (p->class_id != JS_CLASS_ARRAY_BUFFER &&\n        p->class_id != JS_CLASS_SHARED_ARRAY_BUFFER) {\n    fail:\n        JS_ThrowTypeErrorInvalidClass(ctx, JS_CLASS_ARRAY_BUFFER);\n        return NULL;\n    }\n    return p->u.array_buffer;\n}\n\n/* return NULL if exception. WARNING: any JS call can detach the\n   buffer and render the returned pointer invalid */\nuint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj)\n{\n    JSArrayBuffer *abuf = js_get_array_buffer(ctx, obj);\n    if (!abuf)\n        goto fail;\n    if (abuf->detached) {\n        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n        goto fail;\n    }\n    *psize = abuf->byte_length;\n    return abuf->data;\n fail:\n    *psize = 0;\n    return NULL;\n}\n\nstatic BOOL array_buffer_is_resizable(const JSArrayBuffer *abuf)\n{\n    return abuf->max_byte_length >= 0;\n}\n\n// ES #sec-arraybuffer.prototype.transfer\nstatic JSValue js_array_buffer_transfer(JSContext *ctx,\n                                        JSValueConst this_val,\n                                        int argc, JSValueConst *argv,\n                                        int transfer_to_fixed_length)\n{\n    JSArrayBuffer *abuf;\n    uint64_t new_len, *pmax_len, max_len;\n\n    abuf = JS_GetOpaque2(ctx, this_val, JS_CLASS_ARRAY_BUFFER);\n    if (!abuf)\n        return JS_EXCEPTION;\n    if (abuf->shared)\n        return JS_ThrowTypeError(ctx, \"cannot transfer a SharedArrayBuffer\");\n    if (argc < 1 || JS_IsUndefined(argv[0]))\n        new_len = abuf->byte_length;\n    else if (JS_ToIndex(ctx, &new_len, argv[0]))\n        return JS_EXCEPTION;\n    if (abuf->detached)\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n    pmax_len = NULL;\n    if (!transfer_to_fixed_length) {\n        if (array_buffer_is_resizable(abuf)) { // carry over maxByteLength\n            max_len = abuf->max_byte_length;\n            if (new_len > max_len)\n                return JS_ThrowTypeError(ctx, \"invalid array buffer length\");\n            // TODO(bnoordhuis) support externally managed RABs\n            if (abuf->free_func == js_array_buffer_free)\n                pmax_len = &max_len;\n        }\n    }\n    /* create an empty AB */\n    if (new_len == 0) {\n        JS_DetachArrayBuffer(ctx, this_val);\n        return js_array_buffer_constructor2(ctx, JS_UNDEFINED, 0, pmax_len, JS_CLASS_ARRAY_BUFFER);\n    } else {\n        uint64_t old_len;\n        uint8_t *bs, *new_bs;\n        JSFreeArrayBufferDataFunc *free_func;\n        \n        bs = abuf->data;\n        old_len = abuf->byte_length;\n        free_func = abuf->free_func;\n\n        /* if length mismatch, realloc. Otherwise, use the same backing buffer. */\n        if (new_len != old_len) {\n            /* XXX: we are currently limited to 2 GB */\n            if (new_len > INT32_MAX)\n                return JS_ThrowRangeError(ctx, \"invalid array buffer length\");\n\n            if (free_func != js_array_buffer_free) {\n                /* cannot use js_realloc() because the buffer was\n                   allocated with a custom allocator */\n                new_bs = js_mallocz(ctx, new_len);\n                if (!new_bs)\n                    return JS_EXCEPTION;\n                memcpy(new_bs, bs, min_int(old_len, new_len));\n                abuf->free_func(ctx->rt, abuf->opaque, bs);\n                bs = new_bs;\n                free_func = js_array_buffer_free;\n            } else {\n                new_bs = js_realloc(ctx, bs, new_len);\n                if (!new_bs)\n                    return JS_EXCEPTION;\n                bs = new_bs;\n                if (new_len > old_len)\n                    memset(bs + old_len, 0, new_len - old_len);\n            }\n        }\n        /* neuter the backing buffer */\n        abuf->data = NULL;\n        abuf->byte_length = 0;\n        abuf->detached = TRUE;\n        js_array_buffer_update_typed_arrays(abuf);\n        return js_array_buffer_constructor3(ctx, JS_UNDEFINED, new_len, pmax_len,\n                                            JS_CLASS_ARRAY_BUFFER,\n                                            bs, free_func,\n                                            NULL, FALSE);\n    }\n}\n\nstatic JSValue js_array_buffer_resize(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv, int class_id)\n{\n    JSArrayBuffer *abuf;\n    uint8_t *data;\n    int64_t len;\n\n    abuf = JS_GetOpaque2(ctx, this_val, class_id);\n    if (!abuf)\n        return JS_EXCEPTION;\n    if (JS_ToInt64(ctx, &len, argv[0]))\n        return JS_EXCEPTION;\n    if (abuf->detached)\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n    if (!array_buffer_is_resizable(abuf))\n        return JS_ThrowTypeError(ctx, \"array buffer is not resizable\");\n    // TODO(bnoordhuis) support externally managed RABs\n    if (abuf->free_func != js_array_buffer_free)\n        return JS_ThrowTypeError(ctx, \"external array buffer is not resizable\");\n    if (len < 0 || len > abuf->max_byte_length) {\n    bad_length:\n        return JS_ThrowRangeError(ctx, \"invalid array buffer length\");\n    }\n    // SABs can only grow and we don't need to realloc because\n    // js_array_buffer_constructor3 commits all memory upfront;\n    // regular RABs are resizable both ways and realloc\n    if (abuf->shared) {\n        if (len < abuf->byte_length)\n            goto bad_length;\n        // Note this is off-spec; there's supposed to be a single atomic\n        // |byteLength| property that's shared across SABs but we store\n        // it per SAB instead. That means when thread A calls sab.grow(2)\n        // at time t0, and thread B calls sab.grow(1) at time t1, we don't\n        // throw a TypeError in thread B as the spec says we should,\n        // instead both threads get their own view of the backing memory,\n        // 2 bytes big in A, and 1 byte big in B\n        abuf->byte_length = len;\n    } else {\n        data = js_realloc(ctx, abuf->data, max_int(len, 1));\n        if (!data)\n            return JS_EXCEPTION;\n        if (len > abuf->byte_length)\n            memset(&data[abuf->byte_length], 0, len - abuf->byte_length);\n        abuf->byte_length = len;\n        abuf->data = data;\n    }\n    js_array_buffer_update_typed_arrays(abuf);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_array_buffer_slice(JSContext *ctx,\n                                     JSValueConst this_val,\n                                     int argc, JSValueConst *argv, int class_id)\n{\n    JSArrayBuffer *abuf, *new_abuf;\n    int64_t len, start, end, new_len;\n    JSValue ctor, new_obj;\n\n    abuf = JS_GetOpaque2(ctx, this_val, class_id);\n    if (!abuf)\n        return JS_EXCEPTION;\n    if (abuf->detached)\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n    len = abuf->byte_length;\n\n    if (JS_ToInt64Clamp(ctx, &start, argv[0], 0, len, len))\n        return JS_EXCEPTION;\n\n    end = len;\n    if (!JS_IsUndefined(argv[1])) {\n        if (JS_ToInt64Clamp(ctx, &end, argv[1], 0, len, len))\n            return JS_EXCEPTION;\n    }\n    new_len = max_int64(end - start, 0);\n    ctor = JS_SpeciesConstructor(ctx, this_val, JS_UNDEFINED);\n    if (JS_IsException(ctor))\n        return ctor;\n    if (JS_IsUndefined(ctor)) {\n        new_obj = js_array_buffer_constructor2(ctx, JS_UNDEFINED, new_len,\n                                               NULL, class_id);\n    } else {\n        JSValue args[1];\n        args[0] = JS_NewInt64(ctx, new_len);\n        new_obj = JS_CallConstructor(ctx, ctor, 1, (JSValueConst *)args);\n        JS_FreeValue(ctx, ctor);\n        JS_FreeValue(ctx, args[0]);\n    }\n    if (JS_IsException(new_obj))\n        return new_obj;\n    new_abuf = JS_GetOpaque2(ctx, new_obj, class_id);\n    if (!new_abuf)\n        goto fail;\n    if (js_same_value(ctx, new_obj, this_val)) {\n        JS_ThrowTypeError(ctx, \"cannot use identical ArrayBuffer\");\n        goto fail;\n    }\n    if (new_abuf->detached) {\n        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n        goto fail;\n    }\n    if (new_abuf->byte_length < new_len) {\n        JS_ThrowTypeError(ctx, \"new ArrayBuffer is too small\");\n        goto fail;\n    }\n    /* must test again because of side effects */\n    if (abuf->detached || abuf->byte_length < start + new_len) {\n        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n        goto fail;\n    }\n    memcpy(new_abuf->data, abuf->data + start, new_len);\n    return new_obj;\n fail:\n    JS_FreeValue(ctx, new_obj);\n    return JS_EXCEPTION;\n}\n\nstatic const JSCFunctionListEntry js_array_buffer_proto_funcs[] = {\n    JS_CGETSET_MAGIC_DEF(\"byteLength\", js_array_buffer_get_byteLength, NULL, JS_CLASS_ARRAY_BUFFER ),\n    JS_CGETSET_MAGIC_DEF(\"maxByteLength\", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_ARRAY_BUFFER ),\n    JS_CGETSET_MAGIC_DEF(\"resizable\", js_array_buffer_get_resizable, NULL, JS_CLASS_ARRAY_BUFFER ),\n    JS_CGETSET_DEF(\"detached\", js_array_buffer_get_detached, NULL ),\n    JS_CFUNC_MAGIC_DEF(\"resize\", 1, js_array_buffer_resize, JS_CLASS_ARRAY_BUFFER ),\n    JS_CFUNC_MAGIC_DEF(\"slice\", 2, js_array_buffer_slice, JS_CLASS_ARRAY_BUFFER ),\n    JS_CFUNC_MAGIC_DEF(\"transfer\", 0, js_array_buffer_transfer, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"transferToFixedLength\", 0, js_array_buffer_transfer, 1 ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"ArrayBuffer\", JS_PROP_CONFIGURABLE ),\n};\n\n/* SharedArrayBuffer */\n\nstatic const JSCFunctionListEntry js_shared_array_buffer_funcs[] = {\n    JS_CGETSET_DEF(\"[Symbol.species]\", js_get_this, NULL ),\n};\n\nstatic const JSCFunctionListEntry js_shared_array_buffer_proto_funcs[] = {\n    JS_CGETSET_MAGIC_DEF(\"byteLength\", js_array_buffer_get_byteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),\n    JS_CGETSET_MAGIC_DEF(\"maxByteLength\", js_array_buffer_get_maxByteLength, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),\n    JS_CGETSET_MAGIC_DEF(\"growable\", js_array_buffer_get_resizable, NULL, JS_CLASS_SHARED_ARRAY_BUFFER ),\n    JS_CFUNC_MAGIC_DEF(\"grow\", 1, js_array_buffer_resize, JS_CLASS_SHARED_ARRAY_BUFFER ),\n    JS_CFUNC_MAGIC_DEF(\"slice\", 2, js_array_buffer_slice, JS_CLASS_SHARED_ARRAY_BUFFER ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"SharedArrayBuffer\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic JSObject *get_typed_array(JSContext *ctx, JSValueConst this_val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)\n        goto fail;\n    p = JS_VALUE_GET_OBJ(this_val);\n    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n          p->class_id <= JS_CLASS_FLOAT64_ARRAY)) {\n    fail:\n        JS_ThrowTypeError(ctx, \"not a TypedArray\");\n        return NULL;\n    }\n    return p;\n}\n\n// is the typed array detached or out of bounds relative to its RAB?\n// |p| must be a typed array, *not* a DataView\nstatic BOOL typed_array_is_oob(JSObject *p)\n{\n    JSArrayBuffer *abuf;\n    JSTypedArray *ta;\n    int len, size_elem;\n    int64_t end;\n\n    assert(p->class_id >= JS_CLASS_UINT8C_ARRAY);\n    assert(p->class_id <= JS_CLASS_FLOAT64_ARRAY);\n\n    ta = p->u.typed_array;\n    abuf = ta->buffer->u.array_buffer;\n    if (abuf->detached)\n        return TRUE;\n    len = abuf->byte_length;\n    if (ta->offset > len)\n        return TRUE;\n    if (ta->track_rab)\n        return FALSE;\n    if (len < (int64_t)ta->offset + ta->length)\n        return TRUE;\n    size_elem = 1 << typed_array_size_log2(p->class_id);\n    end = (int64_t)ta->offset + (int64_t)p->u.array.count * size_elem;\n    return end > len;\n}\n\n// Be *very* careful if you touch the typed array's memory directly:\n// the length is only valid until the next call into JS land because\n// JS code can detach or resize the backing array buffer. Functions\n// like JS_GetProperty and JS_ToIndex call JS code.\n//\n// Exclusively reading or writing elements with JS_GetProperty,\n// JS_GetPropertyInt64, JS_SetProperty, etc. is safe because they\n// perform bounds checks, as does js_get_fast_array_element.\nstatic int js_typed_array_get_length_unsafe(JSContext *ctx, JSValueConst obj)\n{\n    JSObject *p;\n    p = get_typed_array(ctx, obj);\n    if (!p)\n        return -1;\n    if (typed_array_is_oob(p)) {\n        JS_ThrowTypeErrorArrayBufferOOB(ctx);\n        return -1;\n    }\n    return p->u.array.count;\n}\n\nstatic int validate_typed_array(JSContext *ctx, JSValueConst this_val)\n{\n    JSObject *p;\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return -1;\n    if (typed_array_is_oob(p)) {\n        JS_ThrowTypeErrorArrayBufferOOB(ctx);\n        return -1;\n    }\n    return 0;\n}\n\nstatic JSValue js_typed_array_get_length(JSContext *ctx,\n                                         JSValueConst this_val)\n{\n    JSObject *p;\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    return JS_NewInt32(ctx, p->u.array.count);\n}\n\nstatic JSValue js_typed_array_get_buffer(JSContext *ctx,\n                                         JSValueConst this_val)\n{\n    JSObject *p;\n    JSTypedArray *ta;\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    ta = p->u.typed_array;\n    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));\n}\n\nstatic JSValue js_typed_array_get_byteLength(JSContext *ctx,\n                                             JSValueConst this_val)\n{\n    JSObject *p;\n    JSTypedArray *ta;\n    int size_log2;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_NewInt32(ctx, 0);\n    ta = p->u.typed_array;\n    if (!ta->track_rab)\n        return JS_NewUint32(ctx, ta->length);\n    size_log2 = typed_array_size_log2(p->class_id);\n    return JS_NewInt64(ctx, (int64_t)p->u.array.count << size_log2);\n}\n\nstatic JSValue js_typed_array_get_byteOffset(JSContext *ctx,\n                                             JSValueConst this_val)\n{\n    JSObject *p;\n    JSTypedArray *ta;\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_NewInt32(ctx, 0);\n    ta = p->u.typed_array;\n    return JS_NewUint32(ctx, ta->offset);\n}\n\nJSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,\n                         JSTypedArrayEnum type)\n{\n    if (type < JS_TYPED_ARRAY_UINT8C || type > JS_TYPED_ARRAY_FLOAT64)\n        return JS_ThrowRangeError(ctx, \"invalid typed array type\");\n\n    return js_typed_array_constructor(ctx, JS_UNDEFINED, argc, argv,\n                                      JS_CLASS_UINT8C_ARRAY + type);\n}\n\n/* Return the buffer associated to the typed array or an exception if\n   it is not a typed array or if the buffer is detached. pbyte_offset,\n   pbyte_length or pbytes_per_element can be NULL. */\nJSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,\n                               size_t *pbyte_offset,\n                               size_t *pbyte_length,\n                               size_t *pbytes_per_element)\n{\n    JSObject *p;\n    JSTypedArray *ta;\n    p = get_typed_array(ctx, obj);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    ta = p->u.typed_array;\n    if (pbyte_offset)\n        *pbyte_offset = ta->offset;\n    if (pbyte_length)\n        *pbyte_length = ta->length;\n    if (pbytes_per_element) {\n        *pbytes_per_element = 1 << typed_array_size_log2(p->class_id);\n    }\n    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));\n}\n\nstatic JSValue js_typed_array_get_toStringTag(JSContext *ctx,\n                                              JSValueConst this_val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)\n        return JS_UNDEFINED;\n    p = JS_VALUE_GET_OBJ(this_val);\n    if (!(p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n          p->class_id <= JS_CLASS_FLOAT64_ARRAY))\n        return JS_UNDEFINED;\n    return JS_AtomToString(ctx, ctx->rt->class_array[p->class_id].class_name);\n}\n\nstatic JSValue js_typed_array_set_internal(JSContext *ctx,\n                                           JSValueConst dst,\n                                           JSValueConst src,\n                                           JSValueConst off)\n{\n    JSObject *p;\n    JSObject *src_p;\n    uint32_t i;\n    int64_t dst_len, src_len, offset;\n    JSValue val, src_obj = JS_UNDEFINED;\n\n    p = get_typed_array(ctx, dst);\n    if (!p)\n        goto fail;\n    if (JS_ToInt64Sat(ctx, &offset, off))\n        goto fail;\n    if (offset < 0)\n        goto range_error;\n    if (typed_array_is_oob(p)) {\n    detached:\n        JS_ThrowTypeErrorArrayBufferOOB(ctx);\n        goto fail;\n    }\n    dst_len = p->u.array.count;\n    src_obj = JS_ToObject(ctx, src);\n    if (JS_IsException(src_obj))\n        goto fail;\n    src_p = JS_VALUE_GET_OBJ(src_obj);\n    if (src_p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n        src_p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n        JSTypedArray *dest_ta = p->u.typed_array;\n        JSArrayBuffer *dest_abuf = dest_ta->buffer->u.array_buffer;\n        JSTypedArray *src_ta = src_p->u.typed_array;\n        JSArrayBuffer *src_abuf = src_ta->buffer->u.array_buffer;\n        int shift = typed_array_size_log2(p->class_id);\n\n        if (typed_array_is_oob(src_p))\n            goto detached;\n\n        src_len = src_p->u.array.count;\n        if (offset > dst_len - src_len)\n            goto range_error;\n\n        /* copying between typed objects */\n        if (src_p->class_id == p->class_id) {\n            /* same type, use memmove */\n            memmove(dest_abuf->data + dest_ta->offset + (offset << shift),\n                    src_abuf->data + src_ta->offset, src_len << shift);\n            goto done;\n        }\n        if (dest_abuf->data == src_abuf->data) {\n            /* copying between the same buffer using different types of mappings\n               would require a temporary buffer */\n        }\n        /* otherwise, default behavior is slow but correct */\n    } else {\n        // can change |dst| as a side effect; per spec,\n        // perform the range check against its old length\n        if (js_get_length64(ctx, &src_len, src_obj))\n            goto fail;\n        if (offset > dst_len - src_len) {\n        range_error:\n            JS_ThrowRangeError(ctx, \"invalid array length\");\n            goto fail;\n        }\n    }\n    for(i = 0; i < src_len; i++) {\n        val = JS_GetPropertyUint32(ctx, src_obj, i);\n        if (JS_IsException(val))\n            goto fail;\n        if (JS_SetPropertyUint32(ctx, dst, offset + i, val) < 0)\n            goto fail;\n    }\ndone:\n    JS_FreeValue(ctx, src_obj);\n    return JS_UNDEFINED;\nfail:\n    JS_FreeValue(ctx, src_obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_typed_array_at(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSObject *p;\n    int64_t idx, len;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n    len = p->u.array.count;\n\n    // note: can change p->u.array.count\n    if (JS_ToInt64Sat(ctx, &idx, argv[0]))\n        return JS_EXCEPTION;\n\n    if (idx < 0)\n        idx = len + idx;\n\n    len = p->u.array.count;\n    if (idx < 0 || idx >= len)\n        return JS_UNDEFINED;\n    return JS_GetPropertyInt64(ctx, this_val, idx);\n}\n\nstatic JSValue js_typed_array_with(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSValue arr, val;\n    JSObject *p;\n    int64_t idx, len;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n\n    len = p->u.array.count;\n    if (JS_ToInt64Sat(ctx, &idx, argv[0]))\n        return JS_EXCEPTION;\n\n    if (idx < 0)\n        idx = len + idx;\n\n    val = JS_ToPrimitive(ctx, argv[1], HINT_NUMBER);\n    if (JS_IsException(val))\n        return JS_EXCEPTION;\n\n    if (typed_array_is_oob(p) || idx < 0 || idx >= p->u.array.count)\n        return JS_ThrowRangeError(ctx, \"invalid array index\");\n\n    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,\n                                        p->class_id, len);\n    if (JS_IsException(arr)) {\n        JS_FreeValue(ctx, val);\n        return JS_EXCEPTION;\n    }\n    if (JS_SetPropertyInt64(ctx, arr, idx, val) < 0) {\n        JS_FreeValue(ctx, arr);\n        return JS_EXCEPTION;\n    }\n    return arr;\n}\n\nstatic JSValue js_typed_array_set(JSContext *ctx,\n                                  JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValueConst offset = JS_UNDEFINED;\n    if (argc > 1) {\n        offset = argv[1];\n    }\n    return js_typed_array_set_internal(ctx, this_val, argv[0], offset);\n}\n\nstatic JSValue js_create_typed_array_iterator(JSContext *ctx, JSValueConst this_val,\n                                              int argc, JSValueConst *argv, int magic)\n{\n    if (validate_typed_array(ctx, this_val))\n        return JS_EXCEPTION;\n    return js_create_array_iterator(ctx, this_val, argc, argv, magic);\n}\n\nstatic JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,\n                                     int argc, JSValueConst *argv)\n{\n    JSValue ret;\n    int new_len;\n    int64_t len;\n\n    ret = JS_CallConstructor(ctx, ctor, argc, argv);\n    if (JS_IsException(ret))\n        return ret;\n    /* validate the typed array */\n    new_len = js_typed_array_get_length_unsafe(ctx, ret);\n    if (new_len < 0)\n        goto fail;\n    if (argc == 1) {\n        /* ensure that it is large enough */\n        if (JS_ToLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))\n            goto fail;\n        if (new_len < len) {\n            JS_ThrowTypeError(ctx, \"TypedArray length is too small\");\n        fail:\n            JS_FreeValue(ctx, ret);\n            return JS_EXCEPTION;\n        }\n    }\n    return ret;\n}\n\n#if 0\nstatic JSValue js_typed_array___create(JSContext *ctx,\n                                       JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    return js_typed_array_create(ctx, argv[0], max_int(argc - 1, 0), argv + 1);\n}\n#endif\n\nstatic JSValue js_typed_array___speciesCreate(JSContext *ctx,\n                                              JSValueConst this_val,\n                                              int argc, JSValueConst *argv)\n{\n    JSValueConst obj;\n    JSObject *p;\n    JSValue ctor, ret;\n    int argc1;\n\n    obj = argv[0];\n    p = get_typed_array(ctx, obj);\n    if (!p)\n        return JS_EXCEPTION;\n    ctor = JS_SpeciesConstructor(ctx, obj, JS_UNDEFINED);\n    if (JS_IsException(ctor))\n        return ctor;\n    argc1 = max_int(argc - 1, 0);\n    if (JS_IsUndefined(ctor)) {\n        ret = js_typed_array_constructor(ctx, JS_UNDEFINED, argc1, argv + 1,\n                                         p->class_id);\n    } else {\n        ret = js_typed_array_create(ctx, ctor, argc1, argv + 1);\n        JS_FreeValue(ctx, ctor);\n    }\n    return ret;\n}\n\nstatic JSValue js_typed_array_from(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    // from(items, mapfn = void 0, this_arg = void 0)\n    JSValueConst items = argv[0], mapfn, this_arg;\n    JSValueConst args[2];\n    JSValue iter, arr, r, v, v2;\n    int64_t k, len;\n    int mapping;\n\n    mapping = FALSE;\n    mapfn = JS_UNDEFINED;\n    this_arg = JS_UNDEFINED;\n    r = JS_UNDEFINED;\n    arr = JS_UNDEFINED;\n    iter = JS_UNDEFINED;\n\n    if (argc > 1) {\n        mapfn = argv[1];\n        if (!JS_IsUndefined(mapfn)) {\n            if (check_function(ctx, mapfn))\n                goto exception;\n            mapping = 1;\n            if (argc > 2)\n                this_arg = argv[2];\n        }\n    }\n    iter = JS_GetProperty(ctx, items, JS_ATOM_Symbol_iterator);\n    if (JS_IsException(iter))\n        goto exception;\n    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {\n        uint32_t len1;\n        if (!JS_IsFunction(ctx, iter)) {\n            JS_ThrowTypeError(ctx, \"value is not iterable\");\n            goto exception;\n        }\n        arr = js_array_from_iterator(ctx, &len1, items, iter);\n        if (JS_IsException(arr))\n            goto exception;\n        len = len1;\n    } else {\n        arr = JS_ToObject(ctx, items);\n        if (JS_IsException(arr))\n            goto exception;\n        if (js_get_length64(ctx, &len, arr) < 0)\n            goto exception;\n    }\n    v = JS_NewInt64(ctx, len);\n    args[0] = v;\n    r = js_typed_array_create(ctx, this_val, 1, args);\n    JS_FreeValue(ctx, v);\n    if (JS_IsException(r))\n        goto exception;\n    for(k = 0; k < len; k++) {\n        v = JS_GetPropertyInt64(ctx, arr, k);\n        if (JS_IsException(v))\n            goto exception;\n        if (mapping) {\n            args[0] = v;\n            args[1] = JS_NewInt32(ctx, k);\n            v2 = JS_Call(ctx, mapfn, this_arg, 2, args);\n            JS_FreeValue(ctx, v);\n            v = v2;\n            if (JS_IsException(v))\n                goto exception;\n        }\n        if (JS_SetPropertyInt64(ctx, r, k, v) < 0)\n            goto exception;\n    }\n    goto done;\n exception:\n    JS_FreeValue(ctx, r);\n    r = JS_EXCEPTION;\n done:\n    JS_FreeValue(ctx, arr);\n    JS_FreeValue(ctx, iter);\n    return r;\n}\n\nstatic JSValue js_typed_array_of(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv)\n{\n    JSValue obj;\n    JSValueConst args[1];\n    int i;\n\n    args[0] = JS_NewInt32(ctx, argc);\n    obj = js_typed_array_create(ctx, this_val, 1, args);\n    if (JS_IsException(obj))\n        return obj;\n\n    for(i = 0; i < argc; i++) {\n        if (JS_SetPropertyUint32(ctx, obj, i, JS_DupValue(ctx, argv[i])) < 0) {\n            JS_FreeValue(ctx, obj);\n            return JS_EXCEPTION;\n        }\n    }\n    return obj;\n}\n\nstatic JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    JSObject *p;\n    int len, to, from, final, count, shift, space;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    len = p->u.array.count;\n\n    if (JS_ToInt32Clamp(ctx, &to, argv[0], 0, len, len))\n        return JS_EXCEPTION;\n\n    if (JS_ToInt32Clamp(ctx, &from, argv[1], 0, len, len))\n        return JS_EXCEPTION;\n\n    final = len;\n    if (argc > 2 && !JS_IsUndefined(argv[2])) {\n        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))\n            return JS_EXCEPTION;\n    }\n\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n\n    // RAB may have been resized by evil .valueOf method\n    space = p->u.array.count - max_int(to, from);\n    count = min_int(final - from, len - to);\n    count = min_int(count, space);\n    if (count > 0) {\n        shift = typed_array_size_log2(p->class_id);\n        memmove(p->u.array.u.uint8_ptr + (to << shift),\n                p->u.array.u.uint8_ptr + (from << shift),\n                count << shift);\n    }\n    return JS_DupValue(ctx, this_val);\n}\n\nstatic JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSObject *p;\n    int len, k, final, shift;\n    uint64_t v64;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    len = p->u.array.count;\n\n    if (p->class_id == JS_CLASS_UINT8C_ARRAY) {\n        int32_t v;\n        if (JS_ToUint8ClampFree(ctx, &v, JS_DupValue(ctx, argv[0])))\n            return JS_EXCEPTION;\n        v64 = v;\n    } else if (p->class_id <= JS_CLASS_UINT32_ARRAY) {\n        uint32_t v;\n        if (JS_ToUint32(ctx, &v, argv[0]))\n            return JS_EXCEPTION;\n        v64 = v;\n    } else if (p->class_id <= JS_CLASS_BIG_UINT64_ARRAY) {\n        if (JS_ToBigInt64(ctx, (int64_t *)&v64, argv[0]))\n            return JS_EXCEPTION;\n    } else {\n        double d;\n        if (JS_ToFloat64(ctx, &d, argv[0]))\n            return JS_EXCEPTION;\n        if (p->class_id == JS_CLASS_FLOAT16_ARRAY) {\n            v64 = tofp16(d);\n        } else if (p->class_id == JS_CLASS_FLOAT32_ARRAY) {\n            union {\n                float f;\n                uint32_t u32;\n            } u;\n            u.f = d;\n            v64 = u.u32;\n        } else {\n            JSFloat64Union u;\n            u.d = d;\n            v64 = u.u64;\n        }\n    }\n\n    k = 0;\n    if (argc > 1) {\n        if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))\n            return JS_EXCEPTION;\n    }\n\n    final = len;\n    if (argc > 2 && !JS_IsUndefined(argv[2])) {\n        if (JS_ToInt32Clamp(ctx, &final, argv[2], 0, len, len))\n            return JS_EXCEPTION;\n    }\n\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n\n    // RAB may have been resized by evil .valueOf method\n    final = min_int(final, p->u.array.count);\n    shift = typed_array_size_log2(p->class_id);\n    switch(shift) {\n    case 0:\n        if (k < final) {\n            memset(p->u.array.u.uint8_ptr + k, v64, final - k);\n        }\n        break;\n    case 1:\n        for(; k < final; k++) {\n            p->u.array.u.uint16_ptr[k] = v64;\n        }\n        break;\n    case 2:\n        for(; k < final; k++) {\n            p->u.array.u.uint32_ptr[k] = v64;\n        }\n        break;\n    case 3:\n        for(; k < final; k++) {\n            p->u.array.u.uint64_ptr[k] = v64;\n        }\n        break;\n    default:\n        abort();\n    }\n    return JS_DupValue(ctx, this_val);\n}\n\nstatic JSValue js_typed_array_find(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv, int mode)\n{\n    JSValueConst func, this_arg;\n    JSValueConst args[3];\n    JSValue val, index_val, res;\n    int len, k, end;\n    int dir;\n\n    val = JS_UNDEFINED;\n    len = js_typed_array_get_length_unsafe(ctx, this_val);\n    if (len < 0)\n        goto exception;\n\n    func = argv[0];\n    if (check_function(ctx, func))\n        goto exception;\n\n    this_arg = JS_UNDEFINED;\n    if (argc > 1)\n        this_arg = argv[1];\n\n    k = 0;\n    dir = 1;\n    end = len;\n    if (mode == ArrayFindLast || mode == ArrayFindLastIndex) {\n        k = len - 1;\n        dir = -1;\n        end = -1;\n    }\n\n    for(; k != end; k += dir) {\n        index_val = JS_NewInt32(ctx, k);\n        val = JS_GetPropertyValue(ctx, this_val, index_val);\n        if (JS_IsException(val))\n            goto exception;\n        args[0] = val;\n        args[1] = index_val;\n        args[2] = this_val;\n        res = JS_Call(ctx, func, this_arg, 3, args);\n        if (JS_IsException(res))\n            goto exception;\n        if (JS_ToBoolFree(ctx, res)) {\n            if (mode == ArrayFindIndex || mode == ArrayFindLastIndex) {\n                JS_FreeValue(ctx, val);\n                return index_val;\n            } else {\n                return val;\n            }\n        }\n        JS_FreeValue(ctx, val);\n    }\n    if (mode == ArrayFindIndex || mode == ArrayFindLastIndex)\n        return JS_NewInt32(ctx, -1);\n    else\n        return JS_UNDEFINED;\n\nexception:\n    JS_FreeValue(ctx, val);\n    return JS_EXCEPTION;\n}\n\n#define special_indexOf 0\n#define special_lastIndexOf 1\n#define special_includes -1\n\nstatic JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv, int special)\n{\n    JSObject *p;\n    int len, tag, is_int, is_bigint, k, stop, inc, res = -1;\n    int64_t v64;\n    double d;\n    float f;\n    uint16_t hf;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    len = p->u.array.count;\n\n    if (len == 0)\n        goto done;\n\n    if (special == special_lastIndexOf) {\n        k = len - 1;\n        if (argc > 1) {\n            int64_t k1;\n            if (JS_ToInt64Clamp(ctx, &k1, argv[1], -1, len - 1, len))\n                goto exception;\n            k = k1;\n            if (k < 0)\n                goto done;\n        }\n        stop = -1;\n        inc = -1;\n    } else {\n        k = 0;\n        if (argc > 1) {\n            if (JS_ToInt32Clamp(ctx, &k, argv[1], 0, len, len))\n                goto exception;\n        }\n        stop = len;\n        inc = 1;\n    }\n\n    /* includes function: 'undefined' can be found if searching out of bounds */\n    if (len > p->u.array.count && special == special_includes &&\n        JS_IsUndefined(argv[0]) && k < len) {\n        res = 0;\n        goto done;\n    }\n\n    // RAB may have been resized by evil .valueOf method\n    len = min_int(len, p->u.array.count);\n    if (len == 0)\n        goto done;\n    if (special == special_lastIndexOf)\n        k = min_int(k, len - 1);\n    else\n        k = min_int(k, len);\n    stop = min_int(stop, len);\n\n    is_bigint = 0;\n    is_int = 0; /* avoid warning */\n    v64 = 0; /* avoid warning */\n    tag = JS_VALUE_GET_NORM_TAG(argv[0]);\n    if (tag == JS_TAG_INT) {\n        is_int = 1;\n        v64 = JS_VALUE_GET_INT(argv[0]);\n        d = v64;\n    } else\n    if (tag == JS_TAG_FLOAT64) {\n        d = JS_VALUE_GET_FLOAT64(argv[0]);\n        if (d >= INT64_MIN && d < 0x1p63) {\n            v64 = d;\n            is_int = (v64 == d);\n        }\n    } else if (tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT) {\n        JSBigIntBuf buf1;\n        JSBigInt *p1;\n        int sz = (64 / JS_LIMB_BITS);\n        if (tag == JS_TAG_SHORT_BIG_INT)\n            p1 = js_bigint_set_short(&buf1, argv[0]);\n        else\n            p1 = JS_VALUE_GET_PTR(argv[0]);\n        \n        if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {\n            if (p1->len > sz)\n                goto done; /* does not fit an int64 : cannot be found */\n        } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {\n            if (js_bigint_sign(p1))\n                goto done; /* v < 0 */\n            if (p1->len <= sz) {\n                /* OK */\n            } else if (p1->len == sz + 1 && p1->tab[sz] == 0) {\n                /* 2^63 <= v <= 2^64-1 */\n            } else {\n                goto done;\n            }\n        } else {\n            goto done;\n        }\n        if (JS_ToBigInt64(ctx, &v64, argv[0]))\n            goto exception;\n        d = 0;\n        is_bigint = 1;\n    } else {\n        goto done;\n    }\n\n    switch (p->class_id) {\n    case JS_CLASS_INT8_ARRAY:\n        if (is_int && (int8_t)v64 == v64)\n            goto scan8;\n        break;\n    case JS_CLASS_UINT8C_ARRAY:\n    case JS_CLASS_UINT8_ARRAY:\n        if (is_int && (uint8_t)v64 == v64) {\n            const uint8_t *pv, *pp;\n            uint16_t v;\n        scan8:\n            pv = p->u.array.u.uint8_ptr;\n            v = v64;\n            if (inc > 0) {\n                pp = NULL;\n                if (pv)\n                    pp = memchr(pv + k, v, len - k);\n                if (pp)\n                    res = pp - pv;\n            } else {\n                for (; k != stop; k += inc) {\n                    if (pv[k] == v) {\n                        res = k;\n                        break;\n                    }\n                }\n            }\n        }\n        break;\n    case JS_CLASS_INT16_ARRAY:\n        if (is_int && (int16_t)v64 == v64)\n            goto scan16;\n        break;\n    case JS_CLASS_UINT16_ARRAY:\n        if (is_int && (uint16_t)v64 == v64) {\n            const uint16_t *pv;\n            uint16_t v;\n        scan16:\n            pv = p->u.array.u.uint16_ptr;\n            v = v64;\n            for (; k != stop; k += inc) {\n                if (pv[k] == v) {\n                    res = k;\n                    break;\n                }\n            }\n        }\n        break;\n    case JS_CLASS_INT32_ARRAY:\n        if (is_int && (int32_t)v64 == v64)\n            goto scan32;\n        break;\n    case JS_CLASS_UINT32_ARRAY:\n        if (is_int && (uint32_t)v64 == v64) {\n            const uint32_t *pv;\n            uint32_t v;\n        scan32:\n            pv = p->u.array.u.uint32_ptr;\n            v = v64;\n            for (; k != stop; k += inc) {\n                if (pv[k] == v) {\n                    res = k;\n                    break;\n                }\n            }\n        }\n        break;\n    case JS_CLASS_FLOAT16_ARRAY:\n        if (is_bigint)\n            break;\n        if (isnan(d)) {\n            const uint16_t *pv = p->u.array.u.fp16_ptr;\n            /* special case: indexOf returns -1, includes finds NaN */\n            if (special != special_includes)\n                goto done;\n            for (; k != stop; k += inc) {\n                if (isfp16nan(pv[k])) {\n                    res = k;\n                    break;\n                }\n            }\n        } else if (d == 0) {\n            // special case: includes also finds negative zero\n            const uint16_t *pv = p->u.array.u.fp16_ptr;\n            for (; k != stop; k += inc) {\n                if (isfp16zero(pv[k])) {\n                    res = k;\n                    break;\n                }\n            }\n        } else if (hf = tofp16(d), d == fromfp16(hf)) {\n            const uint16_t *pv = p->u.array.u.fp16_ptr;\n            for (; k != stop; k += inc) {\n                if (pv[k] == hf) {\n                    res = k;\n                    break;\n                }\n            }\n        }\n        break;\n    case JS_CLASS_FLOAT32_ARRAY:\n        if (is_bigint)\n            break;\n        if (isnan(d)) {\n            const float *pv = p->u.array.u.float_ptr;\n            /* special case: indexOf returns -1, includes finds NaN */\n            if (special != special_includes)\n                goto done;\n            for (; k != stop; k += inc) {\n                if (isnan(pv[k])) {\n                    res = k;\n                    break;\n                }\n            }\n        } else if ((f = (float)d) == d) {\n            const float *pv = p->u.array.u.float_ptr;\n            for (; k != stop; k += inc) {\n                if (pv[k] == f) {\n                    res = k;\n                    break;\n                }\n            }\n        }\n        break;\n    case JS_CLASS_FLOAT64_ARRAY:\n        if (is_bigint)\n            break;\n        if (isnan(d)) {\n            const double *pv = p->u.array.u.double_ptr;\n            /* special case: indexOf returns -1, includes finds NaN */\n            if (special != special_includes)\n                goto done;\n            for (; k != stop; k += inc) {\n                if (isnan(pv[k])) {\n                    res = k;\n                    break;\n                }\n            }\n        } else {\n            const double *pv = p->u.array.u.double_ptr;\n            for (; k != stop; k += inc) {\n                if (pv[k] == d) {\n                    res = k;\n                    break;\n                }\n            }\n        }\n        break;\n    case JS_CLASS_BIG_INT64_ARRAY:\n        if (is_bigint) {\n            goto scan64;\n        }\n        break;\n    case JS_CLASS_BIG_UINT64_ARRAY:\n        if (is_bigint) {\n            const uint64_t *pv;\n            uint64_t v;\n        scan64:\n            pv = p->u.array.u.uint64_ptr;\n            v = v64;\n            for (; k != stop; k += inc) {\n                if (pv[k] == v) {\n                    res = k;\n                    break;\n                }\n            }\n        }\n        break;\n    }\n\ndone:\n    if (special == special_includes)\n        return JS_NewBool(ctx, res >= 0);\n    else\n        return JS_NewInt32(ctx, res);\n\nexception:\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv, int toLocaleString)\n{\n    JSValue sep = JS_UNDEFINED, el;\n    StringBuffer b_s, *b = &b_s;\n    JSString *s = NULL;\n    JSObject *p;\n    int i, len, oldlen, newlen;\n    int c;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    len = oldlen = newlen = p->u.array.count;\n\n    c = ',';    /* default separator */\n    if (!toLocaleString && argc > 0 && !JS_IsUndefined(argv[0])) {\n        sep = JS_ToString(ctx, argv[0]);\n        if (JS_IsException(sep))\n            goto exception;\n        s = JS_VALUE_GET_STRING(sep);\n        if (s->len == 1 && !s->is_wide_char)\n            c = s->u.str8[0];\n        else\n            c = -1;\n        // ToString(sep) can detach or resize the arraybuffer as a side effect\n        newlen = p->u.array.count;\n        len = min_int(len, newlen);\n    }\n    string_buffer_init(ctx, b, 0);\n\n    /* XXX: optimize with direct access */\n    for(i = 0; i < len; i++) {\n        if (i > 0) {\n            if (c >= 0) {\n                if (string_buffer_putc8(b, c))\n                    goto fail;\n            } else {\n                if (string_buffer_concat(b, s, 0, s->len))\n                    goto fail;\n            }\n        }\n        el = JS_GetPropertyUint32(ctx, this_val, i);\n        /* Can return undefined for example if the typed array is detached */\n        if (!JS_IsNull(el) && !JS_IsUndefined(el)) {\n            if (JS_IsException(el))\n                goto fail;\n            if (toLocaleString) {\n                el = JS_ToLocaleStringFree(ctx, el);\n            }\n            if (string_buffer_concat_value_free(b, el))\n                goto fail;\n        }\n    }\n\n    // add extra separators in case RAB was resized by evil .valueOf method\n    i = max_int(1, newlen);\n    for(/*empty*/; i < oldlen; i++) {\n        if (c >= 0) {\n            if (string_buffer_putc8(b, c))\n                goto fail;\n        } else {\n            if (string_buffer_concat(b, s, 0, s->len))\n                goto fail;\n        }\n    }\n\n    JS_FreeValue(ctx, sep);\n    return string_buffer_end(b);\n\nfail:\n    string_buffer_free(b);\n    JS_FreeValue(ctx, sep);\nexception:\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_typed_array_reverse(JSContext *ctx, JSValueConst this_val,\n                                      int argc, JSValueConst *argv)\n{\n    JSObject *p;\n    int len;\n\n    len = js_typed_array_get_length_unsafe(ctx, this_val);\n    if (len < 0)\n        return JS_EXCEPTION;\n    if (len > 0) {\n        p = JS_VALUE_GET_OBJ(this_val);\n        switch (typed_array_size_log2(p->class_id)) {\n        case 0:\n            {\n                uint8_t *p1 = p->u.array.u.uint8_ptr;\n                uint8_t *p2 = p1 + len - 1;\n                while (p1 < p2) {\n                    uint8_t v = *p1;\n                    *p1++ = *p2;\n                    *p2-- = v;\n                }\n            }\n            break;\n        case 1:\n            {\n                uint16_t *p1 = p->u.array.u.uint16_ptr;\n                uint16_t *p2 = p1 + len - 1;\n                while (p1 < p2) {\n                    uint16_t v = *p1;\n                    *p1++ = *p2;\n                    *p2-- = v;\n                }\n            }\n            break;\n        case 2:\n            {\n                uint32_t *p1 = p->u.array.u.uint32_ptr;\n                uint32_t *p2 = p1 + len - 1;\n                while (p1 < p2) {\n                    uint32_t v = *p1;\n                    *p1++ = *p2;\n                    *p2-- = v;\n                }\n            }\n            break;\n        case 3:\n            {\n                uint64_t *p1 = p->u.array.u.uint64_ptr;\n                uint64_t *p2 = p1 + len - 1;\n                while (p1 < p2) {\n                    uint64_t v = *p1;\n                    *p1++ = *p2;\n                    *p2-- = v;\n                }\n            }\n            break;\n        default:\n            abort();\n        }\n    }\n    return JS_DupValue(ctx, this_val);\n}\n\nstatic JSValue js_typed_array_toReversed(JSContext *ctx, JSValueConst this_val,\n                                         int argc, JSValueConst *argv)\n{\n    JSValue arr, ret;\n    JSObject *p;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,\n                                        p->class_id, p->u.array.count);\n    if (JS_IsException(arr))\n        return JS_EXCEPTION;\n    ret = js_typed_array_reverse(ctx, arr, argc, argv);\n    JS_FreeValue(ctx, arr);\n    return ret;\n}\n\nstatic void slice_memcpy(uint8_t *dst, const uint8_t *src, size_t len)\n{\n    if (dst + len <= src || dst >= src + len) {\n        /* no overlap: can use memcpy */\n        memcpy(dst, src, len);\n    } else {\n        /* otherwise the spec mandates byte copy */\n        while (len-- != 0)\n            *dst++ = *src++;\n    }\n}\n\nstatic JSValue js_typed_array_slice(JSContext *ctx, JSValueConst this_val,\n                                    int argc, JSValueConst *argv)\n{\n    JSValueConst args[2];\n    JSValue arr, val;\n    JSObject *p, *p1;\n    int n, len, start, final, count, shift, space;\n\n    arr = JS_UNDEFINED;\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        goto exception;\n    if (typed_array_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    len = p->u.array.count;\n\n    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))\n        goto exception;\n    final = len;\n    if (!JS_IsUndefined(argv[1])) {\n        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))\n            goto exception;\n    }\n    count = max_int(final - start, 0);\n\n    shift = typed_array_size_log2(p->class_id);\n\n    args[0] = this_val;\n    args[1] = JS_NewInt32(ctx, count);\n    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, 2, args);\n    if (JS_IsException(arr))\n        goto exception;\n\n    if (count > 0) {\n        if (validate_typed_array(ctx, this_val)\n        ||  validate_typed_array(ctx, arr))\n            goto exception;\n\n        p1 = get_typed_array(ctx, arr);\n        space = max_int(0, p->u.array.count - start);\n        count = min_int(count, space);\n        if (p1 != NULL && p->class_id == p1->class_id) {\n            slice_memcpy(p1->u.array.u.uint8_ptr,\n                         p->u.array.u.uint8_ptr + (start << shift),\n                         count << shift);\n        } else {\n            for (n = 0; n < count; n++) {\n                val = JS_GetPropertyValue(ctx, this_val, JS_NewInt32(ctx, start + n));\n                if (JS_IsException(val))\n                    goto exception;\n                if (JS_SetPropertyValue(ctx, arr, JS_NewInt32(ctx, n), val,\n                                        JS_PROP_THROW) < 0)\n                    goto exception;\n            }\n        }\n    }\n    return arr;\n\n exception:\n    JS_FreeValue(ctx, arr);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_typed_array_subarray(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JSValueConst args[4];\n    JSValue arr, ta_buffer;\n    JSTypedArray *ta;\n    JSObject *p;\n    int len, start, final, count, shift, offset;\n    BOOL is_auto;\n        \n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        goto exception;\n    len = p->u.array.count;\n    if (JS_ToInt32Clamp(ctx, &start, argv[0], 0, len, len))\n        goto exception;\n\n    shift = typed_array_size_log2(p->class_id);\n    ta = p->u.typed_array;\n    /* Read byteOffset (ta->offset) even if detached */\n    offset = ta->offset + (start << shift);\n\n    final = len;\n    if (JS_IsUndefined(argv[1])) {\n        is_auto = ta->track_rab;\n    } else {\n        is_auto = FALSE;\n        if (JS_ToInt32Clamp(ctx, &final, argv[1], 0, len, len))\n            goto exception;\n    } \n    count = max_int(final - start, 0);\n    ta_buffer = js_typed_array_get_buffer(ctx, this_val);\n    if (JS_IsException(ta_buffer))\n        goto exception;\n    args[0] = this_val;\n    args[1] = ta_buffer;\n    args[2] = JS_NewInt32(ctx, offset);\n    args[3] = JS_NewInt32(ctx, count);\n    arr = js_typed_array___speciesCreate(ctx, JS_UNDEFINED, is_auto ? 3 : 4, args);\n    JS_FreeValue(ctx, ta_buffer);\n    return arr;\n\n exception:\n    return JS_EXCEPTION;\n}\n\n/* TypedArray.prototype.sort */\n\nstatic int js_cmp_doubles(double x, double y)\n{\n    if (isnan(x))    return isnan(y) ? 0 : +1;\n    if (isnan(y))    return -1;\n    if (x < y)       return -1;\n    if (x > y)       return 1;\n    if (x != 0)      return 0;\n    if (signbit(x))  return signbit(y) ? 0 : -1;\n    else             return signbit(y) ? 1 : 0;\n}\n\nstatic int js_TA_cmp_int8(const void *a, const void *b, void *opaque) {\n    return *(const int8_t *)a - *(const int8_t *)b;\n}\n\nstatic int js_TA_cmp_uint8(const void *a, const void *b, void *opaque) {\n    return *(const uint8_t *)a - *(const uint8_t *)b;\n}\n\nstatic int js_TA_cmp_int16(const void *a, const void *b, void *opaque) {\n    return *(const int16_t *)a - *(const int16_t *)b;\n}\n\nstatic int js_TA_cmp_uint16(const void *a, const void *b, void *opaque) {\n    return *(const uint16_t *)a - *(const uint16_t *)b;\n}\n\nstatic int js_TA_cmp_int32(const void *a, const void *b, void *opaque) {\n    int32_t x = *(const int32_t *)a;\n    int32_t y = *(const int32_t *)b;\n    return (y < x) - (y > x);\n}\n\nstatic int js_TA_cmp_uint32(const void *a, const void *b, void *opaque) {\n    uint32_t x = *(const uint32_t *)a;\n    uint32_t y = *(const uint32_t *)b;\n    return (y < x) - (y > x);\n}\n\nstatic int js_TA_cmp_int64(const void *a, const void *b, void *opaque) {\n    int64_t x = *(const int64_t *)a;\n    int64_t y = *(const int64_t *)b;\n    return (y < x) - (y > x);\n}\n\nstatic int js_TA_cmp_uint64(const void *a, const void *b, void *opaque) {\n    uint64_t x = *(const uint64_t *)a;\n    uint64_t y = *(const uint64_t *)b;\n    return (y < x) - (y > x);\n}\n\nstatic int js_TA_cmp_float16(const void *a, const void *b, void *opaque) {\n    return js_cmp_doubles(fromfp16(*(const uint16_t *)a),\n                          fromfp16(*(const uint16_t *)b));\n}\n\nstatic int js_TA_cmp_float32(const void *a, const void *b, void *opaque) {\n    return js_cmp_doubles(*(const float *)a, *(const float *)b);\n}\n\nstatic int js_TA_cmp_float64(const void *a, const void *b, void *opaque) {\n    return js_cmp_doubles(*(const double *)a, *(const double *)b);\n}\n\nstatic JSValue js_TA_get_int8(JSContext *ctx, const void *a) {\n    return JS_NewInt32(ctx, *(const int8_t *)a);\n}\n\nstatic JSValue js_TA_get_uint8(JSContext *ctx, const void *a) {\n    return JS_NewInt32(ctx, *(const uint8_t *)a);\n}\n\nstatic JSValue js_TA_get_int16(JSContext *ctx, const void *a) {\n    return JS_NewInt32(ctx, *(const int16_t *)a);\n}\n\nstatic JSValue js_TA_get_uint16(JSContext *ctx, const void *a) {\n    return JS_NewInt32(ctx, *(const uint16_t *)a);\n}\n\nstatic JSValue js_TA_get_int32(JSContext *ctx, const void *a) {\n    return JS_NewInt32(ctx, *(const int32_t *)a);\n}\n\nstatic JSValue js_TA_get_uint32(JSContext *ctx, const void *a) {\n    return JS_NewUint32(ctx, *(const uint32_t *)a);\n}\n\nstatic JSValue js_TA_get_int64(JSContext *ctx, const void *a) {\n    return JS_NewBigInt64(ctx, *(int64_t *)a);\n}\n\nstatic JSValue js_TA_get_uint64(JSContext *ctx, const void *a) {\n    return JS_NewBigUint64(ctx, *(uint64_t *)a);\n}\n\nstatic JSValue js_TA_get_float16(JSContext *ctx, const void *a) {\n    return __JS_NewFloat64(ctx, fromfp16(*(const uint16_t *)a));\n}\n\nstatic JSValue js_TA_get_float32(JSContext *ctx, const void *a) {\n    return __JS_NewFloat64(ctx, *(const float *)a);\n}\n\nstatic JSValue js_TA_get_float64(JSContext *ctx, const void *a) {\n    return __JS_NewFloat64(ctx, *(const double *)a);\n}\n\nstruct TA_sort_context {\n    JSContext *ctx;\n    int exception; /* 1 = exception, 2 = detached typed array */\n    JSValueConst arr;\n    JSValueConst cmp;\n    JSValue (*getfun)(JSContext *ctx, const void *a);\n    int elt_size;\n};\n\nstatic int js_TA_cmp_generic(const void *a, const void *b, void *opaque) {\n    struct TA_sort_context *psc = opaque;\n    JSContext *ctx = psc->ctx;\n    uint32_t a_idx, b_idx;\n    JSValueConst argv[2];\n    JSValue res;\n    int cmp;\n    JSObject *p;\n    \n    cmp = 0;\n    if (!psc->exception) {\n        /* Note: the typed array can be detached without causing an\n           error */\n        a_idx = *(uint32_t *)a;\n        b_idx = *(uint32_t *)b;\n        p = JS_VALUE_GET_PTR(psc->arr);\n        if (a_idx >= p->u.array.count || b_idx >= p->u.array.count) {\n            /* OOB case */\n            psc->exception = 2;\n            return 0;\n        }\n        argv[0] = psc->getfun(ctx, p->u.array.u.uint8_ptr +\n                              a_idx * (size_t)psc->elt_size);\n        argv[1] = psc->getfun(ctx, p->u.array.u.uint8_ptr +\n                              b_idx * (size_t)(psc->elt_size));\n        res = JS_Call(ctx, psc->cmp, JS_UNDEFINED, 2, argv);\n        if (JS_IsException(res)) {\n            psc->exception = 1;\n            goto done;\n        }\n        if (JS_VALUE_GET_TAG(res) == JS_TAG_INT) {\n            int val = JS_VALUE_GET_INT(res);\n            cmp = (val > 0) - (val < 0);\n        } else {\n            double val;\n            if (JS_ToFloat64Free(ctx, &val, res) < 0) {\n                psc->exception = 1;\n                goto done;\n            } else {\n                cmp = (val > 0) - (val < 0);\n            }\n        }\n        if (cmp == 0) {\n            /* make sort stable: compare array offsets */\n            cmp = (a_idx > b_idx) - (a_idx < b_idx);\n        }\n    done:\n        JS_FreeValue(ctx, (JSValue)argv[0]);\n        JS_FreeValue(ctx, (JSValue)argv[1]);\n    }\n    return cmp;\n}\n\nstatic JSValue js_typed_array_sort(JSContext *ctx, JSValueConst this_val,\n                                   int argc, JSValueConst *argv)\n{\n    JSObject *p;\n    int len;\n    size_t elt_size;\n    struct TA_sort_context tsc;\n    int (*cmpfun)(const void *a, const void *b, void *opaque);\n\n    tsc.ctx = ctx;\n    tsc.exception = 0;\n    tsc.arr = this_val;\n    tsc.cmp = argv[0];\n\n    if (!JS_IsUndefined(tsc.cmp) && check_function(ctx, tsc.cmp))\n        return JS_EXCEPTION;\n    len = js_typed_array_get_length_unsafe(ctx, this_val);\n    if (len < 0)\n        return JS_EXCEPTION;\n\n    if (len > 1) {\n        p = JS_VALUE_GET_OBJ(this_val);\n        switch (p->class_id) {\n        case JS_CLASS_INT8_ARRAY:\n            tsc.getfun = js_TA_get_int8;\n            cmpfun = js_TA_cmp_int8;\n            break;\n        case JS_CLASS_UINT8C_ARRAY:\n        case JS_CLASS_UINT8_ARRAY:\n            tsc.getfun = js_TA_get_uint8;\n            cmpfun = js_TA_cmp_uint8;\n            break;\n        case JS_CLASS_INT16_ARRAY:\n            tsc.getfun = js_TA_get_int16;\n            cmpfun = js_TA_cmp_int16;\n            break;\n        case JS_CLASS_UINT16_ARRAY:\n            tsc.getfun = js_TA_get_uint16;\n            cmpfun = js_TA_cmp_uint16;\n            break;\n        case JS_CLASS_INT32_ARRAY:\n            tsc.getfun = js_TA_get_int32;\n            cmpfun = js_TA_cmp_int32;\n            break;\n        case JS_CLASS_UINT32_ARRAY:\n            tsc.getfun = js_TA_get_uint32;\n            cmpfun = js_TA_cmp_uint32;\n            break;\n        case JS_CLASS_BIG_INT64_ARRAY:\n            tsc.getfun = js_TA_get_int64;\n            cmpfun = js_TA_cmp_int64;\n            break;\n        case JS_CLASS_BIG_UINT64_ARRAY:\n            tsc.getfun = js_TA_get_uint64;\n            cmpfun = js_TA_cmp_uint64;\n            break;\n        case JS_CLASS_FLOAT16_ARRAY:\n            tsc.getfun = js_TA_get_float16;\n            cmpfun = js_TA_cmp_float16;\n            break;\n        case JS_CLASS_FLOAT32_ARRAY:\n            tsc.getfun = js_TA_get_float32;\n            cmpfun = js_TA_cmp_float32;\n            break;\n        case JS_CLASS_FLOAT64_ARRAY:\n            tsc.getfun = js_TA_get_float64;\n            cmpfun = js_TA_cmp_float64;\n            break;\n        default:\n            abort();\n        }\n        elt_size = 1 << typed_array_size_log2(p->class_id);\n        if (!JS_IsUndefined(tsc.cmp)) {\n            uint32_t *array_idx;\n            void *array_tmp;\n            size_t i, j;\n\n            /* XXX: a stable sort would use less memory */\n            array_idx = js_malloc(ctx, len * sizeof(array_idx[0]));\n            if (!array_idx)\n                return JS_EXCEPTION;\n            for(i = 0; i < len; i++)\n                array_idx[i] = i;\n            tsc.elt_size = elt_size;\n            rqsort(array_idx, len, sizeof(array_idx[0]),\n                   js_TA_cmp_generic, &tsc);\n            if (tsc.exception) {\n                if (tsc.exception == 1)\n                    goto fail;\n                /* detached typed array during the sort: no error */\n            } else {\n                void *array_ptr = p->u.array.u.ptr;\n                len = min_int(len, p->u.array.count);\n                if (len != 0) {\n                    array_tmp = js_malloc(ctx, len * elt_size);\n                    if (!array_tmp) {\n                    fail:\n                        js_free(ctx, array_idx);\n                        return JS_EXCEPTION;\n                    }\n                    memcpy(array_tmp, array_ptr, len * elt_size);\n                    switch(elt_size) {\n                    case 1:\n                        for(i = 0; i < len; i++) {\n                            j = array_idx[i];\n                            ((uint8_t *)array_ptr)[i] = ((uint8_t *)array_tmp)[j];\n                        }\n                        break;\n                    case 2:\n                        for(i = 0; i < len; i++) {\n                            j = array_idx[i];\n                            ((uint16_t *)array_ptr)[i] = ((uint16_t *)array_tmp)[j];\n                        }\n                        break;\n                    case 4:\n                        for(i = 0; i < len; i++) {\n                            j = array_idx[i];\n                            ((uint32_t *)array_ptr)[i] = ((uint32_t *)array_tmp)[j];\n                        }\n                        break;\n                    case 8:\n                        for(i = 0; i < len; i++) {\n                            j = array_idx[i];\n                            ((uint64_t *)array_ptr)[i] = ((uint64_t *)array_tmp)[j];\n                        }\n                        break;\n                    default:\n                        abort();\n                    }\n                    js_free(ctx, array_tmp);\n                }\n            }\n            js_free(ctx, array_idx);\n        } else {\n            rqsort(p->u.array.u.ptr, len, elt_size, cmpfun, &tsc);\n            if (tsc.exception)\n                return JS_EXCEPTION;\n        }\n    }\n    return JS_DupValue(ctx, this_val);\n}\n\nstatic JSValue js_typed_array_toSorted(JSContext *ctx, JSValueConst this_val,\n                                       int argc, JSValueConst *argv)\n{\n    JSValue arr, ret;\n    JSObject *p;\n\n    p = get_typed_array(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    arr = js_typed_array_constructor_ta(ctx, JS_UNDEFINED, this_val,\n                                        p->class_id, p->u.array.count);\n    if (JS_IsException(arr))\n        return JS_EXCEPTION;\n    ret = js_typed_array_sort(ctx, arr, argc, argv);\n    JS_FreeValue(ctx, arr);\n    return ret;\n}\n\nstatic const JSCFunctionListEntry js_typed_array_base_funcs[] = {\n    JS_CFUNC_DEF(\"from\", 1, js_typed_array_from ),\n    JS_CFUNC_DEF(\"of\", 0, js_typed_array_of ),\n    JS_CGETSET_DEF(\"[Symbol.species]\", js_get_this, NULL ),\n};\n\nstatic const JSCFunctionListEntry js_typed_array_base_proto_funcs[] = {\n    JS_CGETSET_DEF(\"length\", js_typed_array_get_length, NULL ),\n    JS_CFUNC_DEF(\"at\", 1, js_typed_array_at ),\n    JS_CFUNC_DEF(\"with\", 2, js_typed_array_with ),\n    JS_CGETSET_DEF(\"buffer\", js_typed_array_get_buffer, NULL ),\n    JS_CGETSET_DEF(\"byteLength\", js_typed_array_get_byteLength, NULL ),\n    JS_CGETSET_DEF(\"byteOffset\", js_typed_array_get_byteOffset, NULL ),\n    JS_CFUNC_DEF(\"set\", 1, js_typed_array_set ),\n    JS_CFUNC_MAGIC_DEF(\"values\", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_VALUE ),\n    JS_ALIAS_DEF(\"[Symbol.iterator]\", \"values\" ),\n    JS_CFUNC_MAGIC_DEF(\"keys\", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY ),\n    JS_CFUNC_MAGIC_DEF(\"entries\", 0, js_create_typed_array_iterator, JS_ITERATOR_KIND_KEY_AND_VALUE ),\n    JS_CGETSET_DEF(\"[Symbol.toStringTag]\", js_typed_array_get_toStringTag, NULL ),\n    JS_CFUNC_DEF(\"copyWithin\", 2, js_typed_array_copyWithin ),\n    JS_CFUNC_MAGIC_DEF(\"every\", 1, js_array_every, special_every | special_TA ),\n    JS_CFUNC_MAGIC_DEF(\"some\", 1, js_array_every, special_some | special_TA ),\n    JS_CFUNC_MAGIC_DEF(\"forEach\", 1, js_array_every, special_forEach | special_TA ),\n    JS_CFUNC_MAGIC_DEF(\"map\", 1, js_array_every, special_map | special_TA ),\n    JS_CFUNC_MAGIC_DEF(\"filter\", 1, js_array_every, special_filter | special_TA ),\n    JS_CFUNC_MAGIC_DEF(\"reduce\", 1, js_array_reduce, special_reduce | special_TA ),\n    JS_CFUNC_MAGIC_DEF(\"reduceRight\", 1, js_array_reduce, special_reduceRight | special_TA ),\n    JS_CFUNC_DEF(\"fill\", 1, js_typed_array_fill ),\n    JS_CFUNC_MAGIC_DEF(\"find\", 1, js_typed_array_find, ArrayFind ),\n    JS_CFUNC_MAGIC_DEF(\"findIndex\", 1, js_typed_array_find, ArrayFindIndex ),\n    JS_CFUNC_MAGIC_DEF(\"findLast\", 1, js_typed_array_find, ArrayFindLast ),\n    JS_CFUNC_MAGIC_DEF(\"findLastIndex\", 1, js_typed_array_find, ArrayFindLastIndex ),\n    JS_CFUNC_DEF(\"reverse\", 0, js_typed_array_reverse ),\n    JS_CFUNC_DEF(\"toReversed\", 0, js_typed_array_toReversed ),\n    JS_CFUNC_DEF(\"slice\", 2, js_typed_array_slice ),\n    JS_CFUNC_DEF(\"subarray\", 2, js_typed_array_subarray ),\n    JS_CFUNC_DEF(\"sort\", 1, js_typed_array_sort ),\n    JS_CFUNC_DEF(\"toSorted\", 1, js_typed_array_toSorted ),\n    JS_CFUNC_MAGIC_DEF(\"join\", 1, js_typed_array_join, 0 ),\n    JS_CFUNC_MAGIC_DEF(\"toLocaleString\", 0, js_typed_array_join, 1 ),\n    JS_CFUNC_MAGIC_DEF(\"indexOf\", 1, js_typed_array_indexOf, special_indexOf ),\n    JS_CFUNC_MAGIC_DEF(\"lastIndexOf\", 1, js_typed_array_indexOf, special_lastIndexOf ),\n    JS_CFUNC_MAGIC_DEF(\"includes\", 1, js_typed_array_indexOf, special_includes ),\n    //JS_ALIAS_BASE_DEF(\"toString\", \"toString\", 2 /* Array.prototype. */), @@@\n};\n\nstatic const JSCFunctionListEntry js_typed_array_funcs[] = {\n    JS_PROP_INT32_DEF(\"BYTES_PER_ELEMENT\", 1, 0),\n    JS_PROP_INT32_DEF(\"BYTES_PER_ELEMENT\", 2, 0),\n    JS_PROP_INT32_DEF(\"BYTES_PER_ELEMENT\", 4, 0),\n    JS_PROP_INT32_DEF(\"BYTES_PER_ELEMENT\", 8, 0),\n};\n\nstatic JSValue js_typed_array_base_constructor(JSContext *ctx,\n                                               JSValueConst this_val,\n                                               int argc, JSValueConst *argv)\n{\n    return JS_ThrowTypeError(ctx, \"cannot be called\");\n}\n\n/* 'obj' must be an allocated typed array object */\nstatic int typed_array_init(JSContext *ctx, JSValueConst obj,\n                            JSValue buffer, uint64_t offset, uint64_t len,\n                            BOOL track_rab)\n{\n    JSTypedArray *ta;\n    JSObject *p, *pbuffer;\n    JSArrayBuffer *abuf;\n    int size_log2;\n\n    p = JS_VALUE_GET_OBJ(obj);\n    size_log2 = typed_array_size_log2(p->class_id);\n    ta = js_malloc(ctx, sizeof(*ta));\n    if (!ta) {\n        JS_FreeValue(ctx, buffer);\n        return -1;\n    }\n    pbuffer = JS_VALUE_GET_OBJ(buffer);\n    abuf = pbuffer->u.array_buffer;\n    ta->obj = p;\n    ta->buffer = pbuffer;\n    ta->offset = offset;\n    ta->length = len << size_log2;\n    ta->track_rab = track_rab;\n    list_add_tail(&ta->link, &abuf->array_list);\n    p->u.typed_array = ta;\n    p->u.array.count = len;\n    p->u.array.u.ptr = abuf->data + offset;\n    return 0;\n}\n\n\nstatic JSValue js_array_from_iterator(JSContext *ctx, uint32_t *plen,\n                                      JSValueConst obj, JSValueConst method)\n{\n    JSValue arr, iter, next_method = JS_UNDEFINED, val;\n    BOOL done;\n    uint32_t k;\n\n    *plen = 0;\n    arr = JS_NewArray(ctx);\n    if (JS_IsException(arr))\n        return arr;\n    iter = JS_GetIterator2(ctx, obj, method);\n    if (JS_IsException(iter))\n        goto fail;\n    next_method = JS_GetProperty(ctx, iter, JS_ATOM_next);\n    if (JS_IsException(next_method))\n        goto fail;\n    k = 0;\n    for(;;) {\n        val = JS_IteratorNext(ctx, iter, next_method, 0, NULL, &done);\n        if (JS_IsException(val))\n            goto fail;\n        if (done)\n            break;\n        if (JS_CreateDataPropertyUint32(ctx, arr, k, val, JS_PROP_THROW) < 0)\n            goto fail;\n        k++;\n    }\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    *plen = k;\n    return arr;\n fail:\n    JS_FreeValue(ctx, next_method);\n    JS_FreeValue(ctx, iter);\n    JS_FreeValue(ctx, arr);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_typed_array_constructor_obj(JSContext *ctx,\n                                              JSValueConst new_target,\n                                              JSValueConst obj,\n                                              int classid)\n{\n    JSValue iter, ret, arr = JS_UNDEFINED, val, buffer;\n    uint32_t i;\n    int size_log2;\n    int64_t len;\n\n    size_log2 = typed_array_size_log2(classid);\n    ret = js_create_from_ctor(ctx, new_target, classid);\n    if (JS_IsException(ret))\n        return JS_EXCEPTION;\n\n    iter = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);\n    if (JS_IsException(iter))\n        goto fail;\n    if (!JS_IsUndefined(iter) && !JS_IsNull(iter)) {\n        uint32_t len1;\n        arr = js_array_from_iterator(ctx, &len1, obj, iter);\n        JS_FreeValue(ctx, iter);\n        if (JS_IsException(arr))\n            goto fail;\n        len = len1;\n    } else {\n        if (js_get_length64(ctx, &len, obj))\n            goto fail;\n        arr = JS_DupValue(ctx, obj);\n    }\n\n    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,\n                                          len << size_log2,\n                                          NULL);\n    if (JS_IsException(buffer))\n        goto fail;\n    if (typed_array_init(ctx, ret, buffer, 0, len, /*track_rab*/FALSE))\n        goto fail;\n\n    for(i = 0; i < len; i++) {\n        val = JS_GetPropertyUint32(ctx, arr, i);\n        if (JS_IsException(val))\n            goto fail;\n        if (JS_SetPropertyUint32(ctx, ret, i, val) < 0)\n            goto fail;\n    }\n    JS_FreeValue(ctx, arr);\n    return ret;\n fail:\n    JS_FreeValue(ctx, arr);\n    JS_FreeValue(ctx, ret);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_typed_array_constructor_ta(JSContext *ctx,\n                                             JSValueConst new_target,\n                                             JSValueConst src_obj,\n                                             int classid, uint32_t len)\n{\n    JSObject *p, *src_buffer;\n    JSTypedArray *ta;\n    JSValue obj, buffer;\n    uint32_t i;\n    int size_log2;\n    JSArrayBuffer *src_abuf, *abuf;\n\n    obj = js_create_from_ctor(ctx, new_target, classid);\n    if (JS_IsException(obj))\n        return obj;\n    p = JS_VALUE_GET_OBJ(src_obj);\n    if (typed_array_is_oob(p)) {\n        JS_ThrowTypeErrorArrayBufferOOB(ctx);\n        goto fail;\n    }\n    ta = p->u.typed_array;\n    src_buffer = ta->buffer;\n    src_abuf = src_buffer->u.array_buffer;\n    size_log2 = typed_array_size_log2(classid);\n    buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,\n                                          (uint64_t)len << size_log2,\n                                          NULL);\n    if (JS_IsException(buffer))\n        goto fail;\n    /* necessary because it could have been detached */\n    if (typed_array_is_oob(p)) {\n        JS_FreeValue(ctx, buffer);\n        JS_ThrowTypeErrorArrayBufferOOB(ctx);\n        goto fail;\n    }\n    abuf = JS_GetOpaque(buffer, JS_CLASS_ARRAY_BUFFER);\n    if (typed_array_init(ctx, obj, buffer, 0, len, /*track_rab*/FALSE))\n        goto fail;\n    if (p->class_id == classid) {\n        /* same type: copy the content */\n        memcpy(abuf->data, src_abuf->data + ta->offset, abuf->byte_length);\n    } else {\n        for(i = 0; i < len; i++) {\n            JSValue val;\n            val = JS_GetPropertyUint32(ctx, src_obj, i);\n            if (JS_IsException(val))\n                goto fail;\n            if (JS_SetPropertyUint32(ctx, obj, i, val) < 0)\n                goto fail;\n        }\n    }\n    return obj;\n fail:\n    JS_FreeValue(ctx, obj);\n    return JS_EXCEPTION;\n}\n\nstatic JSValue js_typed_array_constructor(JSContext *ctx,\n                                          JSValueConst new_target,\n                                          int argc, JSValueConst *argv,\n                                          int classid)\n{\n    BOOL track_rab = FALSE;\n    JSValue buffer, obj;\n    JSArrayBuffer *abuf;\n    int size_log2;\n    uint64_t len, offset;\n\n    size_log2 = typed_array_size_log2(classid);\n    if (JS_VALUE_GET_TAG(argv[0]) != JS_TAG_OBJECT) {\n        if (JS_ToIndex(ctx, &len, argv[0]))\n            return JS_EXCEPTION;\n        buffer = js_array_buffer_constructor1(ctx, JS_UNDEFINED,\n                                              len << size_log2,\n                                              NULL);\n        if (JS_IsException(buffer))\n            return JS_EXCEPTION;\n        offset = 0;\n    } else {\n        JSObject *p = JS_VALUE_GET_OBJ(argv[0]);\n        if (p->class_id == JS_CLASS_ARRAY_BUFFER ||\n            p->class_id == JS_CLASS_SHARED_ARRAY_BUFFER) {\n            abuf = p->u.array_buffer;\n            if (JS_ToIndex(ctx, &offset, argv[1]))\n                return JS_EXCEPTION;\n            if (abuf->detached)\n                return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n            if ((offset & ((1 << size_log2) - 1)) != 0 ||\n                offset > abuf->byte_length)\n                return JS_ThrowRangeError(ctx, \"invalid offset\");\n            if (JS_IsUndefined(argv[2])) {\n                track_rab = array_buffer_is_resizable(abuf);\n                if (!track_rab)\n                    if ((abuf->byte_length & ((1 << size_log2) - 1)) != 0)\n                        goto invalid_length;\n                len = (abuf->byte_length - offset) >> size_log2;\n            } else {\n                if (JS_ToIndex(ctx, &len, argv[2]))\n                    return JS_EXCEPTION;\n                if (abuf->detached)\n                    return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n                if ((offset + (len << size_log2)) > abuf->byte_length) {\n                invalid_length:\n                    return JS_ThrowRangeError(ctx, \"invalid length\");\n                }\n            }\n            buffer = JS_DupValue(ctx, argv[0]);\n        } else {\n            if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&\n                p->class_id <= JS_CLASS_FLOAT64_ARRAY) {\n                return js_typed_array_constructor_ta(ctx, new_target, argv[0],\n                                                     classid, p->u.array.count);\n            } else {\n                return js_typed_array_constructor_obj(ctx, new_target, argv[0], classid);\n            }\n        }\n    }\n\n    obj = js_create_from_ctor(ctx, new_target, classid);\n    if (JS_IsException(obj)) {\n        JS_FreeValue(ctx, buffer);\n        return JS_EXCEPTION;\n    }\n    if (typed_array_init(ctx, obj, buffer, offset, len, track_rab)) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    return obj;\n}\n\nstatic void js_typed_array_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSTypedArray *ta = p->u.typed_array;\n    if (ta) {\n        /* during the GC the finalizers are called in an arbitrary\n           order so the ArrayBuffer finalizer may have been called */\n        if (ta->link.next) {\n            list_del(&ta->link);\n        }\n        JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));\n        js_free_rt(rt, ta);\n    }\n}\n\nstatic void js_typed_array_mark(JSRuntime *rt, JSValueConst val,\n                                JS_MarkFunc *mark_func)\n{\n    JSObject *p = JS_VALUE_GET_OBJ(val);\n    JSTypedArray *ta = p->u.typed_array;\n    if (ta) {\n        JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ta->buffer), mark_func);\n    }\n}\n\nstatic JSValue js_dataview_constructor(JSContext *ctx,\n                                       JSValueConst new_target,\n                                       int argc, JSValueConst *argv)\n{\n    BOOL recompute_len = FALSE;\n    BOOL track_rab = FALSE;\n    JSArrayBuffer *abuf;\n    uint64_t offset;\n    uint32_t len;\n    JSValueConst buffer;\n    JSValue obj;\n    JSTypedArray *ta;\n    JSObject *p;\n\n    buffer = argv[0];\n    abuf = js_get_array_buffer(ctx, buffer);\n    if (!abuf)\n        return JS_EXCEPTION;\n    offset = 0;\n    if (argc > 1) {\n        if (JS_ToIndex(ctx, &offset, argv[1]))\n            return JS_EXCEPTION;\n    }\n    if (abuf->detached)\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n    if (offset > abuf->byte_length)\n        return JS_ThrowRangeError(ctx, \"invalid byteOffset\");\n    len = abuf->byte_length - offset;\n    if (argc > 2 && !JS_IsUndefined(argv[2])) {\n        uint64_t l;\n        if (JS_ToIndex(ctx, &l, argv[2]))\n            return JS_EXCEPTION;\n        if (l > len)\n            return JS_ThrowRangeError(ctx, \"invalid byteLength\");\n        len = l;\n    } else {\n        recompute_len = TRUE;\n        track_rab = array_buffer_is_resizable(abuf);\n    }\n\n    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_DATAVIEW);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    if (abuf->detached) {\n        /* could have been detached in js_create_from_ctor() */\n        JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n        goto fail;\n    }\n    // RAB could have been resized in js_create_from_ctor()\n    if (offset > abuf->byte_length) {\n        goto out_of_bound;\n    } else if (recompute_len) {\n        len = abuf->byte_length - offset;\n    } else if (offset + len > abuf->byte_length) {\n    out_of_bound:\n        JS_ThrowRangeError(ctx, \"invalid byteOffset or byteLength\");\n        goto fail;\n    }\n    ta = js_malloc(ctx, sizeof(*ta));\n    if (!ta) {\n    fail:\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    p = JS_VALUE_GET_OBJ(obj);\n    ta->obj = p;\n    ta->buffer = JS_VALUE_GET_OBJ(JS_DupValue(ctx, buffer));\n    ta->offset = offset;\n    ta->length = len;\n    ta->track_rab = track_rab;\n    list_add_tail(&ta->link, &abuf->array_list);\n    p->u.typed_array = ta;\n    return obj;\n}\n\n// is the DataView out of bounds relative to its parent arraybuffer?\nstatic BOOL dataview_is_oob(JSObject *p)\n{\n    JSArrayBuffer *abuf;\n    JSTypedArray *ta;\n\n    assert(p->class_id == JS_CLASS_DATAVIEW);\n    ta = p->u.typed_array;\n    abuf = ta->buffer->u.array_buffer;\n    if (abuf->detached)\n        return TRUE;\n    if (ta->offset > abuf->byte_length)\n        return TRUE;\n    if (ta->track_rab)\n        return FALSE;\n    return (int64_t)ta->offset + ta->length > abuf->byte_length;\n}\n\nstatic JSObject *get_dataview(JSContext *ctx, JSValueConst this_val)\n{\n    JSObject *p;\n    if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)\n        goto fail;\n    p = JS_VALUE_GET_OBJ(this_val);\n    if (p->class_id != JS_CLASS_DATAVIEW) {\n    fail:\n        JS_ThrowTypeError(ctx, \"not a DataView\");\n        return NULL;\n    }\n    return p;\n}\n\nstatic JSValue js_dataview_get_buffer(JSContext *ctx, JSValueConst this_val)\n{\n    JSObject *p;\n    JSTypedArray *ta;\n    p = get_dataview(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    ta = p->u.typed_array;\n    return JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, ta->buffer));\n}\n\nstatic JSValue js_dataview_get_byteLength(JSContext *ctx, JSValueConst this_val)\n{\n    JSArrayBuffer *abuf;\n    JSTypedArray *ta;\n    JSObject *p;\n\n    p = get_dataview(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (dataview_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    ta = p->u.typed_array;\n    if (ta->track_rab) {\n        abuf = ta->buffer->u.array_buffer;\n        return JS_NewUint32(ctx, abuf->byte_length - ta->offset);\n    }\n    return JS_NewUint32(ctx, ta->length);\n}\n\nstatic JSValue js_dataview_get_byteOffset(JSContext *ctx, JSValueConst this_val)\n{\n    JSTypedArray *ta;\n    JSObject *p;\n\n    p = get_dataview(ctx, this_val);\n    if (!p)\n        return JS_EXCEPTION;\n    if (dataview_is_oob(p))\n        return JS_ThrowTypeErrorArrayBufferOOB(ctx);\n    ta = p->u.typed_array;\n    return JS_NewUint32(ctx, ta->offset);\n}\n\nstatic JSValue js_dataview_getValue(JSContext *ctx,\n                                    JSValueConst this_obj,\n                                    int argc, JSValueConst *argv, int class_id)\n{\n    JSTypedArray *ta;\n    JSArrayBuffer *abuf;\n    BOOL littleEndian, is_swap;\n    int size;\n    uint8_t *ptr;\n    uint32_t v;\n    uint64_t pos;\n\n    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);\n    if (!ta)\n        return JS_EXCEPTION;\n    size = 1 << typed_array_size_log2(class_id);\n    if (JS_ToIndex(ctx, &pos, argv[0]))\n        return JS_EXCEPTION;\n    littleEndian = argc > 1 && JS_ToBool(ctx, argv[1]);\n    is_swap = littleEndian ^ !is_be();\n    abuf = ta->buffer->u.array_buffer;\n    if (abuf->detached)\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n    // order matters: this check should come before the next one\n    if ((pos + size) > ta->length)\n        return JS_ThrowRangeError(ctx, \"out of bound\");\n    // test262 expects a TypeError for this and V8, in its infinite wisdom,\n    // throws a \"detached array buffer\" exception, but IMO that doesn't make\n    // sense because the buffer is not in fact detached, it's still there\n    if ((int64_t)ta->offset + ta->length > abuf->byte_length)\n        return JS_ThrowTypeError(ctx, \"out of bound\");\n    ptr = abuf->data + ta->offset + pos;\n\n    switch(class_id) {\n    case JS_CLASS_INT8_ARRAY:\n        return JS_NewInt32(ctx, *(int8_t *)ptr);\n    case JS_CLASS_UINT8_ARRAY:\n        return JS_NewInt32(ctx, *(uint8_t *)ptr);\n    case JS_CLASS_INT16_ARRAY:\n        v = get_u16(ptr);\n        if (is_swap)\n            v = bswap16(v);\n        return JS_NewInt32(ctx, (int16_t)v);\n    case JS_CLASS_UINT16_ARRAY:\n        v = get_u16(ptr);\n        if (is_swap)\n            v = bswap16(v);\n        return JS_NewInt32(ctx, v);\n    case JS_CLASS_INT32_ARRAY:\n        v = get_u32(ptr);\n        if (is_swap)\n            v = bswap32(v);\n        return JS_NewInt32(ctx, v);\n    case JS_CLASS_UINT32_ARRAY:\n        v = get_u32(ptr);\n        if (is_swap)\n            v = bswap32(v);\n        return JS_NewUint32(ctx, v);\n    case JS_CLASS_BIG_INT64_ARRAY:\n        {\n            uint64_t v;\n            v = get_u64(ptr);\n            if (is_swap)\n                v = bswap64(v);\n            return JS_NewBigInt64(ctx, v);\n        }\n        break;\n    case JS_CLASS_BIG_UINT64_ARRAY:\n        {\n            uint64_t v;\n            v = get_u64(ptr);\n            if (is_swap)\n                v = bswap64(v);\n            return JS_NewBigUint64(ctx, v);\n        }\n        break;\n    case JS_CLASS_FLOAT16_ARRAY:\n        {\n            uint16_t v;\n            v = get_u16(ptr);\n            if (is_swap)\n                v = bswap16(v);\n            return __JS_NewFloat64(ctx, fromfp16(v));\n        }\n    case JS_CLASS_FLOAT32_ARRAY:\n        {\n            union {\n                float f;\n                uint32_t i;\n            } u;\n            v = get_u32(ptr);\n            if (is_swap)\n                v = bswap32(v);\n            u.i = v;\n            return __JS_NewFloat64(ctx, u.f);\n        }\n    case JS_CLASS_FLOAT64_ARRAY:\n        {\n            union {\n                double f;\n                uint64_t i;\n            } u;\n            u.i = get_u64(ptr);\n            if (is_swap)\n                u.i = bswap64(u.i);\n            return __JS_NewFloat64(ctx, u.f);\n        }\n    default:\n        abort();\n    }\n}\n\nstatic JSValue js_dataview_setValue(JSContext *ctx,\n                                    JSValueConst this_obj,\n                                    int argc, JSValueConst *argv, int class_id)\n{\n    JSTypedArray *ta;\n    JSArrayBuffer *abuf;\n    BOOL littleEndian, is_swap;\n    int size;\n    uint8_t *ptr;\n    uint64_t v64;\n    uint32_t v;\n    uint64_t pos;\n    JSValueConst val;\n\n    ta = JS_GetOpaque2(ctx, this_obj, JS_CLASS_DATAVIEW);\n    if (!ta)\n        return JS_EXCEPTION;\n    size = 1 << typed_array_size_log2(class_id);\n    if (JS_ToIndex(ctx, &pos, argv[0]))\n        return JS_EXCEPTION;\n    val = argv[1];\n    v = 0; /* avoid warning */\n    v64 = 0; /* avoid warning */\n    if (class_id <= JS_CLASS_UINT32_ARRAY) {\n        if (JS_ToUint32(ctx, &v, val))\n            return JS_EXCEPTION;\n    } else if (class_id <= JS_CLASS_BIG_UINT64_ARRAY) {\n        if (JS_ToBigInt64(ctx, (int64_t *)&v64, val))\n            return JS_EXCEPTION;\n    } else {\n        double d;\n        if (JS_ToFloat64(ctx, &d, val))\n            return JS_EXCEPTION;\n        if (class_id == JS_CLASS_FLOAT16_ARRAY) {\n            v = tofp16(d);\n        } else if (class_id == JS_CLASS_FLOAT32_ARRAY) {\n            union {\n                float f;\n                uint32_t i;\n            } u;\n            u.f = d;\n            v = u.i;\n        } else {\n            JSFloat64Union u;\n            u.d = d;\n            v64 = u.u64;\n        }\n    }\n    littleEndian = argc > 2 && JS_ToBool(ctx, argv[2]);\n    is_swap = littleEndian ^ !is_be();\n    abuf = ta->buffer->u.array_buffer;\n    if (abuf->detached)\n        return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n    // order matters: this check should come before the next one\n    if ((pos + size) > ta->length)\n        return JS_ThrowRangeError(ctx, \"out of bound\");\n    // test262 expects a TypeError for this and V8, in its infinite wisdom,\n    // throws a \"detached array buffer\" exception, but IMO that doesn't make\n    // sense because the buffer is not in fact detached, it's still there\n    if ((int64_t)ta->offset + ta->length > abuf->byte_length)\n        return JS_ThrowTypeError(ctx, \"out of bound\");\n    ptr = abuf->data + ta->offset + pos;\n\n    switch(class_id) {\n    case JS_CLASS_INT8_ARRAY:\n    case JS_CLASS_UINT8_ARRAY:\n        *ptr = v;\n        break;\n    case JS_CLASS_INT16_ARRAY:\n    case JS_CLASS_UINT16_ARRAY:\n    case JS_CLASS_FLOAT16_ARRAY:\n        if (is_swap)\n            v = bswap16(v);\n        put_u16(ptr, v);\n        break;\n    case JS_CLASS_INT32_ARRAY:\n    case JS_CLASS_UINT32_ARRAY:\n    case JS_CLASS_FLOAT32_ARRAY:\n        if (is_swap)\n            v = bswap32(v);\n        put_u32(ptr, v);\n        break;\n    case JS_CLASS_BIG_INT64_ARRAY:\n    case JS_CLASS_BIG_UINT64_ARRAY:\n    case JS_CLASS_FLOAT64_ARRAY:\n        if (is_swap)\n            v64 = bswap64(v64);\n        put_u64(ptr, v64);\n        break;\n    default:\n        abort();\n    }\n    return JS_UNDEFINED;\n}\n\nstatic const JSCFunctionListEntry js_dataview_proto_funcs[] = {\n    JS_CGETSET_DEF(\"buffer\", js_dataview_get_buffer, NULL ),\n    JS_CGETSET_DEF(\"byteLength\", js_dataview_get_byteLength, NULL ),\n    JS_CGETSET_DEF(\"byteOffset\", js_dataview_get_byteOffset, NULL ),\n    JS_CFUNC_MAGIC_DEF(\"getInt8\", 1, js_dataview_getValue, JS_CLASS_INT8_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getUint8\", 1, js_dataview_getValue, JS_CLASS_UINT8_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getInt16\", 1, js_dataview_getValue, JS_CLASS_INT16_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getUint16\", 1, js_dataview_getValue, JS_CLASS_UINT16_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getInt32\", 1, js_dataview_getValue, JS_CLASS_INT32_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getUint32\", 1, js_dataview_getValue, JS_CLASS_UINT32_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getBigInt64\", 1, js_dataview_getValue, JS_CLASS_BIG_INT64_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getBigUint64\", 1, js_dataview_getValue, JS_CLASS_BIG_UINT64_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getFloat16\", 1, js_dataview_getValue, JS_CLASS_FLOAT16_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getFloat32\", 1, js_dataview_getValue, JS_CLASS_FLOAT32_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"getFloat64\", 1, js_dataview_getValue, JS_CLASS_FLOAT64_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setInt8\", 2, js_dataview_setValue, JS_CLASS_INT8_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setUint8\", 2, js_dataview_setValue, JS_CLASS_UINT8_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setInt16\", 2, js_dataview_setValue, JS_CLASS_INT16_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setUint16\", 2, js_dataview_setValue, JS_CLASS_UINT16_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setInt32\", 2, js_dataview_setValue, JS_CLASS_INT32_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setUint32\", 2, js_dataview_setValue, JS_CLASS_UINT32_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setBigInt64\", 2, js_dataview_setValue, JS_CLASS_BIG_INT64_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setBigUint64\", 2, js_dataview_setValue, JS_CLASS_BIG_UINT64_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setFloat16\", 2, js_dataview_setValue, JS_CLASS_FLOAT16_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setFloat32\", 2, js_dataview_setValue, JS_CLASS_FLOAT32_ARRAY ),\n    JS_CFUNC_MAGIC_DEF(\"setFloat64\", 2, js_dataview_setValue, JS_CLASS_FLOAT64_ARRAY ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"DataView\", JS_PROP_CONFIGURABLE ),\n};\n\n/* Atomics */\n#ifdef CONFIG_ATOMICS\n\ntypedef enum AtomicsOpEnum {\n    ATOMICS_OP_ADD,\n    ATOMICS_OP_AND,\n    ATOMICS_OP_OR,\n    ATOMICS_OP_SUB,\n    ATOMICS_OP_XOR,\n    ATOMICS_OP_EXCHANGE,\n    ATOMICS_OP_COMPARE_EXCHANGE,\n    ATOMICS_OP_LOAD,\n} AtomicsOpEnum;\n\nstatic int js_atomics_get_ptr(JSContext *ctx,\n                              void **pptr,\n                              JSArrayBuffer **pabuf,\n                              int *psize_log2, JSClassID *pclass_id,\n                              JSValueConst obj, JSValueConst idx_val,\n                              int is_waitable)\n{\n    JSObject *p;\n    JSTypedArray *ta;\n    JSArrayBuffer *abuf;\n    void *ptr;\n    uint64_t idx;\n    BOOL err;\n    int size_log2, old_len;\n\n    if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT)\n        goto fail;\n    p = JS_VALUE_GET_OBJ(obj);\n    if (is_waitable)\n        err = (p->class_id != JS_CLASS_INT32_ARRAY &&\n               p->class_id != JS_CLASS_BIG_INT64_ARRAY);\n    else\n        err = !(p->class_id >= JS_CLASS_INT8_ARRAY &&\n                p->class_id <= JS_CLASS_BIG_UINT64_ARRAY);\n    if (err) {\n    fail:\n        JS_ThrowTypeError(ctx, \"integer TypedArray expected\");\n        return -1;\n    }\n    ta = p->u.typed_array;\n    abuf = ta->buffer->u.array_buffer;\n    if (!abuf->shared) {\n        if (is_waitable == 2) {\n            JS_ThrowTypeError(ctx, \"not a SharedArrayBuffer TypedArray\");\n            return -1;\n        }\n        if (abuf->detached) {\n            JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n            return -1;\n        }\n    }\n    old_len = p->u.array.count;\n    \n    if (JS_ToIndex(ctx, &idx, idx_val)) {\n        return -1;\n    }\n\n    if (idx >= old_len)\n        goto oob;\n\n    if (is_waitable == 1) {\n        /* notify(): just avoid having an invalid pointer if overflow */\n        if (idx >= p->u.array.count)\n            ptr = NULL;\n    } else {\n        /* RevalidateAtomicAccess() */\n        if (typed_array_is_oob(p)) {\n            JS_ThrowTypeErrorArrayBufferOOB(ctx);\n            return -1;\n        }\n        if (idx >= p->u.array.count) {\n        oob:\n            JS_ThrowRangeError(ctx, \"out-of-bound access\");\n            return -1;\n        }\n    }\n\n    size_log2 = typed_array_size_log2(p->class_id);\n    ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);\n    if (pabuf)\n        *pabuf = abuf;\n    if (psize_log2)\n        *psize_log2 = size_log2;\n    if (pclass_id)\n        *pclass_id = p->class_id;\n    *pptr = ptr;\n    return 0;\n}\n\nstatic JSValue js_atomics_op(JSContext *ctx,\n                             JSValueConst this_obj,\n                             int argc, JSValueConst *argv, int op)\n{\n    int size_log2;\n    uint64_t v, a, rep_val;\n    void *ptr;\n    JSValue ret;\n    JSClassID class_id;\n    JSArrayBuffer *abuf;\n\n    if (js_atomics_get_ptr(ctx, &ptr, &abuf, &size_log2, &class_id,\n                           argv[0], argv[1], 0))\n        return JS_EXCEPTION;\n    rep_val = 0;\n    if (op == ATOMICS_OP_LOAD) {\n        v = 0;\n    } else {\n        if (size_log2 == 3) {\n            int64_t v64;\n            if (JS_ToBigInt64(ctx, &v64, argv[2]))\n                return JS_EXCEPTION;\n            v = v64;\n            if (op == ATOMICS_OP_COMPARE_EXCHANGE) {\n                if (JS_ToBigInt64(ctx, &v64, argv[3]))\n                    return JS_EXCEPTION;\n                rep_val = v64;\n            }\n        } else {\n                uint32_t v32;\n                if (JS_ToUint32(ctx, &v32, argv[2]))\n                    return JS_EXCEPTION;\n                v = v32;\n                if (op == ATOMICS_OP_COMPARE_EXCHANGE) {\n                    if (JS_ToUint32(ctx, &v32, argv[3]))\n                        return JS_EXCEPTION;\n                    rep_val = v32;\n                }\n        }\n        if (abuf->detached)\n            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n   }\n\n   switch(op | (size_log2 << 3)) {\n\n#define OP(op_name, func_name)                          \\\n    case ATOMICS_OP_ ## op_name | (0 << 3):             \\\n       a = func_name((_Atomic(uint8_t) *)ptr, v);       \\\n       break;                                           \\\n    case ATOMICS_OP_ ## op_name | (1 << 3):             \\\n        a = func_name((_Atomic(uint16_t) *)ptr, v);     \\\n        break;                                          \\\n    case ATOMICS_OP_ ## op_name | (2 << 3):             \\\n        a = func_name((_Atomic(uint32_t) *)ptr, v);     \\\n        break;                                          \\\n    case ATOMICS_OP_ ## op_name | (3 << 3):             \\\n        a = func_name((_Atomic(uint64_t) *)ptr, v);     \\\n        break;\n\n        OP(ADD, atomic_fetch_add)\n        OP(AND, atomic_fetch_and)\n        OP(OR, atomic_fetch_or)\n        OP(SUB, atomic_fetch_sub)\n        OP(XOR, atomic_fetch_xor)\n        OP(EXCHANGE, atomic_exchange)\n#undef OP\n\n    case ATOMICS_OP_LOAD | (0 << 3):\n        a = atomic_load((_Atomic(uint8_t) *)ptr);\n        break;\n    case ATOMICS_OP_LOAD | (1 << 3):\n        a = atomic_load((_Atomic(uint16_t) *)ptr);\n        break;\n    case ATOMICS_OP_LOAD | (2 << 3):\n        a = atomic_load((_Atomic(uint32_t) *)ptr);\n        break;\n    case ATOMICS_OP_LOAD | (3 << 3):\n        a = atomic_load((_Atomic(uint64_t) *)ptr);\n        break;\n\n    case ATOMICS_OP_COMPARE_EXCHANGE | (0 << 3):\n        {\n            uint8_t v1 = v;\n            atomic_compare_exchange_strong((_Atomic(uint8_t) *)ptr, &v1, rep_val);\n            a = v1;\n        }\n        break;\n    case ATOMICS_OP_COMPARE_EXCHANGE | (1 << 3):\n        {\n            uint16_t v1 = v;\n            atomic_compare_exchange_strong((_Atomic(uint16_t) *)ptr, &v1, rep_val);\n            a = v1;\n        }\n        break;\n    case ATOMICS_OP_COMPARE_EXCHANGE | (2 << 3):\n        {\n            uint32_t v1 = v;\n            atomic_compare_exchange_strong((_Atomic(uint32_t) *)ptr, &v1, rep_val);\n            a = v1;\n        }\n        break;\n    case ATOMICS_OP_COMPARE_EXCHANGE | (3 << 3):\n        {\n            uint64_t v1 = v;\n            atomic_compare_exchange_strong((_Atomic(uint64_t) *)ptr, &v1, rep_val);\n            a = v1;\n        }\n        break;\n    default:\n        abort();\n    }\n\n    switch(class_id) {\n    case JS_CLASS_INT8_ARRAY:\n        a = (int8_t)a;\n        goto done;\n    case JS_CLASS_UINT8_ARRAY:\n        a = (uint8_t)a;\n        goto done;\n    case JS_CLASS_INT16_ARRAY:\n        a = (int16_t)a;\n        goto done;\n    case JS_CLASS_UINT16_ARRAY:\n        a = (uint16_t)a;\n        goto done;\n    case JS_CLASS_INT32_ARRAY:\n    done:\n        ret = JS_NewInt32(ctx, a);\n        break;\n    case JS_CLASS_UINT32_ARRAY:\n        ret = JS_NewUint32(ctx, a);\n        break;\n    case JS_CLASS_BIG_INT64_ARRAY:\n        ret = JS_NewBigInt64(ctx, a);\n        break;\n    case JS_CLASS_BIG_UINT64_ARRAY:\n        ret = JS_NewBigUint64(ctx, a);\n        break;\n    default:\n        abort();\n    }\n    return ret;\n}\n\nstatic JSValue js_atomics_store(JSContext *ctx,\n                                JSValueConst this_obj,\n                                int argc, JSValueConst *argv)\n{\n    int size_log2;\n    void *ptr;\n    JSValue ret;\n    JSArrayBuffer *abuf;\n\n    if (js_atomics_get_ptr(ctx, &ptr, &abuf, &size_log2, NULL,\n                           argv[0], argv[1], 0))\n        return JS_EXCEPTION;\n    if (size_log2 == 3) {\n        int64_t v64;\n        ret = JS_ToBigIntFree(ctx, JS_DupValue(ctx, argv[2]));\n        if (JS_IsException(ret))\n            return ret;\n        if (JS_ToBigInt64(ctx, &v64, ret)) {\n            JS_FreeValue(ctx, ret);\n            return JS_EXCEPTION;\n        }\n        if (abuf->detached)\n            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n        atomic_store((_Atomic(uint64_t) *)ptr, v64);\n    } else {\n        uint32_t v;\n        /* XXX: spec, would be simpler to return the written value */\n        ret = JS_ToIntegerFree(ctx, JS_DupValue(ctx, argv[2]));\n        if (JS_IsException(ret))\n            return ret;\n        if (JS_ToUint32(ctx, &v, ret)) {\n            JS_FreeValue(ctx, ret);\n            return JS_EXCEPTION;\n        }\n        if (abuf->detached)\n            return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);\n        switch(size_log2) {\n        case 0:\n            atomic_store((_Atomic(uint8_t) *)ptr, v);\n            break;\n        case 1:\n            atomic_store((_Atomic(uint16_t) *)ptr, v);\n            break;\n        case 2:\n            atomic_store((_Atomic(uint32_t) *)ptr, v);\n            break;\n        default:\n            abort();\n        }\n    }\n    return ret;\n}\n\nstatic JSValue js_atomics_isLockFree(JSContext *ctx,\n                                     JSValueConst this_obj,\n                                     int argc, JSValueConst *argv)\n{\n    int v, ret;\n    if (JS_ToInt32Sat(ctx, &v, argv[0]))\n        return JS_EXCEPTION;\n    ret = (v == 1 || v == 2 || v == 4 || v == 8);\n    return JS_NewBool(ctx, ret);\n}\n\ntypedef struct JSAtomicsWaiter {\n    struct list_head link;\n    BOOL linked;\n    pthread_cond_t cond;\n    int32_t *ptr;\n} JSAtomicsWaiter;\n\nstatic pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER;\nstatic struct list_head js_atomics_waiter_list =\n    LIST_HEAD_INIT(js_atomics_waiter_list);\n\n#if defined(__aarch64__)\nstatic inline void cpu_pause(void)\n{\n    asm volatile(\"yield\" ::: \"memory\");\n}\n#elif defined(__x86_64) || defined(__i386__)\nstatic inline void cpu_pause(void)\n{\n    asm volatile(\"pause\" ::: \"memory\");\n}\n#else\nstatic inline void cpu_pause(void)\n{\n}\n#endif\n\n// no-op: Atomics.pause() is not allowed to block or yield to another\n// thread, only to hint the CPU that it should back off for a bit;\n// the amount of work we do here is a good enough substitute\nstatic JSValue js_atomics_pause(JSContext *ctx, JSValueConst this_obj,\n                                int argc, JSValueConst *argv)\n{\n    double d;\n\n    if (argc > 0) {\n        switch (JS_VALUE_GET_NORM_TAG(argv[0])) {\n        case JS_TAG_FLOAT64: // accepted if and only if fraction == 0.0\n            d = JS_VALUE_GET_FLOAT64(argv[0]);\n            if (isfinite(d))\n                if (0 == modf(d, &d))\n                    break;\n            // fallthru\n        default:\n            return JS_ThrowTypeError(ctx, \"not an integral number\");\n        case JS_TAG_UNDEFINED:\n        case JS_TAG_INT:\n            break;\n        }\n    }\n    cpu_pause();\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_atomics_wait(JSContext *ctx,\n                               JSValueConst this_obj,\n                               int argc, JSValueConst *argv)\n{\n    int64_t v;\n    int32_t v32;\n    void *ptr;\n    int64_t timeout;\n    struct timespec ts;\n    JSAtomicsWaiter waiter_s, *waiter;\n    int ret, size_log2, res;\n    double d;\n\n    if (js_atomics_get_ptr(ctx, &ptr, NULL, &size_log2, NULL,\n                             argv[0], argv[1], 2))\n        return JS_EXCEPTION;\n    if (size_log2 == 3) {\n        if (JS_ToBigInt64(ctx, &v, argv[2]))\n            return JS_EXCEPTION;\n    } else {\n        if (JS_ToInt32(ctx, &v32, argv[2]))\n            return JS_EXCEPTION;\n        v = v32;\n    }\n    if (JS_ToFloat64(ctx, &d, argv[3]))\n        return JS_EXCEPTION;\n    /* must use INT64_MAX + 1 because INT64_MAX cannot be exactly represented as a double */\n    if (isnan(d) || d >= 0x1p63)\n        timeout = INT64_MAX;\n    else if (d < 0)\n        timeout = 0;\n    else\n        timeout = (int64_t)d;\n    if (!ctx->rt->can_block)\n        return JS_ThrowTypeError(ctx, \"cannot block in this thread\");\n\n    /* XXX: inefficient if large number of waiters, should hash on\n       'ptr' value */\n    /* XXX: use Linux futexes when available ? */\n    pthread_mutex_lock(&js_atomics_mutex);\n    if (size_log2 == 3) {\n        res = *(int64_t *)ptr != v;\n    } else {\n        res = *(int32_t *)ptr != v;\n    }\n    if (res) {\n        pthread_mutex_unlock(&js_atomics_mutex);\n        return JS_AtomToString(ctx, JS_ATOM_not_equal);\n    }\n\n    waiter = &waiter_s;\n    waiter->ptr = ptr;\n    pthread_cond_init(&waiter->cond, NULL);\n    waiter->linked = TRUE;\n    list_add_tail(&waiter->link, &js_atomics_waiter_list);\n\n    if (timeout == INT64_MAX) {\n        pthread_cond_wait(&waiter->cond, &js_atomics_mutex);\n        ret = 0;\n    } else {\n        /* XXX: use clock monotonic */\n        clock_gettime(CLOCK_REALTIME, &ts);\n        ts.tv_sec += timeout / 1000;\n        ts.tv_nsec += (timeout % 1000) * 1000000;\n        if (ts.tv_nsec >= 1000000000) {\n            ts.tv_nsec -= 1000000000;\n            ts.tv_sec++;\n        }\n        ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex,\n                                     &ts);\n    }\n    if (waiter->linked)\n        list_del(&waiter->link);\n    pthread_mutex_unlock(&js_atomics_mutex);\n    pthread_cond_destroy(&waiter->cond);\n    if (ret == ETIMEDOUT) {\n        return JS_AtomToString(ctx, JS_ATOM_timed_out);\n    } else {\n        return JS_AtomToString(ctx, JS_ATOM_ok);\n    }\n}\n\nstatic JSValue js_atomics_notify(JSContext *ctx,\n                                 JSValueConst this_obj,\n                                 int argc, JSValueConst *argv)\n{\n    struct list_head *el, *el1, waiter_list;\n    int32_t count, n;\n    void *ptr;\n    JSAtomicsWaiter *waiter;\n    JSArrayBuffer *abuf;\n\n    if (js_atomics_get_ptr(ctx, &ptr, &abuf, NULL, NULL, argv[0], argv[1], 1))\n        return JS_EXCEPTION;\n    \n    if (JS_IsUndefined(argv[2])) {\n        count = INT32_MAX;\n    } else {\n        if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))\n            return JS_EXCEPTION;\n    }\n\n    n = 0;\n    if (abuf->shared && count > 0) {\n        pthread_mutex_lock(&js_atomics_mutex);\n        init_list_head(&waiter_list);\n        list_for_each_safe(el, el1, &js_atomics_waiter_list) {\n            waiter = list_entry(el, JSAtomicsWaiter, link);\n            if (waiter->ptr == ptr) {\n                list_del(&waiter->link);\n                waiter->linked = FALSE;\n                list_add_tail(&waiter->link, &waiter_list);\n                n++;\n                if (n >= count)\n                    break;\n            }\n        }\n        list_for_each(el, &waiter_list) {\n            waiter = list_entry(el, JSAtomicsWaiter, link);\n            pthread_cond_signal(&waiter->cond);\n        }\n        pthread_mutex_unlock(&js_atomics_mutex);\n    }\n    return JS_NewInt32(ctx, n);\n}\n\nstatic const JSCFunctionListEntry js_atomics_funcs[] = {\n    JS_CFUNC_MAGIC_DEF(\"add\", 3, js_atomics_op, ATOMICS_OP_ADD ),\n    JS_CFUNC_MAGIC_DEF(\"and\", 3, js_atomics_op, ATOMICS_OP_AND ),\n    JS_CFUNC_MAGIC_DEF(\"or\", 3, js_atomics_op, ATOMICS_OP_OR ),\n    JS_CFUNC_MAGIC_DEF(\"sub\", 3, js_atomics_op, ATOMICS_OP_SUB ),\n    JS_CFUNC_MAGIC_DEF(\"xor\", 3, js_atomics_op, ATOMICS_OP_XOR ),\n    JS_CFUNC_MAGIC_DEF(\"exchange\", 3, js_atomics_op, ATOMICS_OP_EXCHANGE ),\n    JS_CFUNC_MAGIC_DEF(\"compareExchange\", 4, js_atomics_op, ATOMICS_OP_COMPARE_EXCHANGE ),\n    JS_CFUNC_MAGIC_DEF(\"load\", 2, js_atomics_op, ATOMICS_OP_LOAD ),\n    JS_CFUNC_DEF(\"store\", 3, js_atomics_store ),\n    JS_CFUNC_DEF(\"isLockFree\", 1, js_atomics_isLockFree ),\n    JS_CFUNC_DEF(\"pause\", 0, js_atomics_pause ),\n    JS_CFUNC_DEF(\"wait\", 4, js_atomics_wait ),\n    JS_CFUNC_DEF(\"notify\", 3, js_atomics_notify ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"Atomics\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSCFunctionListEntry js_atomics_obj[] = {\n    JS_OBJECT_DEF(\"Atomics\", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ),\n};\n\nstatic int JS_AddIntrinsicAtomics(JSContext *ctx)\n{\n    /* add Atomics as autoinit object */\n    return JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj));\n}\n\n#endif /* CONFIG_ATOMICS */\n\nint JS_AddIntrinsicTypedArrays(JSContext *ctx)\n{\n    JSValue typed_array_base_func, typed_array_base_proto, obj;\n    int i, ret;\n\n    obj = JS_NewCConstructor(ctx, JS_CLASS_ARRAY_BUFFER, \"ArrayBuffer\",\n                                    js_array_buffer_constructor, 1, JS_CFUNC_constructor, 0,\n                                    JS_UNDEFINED,\n                                    js_array_buffer_funcs, countof(js_array_buffer_funcs),\n                                    js_array_buffer_proto_funcs, countof(js_array_buffer_proto_funcs),\n                                    0);\n    if (JS_IsException(obj))\n        return -1;\n    JS_FreeValue(ctx, obj);\n\n    obj = JS_NewCConstructor(ctx, JS_CLASS_SHARED_ARRAY_BUFFER, \"SharedArrayBuffer\",\n                                    js_shared_array_buffer_constructor, 1, JS_CFUNC_constructor, 0,\n                                    JS_UNDEFINED,\n                                    js_shared_array_buffer_funcs, countof(js_shared_array_buffer_funcs),\n                                    js_shared_array_buffer_proto_funcs, countof(js_shared_array_buffer_proto_funcs),\n                                    0);\n    if (JS_IsException(obj))\n        return -1;\n    JS_FreeValue(ctx, obj);\n\n\n    typed_array_base_func =\n        JS_NewCConstructor(ctx, -1, \"TypedArray\",\n                                  js_typed_array_base_constructor, 0, JS_CFUNC_constructor_or_func, 0,\n                                  JS_UNDEFINED,\n                                  js_typed_array_base_funcs, countof(js_typed_array_base_funcs),\n                                  js_typed_array_base_proto_funcs, countof(js_typed_array_base_proto_funcs),\n                                  JS_NEW_CTOR_NO_GLOBAL);\n    if (JS_IsException(typed_array_base_func))\n        return -1;\n\n    /* TypedArray.prototype.toString must be the same object as Array.prototype.toString */\n    obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_ARRAY], JS_ATOM_toString);\n    if (JS_IsException(obj))\n        goto fail;\n    /* XXX: should use alias method in JSCFunctionListEntry */ //@@@\n    typed_array_base_proto = JS_GetProperty(ctx, typed_array_base_func, JS_ATOM_prototype);\n    if (JS_IsException(typed_array_base_proto))\n        goto fail;\n    ret = JS_DefinePropertyValue(ctx, typed_array_base_proto, JS_ATOM_toString, obj,\n                                 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);\n    JS_FreeValue(ctx, typed_array_base_proto);\n    if (ret < 0)\n        goto fail;\n    \n    /* Used to squelch a -Wcast-function-type warning. */\n    JSCFunctionType ft = { .generic_magic = js_typed_array_constructor };\n    for(i = JS_CLASS_UINT8C_ARRAY; i < JS_CLASS_UINT8C_ARRAY + JS_TYPED_ARRAY_COUNT; i++) {\n        char buf[ATOM_GET_STR_BUF_SIZE];\n        const char *name;\n        const JSCFunctionListEntry *bpe;\n            \n        name = JS_AtomGetStr(ctx, buf, sizeof(buf),\n                             JS_ATOM_Uint8ClampedArray + i - JS_CLASS_UINT8C_ARRAY);\n        bpe = js_typed_array_funcs + typed_array_size_log2(i);\n        obj = JS_NewCConstructor(ctx, i, name,\n                                 ft.generic, 3, JS_CFUNC_constructor_magic, i,\n                                 typed_array_base_func,\n                                 bpe, 1,\n                                 bpe, 1,\n                                 0);\n        if (JS_IsException(obj)) {\n        fail:\n            JS_FreeValue(ctx, typed_array_base_func);\n            return -1;\n        }\n        JS_FreeValue(ctx, obj);\n    }\n    JS_FreeValue(ctx, typed_array_base_func);\n\n    /* DataView */\n    obj = JS_NewCConstructor(ctx, JS_CLASS_DATAVIEW, \"DataView\",\n                                    js_dataview_constructor, 1, JS_CFUNC_constructor, 0,\n                                    JS_UNDEFINED,\n                                    NULL, 0,\n                                    js_dataview_proto_funcs, countof(js_dataview_proto_funcs),\n                                    0);\n    if (JS_IsException(obj))\n        return -1;\n    JS_FreeValue(ctx, obj);\n\n    /* Atomics */\n#ifdef CONFIG_ATOMICS\n    if (JS_AddIntrinsicAtomics(ctx))\n        return -1;\n#endif\n    return 0;\n}\n\n/* WeakRef */\n\ntypedef struct JSWeakRefData {\n    JSWeakRefHeader weakref_header;\n    JSValue target;\n} JSWeakRefData;\n\nstatic void js_weakref_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSWeakRefData *wrd = JS_GetOpaque(val, JS_CLASS_WEAK_REF);\n    if (!wrd)\n        return;\n    js_weakref_free(rt, wrd->target);\n    list_del(&wrd->weakref_header.link);\n    js_free_rt(rt, wrd);\n}\n\nstatic void weakref_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)\n{\n    JSWeakRefData *wrd = container_of(wh, JSWeakRefData, weakref_header);\n\n    if (!js_weakref_is_live(wrd->target)) {\n        js_weakref_free(rt, wrd->target);\n        wrd->target = JS_UNDEFINED;\n    }\n}\n\nstatic JSValue js_weakref_constructor(JSContext *ctx, JSValueConst new_target,\n                                      int argc, JSValueConst *argv)\n{\n    JSValueConst arg;\n    JSValue obj;\n\n    if (JS_IsUndefined(new_target))\n        return JS_ThrowTypeError(ctx, \"constructor requires 'new'\");\n    arg = argv[0];\n    if (!js_weakref_is_target(arg))\n        return JS_ThrowTypeError(ctx, \"invalid target\");\n    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_WEAK_REF);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    JSWeakRefData *wrd = js_mallocz(ctx, sizeof(*wrd));\n    if (!wrd) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    wrd->target = js_weakref_new(ctx, arg);\n    wrd->weakref_header.weakref_type = JS_WEAKREF_TYPE_WEAKREF;\n    list_add_tail(&wrd->weakref_header.link, &ctx->rt->weakref_list);\n    JS_SetOpaque(obj, wrd);\n    return obj;\n}\n\nstatic JSValue js_weakref_deref(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)\n{\n    JSWeakRefData *wrd = JS_GetOpaque2(ctx, this_val, JS_CLASS_WEAK_REF);\n    if (!wrd)\n        return JS_EXCEPTION;\n    if (js_weakref_is_live(wrd->target)) \n        return JS_DupValue(ctx, wrd->target);\n    else\n        return JS_UNDEFINED;\n}\n\nstatic const JSCFunctionListEntry js_weakref_proto_funcs[] = {\n    JS_CFUNC_DEF(\"deref\", 0, js_weakref_deref ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"WeakRef\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSClassShortDef js_weakref_class_def[] = {\n    { JS_ATOM_WeakRef, js_weakref_finalizer, NULL }, /* JS_CLASS_WEAK_REF */\n};\n\ntypedef struct JSFinRecEntry {\n    struct list_head link;\n    JSValue target;\n    JSValue held_val;\n    JSValue token;\n} JSFinRecEntry;\n\ntypedef struct JSFinalizationRegistryData {\n    JSWeakRefHeader weakref_header;\n    struct list_head entries; /* list of JSFinRecEntry.link */\n    JSContext *realm;\n    JSValue cb;\n} JSFinalizationRegistryData;\n\nstatic void js_finrec_finalizer(JSRuntime *rt, JSValue val)\n{\n    JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);\n    if (frd) {\n        struct list_head *el, *el1;\n        list_for_each_safe(el, el1, &frd->entries) {\n            JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);\n            js_weakref_free(rt, fre->target);\n            js_weakref_free(rt, fre->token);\n            JS_FreeValueRT(rt, fre->held_val);\n            js_free_rt(rt, fre);\n        }\n        JS_FreeValueRT(rt, frd->cb);\n        JS_FreeContext(frd->realm);\n        list_del(&frd->weakref_header.link);\n        js_free_rt(rt, frd);\n    }\n}\n\nstatic void js_finrec_mark(JSRuntime *rt, JSValueConst val,\n                           JS_MarkFunc *mark_func)\n{\n    JSFinalizationRegistryData *frd = JS_GetOpaque(val, JS_CLASS_FINALIZATION_REGISTRY);\n    struct list_head *el;\n    if (frd) {\n        list_for_each(el, &frd->entries) {\n            JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);\n            JS_MarkValue(rt, fre->held_val, mark_func);\n        }\n        JS_MarkValue(rt, frd->cb, mark_func);\n        mark_func(rt, &frd->realm->header);\n    }\n}\n\nstatic JSValue js_finrec_job(JSContext *ctx, int argc, JSValueConst *argv)\n{\n    return JS_Call(ctx, argv[0], JS_UNDEFINED, 1, &argv[1]);\n}\n\nstatic void finrec_delete_weakref(JSRuntime *rt, JSWeakRefHeader *wh)\n{\n    JSFinalizationRegistryData *frd = container_of(wh, JSFinalizationRegistryData, weakref_header);\n    struct list_head *el, *el1;\n\n    list_for_each_safe(el, el1, &frd->entries) {\n        JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);\n\n        if (!js_weakref_is_live(fre->token)) {\n            js_weakref_free(rt, fre->token);\n            fre->token = JS_UNDEFINED;\n        }\n\n        if (!js_weakref_is_live(fre->target)) {\n            JSValueConst args[2];\n            args[0] = frd->cb;\n            args[1] = fre->held_val;\n            JS_EnqueueJob(frd->realm, js_finrec_job, 2, args);\n                \n            js_weakref_free(rt, fre->target);\n            js_weakref_free(rt, fre->token);\n            JS_FreeValueRT(rt, fre->held_val);\n            list_del(&fre->link);\n            js_free_rt(rt, fre);\n        }\n    }\n}\n\nstatic JSValue js_finrec_constructor(JSContext *ctx, JSValueConst new_target,\n                                     int argc, JSValueConst *argv)\n{\n    JSValueConst cb;\n    JSValue obj;\n    JSFinalizationRegistryData *frd;\n    \n    if (JS_IsUndefined(new_target))\n        return JS_ThrowTypeError(ctx, \"constructor requires 'new'\");\n    cb = argv[0];\n    if (!JS_IsFunction(ctx, cb))\n        return JS_ThrowTypeError(ctx, \"argument must be a function\");\n\n    obj = js_create_from_ctor(ctx, new_target, JS_CLASS_FINALIZATION_REGISTRY);\n    if (JS_IsException(obj))\n        return JS_EXCEPTION;\n    frd = js_mallocz(ctx, sizeof(*frd));\n    if (!frd) {\n        JS_FreeValue(ctx, obj);\n        return JS_EXCEPTION;\n    }\n    frd->weakref_header.weakref_type = JS_WEAKREF_TYPE_FINREC;\n    list_add_tail(&frd->weakref_header.link, &ctx->rt->weakref_list);\n    init_list_head(&frd->entries);\n    frd->realm = JS_DupContext(ctx);\n    frd->cb = JS_DupValue(ctx, cb);\n    JS_SetOpaque(obj, frd);\n    return obj;\n}\n\nstatic JSValue js_finrec_register(JSContext *ctx, JSValueConst this_val,\n                                  int argc, JSValueConst *argv)\n{\n    JSValueConst target, held_val, token;\n    JSFinalizationRegistryData *frd;\n    JSFinRecEntry *fre;\n\n    frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);\n    if (!frd)\n        return JS_EXCEPTION;\n    target = argv[0];\n    held_val = argv[1];\n    token = argc > 2 ? argv[2] : JS_UNDEFINED;\n\n    if (!js_weakref_is_target(target))\n        return JS_ThrowTypeError(ctx, \"invalid target\");\n    if (js_same_value(ctx, target, held_val))\n        return JS_ThrowTypeError(ctx, \"held value cannot be the target\");\n    if (!JS_IsUndefined(token) && !js_weakref_is_target(token))\n        return JS_ThrowTypeError(ctx, \"invalid unregister token\");\n    fre = js_malloc(ctx, sizeof(*fre));\n    if (!fre)\n        return JS_EXCEPTION;\n    fre->target = js_weakref_new(ctx, target);\n    fre->held_val = JS_DupValue(ctx, held_val);\n    fre->token = js_weakref_new(ctx, token);\n    list_add_tail(&fre->link, &frd->entries);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_finrec_unregister(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)\n{\n    JSFinalizationRegistryData *frd = JS_GetOpaque2(ctx, this_val, JS_CLASS_FINALIZATION_REGISTRY);\n    JSValueConst token;\n    BOOL removed;\n    struct list_head *el, *el1;\n\n    if (!frd)\n        return JS_EXCEPTION;\n    token = argv[0];\n    if (!js_weakref_is_target(token))\n        return JS_ThrowTypeError(ctx, \"invalid unregister token\");\n\n    removed = FALSE;\n    list_for_each_safe(el, el1, &frd->entries) {\n        JSFinRecEntry *fre = list_entry(el, JSFinRecEntry, link);\n        if (js_weakref_is_live(fre->token) && js_same_value(ctx, fre->token, token)) {\n            js_weakref_free(ctx->rt, fre->target);\n            js_weakref_free(ctx->rt, fre->token);\n            JS_FreeValue(ctx, fre->held_val);\n            list_del(&fre->link);\n            js_free(ctx, fre);\n            removed = TRUE;\n        }\n    }\n    return JS_NewBool(ctx, removed);\n}\n\nstatic const JSCFunctionListEntry js_finrec_proto_funcs[] = {\n    JS_CFUNC_DEF(\"register\", 2, js_finrec_register ),\n    JS_CFUNC_DEF(\"unregister\", 1, js_finrec_unregister ),\n    JS_PROP_STRING_DEF(\"[Symbol.toStringTag]\", \"FinalizationRegistry\", JS_PROP_CONFIGURABLE ),\n};\n\nstatic const JSClassShortDef js_finrec_class_def[] = {\n    { JS_ATOM_FinalizationRegistry, js_finrec_finalizer, js_finrec_mark }, /* JS_CLASS_FINALIZATION_REGISTRY */\n};\n\nint JS_AddIntrinsicWeakRef(JSContext *ctx)\n{\n    JSRuntime *rt = ctx->rt;\n    JSValue obj;\n    \n    /* WeakRef */\n    if (!JS_IsRegisteredClass(rt, JS_CLASS_WEAK_REF)) {\n        if (init_class_range(rt, js_weakref_class_def, JS_CLASS_WEAK_REF,\n                             countof(js_weakref_class_def)))\n            return -1;\n    }\n    obj = JS_NewCConstructor(ctx, JS_CLASS_WEAK_REF, \"WeakRef\",\n                             js_weakref_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                             JS_UNDEFINED,\n                             NULL, 0,\n                             js_weakref_proto_funcs, countof(js_weakref_proto_funcs),\n                             0);\n    if (JS_IsException(obj))\n        return -1;\n    JS_FreeValue(ctx, obj);\n\n    /* FinalizationRegistry */\n    if (!JS_IsRegisteredClass(rt, JS_CLASS_FINALIZATION_REGISTRY)) {\n        if (init_class_range(rt, js_finrec_class_def, JS_CLASS_FINALIZATION_REGISTRY,\n                             countof(js_finrec_class_def)))\n            return -1;\n    }\n\n    obj = JS_NewCConstructor(ctx, JS_CLASS_FINALIZATION_REGISTRY, \"FinalizationRegistry\",\n                             js_finrec_constructor, 1, JS_CFUNC_constructor_or_func, 0,\n                             JS_UNDEFINED,\n                             NULL, 0,\n                             js_finrec_proto_funcs, countof(js_finrec_proto_funcs),\n                             0);\n    if (JS_IsException(obj))\n        return -1;\n    JS_FreeValue(ctx, obj);\n    return 0;\n}\n"
  },
  {
    "path": "quickjs.h",
    "content": "/*\n * QuickJS Javascript Engine\n *\n * Copyright (c) 2017-2021 Fabrice Bellard\n * Copyright (c) 2017-2021 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#ifndef QUICKJS_H\n#define QUICKJS_H\n\n#include <stdio.h>\n#include <stdint.h>\n#include <string.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#define js_likely(x)          __builtin_expect(!!(x), 1)\n#define js_unlikely(x)        __builtin_expect(!!(x), 0)\n#define js_force_inline       inline __attribute__((always_inline))\n#define __js_printf_like(f, a)   __attribute__((format(printf, f, a)))\n#else\n#define js_likely(x)     (x)\n#define js_unlikely(x)   (x)\n#define js_force_inline  inline\n#define __js_printf_like(a, b)\n#endif\n\n#define JS_BOOL int\n\ntypedef struct JSRuntime JSRuntime;\ntypedef struct JSContext JSContext;\ntypedef struct JSClass JSClass;\ntypedef uint32_t JSClassID;\ntypedef uint32_t JSAtom;\n\n#if INTPTR_MAX >= INT64_MAX\n#define JS_PTR64\n#define JS_PTR64_DEF(a) a\n#else\n#define JS_PTR64_DEF(a)\n#endif\n\n#ifndef JS_PTR64\n#define JS_NAN_BOXING\n#endif\n\n#if defined(__SIZEOF_INT128__) && (INTPTR_MAX >= INT64_MAX)\n#define JS_LIMB_BITS 64\n#else\n#define JS_LIMB_BITS 32\n#endif\n\n#define JS_SHORT_BIG_INT_BITS JS_LIMB_BITS\n    \nenum {\n    /* all tags with a reference count are negative */\n    JS_TAG_FIRST       = -9, /* first negative tag */\n    JS_TAG_BIG_INT     = -9,\n    JS_TAG_SYMBOL      = -8,\n    JS_TAG_STRING      = -7,\n    JS_TAG_STRING_ROPE = -6,\n    JS_TAG_MODULE      = -3, /* used internally */\n    JS_TAG_FUNCTION_BYTECODE = -2, /* used internally */\n    JS_TAG_OBJECT      = -1,\n\n    JS_TAG_INT         = 0,\n    JS_TAG_BOOL        = 1,\n    JS_TAG_NULL        = 2,\n    JS_TAG_UNDEFINED   = 3,\n    JS_TAG_UNINITIALIZED = 4,\n    JS_TAG_CATCH_OFFSET = 5,\n    JS_TAG_EXCEPTION   = 6,\n    JS_TAG_SHORT_BIG_INT = 7,\n    JS_TAG_FLOAT64     = 8,\n    /* any larger tag is FLOAT64 if JS_NAN_BOXING */\n};\n\ntypedef struct JSRefCountHeader {\n    int ref_count;\n} JSRefCountHeader;\n\n#define JS_FLOAT64_NAN NAN\n\n#ifdef CONFIG_CHECK_JSVALUE\n/* JSValue consistency : it is not possible to run the code in this\n   mode, but it is useful to detect simple reference counting\n   errors. It would be interesting to modify a static C analyzer to\n   handle specific annotations (clang has such annotations but only\n   for objective C) */\ntypedef struct __JSValue *JSValue;\ntypedef const struct __JSValue *JSValueConst;\n\n#define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf)\n/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */\n#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)\n#define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4)\n#define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v)\n#define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v)\n#define JS_VALUE_GET_SHORT_BIG_INT(v) JS_VALUE_GET_INT(v)\n#define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf)\n\n#define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag))\n#define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag))\n\n#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)\n\n#define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1)\n\nstatic inline JSValue __JS_NewFloat64(JSContext *ctx, double d)\n{\n    return JS_MKVAL(JS_TAG_FLOAT64, (int)d);\n}\n\nstatic inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)\n{\n    return 0;\n}\n\nstatic inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)\n{\n    return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);\n}\n\n#elif defined(JS_NAN_BOXING)\n\ntypedef uint64_t JSValue;\n\n#define JSValueConst JSValue\n\n#define JS_VALUE_GET_TAG(v) (int)((v) >> 32)\n#define JS_VALUE_GET_INT(v) (int)(v)\n#define JS_VALUE_GET_BOOL(v) (int)(v)\n#define JS_VALUE_GET_SHORT_BIG_INT(v) (int)(v)\n#define JS_VALUE_GET_PTR(v) (void *)(intptr_t)(v)\n\n#define JS_MKVAL(tag, val) (((uint64_t)(tag) << 32) | (uint32_t)(val))\n#define JS_MKPTR(tag, ptr) (((uint64_t)(tag) << 32) | (uintptr_t)(ptr))\n\n#define JS_FLOAT64_TAG_ADDEND (0x7ff80000 - JS_TAG_FIRST + 1) /* quiet NaN encoding */\n\nstatic inline double JS_VALUE_GET_FLOAT64(JSValue v)\n{\n    union {\n        JSValue v;\n        double d;\n    } u;\n    u.v = v;\n    u.v += (uint64_t)JS_FLOAT64_TAG_ADDEND << 32;\n    return u.d;\n}\n\n#define JS_NAN (0x7ff8000000000000 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32))\n\nstatic inline JSValue __JS_NewFloat64(JSContext *ctx, double d)\n{\n    union {\n        double d;\n        uint64_t u64;\n    } u;\n    JSValue v;\n    u.d = d;\n    /* normalize NaN */\n    if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000))\n        v = JS_NAN;\n    else\n        v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32);\n    return v;\n}\n\n#define JS_TAG_IS_FLOAT64(tag) ((unsigned)((tag) - JS_TAG_FIRST) >= (JS_TAG_FLOAT64 - JS_TAG_FIRST))\n\n/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */\nstatic inline int JS_VALUE_GET_NORM_TAG(JSValue v)\n{\n    uint32_t tag;\n    tag = JS_VALUE_GET_TAG(v);\n    if (JS_TAG_IS_FLOAT64(tag))\n        return JS_TAG_FLOAT64;\n    else\n        return tag;\n}\n\nstatic inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)\n{\n    uint32_t tag;\n    tag = JS_VALUE_GET_TAG(v);\n    return tag == (JS_NAN >> 32);\n}\n\nstatic inline JSValue __JS_NewShortBigInt(JSContext *ctx, int32_t d)\n{\n    return JS_MKVAL(JS_TAG_SHORT_BIG_INT, d);\n}\n\n#else /* !JS_NAN_BOXING */\n\ntypedef union JSValueUnion {\n    int32_t int32;\n    double float64;\n    void *ptr;\n#if JS_SHORT_BIG_INT_BITS == 32\n    int32_t short_big_int;\n#else\n    int64_t short_big_int;\n#endif\n} JSValueUnion;\n\ntypedef struct JSValue {\n    JSValueUnion u;\n    int64_t tag;\n} JSValue;\n\n#define JSValueConst JSValue\n\n#define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag)\n/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */\n#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)\n#define JS_VALUE_GET_INT(v) ((v).u.int32)\n#define JS_VALUE_GET_BOOL(v) ((v).u.int32)\n#define JS_VALUE_GET_FLOAT64(v) ((v).u.float64)\n#define JS_VALUE_GET_SHORT_BIG_INT(v) ((v).u.short_big_int)\n#define JS_VALUE_GET_PTR(v) ((v).u.ptr)\n\n#define JS_MKVAL(tag, val) (JSValue){ (JSValueUnion){ .int32 = val }, tag }\n#define JS_MKPTR(tag, p) (JSValue){ (JSValueUnion){ .ptr = p }, tag }\n\n#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)\n\n#define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 }\n\nstatic inline JSValue __JS_NewFloat64(JSContext *ctx, double d)\n{\n    JSValue v;\n    v.tag = JS_TAG_FLOAT64;\n    v.u.float64 = d;\n    return v;\n}\n\nstatic inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)\n{\n    union {\n        double d;\n        uint64_t u64;\n    } u;\n    if (v.tag != JS_TAG_FLOAT64)\n        return 0;\n    u.d = v.u.float64;\n    return (u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000;\n}\n\nstatic inline JSValue __JS_NewShortBigInt(JSContext *ctx, int64_t d)\n{\n    JSValue v;\n    v.tag = JS_TAG_SHORT_BIG_INT;\n    v.u.short_big_int = d;\n    return v;\n}\n\n#endif /* !JS_NAN_BOXING */\n\n#define JS_VALUE_IS_BOTH_INT(v1, v2) ((JS_VALUE_GET_TAG(v1) | JS_VALUE_GET_TAG(v2)) == 0)\n#define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2)))\n\n#define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST)\n\n/* special values */\n#define JS_NULL      JS_MKVAL(JS_TAG_NULL, 0)\n#define JS_UNDEFINED JS_MKVAL(JS_TAG_UNDEFINED, 0)\n#define JS_FALSE     JS_MKVAL(JS_TAG_BOOL, 0)\n#define JS_TRUE      JS_MKVAL(JS_TAG_BOOL, 1)\n#define JS_EXCEPTION JS_MKVAL(JS_TAG_EXCEPTION, 0)\n#define JS_UNINITIALIZED JS_MKVAL(JS_TAG_UNINITIALIZED, 0)\n\n/* flags for object properties */\n#define JS_PROP_CONFIGURABLE  (1 << 0)\n#define JS_PROP_WRITABLE      (1 << 1)\n#define JS_PROP_ENUMERABLE    (1 << 2)\n#define JS_PROP_C_W_E         (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)\n#define JS_PROP_LENGTH        (1 << 3) /* used internally in Arrays */\n#define JS_PROP_TMASK         (3 << 4) /* mask for NORMAL, GETSET, VARREF, AUTOINIT */\n#define JS_PROP_NORMAL         (0 << 4)\n#define JS_PROP_GETSET         (1 << 4)\n#define JS_PROP_VARREF         (2 << 4) /* used internally */\n#define JS_PROP_AUTOINIT       (3 << 4) /* used internally */\n\n/* flags for JS_DefineProperty */\n#define JS_PROP_HAS_SHIFT        8\n#define JS_PROP_HAS_CONFIGURABLE (1 << 8)\n#define JS_PROP_HAS_WRITABLE     (1 << 9)\n#define JS_PROP_HAS_ENUMERABLE   (1 << 10)\n#define JS_PROP_HAS_GET          (1 << 11)\n#define JS_PROP_HAS_SET          (1 << 12)\n#define JS_PROP_HAS_VALUE        (1 << 13)\n\n/* throw an exception if false would be returned\n   (JS_DefineProperty/JS_SetProperty) */\n#define JS_PROP_THROW            (1 << 14)\n/* throw an exception if false would be returned in strict mode\n   (JS_SetProperty) */\n#define JS_PROP_THROW_STRICT     (1 << 15)\n\n#define JS_PROP_NO_EXOTIC        (1 << 16) /* internal use */\n\n#ifndef JS_DEFAULT_STACK_SIZE\n#define JS_DEFAULT_STACK_SIZE (1024 * 1024)\n#endif\n\n/* JS_Eval() flags */\n#define JS_EVAL_TYPE_GLOBAL   (0 << 0) /* global code (default) */\n#define JS_EVAL_TYPE_MODULE   (1 << 0) /* module code */\n#define JS_EVAL_TYPE_DIRECT   (2 << 0) /* direct call (internal use) */\n#define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */\n#define JS_EVAL_TYPE_MASK     (3 << 0)\n\n#define JS_EVAL_FLAG_STRICT   (1 << 3) /* force 'strict' mode */\n/* compile but do not run. The result is an object with a\n   JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed\n   with JS_EvalFunction(). */\n#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)\n/* don't include the stack frames before this eval in the Error() backtraces */\n#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)\n/* allow top-level await in normal script. JS_Eval() returns a\n   promise. Only allowed with JS_EVAL_TYPE_GLOBAL */\n#define JS_EVAL_FLAG_ASYNC (1 << 7)\n\ntypedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv);\ntypedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);\ntypedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data);\n\ntypedef struct JSMallocState {\n    size_t malloc_count;\n    size_t malloc_size;\n    size_t malloc_limit;\n    void *opaque; /* user opaque */\n} JSMallocState;\n\ntypedef struct JSMallocFunctions {\n    void *(*js_malloc)(JSMallocState *s, size_t size);\n    void (*js_free)(JSMallocState *s, void *ptr);\n    void *(*js_realloc)(JSMallocState *s, void *ptr, size_t size);\n    size_t (*js_malloc_usable_size)(const void *ptr);\n} JSMallocFunctions;\n\ntypedef struct JSGCObjectHeader JSGCObjectHeader;\n\nJSRuntime *JS_NewRuntime(void);\n/* info lifetime must exceed that of rt */\nvoid JS_SetRuntimeInfo(JSRuntime *rt, const char *info);\nvoid JS_SetMemoryLimit(JSRuntime *rt, size_t limit);\nvoid JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);\n/* use 0 to disable maximum stack size check */\nvoid JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);\n/* should be called when changing thread to update the stack top value\n   used to check stack overflow. */\nvoid JS_UpdateStackTop(JSRuntime *rt);\nJSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);\nvoid JS_FreeRuntime(JSRuntime *rt);\nvoid *JS_GetRuntimeOpaque(JSRuntime *rt);\nvoid JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque);\ntypedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp);\nvoid JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func);\nvoid JS_RunGC(JSRuntime *rt);\nJS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj);\n\nJSContext *JS_NewContext(JSRuntime *rt);\nvoid JS_FreeContext(JSContext *s);\nJSContext *JS_DupContext(JSContext *ctx);\nvoid *JS_GetContextOpaque(JSContext *ctx);\nvoid JS_SetContextOpaque(JSContext *ctx, void *opaque);\nJSRuntime *JS_GetRuntime(JSContext *ctx);\nvoid JS_SetClassProto(JSContext *ctx, JSClassID class_id, JSValue obj);\nJSValue JS_GetClassProto(JSContext *ctx, JSClassID class_id);\n\n/* the following functions are used to select the intrinsic object to\n   save memory */\nJSContext *JS_NewContextRaw(JSRuntime *rt);\nint JS_AddIntrinsicBaseObjects(JSContext *ctx);\nint JS_AddIntrinsicDate(JSContext *ctx);\nint JS_AddIntrinsicEval(JSContext *ctx);\nint JS_AddIntrinsicStringNormalize(JSContext *ctx);\nvoid JS_AddIntrinsicRegExpCompiler(JSContext *ctx);\nint JS_AddIntrinsicRegExp(JSContext *ctx);\nint JS_AddIntrinsicJSON(JSContext *ctx);\nint JS_AddIntrinsicProxy(JSContext *ctx);\nint JS_AddIntrinsicMapSet(JSContext *ctx);\nint JS_AddIntrinsicTypedArrays(JSContext *ctx);\nint JS_AddIntrinsicPromise(JSContext *ctx);\nint JS_AddIntrinsicWeakRef(JSContext *ctx);\n\nJSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val,\n                                 int argc, JSValueConst *argv);\n\nvoid *js_malloc_rt(JSRuntime *rt, size_t size);\nvoid js_free_rt(JSRuntime *rt, void *ptr);\nvoid *js_realloc_rt(JSRuntime *rt, void *ptr, size_t size);\nsize_t js_malloc_usable_size_rt(JSRuntime *rt, const void *ptr);\nvoid *js_mallocz_rt(JSRuntime *rt, size_t size);\n\nvoid *js_malloc(JSContext *ctx, size_t size);\nvoid js_free(JSContext *ctx, void *ptr);\nvoid *js_realloc(JSContext *ctx, void *ptr, size_t size);\nsize_t js_malloc_usable_size(JSContext *ctx, const void *ptr);\nvoid *js_realloc2(JSContext *ctx, void *ptr, size_t size, size_t *pslack);\nvoid *js_mallocz(JSContext *ctx, size_t size);\nchar *js_strdup(JSContext *ctx, const char *str);\nchar *js_strndup(JSContext *ctx, const char *s, size_t n);\n\ntypedef struct JSMemoryUsage {\n    int64_t malloc_size, malloc_limit, memory_used_size;\n    int64_t malloc_count;\n    int64_t memory_used_count;\n    int64_t atom_count, atom_size;\n    int64_t str_count, str_size;\n    int64_t obj_count, obj_size;\n    int64_t prop_count, prop_size;\n    int64_t shape_count, shape_size;\n    int64_t js_func_count, js_func_size, js_func_code_size;\n    int64_t js_func_pc2line_count, js_func_pc2line_size;\n    int64_t c_func_count, array_count;\n    int64_t fast_array_count, fast_array_elements;\n    int64_t binary_object_count, binary_object_size;\n} JSMemoryUsage;\n\nvoid JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);\nvoid JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);\n\n/* atom support */\n#define JS_ATOM_NULL 0\n\nJSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);\nJSAtom JS_NewAtom(JSContext *ctx, const char *str);\nJSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n);\nJSAtom JS_DupAtom(JSContext *ctx, JSAtom v);\nvoid JS_FreeAtom(JSContext *ctx, JSAtom v);\nvoid JS_FreeAtomRT(JSRuntime *rt, JSAtom v);\nJSValue JS_AtomToValue(JSContext *ctx, JSAtom atom);\nJSValue JS_AtomToString(JSContext *ctx, JSAtom atom);\nconst char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom);\nstatic inline const char *JS_AtomToCString(JSContext *ctx, JSAtom atom)\n{\n    return JS_AtomToCStringLen(ctx, NULL, atom);\n}\nJSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val);\n\n/* object class support */\n\ntypedef struct JSPropertyEnum {\n    JS_BOOL is_enumerable;\n    JSAtom atom;\n} JSPropertyEnum;\n\ntypedef struct JSPropertyDescriptor {\n    int flags;\n    JSValue value;\n    JSValue getter;\n    JSValue setter;\n} JSPropertyDescriptor;\n\ntypedef struct JSClassExoticMethods {\n    /* Return -1 if exception (can only happen in case of Proxy object),\n       FALSE if the property does not exists, TRUE if it exists. If 1 is\n       returned, the property descriptor 'desc' is filled if != NULL. */\n    int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc,\n                             JSValueConst obj, JSAtom prop);\n    /* '*ptab' should hold the '*plen' property keys. Return 0 if OK,\n       -1 if exception. The 'is_enumerable' field is ignored.\n    */\n    int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab,\n                                  uint32_t *plen,\n                                  JSValueConst obj);\n    /* return < 0 if exception, or TRUE/FALSE */\n    int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop);\n    /* return < 0 if exception or TRUE/FALSE */\n    int (*define_own_property)(JSContext *ctx, JSValueConst this_obj,\n                               JSAtom prop, JSValueConst val,\n                               JSValueConst getter, JSValueConst setter,\n                               int flags);\n    /* The following methods can be emulated with the previous ones,\n       so they are usually not needed */\n    /* return < 0 if exception or TRUE/FALSE */\n    int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom);\n    JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,\n                            JSValueConst receiver);\n    /* return < 0 if exception or TRUE/FALSE */\n    int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom,\n                        JSValueConst value, JSValueConst receiver, int flags);\n\n    /* To get a consistent object behavior when get_prototype != NULL,\n       get_property, set_property and set_prototype must be != NULL\n       and the object must be created with a JS_NULL prototype. */\n    JSValue (*get_prototype)(JSContext *ctx, JSValueConst obj);\n    /* return < 0 if exception or TRUE/FALSE */\n    int (*set_prototype)(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);\n    /* return < 0 if exception or TRUE/FALSE */\n    int (*is_extensible)(JSContext *ctx, JSValueConst obj);\n    /* return < 0 if exception or TRUE/FALSE */\n    int (*prevent_extensions)(JSContext *ctx, JSValueConst obj);\n} JSClassExoticMethods;\n\ntypedef void JSClassFinalizer(JSRuntime *rt, JSValue val);\ntypedef void JSClassGCMark(JSRuntime *rt, JSValueConst val,\n                           JS_MarkFunc *mark_func);\n#define JS_CALL_FLAG_CONSTRUCTOR (1 << 0)\ntypedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj,\n                            JSValueConst this_val, int argc, JSValueConst *argv,\n                            int flags);\n\ntypedef struct JSClassDef {\n    const char *class_name;\n    JSClassFinalizer *finalizer;\n    JSClassGCMark *gc_mark;\n    /* if call != NULL, the object is a function. If (flags &\n       JS_CALL_FLAG_CONSTRUCTOR) != 0, the function is called as a\n       constructor. In this case, 'this_val' is new.target. A\n       constructor call only happens if the object constructor bit is\n       set (see JS_SetConstructorBit()). */\n    JSClassCall *call;\n    /* XXX: suppress this indirection ? It is here only to save memory\n       because only a few classes need these methods */\n    JSClassExoticMethods *exotic;\n} JSClassDef;\n\n#define JS_INVALID_CLASS_ID 0\nJSClassID JS_NewClassID(JSClassID *pclass_id);\n/* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */\nJSClassID JS_GetClassID(JSValue v);\nint JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def);\nint JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);\n\n/* value handling */\n\nstatic js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val)\n{\n    return JS_MKVAL(JS_TAG_BOOL, (val != 0));\n}\n\nstatic js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)\n{\n    return JS_MKVAL(JS_TAG_INT, val);\n}\n\nstatic js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)\n{\n    return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);\n}\n\nstatic js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)\n{\n    JSValue v;\n    if (val == (int32_t)val) {\n        v = JS_NewInt32(ctx, val);\n    } else {\n        v = __JS_NewFloat64(ctx, val);\n    }\n    return v;\n}\n\nstatic js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)\n{\n    JSValue v;\n    if (val <= 0x7fffffff) {\n        v = JS_NewInt32(ctx, val);\n    } else {\n        v = __JS_NewFloat64(ctx, val);\n    }\n    return v;\n}\n\nJSValue JS_NewBigInt64(JSContext *ctx, int64_t v);\nJSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);\n\nstatic js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double d)\n{\n    int32_t val;\n    union {\n        double d;\n        uint64_t u;\n    } u, t;\n    if (d >= INT32_MIN && d <= INT32_MAX) {\n        u.d = d;\n        val = (int32_t)d;\n        t.d = val;\n        /* -0 cannot be represented as integer, so we compare the bit\n           representation */\n        if (u.u == t.u)\n            return JS_MKVAL(JS_TAG_INT, val);\n    }\n    return __JS_NewFloat64(ctx, d);\n}\n\nstatic inline JS_BOOL JS_IsNumber(JSValueConst v)\n{\n    int tag = JS_VALUE_GET_TAG(v);\n    return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);\n}\n\nstatic inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)\n{\n    int tag = JS_VALUE_GET_TAG(v);\n    return tag == JS_TAG_BIG_INT || tag == JS_TAG_SHORT_BIG_INT;\n}\n\nstatic inline JS_BOOL JS_IsBool(JSValueConst v)\n{\n    return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;\n}\n\nstatic inline JS_BOOL JS_IsNull(JSValueConst v)\n{\n    return JS_VALUE_GET_TAG(v) == JS_TAG_NULL;\n}\n\nstatic inline JS_BOOL JS_IsUndefined(JSValueConst v)\n{\n    return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED;\n}\n\nstatic inline JS_BOOL JS_IsException(JSValueConst v)\n{\n    return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION);\n}\n\nstatic inline JS_BOOL JS_IsUninitialized(JSValueConst v)\n{\n    return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED);\n}\n\nstatic inline JS_BOOL JS_IsString(JSValueConst v)\n{\n    return JS_VALUE_GET_TAG(v) == JS_TAG_STRING ||\n        JS_VALUE_GET_TAG(v) == JS_TAG_STRING_ROPE;\n}\n\nstatic inline JS_BOOL JS_IsSymbol(JSValueConst v)\n{\n    return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL;\n}\n\nstatic inline JS_BOOL JS_IsObject(JSValueConst v)\n{\n    return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT;\n}\n\nJSValue JS_Throw(JSContext *ctx, JSValue obj);\nvoid JS_SetUncatchableException(JSContext *ctx, JS_BOOL flag);\nJSValue JS_GetException(JSContext *ctx);\nJS_BOOL JS_HasException(JSContext *ctx);\nJS_BOOL JS_IsError(JSContext *ctx, JSValueConst val);\nJSValue JS_NewError(JSContext *ctx);\nJSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);\nJSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...);\nJSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...);\nJSValue __js_printf_like(2, 3) JS_ThrowRangeError(JSContext *ctx, const char *fmt, ...);\nJSValue __js_printf_like(2, 3) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);\nJSValue JS_ThrowOutOfMemory(JSContext *ctx);\n\nvoid __JS_FreeValue(JSContext *ctx, JSValue v);\nstatic inline void JS_FreeValue(JSContext *ctx, JSValue v)\n{\n    if (JS_VALUE_HAS_REF_COUNT(v)) {\n        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);\n        if (--p->ref_count <= 0) {\n            __JS_FreeValue(ctx, v);\n        }\n    }\n}\nvoid __JS_FreeValueRT(JSRuntime *rt, JSValue v);\nstatic inline void JS_FreeValueRT(JSRuntime *rt, JSValue v)\n{\n    if (JS_VALUE_HAS_REF_COUNT(v)) {\n        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);\n        if (--p->ref_count <= 0) {\n            __JS_FreeValueRT(rt, v);\n        }\n    }\n}\n\nstatic inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v)\n{\n    if (JS_VALUE_HAS_REF_COUNT(v)) {\n        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);\n        p->ref_count++;\n    }\n    return (JSValue)v;\n}\n\nstatic inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v)\n{\n    if (JS_VALUE_HAS_REF_COUNT(v)) {\n        JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);\n        p->ref_count++;\n    }\n    return (JSValue)v;\n}\n\nJS_BOOL JS_StrictEq(JSContext *ctx, JSValueConst op1, JSValueConst op2);\nJS_BOOL JS_SameValue(JSContext *ctx, JSValueConst op1, JSValueConst op2);\nJS_BOOL JS_SameValueZero(JSContext *ctx, JSValueConst op1, JSValueConst op2);\n\nint JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */\nint JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val);\nstatic inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val)\n{\n    return JS_ToInt32(ctx, (int32_t*)pres, val);\n}\nint JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val);\nint JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val);\nint JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val);\n/* return an exception if 'val' is a Number */\nint JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val);\n/* same as JS_ToInt64() but allow BigInt */\nint JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val);\n\nJSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1);\nstatic inline JSValue JS_NewString(JSContext *ctx, const char *str)\n{\n    return JS_NewStringLen(ctx, str, strlen(str));\n}\nJSValue JS_NewAtomString(JSContext *ctx, const char *str);\nJSValue JS_ToString(JSContext *ctx, JSValueConst val);\nJSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val);\nconst char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8);\nstatic inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1)\n{\n    return JS_ToCStringLen2(ctx, plen, val1, 0);\n}\nstatic inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1)\n{\n    return JS_ToCStringLen2(ctx, NULL, val1, 0);\n}\nvoid JS_FreeCString(JSContext *ctx, const char *ptr);\n\nJSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id);\nJSValue JS_NewObjectClass(JSContext *ctx, int class_id);\nJSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto);\nJSValue JS_NewObject(JSContext *ctx);\n\nJS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val);\nJS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val);\nJS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val);\n\nJSValue JS_NewArray(JSContext *ctx);\nint JS_IsArray(JSContext *ctx, JSValueConst val);\n\nJSValue JS_NewDate(JSContext *ctx, double epoch_ms);\n\nJSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,\n                               JSAtom prop, JSValueConst receiver,\n                               JS_BOOL throw_ref_error);\nstatic js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj,\n                                              JSAtom prop)\n{\n    return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0);\n}\nJSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,\n                          const char *prop);\nJSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,\n                             uint32_t idx);\n\nint JS_SetPropertyInternal(JSContext *ctx, JSValueConst obj,\n                           JSAtom prop, JSValue val, JSValueConst this_obj,\n                           int flags);\nstatic inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj,\n                                 JSAtom prop, JSValue val)\n{\n    return JS_SetPropertyInternal(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW);\n}\nint JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,\n                         uint32_t idx, JSValue val);\nint JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj,\n                        int64_t idx, JSValue val);\nint JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj,\n                      const char *prop, JSValue val);\nint JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop);\nint JS_IsExtensible(JSContext *ctx, JSValueConst obj);\nint JS_PreventExtensions(JSContext *ctx, JSValueConst obj);\nint JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);\nint JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);\nJSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);\n\n#define JS_GPN_STRING_MASK  (1 << 0)\n#define JS_GPN_SYMBOL_MASK  (1 << 1)\n#define JS_GPN_PRIVATE_MASK (1 << 2)\n/* only include the enumerable properties */\n#define JS_GPN_ENUM_ONLY    (1 << 4)\n/* set theJSPropertyEnum.is_enumerable field */\n#define JS_GPN_SET_ENUM     (1 << 5)\n\nint JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,\n                           uint32_t *plen, JSValueConst obj, int flags);\nvoid JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab,\n                         uint32_t len);\nint JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,\n                      JSValueConst obj, JSAtom prop);\n\nJSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj,\n                int argc, JSValueConst *argv);\nJSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom,\n                  int argc, JSValueConst *argv);\nJSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj,\n                           int argc, JSValueConst *argv);\nJSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj,\n                            JSValueConst new_target,\n                            int argc, JSValueConst *argv);\nJS_BOOL JS_DetectModule(const char *input, size_t input_len);\n/* 'input' must be zero terminated i.e. input[input_len] = '\\0'. */\nJSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,\n                const char *filename, int eval_flags);\n/* same as JS_Eval() but with an explicit 'this_obj' parameter */\nJSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,\n                    const char *input, size_t input_len,\n                    const char *filename, int eval_flags);\nJSValue JS_GetGlobalObject(JSContext *ctx);\nint JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj);\nint JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,\n                      JSAtom prop, JSValueConst val,\n                      JSValueConst getter, JSValueConst setter, int flags);\nint JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj,\n                           JSAtom prop, JSValue val, int flags);\nint JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj,\n                                 uint32_t idx, JSValue val, int flags);\nint JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj,\n                              const char *prop, JSValue val, int flags);\nint JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj,\n                            JSAtom prop, JSValue getter, JSValue setter,\n                            int flags);\nvoid JS_SetOpaque(JSValue obj, void *opaque);\nvoid *JS_GetOpaque(JSValueConst obj, JSClassID class_id);\nvoid *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id);\nvoid *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id);\n\n/* 'buf' must be zero terminated i.e. buf[buf_len] = '\\0'. */\nJSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,\n                     const char *filename);\n#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */\nJSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,\n                      const char *filename, int flags);\nJSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,\n                         JSValueConst replacer, JSValueConst space0);\n\ntypedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr);\nJSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,\n                          JSFreeArrayBufferDataFunc *free_func, void *opaque,\n                          JS_BOOL is_shared);\nJSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len);\nvoid JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj);\nuint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj);\n\ntypedef enum JSTypedArrayEnum {\n    JS_TYPED_ARRAY_UINT8C = 0,\n    JS_TYPED_ARRAY_INT8,\n    JS_TYPED_ARRAY_UINT8,\n    JS_TYPED_ARRAY_INT16,\n    JS_TYPED_ARRAY_UINT16,\n    JS_TYPED_ARRAY_INT32,\n    JS_TYPED_ARRAY_UINT32,\n    JS_TYPED_ARRAY_BIG_INT64,\n    JS_TYPED_ARRAY_BIG_UINT64,\n    JS_TYPED_ARRAY_FLOAT16,\n    JS_TYPED_ARRAY_FLOAT32,\n    JS_TYPED_ARRAY_FLOAT64,\n} JSTypedArrayEnum;\n\nJSValue JS_NewTypedArray(JSContext *ctx, int argc, JSValueConst *argv,\n                         JSTypedArrayEnum array_type);\nJSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj,\n                               size_t *pbyte_offset,\n                               size_t *pbyte_length,\n                               size_t *pbytes_per_element);\ntypedef struct {\n    void *(*sab_alloc)(void *opaque, size_t size);\n    void (*sab_free)(void *opaque, void *ptr);\n    void (*sab_dup)(void *opaque, void *ptr);\n    void *sab_opaque;\n} JSSharedArrayBufferFunctions;\nvoid JS_SetSharedArrayBufferFunctions(JSRuntime *rt,\n                                      const JSSharedArrayBufferFunctions *sf);\n\ntypedef enum JSPromiseStateEnum {\n    JS_PROMISE_PENDING,\n    JS_PROMISE_FULFILLED,\n    JS_PROMISE_REJECTED,\n} JSPromiseStateEnum;\n\nJSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);\nJSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);\nJSValue JS_PromiseResult(JSContext *ctx, JSValue promise);\n\n/* is_handled = TRUE means that the rejection is handled */\ntypedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise,\n                                           JSValueConst reason,\n                                           JS_BOOL is_handled, void *opaque);\nvoid JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque);\n\n/* return != 0 if the JS code needs to be interrupted */\ntypedef int JSInterruptHandler(JSRuntime *rt, void *opaque);\nvoid JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque);\n/* if can_block is TRUE, Atomics.wait() can be used */\nvoid JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);\n/* select which debug info is stripped from the compiled code */\n#define JS_STRIP_SOURCE (1 << 0) /* strip source code */\n#define JS_STRIP_DEBUG  (1 << 1) /* strip all debug info including source code */\nvoid JS_SetStripInfo(JSRuntime *rt, int flags);\nint JS_GetStripInfo(JSRuntime *rt);\n\n/* set the [IsHTMLDDA] internal slot */\nvoid JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj);\n\ntypedef struct JSModuleDef JSModuleDef;\n\n/* return the module specifier (allocated with js_malloc()) or NULL if\n   exception */\ntypedef char *JSModuleNormalizeFunc(JSContext *ctx,\n                                    const char *module_base_name,\n                                    const char *module_name, void *opaque);\ntypedef JSModuleDef *JSModuleLoaderFunc(JSContext *ctx,\n                                        const char *module_name, void *opaque);\ntypedef JSModuleDef *JSModuleLoaderFunc2(JSContext *ctx,\n                                         const char *module_name, void *opaque,\n                                         JSValueConst attributes);\n/* return -1 if exception, 0 if OK */\ntypedef int JSModuleCheckSupportedImportAttributes(JSContext *ctx, void *opaque,\n                                                   JSValueConst attributes);\n                                                   \n/* module_normalize = NULL is allowed and invokes the default module\n   filename normalizer */\nvoid JS_SetModuleLoaderFunc(JSRuntime *rt,\n                            JSModuleNormalizeFunc *module_normalize,\n                            JSModuleLoaderFunc *module_loader, void *opaque);\n/* same as JS_SetModuleLoaderFunc but with attributes. if\n   module_check_attrs = NULL, no attribute checking is done. */\nvoid JS_SetModuleLoaderFunc2(JSRuntime *rt,\n                             JSModuleNormalizeFunc *module_normalize,\n                             JSModuleLoaderFunc2 *module_loader,\n                             JSModuleCheckSupportedImportAttributes *module_check_attrs,\n                             void *opaque);\n/* return the import.meta object of a module */\nJSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);\nJSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);\nJSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m);\n\n/* JS Job support */\n\ntypedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv);\nint JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv);\n\nJS_BOOL JS_IsJobPending(JSRuntime *rt);\nint JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);\n\n/* Object Writer/Reader (currently only used to handle precompiled code) */\n#define JS_WRITE_OBJ_BYTECODE  (1 << 0) /* allow function/module */\n#define JS_WRITE_OBJ_BSWAP     (1 << 1) /* byte swapped output */\n#define JS_WRITE_OBJ_SAB       (1 << 2) /* allow SharedArrayBuffer */\n#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to\n                                           encode arbitrary object\n                                           graph */\nuint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,\n                        int flags);\nuint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,\n                         int flags, uint8_t ***psab_tab, size_t *psab_tab_len);\n\n#define JS_READ_OBJ_BYTECODE  (1 << 0) /* allow function/module */\n#define JS_READ_OBJ_ROM_DATA  (1 << 1) /* avoid duplicating 'buf' data */\n#define JS_READ_OBJ_SAB       (1 << 2) /* allow SharedArrayBuffer */\n#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */\nJSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,\n                      int flags);\n/* instantiate and evaluate a bytecode function. Only used when\n   reading a script or module with JS_ReadObject() */\nJSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);\n/* load the dependencies of the module 'obj'. Useful when JS_ReadObject()\n   returns a module. */\nint JS_ResolveModule(JSContext *ctx, JSValueConst obj);\n\n/* only exported for os.Worker() */\nJSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);\n/* only exported for os.Worker() */\nJSValue JS_LoadModule(JSContext *ctx, const char *basename,\n                      const char *filename);\n\n/* C function definition */\ntypedef enum JSCFunctionEnum {  /* XXX: should rename for namespace isolation */\n    JS_CFUNC_generic,\n    JS_CFUNC_generic_magic,\n    JS_CFUNC_constructor,\n    JS_CFUNC_constructor_magic,\n    JS_CFUNC_constructor_or_func,\n    JS_CFUNC_constructor_or_func_magic,\n    JS_CFUNC_f_f,\n    JS_CFUNC_f_f_f,\n    JS_CFUNC_getter,\n    JS_CFUNC_setter,\n    JS_CFUNC_getter_magic,\n    JS_CFUNC_setter_magic,\n    JS_CFUNC_iterator_next,\n} JSCFunctionEnum;\n\ntypedef union JSCFunctionType {\n    JSCFunction *generic;\n    JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);\n    JSCFunction *constructor;\n    JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic);\n    JSCFunction *constructor_or_func;\n    double (*f_f)(double);\n    double (*f_f_f)(double, double);\n    JSValue (*getter)(JSContext *ctx, JSValueConst this_val);\n    JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val);\n    JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic);\n    JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic);\n    JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv, int *pdone, int magic);\n} JSCFunctionType;\n\nJSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,\n                         const char *name,\n                         int length, JSCFunctionEnum cproto, int magic);\nJSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,\n                            int length, int magic, int data_len,\n                            JSValueConst *data);\n\nstatic inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,\n                                      int length)\n{\n    return JS_NewCFunction2(ctx, func, name, length, JS_CFUNC_generic, 0);\n}\n\nstatic inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *func,\n                                           const char *name,\n                                           int length, JSCFunctionEnum cproto, int magic)\n{\n    /* Used to squelch a -Wcast-function-type warning. */\n    JSCFunctionType ft = { .generic_magic = func };\n    return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic);\n}\nint JS_SetConstructor(JSContext *ctx, JSValueConst func_obj,\n                      JSValueConst proto);\n\n/* C property definition */\n\ntypedef struct JSCFunctionListEntry {\n    const char *name;\n    uint8_t prop_flags;\n    uint8_t def_type;\n    int16_t magic;\n    union {\n        struct {\n            uint8_t length; /* XXX: should move outside union */\n            uint8_t cproto; /* XXX: should move outside union */\n            JSCFunctionType cfunc;\n        } func;\n        struct {\n            JSCFunctionType get;\n            JSCFunctionType set;\n        } getset;\n        struct {\n            const char *name;\n            int base;\n        } alias;\n        struct {\n            const struct JSCFunctionListEntry *tab;\n            int len;\n        } prop_list;\n        const char *str;\n        int32_t i32;\n        int64_t i64;\n        double f64;\n    } u;\n} JSCFunctionListEntry;\n\n#define JS_DEF_CFUNC          0\n#define JS_DEF_CGETSET        1\n#define JS_DEF_CGETSET_MAGIC  2\n#define JS_DEF_PROP_STRING    3\n#define JS_DEF_PROP_INT32     4\n#define JS_DEF_PROP_INT64     5\n#define JS_DEF_PROP_DOUBLE    6\n#define JS_DEF_PROP_UNDEFINED 7\n#define JS_DEF_OBJECT         8\n#define JS_DEF_ALIAS          9\n#define JS_DEF_PROP_ATOM     10\n#define JS_DEF_PROP_BOOL     11\n\n/* Note: c++ does not like nested designators */\n#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }\n#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }\n#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }\n#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }\n#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }\n#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } }\n#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } }\n#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } }\n#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } }\n#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } }\n#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } }\n#define JS_PROP_ATOM_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_ATOM, 0, .u = { .i32 = val } }\n#define JS_PROP_BOOL_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_BOOL, 0, .u = { .i32 = val } }\n#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } }\n#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } }\n#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } }\n\nint JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,\n                               const JSCFunctionListEntry *tab,\n                               int len);\n\n/* C module definition */\n\ntypedef int JSModuleInitFunc(JSContext *ctx, JSModuleDef *m);\n\nJSModuleDef *JS_NewCModule(JSContext *ctx, const char *name_str,\n                           JSModuleInitFunc *func);\n/* can only be called before the module is instantiated */\nint JS_AddModuleExport(JSContext *ctx, JSModuleDef *m, const char *name_str);\nint JS_AddModuleExportList(JSContext *ctx, JSModuleDef *m,\n                           const JSCFunctionListEntry *tab, int len);\n/* can only be called after the module is instantiated */\nint JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name,\n                       JSValue val);\nint JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,\n                           const JSCFunctionListEntry *tab, int len);\n/* associate a JSValue to a C module */\nint JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val);\nJSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m);\n                        \n/* debug value output */\n\ntypedef struct {\n    JS_BOOL show_hidden : 8; /* only show enumerable properties */\n    JS_BOOL raw_dump : 8; /* avoid doing autoinit and avoid any malloc() call (for internal use) */\n    uint32_t max_depth; /* recurse up to this depth, 0 = no limit */\n    uint32_t max_string_length; /* print no more than this length for\n                                   strings, 0 = no limit */\n    uint32_t max_item_count; /*  print no more than this count for\n                                 arrays or objects, 0 = no limit */\n} JSPrintValueOptions;\n\ntypedef void JSPrintValueWrite(void *opaque, const char *buf, size_t len);\n\nvoid JS_PrintValueSetDefaultOptions(JSPrintValueOptions *options);\nvoid JS_PrintValueRT(JSRuntime *rt, JSPrintValueWrite *write_func, void *write_opaque,\n                     JSValueConst val, const JSPrintValueOptions *options);\nvoid JS_PrintValue(JSContext *ctx, JSPrintValueWrite *write_func, void *write_opaque,\n                   JSValueConst val, const JSPrintValueOptions *options);\n\n#undef js_unlikely\n#undef js_force_inline\n\n#ifdef __cplusplus\n} /* extern \"C\" { */\n#endif\n\n#endif /* QUICKJS_H */\n"
  },
  {
    "path": "readme-cosmo.txt",
    "content": "The executables included in this archive run on Linux, Mac, Windows,\nFreeBSD, OpenBSD and NetBSD for both the ARM64 and x86_64\narchitectures.\n\nPlatform Notes:\n\n- if you get errors on Linux, you should disable the binfmt_misc\n  module which automatically invokes wine with Windows executable:\n\nsudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/cli'     # remove Ubuntu's MZ interpreter\nsudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/status'  # remove ALL binfmt_misc entries\n\n- Under Windows, you can rename the executables with a .exe extension.\n\n- Use the --assimilate option to build a platform specific binary for\n  better startup time:\n\n  ./qjs --assimilate\n\n- See https://github.com/jart/cosmopolitan for more information about\n  platform specific issues.\n"
  },
  {
    "path": "readme.txt",
    "content": "The main documentation is in doc/quickjs.pdf or doc/quickjs.html.\n"
  },
  {
    "path": "release.sh",
    "content": "#!/bin/sh\n# Release the QuickJS source code\n\nset -e\n\nversion=`cat VERSION`\n\nif [ \"$1\" = \"-h\" ] ; then\n    echo \"release.sh [release_list]\"\n    echo \"\"\n    echo \"release_list: extras binary win_binary cosmo_binary quickjs\"\n\n    exit 1\nfi\n\nrelease_list=\"extras binary win_binary cosmo_binary quickjs\"\n\nif [ \"$1\" != \"\" ] ; then\n    release_list=\"$1\"\nfi\n\n#################################################\"\n# extras\n\nif echo $release_list | grep -w -q extras ; then\n\nd=\"quickjs-${version}\"\nname=\"quickjs-extras-${version}\"\noutdir=\"/tmp/${d}\"\n\nrm -rf $outdir\nmkdir -p $outdir $outdir/unicode $outdir/tests\n\ncp unicode/* $outdir/unicode\ncp -a tests/bench-v8 $outdir/tests\n\n( cd /tmp && tar Jcvf /tmp/${name}.tar.xz ${d} )\n\nfi\n\n#################################################\"\n# Windows binary release\n\nif echo $release_list | grep -w -q win_binary ; then\n\n# win64\n\ndlldir=/usr/x86_64-w64-mingw32/sys-root/mingw/bin\ncross_prefix=\"x86_64-w64-mingw32-\"\nd=\"quickjs-win-x86_64-${version}\"\noutdir=\"/tmp/${d}\"\n\nrm -rf $outdir\nmkdir -p $outdir\n\nmake clean\nmake CONFIG_WIN32=y clean\n\nmake CONFIG_WIN32=y CONFIG_LTO=y qjs.exe\ncp qjs.exe $outdir\n${cross_prefix}strip $outdir/qjs.exe\ncp $dlldir/libwinpthread-1.dll $outdir\n\n( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )\n\nmake CONFIG_WIN32=y clean\n\n# win32\n\ndlldir=/usr/i686-w64-mingw32/sys-root/mingw/bin\ncross_prefix=\"i686-w64-mingw32-\"\nd=\"quickjs-win-i686-${version}\"\noutdir=\"/tmp/${d}\"\n\nrm -rf $outdir\nmkdir -p $outdir\n\nmake clean\nmake CONFIG_WIN32=y clean\n\nmake CONFIG_WIN32=y CONFIG_M32=y CONFIG_LTO=y qjs.exe\ncp qjs.exe $outdir\n${cross_prefix}strip $outdir/qjs.exe\ncp $dlldir/libwinpthread-1.dll $outdir\n\n( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )\n\nfi\n\n#################################################\"\n# Linux binary release\n\nif echo $release_list | grep -w -q binary ; then\n\nmake clean\nmake CONFIG_WIN32=y clean\nmake -j4 CONFIG_LTO=y qjs run-test262\nstrip qjs run-test262\n\nd=\"quickjs-linux-x86_64-${version}\"\noutdir=\"/tmp/${d}\"\n\nrm -rf $outdir\nmkdir -p $outdir\n\ncp qjs run-test262 $outdir\n\n( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )\n\nmake clean\nmake -j4 CONFIG_LTO=y CONFIG_M32=y qjs run-test262\nstrip qjs run-test262\n\nd=\"quickjs-linux-i686-${version}\"\noutdir=\"/tmp/${d}\"\n\nrm -rf $outdir\nmkdir -p $outdir\n\ncp qjs run-test262 $outdir\n\n( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )\n\nfi\n\n#################################################\"\n# Cosmopolitan binary release\n\nif echo $release_list | grep -w -q cosmo_binary ; then\n\nexport PATH=$PATH:$HOME/cosmocc/bin\n\nd=\"quickjs-cosmo-${version}\"\noutdir=\"/tmp/${d}\"\n\nrm -rf $outdir\nmkdir -p $outdir\n\nmake clean\nmake CONFIG_COSMO=y -j4 qjs run-test262\ncp qjs run-test262 $outdir\ncp readme-cosmo.txt $outdir/readme.txt\n\n( cd /tmp/$d && rm -f ../${d}.zip && zip -r ../${d}.zip . )\n\nfi\n\n#################################################\"\n# quickjs\n\nif echo $release_list | grep -w -q quickjs ; then\n\nmake build_doc\n\nd=\"quickjs-${version}\"\noutdir=\"/tmp/${d}\"\n\nrm -rf $outdir\nmkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples\n\ncp Makefile VERSION TODO Changelog readme.txt LICENSE \\\n   release.sh unicode_download.sh \\\n   qjs.c qjsc.c repl.js \\\n   quickjs.c quickjs.h quickjs-atom.h \\\n   quickjs-libc.c quickjs-libc.h quickjs-opcode.h \\\n   cutils.c cutils.h list.h \\\n   libregexp.c libregexp.h libregexp-opcode.h \\\n   libunicode.c libunicode.h libunicode-table.h \\\n   dtoa.c dtoa.h \\\n   unicode_gen.c unicode_gen_def.h \\\n   run-test262.c test262o.conf test262.conf \\\n   test262o_errors.txt test262_errors.txt \\\n   $outdir\n\ncp tests/*.js tests/*.patch tests/bjson.c $outdir/tests\n\ncp examples/*.js examples/*.c examples/*.json $outdir/examples\n\ncp doc/quickjs.texi doc/quickjs.pdf doc/quickjs.html \\\n   $outdir/doc\n\n( cd /tmp && tar Jcvf /tmp/${d}.tar.xz ${d} )\n\nfi\n"
  },
  {
    "path": "repl.js",
    "content": "/*\n * QuickJS Read Eval Print Loop\n *\n * Copyright (c) 2017-2020 Fabrice Bellard\n * Copyright (c) 2017-2020 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\nimport * as std from \"std\";\nimport * as os from \"os\";\n\n(function(g) {\n    /* add 'os' and 'std' bindings */\n    g.os = os;\n    g.std = std;\n\n    /* close global objects */\n    var Object = g.Object;\n    var String = g.String;\n    var Array = g.Array;\n    var Date = g.Date;\n    var Math = g.Math;\n    var isFinite = g.isFinite;\n    var parseFloat = g.parseFloat;\n\n    var colors = {\n        none:    \"\\x1b[0m\",\n        black:   \"\\x1b[30m\",\n        red:     \"\\x1b[31m\",\n        green:   \"\\x1b[32m\",\n        yellow:  \"\\x1b[33m\",\n        blue:    \"\\x1b[34m\",\n        magenta: \"\\x1b[35m\",\n        cyan:    \"\\x1b[36m\",\n        white:   \"\\x1b[37m\",\n        gray:    \"\\x1b[30;1m\",\n        grey:    \"\\x1b[30;1m\",\n        bright_red:     \"\\x1b[31;1m\",\n        bright_green:   \"\\x1b[32;1m\",\n        bright_yellow:  \"\\x1b[33;1m\",\n        bright_blue:    \"\\x1b[34;1m\",\n        bright_magenta: \"\\x1b[35;1m\",\n        bright_cyan:    \"\\x1b[36;1m\",\n        bright_white:   \"\\x1b[37;1m\",\n    };\n\n    var styles = {\n        'default':    'bright_green',\n        'comment':    'white',\n        'string':     'bright_cyan',\n        'regex':      'cyan',\n        'number':     'green',\n        'keyword':    'bright_white',\n        'function':   'bright_yellow',\n        'type':       'bright_magenta',\n        'identifier': 'bright_green',\n        'error':      'red',\n        'result':     'bright_white',\n        'error_msg':  'bright_red',\n    };\n\n    var history = [];\n    var clip_board = \"\";\n    var prec;\n    var expBits;\n    var log2_10;\n\n    var pstate = \"\";\n    var prompt = \"\";\n    var plen = 0;\n    var ps1 = \"qjs > \";\n    var ps2 = \"  ... \";\n    var utf8 = true;\n    var show_time = false;\n    var show_colors = true;\n    var eval_start_time;\n    var eval_time = 0;\n\n    var mexpr = \"\";\n    var level = 0;\n    var cmd = \"\";\n    var cursor_pos = 0;\n    var last_cmd = \"\";\n    var last_cursor_pos = 0;\n    var history_index;\n    var this_fun, last_fun;\n    var quote_flag = false;\n\n    var utf8_state = 0;\n    var utf8_val = 0;\n\n    var term_fd;\n    var term_read_buf;\n    var term_width;\n    /* current X position of the cursor in the terminal */\n    var term_cursor_x = 0;\n\n    function termInit() {\n        var tab;\n        term_fd = std.in.fileno();\n\n        /* get the terminal size */\n        term_width = 80;\n        if (os.isatty(term_fd)) {\n            if (os.ttyGetWinSize) {\n                tab = os.ttyGetWinSize(term_fd);\n                if (tab)\n                    term_width = tab[0];\n            }\n            if (os.ttySetRaw) {\n                /* set the TTY to raw mode */\n                os.ttySetRaw(term_fd);\n            }\n        }\n\n        /* install a Ctrl-C signal handler */\n        os.signal(os.SIGINT, sigint_handler);\n\n        /* install a handler to read stdin */\n        term_read_buf = new Uint8Array(64);\n        os.setReadHandler(term_fd, term_read_handler);\n    }\n\n    function sigint_handler() {\n        /* send Ctrl-C to readline */\n        handle_byte(3);\n    }\n\n    function term_read_handler() {\n        var l, i;\n        l = os.read(term_fd, term_read_buf.buffer, 0, term_read_buf.length);\n        for(i = 0; i < l; i++)\n            handle_byte(term_read_buf[i]);\n    }\n\n    function handle_byte(c) {\n        if (!utf8) {\n            handle_char(c);\n        } else if (utf8_state !== 0 && (c >= 0x80 && c < 0xc0)) {\n            utf8_val = (utf8_val << 6) | (c & 0x3F);\n            utf8_state--;\n            if (utf8_state === 0) {\n                handle_char(utf8_val);\n            }\n        } else if (c >= 0xc0 && c < 0xf8) {\n            utf8_state = 1 + (c >= 0xe0) + (c >= 0xf0);\n            utf8_val = c & ((1 << (6 - utf8_state)) - 1);\n        } else {\n            utf8_state = 0;\n            handle_char(c);\n        }\n    }\n\n    function is_alpha(c) {\n        return typeof c === \"string\" &&\n            ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));\n    }\n\n    function is_digit(c) {\n        return typeof c === \"string\" && (c >= '0' && c <= '9');\n    }\n\n    function is_word(c) {\n        return typeof c === \"string\" &&\n            (is_alpha(c) || is_digit(c) || c == '_' || c == '$');\n    }\n\n    function ucs_length(str) {\n        var len, c, i, str_len = str.length;\n        len = 0;\n        /* we never count the trailing surrogate to have the\n         following property: ucs_length(str) =\n         ucs_length(str.substring(0, a)) + ucs_length(str.substring(a,\n         str.length)) for 0 <= a <= str.length */\n        for(i = 0; i < str_len; i++) {\n            c = str.charCodeAt(i);\n            if (c < 0xdc00 || c >= 0xe000)\n                len++;\n        }\n        return len;\n    }\n\n    function is_trailing_surrogate(c)  {\n        var d;\n        if (typeof c !== \"string\")\n            return false;\n        d = c.codePointAt(0); /* can be NaN if empty string */\n        return d >= 0xdc00 && d < 0xe000;\n    }\n\n    function is_balanced(a, b) {\n        switch (a + b) {\n        case \"()\":\n        case \"[]\":\n        case \"{}\":\n            return true;\n        }\n        return false;\n    }\n\n    function print_color_text(str, start, style_names) {\n        var i, j;\n        for (j = start; j < str.length;) {\n            var style = style_names[i = j];\n            while (++j < str.length && style_names[j] == style)\n                continue;\n            std.puts(colors[styles[style] || 'default']);\n            std.puts(str.substring(i, j));\n            std.puts(colors['none']);\n        }\n    }\n\n    function print_csi(n, code) {\n        std.puts(\"\\x1b[\" + ((n != 1) ? n : \"\") + code);\n    }\n\n    /* XXX: handle double-width characters */\n    function move_cursor(delta) {\n        var i, l;\n        if (delta > 0) {\n            while (delta != 0) {\n                if (term_cursor_x == (term_width - 1)) {\n                    std.puts(\"\\n\"); /* translated to CRLF */\n                    term_cursor_x = 0;\n                    delta--;\n                } else {\n                    l = Math.min(term_width - 1 - term_cursor_x, delta);\n                    print_csi(l, \"C\"); /* right */\n                    delta -= l;\n                    term_cursor_x += l;\n                }\n            }\n        } else {\n            delta = -delta;\n            while (delta != 0) {\n                if (term_cursor_x == 0) {\n                    print_csi(1, \"A\"); /* up */\n                    print_csi(term_width - 1, \"C\"); /* right */\n                    delta--;\n                    term_cursor_x = term_width - 1;\n                } else {\n                    l = Math.min(delta, term_cursor_x);\n                    print_csi(l, \"D\"); /* left */\n                    delta -= l;\n                    term_cursor_x -= l;\n                }\n            }\n        }\n    }\n\n    function update() {\n        var i, cmd_len;\n        /* cursor_pos is the position in 16 bit characters inside the\n           UTF-16 string 'cmd' */\n        if (cmd != last_cmd) {\n            if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) {\n                /* optimize common case */\n                std.puts(cmd.substring(last_cursor_pos));\n            } else {\n                /* goto the start of the line */\n                move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos)));\n                if (show_colors) {\n                    var str = mexpr ? mexpr + '\\n' + cmd : cmd;\n                    var start = str.length - cmd.length;\n                    var colorstate = colorize_js(str);\n                    print_color_text(str, start, colorstate[2]);\n                } else {\n                    std.puts(cmd);\n                }\n            }\n            term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width;\n            if (term_cursor_x == 0) {\n                /* show the cursor on the next line */\n                std.puts(\" \\x08\");\n            }\n            /* remove the trailing characters */\n            std.puts(\"\\x1b[J\");\n            last_cmd = cmd;\n            last_cursor_pos = cmd.length;\n        }\n        if (cursor_pos > last_cursor_pos) {\n            move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos)));\n        } else if (cursor_pos < last_cursor_pos) {\n            move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos)));\n        }\n        last_cursor_pos = cursor_pos;\n        std.out.flush();\n    }\n\n    /* editing commands */\n    function insert(str) {\n        if (str) {\n            cmd = cmd.substring(0, cursor_pos) + str + cmd.substring(cursor_pos);\n            cursor_pos += str.length;\n        }\n    }\n\n    function quoted_insert() {\n        quote_flag = true;\n    }\n\n    function abort() {\n        cmd = \"\";\n        cursor_pos = 0;\n        return -2;\n    }\n\n    function alert() {\n    }\n\n    function beginning_of_line() {\n        cursor_pos = 0;\n    }\n\n    function end_of_line() {\n        cursor_pos = cmd.length;\n    }\n\n    function forward_char() {\n        if (cursor_pos < cmd.length) {\n            cursor_pos++;\n            while (is_trailing_surrogate(cmd.charAt(cursor_pos)))\n                cursor_pos++;\n        }\n    }\n\n    function backward_char() {\n        if (cursor_pos > 0) {\n            cursor_pos--;\n            while (is_trailing_surrogate(cmd.charAt(cursor_pos)))\n                cursor_pos--;\n        }\n    }\n\n    function skip_word_forward(pos) {\n        while (pos < cmd.length && !is_word(cmd.charAt(pos)))\n            pos++;\n        while (pos < cmd.length && is_word(cmd.charAt(pos)))\n            pos++;\n        return pos;\n    }\n\n    function skip_word_backward(pos) {\n        while (pos > 0 && !is_word(cmd.charAt(pos - 1)))\n            pos--;\n        while (pos > 0 && is_word(cmd.charAt(pos - 1)))\n            pos--;\n        return pos;\n    }\n\n    function forward_word() {\n        cursor_pos = skip_word_forward(cursor_pos);\n    }\n\n    function backward_word() {\n        cursor_pos = skip_word_backward(cursor_pos);\n    }\n\n    function accept_line() {\n        std.puts(\"\\n\");\n        history_add(cmd);\n        return -1;\n    }\n\n    function history_add(str) {\n        if (str) {\n            history.push(str);\n        }\n        history_index = history.length;\n    }\n\n    function previous_history() {\n        if (history_index > 0) {\n            if (history_index == history.length) {\n                history.push(cmd);\n            }\n            history_index--;\n            cmd = history[history_index];\n            cursor_pos = cmd.length;\n        }\n    }\n\n    function next_history() {\n        if (history_index < history.length - 1) {\n            history_index++;\n            cmd = history[history_index];\n            cursor_pos = cmd.length;\n        }\n    }\n\n    function history_search(dir) {\n        var pos = cursor_pos;\n        for (var i = 1; i <= history.length; i++) {\n            var index = (history.length + i * dir + history_index) % history.length;\n            if (history[index].substring(0, pos) == cmd.substring(0, pos)) {\n                history_index = index;\n                cmd = history[index];\n                return;\n            }\n        }\n    }\n\n    function history_search_backward() {\n        return history_search(-1);\n    }\n\n    function history_search_forward() {\n        return history_search(1);\n    }\n\n    function delete_char_dir(dir) {\n        var start, end;\n\n        start = cursor_pos;\n        if (dir < 0) {\n            start--;\n            while (is_trailing_surrogate(cmd.charAt(start)))\n                start--;\n        }\n        end = start + 1;\n        while (is_trailing_surrogate(cmd.charAt(end)))\n            end++;\n\n        if (start >= 0 && start < cmd.length) {\n            if (last_fun === kill_region) {\n                kill_region(start, end, dir);\n            } else {\n                cmd = cmd.substring(0, start) + cmd.substring(end);\n                cursor_pos = start;\n            }\n        }\n    }\n\n    function delete_char() {\n        delete_char_dir(1);\n    }\n\n    function control_d() {\n        if (cmd.length == 0) {\n            std.puts(\"\\n\");\n            return -3; /* exit read eval print loop */\n        } else {\n            delete_char_dir(1);\n        }\n    }\n\n    function backward_delete_char() {\n        delete_char_dir(-1);\n    }\n\n    function transpose_chars() {\n        var pos = cursor_pos;\n        if (cmd.length > 1 && pos > 0) {\n            if (pos == cmd.length)\n                pos--;\n            cmd = cmd.substring(0, pos - 1) + cmd.substring(pos, pos + 1) +\n                cmd.substring(pos - 1, pos) + cmd.substring(pos + 1);\n            cursor_pos = pos + 1;\n        }\n    }\n\n    function transpose_words() {\n        var p1 = skip_word_backward(cursor_pos);\n        var p2 = skip_word_forward(p1);\n        var p4 = skip_word_forward(cursor_pos);\n        var p3 = skip_word_backward(p4);\n\n        if (p1 < p2 && p2 <= cursor_pos && cursor_pos <= p3 && p3 < p4) {\n            cmd = cmd.substring(0, p1) + cmd.substring(p3, p4) +\n            cmd.substring(p2, p3) + cmd.substring(p1, p2);\n            cursor_pos = p4;\n        }\n    }\n\n    function upcase_word() {\n        var end = skip_word_forward(cursor_pos);\n        cmd = cmd.substring(0, cursor_pos) +\n            cmd.substring(cursor_pos, end).toUpperCase() +\n            cmd.substring(end);\n    }\n\n    function downcase_word() {\n        var end = skip_word_forward(cursor_pos);\n        cmd = cmd.substring(0, cursor_pos) +\n            cmd.substring(cursor_pos, end).toLowerCase() +\n            cmd.substring(end);\n    }\n\n    function kill_region(start, end, dir) {\n        var s = cmd.substring(start, end);\n        if (last_fun !== kill_region)\n            clip_board = s;\n        else if (dir < 0)\n            clip_board = s + clip_board;\n        else\n            clip_board = clip_board + s;\n\n        cmd = cmd.substring(0, start) + cmd.substring(end);\n        if (cursor_pos > end)\n            cursor_pos -= end - start;\n        else if (cursor_pos > start)\n            cursor_pos = start;\n        this_fun = kill_region;\n    }\n\n    function kill_line() {\n        kill_region(cursor_pos, cmd.length, 1);\n    }\n\n    function backward_kill_line() {\n        kill_region(0, cursor_pos, -1);\n    }\n\n    function kill_word() {\n        kill_region(cursor_pos, skip_word_forward(cursor_pos), 1);\n    }\n\n    function backward_kill_word() {\n        kill_region(skip_word_backward(cursor_pos), cursor_pos, -1);\n    }\n\n    function yank() {\n        insert(clip_board);\n    }\n\n    function control_c() {\n        if (last_fun === control_c) {\n            std.puts(\"\\n\");\n            std.exit(0);\n        } else {\n            std.puts(\"\\n(Press Ctrl-C again to quit)\\n\");\n            readline_print_prompt();\n        }\n    }\n\n    function reset() {\n        cmd = \"\";\n        cursor_pos = 0;\n    }\n\n    function get_context_word(line, pos) {\n        var s = \"\";\n        while (pos > 0 && is_word(line[pos - 1])) {\n            pos--;\n            s = line[pos] + s;\n        }\n        return s;\n    }\n    function get_context_object(line, pos) {\n        var obj, base, c;\n        if (pos <= 0 || \" ~!%^&*(-+={[|:;,<>?/\".indexOf(line[pos - 1]) >= 0)\n            return g;\n        if (pos >= 2 && line[pos - 1] === \".\") {\n            pos--;\n            obj = {};\n            switch (c = line[pos - 1]) {\n            case '\\'':\n            case '\\\"':\n                return \"a\";\n            case ']':\n                return [];\n            case '}':\n                return {};\n            case '/':\n                return / /;\n            default:\n                if (is_word(c)) {\n                    base = get_context_word(line, pos);\n                    if ([\"true\", \"false\", \"null\", \"this\"].includes(base) || !isNaN(+base))\n                        return eval(base);\n                    // Check if `base` is a set of regexp flags\n                    if (pos - base.length >= 3 && line[pos - base.length - 1] === '/')\n                        return new RegExp('', base);\n                    obj = get_context_object(line, pos - base.length);\n                    if (obj === null || obj === void 0)\n                        return obj;\n                    if (obj === g && obj[base] === void 0)\n                        return eval(base);\n                    else\n                        return obj[base];\n                }\n                return {};\n            }\n        }\n        return void 0;\n    }\n\n    function get_completions(line, pos) {\n        var s, obj, ctx_obj, r, i, j, paren;\n\n        s = get_context_word(line, pos);\n        ctx_obj = get_context_object(line, pos - s.length);\n        r = [];\n        /* enumerate properties from object and its prototype chain,\n           add non-numeric regular properties with s as e prefix\n         */\n        for (i = 0, obj = ctx_obj; i < 10 && obj !== null && obj !== void 0; i++) {\n            var props = Object.getOwnPropertyNames(obj);\n            /* add non-numeric regular properties */\n            for (j = 0; j < props.length; j++) {\n                var prop = props[j];\n                if (typeof prop == \"string\" && \"\"+(+prop) != prop && prop.startsWith(s))\n                    r.push(prop);\n            }\n            obj = Object.getPrototypeOf(obj);\n        }\n        if (r.length > 1) {\n            /* sort list with internal names last and remove duplicates */\n            function symcmp(a, b) {\n                if (a[0] != b[0]) {\n                    if (a[0] == '_')\n                        return 1;\n                    if (b[0] == '_')\n                        return -1;\n                }\n                if (a < b)\n                    return -1;\n                if (a > b)\n                    return +1;\n                return 0;\n            }\n            r.sort(symcmp);\n            for(i = j = 1; i < r.length; i++) {\n                if (r[i] != r[i - 1])\n                    r[j++] = r[i];\n            }\n            r.length = j;\n        }\n        /* 'tab' = list of completions, 'pos' = cursor position inside\n           the completions */\n        return { tab: r, pos: s.length, ctx: ctx_obj };\n    }\n\n    function completion() {\n        var tab, res, s, i, j, len, t, max_width, col, n_cols, row, n_rows;\n        res = get_completions(cmd, cursor_pos);\n        tab = res.tab;\n        if (tab.length === 0)\n            return;\n        s = tab[0];\n        len = s.length;\n        /* add the chars which are identical in all the completions */\n        for(i = 1; i < tab.length; i++) {\n            t = tab[i];\n            for(j = 0; j < len; j++) {\n                if (t[j] !== s[j]) {\n                    len = j;\n                    break;\n                }\n            }\n        }\n        for(i = res.pos; i < len; i++) {\n            insert(s[i]);\n        }\n        if (last_fun === completion && tab.length == 1) {\n            /* append parentheses to function names */\n            var m = res.ctx[tab[0]];\n            if (typeof m == \"function\") {\n                insert('(');\n                if (m.length == 0)\n                    insert(')');\n            } else if (typeof m == \"object\") {\n                insert('.');\n            }\n        }\n        /* show the possible completions */\n        if (last_fun === completion && tab.length >= 2) {\n            max_width = 0;\n            for(i = 0; i < tab.length; i++)\n                max_width = Math.max(max_width, tab[i].length);\n            max_width += 2;\n            n_cols = Math.max(1, Math.floor((term_width + 1) / max_width));\n            n_rows = Math.ceil(tab.length / n_cols);\n            std.puts(\"\\n\");\n            /* display the sorted list column-wise */\n            for (row = 0; row < n_rows; row++) {\n                for (col = 0; col < n_cols; col++) {\n                    i = col * n_rows + row;\n                    if (i >= tab.length)\n                        break;\n                    s = tab[i];\n                    if (col != n_cols - 1)\n                        s = s.padEnd(max_width);\n                    std.puts(s);\n                }\n                std.puts(\"\\n\");\n            }\n            /* show a new prompt */\n            readline_print_prompt();\n        }\n    }\n\n    var commands = {        /* command table */\n        \"\\x01\":     beginning_of_line,      /* ^A - bol */\n        \"\\x02\":     backward_char,          /* ^B - backward-char */\n        \"\\x03\":     control_c,              /* ^C - abort */\n        \"\\x04\":     control_d,              /* ^D - delete-char or exit */\n        \"\\x05\":     end_of_line,            /* ^E - eol */\n        \"\\x06\":     forward_char,           /* ^F - forward-char */\n        \"\\x07\":     abort,                  /* ^G - bell */\n        \"\\x08\":     backward_delete_char,   /* ^H - backspace */\n        \"\\x09\":     completion,             /* ^I - history-search-backward */\n        \"\\x0a\":     accept_line,            /* ^J - newline */\n        \"\\x0b\":     kill_line,              /* ^K - delete to end of line */\n        \"\\x0d\":     accept_line,            /* ^M - enter */\n        \"\\x0e\":     next_history,           /* ^N - down */\n        \"\\x10\":     previous_history,       /* ^P - up */\n        \"\\x11\":     quoted_insert,          /* ^Q - quoted-insert */\n        \"\\x12\":     alert,                  /* ^R - reverse-search */\n        \"\\x13\":     alert,                  /* ^S - search */\n        \"\\x14\":     transpose_chars,        /* ^T - transpose */\n        \"\\x18\":     reset,                  /* ^X - cancel */\n        \"\\x19\":     yank,                   /* ^Y - yank */\n        \"\\x1bOA\":   previous_history,       /* ^[OA - up */\n        \"\\x1bOB\":   next_history,           /* ^[OB - down */\n        \"\\x1bOC\":   forward_char,           /* ^[OC - right */\n        \"\\x1bOD\":   backward_char,          /* ^[OD - left */\n        \"\\x1bOF\":   forward_word,           /* ^[OF - ctrl-right */\n        \"\\x1bOH\":   backward_word,          /* ^[OH - ctrl-left */\n        \"\\x1b[1;5C\": forward_word,          /* ^[[1;5C - ctrl-right */\n        \"\\x1b[1;5D\": backward_word,         /* ^[[1;5D - ctrl-left */\n        \"\\x1b[1~\":  beginning_of_line,      /* ^[[1~ - bol */\n        \"\\x1b[3~\":  delete_char,            /* ^[[3~ - delete */\n        \"\\x1b[4~\":  end_of_line,            /* ^[[4~ - eol */\n        \"\\x1b[5~\":  history_search_backward,/* ^[[5~ - page up */\n        \"\\x1b[6~\":  history_search_forward, /* ^[[5~ - page down */\n        \"\\x1b[A\":   previous_history,       /* ^[[A - up */\n        \"\\x1b[B\":   next_history,           /* ^[[B - down */\n        \"\\x1b[C\":   forward_char,           /* ^[[C - right */\n        \"\\x1b[D\":   backward_char,          /* ^[[D - left */\n        \"\\x1b[F\":   end_of_line,            /* ^[[F - end */\n        \"\\x1b[H\":   beginning_of_line,      /* ^[[H - home */\n        \"\\x1b\\x7f\": backward_kill_word,     /* M-C-? - backward_kill_word */\n        \"\\x1bb\":    backward_word,          /* M-b - backward_word */\n        \"\\x1bd\":    kill_word,              /* M-d - kill_word */\n        \"\\x1bf\":    forward_word,           /* M-f - backward_word */\n        \"\\x1bk\":    backward_kill_line,     /* M-k - backward_kill_line */\n        \"\\x1bl\":    downcase_word,          /* M-l - downcase_word */\n        \"\\x1bt\":    transpose_words,        /* M-t - transpose_words */\n        \"\\x1bu\":    upcase_word,            /* M-u - upcase_word */\n        \"\\x7f\":     backward_delete_char,   /* ^? - delete */\n    };\n\n    function dupstr(str, count) {\n        var res = \"\";\n        while (count-- > 0)\n            res += str;\n        return res;\n    }\n\n    var readline_keys;\n    var readline_state;\n    var readline_cb;\n\n    function readline_print_prompt()\n    {\n        std.puts(prompt);\n        term_cursor_x = ucs_length(prompt) % term_width;\n        last_cmd = \"\";\n        last_cursor_pos = 0;\n    }\n\n    function readline_start(defstr, cb) {\n        cmd = defstr || \"\";\n        cursor_pos = cmd.length;\n        history_index = history.length;\n        readline_cb = cb;\n\n        prompt = pstate;\n\n        if (mexpr) {\n            prompt += dupstr(\" \", plen - prompt.length);\n            prompt += ps2;\n        } else {\n            if (show_time) {\n                var t = eval_time / 1000;\n                prompt += t.toFixed(6) + \" \";\n            }\n            plen = prompt.length;\n            prompt += ps1;\n        }\n        readline_print_prompt();\n        update();\n        readline_state = 0;\n    }\n\n    function handle_char(c1) {\n        var c;\n        c = String.fromCodePoint(c1);\n        switch(readline_state) {\n        case 0:\n            if (c == '\\x1b') {  /* '^[' - ESC */\n                readline_keys = c;\n                readline_state = 1;\n            } else {\n                handle_key(c);\n            }\n            break;\n        case 1: /* '^[ */\n            readline_keys += c;\n            if (c == '[') {\n                readline_state = 2;\n            } else if (c == 'O') {\n                readline_state = 3;\n            } else {\n                handle_key(readline_keys);\n                readline_state = 0;\n            }\n            break;\n        case 2: /* '^[[' - CSI */\n            readline_keys += c;\n            if (!(c == ';' || (c >= '0' && c <= '9'))) {\n                handle_key(readline_keys);\n                readline_state = 0;\n            }\n            break;\n        case 3: /* '^[O' - ESC2 */\n            readline_keys += c;\n            handle_key(readline_keys);\n            readline_state = 0;\n            break;\n        }\n    }\n\n    function handle_key(keys) {\n        var fun;\n\n        if (quote_flag) {\n            if (ucs_length(keys) === 1)\n                insert(keys);\n            quote_flag = false;\n        } else if (fun = commands[keys]) {\n            this_fun = fun;\n            switch (fun(keys)) {\n            case -1:\n                readline_cb(cmd);\n                return;\n            case -2:\n                readline_cb(null);\n                return;\n            case -3:\n                /* uninstall a Ctrl-C signal handler */\n                os.signal(os.SIGINT, null);\n                /* uninstall the stdin read handler */\n                os.setReadHandler(term_fd, null);\n                return;\n            }\n            last_fun = this_fun;\n        } else if (ucs_length(keys) === 1 && keys >= ' ') {\n            insert(keys);\n            last_fun = insert;\n        } else {\n            alert(); /* beep! */\n        }\n\n        cursor_pos = (cursor_pos < 0) ? 0 :\n            (cursor_pos > cmd.length) ? cmd.length : cursor_pos;\n        update();\n    }\n\n    var hex_mode = false;\n\n    function number_to_string_hex(a) {\n        var s;\n        if (a < 0) {\n            a = -a;\n            s = \"-\";\n        } else {\n            s = \"\";\n        }\n        s += \"0x\" + a.toString(16);\n        return s;\n    }\n    \n    function extract_directive(a) {\n        var pos;\n        if (a[0] !== '\\\\')\n            return \"\";\n        for (pos = 1; pos < a.length; pos++) {\n            if (!is_alpha(a[pos]))\n                break;\n        }\n        return a.substring(1, pos);\n    }\n\n    /* return true if the string after cmd can be evaluted as JS */\n    function handle_directive(cmd, expr) {\n        var param, prec1, expBits1;\n\n        if (cmd === \"h\" || cmd === \"?\" || cmd == \"help\") {\n            help();\n        } else if (cmd === \"load\") {\n            var filename = expr.substring(cmd.length + 1).trim();\n            if (filename.lastIndexOf(\".\") <= filename.lastIndexOf(\"/\"))\n                filename += \".js\";\n            std.loadScript(filename);\n            return false;\n        } else if (cmd === \"x\") {\n            hex_mode = true;\n        } else if (cmd === \"d\") {\n            hex_mode = false;\n        } else if (cmd === \"t\") {\n            show_time = !show_time;\n        } else if (cmd === \"clear\") {\n            std.puts(\"\\x1b[H\\x1b[J\");\n        } else if (cmd === \"q\") {\n            std.exit(0);\n        } else {\n            std.puts(\"Unknown directive: \" + cmd + \"\\n\");\n            return false;\n        }\n        return true;\n    }\n\n    function help() {\n        function sel(n) {\n            return n ? \"*\": \" \";\n        }\n        std.puts(\"\\\\h          this help\\n\" +\n                 \"\\\\x         \" + sel(hex_mode) + \"hexadecimal number display\\n\" +\n                 \"\\\\d         \" + sel(!hex_mode) + \"decimal number display\\n\" +\n                 \"\\\\t         \" + sel(show_time) + \"toggle timing display\\n\" +\n                  \"\\\\clear      clear the terminal\\n\" +\n                 \"\\\\q          exit\\n\");\n    }\n\n    function cmd_start() {\n        std.puts('QuickJS - Type \"\\\\h\" for help\\n');\n\n        cmd_readline_start();\n    }\n\n    function cmd_readline_start() {\n        readline_start(dupstr(\"    \", level), readline_handle_cmd);\n    }\n\n    function readline_handle_cmd(expr) {\n        if (!handle_cmd(expr)) {\n            cmd_readline_start();\n        }\n    }\n\n    /* return true if async termination */\n    function handle_cmd(expr) {\n        var colorstate, cmd;\n\n        if (expr === null) {\n            expr = \"\";\n            return false;\n        }\n        if (expr === \"?\") {\n            help();\n            return false;\n        }\n        cmd = extract_directive(expr);\n        if (cmd.length > 0) {\n            if (!handle_directive(cmd, expr)) {\n                return false;\n            }\n            expr = expr.substring(cmd.length + 1);\n        }\n        if (expr === \"\")\n            return false;\n\n        if (mexpr)\n            expr = mexpr + '\\n' + expr;\n        colorstate = colorize_js(expr);\n        pstate = colorstate[0];\n        level = colorstate[1];\n        if (pstate) {\n            mexpr = expr;\n            return false;\n        }\n        mexpr = \"\";\n\n        eval_and_print_start(expr);\n\n        return true;\n    }\n\n    function eval_and_print_start(expr) {\n        var result;\n\n        try {\n            eval_start_time = os.now();\n            /* eval as a script */\n            result = std.evalScript(expr, { backtrace_barrier: true, async: true });\n            /* result is a promise */\n            result.then(print_eval_result, print_eval_error);\n        } catch (error) {\n            print_eval_error(error);\n        }\n    }\n\n    function print_eval_result(result) {\n        var default_print = true;\n\n        result = result.value;\n        eval_time = os.now() - eval_start_time;\n        std.puts(colors[styles.result]);\n        if (hex_mode) {\n            if (typeof result == \"number\" &&\n                result === Math.floor(result)) {\n                std.puts(number_to_string_hex(result));\n                default_print = false;\n            } else if (typeof result == \"bigint\") {\n                std.puts(number_to_string_hex(result));\n                std.puts(\"n\");\n                default_print = false;\n            }\n        }\n        if (default_print) {\n            std.__printObject(result);\n        }\n        std.puts(\"\\n\");\n        std.puts(colors.none);\n        /* set the last result */\n        g._ = result;\n\n        handle_cmd_end();\n    }\n\n    function print_eval_error(error) {\n        std.puts(colors[styles.error_msg]);\n        if (!(error instanceof Error))\n            std.puts(\"Throw: \");\n        std.__printObject(error);\n        std.puts(\"\\n\");\n        std.puts(colors.none);\n\n        handle_cmd_end();\n    }\n\n    function handle_cmd_end() {\n        level = 0;\n        /* run the garbage collector after each command */\n        std.gc();\n        cmd_readline_start();\n    }\n\n    function colorize_js(str) {\n        var i, c, start, n = str.length;\n        var style, state = \"\", level = 0;\n        var primary, can_regex = 1;\n        var r = [];\n\n        function push_state(c) { state += c; }\n        function last_state(c) { return state.substring(state.length - 1); }\n        function pop_state(c) {\n            var c = last_state();\n            state = state.substring(0, state.length - 1);\n            return c;\n        }\n\n        function parse_block_comment() {\n            style = 'comment';\n            push_state('/');\n            for (i++; i < n - 1; i++) {\n                if (str[i] == '*' && str[i + 1] == '/') {\n                    i += 2;\n                    pop_state('/');\n                    break;\n                }\n            }\n        }\n\n        function parse_line_comment() {\n            style = 'comment';\n            for (i++; i < n; i++) {\n                if (str[i] == '\\n') {\n                    break;\n                }\n            }\n        }\n\n        function parse_string(delim) {\n            style = 'string';\n            push_state(delim);\n            while (i < n) {\n                c = str[i++];\n                if (c == '\\n') {\n                    style = 'error';\n                    continue;\n                }\n                if (c == '\\\\') {\n                    if (i >= n)\n                        break;\n                    i++;\n                } else\n                if (c == delim) {\n                    pop_state();\n                    break;\n                }\n            }\n        }\n\n        function parse_regex() {\n            style = 'regex';\n            push_state('/');\n            while (i < n) {\n                c = str[i++];\n                if (c == '\\n') {\n                    style = 'error';\n                    continue;\n                }\n                if (c == '\\\\') {\n                    if (i < n) {\n                        i++;\n                    }\n                    continue;\n                }\n                if (last_state() == '[') {\n                    if (c == ']') {\n                        pop_state()\n                    }\n                    // ECMA 5: ignore '/' inside char classes\n                    continue;\n                }\n                if (c == '[') {\n                    push_state('[');\n                    if (str[i] == '[' || str[i] == ']')\n                        i++;\n                    continue;\n                }\n                if (c == '/') {\n                    pop_state();\n                    while (i < n && is_word(str[i]))\n                        i++;\n                    break;\n                }\n            }\n        }\n\n        function parse_number() {\n            style = 'number';\n            while (i < n && (is_word(str[i]) || (str[i] == '.' && (i == n - 1 || str[i + 1] != '.')))) {\n                i++;\n            }\n        }\n\n        var js_keywords = \"|\" +\n            \"break|case|catch|continue|debugger|default|delete|do|\" +\n            \"else|finally|for|function|if|in|instanceof|new|\" +\n            \"return|switch|this|throw|try|typeof|while|with|\" +\n            \"class|const|enum|import|export|extends|super|\" +\n            \"implements|interface|let|package|private|protected|\" +\n            \"public|static|yield|\" +\n            \"undefined|null|true|false|Infinity|NaN|\" +\n            \"eval|arguments|\" +\n            \"await|\";\n\n        var js_no_regex = \"|this|super|undefined|null|true|false|Infinity|NaN|arguments|\";\n        var js_types = \"|void|var|\";\n\n        function parse_identifier() {\n            can_regex = 1;\n\n            while (i < n && is_word(str[i]))\n                i++;\n\n            var w = '|' + str.substring(start, i) + '|';\n\n            if (js_keywords.indexOf(w) >= 0) {\n                style = 'keyword';\n                if (js_no_regex.indexOf(w) >= 0)\n                    can_regex = 0;\n                return;\n            }\n\n            var i1 = i;\n            while (i1 < n && str[i1] == ' ')\n                i1++;\n\n            if (i1 < n && str[i1] == '(') {\n                style = 'function';\n                return;\n            }\n\n            if (js_types.indexOf(w) >= 0) {\n                style = 'type';\n                return;\n            }\n\n            style = 'identifier';\n            can_regex = 0;\n        }\n\n        function set_style(from, to) {\n            while (r.length < from)\n                r.push('default');\n            while (r.length < to)\n                r.push(style);\n        }\n\n        for (i = 0; i < n;) {\n            style = null;\n            start = i;\n            switch (c = str[i++]) {\n            case ' ':\n            case '\\t':\n            case '\\r':\n            case '\\n':\n                continue;\n            case '+':\n            case '-':\n                if (i < n && str[i] == c) {\n                    i++;\n                    continue;\n                }\n                can_regex = 1;\n                continue;\n            case '/':\n                if (i < n && str[i] == '*') { // block comment\n                    parse_block_comment();\n                    break;\n                }\n                if (i < n && str[i] == '/') { // line comment\n                    parse_line_comment();\n                    break;\n                }\n                if (can_regex) {\n                    parse_regex();\n                    can_regex = 0;\n                    break;\n                }\n                can_regex = 1;\n                continue;\n            case '\\'':\n            case '\\\"':\n            case '`':\n                parse_string(c);\n                can_regex = 0;\n                break;\n            case '(':\n            case '[':\n            case '{':\n                can_regex = 1;\n                level++;\n                push_state(c);\n                continue;\n            case ')':\n            case ']':\n            case '}':\n                can_regex = 0;\n                if (level > 0 && is_balanced(last_state(), c)) {\n                    level--;\n                    pop_state();\n                    continue;\n                }\n                style = 'error';\n                break;\n            default:\n                if (is_digit(c)) {\n                    parse_number();\n                    can_regex = 0;\n                    break;\n                }\n                if (is_word(c) || c == '$') {\n                    parse_identifier();\n                    break;\n                }\n                can_regex = 1;\n                continue;\n            }\n            if (style)\n                set_style(start, i);\n        }\n        set_style(n, n);\n        return [ state, level, r ];\n    }\n\n    termInit();\n\n    cmd_start();\n\n})(globalThis);\n"
  },
  {
    "path": "run-test262.c",
    "content": "/*\n * ECMA Test 262 Runner for QuickJS\n *\n * Copyright (c) 2017-2021 Fabrice Bellard\n * Copyright (c) 2017-2021 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n#include <ctype.h>\n#include <unistd.h>\n#include <errno.h>\n#include <time.h>\n#include <dirent.h>\n#include <ftw.h>\n\n#include \"cutils.h\"\n#include \"list.h\"\n#include \"quickjs-libc.h\"\n\n/* enable test262 thread support to test SharedArrayBuffer and Atomics */\n#define CONFIG_AGENT\n\n#define CMD_NAME \"run-test262\"\n\ntypedef struct namelist_t {\n    char **array;\n    int count;\n    int size;\n    unsigned int sorted : 1;\n} namelist_t;\n\nnamelist_t test_list;\nnamelist_t exclude_list;\nnamelist_t exclude_dir_list;\n\nFILE *outfile;\nenum test_mode_t {\n    TEST_DEFAULT_NOSTRICT, /* run tests as nostrict unless test is flagged as strictonly */\n    TEST_DEFAULT_STRICT,   /* run tests as strict unless test is flagged as nostrict */\n    TEST_NOSTRICT,         /* run tests as nostrict, skip strictonly tests */\n    TEST_STRICT,           /* run tests as strict, skip nostrict tests */\n    TEST_ALL,              /* run tests in both strict and nostrict, unless restricted by spec */\n} test_mode = TEST_DEFAULT_NOSTRICT;\nint compact;\nint show_timings;\nint skip_async;\nint skip_module;\nint new_style;\nint dump_memory;\nint stats_count;\nJSMemoryUsage stats_all, stats_avg, stats_min, stats_max;\nchar *stats_min_filename;\nchar *stats_max_filename;\nint verbose;\nchar *harness_dir;\nchar *harness_exclude;\nchar *harness_features;\nchar *harness_skip_features;\nint *harness_skip_features_count;\nchar *error_filename;\nchar *error_file;\nFILE *error_out;\nchar *report_filename;\nint update_errors;\nint test_count, test_failed, test_index, test_skipped, test_excluded;\nint new_errors, changed_errors, fixed_errors;\nint async_done;\n\nvoid warning(const char *, ...) __attribute__((__format__(__printf__, 1, 2)));\nvoid fatal(int, const char *, ...) __attribute__((__format__(__printf__, 2, 3)));\n\nvoid warning(const char *fmt, ...)\n{\n    va_list ap;\n\n    fflush(stdout);\n    fprintf(stderr, \"%s: \", CMD_NAME);\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputc('\\n', stderr);\n}\n\nvoid fatal(int errcode, const char *fmt, ...)\n{\n    va_list ap;\n\n    fflush(stdout);\n    fprintf(stderr, \"%s: \", CMD_NAME);\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputc('\\n', stderr);\n\n    exit(errcode);\n}\n\nvoid perror_exit(int errcode, const char *s)\n{\n    fflush(stdout);\n    fprintf(stderr, \"%s: \", CMD_NAME);\n    perror(s);\n    exit(errcode);\n}\n\nchar *strdup_len(const char *str, int len)\n{\n    char *p = malloc(len + 1);\n    memcpy(p, str, len);\n    p[len] = '\\0';\n    return p;\n}\n\nstatic inline int str_equal(const char *a, const char *b) {\n    return !strcmp(a, b);\n}\n\nchar *str_append(char **pp, const char *sep, const char *str) {\n    char *res, *p;\n    size_t len = 0;\n    p = *pp;\n    if (p) {\n        len = strlen(p) + strlen(sep);\n    }\n    res = malloc(len + strlen(str) + 1);\n    if (p) {\n        strcpy(res, p);\n        strcat(res, sep);\n    }\n    strcpy(res + len, str);\n    free(p);\n    return *pp = res;\n}\n\nchar *str_strip(char *p)\n{\n    size_t len = strlen(p);\n    while (len > 0 && isspace((unsigned char)p[len - 1]))\n        p[--len] = '\\0';\n    while (isspace((unsigned char)*p))\n        p++;\n    return p;\n}\n\nint has_prefix(const char *str, const char *prefix)\n{\n    return !strncmp(str, prefix, strlen(prefix));\n}\n\nchar *skip_prefix(const char *str, const char *prefix)\n{\n    int i;\n    for (i = 0;; i++) {\n        if (prefix[i] == '\\0') {  /* skip the prefix */\n            str += i;\n            break;\n        }\n        if (str[i] != prefix[i])\n            break;\n    }\n    return (char *)str;\n}\n\nchar *get_basename(const char *filename)\n{\n    char *p;\n\n    p = strrchr(filename, '/');\n    if (!p)\n        return NULL;\n    return strdup_len(filename, p - filename);\n}\n\nchar *compose_path(const char *path, const char *name)\n{\n    int path_len, name_len;\n    char *d, *q;\n\n    if (!path || path[0] == '\\0' || *name == '/') {\n        d = strdup(name);\n    } else {\n        path_len = strlen(path);\n        name_len = strlen(name);\n        d = malloc(path_len + 1 + name_len + 1);\n        if (d) {\n            q = d;\n            memcpy(q, path, path_len);\n            q += path_len;\n            if (path[path_len - 1] != '/')\n                *q++ = '/';\n            memcpy(q, name, name_len + 1);\n        }\n    }\n    return d;\n}\n\nint namelist_cmp(const char *a, const char *b)\n{\n    /* compare strings in modified lexicographical order */\n    for (;;) {\n        int ca = (unsigned char)*a++;\n        int cb = (unsigned char)*b++;\n        if (isdigit(ca) && isdigit(cb)) {\n            int na = ca - '0';\n            int nb = cb - '0';\n            while (isdigit(ca = (unsigned char)*a++))\n                na = na * 10 + ca - '0';\n            while (isdigit(cb = (unsigned char)*b++))\n                nb = nb * 10 + cb - '0';\n            if (na < nb)\n                return -1;\n            if (na > nb)\n                return +1;\n        }\n        if (ca < cb)\n            return -1;\n        if (ca > cb)\n            return +1;\n        if (ca == '\\0')\n            return 0;\n    }\n}\n\nint namelist_cmp_indirect(const void *a, const void *b)\n{\n    return namelist_cmp(*(const char **)a, *(const char **)b);\n}\n\nvoid namelist_sort(namelist_t *lp)\n{\n    int i, count;\n    if (lp->count > 1) {\n        qsort(lp->array, lp->count, sizeof(*lp->array), namelist_cmp_indirect);\n        /* remove duplicates */\n        for (count = i = 1; i < lp->count; i++) {\n            if (namelist_cmp(lp->array[count - 1], lp->array[i]) == 0) {\n                free(lp->array[i]);\n            } else {\n                lp->array[count++] = lp->array[i];\n            }\n        }\n        lp->count = count;\n    }\n    lp->sorted = 1;\n}\n\nint namelist_find(namelist_t *lp, const char *name)\n{\n    int a, b, m, cmp;\n\n    if (!lp->sorted) {\n        namelist_sort(lp);\n    }\n    for (a = 0, b = lp->count; a < b;) {\n        m = a + (b - a) / 2;\n        cmp = namelist_cmp(lp->array[m], name);\n        if (cmp < 0)\n            a = m + 1;\n        else if (cmp > 0)\n            b = m;\n        else\n            return m;\n    }\n    return -1;\n}\n\nvoid namelist_add(namelist_t *lp, const char *base, const char *name)\n{\n    char *s;\n\n    s = compose_path(base, name);\n    if (!s)\n        goto fail;\n    if (lp->count == lp->size) {\n        size_t newsize = lp->size + (lp->size >> 1) + 4;\n        char **a = realloc(lp->array, sizeof(lp->array[0]) * newsize);\n        if (!a)\n            goto fail;\n        lp->array = a;\n        lp->size = newsize;\n    }\n    lp->array[lp->count] = s;\n    lp->count++;\n    return;\nfail:\n    fatal(1, \"allocation failure\\n\");\n}\n\nvoid namelist_load(namelist_t *lp, const char *filename)\n{\n    char buf[1024];\n    char *base_name;\n    FILE *f;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror_exit(1, filename);\n    }\n    base_name = get_basename(filename);\n\n    while (fgets(buf, sizeof(buf), f) != NULL) {\n        char *p = str_strip(buf);\n        if (*p == '#' || *p == ';' || *p == '\\0')\n            continue;  /* line comment */\n\n        namelist_add(lp, base_name, p);\n    }\n    free(base_name);\n    fclose(f);\n}\n\nvoid namelist_add_from_error_file(namelist_t *lp, const char *file)\n{\n    const char *p, *p0;\n    char *pp;\n\n    for (p = file; (p = strstr(p, \".js:\")) != NULL; p++) {\n        for (p0 = p; p0 > file && p0[-1] != '\\n'; p0--)\n            continue;\n        pp = strdup_len(p0, p + 3 - p0);\n        namelist_add(lp, NULL, pp);\n        free(pp);\n    }\n}\n\nvoid namelist_free(namelist_t *lp)\n{\n    while (lp->count > 0) {\n        free(lp->array[--lp->count]);\n    }\n    free(lp->array);\n    lp->array = NULL;\n    lp->size = 0;\n}\n\nstatic int add_test_file(const char *filename, const struct stat *ptr, int flag)\n{\n    namelist_t *lp = &test_list;\n    if (has_suffix(filename, \".js\") && !has_suffix(filename, \"_FIXTURE.js\"))\n        namelist_add(lp, NULL, filename);\n    return 0;\n}\n\n/* find js files from the directory tree and sort the list */\nstatic void enumerate_tests(const char *path)\n{\n    namelist_t *lp = &test_list;\n    int start = lp->count;\n    ftw(path, add_test_file, 100);\n    qsort(lp->array + start, lp->count - start, sizeof(*lp->array),\n          namelist_cmp_indirect);\n}\n\nstatic void js_print_value_write(void *opaque, const char *buf, size_t len)\n{\n    FILE *fo = opaque;\n    fwrite(buf, 1, len, fo);\n}\n\nstatic JSValue js_print(JSContext *ctx, JSValueConst this_val,\n                        int argc, JSValueConst *argv)\n{\n    int i;\n    JSValueConst v;\n    \n    if (outfile) {\n        for (i = 0; i < argc; i++) {\n            if (i != 0)\n                fputc(' ', outfile);\n            v = argv[i];\n            if (JS_IsString(v)) {\n                const char *str;\n                size_t len;\n                str = JS_ToCStringLen(ctx, &len, v);\n                if (!str)\n                    return JS_EXCEPTION;\n                if (!strcmp(str, \"Test262:AsyncTestComplete\")) {\n                    async_done++;\n                } else if (strstart(str, \"Test262:AsyncTestFailure\", NULL)) {\n                    async_done = 2; /* force an error */\n                }\n                fwrite(str, 1, len, outfile);\n                JS_FreeCString(ctx, str);\n            } else {\n                JS_PrintValue(ctx, js_print_value_write, outfile, v, NULL);\n            }\n        }\n        fputc('\\n', outfile);\n    }\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_detachArrayBuffer(JSContext *ctx, JSValue this_val,\n                                    int argc, JSValue *argv)\n{\n    JS_DetachArrayBuffer(ctx, argv[0]);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_evalScript(JSContext *ctx, JSValue this_val,\n                             int argc, JSValue *argv)\n{\n    const char *str;\n    size_t len;\n    JSValue ret;\n    str = JS_ToCStringLen(ctx, &len, argv[0]);\n    if (!str)\n        return JS_EXCEPTION;\n    ret = JS_Eval(ctx, str, len, \"<evalScript>\", JS_EVAL_TYPE_GLOBAL);\n    JS_FreeCString(ctx, str);\n    return ret;\n}\n\n#ifdef CONFIG_AGENT\n\n#include <pthread.h>\n\ntypedef struct {\n    struct list_head link;\n    pthread_t tid;\n    char *script;\n    JSValue broadcast_func;\n    BOOL broadcast_pending;\n    JSValue broadcast_sab; /* in the main context */\n    uint8_t *broadcast_sab_buf;\n    size_t broadcast_sab_size;\n    int32_t broadcast_val;\n} Test262Agent;\n\ntypedef struct {\n    struct list_head link;\n    char *str;\n} AgentReport;\n\nstatic JSValue add_helpers1(JSContext *ctx);\nstatic void add_helpers(JSContext *ctx);\n\nstatic pthread_mutex_t agent_mutex = PTHREAD_MUTEX_INITIALIZER;\nstatic pthread_cond_t agent_cond = PTHREAD_COND_INITIALIZER;\n/* list of Test262Agent.link */\nstatic struct list_head agent_list = LIST_HEAD_INIT(agent_list);\n\nstatic pthread_mutex_t report_mutex = PTHREAD_MUTEX_INITIALIZER;\n/* list of AgentReport.link */\nstatic struct list_head report_list = LIST_HEAD_INIT(report_list);\n\nstatic void *agent_start(void *arg)\n{\n    Test262Agent *agent = arg;\n    JSRuntime *rt;\n    JSContext *ctx;\n    JSValue ret_val;\n    int ret;\n\n    rt = JS_NewRuntime();\n    if (rt == NULL) {\n        fatal(1, \"JS_NewRuntime failure\");\n    }\n    ctx = JS_NewContext(rt);\n    if (ctx == NULL) {\n        JS_FreeRuntime(rt);\n        fatal(1, \"JS_NewContext failure\");\n    }\n    JS_SetContextOpaque(ctx, agent);\n    JS_SetRuntimeInfo(rt, \"agent\");\n    JS_SetCanBlock(rt, TRUE);\n\n    add_helpers(ctx);\n    ret_val = JS_Eval(ctx, agent->script, strlen(agent->script),\n                      \"<evalScript>\", JS_EVAL_TYPE_GLOBAL);\n    free(agent->script);\n    agent->script = NULL;\n    if (JS_IsException(ret_val))\n        js_std_dump_error(ctx);\n    JS_FreeValue(ctx, ret_val);\n\n    for(;;) {\n        ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);\n        if (ret < 0) {\n            js_std_dump_error(ctx);\n            break;\n        } else if (ret == 0) {\n            if (JS_IsUndefined(agent->broadcast_func)) {\n                break;\n            } else {\n                JSValue args[2];\n\n                pthread_mutex_lock(&agent_mutex);\n                while (!agent->broadcast_pending) {\n                    pthread_cond_wait(&agent_cond, &agent_mutex);\n                }\n\n                agent->broadcast_pending = FALSE;\n                pthread_cond_signal(&agent_cond);\n\n                pthread_mutex_unlock(&agent_mutex);\n\n                args[0] = JS_NewArrayBuffer(ctx, agent->broadcast_sab_buf,\n                                            agent->broadcast_sab_size,\n                                            NULL, NULL, TRUE);\n                args[1] = JS_NewInt32(ctx, agent->broadcast_val);\n                ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED,\n                                  2, (JSValueConst *)args);\n                JS_FreeValue(ctx, args[0]);\n                JS_FreeValue(ctx, args[1]);\n                if (JS_IsException(ret_val))\n                    js_std_dump_error(ctx);\n                JS_FreeValue(ctx, ret_val);\n                JS_FreeValue(ctx, agent->broadcast_func);\n                agent->broadcast_func = JS_UNDEFINED;\n            }\n        }\n    }\n    JS_FreeValue(ctx, agent->broadcast_func);\n\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n    return NULL;\n}\n\nstatic JSValue js_agent_start(JSContext *ctx, JSValue this_val,\n                              int argc, JSValue *argv)\n{\n    const char *script;\n    Test262Agent *agent;\n    pthread_attr_t attr;\n\n    if (JS_GetContextOpaque(ctx) != NULL)\n        return JS_ThrowTypeError(ctx, \"cannot be called inside an agent\");\n\n    script = JS_ToCString(ctx, argv[0]);\n    if (!script)\n        return JS_EXCEPTION;\n    agent = malloc(sizeof(*agent));\n    memset(agent, 0, sizeof(*agent));\n    agent->broadcast_func = JS_UNDEFINED;\n    agent->broadcast_sab = JS_UNDEFINED;\n    agent->script = strdup(script);\n    JS_FreeCString(ctx, script);\n    list_add_tail(&agent->link, &agent_list);\n    pthread_attr_init(&attr);\n    // musl libc gives threads 80 kb stacks, much smaller than\n    // JS_DEFAULT_STACK_SIZE (256 kb)\n    pthread_attr_setstacksize(&attr, 2 << 20); // 2 MB, glibc default\n    pthread_create(&agent->tid, &attr, agent_start, agent);\n    pthread_attr_destroy(&attr);\n    return JS_UNDEFINED;\n}\n\nstatic void js_agent_free(JSContext *ctx)\n{\n    struct list_head *el, *el1;\n    Test262Agent *agent;\n\n    list_for_each_safe(el, el1, &agent_list) {\n        agent = list_entry(el, Test262Agent, link);\n        pthread_join(agent->tid, NULL);\n        JS_FreeValue(ctx, agent->broadcast_sab);\n        list_del(&agent->link);\n        free(agent);\n    }\n}\n\nstatic JSValue js_agent_leaving(JSContext *ctx, JSValue this_val,\n                                int argc, JSValue *argv)\n{\n    Test262Agent *agent = JS_GetContextOpaque(ctx);\n    if (!agent)\n        return JS_ThrowTypeError(ctx, \"must be called inside an agent\");\n    /* nothing to do */\n    return JS_UNDEFINED;\n}\n\nstatic BOOL is_broadcast_pending(void)\n{\n    struct list_head *el;\n    Test262Agent *agent;\n    list_for_each(el, &agent_list) {\n        agent = list_entry(el, Test262Agent, link);\n        if (agent->broadcast_pending)\n            return TRUE;\n    }\n    return FALSE;\n}\n\nstatic JSValue js_agent_broadcast(JSContext *ctx, JSValue this_val,\n                                  int argc, JSValue *argv)\n{\n    JSValueConst sab = argv[0];\n    struct list_head *el;\n    Test262Agent *agent;\n    uint8_t *buf;\n    size_t buf_size;\n    int32_t val;\n\n    if (JS_GetContextOpaque(ctx) != NULL)\n        return JS_ThrowTypeError(ctx, \"cannot be called inside an agent\");\n\n    buf = JS_GetArrayBuffer(ctx, &buf_size, sab);\n    if (!buf)\n        return JS_EXCEPTION;\n    if (JS_ToInt32(ctx, &val, argv[1]))\n        return JS_EXCEPTION;\n\n    /* broadcast the values and wait until all agents have started\n       calling their callbacks */\n    pthread_mutex_lock(&agent_mutex);\n    list_for_each(el, &agent_list) {\n        agent = list_entry(el, Test262Agent, link);\n        agent->broadcast_pending = TRUE;\n        /* the shared array buffer is used by the thread, so increment\n           its refcount */\n        agent->broadcast_sab = JS_DupValue(ctx, sab);\n        agent->broadcast_sab_buf = buf;\n        agent->broadcast_sab_size = buf_size;\n        agent->broadcast_val = val;\n    }\n    pthread_cond_broadcast(&agent_cond);\n\n    while (is_broadcast_pending()) {\n        pthread_cond_wait(&agent_cond, &agent_mutex);\n    }\n    pthread_mutex_unlock(&agent_mutex);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_agent_receiveBroadcast(JSContext *ctx, JSValue this_val,\n                                         int argc, JSValue *argv)\n{\n    Test262Agent *agent = JS_GetContextOpaque(ctx);\n    if (!agent)\n        return JS_ThrowTypeError(ctx, \"must be called inside an agent\");\n    if (!JS_IsFunction(ctx, argv[0]))\n        return JS_ThrowTypeError(ctx, \"expecting function\");\n    JS_FreeValue(ctx, agent->broadcast_func);\n    agent->broadcast_func = JS_DupValue(ctx, argv[0]);\n    return JS_UNDEFINED;\n}\n\nstatic JSValue js_agent_sleep(JSContext *ctx, JSValue this_val,\n                              int argc, JSValue *argv)\n{\n    uint32_t duration;\n    if (JS_ToUint32(ctx, &duration, argv[0]))\n        return JS_EXCEPTION;\n    usleep(duration * 1000);\n    return JS_UNDEFINED;\n}\n\nstatic int64_t get_clock_ms(void)\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC, &ts);\n    return (uint64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000);\n}\n\nstatic JSValue js_agent_monotonicNow(JSContext *ctx, JSValue this_val,\n                                     int argc, JSValue *argv)\n{\n    return JS_NewInt64(ctx, get_clock_ms());\n}\n\nstatic JSValue js_agent_getReport(JSContext *ctx, JSValue this_val,\n                                  int argc, JSValue *argv)\n{\n    AgentReport *rep;\n    JSValue ret;\n\n    pthread_mutex_lock(&report_mutex);\n    if (list_empty(&report_list)) {\n        rep = NULL;\n    } else {\n        rep = list_entry(report_list.next, AgentReport, link);\n        list_del(&rep->link);\n    }\n    pthread_mutex_unlock(&report_mutex);\n    if (rep) {\n        ret = JS_NewString(ctx, rep->str);\n        free(rep->str);\n        free(rep);\n    } else {\n        ret = JS_NULL;\n    }\n    return ret;\n}\n\nstatic JSValue js_agent_report(JSContext *ctx, JSValue this_val,\n                               int argc, JSValue *argv)\n{\n    const char *str;\n    AgentReport *rep;\n\n    str = JS_ToCString(ctx, argv[0]);\n    if (!str)\n        return JS_EXCEPTION;\n    rep = malloc(sizeof(*rep));\n    rep->str = strdup(str);\n    JS_FreeCString(ctx, str);\n\n    pthread_mutex_lock(&report_mutex);\n    list_add_tail(&rep->link, &report_list);\n    pthread_mutex_unlock(&report_mutex);\n    return JS_UNDEFINED;\n}\n\nstatic const JSCFunctionListEntry js_agent_funcs[] = {\n    /* only in main */\n    JS_CFUNC_DEF(\"start\", 1, js_agent_start ),\n    JS_CFUNC_DEF(\"getReport\", 0, js_agent_getReport ),\n    JS_CFUNC_DEF(\"broadcast\", 2, js_agent_broadcast ),\n    /* only in agent */\n    JS_CFUNC_DEF(\"report\", 1, js_agent_report ),\n    JS_CFUNC_DEF(\"leaving\", 0, js_agent_leaving ),\n    JS_CFUNC_DEF(\"receiveBroadcast\", 1, js_agent_receiveBroadcast ),\n    /* in both */\n    JS_CFUNC_DEF(\"sleep\", 1, js_agent_sleep ),\n    JS_CFUNC_DEF(\"monotonicNow\", 0, js_agent_monotonicNow ),\n};\n\nstatic JSValue js_new_agent(JSContext *ctx)\n{\n    JSValue agent;\n    agent = JS_NewObject(ctx);\n    JS_SetPropertyFunctionList(ctx, agent, js_agent_funcs,\n                               countof(js_agent_funcs));\n    return agent;\n}\n#endif\n\nstatic JSValue js_createRealm(JSContext *ctx, JSValue this_val,\n                              int argc, JSValue *argv)\n{\n    JSContext *ctx1;\n    JSValue ret;\n\n    ctx1 = JS_NewContext(JS_GetRuntime(ctx));\n    if (!ctx1)\n        return JS_ThrowOutOfMemory(ctx);\n    ret = add_helpers1(ctx1);\n    /* ctx1 has a refcount so it stays alive */\n    JS_FreeContext(ctx1);\n    return ret;\n}\n\nstatic JSValue js_IsHTMLDDA(JSContext *ctx, JSValue this_val,\n                            int argc, JSValue *argv)\n{\n    return JS_NULL;\n}\n\nstatic JSValue js_gc(JSContext *ctx, JSValueConst this_val,\n                     int argc, JSValueConst *argv)\n{\n    JS_RunGC(JS_GetRuntime(ctx));\n    return JS_UNDEFINED;\n}\n\nstatic JSValue add_helpers1(JSContext *ctx)\n{\n    JSValue global_obj;\n    JSValue obj262, obj;\n\n    global_obj = JS_GetGlobalObject(ctx);\n\n    JS_SetPropertyStr(ctx, global_obj, \"print\",\n                      JS_NewCFunction(ctx, js_print, \"print\", 1));\n\n    /* $262 special object used by the tests */\n    obj262 = JS_NewObject(ctx);\n    JS_SetPropertyStr(ctx, obj262, \"detachArrayBuffer\",\n                      JS_NewCFunction(ctx, js_detachArrayBuffer,\n                                      \"detachArrayBuffer\", 1));\n    JS_SetPropertyStr(ctx, obj262, \"evalScript\",\n                      JS_NewCFunction(ctx, js_evalScript,\n                                      \"evalScript\", 1));\n    JS_SetPropertyStr(ctx, obj262, \"codePointRange\",\n                      JS_NewCFunction(ctx, js_string_codePointRange,\n                                      \"codePointRange\", 2));\n#ifdef CONFIG_AGENT\n    JS_SetPropertyStr(ctx, obj262, \"agent\", js_new_agent(ctx));\n#endif\n\n    JS_SetPropertyStr(ctx, obj262, \"global\",\n                      JS_DupValue(ctx, global_obj));\n    JS_SetPropertyStr(ctx, obj262, \"createRealm\",\n                      JS_NewCFunction(ctx, js_createRealm,\n                                      \"createRealm\", 0));\n    obj = JS_NewCFunction(ctx, js_IsHTMLDDA, \"IsHTMLDDA\", 0);\n    JS_SetIsHTMLDDA(ctx, obj);\n    JS_SetPropertyStr(ctx, obj262, \"IsHTMLDDA\", obj);\n    JS_SetPropertyStr(ctx, obj262, \"gc\",\n                      JS_NewCFunction(ctx, js_gc, \"gc\", 0));\n\n    JS_SetPropertyStr(ctx, global_obj, \"$262\", JS_DupValue(ctx, obj262));\n\n    JS_FreeValue(ctx, global_obj);\n    return obj262;\n}\n\nstatic void add_helpers(JSContext *ctx)\n{\n    JS_FreeValue(ctx, add_helpers1(ctx));\n}\n\nstatic char *load_file(const char *filename, size_t *lenp)\n{\n    char *buf;\n    size_t buf_len;\n    buf = (char *)js_load_file(NULL, &buf_len, filename);\n    if (!buf)\n        perror_exit(1, filename);\n    if (lenp)\n        *lenp = buf_len;\n    return buf;\n}\n\nstatic int json_module_init_test(JSContext *ctx, JSModuleDef *m)\n{\n    JSValue val;\n    val = JS_GetModulePrivateValue(ctx, m);\n    JS_SetModuleExport(ctx, m, \"default\", val);\n    return 0;\n}\n\nstatic JSModuleDef *js_module_loader_test(JSContext *ctx,\n                                          const char *module_name, void *opaque,\n                                          JSValueConst attributes)\n{\n    size_t buf_len;\n    uint8_t *buf;\n    JSModuleDef *m;\n    char *filename, *slash, path[1024];\n\n    // interpret import(\"bar.js\") from path/to/foo.js as\n    // import(\"path/to/bar.js\") but leave import(\"./bar.js\") untouched\n    filename = opaque;\n    if (!strchr(module_name, '/')) {\n        slash = strrchr(filename, '/');\n        if (slash) {\n            snprintf(path, sizeof(path), \"%.*s/%s\",\n                     (int)(slash - filename), filename, module_name);\n            module_name = path;\n        }\n    }\n\n    buf = js_load_file(ctx, &buf_len, module_name);\n    if (!buf) {\n        JS_ThrowReferenceError(ctx, \"could not load module filename '%s'\",\n                               module_name);\n        return NULL;\n    }\n\n    if (js_module_test_json(ctx, attributes) == 1) {\n        /* compile as JSON */\n        JSValue val;\n        val = JS_ParseJSON(ctx, (char *)buf, buf_len, module_name);\n        js_free(ctx, buf);\n        if (JS_IsException(val))\n            return NULL;\n        m = JS_NewCModule(ctx, module_name, json_module_init_test);\n        if (!m) {\n            JS_FreeValue(ctx, val);\n            return NULL;\n        }\n        /* only export the \"default\" symbol which will contain the JSON object */\n        JS_AddModuleExport(ctx, m, \"default\");\n        JS_SetModulePrivateValue(ctx, m, val);\n    } else {\n        JSValue func_val;\n        /* compile the module */\n        func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,\n                           JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);\n        js_free(ctx, buf);\n        if (JS_IsException(func_val))\n            return NULL;\n        /* the module is already referenced, so we must free it */\n        m = JS_VALUE_GET_PTR(func_val);\n        JS_FreeValue(ctx, func_val);\n    }\n    return m;\n}\n\nint is_line_sep(char c)\n{\n    return (c == '\\0' || c == '\\n' || c == '\\r');\n}\n\nchar *find_line(const char *str, const char *line)\n{\n    if (str) {\n        const char *p;\n        int len = strlen(line);\n        for (p = str; (p = strstr(p, line)) != NULL; p += len + 1) {\n            if ((p == str || is_line_sep(p[-1])) && is_line_sep(p[len]))\n                return (char *)p;\n        }\n    }\n    return NULL;\n}\n\nint is_word_sep(char c)\n{\n    return (c == '\\0' || isspace((unsigned char)c) || c == ',');\n}\n\nchar *find_word(const char *str, const char *word)\n{\n    const char *p;\n    int len = strlen(word);\n    if (str && len) {\n        for (p = str; (p = strstr(p, word)) != NULL; p += len) {\n            if ((p == str || is_word_sep(p[-1])) && is_word_sep(p[len]))\n                return (char *)p;\n        }\n    }\n    return NULL;\n}\n\n/* handle exclude directories */\nvoid update_exclude_dirs(void)\n{\n    namelist_t *lp = &test_list;\n    namelist_t *ep = &exclude_list;\n    namelist_t *dp = &exclude_dir_list;\n    char *name;\n    int i, j, count;\n\n    /* split directpries from exclude_list */\n    for (count = i = 0; i < ep->count; i++) {\n        name = ep->array[i];\n        if (has_suffix(name, \"/\")) {\n            namelist_add(dp, NULL, name);\n            free(name);\n        } else {\n            ep->array[count++] = name;\n        }\n    }\n    ep->count = count;\n\n    namelist_sort(dp);\n\n    /* filter out excluded directories */\n    for (count = i = 0; i < lp->count; i++) {\n        name = lp->array[i];\n        for (j = 0; j < dp->count; j++) {\n            if (has_prefix(name, dp->array[j])) {\n                test_excluded++;\n                free(name);\n                name = NULL;\n                break;\n            }\n        }\n        if (name) {\n            lp->array[count++] = name;\n        }\n    }\n    lp->count = count;\n}\n\nvoid load_config(const char *filename, const char *ignore)\n{\n    char buf[1024];\n    FILE *f;\n    char *base_name;\n    enum {\n        SECTION_NONE = 0,\n        SECTION_CONFIG,\n        SECTION_EXCLUDE,\n        SECTION_FEATURES,\n        SECTION_TESTS,\n    } section = SECTION_NONE;\n    int lineno = 0;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror_exit(1, filename);\n    }\n    base_name = get_basename(filename);\n\n    while (fgets(buf, sizeof(buf), f) != NULL) {\n        char *p, *q;\n        lineno++;\n        p = str_strip(buf);\n        if (*p == '#' || *p == ';' || *p == '\\0')\n            continue;  /* line comment */\n\n        if (*p == \"[]\"[0]) {\n            /* new section */\n            p++;\n            p[strcspn(p, \"]\")] = '\\0';\n            if (str_equal(p, \"config\"))\n                section = SECTION_CONFIG;\n            else if (str_equal(p, \"exclude\"))\n                section = SECTION_EXCLUDE;\n            else if (str_equal(p, \"features\"))\n                section = SECTION_FEATURES;\n            else if (str_equal(p, \"tests\"))\n                section = SECTION_TESTS;\n            else\n                section = SECTION_NONE;\n            continue;\n        }\n        q = strchr(p, '=');\n        if (q) {\n            /* setting: name=value */\n            *q++ = '\\0';\n            q = str_strip(q);\n        }\n        switch (section) {\n        case SECTION_CONFIG:\n            if (!q) {\n                printf(\"%s:%d: syntax error\\n\", filename, lineno);\n                continue;\n            }\n            if (strstr(ignore, p)) {\n                printf(\"%s:%d: ignoring %s=%s\\n\", filename, lineno, p, q);\n                continue;\n            }\n            if (str_equal(p, \"style\")) {\n                new_style = str_equal(q, \"new\");\n                continue;\n            }\n            if (str_equal(p, \"testdir\")) {\n                char *testdir = compose_path(base_name, q);\n                enumerate_tests(testdir);\n                free(testdir);\n                continue;\n            }\n            if (str_equal(p, \"harnessdir\")) {\n                harness_dir = compose_path(base_name, q);\n                continue;\n            }\n            if (str_equal(p, \"harnessexclude\")) {\n                str_append(&harness_exclude, \" \", q);\n                continue;\n            }\n            if (str_equal(p, \"features\")) {\n                str_append(&harness_features, \" \", q);\n                continue;\n            }\n            if (str_equal(p, \"skip-features\")) {\n                str_append(&harness_skip_features, \" \", q);\n                continue;\n            }\n            if (str_equal(p, \"mode\")) {\n                if (str_equal(q, \"default\") || str_equal(q, \"default-nostrict\"))\n                    test_mode = TEST_DEFAULT_NOSTRICT;\n                else if (str_equal(q, \"default-strict\"))\n                    test_mode = TEST_DEFAULT_STRICT;\n                else if (str_equal(q, \"nostrict\"))\n                    test_mode = TEST_NOSTRICT;\n                else if (str_equal(q, \"strict\"))\n                    test_mode = TEST_STRICT;\n                else if (str_equal(q, \"all\") || str_equal(q, \"both\"))\n                    test_mode = TEST_ALL;\n                else\n                    fatal(2, \"unknown test mode: %s\", q);\n                continue;\n            }\n            if (str_equal(p, \"strict\")) {\n                if (str_equal(q, \"skip\") || str_equal(q, \"no\"))\n                    test_mode = TEST_NOSTRICT;\n                continue;\n            }\n            if (str_equal(p, \"nostrict\")) {\n                if (str_equal(q, \"skip\") || str_equal(q, \"no\"))\n                    test_mode = TEST_STRICT;\n                continue;\n            }\n            if (str_equal(p, \"async\")) {\n                skip_async = !str_equal(q, \"yes\");\n                continue;\n            }\n            if (str_equal(p, \"module\")) {\n                skip_module = !str_equal(q, \"yes\");\n                continue;\n            }\n            if (str_equal(p, \"verbose\")) {\n                verbose = str_equal(q, \"yes\");\n                continue;\n            }\n            if (str_equal(p, \"errorfile\")) {\n                error_filename = compose_path(base_name, q);\n                continue;\n            }\n            if (str_equal(p, \"excludefile\")) {\n                char *path = compose_path(base_name, q);\n                namelist_load(&exclude_list, path);\n                free(path);\n                continue;\n            }\n            if (str_equal(p, \"reportfile\")) {\n                report_filename = compose_path(base_name, q);\n                continue;\n            }\n        case SECTION_EXCLUDE:\n            namelist_add(&exclude_list, base_name, p);\n            break;\n        case SECTION_FEATURES:\n            if (!q || str_equal(q, \"yes\"))\n                str_append(&harness_features, \" \", p);\n            else\n                str_append(&harness_skip_features, \" \", p);\n            break;\n        case SECTION_TESTS:\n            namelist_add(&test_list, base_name, p);\n            break;\n        default:\n            /* ignore settings in other sections */\n            break;\n        }\n    }\n    fclose(f);\n    free(base_name);\n}\n\nchar *find_error(const char *filename, int *pline, int is_strict)\n{\n    if (error_file) {\n        size_t len = strlen(filename);\n        const char *p, *q, *r;\n        int line;\n\n        for (p = error_file; (p = strstr(p, filename)) != NULL; p += len) {\n            if ((p == error_file || p[-1] == '\\n' || p[-1] == '(') && p[len] == ':') {\n                q = p + len;\n                line = 1;\n                if (*q == ':') {\n                    line = strtol(q + 1, (char**)&q, 10);\n                    if (*q == ':')\n                        q++;\n                }\n                while (*q == ' ') {\n                    q++;\n                }\n                /* check strict mode indicator */\n                if (!strstart(q, \"strict mode: \", &q) != !is_strict)\n                    continue;\n                r = q = skip_prefix(q, \"unexpected error: \");\n                r += strcspn(r, \"\\n\");\n                while (r[0] == '\\n' && r[1] && strncmp(r + 1, filename, 8)) {\n                    r++;\n                    r += strcspn(r, \"\\n\");\n                }\n                if (pline)\n                    *pline = line;\n                return strdup_len(q, r - q);\n            }\n        }\n    }\n    return NULL;\n}\n\nint skip_comments(const char *str, int line, int *pline)\n{\n    const char *p;\n    int c;\n\n    p = str;\n    while ((c = (unsigned char)*p++) != '\\0') {\n        if (isspace(c)) {\n            if (c == '\\n')\n                line++;\n            continue;\n        }\n        if (c == '/' && *p == '/') {\n            while (*++p && *p != '\\n')\n                continue;\n            continue;\n        }\n        if (c == '/' && *p == '*') {\n            for (p += 1; *p; p++) {\n                if (*p == '\\n') {\n                    line++;\n                    continue;\n                }\n                if (*p == '*' && p[1] == '/') {\n                    p += 2;\n                    break;\n                }\n            }\n            continue;\n        }\n        break;\n    }\n    if (pline)\n        *pline = line;\n\n    return p - str;\n}\n\nint longest_match(const char *str, const char *find, int pos, int *ppos, int line, int *pline)\n{\n    int len, maxlen;\n\n    maxlen = 0;\n\n    if (*find) {\n        const char *p;\n        for (p = str + pos; *p; p++) {\n            if (*p == *find) {\n                for (len = 1; p[len] && p[len] == find[len]; len++)\n                    continue;\n                if (len > maxlen) {\n                    maxlen = len;\n                    if (ppos)\n                        *ppos = p - str;\n                    if (pline)\n                        *pline = line;\n                    if (!find[len])\n                        break;\n                }\n            }\n            if (*p == '\\n')\n                line++;\n        }\n    }\n    return maxlen;\n}\n\nstatic int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,\n                    const char *filename, int is_test, int is_negative,\n                    const char *error_type, FILE *outfile, int eval_flags,\n                    int is_async)\n{\n    JSValue res_val, exception_val;\n    int ret, error_line, pos, pos_line;\n    BOOL is_error, has_error_line, ret_promise;\n    const char *error_name;\n\n    pos = skip_comments(buf, 1, &pos_line);\n    error_line = pos_line;\n    has_error_line = FALSE;\n    exception_val = JS_UNDEFINED;\n    error_name = NULL;\n\n    /* a module evaluation returns a promise */\n    ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0);\n    async_done = 0; /* counter of \"Test262:AsyncTestComplete\" messages */\n\n    res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);\n\n    if ((is_async || ret_promise) && !JS_IsException(res_val)) {\n        JSValue promise = JS_UNDEFINED;\n        if (ret_promise) {\n            promise = res_val;\n        } else {\n            JS_FreeValue(ctx, res_val);\n        }\n        for(;;) {\n            ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);\n            if (ret < 0) {\n                res_val = JS_EXCEPTION;\n                break;\n            } else if (ret == 0) {\n                if (is_async) {\n                    /* test if the test called $DONE() once */\n                    if (async_done != 1) {\n                        res_val = JS_ThrowTypeError(ctx, \"$DONE() not called\");\n                    } else {\n                        res_val = JS_UNDEFINED;\n                    }\n                } else {\n                    /* check that the returned promise is fulfilled */\n                    JSPromiseStateEnum state = JS_PromiseState(ctx, promise);\n                    if (state == JS_PROMISE_FULFILLED)\n                        res_val = JS_UNDEFINED;\n                    else if (state == JS_PROMISE_REJECTED)\n                        res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));\n                    else\n                        res_val = JS_ThrowTypeError(ctx, \"promise is pending\");\n                }\n                break;\n            }\n        }\n        JS_FreeValue(ctx, promise);\n    }\n\n    if (JS_IsException(res_val)) {\n        exception_val = JS_GetException(ctx);\n        is_error = JS_IsError(ctx, exception_val);\n        /* XXX: should get the filename and line number */\n        if (outfile) {\n            if (!is_error)\n                fprintf(outfile, \"%sThrow: \", (eval_flags & JS_EVAL_FLAG_STRICT) ?\n                        \"strict mode: \" : \"\");\n            js_print(ctx, JS_NULL, 1, &exception_val);\n        }\n        if (is_error) {\n            JSValue name, stack;\n            const char *stack_str;\n\n            name = JS_GetPropertyStr(ctx, exception_val, \"name\");\n            error_name = JS_ToCString(ctx, name);\n            stack = JS_GetPropertyStr(ctx, exception_val, \"stack\");\n            if (!JS_IsUndefined(stack)) {\n                stack_str = JS_ToCString(ctx, stack);\n                if (stack_str) {\n                    const char *p;\n                    int len;\n\n                    if (outfile)\n                        fprintf(outfile, \"%s\", stack_str);\n\n                    len = strlen(filename);\n                    p = strstr(stack_str, filename);\n                    if (p != NULL && p[len] == ':') {\n                        error_line = atoi(p + len + 1);\n                        has_error_line = TRUE;\n                    }\n                    JS_FreeCString(ctx, stack_str);\n                }\n            }\n            JS_FreeValue(ctx, stack);\n            JS_FreeValue(ctx, name);\n        }\n        if (is_negative) {\n            ret = 0;\n            if (error_type) {\n                char *error_class;\n                const char *msg;\n\n                msg = JS_ToCString(ctx, exception_val);\n                error_class = strdup_len(msg, strcspn(msg, \":\"));\n                if (!str_equal(error_class, error_type))\n                    ret = -1;\n                free(error_class);\n                JS_FreeCString(ctx, msg);\n            }\n        } else {\n            ret = -1;\n        }\n    } else {\n        if (is_negative)\n            ret = -1;\n        else\n            ret = 0;\n    }\n\n    if (verbose && is_test) {\n        JSValue msg_val = JS_UNDEFINED;\n        const char *msg = NULL;\n        int s_line;\n        char *s = find_error(filename, &s_line, eval_flags & JS_EVAL_FLAG_STRICT);\n        const char *strict_mode = (eval_flags & JS_EVAL_FLAG_STRICT) ? \"strict mode: \" : \"\";\n\n        if (!JS_IsUndefined(exception_val)) {\n            msg_val = JS_ToString(ctx, exception_val);\n            msg = JS_ToCString(ctx, msg_val);\n        }\n        if (is_negative) {  // expect error\n            if (ret == 0) {\n                if (msg && s &&\n                    (str_equal(s, \"expected error\") ||\n                     strstart(s, \"unexpected error type:\", NULL) ||\n                     str_equal(s, msg))) {     // did not have error yet\n                    if (!has_error_line) {\n                        longest_match(buf, msg, pos, &pos, pos_line, &error_line);\n                    }\n                    printf(\"%s:%d: %sOK, now has error %s\\n\",\n                           filename, error_line, strict_mode, msg);\n                    fixed_errors++;\n                }\n            } else {\n                if (!s) {   // not yet reported\n                    if (msg) {\n                        fprintf(error_out, \"%s:%d: %sunexpected error type: %s\\n\",\n                                filename, error_line, strict_mode, msg);\n                    } else {\n                        fprintf(error_out, \"%s:%d: %sexpected error\\n\",\n                                filename, error_line, strict_mode);\n                    }\n                    new_errors++;\n                }\n            }\n        } else {            // should not have error\n            if (msg) {\n                if (!s || !str_equal(s, msg)) {\n                    if (!has_error_line) {\n                        char *p = skip_prefix(msg, \"Test262 Error: \");\n                        if (strstr(p, \"Test case returned non-true value!\")) {\n                            longest_match(buf, \"runTestCase\", pos, &pos, pos_line, &error_line);\n                        } else {\n                            longest_match(buf, p, pos, &pos, pos_line, &error_line);\n                        }\n                    }\n                    fprintf(error_out, \"%s:%d: %s%s%s\\n\", filename, error_line, strict_mode,\n                            error_file ? \"unexpected error: \" : \"\", msg);\n\n                    if (s && (!str_equal(s, msg) || error_line != s_line)) {\n                        printf(\"%s:%d: %sprevious error: %s\\n\", filename, s_line, strict_mode, s);\n                        changed_errors++;\n                    } else {\n                        new_errors++;\n                    }\n                }\n            } else {\n                if (s) {\n                    printf(\"%s:%d: %sOK, fixed error: %s\\n\", filename, s_line, strict_mode, s);\n                    fixed_errors++;\n                }\n            }\n        }\n        JS_FreeValue(ctx, msg_val);\n        JS_FreeCString(ctx, msg);\n        free(s);\n    }\n    JS_FreeCString(ctx, error_name);\n    JS_FreeValue(ctx, exception_val);\n    JS_FreeValue(ctx, res_val);\n    return ret;\n}\n\nstatic int eval_file(JSContext *ctx, const char *base, const char *p,\n                     int eval_flags)\n{\n    char *buf;\n    size_t buf_len;\n    char *filename = compose_path(base, p);\n\n    buf = load_file(filename, &buf_len);\n    if (!buf) {\n        warning(\"cannot load %s\", filename);\n        goto fail;\n    }\n    if (eval_buf(ctx, buf, buf_len, filename, FALSE, FALSE, NULL, stderr,\n                 eval_flags, FALSE)) {\n        warning(\"error evaluating %s\", filename);\n        goto fail;\n    }\n    free(buf);\n    free(filename);\n    return 0;\n\nfail:\n    free(buf);\n    free(filename);\n    return 1;\n}\n\nchar *extract_desc(const char *buf, char style)\n{\n    const char *p, *desc_start;\n    char *desc;\n    int len;\n\n    p = buf;\n    while (*p != '\\0') {\n        if (p[0] == '/' && p[1] == '*' && p[2] == style && p[3] != '/') {\n            p += 3;\n            desc_start = p;\n            while (*p != '\\0' && (p[0] != '*' || p[1] != '/'))\n                p++;\n            if (*p == '\\0') {\n                warning(\"Expecting end of desc comment\");\n                return NULL;\n            }\n            len = p - desc_start;\n            desc = malloc(len + 1);\n            memcpy(desc, desc_start, len);\n            desc[len] = '\\0';\n            return desc;\n        } else {\n            p++;\n        }\n    }\n    return NULL;\n}\n\nstatic char *find_tag(char *desc, const char *tag, int *state)\n{\n    char *p;\n    p = strstr(desc, tag);\n    if (p) {\n        p += strlen(tag);\n        *state = 0;\n    }\n    return p;\n}\n\nstatic char *get_option(char **pp, int *state)\n{\n    char *p, *p0, *option = NULL;\n    if (*pp) {\n        for (p = *pp;; p++) {\n            switch (*p) {\n            case '[':\n                *state += 1;\n                continue;\n            case ']':\n                *state -= 1;\n                if (*state > 0)\n                    continue;\n                p = NULL;\n                break;\n            case ' ':\n            case '\\t':\n            case '\\r':\n            case ',':\n            case '-':\n                continue;\n            case '\\n':\n                if (*state > 0 || p[1] == ' ')\n                    continue;\n                p = NULL;\n                break;\n            case '\\0':\n                p = NULL;\n                break;\n            default:\n                p0 = p;\n                p += strcspn(p0, \" \\t\\r\\n,]\");\n                option = strdup_len(p0, p - p0);\n                break;\n            }\n            break;\n        }\n        *pp = p;\n    }\n    return option;\n}\n\nvoid update_stats(JSRuntime *rt, const char *filename) {\n    JSMemoryUsage stats;\n    JS_ComputeMemoryUsage(rt, &stats);\n    if (stats_count++ == 0) {\n        stats_avg = stats_all = stats_min = stats_max = stats;\n        stats_min_filename = strdup(filename);\n        stats_max_filename = strdup(filename);\n    } else {\n        if (stats_max.malloc_size < stats.malloc_size) {\n            stats_max = stats;\n            free(stats_max_filename);\n            stats_max_filename = strdup(filename);\n        }\n        if (stats_min.malloc_size > stats.malloc_size) {\n            stats_min = stats;\n            free(stats_min_filename);\n            stats_min_filename = strdup(filename);\n        }\n\n#define update(f)  stats_avg.f = (stats_all.f += stats.f) / stats_count\n        update(malloc_count);\n        update(malloc_size);\n        update(memory_used_count);\n        update(memory_used_size);\n        update(atom_count);\n        update(atom_size);\n        update(str_count);\n        update(str_size);\n        update(obj_count);\n        update(obj_size);\n        update(prop_count);\n        update(prop_size);\n        update(shape_count);\n        update(shape_size);\n        update(js_func_count);\n        update(js_func_size);\n        update(js_func_code_size);\n        update(js_func_pc2line_count);\n        update(js_func_pc2line_size);\n        update(c_func_count);\n        update(array_count);\n        update(fast_array_count);\n        update(fast_array_elements);\n    }\n#undef update\n}\n\nint run_test_buf(const char *filename, const char *harness, namelist_t *ip,\n                 char *buf, size_t buf_len, const char* error_type,\n                 int eval_flags, BOOL is_negative, BOOL is_async,\n                 BOOL can_block)\n{\n    JSRuntime *rt;\n    JSContext *ctx;\n    int i, ret;\n\n    rt = JS_NewRuntime();\n    if (rt == NULL) {\n        fatal(1, \"JS_NewRuntime failure\");\n    }\n    ctx = JS_NewContext(rt);\n    if (ctx == NULL) {\n        JS_FreeRuntime(rt);\n        fatal(1, \"JS_NewContext failure\");\n    }\n    JS_SetRuntimeInfo(rt, filename);\n\n    JS_SetCanBlock(rt, can_block);\n\n    /* loader for ES6 modules */\n    JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader_test, NULL, (void *)filename);\n\n    add_helpers(ctx);\n\n    for (i = 0; i < ip->count; i++) {\n        if (eval_file(ctx, harness, ip->array[i],\n                      JS_EVAL_TYPE_GLOBAL)) {\n            fatal(1, \"error including %s for %s\", ip->array[i], filename);\n        }\n    }\n\n    ret = eval_buf(ctx, buf, buf_len, filename, TRUE, is_negative,\n                   error_type, outfile, eval_flags, is_async);\n    ret = (ret != 0);\n\n    if (dump_memory) {\n        update_stats(rt, filename);\n    }\n#ifdef CONFIG_AGENT\n    js_agent_free(ctx);\n#endif\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n\n    test_count++;\n    if (ret) {\n        test_failed++;\n        if (outfile) {\n            /* do not output a failure number to minimize diff */\n            fprintf(outfile, \"  FAILED\\n\");\n        }\n    }\n    return ret;\n}\n\nint run_test(const char *filename, int index)\n{\n    char harnessbuf[1024];\n    char *harness;\n    char *buf;\n    size_t buf_len;\n    char *desc, *p;\n    char *error_type;\n    int ret, eval_flags, use_strict, use_nostrict;\n    BOOL is_negative, is_nostrict, is_onlystrict, is_async, is_module, skip;\n    BOOL can_block;\n    namelist_t include_list = { 0 }, *ip = &include_list;\n\n    is_nostrict = is_onlystrict = is_negative = is_async = is_module = skip = FALSE;\n    can_block = TRUE;\n    error_type = NULL;\n    buf = load_file(filename, &buf_len);\n\n    harness = harness_dir;\n\n    if (new_style) {\n        if (!harness) {\n            p = strstr(filename, \"test/\");\n            if (p) {\n                snprintf(harnessbuf, sizeof(harnessbuf), \"%.*s%s\",\n                         (int)(p - filename), filename, \"harness\");\n            } else {\n                pstrcpy(harnessbuf, sizeof(harnessbuf), \"\");\n            }\n            harness = harnessbuf;\n        }\n        namelist_add(ip, NULL, \"sta.js\");\n        namelist_add(ip, NULL, \"assert.js\");\n        /* extract the YAML frontmatter */\n        desc = extract_desc(buf, '-');\n        if (desc) {\n            char *ifile, *option;\n            int state;\n            p = find_tag(desc, \"includes:\", &state);\n            if (p) {\n                while ((ifile = get_option(&p, &state)) != NULL) {\n                    // skip unsupported harness files\n                    if (find_word(harness_exclude, ifile)) {\n                        skip |= 1;\n                    } else {\n                        namelist_add(ip, NULL, ifile);\n                    }\n                    free(ifile);\n                }\n            }\n            p = find_tag(desc, \"flags:\", &state);\n            if (p) {\n                while ((option = get_option(&p, &state)) != NULL) {\n                    if (str_equal(option, \"noStrict\") ||\n                        str_equal(option, \"raw\")) {\n                        is_nostrict = TRUE;\n                        skip |= (test_mode == TEST_STRICT);\n                    }\n                    else if (str_equal(option, \"onlyStrict\")) {\n                        is_onlystrict = TRUE;\n                        skip |= (test_mode == TEST_NOSTRICT);\n                    }\n                    else if (str_equal(option, \"async\")) {\n                        is_async = TRUE;\n                        skip |= skip_async;\n                    }\n                    else if (str_equal(option, \"module\")) {\n                        is_module = TRUE;\n                        skip |= skip_module;\n                    }\n                    else if (str_equal(option, \"CanBlockIsFalse\")) {\n                        can_block = FALSE;\n                    }\n                    free(option);\n                }\n            }\n            p = find_tag(desc, \"negative:\", &state);\n            if (p) {\n                /* XXX: should extract the phase */\n                char *q = find_tag(p, \"type:\", &state);\n                if (q) {\n                    while (isspace((unsigned char)*q))\n                        q++;\n                    error_type = strdup_len(q, strcspn(q, \" \\n\"));\n                }\n                is_negative = TRUE;\n            }\n            p = find_tag(desc, \"features:\", &state);\n            if (p) {\n                while ((option = get_option(&p, &state)) != NULL) {\n                    char *p1;\n                    if (find_word(harness_features, option)) {\n                        /* feature is enabled */\n                    } else if ((p1 = find_word(harness_skip_features, option)) != NULL) {\n                        /* skip disabled feature */\n                        if (harness_skip_features_count)\n                            harness_skip_features_count[p1 - harness_skip_features]++;\n                        skip |= 1;\n                    } else {\n                        /* feature is not listed: skip and warn */\n                        printf(\"%s:%d: unknown feature: %s\\n\", filename, 1, option);\n                        skip |= 1;\n                    }\n                    free(option);\n                }\n            }\n            free(desc);\n        }\n        if (is_async)\n            namelist_add(ip, NULL, \"doneprintHandle.js\");\n    } else {\n        char *ifile;\n\n        if (!harness) {\n            p = strstr(filename, \"test/\");\n            if (p) {\n                snprintf(harnessbuf, sizeof(harnessbuf), \"%.*s%s\",\n                         (int)(p - filename), filename, \"test/harness\");\n            } else {\n                pstrcpy(harnessbuf, sizeof(harnessbuf), \"\");\n            }\n            harness = harnessbuf;\n        }\n\n        namelist_add(ip, NULL, \"sta.js\");\n\n        /* include extra harness files */\n        for (p = buf; (p = strstr(p, \"$INCLUDE(\\\"\")) != NULL; p++) {\n            p += 10;\n            ifile = strdup_len(p, strcspn(p, \"\\\"\"));\n            // skip unsupported harness files\n            if (find_word(harness_exclude, ifile)) {\n                skip |= 1;\n            } else {\n                namelist_add(ip, NULL, ifile);\n            }\n            free(ifile);\n        }\n\n        /* locate the old style configuration comment */\n        desc = extract_desc(buf, '*');\n        if (desc) {\n            if (strstr(desc, \"@noStrict\")) {\n                is_nostrict = TRUE;\n                skip |= (test_mode == TEST_STRICT);\n            }\n            if (strstr(desc, \"@onlyStrict\")) {\n                is_onlystrict = TRUE;\n                skip |= (test_mode == TEST_NOSTRICT);\n            }\n            if (strstr(desc, \"@negative\")) {\n                /* XXX: should extract the regex to check error type */\n                is_negative = TRUE;\n            }\n            free(desc);\n        }\n    }\n\n    if (outfile && index >= 0) {\n        fprintf(outfile, \"%d: %s%s%s%s%s%s%s\\n\", index, filename,\n                is_nostrict ? \"  @noStrict\" : \"\",\n                is_onlystrict ? \"  @onlyStrict\" : \"\",\n                is_async ? \"  async\" : \"\",\n                is_module ? \"  module\" : \"\",\n                is_negative ? \"  @negative\" : \"\",\n                skip ? \"  SKIPPED\" : \"\");\n        fflush(outfile);\n    }\n\n    use_strict = use_nostrict = 0;\n    /* XXX: should remove 'test_mode' or simplify it just to force\n       strict or non strict mode for single file tests */\n    switch (test_mode) {\n    case TEST_DEFAULT_NOSTRICT:\n        if (is_onlystrict)\n            use_strict = 1;\n        else\n            use_nostrict = 1;\n        break;\n    case TEST_DEFAULT_STRICT:\n        if (is_nostrict)\n            use_nostrict = 1;\n        else\n            use_strict = 1;\n        break;\n    case TEST_NOSTRICT:\n        if (!is_onlystrict)\n            use_nostrict = 1;\n        break;\n    case TEST_STRICT:\n        if (!is_nostrict)\n            use_strict = 1;\n        break;\n    case TEST_ALL:\n        if (is_module) {\n            use_nostrict = 1;\n        } else {\n            if (!is_nostrict)\n                use_strict = 1;\n            if (!is_onlystrict)\n                use_nostrict = 1;\n        }\n        break;\n    }\n\n    if (skip || use_strict + use_nostrict == 0) {\n        test_skipped++;\n        ret = -2;\n    } else {\n        clock_t clocks;\n\n        if (is_module) {\n            eval_flags = JS_EVAL_TYPE_MODULE;\n        } else {\n            eval_flags = JS_EVAL_TYPE_GLOBAL;\n        }\n        clocks = clock();\n        ret = 0;\n        if (use_nostrict) {\n            ret = run_test_buf(filename, harness, ip, buf, buf_len,\n                               error_type, eval_flags, is_negative, is_async,\n                               can_block);\n        }\n        if (use_strict) {\n            ret |= run_test_buf(filename, harness, ip, buf, buf_len,\n                                error_type, eval_flags | JS_EVAL_FLAG_STRICT,\n                                is_negative, is_async, can_block);\n        }\n        clocks = clock() - clocks;\n        if (outfile && index >= 0 && clocks >= CLOCKS_PER_SEC / 10) {\n            /* output timings for tests that take more than 100 ms */\n            fprintf(outfile, \" time: %d ms\\n\", (int)(clocks * 1000LL / CLOCKS_PER_SEC));\n        }\n    }\n    namelist_free(&include_list);\n    free(error_type);\n    free(buf);\n\n    return ret;\n}\n\n/* run a test when called by test262-harness+eshost */\nint run_test262_harness_test(const char *filename, BOOL is_module)\n{\n    JSRuntime *rt;\n    JSContext *ctx;\n    char *buf;\n    size_t buf_len;\n    int eval_flags, ret_code, ret;\n    JSValue res_val;\n    BOOL can_block;\n\n    outfile = stdout; /* for js_print */\n\n    rt = JS_NewRuntime();\n    if (rt == NULL) {\n        fatal(1, \"JS_NewRuntime failure\");\n    }\n    ctx = JS_NewContext(rt);\n    if (ctx == NULL) {\n        JS_FreeRuntime(rt);\n        fatal(1, \"JS_NewContext failure\");\n    }\n    JS_SetRuntimeInfo(rt, filename);\n\n    can_block = TRUE;\n    JS_SetCanBlock(rt, can_block);\n\n    /* loader for ES6 modules */\n    JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader_test, NULL, (void *)filename);\n\n    add_helpers(ctx);\n\n    buf = load_file(filename, &buf_len);\n\n    if (is_module) {\n      eval_flags = JS_EVAL_TYPE_MODULE;\n    } else {\n      eval_flags = JS_EVAL_TYPE_GLOBAL;\n    }\n    res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);\n    ret_code = 0;\n    if (JS_IsException(res_val)) {\n       js_std_dump_error(ctx);\n       ret_code = 1;\n    } else {\n        JSValue promise = JS_UNDEFINED;\n        if (is_module) {\n            promise = res_val;\n        } else {\n            JS_FreeValue(ctx, res_val);\n        }\n        for(;;) {\n            ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);\n            if (ret < 0) {\n                js_std_dump_error(ctx);\n                ret_code = 1;\n            } else if (ret == 0) {\n                break;\n            }\n        }\n        /* dump the error if the module returned an error. */\n        if (is_module) {\n            JSPromiseStateEnum state = JS_PromiseState(ctx, promise);\n            if (state == JS_PROMISE_REJECTED) {\n                JS_Throw(ctx, JS_PromiseResult(ctx, promise));\n                js_std_dump_error(ctx);\n                ret_code = 1;\n            }\n        }\n        JS_FreeValue(ctx, promise);\n    }\n    free(buf);\n#ifdef CONFIG_AGENT\n    js_agent_free(ctx);\n#endif\n    JS_FreeContext(ctx);\n    JS_FreeRuntime(rt);\n    return ret_code;\n}\n\nclock_t last_clock;\n\nvoid show_progress(int force) {\n    clock_t t = clock();\n    if (force || !last_clock || (t - last_clock) > CLOCKS_PER_SEC / 20) {\n        last_clock = t;\n        if (compact) {\n            static int last_test_skipped;\n            static int last_test_failed;\n            static int dots;\n            char c = '.';\n            if (test_skipped > last_test_skipped)\n                c = '-';\n            if (test_failed > last_test_failed)\n                c = '!';\n            last_test_skipped = test_skipped;\n            last_test_failed = test_failed;\n            fputc(c, stderr);\n            if (force || ++dots % 60 == 0) {\n                fprintf(stderr, \" %d/%d/%d\\n\",\n                        test_failed, test_count, test_skipped);\n            }\n        } else {\n            /* output progress indicator: erase end of line and return to col 0 */\n            fprintf(stderr, \"%d/%d/%d\\033[K\\r\",\n                    test_failed, test_count, test_skipped);\n        }\n        fflush(stderr);\n    }\n}\n\nstatic int slow_test_threshold;\n\nvoid run_test_dir_list(namelist_t *lp, int start_index, int stop_index)\n{\n    int i;\n\n    namelist_sort(lp);\n    for (i = 0; i < lp->count; i++) {\n        const char *p = lp->array[i];\n        if (namelist_find(&exclude_list, p) >= 0) {\n            test_excluded++;\n        } else if (test_index < start_index) {\n            test_skipped++;\n        } else if (stop_index >= 0 && test_index > stop_index) {\n            test_skipped++;\n        } else {\n            int ti;\n            if (slow_test_threshold != 0) {\n                ti = get_clock_ms();\n            } else {\n                ti = 0;\n            }\n            run_test(p, test_index);\n            if (slow_test_threshold != 0) {\n                ti = get_clock_ms() - ti;\n                if (ti >= slow_test_threshold)\n                    fprintf(stderr, \"\\n%s (%d ms)\\n\", p, ti);\n            }\n            show_progress(FALSE);\n        }\n        test_index++;\n    }\n    show_progress(TRUE);\n}\n\nvoid help(void)\n{\n    printf(\"run-test262 version \" CONFIG_VERSION \"\\n\"\n           \"usage: run-test262 [options] {-f file ... | [dir_list] [index range]}\\n\"\n           \"-h             help\\n\"\n           \"-a             run tests in strict and nostrict modes\\n\"\n           \"-m             print memory usage summary\\n\"\n           \"-n             use new style harness\\n\"\n           \"-N             run test prepared by test262-harness+eshost\\n\"\n           \"-s             run tests in strict mode, skip @nostrict tests\\n\"\n           \"-E             only run tests from the error file\\n\"\n           \"-C             use compact progress indicator\\n\"\n           \"-t             show timings\\n\"\n           \"-u             update error file\\n\"\n           \"-v             verbose: output error messages\\n\"\n           \"-T duration    display tests taking more than 'duration' ms\\n\"\n           \"-c file        read configuration from 'file'\\n\"\n           \"-d dir         run all test files in directory tree 'dir'\\n\"\n           \"-e file        load the known errors from 'file'\\n\"\n           \"-f file        execute single test from 'file'\\n\"\n           \"-r file        set the report file name (default=none)\\n\"\n           \"-x file        exclude tests listed in 'file'\\n\");\n    exit(1);\n}\n\nchar *get_opt_arg(const char *option, char *arg)\n{\n    if (!arg) {\n        fatal(2, \"missing argument for option %s\", option);\n    }\n    return arg;\n}\n\nint main(int argc, char **argv)\n{\n    int optind, start_index, stop_index;\n    BOOL is_dir_list;\n    BOOL only_check_errors = FALSE;\n    const char *filename;\n    const char *ignore = \"\";\n    BOOL is_test262_harness = FALSE;\n    BOOL is_module = FALSE;\n    BOOL count_skipped_features = FALSE;\n    clock_t clocks;\n\n#if !defined(_WIN32)\n    compact = !isatty(STDERR_FILENO);\n    /* Date tests assume California local time */\n    setenv(\"TZ\", \"America/Los_Angeles\", 1);\n#endif\n\n    optind = 1;\n    while (optind < argc) {\n        char *arg = argv[optind];\n        if (*arg != '-')\n            break;\n        optind++;\n        if (strstr(\"-c -d -e -x -f -r -E -T\", arg))\n            optind++;\n        if (strstr(\"-d -f\", arg))\n            ignore = \"testdir\"; // run only the tests from -d or -f\n    }\n\n    /* cannot use getopt because we want to pass the command line to\n       the script */\n    optind = 1;\n    is_dir_list = TRUE;\n    while (optind < argc) {\n        char *arg = argv[optind];\n        if (*arg != '-')\n            break;\n        optind++;\n        if (str_equal(arg, \"-h\")) {\n            help();\n        } else if (str_equal(arg, \"-m\")) {\n            dump_memory++;\n        } else if (str_equal(arg, \"-n\")) {\n            new_style++;\n        } else if (str_equal(arg, \"-s\")) {\n            test_mode = TEST_STRICT;\n        } else if (str_equal(arg, \"-a\")) {\n            test_mode = TEST_ALL;\n        } else if (str_equal(arg, \"-t\")) {\n            show_timings++;\n        } else if (str_equal(arg, \"-u\")) {\n            update_errors++;\n        } else if (str_equal(arg, \"-v\")) {\n            verbose++;\n        } else if (str_equal(arg, \"-C\")) {\n            compact = 1;\n        } else if (str_equal(arg, \"-c\")) {\n            load_config(get_opt_arg(arg, argv[optind++]), ignore);\n        } else if (str_equal(arg, \"-d\")) {\n            enumerate_tests(get_opt_arg(arg, argv[optind++]));\n        } else if (str_equal(arg, \"-e\")) {\n            error_filename = get_opt_arg(arg, argv[optind++]);\n        } else if (str_equal(arg, \"-x\")) {\n            namelist_load(&exclude_list, get_opt_arg(arg, argv[optind++]));\n        } else if (str_equal(arg, \"-f\")) {\n            is_dir_list = FALSE;\n        } else if (str_equal(arg, \"-r\")) {\n            report_filename = get_opt_arg(arg, argv[optind++]);\n        } else if (str_equal(arg, \"-E\")) {\n            only_check_errors = TRUE;\n        } else if (str_equal(arg, \"-T\")) {\n            slow_test_threshold = atoi(get_opt_arg(arg, argv[optind++]));\n        } else if (str_equal(arg, \"-N\")) {\n            is_test262_harness = TRUE;\n        } else if (str_equal(arg, \"--module\")) {\n            is_module = TRUE;\n        } else if (str_equal(arg, \"--count_skipped_features\")) {\n            count_skipped_features = TRUE;\n        } else {\n            fatal(1, \"unknown option: %s\", arg);\n            break;\n        }\n    }\n\n    if (optind >= argc && !test_list.count)\n        help();\n\n    if (is_test262_harness) {\n        return run_test262_harness_test(argv[optind], is_module);\n    }\n\n    error_out = stdout;\n    if (error_filename) {\n        error_file = load_file(error_filename, NULL);\n        if (only_check_errors && error_file) {\n            namelist_free(&test_list);\n            namelist_add_from_error_file(&test_list, error_file);\n        }\n        if (update_errors) {\n            free(error_file);\n            error_file = NULL;\n            error_out = fopen(error_filename, \"w\");\n            if (!error_out) {\n                perror_exit(1, error_filename);\n            }\n        }\n    }\n\n    update_exclude_dirs();\n\n    clocks = clock();\n\n    if (count_skipped_features) {\n        /* not storage efficient but it is simple */\n        size_t size;\n        size = sizeof(harness_skip_features_count[0]) * strlen(harness_skip_features);\n        harness_skip_features_count = malloc(size);\n        memset(harness_skip_features_count, 0, size);\n    }\n    \n    if (is_dir_list) {\n        if (optind < argc && !isdigit((unsigned char)argv[optind][0])) {\n            filename = argv[optind++];\n            namelist_load(&test_list, filename);\n        }\n        start_index = 0;\n        stop_index = -1;\n        if (optind < argc) {\n            start_index = atoi(argv[optind++]);\n            if (optind < argc) {\n                stop_index = atoi(argv[optind++]);\n            }\n        }\n        if (!report_filename || str_equal(report_filename, \"none\")) {\n            outfile = NULL;\n        } else if (str_equal(report_filename, \"-\")) {\n            outfile = stdout;\n        } else {\n            outfile = fopen(report_filename, \"wb\");\n            if (!outfile) {\n                perror_exit(1, report_filename);\n            }\n        }\n        run_test_dir_list(&test_list, start_index, stop_index);\n\n        if (outfile && outfile != stdout) {\n            fclose(outfile);\n            outfile = NULL;\n        }\n    } else {\n        outfile = stdout;\n        while (optind < argc) {\n            run_test(argv[optind++], -1);\n        }\n    }\n\n    clocks = clock() - clocks;\n\n    if (dump_memory) {\n        if (dump_memory > 1 && stats_count > 1) {\n            printf(\"\\nMininum memory statistics for %s:\\n\\n\", stats_min_filename);\n            JS_DumpMemoryUsage(stdout, &stats_min, NULL);\n            printf(\"\\nMaximum memory statistics for %s:\\n\\n\", stats_max_filename);\n            JS_DumpMemoryUsage(stdout, &stats_max, NULL);\n        }\n        printf(\"\\nAverage memory statistics for %d tests:\\n\\n\", stats_count);\n        JS_DumpMemoryUsage(stdout, &stats_avg, NULL);\n        printf(\"\\n\");\n    }\n\n    if (count_skipped_features) {\n        size_t i, n, len = strlen(harness_skip_features);\n        BOOL disp = FALSE;\n        int c;\n        for(i = 0; i < len; i++) {\n            if (harness_skip_features_count[i] != 0) {\n                if (!disp) {\n                    disp = TRUE;\n                    printf(\"%-30s %7s\\n\", \"SKIPPED FEATURE\", \"COUNT\");\n                }\n                for(n = 0; n < 30; n++) {\n                    c = harness_skip_features[i + n];\n                    if (is_word_sep(c))\n                        break;\n                    putchar(c);\n                }\n                for(; n < 30; n++)\n                    putchar(' ');\n                printf(\" %7d\\n\", harness_skip_features_count[i]);\n            }\n        }\n        printf(\"\\n\");\n    }\n    \n    if (is_dir_list) {\n        fprintf(stderr, \"Result: %d/%d error%s\",\n                test_failed, test_count, test_count != 1 ? \"s\" : \"\");\n        if (test_excluded)\n            fprintf(stderr, \", %d excluded\", test_excluded);\n        if (test_skipped)\n            fprintf(stderr, \", %d skipped\", test_skipped);\n        if (error_file) {\n            if (new_errors)\n                fprintf(stderr, \", %d new\", new_errors);\n            if (changed_errors)\n                fprintf(stderr, \", %d changed\", changed_errors);\n            if (fixed_errors)\n                fprintf(stderr, \", %d fixed\", fixed_errors);\n        }\n        fprintf(stderr, \"\\n\");\n        if (show_timings)\n            fprintf(stderr, \"Total time: %.3fs\\n\", (double)clocks / CLOCKS_PER_SEC);\n    }\n\n    if (error_out && error_out != stdout) {\n        fclose(error_out);\n        error_out = NULL;\n    }\n\n    namelist_free(&test_list);\n    namelist_free(&exclude_list);\n    namelist_free(&exclude_dir_list);\n    free(harness_dir);\n    free(harness_skip_features);\n    free(harness_skip_features_count);\n    free(harness_features);\n    free(harness_exclude);\n    free(error_file);\n\n    /* Signal that the error file is out of date. */\n    return new_errors || changed_errors || fixed_errors;\n}\n"
  },
  {
    "path": "test262.conf",
    "content": "[config]\n# general settings for test262 ES6 version\n\n# framework style: old, new\nstyle=new\n\n# handle tests tagged as [noStrict]: yes, no, skip\nnostrict=yes\n\n# handle tests tagged as [strictOnly]: yes, no, skip\nstrict=yes\n\n# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all\nmode=default\n\n# handle tests flagged as [async]: yes, no, skip\n# for these, load 'harness/doneprintHandle.js' prior to test\n# and expect `print('Test262:AsyncTestComplete')` to be called for\n# successful termination\nasync=yes\n\n# handle tests flagged as [module]: yes, no, skip\nmodule=yes\n\n# output error messages: yes, no\nverbose=yes\n\n# load harness files from this directory\nharnessdir=test262/harness\n\n# names of harness include files to skip\n#harnessexclude=\n\n# name of the error file for known errors\nerrorfile=test262_errors.txt\n\n# exclude tests enumerated in this file (see also [exclude] section)\n#excludefile=test262_exclude.txt\n\n# report test results to this file\nreportfile=test262_report.txt\n\n# enumerate tests from this directory\ntestdir=test262/test\n\n[features]\n# Standard language features and proposed extensions\n# list the features that are included\n# skipped features are tagged as such to avoid warnings\n# Keep this list alpha-sorted (:sort i in vim)\n\n__getter__\n__proto__\n__setter__\nAggregateError\nalign-detached-buffer-semantics-with-web-reality\narbitrary-module-namespace-names=skip\narray-find-from-last\narray-grouping\nArray.fromAsync=skip\nArray.prototype.at\nArray.prototype.flat\nArray.prototype.flatMap\nArray.prototype.includes\nArray.prototype.values\nArrayBuffer\narraybuffer-transfer\narrow-function\nasync-functions\nasync-iteration\nAtomics\nAtomics.pause\nAtomics.waitAsync=skip\nBigInt\ncaller\ncanonical-tz=skip\nchange-array-by-copy\nclass\nclass-fields-private\nclass-fields-private-in\nclass-fields-public\nclass-methods-private\nclass-static-block\nclass-static-fields-private\nclass-static-fields-public\nclass-static-methods-private\ncoalesce-expression\ncomputed-property-names\nconst\ncross-realm\nDataView\nDataView.prototype.getFloat32\nDataView.prototype.getFloat64\nDataView.prototype.getInt16\nDataView.prototype.getInt32\nDataView.prototype.getInt8\nDataView.prototype.getUint16\nDataView.prototype.getUint32\nDataView.prototype.setUint8\ndecorators=skip\ndefault-parameters\ndestructuring-assignment\ndestructuring-binding\ndynamic-import\nerror-cause\nError.isError\nexplicit-resource-management=skip\nexponentiation\nexport-star-as-namespace-from-module\nFinalizationRegistry\nFloat16Array\nFloat32Array\nFloat64Array\nfor-in-order\nfor-of\ngenerators\nglobalThis\nhashbang\nhost-gc-required\nimmutable-arraybuffer=skip\nimport-attributes\nimport-defer=skip\nimport.meta\njoint-iteration=skip\nInt16Array\nInt32Array\nInt8Array\nIntl-enumeration=skip\nintl-normative-optional=skip\nIntl.DateTimeFormat-datetimestyle=skip\nIntl.DateTimeFormat-dayPeriod=skip\nIntl.DateTimeFormat-extend-timezonename=skip\nIntl.DateTimeFormat-formatRange=skip\nIntl.DateTimeFormat-fractionalSecondDigits=skip\nIntl.DisplayNames-v2=skip\nIntl.DisplayNames=skip\nIntl.DurationFormat=skip\nIntl.ListFormat=skip\nIntl.Locale-info=skip\nIntl.Locale=skip\nIntl.NumberFormat-unified=skip\nIntl.NumberFormat-v3=skip\nIntl.RelativeTimeFormat=skip\nIntl.Segmenter=skip\nIsHTMLDDA\niterator-helpers\niterator-sequencing\njson-modules\njson-parse-with-source=skip\njson-superset\nlegacy-regexp=skip\nlet\nlogical-assignment-operators\nMap\nMath.sumPrecise\nnew.target\nnonextensible-applies-to-private=skip\nnumeric-separator-literal\nobject-rest\nobject-spread\nObject.fromEntries\nObject.hasOwn\nObject.is\noptional-catch-binding\noptional-chaining\nPromise\npromise-try\npromise-with-resolvers\nPromise.allSettled\nPromise.any\nPromise.prototype.finally\nProxy\nproxy-missing-checks\nReflect\nReflect.construct\nReflect.set\nReflect.setPrototypeOf\nregexp-dotall\nregexp-duplicate-named-groups\nregexp-lookbehind\nregexp-match-indices\nregexp-modifiers\nregexp-named-groups\nregexp-unicode-property-escapes\nregexp-v-flag\nRegExp.escape\nresizable-arraybuffer\nrest-parameters\nSet\nset-methods\nShadowRealm=skip\nSharedArrayBuffer\nsource-phase-imports-module-source=skip\nsource-phase-imports=skip\nstable-array-sort\nstable-typedarray-sort\nstring-trimming\nString.fromCodePoint\nString.prototype.at\nString.prototype.endsWith\nString.prototype.includes\nString.prototype.isWellFormed\nString.prototype.matchAll\nString.prototype.replaceAll\nString.prototype.toWellFormed\nString.prototype.trimEnd\nString.prototype.trimStart\nsuper\nSymbol\nSymbol.asyncIterator\nSymbol.hasInstance\nSymbol.isConcatSpreadable\nSymbol.iterator\nSymbol.match\nSymbol.matchAll\nSymbol.prototype.description\nSymbol.replace\nSymbol.search\nSymbol.species\nSymbol.split\nSymbol.toPrimitive\nSymbol.toStringTag\nSymbol.unscopables\nsymbols-as-weakmap-keys\ntail-call-optimization=skip\ntemplate\nTemporal=skip\ntop-level-await\nTypedArray\nTypedArray.prototype.at\nu180e\nUint16Array\nUint32Array\nUint8Array\nuint8array-base64=skip\nUint8ClampedArray\nupsert\nWeakMap\nWeakRef\nWeakSet\nwell-formed-json-stringify\n\n[exclude]\n# list excluded tests and directories here\n\n# intl not supported\ntest262/test/intl402/\n\n# incompatible with the \"caller\" feature\ntest262/test/built-ins/Function/prototype/restricted-property-caller.js\ntest262/test/built-ins/Function/prototype/restricted-property-arguments.js\ntest262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js\n\n# slow tests\n#test262/test/built-ins/RegExp/CharacterClassEscapes/\n#test262/test/built-ins/RegExp/property-escapes/\n\n####################################\n# staging tests\n\n# sort() does not modify the array and we don't update it (XXX: the\n# spec updates it in this case)\ntest262/test/staging/sm/Array/frozen-dense-array.js\n\n# does not match spec\ntest262/test/staging/sm/Iterator/from/wrap-next-not-object-throws.js\n\n# not supported\ntest262/test/staging/sm/extensions/censor-strict-caller.js\ntest262/test/staging/sm/JSON/parse-with-source.js\n\n# not standard\ntest262/test/staging/sm/Function/builtin-no-construct.js\ntest262/test/staging/sm/Function/function-caller-restrictions.js\ntest262/test/staging/sm/Function/function-toString-builtin-name.js\ntest262/test/staging/sm/extensions/arguments-property-access-in-function.js\ntest262/test/staging/sm/extensions/function-caller-skips-eval-frames.js\ntest262/test/staging/sm/extensions/function-properties.js\ntest262/test/staging/sm/regress/regress-577648-1.js\ntest262/test/staging/sm/regress/regress-577648-2.js\ntest262/test/staging/sm/regress/regress-584355.js\ntest262/test/staging/sm/regress/regress-586482-1.js\ntest262/test/staging/sm/regress/regress-586482-2.js\ntest262/test/staging/sm/regress/regress-586482-3.js\ntest262/test/staging/sm/regress/regress-586482-4.js\ntest262/test/staging/sm/regress/regress-699682.js\n\n# RegExp toSource not fully compliant\ntest262/test/staging/sm/RegExp/toString.js\ntest262/test/staging/sm/RegExp/source.js\ntest262/test/staging/sm/RegExp/escape.js\n# RegExp.lastMatch not supported\ntest262/test/staging/sm/statements/regress-642975.js\n# source directives are not standard yet\ntest262/test/staging/sm/syntax/syntax-parsed-arrow-then-directive.js\n# returning \"bound fn\" as initialName for a function is permitted by the spec\ntest262/test/staging/sm/Function/function-toString-builtin.js\n\n[tests]\n# list test files or use config.testdir\n"
  },
  {
    "path": "test262o.conf",
    "content": "[config]\n# general settings for test262 ES5 version\n\n# framework style: old, new\nstyle=old\n\n# handle tests tagged as @noStrict: yes, no, skip\nnostrict=yes\n\n# handle tests tagged as @strictOnly: yes, no, skip\nstrict=yes\n\n# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all\nmode=default\n\n# output error messages: yes, no\nverbose=yes\n\n# load harness files this directory\nharnessdir=test262o/test/harness\n\n# name of the error file for known errors\nerrorfile=test262o_errors.txt\n\n# exclude tests enumerated in this file\n#excludefile=test262o_excluded.txt\n\n# report test results to this file\nreportfile=test262o_report.txt\n\n# enumerate tests from this directory\ntestdir=test262o/test/suite\n\n[exclude]\n# list excluded tests and directories here\n\n# intl not supported\ntest262o/test/suite/intl402/\n\n# ES6 != ES5: block scoped function definitions allowed in strict mode\ntest262o/test/suite/bestPractice/Sbp_A1_T1.js\ntest262o/test/suite/bestPractice/Sbp_A2_T1.js\ntest262o/test/suite/bestPractice/Sbp_A2_T2.js\ntest262o/test/suite/bestPractice/Sbp_A3_T1.js\ntest262o/test/suite/bestPractice/Sbp_A3_T2.js\ntest262o/test/suite/bestPractice/Sbp_A4_T1.js\ntest262o/test/suite/bestPractice/Sbp_A4_T2.js\ntest262o/test/suite/bestPractice/Sbp_A5_T2.js\n\n# ES6 != ES5: `y={x};` is shorthand for `y={x:x}`\ntest262o/test/suite/ch12/12.1/S12.1_A4_T2.js\ntest262o/test/suite/ch12/12.6/12.6.4/S12.6.4_A15.js\n\n# ES6 != ES5: function length property is configurable\ntest262o/test/suite/ch11/11.4/11.4.1/11.4.1-5-a-28-s.js\ntest262o/test/suite/ch13/13.2/13.2-15-1.js\ntest262o/test/suite/ch15/15.1/15.1.2/15.1.2.1/S15.1.2.1_A4.2.js\ntest262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A9.2.js\ntest262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A7.2.js\ntest262o/test/suite/ch15/15.1/15.1.2/15.1.2.4/S15.1.2.4_A2.2.js\ntest262o/test/suite/ch15/15.1/15.1.2/15.1.2.5/S15.1.2.5_A2.2.js\ntest262o/test/suite/ch15/15.1/15.1.3/15.1.3.1/S15.1.3.1_A5.2.js\ntest262o/test/suite/ch15/15.1/15.1.3/15.1.3.2/S15.1.3.2_A5.2.js\ntest262o/test/suite/ch15/15.1/15.1.3/15.1.3.3/S15.1.3.3_A5.2.js\ntest262o/test/suite/ch15/15.1/15.1.3/15.1.3.4/S15.1.3.4_A5.2.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201.js\ntest262o/test/suite/ch15/15.2/15.2.4/15.2.4.2/S15.2.4.2_A9.js\ntest262o/test/suite/ch15/15.2/15.2.4/15.2.4.3/S15.2.4.3_A9.js\ntest262o/test/suite/ch15/15.2/15.2.4/15.2.4.4/S15.2.4.4_A9.js\ntest262o/test/suite/ch15/15.2/15.2.4/15.2.4.5/S15.2.4.5_A9.js\ntest262o/test/suite/ch15/15.2/15.2.4/15.2.4.6/S15.2.4.6_A9.js\ntest262o/test/suite/ch15/15.2/15.2.4/15.2.4.7/S15.2.4.7_A9.js\ntest262o/test/suite/ch15/15.3/15.3.3/15.3.3.2/15.3.3.2-1.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.2/S15.3.4.2_A9.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.3/S15.3.4.3_A9.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.4/S15.3.4.4_A9.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-15-2.js\ntest262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T1.js\ntest262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T2.js\ntest262o/test/suite/ch15/15.3/15.3.5/S15.3.5.1_A2_T3.js\ntest262o/test/suite/ch15/15.4/15.4.3/S15.4.3_A2.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.2/S15.4.4.2_A4.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.3/S15.4.4.3_A4.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.4/S15.4.4.4_A4.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A6.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A5.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A6.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A5.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A5.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A5.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A7.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A5.2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A5.2.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.4/S15.5.4.4_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.5/S15.5.4.5_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.6/S15.5.4.6_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.7/S15.5.4.7_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.8/S15.5.4.8_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.9/S15.5.4.9_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.10/S15.5.4.10_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.11/S15.5.4.11_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.12/S15.5.4.12_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.13/S15.5.4.13_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.14/S15.5.4.14_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.15/S15.5.4.15_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.16/S15.5.4.16_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.17/S15.5.4.17_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.18/S15.5.4.18_A9.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.19/S15.5.4.19_A9.js\ntest262o/test/suite/ch15/15.9/15.9.4/15.9.4.2/S15.9.4.2_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.4/15.9.4.3/S15.9.4.3_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.1/S15.9.5.1_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.2/S15.9.5.2_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.3/S15.9.5.3_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.4/S15.9.5.4_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.5/S15.9.5.5_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.6/S15.9.5.6_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.7/S15.9.5.7_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.8/S15.9.5.8_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.9/S15.9.5.9_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.10/S15.9.5.10_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.11/S15.9.5.11_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.12/S15.9.5.12_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.13/S15.9.5.13_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.14/S15.9.5.14_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.15/S15.9.5.15_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.16/S15.9.5.16_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.17/S15.9.5.17_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.18/S15.9.5.18_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.19/S15.9.5.19_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.20/S15.9.5.20_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.21/S15.9.5.21_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.22/S15.9.5.22_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.23/S15.9.5.23_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.24/S15.9.5.24_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.25/S15.9.5.25_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.26/S15.9.5.26_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.27/S15.9.5.27_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.28/S15.9.5.28_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.29/S15.9.5.29_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.30/S15.9.5.30_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.31/S15.9.5.31_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.32/S15.9.5.32_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.33/S15.9.5.33_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.34/S15.9.5.34_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.35/S15.9.5.35_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.36/S15.9.5.36_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.37/S15.9.5.37_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.38/S15.9.5.38_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.39/S15.9.5.39_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/S15.9.5.40_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.41/S15.9.5.41_A3_T2.js\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.42/S15.9.5.42_A3_T2.js\ntest262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A9.js\ntest262o/test/suite/ch15/15.10/15.10.6/15.10.6.3/S15.10.6.3_A9.js\ntest262o/test/suite/ch15/15.10/15.10.6/15.10.6.4/S15.10.6.4_A9.js\n\n# ES6 != ES5: object literals may have duplicates\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5-4-4-a-1-s.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-1.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-b-2.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-1.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-c-2.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-1.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-2.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-3.js\ntest262o/test/suite/ch11/11.1/11.1.5/11.1.5_4-4-d-4.js\n\n# ES6 != ES5: Date.prototype is no longer an instance of Date\ntest262o/test/suite/ch15/15.9/15.9.5/15.9.5.40/15.9.5.40_1.js\n\n# ES6 != ES5: Object.getPrototypeOf converts argument to object\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-3.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-1.js\n\n# ES6 != ES5: Object.getPrototypeOf(NativeError)\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-12.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-13.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-14.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-15.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-16.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.2/15.2.3.2-2-17.js\n\n# ES6 != ES5: Object.getOwnPropertyDescriptor converts argument to object\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-3.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-1.js\n\n# ES6 != ES5: Object.getOwnPropertyNames converts argument to object\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1-5.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-1.js\n\n# ES6 != ES5: Object.seal accepts all types\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-1.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-2.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-3.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.8/15.2.3.8-1.js\n\n# ES6 != ES5: Object.freeze accepts all types\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-1.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-2.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-3.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.9/15.2.3.9-1.js\n\n# ES6 != ES5: Object.preventExtensions accepts all types\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-1.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-2.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-3.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.10/15.2.3.10-1.js\n\n# ES6 != ES5: Object.isSealed accepts all types\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.11/15.2.3.11-1.js\n\n# ES6 != ES5: Object.isFrozen accepts all types\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-1.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-2.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-3.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.12/15.2.3.12-1.js\n\n# ES6 != ES5: Object.isExtensible accepts all types\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-1.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-2.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-3.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1-4.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.13/15.2.3.13-1.js\n\n# ES6 != ES5: Object.keys converts argument to object\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-1.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-2.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.14/15.2.3.14-1-3.js\n\n# ES6 != ES5: source and other properties of RegExp.prototype are not own properties\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-213.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-214.js\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215.js\n\n# ES6 != ES5: String numeric object properties are enumerated first\ntest262o/test/suite/ch15/15.2/15.2.3/15.2.3.4/15.2.3.4-4-44.js\n\n# ES6: new RegExp(regex, flags) is valid\ntest262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T1.js\ntest262o/test/suite/ch15/15.10/15.10.3/S15.10.3.1_A2_T2.js\ntest262o/test/suite/ch15/15.10/15.10.4/15.10.4.1/15.10.4.1-1.js\ntest262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T1.js\ntest262o/test/suite/ch15/15.10/15.10.4/S15.10.4.1_A2_T2.js\n\n# ES6 != ES5: RegExp.prototype.test behavior\ntest262o/test/suite/ch15/15.10/15.10.6/15.10.6.2/S15.10.6.2_A5_T3.js\n\n# ES6 != ES5: source, global, ignoreCase, multiline, lastIndex are not data properties\n# of RegExp objects and RegExp.prototype is not a RegExp object\ntest262o/test/suite/ch15/15.10/15.10.6/15.10.6.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-1.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/15.10.7.1-2.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A8.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A9.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.1/S15.10.7.1_A10.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-1.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/15.10.7.2-2.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A8.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A9.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.2/S15.10.7.2_A10.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-1.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/15.10.7.3-2.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A8.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A9.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.3/S15.10.7.3_A10.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-1.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/15.10.7.4-2.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A8.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A9.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.4/S15.10.7.4_A10.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-1.js\ntest262o/test/suite/ch15/15.10/15.10.7/15.10.7.5/15.10.7.5-2.js\n\n# ES6 != ES5: Error.prototype is a normal object\ntest262o/test/suite/ch15/15.11/15.11.4/S15.11.4_A2.js\n\n# ES6 different ToLength() semantics\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.5/S15.4.4.5_A4_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A2_T2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T1.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.6/S15.4.4.6_A3_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A2_T2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T1.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.7/S15.4.4.7_A4_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.8/S15.4.4.8_A3_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.9/S15.4.4.9_A3_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T1.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.10/S15.4.4.10_A3_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.11/S15.4.4.11_A4_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T1.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.12/S15.4.4.12_A3_T3.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.13/S15.4.4.13_A3_T2.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-8.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-28.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.14/15.4.4.14-3-29.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-28.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-8.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.16/15.4.4.16-3-29.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-8.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-28.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.17/15.4.4.17-3-29.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-8.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-28.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.19/15.4.4.19-3-29.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-25.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-7.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-12.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-25.js\n\n# ES6 different ToLength() semantics causes near infinite runtime\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.15/15.4.4.15-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.18/15.4.4.18-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.20/15.4.4.20-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.21/15.4.4.21-3-14.js\ntest262o/test/suite/ch15/15.4/15.4.4/15.4.4.22/15.4.4.22-3-14.js\n\n# ES6 arguments/caller changes\ntest262o/test/suite/ch10/10.6/10.6-13-b-1-s.js\ntest262o/test/suite/ch10/10.6/10.6-13-b-2-s.js\ntest262o/test/suite/ch10/10.6/10.6-13-b-3-s.js\ntest262o/test/suite/ch10/10.6/10.6-14-1-s.js\ntest262o/test/suite/ch10/10.6/10.6-14-b-1-s.js\ntest262o/test/suite/ch10/10.6/10.6-14-b-4-s.js\ntest262o/test/suite/ch13/13.2/13.2-29-s.js\ntest262o/test/suite/ch13/13.2/13.2-30-s.js\ntest262o/test/suite/ch13/13.2/13.2-31-s.js\ntest262o/test/suite/ch13/13.2/13.2-32-s.js\ntest262o/test/suite/ch13/13.2/13.2-33-s.js\ntest262o/test/suite/ch13/13.2/13.2-34-s.js\ntest262o/test/suite/ch13/13.2/13.2-35-s.js\ntest262o/test/suite/ch13/13.2/13.2-36-s.js\ntest262o/test/suite/ch13/13.2/S13.2.3_A1.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-1.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-4.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-20-5.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-1.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-4.js\ntest262o/test/suite/ch15/15.3/15.3.4/15.3.4.5/15.3.4.5-21-5.js\n\n# u180e is no longer considered as a space\ntest262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A2.js\ntest262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T1.js\ntest262o/test/suite/ch09/9.3/9.3.1/S9.3.1_A3_T2.js\ntest262o/test/suite/ch15/15.1/15.1.2/15.1.2.2/S15.1.2.2_A2_T10.js\ntest262o/test/suite/ch15/15.1/15.1.2/15.1.2.3/S15.1.2.3_A2_T10.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-2.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-3.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-4.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-5.js\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.20/15.5.4.20-3-6.js\ntest262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A1_T1.js\ntest262o/test/suite/ch15/15.10/15.10.2/15.10.2.12/S15.10.2.12_A2_T1.js\n\n# E6 eval return value is different\ntest262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.js\ntest262o/test/suite/ch12/12.6/12.6.3/S12.6.3_A9.1.js\n\n# ECMA 2019 optional-catch-binding feature allows try{}catch{}\ntest262o/test/suite/ch12/12.14/S12.14_A16_T4.js\n\n# Syntax error instead of ReferenceError in ES2020\ntest262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-1.js\ntest262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-2.js\ntest262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-3.js\ntest262o/test/suite/ch11/11.13/11.13.1/11.13.1-1-4.js\n\n# String.prototype.localeCompare special cases\ntest262o/test/suite/ch15/15.5/15.5.4/15.5.4.9/15.5.4.9_CE.js\n\n[tests]\n# list test files or use config.testdir\n"
  },
  {
    "path": "tests/assert.js",
    "content": "export function assert(actual, expected, message) {\n    if (arguments.length === 1)\n        expected = true;\n\n    if (typeof actual === typeof expected) {\n        if (Object.is(actual, expected))\n            return;\n        if (typeof actual === 'object') {\n            if (actual !== null && expected !== null\n            &&  actual.constructor === expected.constructor\n            &&  actual.toString() === expected.toString())\n                return;\n        }\n    }\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\nexport function assertThrows(err, func)\n{\n    var ex;\n    ex = false;\n    try {\n        func();\n    } catch(e) {\n        ex = true;\n        assert(e instanceof err);\n    }\n    assert(ex, true, \"exception expected\");\n}\n\nexport function assertArrayEquals(a, b)\n{\n    if (!Array.isArray(a) || !Array.isArray(b))\n        return assert(false);\n\n    assert(a.length, b.length);\n\n    a.forEach((value, idx) => {\n        assert(b[idx], value);\n    });\n}\n"
  },
  {
    "path": "tests/bjson.c",
    "content": "/*\n * QuickJS: binary JSON module (test only)\n *\n * Copyright (c) 2017-2019 Fabrice Bellard\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include \"../quickjs-libc.h\"\n#include \"../cutils.h\"\n\nstatic JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,\n                             int argc, JSValueConst *argv)\n{\n    uint8_t *buf;\n    uint64_t pos, len;\n    JSValue obj;\n    size_t size;\n    int flags;\n\n    if (JS_ToIndex(ctx, &pos, argv[1]))\n        return JS_EXCEPTION;\n    if (JS_ToIndex(ctx, &len, argv[2]))\n        return JS_EXCEPTION;\n    buf = JS_GetArrayBuffer(ctx, &size, argv[0]);\n    if (!buf)\n        return JS_EXCEPTION;\n    if (pos + len > size)\n        return JS_ThrowRangeError(ctx, \"array buffer overflow\");\n    flags = 0;\n    if (JS_ToBool(ctx, argv[3]))\n        flags |= JS_READ_OBJ_REFERENCE;\n    obj = JS_ReadObject(ctx, buf + pos, len, flags);\n    return obj;\n}\n\nstatic JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val,\n                              int argc, JSValueConst *argv)\n{\n    size_t len;\n    uint8_t *buf;\n    JSValue array;\n    int flags;\n\n    flags = 0;\n    if (JS_ToBool(ctx, argv[1]))\n        flags |= JS_WRITE_OBJ_REFERENCE;\n    buf = JS_WriteObject(ctx, &len, argv[0], flags);\n    if (!buf)\n        return JS_EXCEPTION;\n    array = JS_NewArrayBufferCopy(ctx, buf, len);\n    js_free(ctx, buf);\n    return array;\n}\n\nstatic const JSCFunctionListEntry js_bjson_funcs[] = {\n    JS_CFUNC_DEF(\"read\", 4, js_bjson_read ),\n    JS_CFUNC_DEF(\"write\", 2, js_bjson_write ),\n};\n\nstatic int js_bjson_init(JSContext *ctx, JSModuleDef *m)\n{\n    return JS_SetModuleExportList(ctx, m, js_bjson_funcs,\n                                  countof(js_bjson_funcs));\n}\n\n#ifdef JS_SHARED_LIBRARY\n#define JS_INIT_MODULE js_init_module\n#else\n#define JS_INIT_MODULE js_init_module_bjson\n#endif\n\nJSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)\n{\n    JSModuleDef *m;\n    m = JS_NewCModule(ctx, module_name, js_bjson_init);\n    if (!m)\n        return NULL;\n    JS_AddModuleExportList(ctx, m, js_bjson_funcs, countof(js_bjson_funcs));\n    return m;\n}\n"
  },
  {
    "path": "tests/fixture_cyclic_import.js",
    "content": "import * as a from \"./test_cyclic_import.js\"\nexport function f(x) { return 2 * a.g(x) }\n"
  },
  {
    "path": "tests/microbench.js",
    "content": "/*\n * Javascript Micro benchmark\n *\n * Copyright (c) 2017-2019 Fabrice Bellard\n * Copyright (c) 2017-2019 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n\nif (typeof require !== 'undefined') {\n    var fs = require('fs');\n}\n\nfunction pad(str, n) {\n    str += \"\";\n    while (str.length < n)\n        str += \" \";\n    return str;\n}\n\nfunction pad_left(str, n) {\n    str += \"\";\n    while (str.length < n)\n        str = \" \" + str;\n    return str;\n}\n\nfunction pad_center(str, n) {\n    str += \"\";\n    while (str.length < n) {\n        if ((n - str.length) & 1)\n            str = str + \" \";\n        else\n            str = \" \" + str;\n    }\n    return str;\n}\n\nvar ref_data;\nvar log_data;\n\nvar heads  = [ \"TEST\", \"N\", \"TIME (ns)\", \"REF (ns)\", \"SCORE (1000)\" ];\nvar widths = [    22,   10,          9,     9,       9 ];\nvar precs  = [     0,   0,           2,     2,       0 ];\nvar total  = [     0,   0,           0,     0,       0 ];\nvar total_score = 0;\nvar total_scale = 0;\n\nfunction log_line() {\n    var i, n, s, a;\n    s = \"\";\n    for (i = 0, n = arguments.length; i < n; i++) {\n        if (i > 0)\n            s += \" \";\n        a = arguments[i];\n        if (typeof a === \"number\") {\n            total[i] += a;\n            a = a.toFixed(precs[i]);\n            s += pad_left(a, widths[i]);\n        } else {\n            s += pad_left(a, widths[i]);\n        }\n    }\n    console.log(s);\n}\n\nvar clocks_per_sec = 1000;\nvar max_iterations = 100;\nvar clock_threshold = 2;  /* favoring short measuring spans */\nvar min_n_argument = 1;\nvar get_clock;\nif (typeof performance !== \"undefined\") {\n    // use more precise clock on NodeJS\n    // need a method call on performance object\n    get_clock = () => performance.now();\n} else\nif (typeof os !== \"undefined\") {\n    // use more precise clock on QuickJS\n    get_clock = os.now;\n} else {\n    // use Date.now and round up to the next millisecond\n    get_clock = () => {\n        var t0 = Date.now();\n        var t;\n        while ((t = Date.now()) == t0)\n            continue;\n        return t;\n    }\n}\n\nfunction log_one(text, n, ti) {\n    var ref;\n\n    if (ref_data)\n        ref = ref_data[text];\n    else\n        ref = null;\n\n    ti = Math.round(ti * 100) / 100;\n    log_data[text] = ti;\n    if (typeof ref === \"number\") {\n        log_line(text, n, ti, ref, Math.round(ref * 1000 / ti));\n        total_score += ti * 100 / ref;\n        total_scale += 100;\n    } else {\n        log_line(text, n, ti);\n        total_score += 100;\n        total_scale += 100;\n    }\n}\n\nfunction bench(f, text)\n{\n    var i, j, n, t, ti, nb_its, ref, ti_n, ti_n1;\n\n    nb_its = n = 1;\n    if (f.bench) {\n        ti_n = f(text);\n    } else {\n        // measure ti_n: the shortest time for an individual operation\n        ti_n = 1000000000;\n        for(i = 0; i < 30; i++) {\n            // measure ti: the shortest time for max_iterations iterations\n            ti = 1000000000;\n            for (j = 0; j < max_iterations; j++) {\n                t = get_clock();\n                nb_its = f(n);\n                t = get_clock() - t;\n                if (nb_its < 0)\n                    return; // test failure\n                if (ti > t)\n                    ti = t;\n            }\n            if (ti >= clock_threshold / 10) {\n                ti_n1 = ti / nb_its;\n                if (ti_n > ti_n1)\n                    ti_n = ti_n1;\n            }\n            if (ti >= clock_threshold && n >= min_n_argument)\n                break;\n\n            n = n * [ 2, 2.5, 2 ][i % 3];\n        }\n        // to use only the best timing from the last loop, uncomment below\n        //ti_n = ti / nb_its;\n    }\n    /* nano seconds per iteration */\n    log_one(text, n, ti_n * 1e9 / clocks_per_sec);\n}\n\nvar global_res; /* to be sure the code is not optimized */\n\nfunction empty_loop(n) {\n    var j;\n    for(j = 0; j < n; j++) {\n    }\n    return n;\n}\n\nfunction empty_down_loop(n) {\n    var j;\n    for(j = n; j > 0; j--) {\n    }\n    return n;\n}\n\nfunction empty_down_loop2(n) {\n    var j;\n    for(j = n; j --> 0;) {\n    }\n    return n;\n}\n\nfunction empty_do_loop(n) {\n    var j = n;\n    do { } while (--j > 0);\n    return n;\n}\n\nfunction date_now(n) {\n    var j;\n    for(j = 0; j < n; j++) {\n        Date.now();\n    }\n    return n;\n}\n\nfunction date_parse(n) {\n    var x0 = 0, dx = 0;\n    var j;\n    for(j = 0; j < n; j++) {\n        var x1 = x0 - x0 % 1000;\n        var x2 = -x0;\n        var x3 = -x1;\n        var d0 = new Date(x0);\n        var d1 = new Date(x1);\n        var d2 = new Date(x2);\n        var d3 = new Date(x3);\n        if (Date.parse(d0.toISOString()) != x0\n        ||  Date.parse(d1.toGMTString()) != x1\n        ||  Date.parse(d1.toString()) != x1\n        ||  Date.parse(d2.toISOString()) != x2\n        ||  Date.parse(d3.toGMTString()) != x3\n        ||  Date.parse(d3.toString()) != x3) {\n            console.log(\"Date.parse error for \" + x0);\n            return -1;\n        }\n        dx = (dx * 1.1 + 1) >> 0;\n        x0 = (x0 + dx) % 8.64e15;\n    }\n    return n * 6;\n}\n\nfunction prop_read(n)\n{\n    var obj, sum, j;\n    obj = {a: 1, b: 2, c:3, d:4 };\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += obj.a;\n        sum += obj.b;\n        sum += obj.c;\n        sum += obj.d;\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nfunction prop_write(n)\n{\n    var obj, j;\n    obj = {a: 1, b: 2, c:3, d:4 };\n    for(j = 0; j < n; j++) {\n        obj.a = j;\n        obj.b = j;\n        obj.c = j;\n        obj.d = j;\n    }\n    return n * 4;\n}\n\nfunction prop_update(n)\n{\n    var obj, j;\n    obj = {a: 1, b: 2, c:3, d:4 };\n    for(j = 0; j < n; j++) {\n        obj.a += j;\n        obj.b += j;\n        obj.c += j;\n        obj.d += j;\n    }\n    return n * 4;\n}\n\nfunction prop_create(n)\n{\n    var obj, i, j;\n    for(j = 0; j < n; j++) {\n        obj = {};\n        obj.a = 1;\n        obj.b = 2;\n        obj.c = 3;\n        obj.d = 4;\n        obj.e = 5;\n        obj.f = 6;\n        obj.g = 7;\n        obj.h = 8;\n        obj.i = 9;\n        obj.j = 10;\n        for(i = 0; i < 10; i++) {\n            obj[i] = i;\n        }\n    }\n    return n * 20;\n}\n\nfunction prop_clone(n)\n{\n    var ref, obj, j, k;\n    ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 };\n    for(k = 0; k < 10; k++) {\n        ref[k] = k;\n    }\n    for (j = 0; j < n; j++) {\n        global_res = { ...ref };\n    }\n    return n * 20;\n}\n\nfunction prop_delete(n)\n{\n    var ref, obj, j, k;\n    ref = { a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9, j:10 };\n    for(k = 0; k < 10; k++) {\n        ref[k] = k;\n    }\n    for (j = 0; j < n; j++) {\n        obj = { ...ref };\n        delete obj.a;\n        delete obj.b;\n        delete obj.c;\n        delete obj.d;\n        delete obj.e;\n        delete obj.f;\n        delete obj.g;\n        delete obj.h;\n        delete obj.i;\n        delete obj.j;\n        for(k = 0; k < 10; k++) {\n            delete obj[k];\n        }\n    }\n    return n * 20;\n}\n\nfunction array_read(n)\n{\n    var tab, len, sum, i, j;\n    tab = [];\n    len = 10;\n    for(i = 0; i < len; i++)\n        tab[i] = i;\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += tab[0];\n        sum += tab[1];\n        sum += tab[2];\n        sum += tab[3];\n        sum += tab[4];\n        sum += tab[5];\n        sum += tab[6];\n        sum += tab[7];\n        sum += tab[8];\n        sum += tab[9];\n    }\n    global_res = sum;\n    return len * n;\n}\n\nfunction array_write(n)\n{\n    var tab, len, i, j;\n    tab = [];\n    len = 10;\n    for(i = 0; i < len; i++)\n        tab[i] = i;\n    for(j = 0; j < n; j++) {\n        tab[0] = j;\n        tab[1] = j;\n        tab[2] = j;\n        tab[3] = j;\n        tab[4] = j;\n        tab[5] = j;\n        tab[6] = j;\n        tab[7] = j;\n        tab[8] = j;\n        tab[9] = j;\n    }\n    return len * n;\n}\n\nfunction array_update(n)\n{\n    var tab, len, i, j;\n    tab = [];\n    len = 10;\n    for(i = 0; i < len; i++)\n        tab[i] = i;\n    for(j = 0; j < n; j++) {\n        tab[0] += j;\n        tab[1] += j;\n        tab[2] += j;\n        tab[3] += j;\n        tab[4] += j;\n        tab[5] += j;\n        tab[6] += j;\n        tab[7] += j;\n        tab[8] += j;\n        tab[9] += j;\n    }\n    return len * n;\n}\n\nfunction array_prop_create(n)\n{\n    var tab, i, j, len;\n    len = 1000;\n    for(j = 0; j < n; j++) {\n        tab = [];\n        for(i = 0; i < len; i++)\n            tab[i] = i;\n    }\n    return len * n;\n}\n\nfunction array_slice(n)\n{\n    var ref, a, i, j, len;\n    len = 1000;\n    ref = [];\n    for(i = 0; i < len; i++)\n        ref[i] = i;\n    for(j = 0; j < n; j++) {\n        ref[0] = j;\n        a = ref.slice();\n        a[0] = 0;\n        global_res = a;\n    }\n    return len * n;\n}\n\nfunction array_length_read(n)\n{\n    var tab, sum, j;\n    tab = [1, 2, 3];\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += tab.length;\n        sum += tab.length;\n        sum += tab.length;\n        sum += tab.length;\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nfunction array_length_decr(n)\n{\n    var tab, ref, i, j, len;\n    len = 1000;\n    ref = [];\n    for(i = 0; i < len; i++)\n        ref[i] = i;\n    for(j = 0; j < n; j++) {\n        tab = ref.slice();\n        for(i = len; i --> 0;)\n            tab.length = i;\n    }\n    return len * n;\n}\n\nfunction array_hole_length_decr(n)\n{\n    var tab, ref, i, j, len;\n    len = 1000;\n    ref = [];\n    for(i = 0; i < len; i++) {\n        if (i % 10 == 9)\n            ref[i] = i;\n    }\n    for(j = 0; j < n; j++) {\n        tab = ref.slice();\n        for(i = len; i --> 0;)\n            tab.length = i;\n    }\n    return len * n;\n}\n\nfunction array_push(n)\n{\n    var tab, i, j, len;\n    len = 500;\n    for(j = 0; j < n; j++) {\n        tab = [];\n        for(i = 0; i < len; i++)\n            tab.push(i);\n    }\n    return len * n;\n}\n\nfunction array_pop(n)\n{\n    var tab, ref, i, j, len, sum;\n    len = 500;\n    ref = [];\n    for(i = 0; i < len; i++)\n        ref[i] = i;\n    for(j = 0; j < n; j++) {\n        tab = ref.slice();\n        sum = 0;\n        for(i = 0; i < len; i++)\n            sum += tab.pop();\n        global_res = sum;\n    }\n    return len * n;\n}\n\nfunction typed_array_read(n)\n{\n    var tab, len, sum, i, j;\n    len = 10;\n    tab = new Int32Array(len);\n    for(i = 0; i < len; i++)\n        tab[i] = i;\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += tab[0];\n        sum += tab[1];\n        sum += tab[2];\n        sum += tab[3];\n        sum += tab[4];\n        sum += tab[5];\n        sum += tab[6];\n        sum += tab[7];\n        sum += tab[8];\n        sum += tab[9];\n    }\n    global_res = sum;\n    return len * n;\n}\n\nfunction typed_array_write(n)\n{\n    var tab, len, i, j;\n    len = 10;\n    tab = new Int32Array(len);\n    for(i = 0; i < len; i++)\n        tab[i] = i;\n    for(j = 0; j < n; j++) {\n        tab[0] = j;\n        tab[1] = j;\n        tab[2] = j;\n        tab[3] = j;\n        tab[4] = j;\n        tab[5] = j;\n        tab[6] = j;\n        tab[7] = j;\n        tab[8] = j;\n        tab[9] = j;\n    }\n    return len * n;\n}\n\nfunction arguments_test()\n{\n    return arguments[0] + arguments[1] + arguments[2];\n}\n\nfunction arguments_read(n)\n{\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += arguments_test(j, j, j);\n        sum += arguments_test(j, j, j);\n        sum += arguments_test(j, j, j);\n        sum += arguments_test(j, j, j);\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nfunction arguments_strict_test()\n{\n    \"use strict\";\n    return arguments[0] + arguments[1] + arguments[2];\n}\n\nfunction arguments_strict_read(n)\n{\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += arguments_strict_test(j, j, j);\n        sum += arguments_strict_test(j, j, j);\n        sum += arguments_strict_test(j, j, j);\n        sum += arguments_strict_test(j, j, j);\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nvar global_var0;\n\nfunction global_read(n)\n{\n    var sum, j;\n    global_var0 = 0;\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += global_var0;\n        sum += global_var0;\n        sum += global_var0;\n        sum += global_var0;\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nfunction global_write(n)\n{\n    var j;\n    for(j = 0; j < n; j++) {\n        global_var0 = j;\n        global_var0 = j;\n        global_var0 = j;\n        global_var0 = j;\n    }\n    return n * 4;\n}\n\nfunction global_write_strict(n)\n{\n    \"use strict\";\n    var j;\n    for(j = 0; j < n; j++) {\n        global_var0 = j;\n        global_var0 = j;\n        global_var0 = j;\n        global_var0 = j;\n    }\n    return n * 4;\n}\n\nfunction local_destruct(n)\n{\n    var j, v1, v2, v3, v4;\n    var array = [ 1, 2, 3, 4, 5];\n    var o = { a:1, b:2, c:3, d:4 };\n    var a, b, c, d;\n    for(j = 0; j < n; j++) {\n        [ v1, v2,, v3, ...v4] = array;\n        ({ a, b, c, d } = o);\n        ({ a: a, b: b, c: c, d: d } = o);\n    }\n    return n * 12;\n}\n\nvar global_v1, global_v2, global_v3, global_v4;\nvar global_a, global_b, global_c, global_d;\n\nfunction global_destruct(n)\n{\n    var j, v1, v2, v3, v4;\n    var array = [ 1, 2, 3, 4, 5 ];\n    var o = { a:1, b:2, c:3, d:4 };\n    var a, b, c, d;\n    for(j = 0; j < n; j++) {\n        [ global_v1, global_v2,, global_v3, ...global_v4] = array;\n        ({ a: global_a, b: global_b, c: global_c, d: global_d } = o);\n    }\n    return n * 8;\n}\n\nfunction global_destruct_strict(n)\n{\n    \"use strict\";\n    var j, v1, v2, v3, v4;\n    var array = [ 1, 2, 3, 4, 5 ];\n    var o = { a:1, b:2, c:3, d:4 };\n    var a, b, c, d;\n    for(j = 0; j < n; j++) {\n        [ global_v1, global_v2,, global_v3, ...global_v4] = array;\n        ({ a: global_a, b: global_b, c: global_c, d: global_d } = o);\n    }\n    return n * 8;\n}\n\nfunction g(a)\n{\n    return 1;\n}\n\nfunction global_func_call(n)\n{\n    var j, sum;\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += g(j);\n        sum += g(j);\n        sum += g(j);\n        sum += g(j);\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nfunction func_call(n)\n{\n    function f(a)\n    {\n        return 1;\n    }\n\n    var j, sum;\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += f(j);\n        sum += f(j);\n        sum += f(j);\n        sum += f(j);\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nfunction func_closure_call(n)\n{\n    function f(a)\n    {\n        sum++;\n    }\n\n    var j, sum;\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        f(j);\n        f(j);\n        f(j);\n        f(j);\n    }\n    global_res = sum;\n    return n * 4;\n}\n\nfunction int_arith(n)\n{\n    var i, j, sum;\n    global_res = 0;\n    for(j = 0; j < n; j++) {\n        sum = 0;\n        for(i = 0; i < 1000; i++) {\n            sum += i * i;\n        }\n        global_res += sum;\n    }\n    return n * 1000;\n}\n\nfunction float_arith(n)\n{\n    var i, j, sum, a, incr, a0;\n    global_res = 0;\n    a0 = 0.1;\n    incr = 1.1;\n    for(j = 0; j < n; j++) {\n        sum = 0;\n        a = a0;\n        for(i = 0; i < 1000; i++) {\n            sum += a * a;\n            a += incr;\n        }\n        global_res += sum;\n    }\n    return n * 1000;\n}\n\nfunction bigint_arith(n, bits)\n{\n    var i, j, sum, a, incr, a0, sum0;\n    sum0 = global_res = BigInt(0);\n    a0 = BigInt(1) << BigInt(Math.floor((bits - 10) * 0.5));\n    incr = BigInt(1);\n    for(j = 0; j < n; j++) {\n        sum = sum0;\n        a = a0;\n        for(i = 0; i < 1000; i++) {\n            sum += a * a;\n            a += incr;\n        }\n        global_res += sum;\n    }\n    return n * 1000;\n}\n\nfunction bigint32_arith(n)\n{\n    return bigint_arith(n, 32);\n}\n\nfunction bigint64_arith(n)\n{\n    return bigint_arith(n, 64);\n}\n\nfunction bigint256_arith(n)\n{\n    return bigint_arith(n, 256);\n}\n\nfunction map_set_string(n)\n{\n    var s, i, j, len = 1000;\n    for(j = 0; j < n; j++) {\n        s = new Map();\n        for(i = 0; i < len; i++) {\n            s.set(String(i), i);\n        }\n        for(i = 0; i < len; i++) {\n            if (!s.has(String(i)))\n                throw Error(\"bug in Map\");\n        }\n    }\n    return n * len;\n}\n\nfunction map_set_int(n)\n{\n    var s, i, j, len = 1000;\n    for(j = 0; j < n; j++) {\n        s = new Map();\n        for(i = 0; i < len; i++) {\n            s.set(i, i);\n        }\n        for(i = 0; i < len; i++) {\n            if (!s.has(i))\n                throw Error(\"bug in Map\");\n        }\n    }\n    return n * len;\n}\n\nfunction map_set_bigint(n)\n{\n    var s, i, j, len = 1000;\n    for(j = 0; j < n; j++) {\n        s = new Map();\n        for(i = 0; i < len; i++) {\n            s.set(BigInt(i), i);\n        }\n        for(i = 0; i < len; i++) {\n            if (!s.has(BigInt(i)))\n                throw Error(\"bug in Map\");\n        }\n    }\n    return n * len;\n}\n\nfunction map_delete(n)\n{\n    var a, i, j;\n\n    len = 1000;\n    for(j = 0; j < n; j++) {\n        a = new Map();\n        for(i = 0; i < len; i++) {\n            a.set(String(i), i);\n        }\n        for(i = 0; i < len; i++) {\n            a.delete(String(i));\n        }\n    }\n    return len * n;\n}\n\nfunction weak_map_set(n)\n{\n    var a, i, j, tab;\n\n    len = 1000;\n    tab = [];\n    for(i = 0; i < len; i++) {\n        tab.push({ key: i });\n    }\n    for(j = 0; j < n; j++) {\n        a = new WeakMap();\n        for(i = 0; i < len; i++) {\n            a.set(tab[i], i);\n        }\n    }\n    return len * n;\n}\n\nfunction weak_map_delete(n)\n{\n    var a, i, j, tab;\n\n    len = 1000;\n    for(j = 0; j < n; j++) {\n        tab = [];\n        for(i = 0; i < len; i++) {\n            tab.push({ key: i });\n        }\n        a = new WeakMap();\n        for(i = 0; i < len; i++) {\n            a.set(tab[i], i);\n        }\n        for(i = 0; i < len; i++) {\n            tab[i] = null;\n        }\n    }\n    return len * n;\n}\n\n\nfunction array_for(n)\n{\n    var r, i, j, sum, len = 100;\n    r = [];\n    for(i = 0; i < len; i++)\n        r[i] = i;\n    for(j = 0; j < n; j++) {\n        sum = 0;\n        for(i = 0; i < len; i++) {\n            sum += r[i];\n        }\n        global_res = sum;\n    }\n    return n * len;\n}\n\nfunction array_for_in(n)\n{\n    var r, i, j, sum, len = 100;\n    r = [];\n    for(i = 0; i < len; i++)\n        r[i] = i;\n    for(j = 0; j < n; j++) {\n        sum = 0;\n        for(i in r) {\n            sum += r[i];\n        }\n        global_res = sum;\n    }\n    return n * len;\n}\n\nfunction array_for_of(n)\n{\n    var r, i, j, sum, len = 100;\n    r = [];\n    for(i = 0; i < len; i++)\n        r[i] = i;\n    for(j = 0; j < n; j++) {\n        sum = 0;\n        for(i of r) {\n            sum += i;\n        }\n        global_res = sum;\n    }\n    return n * len;\n}\n\nfunction math_min(n)\n{\n    var i, j, r;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        for(i = 0; i < 1000; i++)\n            r = Math.min(i, 500);\n        global_res = r;\n    }\n    return n * 1000;\n}\n\nfunction regexp_ascii(n)\n{\n    var i, j, r, s;\n    s = \"the quick brown fox jumped over the lazy dog\"\n    for(j = 0; j < n; j++) {\n        for(i = 0; i < 1000; i++)\n            r = /the quick brown fox/.exec(s)\n        global_res = r;\n    }\n    return n * 1000;\n}\n\nfunction regexp_utf16(n)\n{\n    var i, j, r, s;\n    s = \"the quick brown ᶠᵒˣ jumped over the lazy ᵈᵒᵍ\"\n    for(j = 0; j < n; j++) {\n        for(i = 0; i < 1000; i++)\n            r = /the quick brown ᶠᵒˣ/.exec(s)\n        global_res = r;\n    }\n    return n * 1000;\n}\n\nfunction regexp_replace(n)\n{\n    var i, j, r, s;\n    s = \"the quick abc brown fox jumped abc over the lazy dog\"\n    for(j = 0; j < n; j++) {\n        for(i = 0; i < 1000; i++)\n            r = s.replace(/abc /g, \"-\");\n        global_res = r;\n    }\n    return n * 1000;\n}\n\nfunction string_length(n)\n{\n    var str, sum, j;\n    str = \"abcde\";\n    sum = 0;\n    for(j = 0; j < n; j++) {\n        sum += str.length;\n        sum += str.length;\n        sum += str.length;\n        sum += str.length;\n    }\n    global_res = sum;\n    return n * 4;\n}\n\n/* incremental string contruction as local var */\nfunction string_build1(n)\n{\n    var i, j, r;\n    for(j = 0; j < n; j++) {\n        r = \"\";\n        for(i = 0; i < 1000; i++)\n            r += \"x\";\n        global_res = r;\n    }\n    return n * 1000;\n}\n\n/* incremental string contruction using + */\nfunction string_build1x(n)\n{\n    var i, j, r;\n    for(j = 0; j < n; j++) {\n        r = \"\";\n        for(i = 0; i < 1000; i++)\n            r = r + \"x\";\n        global_res = r;\n    }\n    return n * 1000;\n}\n\n/* incremental string contruction using +2c */\nfunction string_build2c(n)\n{\n    var i, j;\n    for(j = 0; j < n; j++) {\n        var r = \"\";\n        for(i = 0; i < 1000; i++)\n            r += \"xy\";\n        global_res = r;\n    }\n    return n * 1000;\n}\n\n/* incremental string contruction as arg */\nfunction string_build2(n, r)\n{\n    var i, j;\n    for(j = 0; j < n; j++) {\n        r = \"\";\n        for(i = 0; i < 1000; i++)\n            r += \"x\";\n        global_res = r;\n    }\n    return n * 1000;\n}\n\n/* incremental string contruction by prepending */\nfunction string_build3(n)\n{\n    var i, j, r;\n    for(j = 0; j < n; j++) {\n        r = \"\";\n        for(i = 0; i < 1000; i++)\n            r = \"x\" + r;\n        global_res = r;\n    }\n    return n * 1000;\n}\n\n/* incremental string contruction with multiple reference */\nfunction string_build4(n)\n{\n    var i, j, r, s;\n    for(j = 0; j < n; j++) {\n        r = \"\";\n        for(i = 0; i < 1000; i++) {\n            s = r;\n            r += \"x\";\n        }\n        global_res = r;\n    }\n    return n * 1000;\n}\n\n/* append */\nfunction string_build_large1(n)\n{\n    var i, j, r, len = 20000;\n    for(j = 0; j < n; j++) {\n        r = \"\";\n        for(i = 0; i < len; i++)\n            r += \"abcdef\";\n        global_res = r;\n    }\n    return n * len;\n}\n\n/* prepend */\nfunction string_build_large2(n)\n{\n    var i, j, r, len = 20000;\n    for(j = 0; j < n; j++) {\n        r = \"\";\n        for(i = 0; i < len; i++)\n            r = \"abcdef\" + r;\n        global_res = r;\n    }\n    return n * len;\n}\n\n/* sort bench */\n\nfunction sort_bench(text) {\n    function random(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[(Math.random() * n) >> 0];\n    }\n    function random8(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[(Math.random() * 256) >> 0];\n    }\n    function random1(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[(Math.random() * 2) >> 0];\n    }\n    function hill(arr, n, def) {\n        var mid = n >> 1;\n        for (var i = 0; i < mid; i++)\n            arr[i] = def[i];\n        for (var i = mid; i < n; i++)\n            arr[i] = def[n - i];\n    }\n    function comb(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[(i & 1) * i];\n    }\n    function crisscross(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[(i & 1) ? n - i : i];\n    }\n    function zero(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[0];\n    }\n    function increasing(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[i];\n    }\n    function decreasing(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[n - 1 - i];\n    }\n    function alternate(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[i ^ 1];\n    }\n    function jigsaw(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[i % (n >> 4)];\n    }\n    function incbutone(arr, n, def) {\n        for (var i = 0; i < n; i++)\n            arr[i] = def[i];\n        if (n > 0)\n            arr[n >> 2] = def[n];\n    }\n    function incbutfirst(arr, n, def) {\n        if (n > 0)\n            arr[0] = def[n];\n        for (var i = 1; i < n; i++)\n            arr[i] = def[i];\n    }\n    function incbutlast(arr, n, def) {\n        for (var i = 0; i < n - 1; i++)\n            arr[i] = def[i + 1];\n        if (n > 0)\n            arr[n - 1] = def[0];\n    }\n\n    var sort_cases = [ random, random8, random1, jigsaw, hill, comb,\n                      crisscross, zero, increasing, decreasing, alternate,\n                      incbutone, incbutlast, incbutfirst ];\n\n    var n = sort_bench.array_size || 10000;\n    var array_type = sort_bench.array_type || Array;\n    var def, arr;\n    var i, j, x, y;\n    var total = 0;\n\n    var save_total_score = total_score;\n    var save_total_scale = total_scale;\n\n    // initialize default sorted array (n + 1 elements)\n    def = new array_type(n + 1);\n    if (array_type == Array) {\n        for (i = 0; i <= n; i++) {\n            def[i] = i + \"\";\n        }\n    } else {\n        for (i = 0; i <= n; i++) {\n            def[i] = i;\n        }\n    }\n    def.sort();\n    for (var f of sort_cases) {\n        var ti = 0, tx = 0;\n        for (j = 0; j < 100; j++) {\n            arr = new array_type(n);\n            f(arr, n, def);\n            var t1 = get_clock();\n            arr.sort();\n            t1 = get_clock() - t1;\n            tx += t1;\n            if (!ti || ti > t1)\n                ti = t1;\n            if (tx >= clocks_per_sec)\n                break;\n        }\n        total += ti;\n\n        i = 0;\n        x = arr[0];\n        if (x !== void 0) {\n            for (i = 1; i < n; i++) {\n                y = arr[i];\n                if (y === void 0)\n                    break;\n                if (x > y)\n                    break;\n                x = y;\n            }\n        }\n        while (i < n && arr[i] === void 0)\n            i++;\n        if (i < n) {\n            console.log(\"sort_bench: out of order error for \" + f.name +\n                        \" at offset \" + (i - 1) +\n                        \": \" + arr[i - 1] + \" > \" + arr[i]);\n        }\n        if (sort_bench.verbose)\n            log_one(\"sort_\" + f.name, 1, ti / 100);\n    }\n    total_score = save_total_score;\n    total_scale = save_total_scale;\n    return total / n / 100;\n}\nsort_bench.bench = true;\nsort_bench.verbose = false;\n\nfunction int_to_string(n)\n{\n    var s, r, j;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        s = (j % 10) + '';\n        s = (j % 100) + '';\n        s = (j) + '';\n    }\n    return n * 3;\n}\n\nfunction int_toString(n)\n{\n    var s, r, j;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        s = (j % 10).toString();\n        s = (j % 100).toString();\n        s = (j).toString();\n    }\n    return n * 3;\n}\n\nfunction float_to_string(n)\n{\n    var s, r, j;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        s = (j % 10 + 0.1) + '';\n        s = (j + 0.1) + '';\n        s = (j * 12345678 + 0.1) + '';\n    }\n    return n * 3;\n}\n\nfunction float_toString(n)\n{\n    var s, r, j;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        s = (j % 10 + 0.1).toString();\n        s = (j + 0.1).toString();\n        s = (j * 12345678 + 0.1).toString();\n    }\n    return n * 3;\n}\n\nfunction float_toFixed(n)\n{\n    var s, r, j;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        s = (j % 10 + 0.1).toFixed(j % 16);\n        s = (j + 0.1).toFixed(j % 16);\n        s = (j * 12345678 + 0.1).toFixed(j % 16);\n    }\n    return n * 3;\n}\n\nfunction float_toPrecision(n)\n{\n    var s, r, j;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        s = (j % 10 + 0.1).toPrecision(j % 16 + 1);\n        s = (j + 0.1).toPrecision(j % 16 + 1);\n        s = (j * 12345678 + 0.1).toPrecision(j % 16 + 1);\n    }\n    return n * 3;\n}\n\nfunction float_toExponential(n)\n{\n    var s, r, j;\n    r = 0;\n    for(j = 0; j < n; j++) {\n        s = (j % 10 + 0.1).toExponential(j % 16);\n        s = (j + 0.1).toExponential(j % 16);\n        s = (j * 12345678 + 0.1).toExponential(j % 16);\n    }\n    return n * 3;\n}\n\nfunction string_to_int(n)\n{\n    var s, r, j;\n    r = 0;\n    s = \"12345\";\n    for(j = 0; j < n; j++) {\n        r += (s | 0);\n    }\n    global_res = r;\n    return n;\n}\n\nfunction string_to_float(n)\n{\n    var s, r, j;\n    r = 0;\n    s = \"12345.6\";\n    for(j = 0; j < n; j++) {\n        r -= s;\n    }\n    global_res = r;\n    return n;\n}\n\nfunction load_result(filename)\n{\n    var has_filename = filename;\n    var has_error = false;\n    var str, res;\n\n    if (!filename)\n        filename = \"microbench.txt\";\n\n    if (typeof fs !== \"undefined\") {\n        // read the file in Node.js\n        try {\n            str = fs.readFileSync(filename, { encoding: \"utf8\" });\n        } catch {\n            has_error = true;\n        }\n    } else\n    if (typeof std !== \"undefined\") {\n        // read the file in QuickJS\n        var f = std.open(filename, \"r\");\n        if (f) {\n            str = f.readAsString();\n            f.close();\n        } else {\n            has_error = true;\n        }\n    } else {\n        return null;\n    }\n    if (has_error) {\n        if (has_filename) {\n            // Should throw exception?\n            console.log(\"cannot load \" + filename);\n        }\n        return null;\n    }\n    res = JSON.parse(str);\n    return res;\n}\n\nfunction save_result(filename, obj)\n{\n    var str = JSON.stringify(obj, null, 2) + \"\\n\";\n    var has_error = false;\n\n    if (typeof fs !== \"undefined\") {\n        // save the file in Node.js\n        try {\n            str = fs.writeFileSync(filename, str, { encoding: \"utf8\" });\n        } catch {\n            has_error = true;\n        }\n    } else\n    if (typeof std !== \"undefined\") {\n        // save the file in QuickJS\n        var f = std.open(filename, \"w\");\n        if (f) {\n            f.puts(str);\n            f.close();\n        } else {\n            has_error = 'true';\n        }\n    } else {\n        return;\n    }\n    if (has_error)\n        console.log(\"cannot save \" + filename);\n}\n\nfunction main(argc, argv, g)\n{\n    var test_list = [\n        empty_loop,\n        empty_down_loop,\n        empty_down_loop2,\n        empty_do_loop,\n        date_now,\n        date_parse,\n        prop_read,\n        prop_write,\n        prop_update,\n        prop_create,\n        prop_clone,\n        prop_delete,\n        array_read,\n        array_write,\n        array_update,\n        array_prop_create,\n        array_slice,\n        array_length_read,\n        array_length_decr,\n        array_hole_length_decr,\n        array_push,\n        array_pop,\n        typed_array_read,\n        typed_array_write,\n        arguments_read,\n        arguments_strict_read,\n        global_read,\n        global_write,\n        global_write_strict,\n        local_destruct,\n        global_destruct,\n        global_destruct_strict,\n        global_func_call,\n        func_call,\n        func_closure_call,\n        int_arith,\n        float_arith,\n        map_set_string,\n        map_set_int,\n        map_set_bigint,\n        map_delete,\n        weak_map_set,\n        weak_map_delete,\n        array_for,\n        array_for_in,\n        array_for_of,\n        math_min,\n        regexp_ascii,\n        regexp_utf16,\n        regexp_replace,\n        string_length,\n        string_build1,\n        string_build1x,\n        string_build2c,\n        string_build2,\n        string_build3,\n        string_build4,\n        string_build_large1,\n        string_build_large2,\n        int_to_string,\n        int_toString,\n        float_to_string,\n        float_toString,\n        float_toFixed,\n        float_toPrecision,\n        float_toExponential,\n        string_to_int,\n        string_to_float,\n    ];\n    var tests = [];\n    var i, j, n, f, name, found;\n    var ref_file, new_ref_file = \"microbench-new.txt\";\n\n    if (typeof BigInt === \"function\") {\n        /* BigInt test */\n        test_list.push(bigint32_arith);\n        test_list.push(bigint64_arith);\n        test_list.push(bigint256_arith);\n    }\n    test_list.push(sort_bench);\n\n    for (i = 1; i < argc;) {\n        name = argv[i++];\n        if (name == \"-a\") {\n            sort_bench.verbose = true;\n            continue;\n        }\n        if (name == \"-t\") {\n            name = argv[i++];\n            sort_bench.array_type = g[name];\n            if (typeof sort_bench.array_type !== \"function\") {\n                console.log(\"unknown array type: \" + name);\n                return 1;\n            }\n            continue;\n        }\n        if (name == \"-n\") {\n            sort_bench.array_size = +argv[i++];\n            continue;\n        }\n        if (name == \"-r\") {\n            ref_file = argv[i++];\n            continue;\n        }\n        if (name == \"-s\") {\n            new_ref_file = argv[i++];\n            continue;\n        }\n        for (j = 0, found = false; j < test_list.length; j++) {\n            f = test_list[j];\n            if (f.name.startsWith(name)) {\n                tests.push(f);\n                found = true;\n            }\n        }\n        if (!found) {\n            console.log(\"unknown benchmark: \" + name);\n            return 1;\n        }\n    }\n    if (tests.length == 0)\n        tests = test_list;\n\n    ref_data = load_result(ref_file);\n    log_data = {};\n    log_line.apply(null, heads);\n    n = 0;\n\n    for(i = 0; i < tests.length; i++) {\n        f = tests[i];\n        bench(f, f.name, ref_data, log_data);\n        if (ref_data && ref_data[f.name])\n            n++;\n    }\n    if (ref_data)\n        log_line(\"total\", \"\", total[2], total[3], Math.round(total_scale * 1000 / total_score));\n    else\n        log_line(\"total\", \"\", total[2]);\n\n    if (tests == test_list && new_ref_file)\n        save_result(new_ref_file, log_data);\n}\n\nif (typeof scriptArgs === \"undefined\") {\n    scriptArgs = [];\n    if (typeof process.argv === \"object\")\n        scriptArgs = process.argv.slice(1);\n}\nmain(scriptArgs.length, scriptArgs, this);\n"
  },
  {
    "path": "tests/test262.patch",
    "content": "diff --git a/harness/atomicsHelper.js b/harness/atomicsHelper.js\nindex 9828b15..9e24d64 100644\n--- a/harness/atomicsHelper.js\n+++ b/harness/atomicsHelper.js\n@@ -272,10 +272,14 @@ $262.agent.waitUntil = function(typedArray, index, expected) {\n  *   }\n  */\n $262.agent.timeouts = {\n-  yield: 100,\n-  small: 200,\n-  long: 1000,\n-  huge: 10000,\n+//  yield: 100,\n+//  small: 200,\n+//  long: 1000,\n+//  huge: 10000,\n+  yield: 40,\n+  small: 40,\n+  long: 200,\n+  huge: 1000,\n };\n \n /**\ndiff --git a/harness/regExpUtils.js b/harness/regExpUtils.js\nindex b397be0..c197ddc 100644\n--- a/harness/regExpUtils.js\n+++ b/harness/regExpUtils.js\n@@ -6,27 +6,30 @@ description: |\n defines: [buildString, testPropertyEscapes, testPropertyOfStrings, testExtendedCharacterClass, matchValidator]\n ---*/\n \n+if ($262 && typeof $262.codePointRange === \"function\") {\n+    /* use C function to build the codePointRange (much faster with\n+       slow JS engines) */\n+    codePointRange = $262.codePointRange;\n+} else {\n+    codePointRange = function codePointRange(start, end) {\n+        const codePoints = [];\n+        let length = 0;\n+        for (codePoint = start; codePoint < end; codePoint++) {\n+            codePoints[length++] = codePoint;\n+        }\n+        return String.fromCodePoint.apply(null, codePoints);\n+    }\n+}\n+\n function buildString(args) {\n   // Use member expressions rather than destructuring `args` for improved\n   // compatibility with engines that only implement assignment patterns\n   // partially or not at all.\n   const loneCodePoints = args.loneCodePoints;\n   const ranges = args.ranges;\n-  const CHUNK_SIZE = 10000;\n   let result = String.fromCodePoint.apply(null, loneCodePoints);\n-  for (let i = 0; i < ranges.length; i++) {\n-    let range = ranges[i];\n-    let start = range[0];\n-    let end = range[1];\n-    let codePoints = [];\n-    for (let length = 0, codePoint = start; codePoint <= end; codePoint++) {\n-      codePoints[length++] = codePoint;\n-      if (length === CHUNK_SIZE) {\n-        result += String.fromCodePoint.apply(null, codePoints);\n-        codePoints.length = length = 0;\n-      }\n-    }\n-    result += String.fromCodePoint.apply(null, codePoints);\n+  for (const [start, end] of ranges) {\n+    result += codePointRange(start, end + 1);\n   }\n   return result;\n }\n"
  },
  {
    "path": "tests/test_bigint.js",
    "content": "\"use strict\";\n\nfunction assert(actual, expected, message) {\n    if (arguments.length == 1)\n        expected = true;\n\n    if (actual === expected)\n        return;\n\n    if (actual !== null && expected !== null\n    &&  typeof actual == 'object' && typeof expected == 'object'\n    &&  actual.toString() === expected.toString())\n        return;\n\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\nfunction assertThrows(err, func)\n{\n    var ex;\n    ex = false;\n    try {\n        func();\n    } catch(e) {\n        ex = true;\n        assert(e instanceof err);\n    }\n    assert(ex, true, \"exception expected\");\n}\n\n// load more elaborate version of assert if available\ntry { __loadScript(\"test_assert.js\"); } catch(e) {}\n\n/*----------------*/\n\nfunction bigint_pow(a, n)\n{\n    var r, i;\n    r = 1n;\n    for(i = 0n; i < n; i++)\n        r *= a;\n    return r;\n}\n\n/* a must be < b */\nfunction test_less(a, b)\n{\n    assert(a < b);\n    assert(!(b < a));\n    assert(a <= b);\n    assert(!(b <= a));\n    assert(b > a);\n    assert(!(a > b));\n    assert(b >= a);\n    assert(!(a >= b));\n    assert(a != b);\n    assert(!(a == b));\n}\n\n/* a must be numerically equal to b */\nfunction test_eq(a, b)\n{\n    assert(a == b);\n    assert(b == a);\n    assert(!(a != b));\n    assert(!(b != a));\n    assert(a <= b);\n    assert(b <= a);\n    assert(!(a < b));\n    assert(a >= b);\n    assert(b >= a);\n    assert(!(a > b));\n}\n\nfunction test_bigint1()\n{\n    var a, r;\n\n    test_less(2n, 3n);\n    test_eq(3n, 3n);\n\n    test_less(2, 3n);\n    test_eq(3, 3n);\n\n    test_less(2.1, 3n);\n    test_eq(Math.sqrt(4), 2n);\n\n    a = bigint_pow(3n, 100n);\n    assert((a - 1n) != a);\n    assert(a == 515377520732011331036461129765621272702107522001n);\n    assert(a == 0x5a4653ca673768565b41f775d6947d55cf3813d1n);\n\n    r = 1n << 31n;\n    assert(r, 2147483648n, \"1 << 31n === 2147483648n\");\n\n    r = 1n << 32n;\n    assert(r, 4294967296n, \"1 << 32n === 4294967296n\");\n}\n\nfunction test_bigint2()\n{\n    assert(BigInt(\"\"), 0n);\n    assert(BigInt(\"  123\"), 123n);\n    assert(BigInt(\"  123   \"), 123n);\n    assertThrows(SyntaxError, () => { BigInt(\"+\") } );\n    assertThrows(SyntaxError, () => { BigInt(\"-\") } );\n    assertThrows(SyntaxError, () => { BigInt(\"\\x00a\") } );\n    assertThrows(SyntaxError, () => { BigInt(\"  123  r\") } );\n}\n\nfunction test_bigint3()\n{\n    assert(Number(0xffffffffffffffffn), 18446744073709552000);\n    assert(Number(-0xffffffffffffffffn), -18446744073709552000);\n    assert(100000000000000000000n == 1e20, true);\n    assert(100000000000000000001n == 1e20, false);\n    assert((1n << 100n).toString(10), \"1267650600228229401496703205376\");\n    assert((-1n << 100n).toString(36), \"-3ewfdnca0n6ld1ggvfgg\");\n    assert((1n << 100n).toString(8), \"2000000000000000000000000000000000\");\n\n    assert(0x5a4653ca673768565b41f775n << 78n, 8443945299673273647701379149826607537748959488376832n);\n    assert(-0x5a4653ca673768565b41f775n << 78n, -8443945299673273647701379149826607537748959488376832n);\n    assert(0x5a4653ca673768565b41f775n >> 78n, 92441n);\n    assert(-0x5a4653ca673768565b41f775n >> 78n, -92442n);\n\n    assert(~0x5a653ca6n, -1516584103n);\n    assert(0x5a463ca6n | 0x67376856n, 2138537206n);\n    assert(0x5a463ca6n & 0x67376856n, 1107699718n);\n    assert(0x5a463ca6n ^ 0x67376856n, 1030837488n);\n\n    assert(3213213213213213432453243n / 123434343439n, 26031760073331n);\n    assert(-3213213213213213432453243n / 123434343439n, -26031760073331n);\n    assert(-3213213213213213432453243n % -123434343439n, -26953727934n);\n    assert(3213213213213213432453243n % 123434343439n, 26953727934n);\n\n    assert((-2n) ** 127n, -170141183460469231731687303715884105728n);\n    assert((2n) ** 127n, 170141183460469231731687303715884105728n);\n    assert((-256n) ** 11n, -309485009821345068724781056n);\n    assert((7n) ** 20n, 79792266297612001n);\n}\n\n/* pi computation */\n\n/* return floor(log2(a)) for a > 0 and 0 for a = 0 */\nfunction floor_log2(a)\n{\n    var k_max, a1, k, i;\n    k_max = 0n;\n    while ((a >> (2n ** k_max)) != 0n) {\n        k_max++;\n    }\n    k = 0n;\n    a1 = a;\n    for(i = k_max - 1n; i >= 0n; i--) {\n        a1 = a >> (2n ** i);\n        if (a1 != 0n) {\n            a = a1;\n            k |= (1n << i);\n        }\n    }\n    return k;\n}\n\n/* return ceil(log2(a)) for a > 0 */\nfunction ceil_log2(a)\n{\n    return floor_log2(a - 1n) + 1n;\n}\n\n/* return floor(sqrt(a)) (not efficient but simple) */\nfunction int_sqrt(a)\n{\n    var l, u, s;\n    if (a == 0n)\n        return a;\n    l = ceil_log2(a);\n    u = 1n << ((l + 1n) / 2n);\n    /* u >= floor(sqrt(a)) */\n    for(;;) {\n        s = u;\n        u = ((a / s) + s) / 2n;\n        if (u >= s)\n            break;\n    }\n    return s;\n}\n\n/* return pi * 2**prec */\nfunction calc_pi(prec) {\n    const CHUD_A = 13591409n;\n    const CHUD_B = 545140134n;\n    const CHUD_C = 640320n;\n    const CHUD_C3 = 10939058860032000n; /* C^3/24 */\n    const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */\n\n    /* return [P, Q, G] */\n    function chud_bs(a, b, need_G) {\n        var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;\n        if (a == (b - 1n)) {\n            G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);\n            P = G * (CHUD_B * b + CHUD_A);\n            if (b & 1n)\n                P = -P;\n            Q = b * b * b * CHUD_C3;\n        } else {\n            c = (a + b) >> 1n;\n            [P1, Q1, G1] = chud_bs(a, c, true);\n            [P2, Q2, G2] = chud_bs(c, b, need_G);\n            P = P1 * Q2 + P2 * G1;\n            Q = Q1 * Q2;\n            if (need_G)\n                G = G1 * G2;\n            else\n                G = 0n;\n        }\n        return [P, Q, G];\n    }\n\n    var n, P, Q, G;\n    /* number of serie terms */\n    n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;\n    [P, Q, G] = chud_bs(0n, n, false);\n    Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);\n    G = int_sqrt(CHUD_C << (2n * prec));\n    return (Q * G) >> prec;\n}\n\nfunction compute_pi(n_digits) {\n    var r, n_digits, n_bits, out;\n    /* we add more bits to reduce the probability of bad rounding for\n      the last digits */\n    n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;\n    r = calc_pi(n_bits);\n    r = ((10n ** BigInt(n_digits)) * r) >> n_bits;\n    out = r.toString();\n    return out[0] + \".\" + out.slice(1);\n}\n\nfunction test_pi()\n{\n    assert(compute_pi(2000), \"3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009\");\n}\n\ntest_bigint1();\ntest_bigint2();\ntest_bigint3();\ntest_pi();\n"
  },
  {
    "path": "tests/test_bjson.js",
    "content": "import * as bjson from \"./bjson.so\";\n\nfunction assert(actual, expected, message) {\n    if (arguments.length == 1)\n        expected = true;\n\n    if (actual === expected)\n        return;\n\n    if (actual !== null && expected !== null\n    &&  typeof actual == 'object' && typeof expected == 'object'\n    &&  actual.toString() === expected.toString())\n        return;\n\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\nfunction toHex(a)\n{\n    var i, s = \"\", tab, v;\n    tab = new Uint8Array(a);\n    for(i = 0; i < tab.length; i++) {\n        v = tab[i].toString(16);\n        if (v.length < 2)\n            v = \"0\" + v;\n        if (i !== 0)\n            s += \" \";\n        s += v;\n    }\n    return s;\n}\n\nfunction isArrayLike(a)\n{\n    return Array.isArray(a) ||\n        (a instanceof Uint8ClampedArray) ||\n        (a instanceof Uint8Array) ||\n        (a instanceof Uint16Array) ||\n        (a instanceof Uint32Array) ||\n        (a instanceof Int8Array) ||\n        (a instanceof Int16Array) ||\n        (a instanceof Int32Array) ||\n        (a instanceof Float16Array) ||\n        (a instanceof Float32Array) ||\n        (a instanceof Float64Array);\n}\n\nfunction toStr(a)\n{\n    var s, i, props, prop;\n\n    switch(typeof(a)) {\n    case \"object\":\n        if (a === null)\n            return \"null\";\n        if (a instanceof Date) {\n            s = \"Date(\" + toStr(a.valueOf()) + \")\";\n        } else if (a instanceof Number) {\n            s = \"Number(\" + toStr(a.valueOf()) + \")\";\n        } else if (a instanceof String) {\n            s = \"String(\" + toStr(a.valueOf()) + \")\";\n        } else if (a instanceof Boolean) {\n            s = \"Boolean(\" + toStr(a.valueOf()) + \")\";\n        } else if (isArrayLike(a)) {\n            s = \"[\";\n            for(i = 0; i < a.length; i++) {\n                if (i != 0)\n                    s += \",\";\n                s += toStr(a[i]);\n            }\n            s += \"]\";\n        } else {\n            props = Object.keys(a);\n            s = \"{\";\n            for(i = 0; i < props.length; i++) {\n                if (i != 0)\n                    s += \",\";\n                prop = props[i];\n                s += prop + \":\" + toStr(a[prop]);\n            }\n            s += \"}\";\n        }\n        return s;\n    case \"undefined\":\n        return \"undefined\";\n    case \"string\":\n        return JSON.stringify(a);\n    case \"number\":\n        if (a == 0 && 1 / a < 0)\n            return \"-0\";\n        else\n            return a.toString();\n        break;\n    default:\n        return a.toString();\n    }\n}\n\nfunction bjson_test(a)\n{\n    var buf, r, a_str, r_str;\n    a_str = toStr(a);\n    buf = bjson.write(a);\n    if (0) {\n        print(a_str, \"->\", toHex(buf));\n    }\n    r = bjson.read(buf, 0, buf.byteLength);\n    r_str = toStr(r);\n    if (a_str != r_str) {\n        print(a_str);\n        print(r_str);\n        assert(false);\n    }\n}\n\nfunction bjson_test_arraybuffer()\n{\n    var buf, array_buffer;\n\n    array_buffer = new ArrayBuffer(4);\n    assert(array_buffer.byteLength, 4);\n    assert(array_buffer.maxByteLength, 4);\n    assert(array_buffer.resizable, false);\n    buf = bjson.write(array_buffer);\n    array_buffer = bjson.read(buf, 0, buf.byteLength);\n    assert(array_buffer.byteLength, 4);\n    assert(array_buffer.maxByteLength, 4);\n    assert(array_buffer.resizable, false);\n\n    array_buffer = new ArrayBuffer(4, {maxByteLength: 4});\n    assert(array_buffer.byteLength, 4);\n    assert(array_buffer.maxByteLength, 4);\n    assert(array_buffer.resizable, true);\n    buf = bjson.write(array_buffer);\n    array_buffer = bjson.read(buf, 0, buf.byteLength);\n    assert(array_buffer.byteLength, 4);\n    assert(array_buffer.maxByteLength, 4);\n    assert(array_buffer.resizable, true);\n\n    array_buffer = new ArrayBuffer(4, {maxByteLength: 8});\n    assert(array_buffer.byteLength, 4);\n    assert(array_buffer.maxByteLength, 8);\n    assert(array_buffer.resizable, true);\n    buf = bjson.write(array_buffer);\n    array_buffer = bjson.read(buf, 0, buf.byteLength);\n    assert(array_buffer.byteLength, 4);\n    assert(array_buffer.maxByteLength, 8);\n    assert(array_buffer.resizable, true);\n}\n\n/* test multiple references to an object including circular\n   references */\nfunction bjson_test_reference()\n{\n    var array, buf, i, n, array_buffer;\n    n = 16;\n    array = [];\n    for(i = 0; i < n; i++)\n        array[i] = {};\n    array_buffer = new ArrayBuffer(n);\n    for(i = 0; i < n; i++) {\n        array[i].next = array[(i + 1) % n];\n        array[i].idx = i;\n        array[i].typed_array = new Uint8Array(array_buffer, i, 1);\n    }\n    buf = bjson.write(array, true);\n\n    array = bjson.read(buf, 0, buf.byteLength, true);\n\n    /* check the result */\n    for(i = 0; i < n; i++) {\n        assert(array[i].next, array[(i + 1) % n]);\n        assert(array[i].idx, i);\n        assert(array[i].typed_array.buffer, array_buffer);\n        assert(array[i].typed_array.length, 1);\n        assert(array[i].typed_array.byteOffset, i);\n    }\n}\n\nfunction bjson_test_all()\n{\n    var obj;\n\n    bjson_test({x:1, y:2, if:3});\n\n    bjson_test([1, 2, 3]);\n\n    /* array with holes */\n    bjson_test([1, , 2, , 3]); \n\n    /* fast array with hole */\n    obj = new Array(5);\n    obj[0] = 1;\n    obj[1] = 2;\n    bjson_test(obj);\n\n    bjson_test([1.0, \"aa\", true, false, undefined, null, NaN, -Infinity, -0.0]);\n    if (typeof BigInt !== \"undefined\") {\n        bjson_test([BigInt(\"1\"), -BigInt(\"0x123456789\"),\n               BigInt(\"0x123456789abcdef123456789abcdef\")]);\n    }\n    bjson_test([new Date(1234), new String(\"abc\"), new Number(-12.1), new Boolean(true)]);\n\n    bjson_test(new Int32Array([123123, 222111, -32222]));\n    bjson_test(new Float16Array([1024, 1024.5]));\n    bjson_test(new Float64Array([123123, 222111.5]));\n\n    /* tested with a circular reference */\n    obj = {};\n    obj.x = obj;\n    try {\n        bjson.write(obj);\n        assert(false);\n    } catch(e) {\n        assert(e instanceof TypeError);\n    }\n\n    bjson_test_arraybuffer();\n    bjson_test_reference();\n}\n\nbjson_test_all();\n"
  },
  {
    "path": "tests/test_builtin.js",
    "content": "\"use strict\";\n\nvar status = 0;\nvar throw_errors = true;\n\nfunction throw_error(msg) {\n    if (throw_errors)\n        throw Error(msg);\n    console.log(msg);\n    status = 1;\n}\n\nfunction assert(actual, expected, message) {\n    function get_full_type(o) {\n        var type = typeof(o);\n        if (type === 'object') {\n            if (o === null)\n                return 'null';\n            if (o.constructor && o.constructor.name)\n                return o.constructor.name;\n        }\n        return type;\n    }\n\n    if (arguments.length == 1)\n        expected = true;\n\n    if (typeof actual === typeof expected) {\n        if (actual === expected) {\n            if (actual !== 0 || (1 / actual) === (1 / expected))\n                return;\n        }\n        if (typeof actual === 'number') {\n            if (isNaN(actual) && isNaN(expected))\n                return true;\n        }\n        if (typeof actual === 'object') {\n            if (actual !== null && expected !== null\n            &&  actual.constructor === expected.constructor\n            &&  actual.toString() === expected.toString())\n                return;\n        }\n    }\n    // Should output the source file and line number and extract\n    //   the expression from the assert call\n    throw_error(\"assertion failed: got \" +\n                get_full_type(actual) + \":|\" + actual + \"|, expected \" +\n                get_full_type(expected) + \":|\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\nfunction assert_throws(expected_error, func)\n{\n    var err = false;\n    try {\n        func();\n    } catch(e) {\n        err = true;\n        if (!(e instanceof expected_error)) {\n            // Should output the source file and line number and extract\n            //   the expression from the assert_throws() call\n            throw_error(\"unexpected exception type\");\n            return;\n        }\n    }\n    if (!err) {\n        // Should output the source file and line number and extract\n        //   the expression from the assert_throws() call\n        throw_error(\"expected exception\");\n    }\n}\n\n// load more elaborate version of assert if available\ntry { __loadScript(\"test_assert.js\"); } catch(e) {}\n\n/*----------------*/\n\nfunction my_func(a, b)\n{\n    return a + b;\n}\n\nfunction test_function()\n{\n    function f(a, b) {\n        var i, tab = [];\n        tab.push(this);\n        for(i = 0; i < arguments.length; i++)\n            tab.push(arguments[i]);\n        return tab;\n    }\n    function constructor1(a) {\n        this.x = a;\n    }\n\n    var r, g;\n\n    r = my_func.call(null, 1, 2);\n    assert(r, 3, \"call\");\n\n    r = my_func.apply(null, [1, 2]);\n    assert(r, 3, \"apply\");\n\n    r = (function () { return 1; }).apply(null, undefined);\n    assert(r, 1);\n\n    assert_throws(TypeError, (function() {\n        Reflect.apply((function () { return 1; }), null, undefined);\n    }));\n\n    r = new Function(\"a\", \"b\", \"return a + b;\");\n    assert(r(2,3), 5, \"function\");\n\n    g = f.bind(1, 2);\n    assert(g.length, 1);\n    assert(g.name, \"bound f\");\n    assert(g(3), [1,2,3]);\n\n    g = constructor1.bind(null, 1);\n    r = new g();\n    assert(r.x, 1);\n}\n\nfunction test()\n{\n    var r, a, b, c, err;\n\n    r = Error(\"hello\");\n    assert(r.message, \"hello\", \"Error\");\n\n    a = new Object();\n    a.x = 1;\n    assert(a.x, 1, \"Object\");\n\n    assert(Object.getPrototypeOf(a), Object.prototype, \"getPrototypeOf\");\n    Object.defineProperty(a, \"y\", { value: 3, writable: true, configurable: true, enumerable: true });\n    assert(a.y, 3, \"defineProperty\");\n\n    Object.defineProperty(a, \"z\", { get: function () { return 4; }, set: function(val) { this.z_val = val; }, configurable: true, enumerable: true });\n    assert(a.z, 4, \"get\");\n    a.z = 5;\n    assert(a.z_val, 5, \"set\");\n\n    a = { get z() { return 4; }, set z(val) { this.z_val = val; } };\n    assert(a.z, 4, \"get\");\n    a.z = 5;\n    assert(a.z_val, 5, \"set\");\n\n    b = Object.create(a);\n    assert(Object.getPrototypeOf(b), a, \"create\");\n    c = {u:2};\n    /* XXX: refcount bug in 'b' instead of 'a' */\n    Object.setPrototypeOf(a, c);\n    assert(Object.getPrototypeOf(a), c, \"setPrototypeOf\");\n\n    a = {};\n    assert(a.toString(), \"[object Object]\", \"toString\");\n\n    a = {x:1};\n    assert(Object.isExtensible(a), true, \"extensible\");\n    Object.preventExtensions(a);\n\n    err = false;\n    try {\n        a.y = 2;\n    } catch(e) {\n        err = true;\n    }\n    assert(Object.isExtensible(a), false, \"extensible\");\n    assert(typeof a.y, \"undefined\", \"extensible\");\n    assert(err, true, \"extensible\");\n}\n\nfunction test_enum()\n{\n    var a, tab;\n    a = {x:1,\n         \"18014398509481984\": 1,\n         \"9007199254740992\": 1,\n         \"9007199254740991\": 1,\n         \"4294967296\": 1,\n         \"4294967295\": 1,\n         y:1,\n         \"4294967294\": 1,\n         \"1\": 2};\n    tab = Object.keys(a);\n//    console.log(\"tab=\" + tab.toString());\n    assert(tab, [\"1\",\"4294967294\",\"x\",\"18014398509481984\",\"9007199254740992\",\"9007199254740991\",\"4294967296\",\"4294967295\",\"y\"], \"keys\");\n}\n\nfunction test_array()\n{\n    var a, err;\n\n    a = [1, 2, 3];\n    assert(a.length, 3, \"array\");\n    assert(a[2], 3, \"array1\");\n\n    a = new Array(10);\n    assert(a.length, 10, \"array2\");\n\n    a = new Array(1, 2);\n    assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, \"array3\");\n\n    a = [1, 2, 3];\n    a.length = 2;\n    assert(a.length === 2 && a[0] === 1 && a[1] === 2, true, \"array4\");\n\n    a = [];\n    a[1] = 10;\n    a[4] = 3;\n    assert(a.length, 5);\n\n    a = [1,2];\n    a.length = 5;\n    a[4] = 1;\n    a.length = 4;\n    assert(a[4] !== 1, true, \"array5\");\n\n    a = [1,2];\n    a.push(3,4);\n    assert(a.join(), \"1,2,3,4\", \"join\");\n\n    a = [1,2,3,4,5];\n    Object.defineProperty(a, \"3\", { configurable: false });\n    err = false;\n    try {\n        a.length = 2;\n    } catch(e) {\n        err = true;\n    }\n    assert(err && a.toString() === \"1,2,3,4\");\n}\n\nfunction test_string()\n{\n    var a;\n    a = String(\"abc\");\n    assert(a.length, 3, \"string\");\n    assert(a[1], \"b\", \"string\");\n    assert(a.charCodeAt(1), 0x62, \"string\");\n    assert(String.fromCharCode(65), \"A\", \"string\");\n    assert(String.fromCharCode.apply(null, [65, 66, 67]), \"ABC\", \"string\");\n    assert(a.charAt(1), \"b\");\n    assert(a.charAt(-1), \"\");\n    assert(a.charAt(3), \"\");\n\n    a = \"abcd\";\n    assert(a.substring(1, 3), \"bc\", \"substring\");\n    a = String.fromCharCode(0x20ac);\n    assert(a.charCodeAt(0), 0x20ac, \"unicode\");\n    assert(a, \"€\", \"unicode\");\n    assert(a, \"\\u20ac\", \"unicode\");\n    assert(a, \"\\u{20ac}\", \"unicode\");\n    assert(\"a\", \"\\x61\", \"unicode\");\n\n    a = \"\\u{10ffff}\";\n    assert(a.length, 2, \"unicode\");\n    assert(a, \"\\u{dbff}\\u{dfff}\", \"unicode\");\n    assert(a.codePointAt(0), 0x10ffff);\n    assert(String.fromCodePoint(0x10ffff), a);\n\n    assert(\"a\".concat(\"b\", \"c\"), \"abc\");\n\n    assert(\"abcabc\".indexOf(\"cab\"), 2);\n    assert(\"abcabc\".indexOf(\"cab2\"), -1);\n    assert(\"abc\".indexOf(\"c\"), 2);\n\n    assert(\"aaa\".indexOf(\"a\"), 0);\n    assert(\"aaa\".indexOf(\"a\", NaN), 0);\n    assert(\"aaa\".indexOf(\"a\", -Infinity), 0);\n    assert(\"aaa\".indexOf(\"a\", -1), 0);\n    assert(\"aaa\".indexOf(\"a\", -0), 0);\n    assert(\"aaa\".indexOf(\"a\", 0), 0);\n    assert(\"aaa\".indexOf(\"a\", 1), 1);\n    assert(\"aaa\".indexOf(\"a\", 2), 2);\n    assert(\"aaa\".indexOf(\"a\", 3), -1);\n    assert(\"aaa\".indexOf(\"a\", 4), -1);\n    assert(\"aaa\".indexOf(\"a\", Infinity), -1);\n\n    assert(\"aaa\".indexOf(\"\"), 0);\n    assert(\"aaa\".indexOf(\"\", NaN), 0);\n    assert(\"aaa\".indexOf(\"\", -Infinity), 0);\n    assert(\"aaa\".indexOf(\"\", -1), 0);\n    assert(\"aaa\".indexOf(\"\", -0), 0);\n    assert(\"aaa\".indexOf(\"\", 0), 0);\n    assert(\"aaa\".indexOf(\"\", 1), 1);\n    assert(\"aaa\".indexOf(\"\", 2), 2);\n    assert(\"aaa\".indexOf(\"\", 3), 3);\n    assert(\"aaa\".indexOf(\"\", 4), 3);\n    assert(\"aaa\".indexOf(\"\", Infinity), 3);\n\n    assert(\"aaa\".lastIndexOf(\"a\"), 2);\n    assert(\"aaa\".lastIndexOf(\"a\", NaN), 2);\n    assert(\"aaa\".lastIndexOf(\"a\", -Infinity), 0);\n    assert(\"aaa\".lastIndexOf(\"a\", -1), 0);\n    assert(\"aaa\".lastIndexOf(\"a\", -0), 0);\n    assert(\"aaa\".lastIndexOf(\"a\", 0), 0);\n    assert(\"aaa\".lastIndexOf(\"a\", 1), 1);\n    assert(\"aaa\".lastIndexOf(\"a\", 2), 2);\n    assert(\"aaa\".lastIndexOf(\"a\", 3), 2);\n    assert(\"aaa\".lastIndexOf(\"a\", 4), 2);\n    assert(\"aaa\".lastIndexOf(\"a\", Infinity), 2);\n\n    assert(\"aaa\".lastIndexOf(\"\"), 3);\n    assert(\"aaa\".lastIndexOf(\"\", NaN), 3);\n    assert(\"aaa\".lastIndexOf(\"\", -Infinity), 0);\n    assert(\"aaa\".lastIndexOf(\"\", -1), 0);\n    assert(\"aaa\".lastIndexOf(\"\", -0), 0);\n    assert(\"aaa\".lastIndexOf(\"\", 0), 0);\n    assert(\"aaa\".lastIndexOf(\"\", 1), 1);\n    assert(\"aaa\".lastIndexOf(\"\", 2), 2);\n    assert(\"aaa\".lastIndexOf(\"\", 3), 3);\n    assert(\"aaa\".lastIndexOf(\"\", 4), 3);\n    assert(\"aaa\".lastIndexOf(\"\", Infinity), 3);\n\n    assert(\"a,b,c\".split(\",\"), [\"a\",\"b\",\"c\"]);\n    assert(\",b,c\".split(\",\"), [\"\",\"b\",\"c\"]);\n    assert(\"a,b,\".split(\",\"), [\"a\",\"b\",\"\"]);\n\n    assert(\"aaaa\".split(), [ \"aaaa\" ]);\n    assert(\"aaaa\".split(undefined, 0), [ ]);\n    assert(\"aaaa\".split(\"\"), [ \"a\", \"a\", \"a\", \"a\" ]);\n    assert(\"aaaa\".split(\"\", 0), [ ]);\n    assert(\"aaaa\".split(\"\", 1), [ \"a\" ]);\n    assert(\"aaaa\".split(\"\", 2), [ \"a\", \"a\" ]);\n    assert(\"aaaa\".split(\"a\"), [ \"\", \"\", \"\", \"\", \"\" ]);\n    assert(\"aaaa\".split(\"a\", 2), [ \"\", \"\" ]);\n    assert(\"aaaa\".split(\"aa\"), [ \"\", \"\", \"\" ]);\n    assert(\"aaaa\".split(\"aa\", 0), [ ]);\n    assert(\"aaaa\".split(\"aa\", 1), [ \"\" ]);\n    assert(\"aaaa\".split(\"aa\", 2), [ \"\", \"\" ]);\n    assert(\"aaaa\".split(\"aaa\"), [ \"\", \"a\" ]);\n    assert(\"aaaa\".split(\"aaaa\"), [ \"\", \"\" ]);\n    assert(\"aaaa\".split(\"aaaaa\"), [ \"aaaa\" ]);\n    assert(\"aaaa\".split(\"aaaaa\", 0), [  ]);\n    assert(\"aaaa\".split(\"aaaaa\", 1), [ \"aaaa\" ]);\n\n    assert(eval('\"\\0\"'), \"\\0\");\n\n    assert(\"abc\".padStart(Infinity, \"\"), \"abc\");\n}\n\nfunction test_math()\n{\n    var a;\n    a = 1.4;\n    assert(Math.floor(a), 1);\n    assert(Math.ceil(a), 2);\n    assert(Math.imul(0x12345678, 123), -1088058456);\n    assert(Math.imul(0xB505, 0xB504), 2147441940);\n    assert(Math.imul(0xB505, 0xB505), -2147479015);\n    assert(Math.imul((-2)**31, (-2)**31), 0);\n    assert(Math.imul(2**31-1, 2**31-1), 1);\n    assert(Math.fround(0.1), 0.10000000149011612);\n    assert(Math.hypot(), 0);\n    assert(Math.hypot(-2), 2);\n    assert(Math.hypot(3, 4), 5);\n    assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15);\n    assert(Math.sumPrecise([1,Number.EPSILON/2,Number.MIN_VALUE]), 1.0000000000000002);\n}\n\nfunction test_number()\n{\n    assert(parseInt(\"123\"), 123);\n    assert(parseInt(\"  123r\"), 123);\n    assert(parseInt(\"0x123\"), 0x123);\n    assert(parseInt(\"0o123\"), 0);\n    assert(+\"  123   \", 123);\n    assert(+\"0b111\", 7);\n    assert(+\"0o123\", 83);\n    assert(parseFloat(\"2147483647\"), 2147483647);\n    assert(parseFloat(\"2147483648\"), 2147483648);\n    assert(parseFloat(\"-2147483647\"), -2147483647);\n    assert(parseFloat(\"-2147483648\"), -2147483648);\n    assert(parseFloat(\"0x1234\"), 0);\n    assert(parseFloat(\"Infinity\"), Infinity);\n    assert(parseFloat(\"-Infinity\"), -Infinity);\n    assert(parseFloat(\"123.2\"), 123.2);\n    assert(parseFloat(\"123.2e3\"), 123200);\n    assert(Number.isNaN(Number(\"+\")));\n    assert(Number.isNaN(Number(\"-\")));\n    assert(Number.isNaN(Number(\"\\x00a\")));\n\n    assert((1-2**-53).toString(12), \"0.bbbbbbbbbbbbbba\");\n    assert((1000000000000000128).toString(), \"1000000000000000100\");\n    assert((1000000000000000128).toFixed(0), \"1000000000000000128\");\n    assert((25).toExponential(0), \"3e+1\");\n    assert((-25).toExponential(0), \"-3e+1\");\n    assert((2.5).toPrecision(1), \"3\");\n    assert((-2.5).toPrecision(1), \"-3\");\n    assert((25).toPrecision(1) === \"3e+1\");\n    assert((1.125).toFixed(2), \"1.13\");\n    assert((-1.125).toFixed(2), \"-1.13\");\n    assert((0.5).toFixed(0), \"1\");\n    assert((-0.5).toFixed(0), \"-1\");\n    assert((-1e-10).toFixed(0), \"-0\");\n\n    assert((1.3).toString(7), \"1.2046204620462046205\");\n    assert((1.3).toString(35), \"1.ahhhhhhhhhm\");\n}\n\nfunction test_eval2()\n{\n    var g_call_count = 0;\n    /* force non strict mode for f1 and f2 */\n    var f1 = new Function(\"eval\", \"eval(1, 2)\");\n    var f2 = new Function(\"eval\", \"eval(...[1, 2])\");\n    function g(a, b) {\n        assert(a, 1);\n        assert(b, 2);\n        g_call_count++;\n    }\n    f1(g);\n    f2(g);\n    assert(g_call_count, 2);\n}\n\nfunction test_eval()\n{\n    function f(b) {\n        var x = 1;\n        return eval(b);\n    }\n    var r, a;\n\n    r = eval(\"1+1;\");\n    assert(r, 2, \"eval\");\n\n    r = eval(\"var my_var=2; my_var;\");\n    assert(r, 2, \"eval\");\n    assert(typeof my_var, \"undefined\");\n\n    assert(eval(\"if (1) 2; else 3;\"), 2);\n    assert(eval(\"if (0) 2; else 3;\"), 3);\n\n    assert(f.call(1, \"this\"), 1);\n\n    a = 2;\n    assert(eval(\"a\"), 2);\n\n    eval(\"a = 3\");\n    assert(a, 3);\n\n    assert(f(\"arguments.length\", 1), 2);\n    assert(f(\"arguments[1]\", 1), 1);\n\n    a = 4;\n    assert(f(\"a\"), 4);\n    f(\"a=3\");\n    assert(a, 3);\n\n    test_eval2();\n}\n\nfunction test_typed_array()\n{\n    var buffer, a, i, str;\n\n    a = new Uint8Array(4);\n    assert(a.length, 4);\n    for(i = 0; i < a.length; i++)\n        a[i] = i;\n    assert(a.join(\",\"), \"0,1,2,3\");\n    a[0] = -1;\n    assert(a[0], 255);\n\n    a = new Int8Array(3);\n    a[0] = 255;\n    assert(a[0], -1);\n\n    a = new Int32Array(3);\n    a[0] = Math.pow(2, 32) - 1;\n    assert(a[0], -1);\n    assert(a.BYTES_PER_ELEMENT, 4);\n\n    a = new Uint8ClampedArray(4);\n    a[0] = -100;\n    a[1] = 1.5;\n    a[2] = 0.5;\n    a[3] = 1233.5;\n    assert(a.toString(), \"0,2,0,255\");\n\n    buffer = new ArrayBuffer(16);\n    assert(buffer.byteLength, 16);\n    a = new Uint32Array(buffer, 12, 1);\n    assert(a.length, 1);\n    a[0] = -1;\n\n    a = new Uint16Array(buffer, 2);\n    a[0] = -1;\n\n    a = new Float16Array(buffer, 8, 1);\n    a[0] = 1;\n\n    a = new Float32Array(buffer, 8, 1);\n    a[0] = 1;\n\n    a = new Uint8Array(buffer);\n\n    str = a.toString();\n    /* test little and big endian cases */\n    if (str !== \"0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255\" &&\n        str !== \"0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255\") {\n        assert(false);\n    }\n\n    assert(a.buffer, buffer);\n\n    a = new Uint8Array([1, 2, 3, 4]);\n    assert(a.toString(), \"1,2,3,4\");\n    a.set([10, 11], 2);\n    assert(a.toString(), \"1,2,10,11\");\n\n    // https://github.com/quickjs-ng/quickjs/issues/1208\n    buffer = new ArrayBuffer(16);\n    a = new Uint8Array(buffer);\n    a.fill(42);\n    assert(a[0], 42);\n    buffer.transfer();\n    assert(a[0], undefined);\n}\n\n/* return [s, line_num, col_num] where line_num and col_num are the\n   position of the '@' character in 'str'. 's' is str without the '@'\n   character */\nfunction get_string_pos(str)\n{\n    var p, line_num, col_num, s, q, r;\n    p = str.indexOf('@');\n    assert(p >= 0, true);\n    q = 0;\n    line_num = 1;\n    for(;;) {\n        r = str.indexOf('\\n', q);\n        if (r < 0 || r >= p)\n            break;\n        q = r + 1;\n        line_num++;\n    }\n    col_num = p - q + 1;\n    s = str.slice(0, p) + str.slice(p + 1);\n    return [s, line_num, col_num];\n}\n\nfunction check_error_pos(e, expected_error, line_num, col_num, level)\n{\n    var expected_pos, tab, line;\n    level |= 0;\n    expected_pos = \":\" + line_num + \":\" + col_num;\n    tab = e.stack.split(\"\\n\");\n    line = tab[level];\n    if (line.slice(-1) == ')')\n        line = line.slice(0, -1);\n    if (line.indexOf(expected_pos) < 0) {\n        throw_error(\"unexpected line or column number. error=\" + e.message +\n                    \".got |\" + line + \"|, expected |\" + expected_pos + \"|\");\n    }\n}\n\nfunction assert_json_error(str, line_num, col_num)\n{\n    var err = false;\n    var expected_pos, tab;\n\n    tab = get_string_pos(str);\n    \n    try {\n        JSON.parse(tab[0]);\n    } catch(e) {\n        err = true;\n        if (!(e instanceof SyntaxError)) {\n            throw_error(\"unexpected exception type\");\n            return;\n        }\n        /* XXX: the way quickjs returns JSON errors is not similar to Node or spiderMonkey */\n        check_error_pos(e, SyntaxError, tab[1], tab[2]);\n    }\n    if (!err) {\n        throw_error(\"expected exception\");\n    }\n}\n\nfunction test_json()\n{\n    var a, s;\n    s = '{\"x\":1,\"y\":true,\"z\":null,\"a\":[1,2,3],\"s\":\"str\"}';\n    a = JSON.parse(s);\n    assert(a.x, 1);\n    assert(a.y, true);\n    assert(a.z, null);\n    assert(JSON.stringify(a), s);\n\n    /* indentation test */\n    assert(JSON.stringify([[{x:1,y:{},z:[]},2,3]],undefined,1),\n`[\n [\n  {\n   \"x\": 1,\n   \"y\": {},\n   \"z\": []\n  },\n  2,\n  3\n ]\n]`);\n\n    assert_json_error('\\n\"  \\\\@x\"');\n    assert_json_error('\\n{ \"a\": @x }\"');\n}\n\nfunction test_date()\n{\n    // Date Time String format is YYYY-MM-DDTHH:mm:ss.sssZ\n    // accepted date formats are: YYYY, YYYY-MM and YYYY-MM-DD\n    // accepted time formats are: THH:mm, THH:mm:ss, THH:mm:ss.sss\n    // expanded years are represented with 6 digits prefixed by + or -\n    // -000000 is invalid.\n    // A string containing out-of-bounds or nonconforming elements\n    //   is not a valid instance of this format.\n    // Hence the fractional part after . should have 3 digits and how\n    // a different number of digits is handled is implementation defined.\n    assert(Date.parse(\"\"), NaN);\n    assert(Date.parse(\"2000\"), 946684800000);\n    assert(Date.parse(\"2000-01\"), 946684800000);\n    assert(Date.parse(\"2000-01-01\"), 946684800000);\n    //assert(Date.parse(\"2000-01-01T\"), NaN);\n    //assert(Date.parse(\"2000-01-01T00Z\"), NaN);\n    assert(Date.parse(\"2000-01-01T00:00Z\"), 946684800000);\n    assert(Date.parse(\"2000-01-01T00:00:00Z\"), 946684800000);\n    assert(Date.parse(\"2000-01-01T00:00:00.1Z\"), 946684800100);\n    assert(Date.parse(\"2000-01-01T00:00:00.10Z\"), 946684800100);\n    assert(Date.parse(\"2000-01-01T00:00:00.100Z\"), 946684800100);\n    assert(Date.parse(\"2000-01-01T00:00:00.1000Z\"), 946684800100);\n    assert(Date.parse(\"2000-01-01T00:00:00+00:00\"), 946684800000);\n    //assert(Date.parse(\"2000-01-01T00:00:00+00:30\"), 946686600000);\n    var d = new Date(\"2000T00:00\");  // Jan 1st 2000, 0:00:00 local time\n    assert(typeof d === 'object' && d.toString() != 'Invalid Date');\n    assert((new Date('Jan 1 2000')).toISOString(),\n           d.toISOString());\n    assert((new Date('Jan 1 2000 00:00')).toISOString(),\n           d.toISOString());\n    assert((new Date('Jan 1 2000 00:00:00')).toISOString(),\n           d.toISOString());\n    assert((new Date('Jan 1 2000 00:00:00 GMT+0100')).toISOString(),\n           '1999-12-31T23:00:00.000Z');\n    assert((new Date('Jan 1 2000 00:00:00 GMT+0200')).toISOString(),\n           '1999-12-31T22:00:00.000Z');\n    assert((new Date('Sat Jan 1 2000')).toISOString(),\n           d.toISOString());\n    assert((new Date('Sat Jan 1 2000 00:00')).toISOString(),\n           d.toISOString());\n    assert((new Date('Sat Jan 1 2000 00:00:00')).toISOString(),\n           d.toISOString());\n    assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0100')).toISOString(),\n           '1999-12-31T23:00:00.000Z');\n    assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0200')).toISOString(),\n           '1999-12-31T22:00:00.000Z');\n\n    var d = new Date(1506098258091);\n    assert(d.toISOString(), \"2017-09-22T16:37:38.091Z\");\n    d.setUTCHours(18, 10, 11);\n    assert(d.toISOString(), \"2017-09-22T18:10:11.091Z\");\n    var a = Date.parse(d.toISOString());\n    assert((new Date(a)).toISOString(), d.toISOString());\n\n    assert((new Date(\"2020-01-01T01:01:01.123Z\")).toISOString(),\n                     \"2020-01-01T01:01:01.123Z\");\n    /* implementation defined behavior */\n    assert((new Date(\"2020-01-01T01:01:01.1Z\")).toISOString(),\n                     \"2020-01-01T01:01:01.100Z\");\n    assert((new Date(\"2020-01-01T01:01:01.12Z\")).toISOString(),\n                     \"2020-01-01T01:01:01.120Z\");\n    assert((new Date(\"2020-01-01T01:01:01.1234Z\")).toISOString(),\n                     \"2020-01-01T01:01:01.123Z\");\n    assert((new Date(\"2020-01-01T01:01:01.12345Z\")).toISOString(),\n                     \"2020-01-01T01:01:01.123Z\");\n    assert((new Date(\"2020-01-01T01:01:01.1235Z\")).toISOString(),\n                     \"2020-01-01T01:01:01.123Z\");\n    assert((new Date(\"2020-01-01T01:01:01.9999Z\")).toISOString(),\n                     \"2020-01-01T01:01:01.999Z\");\n\n    assert(Date.UTC(2017), 1483228800000);\n    assert(Date.UTC(2017, 9), 1506816000000);\n    assert(Date.UTC(2017, 9, 22), 1508630400000);\n    assert(Date.UTC(2017, 9, 22, 18), 1508695200000);\n    assert(Date.UTC(2017, 9, 22, 18, 10), 1508695800000);\n    assert(Date.UTC(2017, 9, 22, 18, 10, 11), 1508695811000);\n    assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91), 1508695811091);\n\n    assert(Date.UTC(NaN), NaN);\n    assert(Date.UTC(2017, NaN), NaN);\n    assert(Date.UTC(2017, 9, NaN), NaN);\n    assert(Date.UTC(2017, 9, 22, NaN), NaN);\n    assert(Date.UTC(2017, 9, 22, 18, NaN), NaN);\n    assert(Date.UTC(2017, 9, 22, 18, 10, NaN), NaN);\n    assert(Date.UTC(2017, 9, 22, 18, 10, 11, NaN), NaN);\n    assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91, NaN), 1508695811091);\n\n    // TODO: Fix rounding errors on Windows/Cygwin.\n    if (!(typeof os !== 'undefined' && ['win32', 'cygwin'].includes(os.platform))) {\n        // from test262/test/built-ins/Date/UTC/fp-evaluation-order.js\n        assert(Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740), 29312,\n               'order of operations / precision in MakeTime');\n        assert(Date.UTC(1970, 0, 213503982336, 0, 0, 0, -18446744073709552000), 34447360,\n               'precision in MakeDate');\n    }\n    //assert(Date.UTC(2017 - 1e9, 9 + 12e9), 1506816000000);  // node fails this\n    assert(Date.UTC(2017, 9, 22 - 1e10, 18 + 24e10), 1508695200000);\n    assert(Date.UTC(2017, 9, 22, 18 - 1e10, 10 + 60e10), 1508695800000);\n    assert(Date.UTC(2017, 9, 22, 18, 10 - 1e10, 11 + 60e10), 1508695811000);\n    assert(Date.UTC(2017, 9, 22, 18, 10, 11 - 1e12, 91 + 1000e12), 1508695811091);\n}\n\nfunction test_regexp()\n{\n    var a, str;\n    str = \"abbbbbc\";\n    a = /(b+)c/.exec(str);\n    assert(a[0], \"bbbbbc\");\n    assert(a[1], \"bbbbb\");\n    assert(a.index, 1);\n    assert(a.input, str);\n    a = /(b+)c/.test(str);\n    assert(a, true);\n    assert(/\\x61/.exec(\"a\")[0], \"a\");\n    assert(/\\u0061/.exec(\"a\")[0], \"a\");\n    assert(/\\ca/.exec(\"\\x01\")[0], \"\\x01\");\n    assert(/\\\\a/.exec(\"\\\\a\")[0], \"\\\\a\");\n    assert(/\\c0/.exec(\"\\\\c0\")[0], \"\\\\c0\");\n\n    a = /(\\.(?=com|org)|\\/)/.exec(\"ah.com\");\n    assert(a.index === 2 && a[0] === \".\");\n\n    a = /(\\.(?!com|org)|\\/)/.exec(\"ah.com\");\n    assert(a, null);\n\n    a = /(?=(a+))/.exec(\"baaabac\");\n    assert(a.index === 1 && a[0] === \"\" && a[1] === \"aaa\");\n\n    a = /(z)((a+)?(b+)?(c))*/.exec(\"zaacbbbcac\");\n    assert(a, [\"zaacbbbcac\",\"z\",\"ac\",\"a\",,\"c\"]);\n\n    a = eval(\"/\\0a/\");\n    assert(a.toString(), \"/\\0a/\");\n    assert(a.exec(\"\\0a\")[0], \"\\0a\");\n\n    assert(/{1a}/.toString(), \"/{1a}/\");\n    a = /a{1+/.exec(\"a{11\");\n    assert(a, [\"a{11\"]);\n\n    /* test zero length matches */\n    a = /(?:(?=(abc)))a/.exec(\"abc\");\n    assert(a, [\"a\", \"abc\"]);\n    a = /(?:(?=(abc)))?a/.exec(\"abc\");\n    assert(a, [\"a\", undefined]);\n    a = /(?:(?=(abc))){0,2}a/.exec(\"abc\");\n    assert(a, [\"a\", undefined]);\n    a = /(?:|[\\w])+([0-9])/.exec(\"123a23\");\n    assert(a, [\"123a23\", \"3\"]);\n    a = /()*?a/.exec(\",\");\n    assert(a, null);\n\n    /* test \\b escape */\n    assert(/[\\q{a\\b}]/.test(\"a\\b\"), true);\n    assert(/[\\b]/.test(\"\\b\"), true);\n    \n    /* test case insensitive matching (test262 hardly tests it) */\n    assert(\"aAbBcC#4\".replace(/\\p{Lower}/gu,\"X\"), \"XAXBXC#4\");\n\n    assert(\"aAbBcC#4\".replace(/\\p{Lower}/gui,\"X\"), \"XXXXXX#4\");\n    assert(\"aAbBcC#4\".replace(/\\p{Upper}/gui,\"X\"), \"XXXXXX#4\");\n    assert(\"aAbBcC#4\".replace(/\\P{Lower}/gui,\"X\"), \"XXXXXXXX\");\n    assert(\"aAbBcC#4\".replace(/\\P{Upper}/gui,\"X\"), \"XXXXXXXX\");\n    assert(\"aAbBcC\".replace(/[^b]/gui, \"X\"), \"XXbBXX\");\n    assert(\"aAbBcC\".replace(/[^A-B]/gui, \"X\"), \"aAbBXX\");\n\n    assert(\"aAbBcC#4\".replace(/\\p{Lower}/gvi,\"X\"), \"XXXXXX#4\");\n    assert(\"aAbBcC#4\".replace(/\\P{Lower}/gvi,\"X\"), \"aAbBcCXX\");\n    assert(\"aAbBcC#4\".replace(/[^\\P{Lower}]/gvi,\"X\"), \"XXXXXX#4\");\n    assert(\"aAbBcC#4\".replace(/\\P{Upper}/gvi,\"X\"), \"aAbBcCXX\");\n    assert(\"aAbBcC\".replace(/[^b]/gvi, \"X\"), \"XXbBXX\");\n    assert(\"aAbBcC\".replace(/[^A-B]/gvi, \"X\"), \"aAbBXX\");\n    assert(\"aAbBcC\".replace(/[[a-c]&&B]/gvi, \"X\"), \"aAXXcC\");\n    assert(\"aAbBcC\".replace(/[[a-c]--B]/gvi, \"X\"), \"XXbBXX\");\n    \n    assert(\"abcAbC\".replace(/[\\q{AbC}]/gvi,\"X\"), \"XX\");\n    /* Note: SpiderMonkey and v8 may not be correct */\n    assert(\"abcAbC\".replace(/[\\q{BC|A}]/gvi,\"X\"), \"XXXX\");\n    assert(\"abcAbC\".replace(/[\\q{BC|A}--a]/gvi,\"X\"), \"aXAX\");\n\n    /* case where lastIndex points to the second element of a\n       surrogate pair */\n    a = /(?:)/gu;\n    a.lastIndex = 1;\n    a.exec(\"🐱\");\n    assert(a.lastIndex, 0);\n\n    a.lastIndex = 1;\n    a.exec(\"a\\udc00\");\n    assert(a.lastIndex, 1);\n\n    a = /\\u{10000}/vgd;\n    a.lastIndex = 1;\n    a = a.exec(\"\\u{10000}_\\u{10000}\");\n    assert(a.indices[0][0], 0);\n    assert(a.indices[0][1], 2);\n}\n\nfunction test_symbol()\n{\n    var a, b, obj, c;\n    a = Symbol(\"abc\");\n    obj = {};\n    obj[a] = 2;\n    assert(obj[a], 2);\n    assert(typeof obj[\"abc\"], \"undefined\");\n    assert(String(a), \"Symbol(abc)\");\n    b = Symbol(\"abc\");\n    assert(a == a);\n    assert(a === a);\n    assert(a != b);\n    assert(a !== b);\n\n    b = Symbol.for(\"abc\");\n    c = Symbol.for(\"abc\");\n    assert(b === c);\n    assert(b !== a);\n\n    assert(Symbol.keyFor(b), \"abc\");\n    assert(Symbol.keyFor(a), undefined);\n\n    a = Symbol(\"aaa\");\n    assert(a.valueOf(), a);\n    assert(a.toString(), \"Symbol(aaa)\");\n\n    b = Object(a);\n    assert(b.valueOf(), a);\n    assert(b.toString(), \"Symbol(aaa)\");\n}\n\nfunction test_map1(key_type, n)\n{\n    var a, i, tab, o, v;\n    a = new Map();\n    tab = [];\n    for(i = 0; i < n; i++) {\n        v = { };\n        switch(key_type) {\n        case \"small_bigint\":\n            o = BigInt(i);\n            break;\n        case \"bigint\":\n            o = BigInt(i) + (1n << 128n);\n            break;\n        case \"object\":\n            o = { id: i };\n            break;\n        default:\n            assert(false);\n        }\n        tab[i] = [o, v];\n        a.set(o, v);\n    }\n\n    assert(a.size, n);\n    for(i = 0; i < n; i++) {\n        assert(a.get(tab[i][0]), tab[i][1]);\n    }\n\n    i = 0;\n    a.forEach(function (v, o) {\n        assert(o, tab[i++][0]);\n        assert(a.has(o));\n        assert(a.delete(o));\n        assert(!a.has(o));\n    });\n\n    assert(a.size, 0);\n}\n\nfunction test_map()\n{\n    var a, i, n, tab, o, v;\n    n = 1000;\n\n    a = new Map();\n    for (var i = 0; i < n; i++) {\n        a.set(i, i);\n    }\n    a.set(-2147483648, 1);\n    assert(a.get(-2147483648), 1);\n    assert(a.get(-2147483647 - 1), 1);\n    assert(a.get(-2147483647.5 - 0.5), 1);\n\n    a.set(1n, 1n);\n    assert(a.get(1n), 1n);\n    assert(a.get(2n**1000n - (2n**1000n - 1n)), 1n);\n\n    test_map1(\"object\", n);\n    test_map1(\"small_bigint\", n);\n    test_map1(\"bigint\", n);\n}\n\nfunction test_weak_map()\n{\n    var a, i, n, tab, o, v, n2;\n    a = new WeakMap();\n    n = 10;\n    tab = [];\n    for(i = 0; i < n; i++) {\n        v = { };\n        if (i & 1)\n            o = Symbol(\"x\" + i);\n        else\n            o = { id: i };\n        tab[i] = [o, v];\n        a.set(o, v);\n    }\n    o = null;\n\n    n2 = 5;\n    for(i = 0; i < n2; i++) {\n        a.delete(tab[i][0]);\n    }\n    for(i = n2; i < n; i++) {\n        tab[i][0] = null; /* should remove the object from the WeakMap too */\n    }\n    std.gc();\n    /* the WeakMap should be empty here */\n}\n\nfunction test_weak_map_cycles()\n{\n    const weak1 = new WeakMap();\n    const weak2 = new WeakMap();\n    function createCyclicKey() {\n        const parent = {};\n        const child = {parent};\n        parent.child = child;\n        return child;\n    }\n    function testWeakMap() {\n        const cyclicKey = createCyclicKey();\n        const valueOfCyclicKey = {};\n        weak1.set(cyclicKey, valueOfCyclicKey);\n        weak2.set(valueOfCyclicKey, 1);\n    }\n    testWeakMap();\n    // Force to free cyclicKey.\n    std.gc();\n    // Here will cause sigsegv because [cyclicKey] and [valueOfCyclicKey] in [weak1] was free,\n    // but weak2's map record was not removed, and it's key refers [valueOfCyclicKey] which is free.\n    weak2.get({});\n    std.gc();\n}\n\nfunction test_weak_ref()\n{\n    var w1, w2, o, i;\n\n    for(i = 0; i < 2; i++) {\n        if (i == 0)\n            o = { };\n        else\n            o = Symbol(\"x\");\n        w1 = new WeakRef(o);\n        assert(w1.deref(), o);\n        w2 = new WeakRef(o);\n        assert(w2.deref(), o);\n        \n        o = null;\n        assert(w1.deref(), undefined);\n        assert(w2.deref(), undefined);\n        std.gc();\n        assert(w1.deref(), undefined);\n        assert(w2.deref(), undefined);\n    }\n}\n\nfunction test_finalization_registry()\n{\n    {\n        let expected = {};\n        let actual;\n        let finrec = new FinalizationRegistry(v => { actual = v });\n        finrec.register({}, expected);\n        os.setTimeout(() => {\n            assert(actual, expected);\n        }, 0);\n    }\n    {\n        let expected = 42;\n        let actual;\n        let finrec = new FinalizationRegistry(v => { actual = v });\n        finrec.register({}, expected);\n        os.setTimeout(() => {\n            assert(actual, expected);\n        }, 0);\n    }\n    std.gc();\n}\n\nfunction test_generator()\n{\n    function *f() {\n        var ret;\n        yield 1;\n        ret = yield 2;\n        assert(ret, \"next_arg\");\n        return 3;\n    }\n    function *f2() {\n        yield 1;\n        yield 2;\n        return \"ret_val\";\n    }\n    function *f1() {\n        var ret = yield *f2();\n        assert(ret, \"ret_val\");\n        return 3;\n    }\n    function *f3() {\n        var ret;\n        /* test stack consistency with nip_n to handle yield return +\n         * finally clause */\n        try {\n            ret = 2 + (yield 1);\n        } catch(e) {\n        } finally {\n            ret++;\n        }\n        return ret;\n    }\n    var g, v;\n    g = f();\n    v = g.next();\n    assert(v.value === 1 && v.done === false);\n    v = g.next();\n    assert(v.value === 2 && v.done === false);\n    v = g.next(\"next_arg\");\n    assert(v.value === 3 && v.done === true);\n    v = g.next();\n    assert(v.value === undefined && v.done === true);\n\n    g = f1();\n    v = g.next();\n    assert(v.value === 1 && v.done === false);\n    v = g.next();\n    assert(v.value === 2 && v.done === false);\n    v = g.next();\n    assert(v.value === 3 && v.done === true);\n    v = g.next();\n    assert(v.value === undefined && v.done === true);\n\n    g = f3();\n    v = g.next();\n    assert(v.value === 1 && v.done === false);\n    v = g.next(3);\n    assert(v.value === 6 && v.done === true);\n}\n\nfunction rope_concat(n, dir)\n{\n    var i, s;\n    s = \"\";\n    if (dir > 0) {\n        for(i = 0; i < n; i++)\n            s += String.fromCharCode(i & 0xffff);\n    } else {\n        for(i = n - 1; i >= 0; i--)\n            s = String.fromCharCode(i & 0xffff) + s;\n    }\n    \n    for(i = 0; i < n; i++) {\n        /* test before the assert to go faster */\n        if (s.charCodeAt(i) != (i & 0xffff)) {\n            assert(s.charCodeAt(i), i & 0xffff);\n        }\n    }\n}\n\nfunction test_rope()\n{\n    rope_concat(100000, 1);\n    rope_concat(100000, -1);\n}\n\nfunction eval_error(eval_str, expected_error, level)\n{\n    var err = false;\n    var expected_pos, tab;\n\n    tab = get_string_pos(eval_str);\n    \n    try {\n        eval(tab[0]);\n    } catch(e) {\n        err = true;\n        if (!(e instanceof expected_error)) {\n            throw_error(\"unexpected exception type\");\n            return;\n        }\n        check_error_pos(e, expected_error, tab[1], tab[2], level);\n    }\n    if (!err) {\n        throw_error(\"expected exception\");\n    }\n}\n\nvar poisoned_number = {\n    valueOf: function() { throw Error(\"poisoned number\") },\n};\n\nfunction test_line_column_numbers()\n{\n    var f, e, tab;\n\n    /* The '@' character provides the expected position of the\n       error. It is removed before evaluating the string. */\n    \n    /* parsing */\n    eval_error(\"\\n 123 @a \", SyntaxError);\n    eval_error(\"\\n  @/*  \", SyntaxError);\n    eval_error(\"function f  @a\", SyntaxError);\n    /* currently regexp syntax errors point to the start of the regexp */\n    eval_error(\"\\n  @/aaa]/u\", SyntaxError); \n\n    /* function definitions */\n    \n    tab = get_string_pos(\"\\n   @function f() { }; f;\");\n    e = eval(tab[0]);\n    assert(e.lineNumber, tab[1]);\n    assert(e.columnNumber, tab[2]);\n\n    /* errors */\n    tab = get_string_pos('\\n  Error@(\"hello\");');\n    e = eval(tab[0]);\n    check_error_pos(e, Error, tab[1], tab[2]);\n    \n    eval_error('\\n  throw Error@(\"hello\");', Error);\n\n    /* operators */\n    eval_error('\\n  1 + 2 @* poisoned_number;', Error, 1);\n    eval_error('\\n  1 + \"café\" @* poisoned_number;', Error, 1);\n    eval_error('\\n  1 + 2 @** poisoned_number;', Error, 1);\n    eval_error('\\n  2 * @+ poisoned_number;', Error, 1);\n    eval_error('\\n  2 * @- poisoned_number;', Error, 1);\n    eval_error('\\n  2 * @~ poisoned_number;', Error, 1);\n    eval_error('\\n  2 * @++ poisoned_number;', Error, 1);\n    eval_error('\\n  2 * @-- poisoned_number;', Error, 1);\n    eval_error('\\n  2 * poisoned_number @++;', Error, 1);\n    eval_error('\\n  2 * poisoned_number @--;', Error, 1);\n\n    /* accessors */\n    eval_error('\\n 1 + null@[0];', TypeError); \n    eval_error('\\n 1 + null @. abcd;', TypeError); \n    eval_error('\\n 1 + null @( 1234 );', TypeError);\n    eval_error('var obj = { get a() { throw Error(\"test\"); } }\\n 1 + obj @. a;',\n               Error, 1);\n    eval_error('var obj = { set a(b) { throw Error(\"test\"); } }\\n obj @. a = 1;',\n               Error, 1);\n\n    /* variables reference */\n    eval_error('\\n  1 + @not_def', ReferenceError, 0);\n\n    /* assignments */\n    eval_error('1 + (@not_def = 1)', ReferenceError, 0);\n    eval_error('1 + (@not_def += 2)', ReferenceError, 0);\n    eval_error('var a;\\n 1 + (a @+= poisoned_number);', Error, 1);\n}\n\ntest();\ntest_function();\ntest_enum();\ntest_array();\ntest_string();\ntest_math();\ntest_number();\ntest_eval();\ntest_typed_array();\ntest_json();\ntest_date();\ntest_regexp();\ntest_symbol();\ntest_map();\ntest_weak_map();\ntest_weak_map_cycles();\ntest_weak_ref();\ntest_finalization_registry();\ntest_generator();\ntest_rope();\ntest_line_column_numbers();\n"
  },
  {
    "path": "tests/test_closure.js",
    "content": "function assert(actual, expected, message) {\n    if (arguments.length == 1)\n        expected = true;\n\n    if (actual === expected)\n        return;\n\n    if (actual !== null && expected !== null\n    &&  typeof actual == 'object' && typeof expected == 'object'\n    &&  actual.toString() === expected.toString())\n        return;\n\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\n// load more elaborate version of assert if available\ntry { __loadScript(\"test_assert.js\"); } catch(e) {}\n\n/*----------------*/\n\nvar log_str = \"\";\n\nfunction log(str)\n{\n    log_str += str + \",\";\n}\n\nfunction f(a, b, c)\n{\n    var x = 10;\n    log(\"a=\"+a);\n    function g(d) {\n        function h() {\n            log(\"d=\" + d);\n            log(\"x=\" + x);\n        }\n        log(\"b=\" + b);\n        log(\"c=\" + c);\n        h();\n    }\n    g(4);\n    return g;\n}\n\nvar g1 = f(1, 2, 3);\ng1(5);\n\nassert(log_str, \"a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,\", \"closure1\");\n\nfunction test_closure1()\n{\n    function f2()\n    {\n        var val = 1;\n\n        function set(a) {\n            val = a;\n        }\n        function get(a) {\n            return val;\n        }\n        return { \"set\": set, \"get\": get };\n    }\n\n    var obj = f2();\n    obj.set(10);\n    var r;\n    r = obj.get();\n    assert(r, 10, \"closure2\");\n}\n\nfunction test_closure2()\n{\n    var expr_func = function myfunc1(n) {\n        function myfunc2(n) {\n            return myfunc1(n - 1);\n        }\n        if (n == 0)\n            return 0;\n        else\n            return myfunc2(n);\n    };\n    var r;\n    r = expr_func(1);\n    assert(r, 0, \"expr_func\");\n}\n\nfunction test_closure3()\n{\n    function fib(n)\n    {\n        if (n <= 0)\n            return 0;\n        else if (n == 1)\n            return 1;\n        else\n            return fib(n - 1) + fib(n - 2);\n    }\n\n    var fib_func = function fib1(n)\n    {\n        if (n <= 0)\n            return 0;\n        else if (n == 1)\n            return 1;\n        else\n            return fib1(n - 1) + fib1(n - 2);\n    };\n\n    assert(fib(6), 8, \"fib\");\n    assert(fib_func(6), 8, \"fib_func\");\n}\n\nfunction test_arrow_function()\n{\n    \"use strict\";\n\n    function f1() {\n        return (() => arguments)();\n    }\n    function f2() {\n        return (() => this)();\n    }\n    function f3() {\n        return (() => eval(\"this\"))();\n    }\n    function f4() {\n        return (() => eval(\"new.target\"))();\n    }\n    var a;\n\n    a = f1(1, 2);\n    assert(a.length, 2);\n    assert(a[0] === 1 && a[1] === 2);\n\n    assert(f2.call(\"this_val\") === \"this_val\");\n    assert(f3.call(\"this_val\") === \"this_val\");\n    assert(new f4() === f4);\n\n    var o1 = { f() { return this; } };\n    var o2 = { f() {\n        return (() => eval(\"super.f()\"))();\n    } };\n    o2.__proto__ = o1;\n\n    assert(o2.f() === o2);\n}\n\nfunction test_with()\n{\n    var o1 = { x: \"o1\", y: \"o1\" };\n    var x = \"local\";\n    eval('var z=\"var_obj\";');\n    assert(z === \"var_obj\");\n    with (o1) {\n        assert(x === \"o1\");\n        assert(eval(\"x\") === \"o1\");\n        var f = function () {\n            o2 = { x: \"o2\" };\n            with (o2) {\n                assert(x === \"o2\");\n                assert(y === \"o1\");\n                assert(z === \"var_obj\");\n                assert(eval(\"x\") === \"o2\");\n                assert(eval(\"y\") === \"o1\");\n                assert(eval(\"z\") === \"var_obj\");\n                assert(eval('eval(\"x\")') === \"o2\");\n            }\n        };\n        f();\n    }\n}\n\nfunction test_eval_closure()\n{\n    var tab;\n\n    tab = [];\n    for(let i = 0; i < 3; i++) {\n        eval(\"tab.push(function g1() { return i; })\");\n    }\n    for(let i = 0; i < 3; i++) {\n        assert(tab[i]() === i);\n    }\n\n    tab = [];\n    for(let i = 0; i < 3; i++) {\n        let f = function f() {\n            eval(\"tab.push(function g2() { return i; })\");\n        };\n        f();\n    }\n    for(let i = 0; i < 3; i++) {\n        assert(tab[i]() === i);\n    }\n}\n\nfunction test_eval_const()\n{\n    const a = 1;\n    var success = false;\n    var f = function () {\n        eval(\"a = 1\");\n    };\n    try {\n        f();\n    } catch(e) {\n        success = (e instanceof TypeError);\n    }\n    assert(success);\n}\n\ntest_closure1();\ntest_closure2();\ntest_closure3();\ntest_arrow_function();\ntest_with();\ntest_eval_closure();\ntest_eval_const();\n"
  },
  {
    "path": "tests/test_cyclic_import.js",
    "content": "/*---\nnegative:\n  phase: resolution\n  type: SyntaxError\n---*/\n// FIXME(bnoordhuis) shouldn't throw SyntaxError but that's still better\n// than segfaulting, see https://github.com/quickjs-ng/quickjs/issues/567\nimport {assert} from \"./assert.js\"\nimport {f} from \"./fixture_cyclic_import.js\"\nexport {f}\nexport function g(x) { return x + 1 }\nassert(f(1), 4)\n"
  },
  {
    "path": "tests/test_language.js",
    "content": "function assert(actual, expected, message) {\n    if (arguments.length == 1)\n        expected = true;\n\n    if (Object.is(actual, expected))\n        return;\n\n    if (actual !== null && expected !== null\n    &&  typeof actual == 'object' && typeof expected == 'object'\n    &&  actual.toString() === expected.toString())\n        return;\n\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\nfunction assert_throws(expected_error, func)\n{\n    var err = false;\n    try {\n        func();\n    } catch(e) {\n        err = true;\n        if (!(e instanceof expected_error)) {\n            throw Error(\"unexpected exception type\");\n        }\n    }\n    if (!err) {\n        throw Error(\"expected exception\");\n    }\n}\n\n// load more elaborate version of assert if available\ntry { __loadScript(\"test_assert.js\"); } catch(e) {}\n\n/*----------------*/\n\nfunction test_op1()\n{\n    var r, a;\n    r = 1 + 2;\n    assert(r, 3, \"1 + 2 === 3\");\n\n    r = 1 - 2;\n    assert(r, -1, \"1 - 2 === -1\");\n\n    r = -1;\n    assert(r, -1, \"-1 === -1\");\n\n    r = +2;\n    assert(r, 2, \"+2 === 2\");\n\n    r = 2 * 3;\n    assert(r, 6, \"2 * 3 === 6\");\n\n    r = 4 / 2;\n    assert(r, 2, \"4 / 2 === 2\");\n\n    r = 4 % 3;\n    assert(r, 1, \"4 % 3 === 3\");\n\n    r = 4 << 2;\n    assert(r, 16, \"4 << 2 === 16\");\n\n    r = 1 << 0;\n    assert(r, 1, \"1 << 0 === 1\");\n\n    r = 1 << 31;\n    assert(r, -2147483648, \"1 << 31 === -2147483648\");\n\n    r = 1 << 32;\n    assert(r, 1, \"1 << 32 === 1\");\n\n    r = (1 << 31) < 0;\n    assert(r, true, \"(1 << 31) < 0 === true\");\n\n    r = -4 >> 1;\n    assert(r, -2, \"-4 >> 1 === -2\");\n\n    r = -4 >>> 1;\n    assert(r, 0x7ffffffe, \"-4 >>> 1 === 0x7ffffffe\");\n\n    r = 1 & 1;\n    assert(r, 1, \"1 & 1 === 1\");\n\n    r = 0 | 1;\n    assert(r, 1, \"0 | 1 === 1\");\n\n    r = 1 ^ 1;\n    assert(r, 0, \"1 ^ 1 === 0\");\n\n    r = ~1;\n    assert(r, -2, \"~1 === -2\");\n\n    r = !1;\n    assert(r, false, \"!1 === false\");\n\n    assert((1 < 2), true, \"(1 < 2) === true\");\n\n    assert((2 > 1), true, \"(2 > 1) === true\");\n\n    assert(('b' > 'a'), true, \"('b' > 'a') === true\");\n\n    assert(2 ** 8, 256, \"2 ** 8 === 256\");\n}\n\nfunction test_cvt()\n{\n    assert((NaN | 0) === 0);\n    assert((Infinity | 0) === 0);\n    assert(((-Infinity) | 0) === 0);\n    assert((\"12345\" | 0) === 12345);\n    assert((\"0x12345\" | 0) === 0x12345);\n    assert(((4294967296 * 3 - 4) | 0) === -4);\n\n    assert((\"12345\" >>> 0) === 12345);\n    assert((\"0x12345\" >>> 0) === 0x12345);\n    assert((NaN >>> 0) === 0);\n    assert((Infinity >>> 0) === 0);\n    assert(((-Infinity) >>> 0) === 0);\n    assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4));\n    assert((19686109595169230000).toString() === \"19686109595169230000\");\n}\n\nfunction test_eq()\n{\n    assert(null == undefined);\n    assert(undefined == null);\n    assert(true == 1);\n    assert(0 == false);\n    assert(\"\" == 0);\n    assert(\"123\" == 123);\n    assert(\"122\" != 123);\n    assert((new Number(1)) == 1);\n    assert(2 == (new Number(2)));\n    assert((new String(\"abc\")) == \"abc\");\n    assert({} != \"abc\");\n}\n\nfunction test_inc_dec()\n{\n    var a, r;\n\n    a = 1;\n    r = a++;\n    assert(r === 1 && a === 2, true, \"++\");\n\n    a = 1;\n    r = ++a;\n    assert(r === 2 && a === 2, true, \"++\");\n\n    a = 1;\n    r = a--;\n    assert(r === 1 && a === 0, true, \"--\");\n\n    a = 1;\n    r = --a;\n    assert(r === 0 && a === 0, true, \"--\");\n\n    a = {x:true};\n    a.x++;\n    assert(a.x, 2, \"++\");\n\n    a = {x:true};\n    a.x--;\n    assert(a.x, 0, \"--\");\n\n    a = [true];\n    a[0]++;\n    assert(a[0], 2, \"++\");\n\n    a = {x:true};\n    r = a.x++;\n    assert(r === 1 && a.x === 2, true, \"++\");\n\n    a = {x:true};\n    r = a.x--;\n    assert(r === 1 && a.x === 0, true, \"--\");\n\n    a = [true];\n    r = a[0]++;\n    assert(r === 1 && a[0] === 2, true, \"++\");\n\n    a = [true];\n    r = a[0]--;\n    assert(r === 1 && a[0] === 0, true, \"--\");\n}\n\nfunction F(x)\n{\n    this.x = x;\n}\n\nfunction test_op2()\n{\n    var a, b;\n    a = new Object;\n    a.x = 1;\n    assert(a.x, 1, \"new\");\n    b = new F(2);\n    assert(b.x, 2, \"new\");\n\n    a = {x : 2};\n    assert((\"x\" in a), true, \"in\");\n    assert((\"y\" in a), false, \"in\");\n\n    a = {};\n    assert((a instanceof Object), true, \"instanceof\");\n    assert((a instanceof String), false, \"instanceof\");\n\n    assert((typeof 1), \"number\", \"typeof\");\n    assert((typeof Object), \"function\", \"typeof\");\n    assert((typeof null), \"object\", \"typeof\");\n    assert((typeof unknown_var), \"undefined\", \"typeof\");\n\n    a = {x: 1, if: 2, async: 3};\n    assert(a.if === 2);\n    assert(a.async === 3);\n}\n\nfunction test_delete()\n{\n    var a, err;\n\n    a = {x: 1, y: 1};\n    assert((delete a.x), true, \"delete\");\n    assert((\"x\" in a), false, \"delete\");\n\n    /* the following are not tested by test262 */\n    assert(delete \"abc\"[100], true);\n\n    err = false;\n    try {\n        delete null.a;\n    } catch(e) {\n        err = (e instanceof TypeError);\n    }\n    assert(err, true, \"delete\");\n\n    err = false;\n    try {\n        a = { f() { delete super.a; } };\n        a.f();\n    } catch(e) {\n        err = (e instanceof ReferenceError);\n    }\n    assert(err, true, \"delete\");\n}\n\nfunction test_constructor()\n{\n    function *G() {}\n    let ex\n    try { new G() } catch (ex_) { ex = ex_ }\n    assert(ex instanceof TypeError)\n    assert(ex.message, \"G is not a constructor\")\n}\n\nfunction test_prototype()\n{\n    var f = function f() { };\n    assert(f.prototype.constructor, f, \"prototype\");\n\n    var g = function g() { };\n    /* QuickJS bug */\n    Object.defineProperty(g, \"prototype\", { writable: false });\n    assert(g.prototype.constructor, g, \"prototype\");\n}\n\nfunction test_arguments()\n{\n    function f2() {\n        assert(arguments.length, 2, \"arguments\");\n        assert(arguments[0], 1, \"arguments\");\n        assert(arguments[1], 3, \"arguments\");\n    }\n    f2(1, 3);\n}\n\nfunction test_class()\n{\n    var o;\n    class C {\n        constructor() {\n            this.x = 10;\n        }\n        f() {\n            return 1;\n        }\n        static F() {\n            return -1;\n        }\n        get y() {\n            return 12;\n        }\n    };\n    class D extends C {\n        constructor() {\n            super();\n            this.z = 20;\n        }\n        g() {\n            return 2;\n        }\n        static G() {\n            return -2;\n        }\n        h() {\n            return super.f();\n        }\n        static H() {\n            return super[\"F\"]();\n        }\n    }\n\n    assert(C.F() === -1);\n    assert(Object.getOwnPropertyDescriptor(C.prototype, \"y\").get.name === \"get y\");\n\n    o = new C();\n    assert(o.f() === 1);\n    assert(o.x === 10);\n\n    assert(D.F() === -1);\n    assert(D.G() === -2);\n    assert(D.H() === -1);\n\n    o = new D();\n    assert(o.f() === 1);\n    assert(o.g() === 2);\n    assert(o.x === 10);\n    assert(o.z === 20);\n    assert(o.h() === 1);\n\n    /* test class name scope */\n    var E1 = class E { static F() { return E; } };\n    assert(E1 === E1.F());\n\n    class S {\n        static x = 42;\n        static y = S.x;\n        static z = this.x;\n    }\n    assert(S.x === 42);\n    assert(S.y === 42);\n    assert(S.z === 42);\n\n    class P {\n        get = () => \"123\";\n        static() { return 42; }\n    }\n    assert(new P().get() === \"123\");\n    assert(new P().static() === 42);\n};\n\nfunction test_template()\n{\n    var a, b;\n    b = 123;\n    a = `abc${b}d`;\n    assert(a, \"abc123d\");\n\n    a = String.raw `abc${b}d`;\n    assert(a, \"abc123d\");\n\n    a = \"aaa\";\n    b = \"bbb\";\n    assert(`aaa${a, b}ccc`, \"aaabbbccc\");\n}\n\nfunction test_template_skip()\n{\n    var a = \"Bar\";\n    var { b = `${a + `a${a}` }baz` } = {};\n    assert(b, \"BaraBarbaz\");\n}\n\nfunction test_object_literal()\n{\n    var x = 0, get = 1, set = 2, async = 3;\n    a = { get: 2, set: 3, async: 4, get a(){ return this.get} };\n    assert(JSON.stringify(a), '{\"get\":2,\"set\":3,\"async\":4,\"a\":2}');\n    assert(a.a === 2);\n\n    a = { x, get, set, async };\n    assert(JSON.stringify(a), '{\"x\":0,\"get\":1,\"set\":2,\"async\":3}');\n}\n\nfunction test_regexp_skip()\n{\n    var a, b;\n    [a, b = /abc\\(/] = [1];\n    assert(a === 1);\n\n    [a, b =/abc\\(/] = [2];\n    assert(a === 2);\n}\n\nfunction test_labels()\n{\n    do x: { break x; } while(0);\n    if (1)\n        x: { break x; }\n    else\n        x: { break x; }\n    with ({}) x: { break x; };\n    while (0) x: { break x; };\n}\n\nfunction test_labels2()\n{\n    while (1) label: break\n    var i = 0\n    while (i < 3) label: {\n        if (i > 0)\n            break\n        i++\n    }\n    assert(i, 1)\n    for (;;) label: break\n    for (i = 0; i < 3; i++) label: {\n        if (i > 0)\n            break\n    }\n    assert(i, 1)\n}\n\nfunction test_destructuring()\n{\n    function * g () { return 0; };\n    var [x] = g();\n    assert(x, void 0);\n}\n\nfunction test_spread()\n{\n    var x;\n    x = [1, 2, ...[3, 4]];\n    assert(x.toString(), \"1,2,3,4\");\n\n    x = [ ...[ , ] ];\n    assert(Object.getOwnPropertyNames(x).toString(), \"0,length\");\n}\n\nfunction test_function_length()\n{\n    assert( ((a, b = 1, c) => {}).length, 1);\n    assert( (([a,b]) => {}).length, 1);\n    assert( (({a,b}) => {}).length, 1);\n    assert( ((c, [a,b] = 1, d) => {}).length, 1);\n}\n\nfunction test_argument_scope()\n{\n    var f;\n    var c = \"global\";\n\n    (function() {\n        \"use strict\";\n        // XXX: node only throws in strict mode\n        f = function(a = eval(\"var arguments\")) {};\n        assert_throws(SyntaxError, f);\n    })();\n\n    f = function(a = eval(\"1\"), b = arguments[0]) { return b; };\n    assert(f(12), 12);\n\n    f = function(a, b = arguments[0]) { return b; };\n    assert(f(12), 12);\n\n    f = function(a, b = () => arguments) { return b; };\n    assert(f(12)()[0], 12);\n\n    f = function(a = eval(\"1\"), b = () => arguments) { return b; };\n    assert(f(12)()[0], 12);\n\n    (function() {\n        \"use strict\";\n        f = function(a = this) { return a; };\n        assert(f.call(123), 123);\n\n        f = function f(a = f) { return a; };\n        assert(f(), f);\n\n        f = function f(a = eval(\"f\")) { return a; };\n        assert(f(), f);\n    })();\n\n    f = (a = eval(\"var c = 1\"), probe = () => c) => {\n        var c = 2;\n        assert(c, 2);\n        assert(probe(), 1);\n    }\n    f();\n\n    f = (a = eval(\"var arguments = 1\"), probe = () => arguments) => {\n        var arguments = 2;\n        assert(arguments, 2);\n        assert(probe(), 1);\n    }\n    f();\n\n    f = function f(a = eval(\"var c = 1\"), b = c, probe = () => c) {\n        assert(b, 1);\n        assert(c, 1);\n        assert(probe(), 1)\n    }\n    f();\n\n    assert(c, \"global\");\n    f = function f(a, b = c, probe = () => c) {\n        eval(\"var c = 1\");\n        assert(c, 1);\n        assert(b, \"global\");\n        assert(probe(), \"global\")\n    }\n    f();\n    assert(c, \"global\");\n\n    f = function f(a = eval(\"var c = 1\"), probe = (d = eval(\"c\")) => d) {\n        assert(probe(), 1)\n    }\n    f();\n}\n\nfunction test_function_expr_name()\n{\n    var f;\n\n    /* non strict mode test : assignment to the function name silently\n       fails */\n\n    f = function myfunc() {\n        myfunc = 1;\n        return myfunc;\n    };\n    assert(f(), f);\n\n    f = function myfunc() {\n        myfunc = 1;\n        (() => {\n            myfunc = 1;\n        })();\n        return myfunc;\n    };\n    assert(f(), f);\n\n    f = function myfunc() {\n        eval(\"myfunc = 1\");\n        return myfunc;\n    };\n    assert(f(), f);\n\n    /* strict mode test : assignment to the function name raises a\n       TypeError exception */\n\n    f = function myfunc() {\n        \"use strict\";\n        myfunc = 1;\n    };\n    assert_throws(TypeError, f);\n\n    f = function myfunc() {\n        \"use strict\";\n        (() => {\n            myfunc = 1;\n        })();\n    };\n    assert_throws(TypeError, f);\n\n    f = function myfunc() {\n        \"use strict\";\n        eval(\"myfunc = 1\");\n    };\n    assert_throws(TypeError, f);\n}\n\nfunction test_parse_semicolon()\n{\n    /* 'yield' or 'await' may not be considered as a token if the\n       previous ';' is missing */\n    function *f()\n    {\n        function func() {\n        }\n        yield 1;\n        var h = x => x + 1\n        yield 2;\n    }\n    async function g()\n    {\n        function func() {\n        }\n        await 1;\n        var h = x => x + 1\n        await 2;\n    }\n}\n\nfunction test_parse_arrow_function()\n{\n    assert(typeof eval(\"() => {}\\n() => {}\"), \"function\");\n    assert(eval(\"() => {}\\n+1\"), 1);\n    assert(typeof eval(\"x => {}\\n() => {}\"), \"function\");\n    assert(typeof eval(\"async () => {}\\n() => {}\"), \"function\");\n    assert(typeof eval(\"async x => {}\\n() => {}\"), \"function\");\n}\n\n/* optional chaining tests not present in test262 */\nfunction test_optional_chaining()\n{\n    var a, z;\n    z = null;\n    a = { b: { c: 2 } };\n    assert(delete z?.b.c, true);\n    assert(delete a?.b.c, true);\n    assert(JSON.stringify(a), '{\"b\":{}}', \"optional chaining delete\");\n\n    a = { b: { c: 2 } };\n    assert(delete z?.b[\"c\"], true);\n    assert(delete a?.b[\"c\"], true);\n    assert(JSON.stringify(a), '{\"b\":{}}');\n\n    a = {\n        b() { return this._b; },\n        _b: { c: 42 }\n    };\n\n    assert((a?.b)().c, 42);\n\n    assert((a?.[\"b\"])().c, 42);\n}\n\nfunction test_unicode_ident()\n{\n    var Ãµ = 3;\n    assert(typeof õ, \"undefined\");\n}\n\n/* check global variable optimization */\nfunction test_global_var_opt()\n{\n    var v2;\n    (1, eval)('var gvar1'); /* create configurable global variables */\n\n    gvar1 = 1;\n    Object.defineProperty(globalThis, \"gvar1\", { writable: false });\n    gvar1 = 2;\n    assert(gvar1, 1);\n\n    Object.defineProperty(globalThis, \"gvar1\", { get: function() { return \"hello\" },\n                                                 set: function(v) { v2 = v; } });\n    assert(gvar1, \"hello\");\n    gvar1 = 3;\n    assert(v2, 3);\n\n    Object.defineProperty(globalThis, \"gvar1\", { value: 4, writable: true, configurable: true });\n    assert(gvar1, 4);\n    gvar1 = 6;\n    \n    delete gvar1;\n    assert_throws(ReferenceError, function() { return gvar1 });\n    gvar1 = 5;\n    assert(gvar1, 5);\n}\n\ntest_op1();\ntest_cvt();\ntest_eq();\ntest_inc_dec();\ntest_op2();\ntest_constructor();\ntest_delete();\ntest_prototype();\ntest_arguments();\ntest_class();\ntest_template();\ntest_template_skip();\ntest_object_literal();\ntest_regexp_skip();\ntest_labels();\ntest_labels2();\ntest_destructuring();\ntest_spread();\ntest_function_length();\ntest_argument_scope();\ntest_function_expr_name();\ntest_parse_semicolon();\ntest_optional_chaining();\ntest_parse_arrow_function();\ntest_unicode_ident();\ntest_global_var_opt();\n"
  },
  {
    "path": "tests/test_loop.js",
    "content": "function assert(actual, expected, message) {\n    if (arguments.length == 1)\n        expected = true;\n\n    if (actual === expected)\n        return;\n\n    if (actual !== null && expected !== null\n    &&  typeof actual == 'object' && typeof expected == 'object'\n    &&  actual.toString() === expected.toString())\n        return;\n\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\n// load more elaborate version of assert if available\ntry { __loadScript(\"test_assert.js\"); } catch(e) {}\n\n/*----------------*/\n\nfunction test_while()\n{\n    var i, c;\n    i = 0;\n    c = 0;\n    while (i < 3) {\n        c++;\n        i++;\n    }\n    assert(c === 3);\n}\n\nfunction test_while_break()\n{\n    var i, c;\n    i = 0;\n    c = 0;\n    while (i < 3) {\n        c++;\n        if (i == 1)\n            break;\n        i++;\n    }\n    assert(c === 2 && i === 1);\n}\n\nfunction test_do_while()\n{\n    var i, c;\n    i = 0;\n    c = 0;\n    do {\n        c++;\n        i++;\n    } while (i < 3);\n    assert(c === 3 && i === 3);\n}\n\nfunction test_for()\n{\n    var i, c;\n    c = 0;\n    for(i = 0; i < 3; i++) {\n        c++;\n    }\n    assert(c === 3 && i === 3);\n\n    c = 0;\n    for(var j = 0; j < 3; j++) {\n        c++;\n    }\n    assert(c === 3 && j === 3);\n}\n\nfunction test_for_in()\n{\n    var i, tab, a, b;\n\n    tab = [];\n    for(i in {x:1, y: 2}) {\n        tab.push(i);\n    }\n    assert(tab.toString(), \"x,y\", \"for_in\");\n\n    /* prototype chain test */\n    a = {x:2, y: 2, \"1\": 3};\n    b = {\"4\" : 3 };\n    Object.setPrototypeOf(a, b);\n    tab = [];\n    for(i in a) {\n        tab.push(i);\n    }\n    assert(tab.toString(), \"1,x,y,4\", \"for_in\");\n\n    /* non enumerable properties hide enumerables ones in the\n       prototype chain */\n    a = {y: 2, \"1\": 3};\n    Object.defineProperty(a, \"x\", { value: 1 });\n    b = {\"x\" : 3 };\n    Object.setPrototypeOf(a, b);\n    tab = [];\n    for(i in a) {\n        tab.push(i);\n    }\n    assert(tab.toString(), \"1,y\", \"for_in\");\n\n    /* array optimization */\n    a = [];\n    for(i = 0; i < 10; i++)\n        a.push(i);\n    tab = [];\n    for(i in a) {\n        tab.push(i);\n    }\n    assert(tab.toString(), \"0,1,2,3,4,5,6,7,8,9\", \"for_in\");\n\n    /* iterate with a field */\n    a={x:0};\n    tab = [];\n    for(a.x in {x:1, y: 2}) {\n        tab.push(a.x);\n    }\n    assert(tab.toString(), \"x,y\", \"for_in\");\n\n    /* iterate with a variable field */\n    a=[0];\n    tab = [];\n    for(a[0] in {x:1, y: 2}) {\n        tab.push(a[0]);\n    }\n    assert(tab.toString(), \"x,y\", \"for_in\");\n\n    /* variable definition in the for in */\n    tab = [];\n    for(var j in {x:1, y: 2}) {\n        tab.push(j);\n    }\n    assert(tab.toString(), \"x,y\", \"for_in\");\n\n    /* variable assigment in the for in */\n    tab = [];\n    for(var k = 2 in {x:1, y: 2}) {\n        tab.push(k);\n    }\n    assert(tab.toString(), \"x,y\", \"for_in\");\n}\n\nfunction test_for_in2()\n{\n    var i, tab;\n    tab = [];\n    for(i in {x:1, y: 2, z:3}) {\n        if (i === \"y\")\n            continue;\n        tab.push(i);\n    }\n    assert(tab.toString() == \"x,z\");\n\n    tab = [];\n    for(i in {x:1, y: 2, z:3}) {\n        if (i === \"z\")\n            break;\n        tab.push(i);\n    }\n    assert(tab.toString() == \"x,y\");\n}\n\nfunction test_for_in_proxy() {\n    let removed_key = \"\";\n    let target = {}\n    let proxy = new Proxy(target, {\n        ownKeys: function() {\n            return [\"a\", \"b\", \"c\"];\n        },\n        getOwnPropertyDescriptor: function(target, key) {\n            if (removed_key != \"\" && key == removed_key)\n                return undefined;\n            else\n                return { enumerable: true, configurable: true, value: this[key] };\n        }\n    });\n    let str = \"\";\n    for(let o in proxy) {\n        str += \" \" + o;\n        if (o == \"a\")\n            removed_key = \"b\";\n    }\n    assert(str == \" a c\");\n}\n\nfunction test_for_break()\n{\n    var i, c;\n    c = 0;\n    L1: for(i = 0; i < 3; i++) {\n        c++;\n        if (i == 0)\n            continue;\n        while (1) {\n            break L1;\n        }\n    }\n    assert(c === 2 && i === 1);\n}\n\nfunction test_switch1()\n{\n    var i, a, s;\n    s = \"\";\n    for(i = 0; i < 3; i++) {\n        a = \"?\";\n        switch(i) {\n        case 0:\n            a = \"a\";\n            break;\n        case 1:\n            a = \"b\";\n            break;\n        default:\n            a = \"c\";\n            break;\n        }\n        s += a;\n    }\n    assert(s === \"abc\" && i === 3);\n}\n\nfunction test_switch2()\n{\n    var i, a, s;\n    s = \"\";\n    for(i = 0; i < 4; i++) {\n        a = \"?\";\n        switch(i) {\n        case 0:\n            a = \"a\";\n            break;\n        case 1:\n            a = \"b\";\n            break;\n        case 2:\n            continue;\n        default:\n            a = \"\" + i;\n            break;\n        }\n        s += a;\n    }\n    assert(s === \"ab3\" && i === 4);\n}\n\nfunction test_try_catch1()\n{\n    try {\n        throw \"hello\";\n    } catch (e) {\n        assert(e, \"hello\", \"catch\");\n        return;\n    }\n    assert(false, \"catch\");\n}\n\nfunction test_try_catch2()\n{\n    var a;\n    try {\n        a = 1;\n    } catch (e) {\n        a = 2;\n    }\n    assert(a, 1, \"catch\");\n}\n\nfunction test_try_catch3()\n{\n    var s;\n    s = \"\";\n    try {\n        s += \"t\";\n    } catch (e) {\n        s += \"c\";\n    } finally {\n        s += \"f\";\n    }\n    assert(s, \"tf\", \"catch\");\n}\n\nfunction test_try_catch4()\n{\n    var s;\n    s = \"\";\n    try {\n        s += \"t\";\n        throw \"c\";\n    } catch (e) {\n        s += e;\n    } finally {\n        s += \"f\";\n    }\n    assert(s, \"tcf\", \"catch\");\n}\n\nfunction test_try_catch5()\n{\n    var s;\n    s = \"\";\n    for(;;) {\n        try {\n            s += \"t\";\n            break;\n            s += \"b\";\n        } finally {\n            s += \"f\";\n        }\n    }\n    assert(s, \"tf\", \"catch\");\n}\n\nfunction test_try_catch6()\n{\n    function f() {\n        try {\n            s += 't';\n            return 1;\n        } finally {\n            s += \"f\";\n        }\n    }\n    var s = \"\";\n    assert(f() === 1);\n    assert(s, \"tf\", \"catch6\");\n}\n\nfunction test_try_catch7()\n{\n    var s;\n    s = \"\";\n\n    try {\n        try {\n            s += \"t\";\n            throw \"a\";\n        } finally {\n            s += \"f\";\n        }\n    } catch(e) {\n        s += e;\n    } finally {\n        s += \"g\";\n    }\n    assert(s, \"tfag\", \"catch\");\n}\n\nfunction test_try_catch8()\n{\n    var i, s;\n\n    s = \"\";\n    for(var i in {x:1, y:2}) {\n        try {\n            s += i;\n            throw \"a\";\n        } catch (e) {\n            s += e;\n        } finally {\n            s += \"f\";\n        }\n    }\n    assert(s === \"xafyaf\");\n}\n\nfunction test_cyclic_labels()\n{\n    /* just check that it compiles without a crash */\n    for (;;) {\n        l: break l;\n        l: break l;\n        l: break l;\n    }\n}\n\ntest_while();\ntest_while_break();\ntest_do_while();\ntest_for();\ntest_for_break();\ntest_switch1();\ntest_switch2();\ntest_for_in();\ntest_for_in2();\ntest_for_in_proxy();\n\ntest_try_catch1();\ntest_try_catch2();\ntest_try_catch3();\ntest_try_catch4();\ntest_try_catch5();\ntest_try_catch6();\ntest_try_catch7();\ntest_try_catch8();\n"
  },
  {
    "path": "tests/test_std.js",
    "content": "#! (shebang test)\nimport * as std from \"std\";\nimport * as os from \"os\";\n\nfunction assert(actual, expected, message) {\n    if (arguments.length == 1)\n        expected = true;\n\n    if (Object.is(actual, expected))\n        return;\n\n    if (actual !== null && expected !== null\n    &&  typeof actual == 'object' && typeof expected == 'object'\n    &&  actual.toString() === expected.toString())\n        return;\n\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\n// load more elaborate version of assert if available\ntry { std.loadScript(\"test_assert.js\"); } catch(e) {}\n\n/*----------------*/\n\nfunction test_printf()\n{\n    assert(std.sprintf(\"a=%d s=%s\", 123, \"abc\"), \"a=123 s=abc\");\n    assert(std.sprintf(\"%010d\", 123), \"0000000123\");\n    assert(std.sprintf(\"%x\", -2), \"fffffffe\");\n    assert(std.sprintf(\"%lx\", -2), \"fffffffffffffffe\");\n    assert(std.sprintf(\"%10.1f\", 2.1), \"       2.1\");\n    assert(std.sprintf(\"%*.*f\", 10, 2, -2.13), \"     -2.13\");\n    assert(std.sprintf(\"%#lx\", 0x7fffffffffffffffn), \"0x7fffffffffffffff\");\n}\n\nfunction test_file1()\n{\n    var f, len, str, size, buf, ret, i, str1;\n\n    f = std.tmpfile();\n    str = \"hello world\\n\";\n    f.puts(str);\n\n    f.seek(0, std.SEEK_SET);\n    str1 = f.readAsString();\n    assert(str1 === str);\n\n    f.seek(0, std.SEEK_END);\n    size = f.tell();\n    assert(size === str.length);\n\n    f.seek(0, std.SEEK_SET);\n\n    buf = new Uint8Array(size);\n    ret = f.read(buf.buffer, 0, size);\n    assert(ret === size);\n    for(i = 0; i < size; i++)\n        assert(buf[i] === str.charCodeAt(i));\n\n    f.close();\n}\n\nfunction test_file2()\n{\n    var f, str, i, size;\n    f = std.tmpfile();\n    str = \"hello world\\n\";\n    size = str.length;\n    for(i = 0; i < size; i++)\n        f.putByte(str.charCodeAt(i));\n    f.seek(0, std.SEEK_SET);\n    for(i = 0; i < size; i++) {\n        assert(str.charCodeAt(i) === f.getByte());\n    }\n    assert(f.getByte() === -1);\n    f.close();\n}\n\nfunction test_getline()\n{\n    var f, line, line_count, lines, i;\n\n    lines = [\"hello world\", \"line 1\", \"line 2\" ];\n    f = std.tmpfile();\n    for(i = 0; i < lines.length; i++) {\n        f.puts(lines[i], \"\\n\");\n    }\n\n    f.seek(0, std.SEEK_SET);\n    assert(!f.eof());\n    line_count = 0;\n    for(;;) {\n        line = f.getline();\n        if (line === null)\n            break;\n        assert(line == lines[line_count]);\n        line_count++;\n    }\n    assert(f.eof());\n    assert(line_count === lines.length);\n\n    f.close();\n}\n\nfunction test_popen()\n{\n    var str, f, fname = \"tmp_file.txt\";\n    var content = \"hello world\";\n\n    f = std.open(fname, \"w\");\n    f.puts(content);\n    f.close();\n\n    /* test loadFile */\n    assert(std.loadFile(fname), content);\n\n    /* execute the 'cat' shell command */\n    f = std.popen(\"cat \" + fname, \"r\");\n    str = f.readAsString();\n    f.close();\n\n    assert(str, content);\n\n    os.remove(fname);\n}\n\nfunction test_ext_json()\n{\n    var expected, input, obj;\n    expected = '{\"x\":false,\"y\":true,\"z2\":null,\"a\":[1,8,160],\"b\":\"abc\\\\u000bd\",\"s\":\"str\"}';\n    input = `{ \"x\":false, /*comments are allowed */\n               \"y\":true,  // also a comment\n               z2:null, // unquoted property names\n               \"a\":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal\n               \"b\": \"ab\\\nc\\\\vd\", // multi-line strings, '\\v' escape\n               \"s\":'str',} // trailing comma in objects and arrays, single quoted string\n            `;\n    obj = std.parseExtJSON(input);\n    assert(JSON.stringify(obj), expected);\n\n    obj = std.parseExtJSON('[Infinity, +Infinity, -Infinity, NaN, +NaN, -NaN, .1, -.2]');\n    assert(obj[0], Infinity);\n    assert(obj[1], Infinity);\n    assert(obj[2], -Infinity);\n    assert(obj[3], NaN);\n    assert(obj[4], NaN);\n    assert(obj[5], NaN);\n    assert(obj[6], 0.1);\n    assert(obj[7], -0.2);\n}\n\nfunction test_os()\n{\n    var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;\n\n    const stdinIsTTY = !os.exec([\"/bin/sh\", \"-c\", \"test -t 0\"], { usePath: false });\n\n    assert(os.isatty(0), stdinIsTTY, `isatty(STDIN)`);\n\n    fdir = \"test_tmp_dir\";\n    fname = \"tmp_file.txt\";\n    fpath = fdir + \"/\" + fname;\n    link_path = fdir + \"/test_link\";\n\n    os.remove(link_path);\n    os.remove(fpath);\n    os.remove(fdir);\n\n    err = os.mkdir(fdir, 0o755);\n    assert(err === 0);\n\n    fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC);\n    assert(fd >= 0);\n\n    buf = new Uint8Array(10);\n    for(i = 0; i < buf.length; i++)\n        buf[i] = i;\n    assert(os.write(fd, buf.buffer, 0, buf.length) === buf.length);\n\n    assert(os.seek(fd, 0, std.SEEK_SET) === 0);\n    buf2 = new Uint8Array(buf.length);\n    assert(os.read(fd, buf2.buffer, 0, buf2.length) === buf2.length);\n\n    for(i = 0; i < buf.length; i++)\n        assert(buf[i] == buf2[i]);\n\n    if (typeof BigInt !== \"undefined\") {\n        assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6));\n        assert(os.read(fd, buf2.buffer, 0, 1) === 1);\n        assert(buf[6] == buf2[0]);\n    }\n\n    assert(os.close(fd) === 0);\n\n    [files, err] = os.readdir(fdir);\n    assert(err, 0);\n    assert(files.indexOf(fname) >= 0);\n\n    fdate = 10000;\n\n    err = os.utimes(fpath, fdate, fdate);\n    assert(err, 0);\n\n    [st, err] = os.stat(fpath);\n    assert(err, 0);\n    assert(st.mode & os.S_IFMT, os.S_IFREG);\n    assert(st.mtime, fdate);\n\n    err = os.symlink(fname, link_path);\n    assert(err === 0);\n\n    [st, err] = os.lstat(link_path);\n    assert(err, 0);\n    assert(st.mode & os.S_IFMT, os.S_IFLNK);\n\n    [buf, err] = os.readlink(link_path);\n    assert(err, 0);\n    assert(buf, fname);\n\n    assert(os.remove(link_path) === 0);\n\n    [buf, err] = os.getcwd();\n    assert(err, 0);\n\n    [buf2, err] = os.realpath(\".\");\n    assert(err, 0);\n\n    assert(buf, buf2);\n\n    assert(os.remove(fpath) === 0);\n\n    fd = os.open(fpath, os.O_RDONLY);\n    assert(fd < 0);\n\n    assert(os.remove(fdir) === 0);\n}\n\nfunction test_os_exec()\n{\n    var ret, fds, pid, f, status;\n\n    ret = os.exec([\"true\"]);\n    assert(ret, 0);\n\n    ret = os.exec([\"/bin/sh\", \"-c\", \"exit 1\"], { usePath: false });\n    assert(ret, 1);\n\n    fds = os.pipe();\n    pid = os.exec([\"sh\", \"-c\", \"echo $FOO\"], {\n        stdout: fds[1],\n        block: false,\n        env: { FOO: \"hello\" },\n    } );\n    assert(pid >= 0);\n    os.close(fds[1]); /* close the write end (as it is only in the child)  */\n    f = std.fdopen(fds[0], \"r\");\n    assert(f.getline(), \"hello\");\n    assert(f.getline(), null);\n    f.close();\n    [ret, status] = os.waitpid(pid, 0);\n    assert(ret, pid);\n    assert(status & 0x7f, 0); /* exited */\n    assert(status >> 8, 0); /* exit code */\n\n    pid = os.exec([\"cat\"], { block: false } );\n    assert(pid >= 0);\n    os.kill(pid, os.SIGTERM);\n    [ret, status] = os.waitpid(pid, 0);\n    assert(ret, pid);\n    assert(status !== 0, true, `expect nonzero exit code (got ${status})`);\n    assert(status & 0x7f, os.SIGTERM);\n}\n\nfunction test_timer()\n{\n    var th, i;\n\n    /* just test that a timer can be inserted and removed */\n    th = [];\n    for(i = 0; i < 3; i++)\n        th[i] = os.setTimeout(function () { }, 1000);\n    for(i = 0; i < 3; i++)\n        os.clearTimeout(th[i]);\n}\n\n/* test closure variable handling when freeing asynchronous\n   function */\nfunction test_async_gc()\n{\n    (async function run () {\n        let obj = {}\n\n        let done = () => {\n            obj\n            std.gc();\n        }\n\n        Promise.resolve().then(done)\n\n        const p = new Promise(() => {})\n\n        await p\n    })();\n}\n\n/* check that the promise async rejection handler is not invoked when\n   the rejection is handled not too late after the promise\n   rejection. */\nfunction test_async_promise_rejection()\n{\n    var counter = 0;\n    var p1, p2, p3;\n    p1 = Promise.reject();\n    p2 = Promise.reject();\n    p3 = Promise.resolve();\n    p1.catch(() => counter++);\n    p2.catch(() => counter++);\n    p3.then(() => counter++)\n    os.setTimeout(() => { assert(counter, 3) }, 10);\n}\n\ntest_printf();\ntest_file1();\ntest_file2();\ntest_getline();\ntest_popen();\ntest_os();\ntest_os_exec();\ntest_timer();\ntest_ext_json();\ntest_async_gc();\ntest_async_promise_rejection();\n\n"
  },
  {
    "path": "tests/test_worker.js",
    "content": "/* os.Worker API test */\nimport * as std from \"std\";\nimport * as os from \"os\";\n\nfunction assert(actual, expected, message) {\n    if (arguments.length == 1)\n        expected = true;\n\n    if (actual === expected)\n        return;\n\n    if (actual !== null && expected !== null\n    &&  typeof actual == 'object' && typeof expected == 'object'\n    &&  actual.toString() === expected.toString())\n        return;\n\n    throw Error(\"assertion failed: got |\" + actual + \"|\" +\n                \", expected |\" + expected + \"|\" +\n                (message ? \" (\" + message + \")\" : \"\"));\n}\n\nvar worker;\n\nfunction test_worker()\n{\n    var counter;\n\n    worker = new os.Worker(\"./test_worker_module.js\");\n\n    counter = 0;\n    worker.onmessage = function (e) {\n        var ev = e.data;\n//        print(\"recv\", JSON.stringify(ev));\n        switch(ev.type) {\n        case \"num\":\n            assert(ev.num, counter);\n            counter++;\n            if (counter == 10) {\n                /* test SharedArrayBuffer modification */\n                let sab = new SharedArrayBuffer(10);\n                let buf = new Uint8Array(sab);\n                worker.postMessage({ type: \"sab\", buf: buf });\n            }\n            break;\n        case \"sab_done\":\n            {\n                let buf = ev.buf;\n                /* check that the SharedArrayBuffer was modified */\n                assert(buf[2], 10);\n                worker.postMessage({ type: \"abort\" });\n            }\n            break;\n        case \"done\":\n            /* terminate */\n            worker.onmessage = null;\n            break;\n        }\n    };\n}\n\n\ntest_worker();\n"
  },
  {
    "path": "tests/test_worker_module.js",
    "content": "/* Worker code for test_worker.js */\nimport * as std from \"std\";\nimport * as os from \"os\";\n\nvar parent = os.Worker.parent;\n\nfunction handle_msg(e) {\n    var ev = e.data;\n    //          print(\"child_recv\", JSON.stringify(ev));\n    switch(ev.type) {\n    case \"abort\":\n        parent.postMessage({ type: \"done\" });\n        parent.onmessage = null; /* terminate the worker */\n        break;\n    case \"sab\":\n        /* modify the SharedArrayBuffer */\n        ev.buf[2] = 10;\n        parent.postMessage({ type: \"sab_done\", buf: ev.buf });\n        break;\n    }\n}\n\nfunction worker_main() {\n    var i;\n\n    parent.onmessage = handle_msg;\n    for(i = 0; i < 10; i++) {\n        parent.postMessage({ type: \"num\", num: i });\n    }\n}\n\nworker_main();\n"
  },
  {
    "path": "unicode_download.sh",
    "content": "#!/bin/sh\nset -e\n\nversion=\"17.0.0\"\nurl=\"ftp://ftp.unicode.org/Public\"\n\nfiles=\"CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \\\nSpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \\\nUnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \\\nPropertyValueAliases.txt\"\n\nmkdir -p unicode\n\nfor f in $files; do\n    g=\"${url}/${version}/ucd/${f}\"\n    wget $g -O unicode/$f\ndone\n\nwget \"${url}/${version}/ucd/emoji/emoji-data.txt\" -O unicode/emoji-data.txt\n\nwget \"${url}/${version}/emoji/emoji-sequences.txt\" -O unicode/emoji-sequences.txt\nwget \"${url}/${version}/emoji/emoji-zwj-sequences.txt\" -O unicode/emoji-zwj-sequences.txt\n"
  },
  {
    "path": "unicode_gen.c",
    "content": "/*\n * Generation of Unicode tables\n *\n * Copyright (c) 2017-2018 Fabrice Bellard\n * Copyright (c) 2017-2018 Charlie Gordon\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n * THE SOFTWARE.\n */\n#include <stdlib.h>\n#include <stdio.h>\n#include <stdarg.h>\n#include <inttypes.h>\n#include <string.h>\n#include <assert.h>\n#include <ctype.h>\n#include <time.h>\n\n#include \"cutils.h\"\n\nuint32_t total_tables;\nuint32_t total_table_bytes;\nuint32_t total_index;\nuint32_t total_index_bytes;\n\n/* define it to be able to test unicode.c */\n//#define USE_TEST\n/* profile tests */\n//#define PROFILE\n\n//#define DUMP_CASE_CONV_TABLE\n//#define DUMP_TABLE_SIZE\n//#define DUMP_CC_TABLE\n//#define DUMP_DECOMP_TABLE\n//#define DUMP_CASE_FOLDING_SPECIAL_CASES\n\n/* Ideas:\n   - Generalize run length encoding + index for all tables\n   - remove redundant tables for ID_start, ID_continue, Case_Ignorable, Cased\n\n   Case conversion:\n   - use a single entry for consecutive U/LF runs\n   - allow EXT runs of length > 1\n\n   Decomposition:\n   - Greek lower case (+1f10/1f10) ?\n   - allow holes in B runs\n   - suppress more upper / lower case redundancy\n*/\n\n#ifdef USE_TEST\n#include \"libunicode.c\"\n#endif\n\n#define CHARCODE_MAX 0x10ffff\n#define CC_LEN_MAX 3\n\nvoid *mallocz(size_t size)\n{\n    void *ptr;\n    ptr = malloc(size);\n    memset(ptr, 0, size);\n    return ptr;\n}\n\nconst char *get_field(const char *p, int n)\n{\n    int i;\n    for(i = 0; i < n; i++) {\n        while (*p != ';' && *p != '\\0')\n            p++;\n        if (*p == '\\0')\n            return NULL;\n        p++;\n    }\n    return p;\n}\n\nconst char *get_field_buf(char *buf, size_t buf_size, const char *p, int n)\n{\n    char *q;\n    p = get_field(p, n);\n    q = buf;\n    while (*p != ';' && *p != '\\0') {\n        if ((q - buf) < buf_size - 1)\n            *q++ = *p;\n        p++;\n    }\n    *q = '\\0';\n    return buf;\n}\n\nvoid add_char(int **pbuf, int *psize, int *plen, int c)\n{\n    int len, size, *buf;\n    buf = *pbuf;\n    size = *psize;\n    len = *plen;\n    if (len >= size) {\n        size = *psize;\n        size = max_int(len + 1, size * 3 / 2);\n        buf = realloc(buf, sizeof(buf[0]) * size);\n        *pbuf = buf;\n        *psize = size;\n    }\n    buf[len++] = c;\n    *plen = len;\n}\n\nint *get_field_str(int *plen, const char *str, int n)\n{\n    const char *p;\n    int *buf, len, size;\n    p = get_field(str, n);\n    if (!p) {\n        *plen = 0;\n        return NULL;\n    }\n    len = 0;\n    size = 0;\n    buf = NULL;\n    for(;;) {\n        while (isspace(*p))\n            p++;\n        if (!isxdigit(*p))\n            break;\n        add_char(&buf, &size, &len, strtoul(p, (char **)&p, 16));\n    }\n    *plen = len;\n    return buf;\n}\n\nchar *get_line(char *buf, int buf_size, FILE *f)\n{\n    int len;\n    if (!fgets(buf, buf_size, f))\n        return NULL;\n    len = strlen(buf);\n    if (len > 0 && buf[len - 1] == '\\n')\n        buf[len - 1] = '\\0';\n    return buf;\n}\n\ntypedef struct REString {\n    struct REString *next;\n    uint32_t hash;\n    uint32_t len;\n    uint32_t flags;\n    uint32_t buf[];\n} REString;\n\ntypedef struct {\n    uint32_t n_strings;\n    uint32_t hash_size;\n    int hash_bits;\n    REString **hash_table;\n} REStringList;\n\nstatic uint32_t re_string_hash(int len, const uint32_t *buf)\n{\n    int i;\n    uint32_t h;\n    h = 1;\n    for(i = 0; i < len; i++)\n        h = h * 263 + buf[i];\n    return h * 0x61C88647;\n}\n\nstatic void re_string_list_init(REStringList *s)\n{\n    s->n_strings = 0;\n    s->hash_size = 0;\n    s->hash_bits = 0;\n    s->hash_table = NULL;\n}\n\nstatic  __maybe_unused void re_string_list_free(REStringList *s)\n{\n    REString *p, *p_next;\n    int i;\n    for(i = 0; i < s->hash_size; i++) {\n        for(p = s->hash_table[i]; p != NULL; p = p_next) {\n            p_next = p->next;\n            free(p);\n        }\n    }\n    free(s->hash_table);\n}\n\nstatic void lre_print_char(int c, BOOL is_range)\n{\n    if (c == '\\'' || c == '\\\\' ||\n        (is_range && (c == '-' || c == ']'))) {\n        printf(\"\\\\%c\", c);\n    } else if (c >= ' ' && c <= 126) {\n        printf(\"%c\", c);\n    } else {\n        printf(\"\\\\u{%04x}\", c);\n    }\n}\n\nstatic __maybe_unused void re_string_list_dump(const char *str, const REStringList *s)\n{\n    REString *p;\n    int i, j, k;\n\n    printf(\"%s:\\n\", str);\n    \n    j = 0;\n    for(i = 0; i < s->hash_size; i++) {\n        for(p = s->hash_table[i]; p != NULL; p = p->next) {\n            printf(\"  %d/%d: '\", j, s->n_strings);\n            for(k = 0; k < p->len; k++) {\n                lre_print_char(p->buf[k], FALSE);\n            }\n            printf(\"'\\n\");\n            j++;\n        }\n    }\n}\n\nstatic REString *re_string_find2(REStringList *s, int len, const uint32_t *buf,\n                                 uint32_t h0, BOOL add_flag)\n{\n    uint32_t h = 0; /* avoid warning */\n    REString *p;\n    if (s->n_strings != 0) {\n        h = h0 >> (32 - s->hash_bits);\n        for(p = s->hash_table[h]; p != NULL; p = p->next) {\n            if (p->hash == h0 && p->len == len &&\n                !memcmp(p->buf, buf, len * sizeof(buf[0]))) {\n                return p;\n            }\n        }\n    }\n    /* not found */\n    if (!add_flag)\n        return NULL;\n    /* increase the size of the hash table if needed */\n    if (unlikely((s->n_strings + 1) > s->hash_size)) {\n        REString **new_hash_table, *p_next;\n        int new_hash_bits, i;\n        uint32_t new_hash_size;\n        new_hash_bits = max_int(s->hash_bits + 1, 4);\n        new_hash_size = 1 << new_hash_bits;\n        new_hash_table = malloc(sizeof(new_hash_table[0]) * new_hash_size);\n        if (!new_hash_table)\n            return NULL;\n        memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);\n        for(i = 0; i < s->hash_size; i++) {\n            for(p = s->hash_table[i]; p != NULL; p = p_next) {\n                p_next = p->next;\n                h = p->hash >> (32 - new_hash_bits);\n                p->next = new_hash_table[h];\n                new_hash_table[h] = p;\n            }\n        }\n        free(s->hash_table);\n        s->hash_bits = new_hash_bits;\n        s->hash_size = new_hash_size;\n        s->hash_table = new_hash_table;\n        h = h0 >> (32 - s->hash_bits);\n    }\n\n    p = malloc(sizeof(REString) + len * sizeof(buf[0]));\n    if (!p)\n        return NULL;\n    p->next = s->hash_table[h];\n    s->hash_table[h] = p;\n    s->n_strings++;\n    p->hash = h0;\n    p->len = len;\n    p->flags = 0;\n    memcpy(p->buf, buf, sizeof(buf[0]) * len);\n    return p;\n}\n\nstatic REString *re_string_find(REStringList *s, int len, const uint32_t *buf,\n                                BOOL add_flag)\n{\n    uint32_t h0;\n    h0 = re_string_hash(len, buf);\n    return re_string_find2(s, len, buf, h0, add_flag);\n}\n\nstatic void re_string_add(REStringList *s, int len, const uint32_t *buf)\n{\n    re_string_find(s, len, buf, TRUE);\n}\n\n#define UNICODE_GENERAL_CATEGORY\n\ntypedef enum {\n#define DEF(id, str) GCAT_ ## id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n    GCAT_COUNT,\n} UnicodeGCEnum1;\n\nstatic const char *unicode_gc_name[] = {\n#define DEF(id, str) #id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n};\n\nstatic const char *unicode_gc_short_name[] = {\n#define DEF(id, str) str,\n#include \"unicode_gen_def.h\"\n#undef DEF\n};\n\n#undef UNICODE_GENERAL_CATEGORY\n\n#define UNICODE_SCRIPT\n\ntypedef enum {\n#define DEF(id, str) SCRIPT_ ## id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n    SCRIPT_COUNT,\n} UnicodeScriptEnum1;\n\nstatic const char *unicode_script_name[] = {\n#define DEF(id, str) #id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n};\n\nconst char *unicode_script_short_name[] = {\n#define DEF(id, str) str,\n#include \"unicode_gen_def.h\"\n#undef DEF\n};\n\n#undef UNICODE_SCRIPT\n\n#define UNICODE_PROP_LIST\n\ntypedef enum {\n#define DEF(id, str) PROP_ ## id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n    PROP_COUNT,\n} UnicodePropEnum1;\n\nstatic const char *unicode_prop_name[] = {\n#define DEF(id, str) #id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n};\n\nstatic const char *unicode_prop_short_name[] = {\n#define DEF(id, str) str,\n#include \"unicode_gen_def.h\"\n#undef DEF\n};\n\n#undef UNICODE_PROP_LIST\n\n#define UNICODE_SEQUENCE_PROP_LIST\n\ntypedef enum {\n#define DEF(id) SEQUENCE_PROP_ ## id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n    SEQUENCE_PROP_COUNT,\n} UnicodeSequencePropEnum1;\n\nstatic const char *unicode_sequence_prop_name[] = {\n#define DEF(id) #id,\n#include \"unicode_gen_def.h\"\n#undef DEF\n};\n\n#undef UNICODE_SEQUENCE_PROP_LIST\n\ntypedef struct {\n    /* case conv */\n    uint8_t u_len;\n    uint8_t l_len;\n    uint8_t f_len;\n    int u_data[CC_LEN_MAX]; /* to upper case */\n    int l_data[CC_LEN_MAX]; /* to lower case */\n    int f_data[CC_LEN_MAX]; /* to case folding */\n\n    uint8_t combining_class;\n    uint8_t is_compat:1;\n    uint8_t is_excluded:1;\n    uint8_t general_category;\n    uint8_t script;\n    uint8_t script_ext_len;\n    uint8_t *script_ext;\n    uint32_t prop_bitmap_tab[3];\n    /* decomposition */\n    int decomp_len;\n    int *decomp_data;\n} CCInfo;\n\ntypedef struct {\n    int count;\n    int size;\n    int *tab;\n} UnicodeSequenceProperties;\n\nCCInfo *unicode_db;\nREStringList rgi_emoji_zwj_sequence;\nDynBuf rgi_emoji_tag_sequence;\n\nint find_name(const char **tab, int tab_len, const char *name)\n{\n    int i, len, name_len;\n    const char *p, *r;\n\n    name_len = strlen(name);\n    for(i = 0; i < tab_len; i++) {\n        p = tab[i];\n        for(;;) {\n            r = strchr(p, ',');\n            if (!r)\n                len = strlen(p);\n            else\n                len = r - p;\n            if (len == name_len && memcmp(p, name, len) == 0)\n                return i;\n            if (!r)\n                break;\n            p = r + 1;\n        }\n    }\n    return -1;\n}\n\nstatic BOOL get_prop(uint32_t c, int prop_idx)\n{\n    return (unicode_db[c].prop_bitmap_tab[prop_idx >> 5] >> (prop_idx & 0x1f)) & 1;\n}\n\nstatic void set_prop(uint32_t c, int prop_idx, int val)\n{\n    uint32_t mask;\n    mask = 1U << (prop_idx & 0x1f);\n    if (val)\n        unicode_db[c].prop_bitmap_tab[prop_idx >> 5] |= mask;\n    else\n        unicode_db[c].prop_bitmap_tab[prop_idx >> 5]  &= ~mask;\n}\n\nvoid parse_unicode_data(const char *filename)\n{\n    FILE *f;\n    char line[1024];\n    char buf1[256];\n    const char *p;\n    int code, lc, uc, last_code;\n    CCInfo *ci, *tab = unicode_db;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    last_code = 0;\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#')\n            continue;\n\n        p = get_field(line, 0);\n        if (!p)\n            continue;\n        code = strtoul(p, NULL, 16);\n        lc = 0;\n        uc = 0;\n\n        p = get_field(line, 12);\n        if (p && *p != ';') {\n            uc = strtoul(p, NULL, 16);\n        }\n\n        p = get_field(line, 13);\n        if (p && *p != ';') {\n            lc = strtoul(p, NULL, 16);\n        }\n        ci = &tab[code];\n        if (uc > 0 || lc > 0) {\n            assert(code <= CHARCODE_MAX);\n            if (uc > 0) {\n                assert(ci->u_len == 0);\n                ci->u_len = 1;\n                ci->u_data[0] = uc;\n            }\n            if (lc > 0) {\n                assert(ci->l_len == 0);\n                ci->l_len = 1;\n                ci->l_data[0] = lc;\n            }\n        }\n\n        {\n            int i;\n            get_field_buf(buf1, sizeof(buf1), line, 2);\n            i = find_name(unicode_gc_name, countof(unicode_gc_name), buf1);\n            if (i < 0) {\n                fprintf(stderr, \"General category '%s' not found\\n\",\n                        buf1);\n                exit(1);\n            }\n            ci->general_category = i;\n        }\n\n        p = get_field(line, 3);\n        if (p && *p != ';' && *p != '\\0') {\n            int cc;\n            cc = strtoul(p, NULL, 0);\n            if (cc != 0) {\n                assert(code <= CHARCODE_MAX);\n                ci->combining_class = cc;\n                //                printf(\"%05x: %d\\n\", code, ci->combining_class);\n            }\n        }\n\n        p = get_field(line, 5);\n        if (p && *p != ';' && *p != '\\0') {\n            int size;\n            assert(code <= CHARCODE_MAX);\n            ci->is_compat = 0;\n            if (*p == '<') {\n                while (*p != '\\0' && *p != '>')\n                    p++;\n                if (*p == '>')\n                    p++;\n                ci->is_compat = 1;\n            }\n            size = 0;\n            for(;;) {\n                while (isspace(*p))\n                    p++;\n                if (!isxdigit(*p))\n                    break;\n                add_char(&ci->decomp_data, &size, &ci->decomp_len, strtoul(p, (char **)&p, 16));\n            }\n#if 0\n            {\n                int i;\n                static int count, d_count;\n\n                printf(\"%05x: %c\", code, ci->is_compat ? 'C': ' ');\n                for(i = 0; i < ci->decomp_len; i++)\n                    printf(\" %05x\", ci->decomp_data[i]);\n                printf(\"\\n\");\n                count++;\n                d_count += ci->decomp_len;\n                //                printf(\"%d %d\\n\", count, d_count);\n            }\n#endif\n        }\n\n        p = get_field(line, 9);\n        if (p && *p == 'Y') {\n            set_prop(code, PROP_Bidi_Mirrored, 1);\n        }\n\n        /* handle ranges */\n        get_field_buf(buf1, sizeof(buf1), line, 1);\n        if (strstr(buf1, \" Last>\")) {\n            int i;\n            //            printf(\"range: 0x%x-%0x\\n\", last_code, code);\n            assert(ci->decomp_len == 0);\n            assert(ci->script_ext_len == 0);\n            for(i = last_code + 1; i < code; i++) {\n                unicode_db[i] = *ci;\n            }\n        }\n        last_code = code;\n    }\n\n    fclose(f);\n}\n\nvoid parse_special_casing(CCInfo *tab, const char *filename)\n{\n    FILE *f;\n    char line[1024];\n    const char *p;\n    int code;\n    CCInfo *ci;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#')\n            continue;\n\n        p = get_field(line, 0);\n        if (!p)\n            continue;\n        code = strtoul(p, NULL, 16);\n        assert(code <= CHARCODE_MAX);\n        ci = &tab[code];\n\n        p = get_field(line, 4);\n        if (p) {\n            /* locale dependent casing */\n            while (isspace(*p))\n                p++;\n            if (*p != '#' && *p != '\\0')\n                continue;\n        }\n\n\n        p = get_field(line, 1);\n        if (p && *p != ';') {\n            ci->l_len = 0;\n            for(;;) {\n                while (isspace(*p))\n                    p++;\n                if (*p == ';')\n                    break;\n                assert(ci->l_len < CC_LEN_MAX);\n                ci->l_data[ci->l_len++] = strtoul(p, (char **)&p, 16);\n            }\n\n            if (ci->l_len == 1 && ci->l_data[0] == code)\n                ci->l_len = 0;\n        }\n\n        p = get_field(line, 3);\n        if (p && *p != ';') {\n            ci->u_len = 0;\n            for(;;) {\n                while (isspace(*p))\n                    p++;\n                if (*p == ';')\n                    break;\n                assert(ci->u_len < CC_LEN_MAX);\n                ci->u_data[ci->u_len++] = strtoul(p, (char **)&p, 16);\n            }\n\n            if (ci->u_len == 1 && ci->u_data[0] == code)\n                ci->u_len = 0;\n        }\n    }\n\n    fclose(f);\n}\n\nvoid parse_case_folding(CCInfo *tab, const char *filename)\n{\n    FILE *f;\n    char line[1024];\n    const char *p;\n    int code, status;\n    CCInfo *ci;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#')\n            continue;\n\n        p = get_field(line, 0);\n        if (!p)\n            continue;\n        code = strtoul(p, NULL, 16);\n        assert(code <= CHARCODE_MAX);\n        ci = &tab[code];\n\n        p = get_field(line, 1);\n        if (!p)\n            continue;\n        /* locale dependent casing */\n        while (isspace(*p))\n            p++;\n        status = *p;\n        if (status != 'C' && status != 'S' && status != 'F')\n            continue;\n\n        p = get_field(line, 2);\n        assert(p != NULL);\n        if (status == 'S') {\n            /* we always select the simple case folding and assume it\n             * comes after the full case folding case */\n            assert(ci->f_len >= 2);\n            ci->f_len = 0;\n        } else {\n            assert(ci->f_len == 0);\n        }\n        for(;;) {\n            while (isspace(*p))\n                p++;\n            if (*p == ';')\n                break;\n            assert(ci->l_len < CC_LEN_MAX);\n            ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16);\n        }\n    }\n\n    fclose(f);\n}\n\nvoid parse_composition_exclusions(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p;\n    uint32_t c0;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@' || *p == '\\0')\n            continue;\n        c0 = strtoul(p, (char **)&p, 16);\n        assert(c0 > 0 && c0 <= CHARCODE_MAX);\n        unicode_db[c0].is_excluded = TRUE;\n    }\n    fclose(f);\n}\n\nvoid parse_derived_core_properties(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p, buf[256], *q;\n    uint32_t c0, c1, c;\n    int i;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@' || *p == '\\0')\n            continue;\n        c0 = strtoul(p, (char **)&p, 16);\n        if (*p == '.' && p[1] == '.') {\n            p += 2;\n            c1 = strtoul(p, (char **)&p, 16);\n        } else {\n            c1 = c0;\n        }\n        assert(c1 <= CHARCODE_MAX);\n        p += strspn(p, \" \\t\");\n        if (*p == ';') {\n            p++;\n            p += strspn(p, \" \\t\");\n            q = buf;\n            while (*p != '\\0' && *p != ' ' && *p != '#' && *p != '\\t' && *p != ';') {\n                if ((q - buf) < sizeof(buf) - 1)\n                    *q++ = *p;\n                p++;\n            }\n            *q = '\\0';\n            i = find_name(unicode_prop_name,\n                          countof(unicode_prop_name), buf);\n            if (i < 0) {\n                if (!strcmp(buf, \"Grapheme_Link\"))\n                    goto next;\n                fprintf(stderr, \"Property not found: %s\\n\", buf);\n                exit(1);\n            }\n            for(c = c0; c <= c1; c++) {\n                set_prop(c, i, 1);\n            }\nnext: ;\n        }\n    }\n    fclose(f);\n}\n\nvoid parse_derived_norm_properties(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p, buf[256], *q;\n    uint32_t c0, c1, c;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@' || *p == '\\0')\n            continue;\n        c0 = strtoul(p, (char **)&p, 16);\n        if (*p == '.' && p[1] == '.') {\n            p += 2;\n            c1 = strtoul(p, (char **)&p, 16);\n        } else {\n            c1 = c0;\n        }\n        assert(c1 <= CHARCODE_MAX);\n        p += strspn(p, \" \\t\");\n        if (*p == ';') {\n            p++;\n            p += strspn(p, \" \\t\");\n            q = buf;\n            while (*p != '\\0' && *p != ' ' && *p != '#' && *p != '\\t') {\n                if ((q - buf) < sizeof(buf) - 1)\n                    *q++ = *p;\n                p++;\n            }\n            *q = '\\0';\n            if (!strcmp(buf, \"Changes_When_NFKC_Casefolded\")) {\n                for(c = c0; c <= c1; c++) {\n                    set_prop(c, PROP_Changes_When_NFKC_Casefolded, 1);\n                }\n            }\n        }\n    }\n    fclose(f);\n}\n\nvoid parse_prop_list(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p, buf[256], *q;\n    uint32_t c0, c1, c;\n    int i;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@' || *p == '\\0')\n            continue;\n        c0 = strtoul(p, (char **)&p, 16);\n        if (*p == '.' && p[1] == '.') {\n            p += 2;\n            c1 = strtoul(p, (char **)&p, 16);\n        } else {\n            c1 = c0;\n        }\n        assert(c1 <= CHARCODE_MAX);\n        p += strspn(p, \" \\t\");\n        if (*p == ';') {\n            p++;\n            p += strspn(p, \" \\t\");\n            q = buf;\n            while (*p != '\\0' && *p != ' ' && *p != '#' && *p != '\\t') {\n                if ((q - buf) < sizeof(buf) - 1)\n                    *q++ = *p;\n                p++;\n            }\n            *q = '\\0';\n            i = find_name(unicode_prop_name,\n                          countof(unicode_prop_name), buf);\n            if (i < 0) {\n                fprintf(stderr, \"Property not found: %s\\n\", buf);\n                exit(1);\n            }\n            for(c = c0; c <= c1; c++) {\n                set_prop(c, i, 1);\n            }\n        }\n    }\n    fclose(f);\n}\n\n#define SEQ_MAX_LEN 16\n\nstatic BOOL is_emoji_modifier(uint32_t c)\n{\n    return (c >= 0x1f3fb && c <= 0x1f3ff);\n}\n\nstatic void add_sequence_prop(int idx, int seq_len, int *seq)\n{\n    int i;\n    \n    assert(idx < SEQUENCE_PROP_COUNT);\n    switch(idx) {\n    case SEQUENCE_PROP_Basic_Emoji:\n        /* convert to 2 properties lists */\n        if (seq_len == 1) {\n            set_prop(seq[0], PROP_Basic_Emoji1, 1);\n        } else if (seq_len == 2 && seq[1] == 0xfe0f) {\n            set_prop(seq[0], PROP_Basic_Emoji2, 1);\n        } else {\n            abort();\n        }\n        break;\n    case SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence:\n        assert(seq_len == 2);\n        assert(is_emoji_modifier(seq[1]));\n        assert(get_prop(seq[0], PROP_Emoji_Modifier_Base));\n        set_prop(seq[0], PROP_RGI_Emoji_Modifier_Sequence, 1);\n        break;\n    case SEQUENCE_PROP_RGI_Emoji_Flag_Sequence:\n        {\n            int code;\n            assert(seq_len == 2);\n            assert(seq[0] >= 0x1F1E6 && seq[0] <= 0x1F1FF);\n            assert(seq[1] >= 0x1F1E6 && seq[1] <= 0x1F1FF);\n            code = (seq[0] - 0x1F1E6) * 26 + (seq[1] - 0x1F1E6);\n            /* XXX: would be more compact with a simple bitmap -> 676 bits */\n            set_prop(code, PROP_RGI_Emoji_Flag_Sequence, 1);\n        }\n        break;\n    case SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence:\n        re_string_add(&rgi_emoji_zwj_sequence, seq_len, (uint32_t *)seq);\n        break;\n    case SEQUENCE_PROP_RGI_Emoji_Tag_Sequence:\n        {\n            assert(seq_len >= 3);\n            assert(seq[0] == 0x1F3F4);\n            assert(seq[seq_len - 1] == 0xE007F);\n            for(i = 1; i < seq_len - 1; i++) {\n                assert(seq[i] >= 0xe0001 && seq[i] <= 0xe007e);\n                dbuf_putc(&rgi_emoji_tag_sequence, seq[i] - 0xe0000);\n            }\n            dbuf_putc(&rgi_emoji_tag_sequence, 0);\n        }\n        break;\n    case SEQUENCE_PROP_Emoji_Keycap_Sequence:\n        assert(seq_len == 3);\n        assert(seq[1] == 0xfe0f);\n        assert(seq[2] == 0x20e3);\n        set_prop(seq[0], PROP_Emoji_Keycap_Sequence, 1);\n        break;\n    default:\n        assert(0);\n    }\n}\n\nvoid parse_sequence_prop_list(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p, buf[256], *q, *p_start;\n    uint32_t c0, c1, c;\n    int idx, seq_len;\n    int seq[SEQ_MAX_LEN];\n    \n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@' || *p == '\\0')\n            continue;\n        p_start = p;\n\n        /* find the sequence property name */\n        p = strchr(p, ';');\n        if (!p)\n            continue;\n        p++;\n        p += strspn(p, \" \\t\");\n        q = buf;\n        while (*p != '\\0' && *p != ' ' && *p != '#' && *p != '\\t' && *p != ';') {\n            if ((q - buf) < sizeof(buf) - 1)\n                *q++ = *p;\n            p++;\n        }\n        *q = '\\0';\n        idx = find_name(unicode_sequence_prop_name,\n                      countof(unicode_sequence_prop_name), buf);\n        if (idx < 0) {\n            fprintf(stderr, \"Property not found: %s\\n\", buf);\n            exit(1);\n        }\n        \n        p = p_start;\n        c0 = strtoul(p, (char **)&p, 16);\n        assert(c0 <= CHARCODE_MAX);\n        \n        if (*p == '.' && p[1] == '.') {\n            p += 2;\n            c1 = strtoul(p, (char **)&p, 16);\n            assert(c1 <= CHARCODE_MAX);\n            for(c = c0; c <= c1; c++) {\n                seq[0] = c;\n                add_sequence_prop(idx, 1, seq);\n            }\n        } else {\n            seq_len = 0;\n            seq[seq_len++] = c0;\n            for(;;) {\n                while (isspace(*p))\n                    p++;\n                if (*p == ';' || *p == '\\0')\n                    break;\n                c0 = strtoul(p, (char **)&p, 16);\n                assert(c0 <= CHARCODE_MAX);\n                assert(seq_len < countof(seq));\n                seq[seq_len++] = c0;\n            }\n            add_sequence_prop(idx, seq_len, seq);\n        }\n    }\n    fclose(f);\n}\n\nvoid parse_scripts(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p, buf[256], *q;\n    uint32_t c0, c1, c;\n    int i;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@' || *p == '\\0')\n            continue;\n        c0 = strtoul(p, (char **)&p, 16);\n        if (*p == '.' && p[1] == '.') {\n            p += 2;\n            c1 = strtoul(p, (char **)&p, 16);\n        } else {\n            c1 = c0;\n        }\n        assert(c1 <= CHARCODE_MAX);\n        p += strspn(p, \" \\t\");\n        if (*p == ';') {\n            p++;\n            p += strspn(p, \" \\t\");\n            q = buf;\n            while (*p != '\\0' && *p != ' ' && *p != '#' && *p != '\\t') {\n                if ((q - buf) < sizeof(buf) - 1)\n                    *q++ = *p;\n                p++;\n            }\n            *q = '\\0';\n            i = find_name(unicode_script_name,\n                          countof(unicode_script_name), buf);\n            if (i < 0) {\n                fprintf(stderr, \"Unknown script: '%s'\\n\", buf);\n                exit(1);\n            }\n            for(c = c0; c <= c1; c++)\n                unicode_db[c].script = i;\n        }\n    }\n    fclose(f);\n}\n\nvoid parse_script_extensions(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p, buf[256], *q;\n    uint32_t c0, c1, c;\n    int i;\n    uint8_t script_ext[255];\n    int script_ext_len;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@' || *p == '\\0')\n            continue;\n        c0 = strtoul(p, (char **)&p, 16);\n        if (*p == '.' && p[1] == '.') {\n            p += 2;\n            c1 = strtoul(p, (char **)&p, 16);\n        } else {\n            c1 = c0;\n        }\n        assert(c1 <= CHARCODE_MAX);\n        p += strspn(p, \" \\t\");\n        script_ext_len = 0;\n        if (*p == ';') {\n            p++;\n            for(;;) {\n                p += strspn(p, \" \\t\");\n                q = buf;\n                while (*p != '\\0' && *p != ' ' && *p != '#' && *p != '\\t') {\n                    if ((q - buf) < sizeof(buf) - 1)\n                        *q++ = *p;\n                    p++;\n                }\n                *q = '\\0';\n                if (buf[0] == '\\0')\n                    break;\n                i = find_name(unicode_script_short_name,\n                              countof(unicode_script_short_name), buf);\n                if (i < 0) {\n                    fprintf(stderr, \"Script not found: %s\\n\", buf);\n                    exit(1);\n                }\n                assert(script_ext_len < sizeof(script_ext));\n                script_ext[script_ext_len++] = i;\n            }\n            for(c = c0; c <= c1; c++) {\n                CCInfo *ci = &unicode_db[c];\n                ci->script_ext_len = script_ext_len;\n                ci->script_ext = malloc(sizeof(ci->script_ext[0]) * script_ext_len);\n                for(i = 0; i < script_ext_len; i++)\n                    ci->script_ext[i] = script_ext[i];\n            }\n        }\n    }\n    fclose(f);\n}\n\nvoid dump_cc_info(CCInfo *ci, int i)\n{\n    int j;\n    printf(\"%05x:\", i);\n    if (ci->u_len != 0) {\n        printf(\" U:\");\n        for(j = 0; j < ci->u_len; j++)\n            printf(\" %05x\", ci->u_data[j]);\n    }\n    if (ci->l_len != 0) {\n        printf(\" L:\");\n        for(j = 0; j < ci->l_len; j++)\n            printf(\" %05x\", ci->l_data[j]);\n    }\n    if (ci->f_len != 0) {\n        printf(\" F:\");\n        for(j = 0; j < ci->f_len; j++)\n            printf(\" %05x\", ci->f_data[j]);\n    }\n    printf(\"\\n\");\n}\n\nvoid dump_unicode_data(CCInfo *tab)\n{\n    int i;\n    CCInfo *ci;\n    for(i = 0; i <= CHARCODE_MAX; i++) {\n        ci = &tab[i];\n        if (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0) {\n            dump_cc_info(ci, i);\n        }\n    }\n}\n\nBOOL is_complicated_case(const CCInfo *ci)\n{\n    return (ci->u_len > 1 || ci->l_len > 1 ||\n            (ci->u_len > 0 && ci->l_len > 0) ||\n            (ci->f_len != ci->l_len) ||\n            (memcmp(ci->f_data, ci->l_data, ci->f_len * sizeof(ci->f_data[0])) != 0));\n}\n\n#ifndef USE_TEST\nenum {\n    RUN_TYPE_U,\n    RUN_TYPE_L,\n    RUN_TYPE_UF,\n    RUN_TYPE_LF,\n    RUN_TYPE_UL,\n    RUN_TYPE_LSU,\n    RUN_TYPE_U2L_399_EXT2,\n    RUN_TYPE_UF_D20,\n    RUN_TYPE_UF_D1_EXT,\n    RUN_TYPE_U_EXT,\n    RUN_TYPE_LF_EXT,\n    RUN_TYPE_UF_EXT2,\n    RUN_TYPE_LF_EXT2,\n    RUN_TYPE_UF_EXT3,\n};\n#endif\n\nconst char *run_type_str[] = {\n    \"U\",\n    \"L\",\n    \"UF\",\n    \"LF\",\n    \"UL\",\n    \"LSU\",\n    \"U2L_399_EXT2\",\n    \"UF_D20\",\n    \"UF_D1_EXT\",\n    \"U_EXT\",\n    \"LF_EXT\",\n    \"UF_EXT2\",\n    \"LF_EXT2\",\n    \"UF_EXT3\",\n};\n\ntypedef struct {\n    int code;\n    int len;\n    int type;\n    int data;\n    int ext_len;\n    int ext_data[3];\n    int data_index; /* 'data' coming from the table */\n} TableEntry;\n\nstatic int simple_to_lower(CCInfo *tab, int c)\n{\n    if (tab[c].l_len != 1)\n        return c;\n    return tab[c].l_data[0];\n}\n\n/* code (17), len (7), type (4) */\n\nvoid find_run_type(TableEntry *te, CCInfo *tab, int code)\n{\n    int is_lower, len;\n    CCInfo *ci, *ci1, *ci2;\n\n    ci = &tab[code];\n    ci1 = &tab[code + 1];\n    ci2 = &tab[code + 2];\n    te->code = code;\n\n    if (ci->l_len == 1 && ci->l_data[0] == code + 2 &&\n        ci->f_len == 1 && ci->f_data[0] == ci->l_data[0] &&\n        ci->u_len == 0 &&\n\n        ci1->l_len == 1 && ci1->l_data[0] == code + 2 &&\n        ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0] &&\n        ci1->u_len == 1 && ci1->u_data[0] == code &&\n\n        ci2->l_len == 0 &&\n        ci2->f_len == 0 &&\n        ci2->u_len == 1 && ci2->u_data[0] == code) {\n        te->len = 3;\n        te->data = 0;\n        te->type = RUN_TYPE_LSU;\n        return;\n    }\n\n    if (is_complicated_case(ci)) {\n        len = 1;\n        while (code + len <= CHARCODE_MAX) {\n            ci1 = &tab[code + len];\n            if (ci1->u_len != 1 ||\n                ci1->u_data[0] != ci->u_data[0] + len ||\n                ci1->l_len != 0 ||\n                ci1->f_len != 1 || ci1->f_data[0] != ci1->u_data[0])\n                break;\n            len++;\n        }\n        if (len > 1) {\n            te->len = len;\n            te->type = RUN_TYPE_UF;\n            te->data = ci->u_data[0];\n            return;\n        }\n\n        if (ci->l_len == 0 &&\n            ci->u_len == 2 && ci->u_data[1] == 0x399 &&\n            ci->f_len == 2 && ci->f_data[1] == 0x3B9 &&\n            ci->f_data[0] == simple_to_lower(tab, ci->u_data[0])) {\n            len = 1;\n            while (code + len <= CHARCODE_MAX) {\n                ci1 = &tab[code + len];\n                if (!(ci1->u_len == 2 &&\n                      ci1->u_data[1] == ci->u_data[1] &&\n                      ci1->u_data[0] == ci->u_data[0] + len &&\n                      ci1->f_len == 2 &&\n                      ci1->f_data[1] == ci->f_data[1] &&\n                      ci1->f_data[0] == ci->f_data[0] + len &&\n                      ci1->l_len == 0))\n                    break;\n                len++;\n            }\n            te->len = len;\n            te->type = RUN_TYPE_UF_EXT2;\n            te->ext_data[0] = ci->u_data[0];\n            te->ext_data[1] = ci->u_data[1];\n            te->ext_len = 2;\n            return;\n        }\n\n        if (ci->u_len == 2 && ci->u_data[1] == 0x399 &&\n            ci->l_len == 1 &&\n            ci->f_len == 1 && ci->f_data[0] == ci->l_data[0]) {\n            len = 1;\n            while (code + len <= CHARCODE_MAX) {\n                ci1 = &tab[code + len];\n                if (!(ci1->u_len == 2 &&\n                      ci1->u_data[1] == 0x399 &&\n                      ci1->u_data[0] == ci->u_data[0] + len &&\n                      ci1->l_len == 1 &&\n                      ci1->l_data[0] == ci->l_data[0] + len &&\n                      ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0]))\n                    break;\n                len++;\n            }\n            te->len = len;\n            te->type = RUN_TYPE_U2L_399_EXT2;\n            te->ext_data[0] = ci->u_data[0];\n            te->ext_data[1] = ci->l_data[0];\n            te->ext_len = 2;\n            return;\n        }\n\n        if (ci->l_len == 1 && ci->u_len == 0 && ci->f_len == 0) {\n            len = 1;\n            while (code + len <= CHARCODE_MAX) {\n                ci1 = &tab[code + len];\n                if (!(ci1->l_len == 1 &&\n                      ci1->l_data[0] == ci->l_data[0] + len &&\n                      ci1->u_len == 0 && ci1->f_len == 0))\n                    break;\n                len++;\n            }\n            te->len = len;\n            te->type = RUN_TYPE_L;\n            te->data = ci->l_data[0];\n            return;\n        }\n\n        if (ci->l_len == 0 &&\n            ci->u_len == 1 &&\n            ci->u_data[0] < 0x1000 &&\n            ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 0x20) {\n            te->len = 1;\n            te->type = RUN_TYPE_UF_D20;\n            te->data = ci->u_data[0];\n        } else if (ci->l_len == 0 &&\n                   ci->u_len == 1 &&\n                   ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 1) {\n            te->len = 1;\n            te->type = RUN_TYPE_UF_D1_EXT;\n            te->ext_data[0] = ci->u_data[0];\n            te->ext_len = 1;\n        } else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_len == 2 &&\n                   ci->l_data[0] == ci->f_data[0] &&\n                   ci->l_data[1] == ci->f_data[1]) {\n            te->len = 1;\n            te->type = RUN_TYPE_LF_EXT2;\n            te->ext_data[0] = ci->l_data[0];\n            te->ext_data[1] = ci->l_data[1];\n            te->ext_len = 2;\n        } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 2 &&\n                   ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) &&\n                   ci->f_data[1] == simple_to_lower(tab, ci->u_data[1])) {\n            te->len = 1;\n            te->type = RUN_TYPE_UF_EXT2;\n            te->ext_data[0] = ci->u_data[0];\n            te->ext_data[1] = ci->u_data[1];\n            te->ext_len = 2;\n        } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 3 &&\n                   ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) &&\n                   ci->f_data[1] == simple_to_lower(tab, ci->u_data[1]) &&\n                   ci->f_data[2] == simple_to_lower(tab, ci->u_data[2])) {\n            te->len = 1;\n            te->type = RUN_TYPE_UF_EXT3;\n            te->ext_data[0] = ci->u_data[0];\n            te->ext_data[1] = ci->u_data[1];\n            te->ext_data[2] = ci->u_data[2];\n            te->ext_len = 3;\n        } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 1) {\n            // U+FB05 LATIN SMALL LIGATURE LONG S T\n            assert(code == 0xFB05);\n            te->len = 1;\n            te->type = RUN_TYPE_UF_EXT2;\n            te->ext_data[0] = ci->u_data[0];\n            te->ext_data[1] = ci->u_data[1];\n            te->ext_len = 2;\n        } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 1) {\n            // U+1FD3 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA or\n            // U+1FE3 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA\n            assert(code == 0x1FD3 || code == 0x1FE3);\n            te->len = 1;\n            te->type = RUN_TYPE_UF_EXT3;\n            te->ext_data[0] = ci->u_data[0];\n            te->ext_data[1] = ci->u_data[1];\n            te->ext_data[2] = ci->u_data[2];\n            te->ext_len = 3;\n        } else {\n            printf(\"unsupported encoding case:\\n\");\n            dump_cc_info(ci, code);\n            abort();\n        }\n    } else {\n        /* look for a run of identical conversions */\n        len = 0;\n        for(;;) {\n            if (code >= CHARCODE_MAX || len >= 126)\n                break;\n            ci = &tab[code + len];\n            ci1 = &tab[code + len + 1];\n            if (is_complicated_case(ci) || is_complicated_case(ci1)) {\n                break;\n            }\n            if (ci->l_len != 1 || ci->l_data[0] != code + len + 1)\n                break;\n            if (ci1->u_len != 1 || ci1->u_data[0] != code + len)\n                break;\n            len += 2;\n        }\n        if (len > 0) {\n            te->len = len;\n            te->type = RUN_TYPE_UL;\n            te->data = 0;\n            return;\n        }\n\n        ci = &tab[code];\n        is_lower = ci->l_len > 0;\n        len = 1;\n        while (code + len <= CHARCODE_MAX) {\n            ci1 = &tab[code + len];\n            if (is_complicated_case(ci1))\n                break;\n            if (is_lower) {\n                if (ci1->l_len != 1 ||\n                    ci1->l_data[0] != ci->l_data[0] + len)\n                    break;\n            } else {\n                if (ci1->u_len != 1 ||\n                    ci1->u_data[0] != ci->u_data[0] + len)\n                    break;\n            }\n            len++;\n        }\n        te->len = len;\n        if (is_lower) {\n            te->type = RUN_TYPE_LF;\n            te->data = ci->l_data[0];\n        } else {\n            te->type = RUN_TYPE_U;\n            te->data = ci->u_data[0];\n        }\n    }\n}\n\nTableEntry conv_table[1000];\nint conv_table_len;\nint ext_data[1000];\nint ext_data_len;\n\nvoid dump_case_conv_table1(void)\n{\n    int i, j;\n    const TableEntry *te;\n\n    for(i = 0; i < conv_table_len; i++) {\n        te = &conv_table[i];\n        printf(\"%05x %02x %-10s %05x\",\n               te->code, te->len, run_type_str[te->type], te->data);\n        for(j = 0; j < te->ext_len; j++) {\n            printf(\" %05x\", te->ext_data[j]);\n        }\n        printf(\"\\n\");\n    }\n    printf(\"table_len=%d ext_len=%d\\n\", conv_table_len, ext_data_len);\n}\n\nint find_data_index(const TableEntry *conv_table, int len, int data)\n{\n    int i;\n    const TableEntry *te;\n    for(i = 0; i < len; i++) {\n        te = &conv_table[i];\n        if (te->code == data)\n            return i;\n    }\n    return -1;\n}\n\nint find_ext_data_index(int data)\n{\n    int i;\n    for(i = 0; i < ext_data_len; i++) {\n        if (ext_data[i] == data)\n            return i;\n    }\n    assert(ext_data_len < countof(ext_data));\n    ext_data[ext_data_len++] = data;\n    return ext_data_len - 1;\n}\n\nvoid build_conv_table(CCInfo *tab)\n{\n    int code, i, j;\n    CCInfo *ci;\n    TableEntry *te;\n\n    te = conv_table;\n    for(code = 0; code <= CHARCODE_MAX; code++) {\n        ci = &tab[code];\n        if (ci->u_len == 0 && ci->l_len == 0 && ci->f_len == 0)\n            continue;\n        assert(te - conv_table < countof(conv_table));\n        find_run_type(te, tab, code);\n#if 0\n        if (te->type == RUN_TYPE_TODO) {\n            printf(\"TODO: \");\n            dump_cc_info(ci, code);\n        }\n#endif\n        assert(te->len <= 127);\n        code += te->len - 1;\n        te++;\n    }\n    conv_table_len = te - conv_table;\n\n    /* find the data index */\n    for(i = 0; i < conv_table_len; i++) {\n        int data_index;\n        te = &conv_table[i];\n\n        switch(te->type) {\n        case RUN_TYPE_U:\n        case RUN_TYPE_L:\n        case RUN_TYPE_UF:\n        case RUN_TYPE_LF:\n            data_index = find_data_index(conv_table, conv_table_len, te->data);\n            if (data_index < 0) {\n                switch(te->type) {\n                case RUN_TYPE_U:\n                    te->type = RUN_TYPE_U_EXT;\n                    te->ext_len = 1;\n                    te->ext_data[0] = te->data;\n                    break;\n                case RUN_TYPE_LF:\n                    te->type = RUN_TYPE_LF_EXT;\n                    te->ext_len = 1;\n                    te->ext_data[0] = te->data;\n                    break;\n                default:\n                    printf(\"%05x: index not found\\n\", te->code);\n                    exit(1);\n                }\n            } else {\n                te->data_index = data_index;\n            }\n            break;\n        case RUN_TYPE_UF_D20:\n            te->data_index = te->data;\n            break;\n        }\n    }\n\n    /* find the data index for ext_data */\n    for(i = 0; i < conv_table_len; i++) {\n        te = &conv_table[i];\n        if (te->type == RUN_TYPE_UF_EXT3) {\n            int p, v;\n            v = 0;\n            for(j = 0; j < 3; j++) {\n                p = find_ext_data_index(te->ext_data[j]);\n                assert(p < 16);\n                v = (v << 4) | p;\n            }\n            te->data_index = v;\n        }\n    }\n\n    for(i = 0; i < conv_table_len; i++) {\n        te = &conv_table[i];\n        if (te->type == RUN_TYPE_LF_EXT2 ||\n            te->type == RUN_TYPE_UF_EXT2 ||\n            te->type == RUN_TYPE_U2L_399_EXT2) {\n            int p, v;\n            v = 0;\n            for(j = 0; j < 2; j++) {\n                p = find_ext_data_index(te->ext_data[j]);\n                assert(p < 64);\n                v = (v << 6) | p;\n            }\n            te->data_index = v;\n        }\n    }\n\n    for(i = 0; i < conv_table_len; i++) {\n        te = &conv_table[i];\n        if (te->type == RUN_TYPE_UF_D1_EXT ||\n            te->type == RUN_TYPE_U_EXT ||\n            te->type == RUN_TYPE_LF_EXT) {\n            te->data_index = find_ext_data_index(te->ext_data[0]);\n        }\n    }\n#ifdef DUMP_CASE_CONV_TABLE\n    dump_case_conv_table1();\n#endif\n}\n\nvoid dump_case_conv_table(FILE *f)\n{\n    int i;\n    uint32_t v;\n    const TableEntry *te;\n\n    total_tables++;\n    total_table_bytes += conv_table_len * sizeof(uint32_t);\n    fprintf(f, \"static const uint32_t case_conv_table1[%d] = {\", conv_table_len);\n    for(i = 0; i < conv_table_len; i++) {\n        if (i % 4 == 0)\n            fprintf(f, \"\\n   \");\n        te = &conv_table[i];\n        v = te->code << (32 - 17);\n        v |= te->len << (32 - 17 - 7);\n        v |= te->type << (32 - 17 - 7 - 4);\n        v |= te->data_index >> 8;\n        fprintf(f, \" 0x%08x,\", v);\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n\n    total_tables++;\n    total_table_bytes += conv_table_len;\n    fprintf(f, \"static const uint8_t case_conv_table2[%d] = {\", conv_table_len);\n    for(i = 0; i < conv_table_len; i++) {\n        if (i % 8 == 0)\n            fprintf(f, \"\\n   \");\n        te = &conv_table[i];\n        fprintf(f, \" 0x%02x,\", te->data_index & 0xff);\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n\n    total_tables++;\n    total_table_bytes += ext_data_len * sizeof(uint16_t);\n    fprintf(f, \"static const uint16_t case_conv_ext[%d] = {\", ext_data_len);\n    for(i = 0; i < ext_data_len; i++) {\n        if (i % 8 == 0)\n            fprintf(f, \"\\n   \");\n        fprintf(f, \" 0x%04x,\", ext_data[i]);\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n}\n\n\nstatic CCInfo *global_tab;\n\nstatic int sp_cc_cmp(const void *p1, const void *p2)\n{\n    CCInfo *c1 = &global_tab[*(const int *)p1];\n    CCInfo *c2 = &global_tab[*(const int *)p2];\n    if (c1->f_len < c2->f_len) {\n        return -1;\n    } else if (c2->f_len < c1->f_len) {\n        return 1;\n    } else {\n        return memcmp(c1->f_data, c2->f_data, sizeof(c1->f_data[0]) * c1->f_len);\n    }\n}\n\n/* dump the case special cases (multi character results which are\n   identical and need specific handling in lre_canonicalize() */\nvoid dump_case_folding_special_cases(CCInfo *tab)\n{\n    int i, len, j;\n    int *perm;\n\n    perm = malloc(sizeof(perm[0]) * (CHARCODE_MAX + 1));\n    for(i = 0; i <= CHARCODE_MAX; i++)\n        perm[i] = i;\n    global_tab = tab;\n    qsort(perm, CHARCODE_MAX + 1, sizeof(perm[0]), sp_cc_cmp);\n    for(i = 0; i <= CHARCODE_MAX;) {\n        if (tab[perm[i]].f_len <= 1) {\n            i++;\n        } else {\n            len = 1;\n            while ((i + len) <= CHARCODE_MAX && !sp_cc_cmp(&perm[i], &perm[i + len]))\n                len++;\n\n            if (len > 1) {\n                for(j = i; j < i + len; j++)\n                    dump_cc_info(&tab[perm[j]], perm[j]);\n            }\n            i += len;\n        }\n    }\n    free(perm);\n    global_tab = NULL;\n}\n\n\nint tabcmp(const int *tab1, const int *tab2, int n)\n{\n    int i;\n    for(i = 0; i < n; i++) {\n        if (tab1[i] != tab2[i])\n            return -1;\n    }\n    return 0;\n}\n\nvoid dump_str(const char *str, const int *buf, int len)\n{\n    int i;\n    printf(\"%s=\", str);\n    for(i = 0; i < len; i++)\n        printf(\" %05x\", buf[i]);\n    printf(\"\\n\");\n}\n\nvoid compute_internal_props(void)\n{\n    int i;\n    BOOL has_ul;\n\n    for(i = 0; i <= CHARCODE_MAX; i++) {\n        CCInfo *ci = &unicode_db[i];\n        has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0);\n        if (has_ul) {\n            assert(get_prop(i, PROP_Cased));\n        } else {\n            set_prop(i, PROP_Cased1, get_prop(i, PROP_Cased));\n        }\n        set_prop(i, PROP_ID_Continue1,\n                 get_prop(i, PROP_ID_Continue) & (get_prop(i, PROP_ID_Start) ^ 1));\n        set_prop(i, PROP_XID_Start1,\n                 get_prop(i, PROP_ID_Start) ^ get_prop(i, PROP_XID_Start));\n        set_prop(i, PROP_XID_Continue1,\n                 get_prop(i, PROP_ID_Continue) ^ get_prop(i, PROP_XID_Continue));\n        set_prop(i, PROP_Changes_When_Titlecased1,\n                 get_prop(i, PROP_Changes_When_Titlecased) ^ (ci->u_len != 0));\n        set_prop(i, PROP_Changes_When_Casefolded1,\n                 get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_len != 0));\n        /* XXX: reduce table size (438 bytes) */\n        set_prop(i, PROP_Changes_When_NFKC_Casefolded1,\n                 get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_len != 0));\n#if 0\n        /* TEST */\n#define M(x) (1U << GCAT_ ## x)\n        {\n            int b;\n            b = ((M(Mn) | M(Cf) | M(Lm) | M(Sk)) >>\n                 unicode_db[i].general_category) & 1;\n            set_prop(i, PROP_Cased1,\n                     get_prop(i, PROP_Case_Ignorable) ^ b);\n        }\n#undef M\n#endif\n    }\n}\n\nvoid dump_byte_table(FILE *f, const char *cname, const uint8_t *tab, int len)\n{\n    int i;\n\n    total_tables++;\n    total_table_bytes += len;\n    fprintf(f, \"static const uint8_t %s[%d] = {\", cname, len);\n    for(i = 0; i < len; i++) {\n        if (i % 8 == 0)\n            fprintf(f, \"\\n   \");\n        fprintf(f, \" 0x%02x,\", tab[i]);\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n}\n\nvoid dump_index_table(FILE *f, const char *cname, const uint8_t *tab, int len)\n{\n    int i, code, offset;\n\n    total_index++;\n    total_index_bytes += len;\n    fprintf(f, \"static const uint8_t %s[%d] = {\\n\", cname, len);\n    for(i = 0; i < len; i += 3) {\n        code = tab[i] + (tab[i+1] << 8) + ((tab[i+2] & 0x1f) << 16);\n        offset = ((i / 3) + 1) * 32 + (tab[i+2] >> 5);\n        fprintf(f, \"    0x%02x, 0x%02x, 0x%02x,\", tab[i], tab[i+1], tab[i+2]);\n        fprintf(f, \"  // %6.5X at %d%s\\n\", code, offset,\n                i == len - 3 ? \" (upper bound)\" : \"\");\n    }\n    fprintf(f, \"};\\n\\n\");\n}\n\n#define PROP_BLOCK_LEN 32\n\nvoid build_prop_table(FILE *f, const char *name, int prop_index, BOOL add_index)\n{\n    int i, j, n, v, offset, code;\n    DynBuf dbuf_s, *dbuf = &dbuf_s;\n    DynBuf dbuf1_s, *dbuf1 = &dbuf1_s;\n    DynBuf dbuf2_s, *dbuf2 = &dbuf2_s;\n    const uint32_t *buf;\n    int buf_len, block_end_pos, bit;\n    char cname[128];\n\n    dbuf_init(dbuf1);\n\n    for(i = 0; i <= CHARCODE_MAX;) {\n        v = get_prop(i, prop_index);\n        j = i + 1;\n        while (j <= CHARCODE_MAX && get_prop(j, prop_index) == v) {\n            j++;\n        }\n        n = j - i;\n        if (j == (CHARCODE_MAX + 1) && v == 0)\n            break; /* no need to encode last zero run */\n        //printf(\"%05x: %d %d\\n\", i, n, v);\n        dbuf_put_u32(dbuf1, n - 1);\n        i += n;\n    }\n\n    dbuf_init(dbuf);\n    dbuf_init(dbuf2);\n    buf = (uint32_t *)dbuf1->buf;\n    buf_len = dbuf1->size / sizeof(buf[0]);\n\n    /* the first value is assumed to be 0 */\n    assert(get_prop(0, prop_index) == 0);\n\n    block_end_pos = PROP_BLOCK_LEN;\n    i = 0;\n    code = 0;\n    bit = 0;\n    while (i < buf_len) {\n        if (add_index && dbuf->size >= block_end_pos && bit == 0) {\n            offset = (dbuf->size - block_end_pos);\n            /* XXX: offset could be larger in case of runs of small\n               lengths. Could add code to change the encoding to\n               prevent it at the expense of one byte loss */\n            assert(offset <= 7);\n            v = code | (offset << 21);\n            dbuf_putc(dbuf2, v);\n            dbuf_putc(dbuf2, v >> 8);\n            dbuf_putc(dbuf2, v >> 16);\n            block_end_pos += PROP_BLOCK_LEN;\n        }\n\n        /* Compressed byte encoding:\n           00..3F: 2 packed lengths: 3-bit + 3-bit\n           40..5F: 5-bits plus extra byte for length\n           60..7F: 5-bits plus 2 extra bytes for length\n           80..FF: 7-bit length\n           lengths must be incremented to get character count\n           Ranges alternate between false and true return value.\n         */\n        v = buf[i];\n        code += v + 1;\n        bit ^= 1;\n        if (v < 8 && (i + 1) < buf_len && buf[i + 1] < 8) {\n            code += buf[i + 1] + 1;\n            bit ^= 1;\n            dbuf_putc(dbuf, (v << 3) | buf[i + 1]);\n            i += 2;\n        } else if (v < 128) {\n            dbuf_putc(dbuf, 0x80 + v);\n            i++;\n        } else if (v < (1 << 13)) {\n            dbuf_putc(dbuf, 0x40 + (v >> 8));\n            dbuf_putc(dbuf, v);\n            i++;\n        } else {\n            assert(v < (1 << 21));\n            dbuf_putc(dbuf, 0x60 + (v >> 16));\n            dbuf_putc(dbuf, v >> 8);\n            dbuf_putc(dbuf, v);\n            i++;\n        }\n    }\n\n    if (add_index) {\n        /* last index entry */\n        v = code;\n        dbuf_putc(dbuf2, v);\n        dbuf_putc(dbuf2, v >> 8);\n        dbuf_putc(dbuf2, v >> 16);\n    }\n\n#ifdef DUMP_TABLE_SIZE\n    printf(\"prop %s: length=%d bytes\\n\", unicode_prop_name[prop_index],\n           (int)(dbuf->size + dbuf2->size));\n#endif\n    snprintf(cname, sizeof(cname), \"unicode_prop_%s_table\", unicode_prop_name[prop_index]);\n    dump_byte_table(f, cname, dbuf->buf, dbuf->size);\n    if (add_index) {\n        snprintf(cname, sizeof(cname), \"unicode_prop_%s_index\", unicode_prop_name[prop_index]);\n        dump_index_table(f, cname, dbuf2->buf, dbuf2->size);\n    }\n\n    dbuf_free(dbuf);\n    dbuf_free(dbuf1);\n    dbuf_free(dbuf2);\n}\n\nvoid build_flags_tables(FILE *f)\n{\n    build_prop_table(f, \"Cased1\", PROP_Cased1, TRUE);\n    build_prop_table(f, \"Case_Ignorable\", PROP_Case_Ignorable, TRUE);\n    build_prop_table(f, \"ID_Start\", PROP_ID_Start, TRUE);\n    build_prop_table(f, \"ID_Continue1\", PROP_ID_Continue1, TRUE);\n}\n\nvoid dump_name_table(FILE *f, const char *cname, const char **tab_name, int len,\n                     const char **tab_short_name)\n{\n    int i, w, maxw;\n\n    maxw = 0;\n    for(i = 0; i < len; i++) {\n        w = strlen(tab_name[i]);\n        if (tab_short_name && tab_short_name[i][0] != '\\0') {\n            w += 1 + strlen(tab_short_name[i]);\n        }\n        if (maxw < w)\n            maxw = w;\n    }\n\n    /* generate a sequence of strings terminated by an empty string */\n    fprintf(f, \"static const char %s[] =\\n\", cname);\n    for(i = 0; i < len; i++) {\n        fprintf(f, \"    \\\"\");\n        w = fprintf(f, \"%s\", tab_name[i]);\n        if (tab_short_name && tab_short_name[i][0] != '\\0') {\n            w += fprintf(f, \",%s\", tab_short_name[i]);\n        }\n        fprintf(f, \"\\\"%*s\\\"\\\\0\\\"\\n\", 1 + maxw - w, \"\");\n    }\n    fprintf(f, \";\\n\\n\");\n}\n\nvoid build_general_category_table(FILE *f)\n{\n    int i, v, j, n, n1;\n    DynBuf dbuf_s, *dbuf = &dbuf_s;\n#ifdef DUMP_TABLE_SIZE\n    int cw_count, cw_len_count[4], cw_start;\n#endif\n\n    fprintf(f, \"typedef enum {\\n\");\n    for(i = 0; i < GCAT_COUNT; i++)\n        fprintf(f, \"    UNICODE_GC_%s,\\n\", unicode_gc_name[i]);\n    fprintf(f, \"    UNICODE_GC_COUNT,\\n\");\n    fprintf(f, \"} UnicodeGCEnum;\\n\\n\");\n\n    dump_name_table(f, \"unicode_gc_name_table\",\n                    unicode_gc_name, GCAT_COUNT,\n                    unicode_gc_short_name);\n\n\n    dbuf_init(dbuf);\n#ifdef DUMP_TABLE_SIZE\n    cw_count = 0;\n    for(i = 0; i < 4; i++)\n        cw_len_count[i] = 0;\n#endif\n    for(i = 0; i <= CHARCODE_MAX;) {\n        v = unicode_db[i].general_category;\n        j = i + 1;\n        while (j <= CHARCODE_MAX && unicode_db[j].general_category == v)\n            j++;\n        n = j - i;\n        /* compress Lu/Ll runs */\n        if (v == GCAT_Lu) {\n            n1 = 1;\n            while ((i + n1) <= CHARCODE_MAX && unicode_db[i + n1].general_category == (v + (n1 & 1))) {\n                n1++;\n            }\n            if (n1 > n) {\n                v = 31;\n                n = n1;\n            }\n        }\n        //        printf(\"%05x %05x %d\\n\", i, n, v);\n        n--;\n#ifdef DUMP_TABLE_SIZE\n        cw_count++;\n        cw_start = dbuf->size;\n#endif\n        if (n < 7) {\n            dbuf_putc(dbuf, (n << 5) | v);\n        } else if (n < 7 + 128) {\n            n1 = n - 7;\n            assert(n1 < 128);\n            dbuf_putc(dbuf, (0xf << 5) | v);\n            dbuf_putc(dbuf, n1);\n        } else if (n < 7 + 128 + (1 << 14)) {\n            n1 = n - (7 + 128);\n            assert(n1 < (1 << 14));\n            dbuf_putc(dbuf, (0xf << 5) | v);\n            dbuf_putc(dbuf, (n1 >> 8) + 128);\n            dbuf_putc(dbuf, n1);\n        } else {\n            n1 = n - (7 + 128 + (1 << 14));\n            assert(n1 < (1 << 22));\n            dbuf_putc(dbuf, (0xf << 5) | v);\n            dbuf_putc(dbuf, (n1 >> 16) + 128 + 64);\n            dbuf_putc(dbuf, n1 >> 8);\n            dbuf_putc(dbuf, n1);\n        }\n#ifdef DUMP_TABLE_SIZE\n        cw_len_count[dbuf->size - cw_start - 1]++;\n#endif\n        i += n + 1;\n    }\n#ifdef DUMP_TABLE_SIZE\n    printf(\"general category: %d entries [\", cw_count);\n    for(i = 0; i < 4; i++)\n        printf(\" %d\", cw_len_count[i]);\n    printf(\" ], length=%d bytes\\n\", (int)dbuf->size);\n#endif\n\n    dump_byte_table(f, \"unicode_gc_table\", dbuf->buf, dbuf->size);\n\n    dbuf_free(dbuf);\n}\n\nvoid build_script_table(FILE *f)\n{\n    int i, v, j, n, n1, type;\n    DynBuf dbuf_s, *dbuf = &dbuf_s;\n#ifdef DUMP_TABLE_SIZE\n    int cw_count, cw_len_count[4], cw_start;\n#endif\n\n    fprintf(f, \"typedef enum {\\n\");\n    for(i = 0; i < SCRIPT_COUNT; i++)\n        fprintf(f, \"    UNICODE_SCRIPT_%s,\\n\", unicode_script_name[i]);\n    fprintf(f, \"    UNICODE_SCRIPT_COUNT,\\n\");\n    fprintf(f, \"} UnicodeScriptEnum;\\n\\n\");\n\n    dump_name_table(f, \"unicode_script_name_table\",\n                    unicode_script_name, SCRIPT_COUNT,\n                    unicode_script_short_name);\n\n    dbuf_init(dbuf);\n#ifdef DUMP_TABLE_SIZE\n    cw_count = 0;\n    for(i = 0; i < 4; i++)\n        cw_len_count[i] = 0;\n#endif\n    for(i = 0; i <= CHARCODE_MAX;) {\n        v = unicode_db[i].script;\n        j = i + 1;\n        while (j <= CHARCODE_MAX && unicode_db[j].script == v)\n            j++;\n        n = j - i;\n        if (v == 0 && j == (CHARCODE_MAX + 1))\n            break;\n        //        printf(\"%05x %05x %d\\n\", i, n, v);\n        n--;\n#ifdef DUMP_TABLE_SIZE\n        cw_count++;\n        cw_start = dbuf->size;\n#endif\n        if (v == 0)\n            type = 0;\n        else\n            type = 1;\n        if (n < 96) {\n            dbuf_putc(dbuf, n | (type << 7));\n        } else if (n < 96 + (1 << 12)) {\n            n1 = n - 96;\n            assert(n1 < (1 << 12));\n            dbuf_putc(dbuf, ((n1 >> 8) + 96) | (type << 7));\n            dbuf_putc(dbuf, n1);\n        } else {\n            n1 = n - (96 + (1 << 12));\n            assert(n1 < (1 << 20));\n            dbuf_putc(dbuf, ((n1 >> 16) + 112) | (type << 7));\n            dbuf_putc(dbuf, n1 >> 8);\n            dbuf_putc(dbuf, n1);\n        }\n        if (type != 0)\n            dbuf_putc(dbuf, v);\n\n#ifdef DUMP_TABLE_SIZE\n        cw_len_count[dbuf->size - cw_start - 1]++;\n#endif\n        i += n + 1;\n    }\n#ifdef DUMP_TABLE_SIZE\n    printf(\"script: %d entries [\", cw_count);\n    for(i = 0; i < 4; i++)\n        printf(\" %d\", cw_len_count[i]);\n    printf(\" ], length=%d bytes\\n\", (int)dbuf->size);\n#endif\n\n    dump_byte_table(f, \"unicode_script_table\", dbuf->buf, dbuf->size);\n\n    dbuf_free(dbuf);\n}\n\nvoid build_script_ext_table(FILE *f)\n{\n    int i, j, n, n1, script_ext_len;\n    DynBuf dbuf_s, *dbuf = &dbuf_s;\n#if defined(DUMP_TABLE_SIZE)\n    int cw_count = 0;\n#endif\n\n    dbuf_init(dbuf);\n    for(i = 0; i <= CHARCODE_MAX;) {\n        script_ext_len = unicode_db[i].script_ext_len;\n        j = i + 1;\n        while (j <= CHARCODE_MAX &&\n               unicode_db[j].script_ext_len == script_ext_len &&\n               !memcmp(unicode_db[j].script_ext, unicode_db[i].script_ext,\n                       script_ext_len)) {\n            j++;\n        }\n        n = j - i;\n#if defined(DUMP_TABLE_SIZE)\n        cw_count++;\n#endif\n        n--;\n        if (n < 128) {\n            dbuf_putc(dbuf, n);\n        } else if (n < 128 + (1 << 14)) {\n            n1 = n - 128;\n            assert(n1 < (1 << 14));\n            dbuf_putc(dbuf, (n1 >> 8) + 128);\n            dbuf_putc(dbuf, n1);\n        } else {\n            n1 = n - (128 + (1 << 14));\n            assert(n1 < (1 << 22));\n            dbuf_putc(dbuf, (n1 >> 16) + 128 + 64);\n            dbuf_putc(dbuf, n1 >> 8);\n            dbuf_putc(dbuf, n1);\n        }\n        dbuf_putc(dbuf, script_ext_len);\n        for(j = 0; j < script_ext_len; j++)\n            dbuf_putc(dbuf, unicode_db[i].script_ext[j]);\n        i += n + 1;\n    }\n#ifdef DUMP_TABLE_SIZE\n    printf(\"script_ext: %d entries\", cw_count);\n    printf(\", length=%d bytes\\n\", (int)dbuf->size);\n#endif\n\n    dump_byte_table(f, \"unicode_script_ext_table\", dbuf->buf, dbuf->size);\n\n    dbuf_free(dbuf);\n}\n\n/* the following properties are synthetized so no table is necessary */\n#define PROP_TABLE_COUNT PROP_ASCII\n\nvoid build_prop_list_table(FILE *f)\n{\n    int i;\n\n    for(i = 0; i < PROP_TABLE_COUNT; i++) {\n        if (i == PROP_ID_Start ||\n            i == PROP_Case_Ignorable ||\n            i == PROP_ID_Continue1) {\n            /* already generated */\n        } else {\n            build_prop_table(f, unicode_prop_name[i], i, FALSE);\n        }\n    }\n\n    fprintf(f, \"typedef enum {\\n\");\n    for(i = 0; i < PROP_COUNT; i++)\n        fprintf(f, \"    UNICODE_PROP_%s,\\n\", unicode_prop_name[i]);\n    fprintf(f, \"    UNICODE_PROP_COUNT,\\n\");\n    fprintf(f, \"} UnicodePropertyEnum;\\n\\n\");\n\n    i = PROP_ASCII_Hex_Digit;\n    dump_name_table(f, \"unicode_prop_name_table\",\n                    unicode_prop_name + i, PROP_XID_Start - i + 1,\n                    unicode_prop_short_name + i);\n\n    fprintf(f, \"static const uint8_t * const unicode_prop_table[] = {\\n\");\n    for(i = 0; i < PROP_TABLE_COUNT; i++) {\n        fprintf(f, \"    unicode_prop_%s_table,\\n\", unicode_prop_name[i]);\n    }\n    fprintf(f, \"};\\n\\n\");\n\n    fprintf(f, \"static const uint16_t unicode_prop_len_table[] = {\\n\");\n    for(i = 0; i < PROP_TABLE_COUNT; i++) {\n        fprintf(f, \"    countof(unicode_prop_%s_table),\\n\", unicode_prop_name[i]);\n    }\n    fprintf(f, \"};\\n\\n\");\n}\n\nstatic BOOL is_emoji_hair_color(uint32_t c)\n{\n    return (c >= 0x1F9B0 && c <= 0x1F9B3);\n}\n\n#define EMOJI_MOD_NONE   0\n#define EMOJI_MOD_TYPE1  1\n#define EMOJI_MOD_TYPE2  2\n#define EMOJI_MOD_TYPE2D 3\n\nstatic BOOL mark_zwj_string(REStringList *sl, uint32_t *buf, int len, int mod_type, int *mod_pos,\n                            int hc_pos, BOOL mark_flag)\n{\n    REString *p;\n    int i, n_mod, i0, i1, hc_count, j;\n\n#if 0\n    if (mark_flag)\n        printf(\"mod_type=%d\\n\", mod_type);\n#endif\n    \n    switch(mod_type) {\n    case EMOJI_MOD_NONE:\n        n_mod = 1;\n        break;\n    case EMOJI_MOD_TYPE1:\n        n_mod = 5;\n        break;\n    case EMOJI_MOD_TYPE2:\n        n_mod = 25;\n        break;\n    case EMOJI_MOD_TYPE2D:\n        n_mod = 20;\n        break;\n    default:\n        assert(0);\n    }\n    if (hc_pos >= 0)\n        hc_count = 4;\n    else\n        hc_count = 1;\n    /* check that all the related strings are present */\n    for(j = 0; j < hc_count; j++) {\n        for(i = 0; i < n_mod; i++) {\n            switch(mod_type) {\n            case EMOJI_MOD_NONE:\n                break;\n            case EMOJI_MOD_TYPE1:\n                buf[mod_pos[0]] = 0x1f3fb + i;\n                break;\n            case EMOJI_MOD_TYPE2:\n            case EMOJI_MOD_TYPE2D:\n                i0 = i / 5;\n                i1 = i % 5;\n                /* avoid identical values */\n                if (mod_type == EMOJI_MOD_TYPE2D && i0 >= i1)\n                    i0++;\n                buf[mod_pos[0]] = 0x1f3fb + i0;\n                buf[mod_pos[1]] = 0x1f3fb + i1;\n                break;\n            default:\n                assert(0);\n            }\n\n            if (hc_pos >= 0)\n                buf[hc_pos] = 0x1F9B0 + j;\n            \n            p = re_string_find(sl, len, buf, FALSE);\n            if (!p)\n                return FALSE;\n            if (mark_flag)\n                p->flags |= 1;\n        }\n    }\n    return TRUE;\n}\n\nstatic void zwj_encode_string(DynBuf *dbuf, const uint32_t *buf, int len, int mod_type, int *mod_pos,\n                              int hc_pos)\n{\n    int i, j;\n    int c, code;\n    uint32_t buf1[SEQ_MAX_LEN];\n    \n    j = 0;\n    for(i = 0; i < len;) {\n        c = buf[i++];\n        if (c >= 0x2000 && c <= 0x2fff) {\n            code = c - 0x2000;\n        } else if (c >= 0x1f000 && c <= 0x1ffff) {\n            code = c - 0x1f000 + 0x1000;\n        } else {\n            assert(0);\n        }\n        if (i < len && is_emoji_modifier(buf[i])) {\n            /* modifier */\n            code |= (mod_type << 13);\n            i++;\n        }\n        if (i < len && buf[i] == 0xfe0f) {\n            /* presentation selector present */\n            code |= 0x8000;\n            i++;\n        }\n        if (i < len) {\n            /* zero width join */\n            assert(buf[i] == 0x200d);\n            i++;\n        }\n        buf1[j++] = code;\n    }\n    dbuf_putc(dbuf, j);\n    for(i = 0; i < j; i++) {\n        dbuf_putc(dbuf, buf1[i]);\n        dbuf_putc(dbuf, buf1[i] >> 8);\n    }\n}\n\nstatic void build_rgi_emoji_zwj_sequence(FILE *f, REStringList *sl)\n{\n    int mod_pos[2], mod_count, hair_color_pos, j, h;\n    REString *p;\n    uint32_t buf[SEQ_MAX_LEN];\n    DynBuf dbuf;\n\n#if 0\n    {\n        for(h = 0; h < sl->hash_size; h++) {\n            for(p = sl->hash_table[h]; p != NULL; p = p->next) {\n                for(j = 0; j < p->len; j++)\n                    printf(\" %04x\", p->buf[j]);\n                printf(\"\\n\");\n            }\n        }\n        exit(0);\n    }\n#endif\n    //    printf(\"rgi_emoji_zwj_sequence: n=%d\\n\", sl->n_strings);\n\n    dbuf_init(&dbuf);\n    \n    /* avoid duplicating strings with emoji modifiers or hair colors */\n    for(h = 0; h < sl->hash_size; h++) {\n        for(p = sl->hash_table[h]; p != NULL; p = p->next) {\n            if (p->flags) /* already examined */\n                continue;\n            mod_count = 0;\n            hair_color_pos = -1;\n            for(j = 0; j < p->len; j++) {\n                if (is_emoji_modifier(p->buf[j])) {\n                    assert(mod_count < 2);\n                    mod_pos[mod_count++] = j;\n                } else if (is_emoji_hair_color(p->buf[j])) {\n                    hair_color_pos = j;\n                }\n                buf[j] = p->buf[j];\n            }\n            \n            if (mod_count != 0 || hair_color_pos >= 0) {\n                int mod_type;\n                if (mod_count == 0)\n                    mod_type = EMOJI_MOD_NONE;\n                else if (mod_count == 1)\n                    mod_type = EMOJI_MOD_TYPE1;\n                else\n                    mod_type = EMOJI_MOD_TYPE2;\n                \n                if (mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, FALSE)) {\n                    mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, TRUE);\n                } else if (mod_type == EMOJI_MOD_TYPE2) {\n                    mod_type = EMOJI_MOD_TYPE2D;\n                    if (mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, FALSE)) {\n                        mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, TRUE);\n                    } else {\n                        dump_str(\"not_found\", (int *)p->buf, p->len);\n                        goto keep;\n                    }\n                }\n                if (hair_color_pos >= 0)\n                    buf[hair_color_pos] = 0x1f9b0;\n                /* encode the string */\n                zwj_encode_string(&dbuf, buf, p->len, mod_type, mod_pos, hair_color_pos);\n            } else {\n            keep:\n                zwj_encode_string(&dbuf, buf, p->len, EMOJI_MOD_NONE, NULL, -1);\n            }\n        }\n    }\n    \n    /* Encode */\n    dump_byte_table(f, \"unicode_rgi_emoji_zwj_sequence\", dbuf.buf, dbuf.size);\n\n    dbuf_free(&dbuf);\n}\n\nvoid build_sequence_prop_list_table(FILE *f)\n{\n    int i;\n    fprintf(f, \"typedef enum {\\n\");\n    for(i = 0; i < SEQUENCE_PROP_COUNT; i++)\n        fprintf(f, \"    UNICODE_SEQUENCE_PROP_%s,\\n\", unicode_sequence_prop_name[i]);\n    fprintf(f, \"    UNICODE_SEQUENCE_PROP_COUNT,\\n\");\n    fprintf(f, \"} UnicodeSequencePropertyEnum;\\n\\n\");\n\n    dump_name_table(f, \"unicode_sequence_prop_name_table\",\n                    unicode_sequence_prop_name, SEQUENCE_PROP_COUNT, NULL);\n\n    dump_byte_table(f, \"unicode_rgi_emoji_tag_sequence\", rgi_emoji_tag_sequence.buf, rgi_emoji_tag_sequence.size);\n\n    build_rgi_emoji_zwj_sequence(f, &rgi_emoji_zwj_sequence);\n}\n\n#ifdef USE_TEST\nint check_conv(uint32_t *res, uint32_t c, int conv_type)\n{\n    return lre_case_conv(res, c, conv_type);\n}\n\nvoid check_case_conv(void)\n{\n    CCInfo *tab = unicode_db;\n    uint32_t res[3];\n    int l, error;\n    CCInfo ci_s, *ci1, *ci = &ci_s;\n    int code;\n\n    for(code = 0; code <= CHARCODE_MAX; code++) {\n        ci1 = &tab[code];\n        *ci = *ci1;\n        if (ci->l_len == 0) {\n            ci->l_len = 1;\n            ci->l_data[0] = code;\n        }\n        if (ci->u_len == 0) {\n            ci->u_len = 1;\n            ci->u_data[0] = code;\n        }\n        if (ci->f_len == 0) {\n            ci->f_len = 1;\n            ci->f_data[0] = code;\n        }\n\n        error = 0;\n        l = check_conv(res, code, 0);\n        if (l != ci->u_len || tabcmp((int *)res, ci->u_data, l)) {\n            printf(\"ERROR: L\\n\");\n            error++;\n        }\n        l = check_conv(res, code, 1);\n        if (l != ci->l_len || tabcmp((int *)res, ci->l_data, l)) {\n            printf(\"ERROR: U\\n\");\n            error++;\n        }\n        l = check_conv(res, code, 2);\n        if (l != ci->f_len || tabcmp((int *)res, ci->f_data, l)) {\n            printf(\"ERROR: F\\n\");\n            error++;\n        }\n        if (error) {\n            dump_cc_info(ci, code);\n            exit(1);\n        }\n    }\n}\n\n#ifdef PROFILE\nstatic int64_t get_time_ns(void)\n{\n    struct timespec ts;\n    clock_gettime(CLOCK_MONOTONIC, &ts);\n    return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;\n}\n#endif\n\n\nvoid check_flags(void)\n{\n    int c;\n    BOOL flag_ref, flag;\n    for(c = 0; c <= CHARCODE_MAX; c++) {\n        flag_ref = get_prop(c, PROP_Cased);\n        flag = !!lre_is_cased(c);\n        if (flag != flag_ref) {\n            printf(\"ERROR: c=%05x cased=%d ref=%d\\n\",\n                   c, flag, flag_ref);\n            exit(1);\n        }\n\n        flag_ref = get_prop(c, PROP_Case_Ignorable);\n        flag = !!lre_is_case_ignorable(c);\n        if (flag != flag_ref) {\n            printf(\"ERROR: c=%05x case_ignorable=%d ref=%d\\n\",\n                   c, flag, flag_ref);\n            exit(1);\n        }\n\n        flag_ref = get_prop(c, PROP_ID_Start);\n        flag = !!lre_is_id_start(c);\n        if (flag != flag_ref) {\n            printf(\"ERROR: c=%05x id_start=%d ref=%d\\n\",\n                   c, flag, flag_ref);\n            exit(1);\n        }\n\n        flag_ref = get_prop(c, PROP_ID_Continue);\n        flag = !!lre_is_id_continue(c);\n        if (flag != flag_ref) {\n            printf(\"ERROR: c=%05x id_cont=%d ref=%d\\n\",\n                   c, flag, flag_ref);\n            exit(1);\n        }\n    }\n#ifdef PROFILE\n    {\n        int64_t ti, count;\n        ti = get_time_ns();\n        count = 0;\n        for(c = 0x20; c <= 0xffff; c++) {\n            flag_ref = get_prop(c, PROP_ID_Start);\n            flag = !!lre_is_id_start(c);\n            assert(flag == flag_ref);\n            count++;\n        }\n        ti = get_time_ns() - ti;\n        printf(\"flags time=%0.1f ns/char\\n\",\n               (double)ti / count);\n    }\n#endif\n}\n\n#endif\n\n#define CC_BLOCK_LEN 32\n\nvoid build_cc_table(FILE *f)\n{\n    // Compress combining class table\n    // see: https://www.unicode.org/reports/tr44/#Canonical_Combining_Class_Values\n    int i, cc, n, type, n1, block_end_pos;\n    DynBuf dbuf_s, *dbuf = &dbuf_s;\n    DynBuf dbuf1_s, *dbuf1 = &dbuf1_s;\n#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)\n    int cw_len_tab[3], cw_start, cc_table_len;\n#endif\n    uint32_t v;\n\n    dbuf_init(dbuf);\n    dbuf_init(dbuf1);\n#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)\n    cc_table_len = 0;\n    for(i = 0; i < countof(cw_len_tab); i++)\n        cw_len_tab[i] = 0;\n#endif\n    block_end_pos = CC_BLOCK_LEN;\n    for(i = 0; i <= CHARCODE_MAX;) {\n        cc = unicode_db[i].combining_class;\n        assert(cc <= 255);\n        /* check increasing values */\n        n = 1;\n        while ((i + n) <= CHARCODE_MAX &&\n               unicode_db[i + n].combining_class == (cc + n))\n            n++;\n        if (n >= 2) {\n            type = 1;\n        } else {\n            type = 0;\n            n = 1;\n            while ((i + n) <= CHARCODE_MAX &&\n                   unicode_db[i + n].combining_class == cc)\n                n++;\n        }\n        /* no need to encode the last run */\n        if (cc == 0 && (i + n - 1) == CHARCODE_MAX)\n            break;\n#ifdef DUMP_CC_TABLE\n        printf(\"%05x %6d %d %d\\n\", i, n, type, cc);\n#endif\n        if (type == 0) {\n            if (cc == 0)\n                type = 2;\n            else if (cc == 230)\n                type = 3;\n        }\n        n1 = n - 1;\n\n        /* add an entry to the index if necessary */\n        if (dbuf->size >= block_end_pos) {\n            v = i | ((dbuf->size - block_end_pos) << 21);\n            dbuf_putc(dbuf1, v);\n            dbuf_putc(dbuf1, v >> 8);\n            dbuf_putc(dbuf1, v >> 16);\n            block_end_pos += CC_BLOCK_LEN;\n        }\n#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)\n        cw_start = dbuf->size;\n#endif\n        /* Compressed run length encoding:\n           - 2 high order bits are combining class type\n           -         0:0, 1:230, 2:extra byte linear progression, 3:extra byte\n           - 00..2F: range length (add 1)\n           - 30..37: 3-bit range-length + 1 extra byte\n           - 38..3F: 3-bit range-length + 2 extra byte\n         */\n        if (n1 < 48) {\n            dbuf_putc(dbuf, n1 | (type << 6));\n        } else if (n1 < 48 + (1 << 11)) {\n            n1 -= 48;\n            dbuf_putc(dbuf, ((n1 >> 8) + 48) | (type << 6));\n            dbuf_putc(dbuf, n1);\n        } else {\n            n1 -= 48 + (1 << 11);\n            assert(n1 < (1 << 20));\n            dbuf_putc(dbuf, ((n1 >> 16) + 56) | (type << 6));\n            dbuf_putc(dbuf, n1 >> 8);\n            dbuf_putc(dbuf, n1);\n        }\n#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)\n        cw_len_tab[dbuf->size - cw_start - 1]++;\n        cc_table_len++;\n#endif\n        if (type == 0 || type == 1)\n            dbuf_putc(dbuf, cc);\n        i += n;\n    }\n\n    /* last index entry */\n    v = i;\n    dbuf_putc(dbuf1, v);\n    dbuf_putc(dbuf1, v >> 8);\n    dbuf_putc(dbuf1, v >> 16);\n\n    dump_byte_table(f, \"unicode_cc_table\", dbuf->buf, dbuf->size);\n    dump_index_table(f, \"unicode_cc_index\", dbuf1->buf, dbuf1->size);\n\n#if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)\n    printf(\"CC table: size=%d (%d entries) [\",\n           (int)(dbuf->size + dbuf1->size),\n           cc_table_len);\n    for(i = 0; i < countof(cw_len_tab); i++)\n        printf(\" %d\", cw_len_tab[i]);\n    printf(\" ]\\n\");\n#endif\n    dbuf_free(dbuf);\n    dbuf_free(dbuf1);\n}\n\n/* maximum length of decomposition: 18 chars (1), then 8 */\n#ifndef USE_TEST\ntypedef enum {\n    DECOMP_TYPE_C1, /* 16 bit char */\n    DECOMP_TYPE_L1, /* 16 bit char table */\n    DECOMP_TYPE_L2,\n    DECOMP_TYPE_L3,\n    DECOMP_TYPE_L4,\n    DECOMP_TYPE_L5, /* XXX: not used */\n    DECOMP_TYPE_L6, /* XXX: could remove */\n    DECOMP_TYPE_L7, /* XXX: could remove */\n    DECOMP_TYPE_LL1, /* 18 bit char table */\n    DECOMP_TYPE_LL2,\n    DECOMP_TYPE_S1, /* 8 bit char table */\n    DECOMP_TYPE_S2,\n    DECOMP_TYPE_S3,\n    DECOMP_TYPE_S4,\n    DECOMP_TYPE_S5,\n    DECOMP_TYPE_I1, /* increment 16 bit char value */\n    DECOMP_TYPE_I2_0,\n    DECOMP_TYPE_I2_1,\n    DECOMP_TYPE_I3_1,\n    DECOMP_TYPE_I3_2,\n    DECOMP_TYPE_I4_1,\n    DECOMP_TYPE_I4_2,\n    DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */\n    DECOMP_TYPE_B2,\n    DECOMP_TYPE_B3,\n    DECOMP_TYPE_B4,\n    DECOMP_TYPE_B5,\n    DECOMP_TYPE_B6,\n    DECOMP_TYPE_B7,\n    DECOMP_TYPE_B8,\n    DECOMP_TYPE_B18,\n    DECOMP_TYPE_LS2,\n    DECOMP_TYPE_PAT3,\n    DECOMP_TYPE_S2_UL,\n    DECOMP_TYPE_LS2_UL,\n} DecompTypeEnum;\n#endif\n\nconst char *decomp_type_str[] = {\n    \"C1\",\n    \"L1\",\n    \"L2\",\n    \"L3\",\n    \"L4\",\n    \"L5\",\n    \"L6\",\n    \"L7\",\n    \"LL1\",\n    \"LL2\",\n    \"S1\",\n    \"S2\",\n    \"S3\",\n    \"S4\",\n    \"S5\",\n    \"I1\",\n    \"I2_0\",\n    \"I2_1\",\n    \"I3_1\",\n    \"I3_2\",\n    \"I4_1\",\n    \"I4_2\",\n    \"B1\",\n    \"B2\",\n    \"B3\",\n    \"B4\",\n    \"B5\",\n    \"B6\",\n    \"B7\",\n    \"B8\",\n    \"B18\",\n    \"LS2\",\n    \"PAT3\",\n    \"S2_UL\",\n    \"LS2_UL\",\n};\n\nconst int decomp_incr_tab[4][4] = {\n    { DECOMP_TYPE_I1, 0, -1 },\n    { DECOMP_TYPE_I2_0, 0, 1, -1 },\n    { DECOMP_TYPE_I3_1, 1, 2, -1 },\n    { DECOMP_TYPE_I4_1, 1, 2, -1 },\n};\n\n/*\n  entry size:\n  type   bits\n  code   18\n  len    7\n  compat 1\n  type   5\n  index  16\n  total  47\n*/\n\ntypedef struct {\n    int code;\n    uint8_t len;\n    uint8_t type;\n    uint8_t c_len;\n    uint16_t c_min;\n    uint16_t data_index;\n    int cost; /* size in bytes from this entry to the end */\n} DecompEntry;\n\nint get_decomp_run_size(const DecompEntry *de)\n{\n    int s;\n    s = 6;\n    if (de->type <= DECOMP_TYPE_C1) {\n        /* nothing more */\n    } else if (de->type <= DECOMP_TYPE_L7) {\n        s += de->len * de->c_len * 2;\n    } else if (de->type <= DECOMP_TYPE_LL2) {\n        /* 18 bits per char */\n        s += (de->len * de->c_len * 18 + 7) / 8;\n    } else if (de->type <= DECOMP_TYPE_S5) {\n        s += de->len * de->c_len;\n    } else if (de->type <= DECOMP_TYPE_I4_2) {\n        s += de->c_len * 2;\n    } else if (de->type <= DECOMP_TYPE_B18) {\n        s += 2 + de->len * de->c_len;\n    } else if (de->type <= DECOMP_TYPE_LS2) {\n        s += de->len * 3;\n    } else if (de->type <= DECOMP_TYPE_PAT3) {\n        s += 4 + de->len * 2;\n    } else if (de->type <= DECOMP_TYPE_S2_UL) {\n        s += de->len;\n    } else if (de->type <= DECOMP_TYPE_LS2_UL) {\n        s += (de->len / 2) * 3;\n    } else {\n        abort();\n    }\n    return s;\n}\n\nstatic const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 };\n\n/* return -1 if not found */\nint get_short_code(int c)\n{\n    int i;\n    if (c < 0x80) {\n        return c;\n    } else if (c >= 0x300 && c < 0x350) {\n        return c - 0x300 + 0x80;\n    } else {\n        for(i = 0; i < countof(unicode_short_table); i++) {\n            if (c == unicode_short_table[i])\n                return i + 0x80 + 0x50;\n        }\n        return -1;\n    }\n}\n\nstatic BOOL is_short(int code)\n{\n    return get_short_code(code) >= 0;\n}\n\nstatic BOOL is_short_tab(const int *tab, int len)\n{\n    int i;\n    for(i = 0; i < len; i++) {\n        if (!is_short(tab[i]))\n            return FALSE;\n    }\n    return TRUE;\n}\n\nstatic BOOL is_16bit(const int *tab, int len)\n{\n    int i;\n    for(i = 0; i < len; i++) {\n        if (tab[i] > 0xffff)\n            return FALSE;\n    }\n    return TRUE;\n}\n\nstatic uint32_t to_lower_simple(uint32_t c)\n{\n    /* Latin1 and Cyrillic */\n    if (c < 0x100 || (c >= 0x410 && c <= 0x42f))\n        c += 0x20;\n    else\n        c++;\n    return c;\n}\n\n/* select best encoding with dynamic programming */\nvoid find_decomp_run(DecompEntry *tab_de, int i)\n{\n    DecompEntry de_s, *de = &de_s;\n    CCInfo *ci, *ci1, *ci2;\n    int l, j, n, len_max;\n\n    ci = &unicode_db[i];\n    l = ci->decomp_len;\n    if (l == 0) {\n        tab_de[i].cost = tab_de[i + 1].cost;\n        return;\n    }\n\n    /* the offset for the compose table has only 6 bits, so we must\n       limit if it can be used by the compose table */\n    if (!ci->is_compat && !ci->is_excluded && l == 2)\n        len_max = 64;\n    else\n        len_max = 127;\n\n    tab_de[i].cost = 0x7fffffff;\n\n    if (!is_16bit(ci->decomp_data, l)) {\n        assert(l <= 2);\n\n        n = 1;\n        for(;;) {\n            de->code = i;\n            de->len = n;\n            de->type = DECOMP_TYPE_LL1 + l - 1;\n            de->c_len = l;\n            de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n            if (de->cost < tab_de[i].cost) {\n                tab_de[i] = *de;\n            }\n            if (!((i + n) <= CHARCODE_MAX && n < len_max))\n                break;\n            ci1 = &unicode_db[i + n];\n            /* Note: we accept a hole */\n            if (!(ci1->decomp_len == 0 ||\n                  (ci1->decomp_len == l &&\n                   ci1->is_compat == ci->is_compat)))\n                break;\n            n++;\n        }\n        return;\n    }\n\n    if (l <= 7) {\n        n = 1;\n        for(;;) {\n            de->code = i;\n            de->len = n;\n            if (l == 1 && n == 1) {\n                de->type = DECOMP_TYPE_C1;\n            } else {\n                assert(l <= 8);\n                de->type = DECOMP_TYPE_L1 + l - 1;\n            }\n            de->c_len = l;\n            de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n            if (de->cost < tab_de[i].cost) {\n                tab_de[i] = *de;\n            }\n\n            if (!((i + n) <= CHARCODE_MAX && n < len_max))\n                break;\n            ci1 = &unicode_db[i + n];\n            /* Note: we accept a hole */\n            if (!(ci1->decomp_len == 0 ||\n                  (ci1->decomp_len == l &&\n                   ci1->is_compat == ci->is_compat &&\n                   is_16bit(ci1->decomp_data, l))))\n                break;\n            n++;\n        }\n    }\n\n    if (l <= 8 || l == 18) {\n        int c_min, c_max, c;\n        c_min = c_max = -1;\n        n = 1;\n        for(;;) {\n            ci1 = &unicode_db[i + n - 1];\n            for(j = 0; j < l; j++) {\n                c = ci1->decomp_data[j];\n                if (c == 0x20) {\n                    /* we accept space for Arabic */\n                } else if (c_min == -1) {\n                    c_min = c_max = c;\n                } else {\n                    c_min = min_int(c_min, c);\n                    c_max = max_int(c_max, c);\n                }\n            }\n            if ((c_max - c_min) > 254)\n                break;\n            de->code = i;\n            de->len = n;\n            if (l == 18)\n                de->type = DECOMP_TYPE_B18;\n            else\n                de->type = DECOMP_TYPE_B1 + l - 1;\n            de->c_len = l;\n            de->c_min = c_min;\n            de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n            if (de->cost < tab_de[i].cost) {\n                tab_de[i] = *de;\n            }\n            if (!((i + n) <= CHARCODE_MAX && n < len_max))\n                break;\n            ci1 = &unicode_db[i + n];\n            if (!(ci1->decomp_len == l &&\n                  ci1->is_compat == ci->is_compat))\n                break;\n            n++;\n        }\n    }\n\n    /* find an ascii run */\n    if (l <= 5 && is_short_tab(ci->decomp_data, l)) {\n        n = 1;\n        for(;;) {\n            de->code = i;\n            de->len = n;\n            de->type = DECOMP_TYPE_S1 + l - 1;\n            de->c_len = l;\n            de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n            if (de->cost < tab_de[i].cost) {\n                tab_de[i] = *de;\n            }\n\n            if (!((i + n) <= CHARCODE_MAX && n < len_max))\n                break;\n            ci1 = &unicode_db[i + n];\n            /* Note: we accept a hole */\n            if (!(ci1->decomp_len == 0 ||\n                  (ci1->decomp_len == l &&\n                   ci1->is_compat == ci->is_compat &&\n                   is_short_tab(ci1->decomp_data, l))))\n                break;\n            n++;\n        }\n    }\n\n    /* check if a single char is increasing */\n    if (l <= 4) {\n        int idx1, idx;\n\n        for(idx1 = 1; (idx = decomp_incr_tab[l - 1][idx1]) >= 0; idx1++) {\n            n = 1;\n            for(;;) {\n                de->code = i;\n                de->len = n;\n                de->type = decomp_incr_tab[l - 1][0] + idx1 - 1;\n                de->c_len = l;\n                de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n                if (de->cost < tab_de[i].cost) {\n                    tab_de[i] = *de;\n                }\n\n                if (!((i + n) <= CHARCODE_MAX && n < len_max))\n                    break;\n                ci1 = &unicode_db[i + n];\n                if (!(ci1->decomp_len == l &&\n                      ci1->is_compat == ci->is_compat))\n                    goto next1;\n                for(j = 0; j < l; j++) {\n                    if (j == idx) {\n                        if (ci1->decomp_data[j] != ci->decomp_data[j] + n)\n                            goto next1;\n                    } else {\n                        if (ci1->decomp_data[j] != ci->decomp_data[j])\n                            goto next1;\n                    }\n                }\n                n++;\n            }\n        next1: ;\n        }\n    }\n\n    if (l == 3) {\n        n = 1;\n        for(;;) {\n            de->code = i;\n            de->len = n;\n            de->type = DECOMP_TYPE_PAT3;\n            de->c_len = l;\n            de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n            if (de->cost < tab_de[i].cost) {\n                tab_de[i] = *de;\n            }\n            if (!((i + n) <= CHARCODE_MAX && n < len_max))\n                break;\n            ci1 = &unicode_db[i + n];\n            if (!(ci1->decomp_len == l &&\n                  ci1->is_compat == ci->is_compat &&\n                  ci1->decomp_data[1] <= 0xffff &&\n                  ci1->decomp_data[0] == ci->decomp_data[0] &&\n                  ci1->decomp_data[l - 1] == ci->decomp_data[l - 1]))\n                break;\n            n++;\n        }\n    }\n\n    if (l == 2 && is_short(ci->decomp_data[1])) {\n        n = 1;\n        for(;;) {\n            de->code = i;\n            de->len = n;\n            de->type = DECOMP_TYPE_LS2;\n            de->c_len = l;\n            de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n            if (de->cost < tab_de[i].cost) {\n                tab_de[i] = *de;\n            }\n            if (!((i + n) <= CHARCODE_MAX && n < len_max))\n                break;\n            ci1 = &unicode_db[i + n];\n            if (!(ci1->decomp_len == 0 ||\n                  (ci1->decomp_len == l &&\n                   ci1->is_compat == ci->is_compat &&\n                   ci1->decomp_data[0] <= 0xffff &&\n                   is_short(ci1->decomp_data[1]))))\n                break;\n            n++;\n        }\n    }\n\n    if (l == 2) {\n        BOOL is_16bit;\n\n        n = 0;\n        is_16bit = FALSE;\n        for(;;) {\n            if (!((i + n + 1) <= CHARCODE_MAX && n + 2 <= len_max))\n                break;\n            ci1 = &unicode_db[i + n];\n            if (!(ci1->decomp_len == l &&\n                  ci1->is_compat == ci->is_compat &&\n                  is_short(ci1->decomp_data[1])))\n                break;\n            if (!is_16bit && !is_short(ci1->decomp_data[0]))\n                is_16bit = TRUE;\n            ci2 = &unicode_db[i + n + 1];\n            if (!(ci2->decomp_len == l &&\n                  ci2->is_compat == ci->is_compat &&\n                  ci2->decomp_data[0] == to_lower_simple(ci1->decomp_data[0])  &&\n                  ci2->decomp_data[1] == ci1->decomp_data[1]))\n                break;\n            n += 2;\n            de->code = i;\n            de->len = n;\n            de->type = DECOMP_TYPE_S2_UL + is_16bit;\n            de->c_len = l;\n            de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;\n            if (de->cost < tab_de[i].cost) {\n                tab_de[i] = *de;\n            }\n        }\n    }\n}\n\nvoid put16(uint8_t *data_buf, int *pidx, uint16_t c)\n{\n    int idx;\n    idx = *pidx;\n    data_buf[idx++] = c;\n    data_buf[idx++] = c >> 8;\n    *pidx = idx;\n}\n\nvoid add_decomp_data(uint8_t *data_buf, int *pidx, DecompEntry *de)\n{\n    int i, j, idx, c;\n    CCInfo *ci;\n\n    idx = *pidx;\n    de->data_index = idx;\n    if (de->type <= DECOMP_TYPE_C1) {\n        ci = &unicode_db[de->code];\n        assert(ci->decomp_len == 1);\n        de->data_index = ci->decomp_data[0];\n    } else if (de->type <= DECOMP_TYPE_L7) {\n        for(i = 0; i < de->len; i++) {\n            ci = &unicode_db[de->code + i];\n            for(j = 0; j < de->c_len; j++) {\n                if (ci->decomp_len == 0)\n                    c = 0;\n                else\n                    c = ci->decomp_data[j];\n                put16(data_buf, &idx,  c);\n            }\n        }\n    } else if (de->type <= DECOMP_TYPE_LL2) {\n        int n, p, k;\n        n = (de->len * de->c_len * 18 + 7) / 8;\n        p = de->len * de->c_len * 2;\n        memset(data_buf + idx, 0, n);\n        k = 0;\n        for(i = 0; i < de->len; i++) {\n            ci = &unicode_db[de->code + i];\n            for(j = 0; j < de->c_len; j++) {\n                if (ci->decomp_len == 0)\n                    c = 0;\n                else\n                    c = ci->decomp_data[j];\n                data_buf[idx + k * 2] = c;\n                data_buf[idx + k * 2 + 1] = c >> 8;\n                data_buf[idx + p + (k / 4)] |= (c >> 16) << ((k % 4) * 2);\n                k++;\n            }\n        }\n        idx += n;\n    } else if (de->type <= DECOMP_TYPE_S5) {\n        for(i = 0; i < de->len; i++) {\n            ci = &unicode_db[de->code + i];\n            for(j = 0; j < de->c_len; j++) {\n                if (ci->decomp_len == 0)\n                    c = 0;\n                else\n                    c = ci->decomp_data[j];\n                c = get_short_code(c);\n                assert(c >= 0);\n                data_buf[idx++] = c;\n            }\n        }\n    } else if (de->type <= DECOMP_TYPE_I4_2) {\n        ci = &unicode_db[de->code];\n        assert(ci->decomp_len == de->c_len);\n        for(j = 0; j < de->c_len; j++)\n            put16(data_buf, &idx, ci->decomp_data[j]);\n    } else if (de->type <= DECOMP_TYPE_B18) {\n        c = de->c_min;\n        data_buf[idx++] = c;\n        data_buf[idx++] = c >> 8;\n        for(i = 0; i < de->len; i++) {\n            ci = &unicode_db[de->code + i];\n            for(j = 0; j < de->c_len; j++) {\n                assert(ci->decomp_len == de->c_len);\n                c = ci->decomp_data[j];\n                if (c == 0x20) {\n                    c = 0xff;\n                } else {\n                    c -= de->c_min;\n                    assert((uint32_t)c <= 254);\n                }\n                data_buf[idx++] = c;\n            }\n        }\n    } else if (de->type <= DECOMP_TYPE_LS2) {\n        assert(de->c_len == 2);\n        for(i = 0; i < de->len; i++) {\n            ci = &unicode_db[de->code + i];\n            if (ci->decomp_len == 0)\n                c = 0;\n            else\n                c = ci->decomp_data[0];\n            put16(data_buf, &idx,  c);\n\n            if (ci->decomp_len == 0)\n                c = 0;\n            else\n                c = ci->decomp_data[1];\n            c = get_short_code(c);\n            assert(c >= 0);\n            data_buf[idx++] = c;\n        }\n    } else if (de->type <= DECOMP_TYPE_PAT3) {\n        ci = &unicode_db[de->code];\n        assert(ci->decomp_len == 3);\n        put16(data_buf, &idx,  ci->decomp_data[0]);\n        put16(data_buf, &idx,  ci->decomp_data[2]);\n        for(i = 0; i < de->len; i++) {\n            ci = &unicode_db[de->code + i];\n            assert(ci->decomp_len == 3);\n            put16(data_buf, &idx,  ci->decomp_data[1]);\n        }\n    } else if (de->type <= DECOMP_TYPE_S2_UL) {\n        for(i = 0; i < de->len; i += 2) {\n            ci = &unicode_db[de->code + i];\n            c = ci->decomp_data[0];\n            c = get_short_code(c);\n            assert(c >= 0);\n            data_buf[idx++] = c;\n            c = ci->decomp_data[1];\n            c = get_short_code(c);\n            assert(c >= 0);\n            data_buf[idx++] = c;\n        }\n    } else if (de->type <= DECOMP_TYPE_LS2_UL) {\n        for(i = 0; i < de->len; i += 2) {\n            ci = &unicode_db[de->code + i];\n            c = ci->decomp_data[0];\n            put16(data_buf, &idx,  c);\n            c = ci->decomp_data[1];\n            c = get_short_code(c);\n            assert(c >= 0);\n            data_buf[idx++] = c;\n        }\n    } else {\n        abort();\n    }\n    *pidx = idx;\n}\n\n#if 0\nvoid dump_large_char(void)\n{\n    int i, j;\n    for(i = 0; i <= CHARCODE_MAX; i++) {\n        CCInfo *ci = &unicode_db[i];\n        for(j = 0; j < ci->decomp_len; j++) {\n            if (ci->decomp_data[j] > 0xffff)\n                printf(\"%05x\\n\", ci->decomp_data[j]);\n        }\n    }\n}\n#endif\n\nvoid build_compose_table(FILE *f, const DecompEntry *tab_de);\n\nvoid build_decompose_table(FILE *f)\n{\n    int i, array_len, code_max, data_len, count;\n    DecompEntry *tab_de, de_s, *de = &de_s;\n    uint8_t *data_buf;\n\n    code_max = CHARCODE_MAX;\n\n    tab_de = mallocz((code_max + 2) * sizeof(*tab_de));\n\n    for(i = code_max; i >= 0; i--) {\n        find_decomp_run(tab_de, i);\n    }\n\n    /* build the data buffer */\n    data_buf = malloc(100000);\n    data_len = 0;\n    array_len = 0;\n    for(i = 0; i <= code_max; i++) {\n        de = &tab_de[i];\n        if (de->len != 0) {\n            add_decomp_data(data_buf, &data_len, de);\n            i += de->len - 1;\n            array_len++;\n        }\n    }\n\n#ifdef DUMP_DECOMP_TABLE\n    /* dump */\n    {\n        int size, size1;\n\n        printf(\"START LEN   TYPE  L C SIZE\\n\");\n        size = 0;\n        for(i = 0; i <= code_max; i++) {\n            de = &tab_de[i];\n            if (de->len != 0) {\n                size1 = get_decomp_run_size(de);\n                printf(\"%05x %3d %6s %2d %1d %4d\\n\", i, de->len,\n                       decomp_type_str[de->type], de->c_len,\n                       unicode_db[i].is_compat, size1);\n                i += de->len - 1;\n                size += size1;\n            }\n        }\n\n        printf(\"array_len=%d estimated size=%d bytes actual=%d bytes\\n\",\n               array_len, size, array_len * 6 + data_len);\n    }\n#endif\n\n    total_tables++;\n    total_table_bytes += array_len * sizeof(uint32_t);\n    fprintf(f, \"static const uint32_t unicode_decomp_table1[%d] = {\", array_len);\n    count = 0;\n    for(i = 0; i <= code_max; i++) {\n        de = &tab_de[i];\n        if (de->len != 0) {\n            uint32_t v;\n            if (count++ % 4 == 0)\n                fprintf(f, \"\\n   \");\n            v = (de->code << (32 - 18)) |\n                (de->len << (32 - 18 - 7)) |\n                (de->type << (32 - 18 - 7 - 6)) |\n                unicode_db[de->code].is_compat;\n            fprintf(f, \" 0x%08x,\", v);\n            i += de->len - 1;\n        }\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n\n    total_tables++;\n    total_table_bytes += array_len * sizeof(uint16_t);\n    fprintf(f, \"static const uint16_t unicode_decomp_table2[%d] = {\", array_len);\n    count = 0;\n    for(i = 0; i <= code_max; i++) {\n        de = &tab_de[i];\n        if (de->len != 0) {\n            if (count++ % 8 == 0)\n                fprintf(f, \"\\n   \");\n            fprintf(f, \" 0x%04x,\", de->data_index);\n            i += de->len - 1;\n        }\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n\n    total_tables++;\n    total_table_bytes += data_len;\n    fprintf(f, \"static const uint8_t unicode_decomp_data[%d] = {\", data_len);\n    for(i = 0; i < data_len; i++) {\n        if (i % 8 == 0)\n            fprintf(f, \"\\n   \");\n        fprintf(f, \" 0x%02x,\", data_buf[i]);\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n\n    build_compose_table(f, tab_de);\n\n    free(data_buf);\n\n    free(tab_de);\n}\n\ntypedef struct {\n    uint32_t c[2];\n    uint32_t p;\n} ComposeEntry;\n\n#define COMPOSE_LEN_MAX 10000\n\nstatic int ce_cmp(const void *p1, const void *p2)\n{\n    const ComposeEntry *ce1 = p1;\n    const ComposeEntry *ce2 = p2;\n    int i;\n\n    for(i = 0; i < 2; i++) {\n        if (ce1->c[i] < ce2->c[i])\n            return -1;\n        else if (ce1->c[i] > ce2->c[i])\n            return 1;\n    }\n    return 0;\n}\n\n\nstatic int get_decomp_pos(const DecompEntry *tab_de, int c)\n{\n    int i, v, k;\n    const DecompEntry *de;\n\n    k = 0;\n    for(i = 0; i <= CHARCODE_MAX; i++) {\n        de = &tab_de[i];\n        if (de->len != 0) {\n            if (c >= de->code && c < de->code + de->len) {\n                v = c - de->code;\n                assert(v < 64);\n                v |= k << 6;\n                assert(v < 65536);\n                return v;\n            }\n            i += de->len - 1;\n            k++;\n        }\n    }\n    return -1;\n}\n\nvoid build_compose_table(FILE *f, const DecompEntry *tab_de)\n{\n    int i, v, tab_ce_len;\n    ComposeEntry *ce, *tab_ce;\n\n    tab_ce = malloc(sizeof(*tab_ce) * COMPOSE_LEN_MAX);\n    tab_ce_len = 0;\n    for(i = 0; i <= CHARCODE_MAX; i++) {\n        CCInfo *ci = &unicode_db[i];\n        if (ci->decomp_len == 2 && !ci->is_compat &&\n            !ci->is_excluded) {\n            assert(tab_ce_len < COMPOSE_LEN_MAX);\n            ce = &tab_ce[tab_ce_len++];\n            ce->c[0] = ci->decomp_data[0];\n            ce->c[1] = ci->decomp_data[1];\n            ce->p = i;\n        }\n    }\n    qsort(tab_ce, tab_ce_len, sizeof(*tab_ce), ce_cmp);\n\n#if 0\n    {\n        printf(\"tab_ce_len=%d\\n\", tab_ce_len);\n        for(i = 0; i < tab_ce_len; i++) {\n            ce = &tab_ce[i];\n            printf(\"%05x %05x %05x\\n\", ce->c[0], ce->c[1], ce->p);\n        }\n    }\n#endif\n\n    total_tables++;\n    total_table_bytes += tab_ce_len * sizeof(uint16_t);\n    fprintf(f, \"static const uint16_t unicode_comp_table[%u] = {\", tab_ce_len);\n    for(i = 0; i < tab_ce_len; i++) {\n        if (i % 8 == 0)\n            fprintf(f, \"\\n   \");\n        v = get_decomp_pos(tab_de, tab_ce[i].p);\n        if (v < 0) {\n            printf(\"ERROR: entry for c=%04x not found\\n\",\n                   tab_ce[i].p);\n            exit(1);\n        }\n        fprintf(f, \" 0x%04x,\", v);\n    }\n    fprintf(f, \"\\n};\\n\\n\");\n\n    free(tab_ce);\n}\n\n#ifdef USE_TEST\nvoid check_decompose_table(void)\n{\n    int c;\n    CCInfo *ci;\n    int res[UNICODE_DECOMP_LEN_MAX], *ref;\n    int len, ref_len, is_compat;\n\n    for(is_compat = 0; is_compat <= 1; is_compat++) {\n        for(c = 0; c < CHARCODE_MAX; c++) {\n            ci = &unicode_db[c];\n            ref_len = ci->decomp_len;\n            ref = ci->decomp_data;\n            if (!is_compat && ci->is_compat) {\n                ref_len = 0;\n            }\n            len = unicode_decomp_char((uint32_t *)res, c, is_compat);\n            if (len != ref_len ||\n                tabcmp(res, ref, ref_len) != 0) {\n                printf(\"ERROR c=%05x compat=%d\\n\", c, is_compat);\n                dump_str(\"res\", res, len);\n                dump_str(\"ref\", ref, ref_len);\n                exit(1);\n            }\n        }\n    }\n}\n\nvoid check_compose_table(void)\n{\n    int i, p;\n    /* XXX: we don't test all the cases */\n\n    for(i = 0; i <= CHARCODE_MAX; i++) {\n        CCInfo *ci = &unicode_db[i];\n        if (ci->decomp_len == 2 && !ci->is_compat &&\n            !ci->is_excluded) {\n            p = unicode_compose_pair(ci->decomp_data[0], ci->decomp_data[1]);\n            if (p != i) {\n                printf(\"ERROR compose: c=%05x %05x -> %05x ref=%05x\\n\",\n                       ci->decomp_data[0], ci->decomp_data[1], p, i);\n                exit(1);\n            }\n        }\n    }\n\n\n\n}\n\n#endif\n\n\n\n#ifdef USE_TEST\n\nvoid check_str(const char *msg, int num, const int *in_buf, int in_len,\n               const int *buf1, int len1,\n               const int *buf2, int len2)\n{\n    if (len1 != len2 || tabcmp(buf1, buf2, len1) != 0) {\n        printf(\"%d: ERROR %s:\\n\", num, msg);\n        dump_str(\" in\", in_buf, in_len);\n        dump_str(\"res\", buf1, len1);\n        dump_str(\"ref\", buf2, len2);\n        exit(1);\n    }\n}\n\nvoid check_cc_table(void)\n{\n    int cc, cc_ref, c;\n\n    for(c = 0; c <= CHARCODE_MAX; c++) {\n        cc_ref = unicode_db[c].combining_class;\n        cc = unicode_get_cc(c);\n        if (cc != cc_ref) {\n            printf(\"ERROR: c=%04x cc=%d cc_ref=%d\\n\",\n                   c, cc, cc_ref);\n            exit(1);\n        }\n    }\n#ifdef PROFILE\n    {\n        int64_t ti, count;\n\n        ti = get_time_ns();\n        count = 0;\n        /* only do it on meaningful chars */\n        for(c = 0x20; c <= 0xffff; c++) {\n            cc_ref = unicode_db[c].combining_class;\n            cc = unicode_get_cc(c);\n            count++;\n        }\n        ti = get_time_ns() - ti;\n        printf(\"cc time=%0.1f ns/char\\n\",\n               (double)ti / count);\n    }\n#endif\n}\n\nvoid normalization_test(const char *filename)\n{\n    FILE *f;\n    char line[4096], *p;\n    int *in_str, *nfc_str, *nfd_str, *nfkc_str, *nfkd_str;\n    int in_len, nfc_len, nfd_len, nfkc_len, nfkd_len;\n    int *buf, buf_len, pos;\n\n    f = fopen(filename, \"rb\");\n    if (!f) {\n        perror(filename);\n        exit(1);\n    }\n    pos = 0;\n    for(;;) {\n        if (!get_line(line, sizeof(line), f))\n            break;\n        pos++;\n        p = line;\n        while (isspace(*p))\n            p++;\n        if (*p == '#' || *p == '@')\n            continue;\n        in_str = get_field_str(&in_len, p, 0);\n        nfc_str = get_field_str(&nfc_len, p, 1);\n        nfd_str = get_field_str(&nfd_len, p, 2);\n        nfkc_str = get_field_str(&nfkc_len, p, 3);\n        nfkd_str = get_field_str(&nfkd_len, p, 4);\n\n        //        dump_str(\"in\", in_str, in_len);\n\n        buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFD, NULL, NULL);\n        check_str(\"nfd\", pos, in_str, in_len, buf, buf_len, nfd_str, nfd_len);\n        free(buf);\n\n        buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKD, NULL, NULL);\n        check_str(\"nfkd\", pos, in_str, in_len, buf, buf_len, nfkd_str, nfkd_len);\n        free(buf);\n\n        buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFC, NULL, NULL);\n        check_str(\"nfc\", pos, in_str, in_len, buf, buf_len, nfc_str, nfc_len);\n        free(buf);\n\n        buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKC, NULL, NULL);\n        check_str(\"nfkc\", pos, in_str, in_len, buf, buf_len, nfkc_str, nfkc_len);\n        free(buf);\n\n        free(in_str);\n        free(nfc_str);\n        free(nfd_str);\n        free(nfkc_str);\n        free(nfkd_str);\n    }\n    fclose(f);\n}\n#endif\n\nint main(int argc, char *argv[])\n{\n    const char *unicode_db_path, *outfilename;\n    char filename[1024];\n    int arg = 1;\n\n    if (arg >= argc || (!strcmp(argv[arg], \"-h\") || !strcmp(argv[arg], \"--help\"))) {\n        printf(\"usage: %s PATH [OUTPUT]\\n\"\n               \"  PATH    path to the Unicode database directory\\n\"\n               \"  OUTPUT  name of the output file.  If omitted, a self test is performed\\n\"\n               \"          using the files from the Unicode library\\n\"\n               , argv[0]);\n        return 1;\n    }\n    unicode_db_path = argv[arg++];\n    outfilename = NULL;\n    if (arg < argc)\n        outfilename = argv[arg++];\n\n    unicode_db = mallocz(sizeof(unicode_db[0]) * (CHARCODE_MAX + 1));\n    re_string_list_init(&rgi_emoji_zwj_sequence);\n    dbuf_init(&rgi_emoji_tag_sequence);\n\n    snprintf(filename, sizeof(filename), \"%s/UnicodeData.txt\", unicode_db_path);\n\n    parse_unicode_data(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/SpecialCasing.txt\", unicode_db_path);\n    parse_special_casing(unicode_db, filename);\n\n    snprintf(filename, sizeof(filename), \"%s/CaseFolding.txt\", unicode_db_path);\n    parse_case_folding(unicode_db, filename);\n\n    snprintf(filename, sizeof(filename), \"%s/CompositionExclusions.txt\", unicode_db_path);\n    parse_composition_exclusions(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/DerivedCoreProperties.txt\", unicode_db_path);\n    parse_derived_core_properties(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/DerivedNormalizationProps.txt\", unicode_db_path);\n    parse_derived_norm_properties(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/PropList.txt\", unicode_db_path);\n    parse_prop_list(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/Scripts.txt\", unicode_db_path);\n    parse_scripts(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/ScriptExtensions.txt\",\n             unicode_db_path);\n    parse_script_extensions(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/emoji-data.txt\",\n             unicode_db_path);\n    parse_prop_list(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/emoji-sequences.txt\",\n             unicode_db_path);\n    parse_sequence_prop_list(filename);\n\n    snprintf(filename, sizeof(filename), \"%s/emoji-zwj-sequences.txt\",\n             unicode_db_path);\n    parse_sequence_prop_list(filename);\n\n    //    dump_unicode_data(unicode_db);\n    build_conv_table(unicode_db);\n\n#ifdef DUMP_CASE_FOLDING_SPECIAL_CASES\n    dump_case_folding_special_cases(unicode_db);\n#endif\n\n    if (!outfilename) {\n#ifdef USE_TEST\n        check_case_conv();\n        check_flags();\n        check_decompose_table();\n        check_compose_table();\n        check_cc_table();\n        snprintf(filename, sizeof(filename), \"%s/NormalizationTest.txt\", unicode_db_path);\n        normalization_test(filename);\n#else\n        fprintf(stderr, \"Tests are not compiled\\n\");\n        exit(1);\n#endif\n    } else\n    {\n        FILE *fo = fopen(outfilename, \"wb\");\n\n        if (!fo) {\n            perror(outfilename);\n            exit(1);\n        }\n        fprintf(fo,\n                \"/* Compressed unicode tables */\\n\"\n                \"/* Automatically generated file - do not edit */\\n\"\n                \"\\n\"\n                \"#include <stdint.h>\\n\"\n                \"\\n\");\n        dump_case_conv_table(fo);\n        compute_internal_props();\n        build_flags_tables(fo);\n        fprintf(fo, \"#ifdef CONFIG_ALL_UNICODE\\n\\n\");\n        build_cc_table(fo);\n        build_decompose_table(fo);\n        build_general_category_table(fo);\n        build_script_table(fo);\n        build_script_ext_table(fo);\n        build_prop_list_table(fo);\n        build_sequence_prop_list_table(fo);\n        fprintf(fo, \"#endif /* CONFIG_ALL_UNICODE */\\n\");\n        fprintf(fo, \"/* %u tables / %u bytes, %u index / %u bytes */\\n\",\n                total_tables, total_table_bytes, total_index, total_index_bytes);\n        fclose(fo);\n    }\n    re_string_list_free(&rgi_emoji_zwj_sequence);\n    return 0;\n}\n"
  },
  {
    "path": "unicode_gen_def.h",
    "content": "#ifdef UNICODE_GENERAL_CATEGORY\nDEF(Cn, \"Unassigned\") /* must be zero */\nDEF(Lu, \"Uppercase_Letter\")\nDEF(Ll, \"Lowercase_Letter\")\nDEF(Lt, \"Titlecase_Letter\")\nDEF(Lm, \"Modifier_Letter\")\nDEF(Lo, \"Other_Letter\")\nDEF(Mn, \"Nonspacing_Mark\")\nDEF(Mc, \"Spacing_Mark\")\nDEF(Me, \"Enclosing_Mark\")\nDEF(Nd, \"Decimal_Number,digit\")\nDEF(Nl, \"Letter_Number\")\nDEF(No, \"Other_Number\")\nDEF(Sm, \"Math_Symbol\")\nDEF(Sc, \"Currency_Symbol\")\nDEF(Sk, \"Modifier_Symbol\")\nDEF(So, \"Other_Symbol\")\nDEF(Pc, \"Connector_Punctuation\")\nDEF(Pd, \"Dash_Punctuation\")\nDEF(Ps, \"Open_Punctuation\")\nDEF(Pe, \"Close_Punctuation\")\nDEF(Pi, \"Initial_Punctuation\")\nDEF(Pf, \"Final_Punctuation\")\nDEF(Po, \"Other_Punctuation\")\nDEF(Zs, \"Space_Separator\")\nDEF(Zl, \"Line_Separator\")\nDEF(Zp, \"Paragraph_Separator\")\nDEF(Cc, \"Control,cntrl\")\nDEF(Cf, \"Format\")\nDEF(Cs, \"Surrogate\")\nDEF(Co, \"Private_Use\")\n/* synthetic properties */\nDEF(LC, \"Cased_Letter\")\nDEF(L, \"Letter\")\nDEF(M, \"Mark,Combining_Mark\")\nDEF(N, \"Number\")\nDEF(S, \"Symbol\")\nDEF(P, \"Punctuation,punct\")\nDEF(Z, \"Separator\")\nDEF(C, \"Other\")\n#endif\n\n#ifdef UNICODE_SCRIPT\n/* scripts aliases names in PropertyValueAliases.txt */\nDEF(Unknown, \"Zzzz\")\nDEF(Adlam, \"Adlm\")\nDEF(Ahom, \"Ahom\")\nDEF(Anatolian_Hieroglyphs, \"Hluw\")\nDEF(Arabic, \"Arab\")\nDEF(Armenian, \"Armn\")\nDEF(Avestan, \"Avst\")\nDEF(Balinese, \"Bali\")\nDEF(Bamum, \"Bamu\")\nDEF(Bassa_Vah, \"Bass\")\nDEF(Batak, \"Batk\")\nDEF(Beria_Erfe, \"Berf\")\nDEF(Bengali, \"Beng\")\nDEF(Bhaiksuki, \"Bhks\")\nDEF(Bopomofo, \"Bopo\")\nDEF(Brahmi, \"Brah\")\nDEF(Braille, \"Brai\")\nDEF(Buginese, \"Bugi\")\nDEF(Buhid, \"Buhd\")\nDEF(Canadian_Aboriginal, \"Cans\")\nDEF(Carian, \"Cari\")\nDEF(Caucasian_Albanian, \"Aghb\")\nDEF(Chakma, \"Cakm\")\nDEF(Cham, \"Cham\")\nDEF(Cherokee, \"Cher\")\nDEF(Chorasmian, \"Chrs\")\nDEF(Common, \"Zyyy\")\nDEF(Coptic, \"Copt,Qaac\")\nDEF(Cuneiform, \"Xsux\")\nDEF(Cypriot, \"Cprt\")\nDEF(Cyrillic, \"Cyrl\")\nDEF(Cypro_Minoan, \"Cpmn\")\nDEF(Deseret, \"Dsrt\")\nDEF(Devanagari, \"Deva\")\nDEF(Dives_Akuru, \"Diak\")\nDEF(Dogra, \"Dogr\")\nDEF(Duployan, \"Dupl\")\nDEF(Egyptian_Hieroglyphs, \"Egyp\")\nDEF(Elbasan, \"Elba\")\nDEF(Elymaic, \"Elym\")\nDEF(Ethiopic, \"Ethi\")\nDEF(Garay, \"Gara\")\nDEF(Georgian, \"Geor\")\nDEF(Glagolitic, \"Glag\")\nDEF(Gothic, \"Goth\")\nDEF(Grantha, \"Gran\")\nDEF(Greek, \"Grek\")\nDEF(Gujarati, \"Gujr\")\nDEF(Gunjala_Gondi, \"Gong\")\nDEF(Gurmukhi, \"Guru\")\nDEF(Gurung_Khema, \"Gukh\")\nDEF(Han, \"Hani\")\nDEF(Hangul, \"Hang\")\nDEF(Hanifi_Rohingya, \"Rohg\")\nDEF(Hanunoo, \"Hano\")\nDEF(Hatran, \"Hatr\")\nDEF(Hebrew, \"Hebr\")\nDEF(Hiragana, \"Hira\")\nDEF(Imperial_Aramaic, \"Armi\")\nDEF(Inherited, \"Zinh,Qaai\")\nDEF(Inscriptional_Pahlavi, \"Phli\")\nDEF(Inscriptional_Parthian, \"Prti\")\nDEF(Javanese, \"Java\")\nDEF(Kaithi, \"Kthi\")\nDEF(Kannada, \"Knda\")\nDEF(Katakana, \"Kana\")\nDEF(Katakana_Or_Hiragana, \"Hrkt\")\nDEF(Kawi, \"Kawi\")\nDEF(Kayah_Li, \"Kali\")\nDEF(Kharoshthi, \"Khar\")\nDEF(Khmer, \"Khmr\")\nDEF(Khojki, \"Khoj\")\nDEF(Khitan_Small_Script, \"Kits\")\nDEF(Khudawadi, \"Sind\")\nDEF(Kirat_Rai, \"Krai\")\nDEF(Lao, \"Laoo\")\nDEF(Latin, \"Latn\")\nDEF(Lepcha, \"Lepc\")\nDEF(Limbu, \"Limb\")\nDEF(Linear_A, \"Lina\")\nDEF(Linear_B, \"Linb\")\nDEF(Lisu, \"Lisu\")\nDEF(Lycian, \"Lyci\")\nDEF(Lydian, \"Lydi\")\nDEF(Makasar, \"Maka\")\nDEF(Mahajani, \"Mahj\")\nDEF(Malayalam, \"Mlym\")\nDEF(Mandaic, \"Mand\")\nDEF(Manichaean, \"Mani\")\nDEF(Marchen, \"Marc\")\nDEF(Masaram_Gondi, \"Gonm\")\nDEF(Medefaidrin, \"Medf\")\nDEF(Meetei_Mayek, \"Mtei\")\nDEF(Mende_Kikakui, \"Mend\")\nDEF(Meroitic_Cursive, \"Merc\")\nDEF(Meroitic_Hieroglyphs, \"Mero\")\nDEF(Miao, \"Plrd\")\nDEF(Modi, \"Modi\")\nDEF(Mongolian, \"Mong\")\nDEF(Mro, \"Mroo\")\nDEF(Multani, \"Mult\")\nDEF(Myanmar, \"Mymr\")\nDEF(Nabataean, \"Nbat\")\nDEF(Nag_Mundari, \"Nagm\")\nDEF(Nandinagari, \"Nand\")\nDEF(New_Tai_Lue, \"Talu\")\nDEF(Newa, \"Newa\")\nDEF(Nko, \"Nkoo\")\nDEF(Nushu, \"Nshu\")\nDEF(Nyiakeng_Puachue_Hmong, \"Hmnp\")\nDEF(Ogham, \"Ogam\")\nDEF(Ol_Chiki, \"Olck\")\nDEF(Ol_Onal, \"Onao\")\nDEF(Old_Hungarian, \"Hung\")\nDEF(Old_Italic, \"Ital\")\nDEF(Old_North_Arabian, \"Narb\")\nDEF(Old_Permic, \"Perm\")\nDEF(Old_Persian, \"Xpeo\")\nDEF(Old_Sogdian, \"Sogo\")\nDEF(Old_South_Arabian, \"Sarb\")\nDEF(Old_Turkic, \"Orkh\")\nDEF(Old_Uyghur, \"Ougr\")\nDEF(Oriya, \"Orya\")\nDEF(Osage, \"Osge\")\nDEF(Osmanya, \"Osma\")\nDEF(Pahawh_Hmong, \"Hmng\")\nDEF(Palmyrene, \"Palm\")\nDEF(Pau_Cin_Hau, \"Pauc\")\nDEF(Phags_Pa, \"Phag\")\nDEF(Phoenician, \"Phnx\")\nDEF(Psalter_Pahlavi, \"Phlp\")\nDEF(Rejang, \"Rjng\")\nDEF(Runic, \"Runr\")\nDEF(Samaritan, \"Samr\")\nDEF(Saurashtra, \"Saur\")\nDEF(Sharada, \"Shrd\")\nDEF(Shavian, \"Shaw\")\nDEF(Siddham, \"Sidd\")\nDEF(Sidetic, \"Sidt\")\nDEF(SignWriting, \"Sgnw\")\nDEF(Sinhala, \"Sinh\")\nDEF(Sogdian, \"Sogd\")\nDEF(Sora_Sompeng, \"Sora\")\nDEF(Soyombo, \"Soyo\")\nDEF(Sundanese, \"Sund\")\nDEF(Sunuwar, \"Sunu\")\nDEF(Syloti_Nagri, \"Sylo\")\nDEF(Syriac, \"Syrc\")\nDEF(Tagalog, \"Tglg\")\nDEF(Tagbanwa, \"Tagb\")\nDEF(Tai_Le, \"Tale\")\nDEF(Tai_Tham, \"Lana\")\nDEF(Tai_Viet, \"Tavt\")\nDEF(Tai_Yo, \"Tayo\")\nDEF(Takri, \"Takr\")\nDEF(Tamil, \"Taml\")\nDEF(Tangut, \"Tang\")\nDEF(Telugu, \"Telu\")\nDEF(Thaana, \"Thaa\")\nDEF(Thai, \"Thai\")\nDEF(Tibetan, \"Tibt\")\nDEF(Tifinagh, \"Tfng\")\nDEF(Tirhuta, \"Tirh\")\nDEF(Tangsa, \"Tnsa\")\nDEF(Todhri, \"Todr\")\nDEF(Tolong_Siki, \"Tols\")\nDEF(Toto, \"Toto\")\nDEF(Tulu_Tigalari, \"Tutg\")\nDEF(Ugaritic, \"Ugar\")\nDEF(Vai, \"Vaii\")\nDEF(Vithkuqi, \"Vith\")\nDEF(Wancho, \"Wcho\")\nDEF(Warang_Citi, \"Wara\")\nDEF(Yezidi, \"Yezi\")\nDEF(Yi, \"Yiii\")\nDEF(Zanabazar_Square, \"Zanb\")\n#endif\n\n#ifdef UNICODE_PROP_LIST\n/* Prop list not exported to regexp */\nDEF(Hyphen, \"\")\nDEF(Other_Math, \"\")\nDEF(Other_Alphabetic, \"\")\nDEF(Other_Lowercase, \"\")\nDEF(Other_Uppercase, \"\")\nDEF(Other_Grapheme_Extend, \"\")\nDEF(Other_Default_Ignorable_Code_Point, \"\")\nDEF(Other_ID_Start, \"\")\nDEF(Other_ID_Continue, \"\")\nDEF(Prepended_Concatenation_Mark, \"\")\n/* additional computed properties for smaller tables */\nDEF(ID_Continue1, \"\")\nDEF(XID_Start1, \"\")\nDEF(XID_Continue1, \"\")\nDEF(Changes_When_Titlecased1, \"\")\nDEF(Changes_When_Casefolded1, \"\")\nDEF(Changes_When_NFKC_Casefolded1, \"\")\nDEF(Basic_Emoji1, \"\")\nDEF(Basic_Emoji2, \"\")\nDEF(RGI_Emoji_Modifier_Sequence, \"\")\nDEF(RGI_Emoji_Flag_Sequence, \"\") \nDEF(Emoji_Keycap_Sequence, \"\")\n\n/* Prop list exported to JS */\nDEF(ASCII_Hex_Digit, \"AHex\")\nDEF(Bidi_Control, \"Bidi_C\")\nDEF(Dash, \"\")\nDEF(Deprecated, \"Dep\")\nDEF(Diacritic, \"Dia\")\nDEF(Extender, \"Ext\")\nDEF(Hex_Digit, \"Hex\")\nDEF(IDS_Unary_Operator, \"IDSU\")\nDEF(IDS_Binary_Operator, \"IDSB\")\nDEF(IDS_Trinary_Operator, \"IDST\")\nDEF(Ideographic, \"Ideo\")\nDEF(Join_Control, \"Join_C\")\nDEF(Logical_Order_Exception, \"LOE\")\nDEF(Modifier_Combining_Mark, \"MCM\")\nDEF(Noncharacter_Code_Point, \"NChar\")\nDEF(Pattern_Syntax, \"Pat_Syn\")\nDEF(Pattern_White_Space, \"Pat_WS\")\nDEF(Quotation_Mark, \"QMark\")\nDEF(Radical, \"\")\nDEF(Regional_Indicator, \"RI\")\nDEF(Sentence_Terminal, \"STerm\")\nDEF(Soft_Dotted, \"SD\")\nDEF(Terminal_Punctuation, \"Term\")\nDEF(Unified_Ideograph, \"UIdeo\")\nDEF(Variation_Selector, \"VS\")\nDEF(White_Space, \"space\")\nDEF(Bidi_Mirrored, \"Bidi_M\")\nDEF(Emoji, \"\")\nDEF(Emoji_Component, \"EComp\")\nDEF(Emoji_Modifier, \"EMod\")\nDEF(Emoji_Modifier_Base, \"EBase\")\nDEF(Emoji_Presentation, \"EPres\")\nDEF(Extended_Pictographic, \"ExtPict\")\nDEF(Default_Ignorable_Code_Point, \"DI\")\nDEF(ID_Start, \"IDS\")\nDEF(Case_Ignorable, \"CI\")\n\n/* other binary properties */\nDEF(ASCII,\"\")\nDEF(Alphabetic, \"Alpha\")\nDEF(Any, \"\")\nDEF(Assigned,\"\")\nDEF(Cased, \"\")\nDEF(Changes_When_Casefolded, \"CWCF\")\nDEF(Changes_When_Casemapped, \"CWCM\")\nDEF(Changes_When_Lowercased, \"CWL\")\nDEF(Changes_When_NFKC_Casefolded, \"CWKCF\")\nDEF(Changes_When_Titlecased, \"CWT\")\nDEF(Changes_When_Uppercased, \"CWU\")\nDEF(Grapheme_Base, \"Gr_Base\")\nDEF(Grapheme_Extend, \"Gr_Ext\")\nDEF(ID_Continue, \"IDC\")\nDEF(ID_Compat_Math_Start, \"\")\nDEF(ID_Compat_Math_Continue, \"\")\nDEF(InCB, \"\")\nDEF(Lowercase, \"Lower\")\nDEF(Math, \"\")\nDEF(Uppercase, \"Upper\")\nDEF(XID_Continue, \"XIDC\")\nDEF(XID_Start, \"XIDS\")\n\n/* internal tables with index */\nDEF(Cased1, \"\")\n\n#endif\n\n#ifdef UNICODE_SEQUENCE_PROP_LIST\nDEF(Basic_Emoji)\nDEF(Emoji_Keycap_Sequence)\nDEF(RGI_Emoji_Modifier_Sequence)\nDEF(RGI_Emoji_Flag_Sequence)\nDEF(RGI_Emoji_Tag_Sequence)\nDEF(RGI_Emoji_ZWJ_Sequence)\nDEF(RGI_Emoji)\n#endif\n"
  }
]