cred: isolate scripts in WASI and move RSA signing to AWS-LC

This commit is contained in:
2026-11-06 22:22:49 +00:00
parent 5b3e1393f5
commit 86c5d8a4e4
217 changed files with 155392 additions and 391 deletions
@@ -0,0 +1,4 @@
# Don't show changes in generated files when doing git diff
gen/** -diff
@@ -0,0 +1,7 @@
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
@@ -0,0 +1,780 @@
name: ci
on:
pull_request:
paths:
- '**'
- '!.gitignore'
- '!LICENSE'
- '!README.md'
- '!docs/**'
- '!examples/**'
- '.github/workflows/ci.yml'
push:
branches:
- master
paths:
- '**'
- '!.gitignore'
- '!LICENSE'
- '!README.md'
- '!docs/**'
- '!examples/**'
- '.github/workflows/ci.yml'
jobs:
codegen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: build
run: |
make codegen
- name: Check if the git repository is clean
run: (exit "$(git status --porcelain --untracked-files=no | head -255 | wc -l)") || (echo "Dirty git tree"; git diff; exit 1)
ci:
runs-on: ${{ matrix.config.os }}
name: ${{ matrix.config.os }} (${{ matrix.config.configType }}${{ matrix.config.arch }})
env:
ASAN_OPTIONS: halt_on_error=1
MSAN_OPTIONS: halt_on_error=1
UBSAN_OPTIONS: halt_on_error=1
defaults:
run:
shell: ${{ matrix.config.arch == '' && 'sh' || 'alpine.sh' }} {0}
strategy:
fail-fast: false
matrix:
config:
# see https://github.com/quickjs-ng/quickjs/issues/879 - tl;dr flaky
#- { os: ubuntu-24.04-arm, configType: Debug }
#- { os: ubuntu-24.04-arm, configType: Release, runTest262: true }
- { os: ubuntu-latest, configType: Debug }
- { os: ubuntu-latest, configType: Release, runTest262: true }
- { os: ubuntu-latest, configType: examples }
- { os: ubuntu-latest, configType: shared }
- { os: ubuntu-latest, configType: asan+ubsan, runTest262: true }
- { os: ubuntu-latest, configType: msan }
- { os: ubuntu-latest, configType: tcc }
- { os: ubuntu-latest, arch: x86, runTest262: true }
- { os: ubuntu-latest, arch: riscv64 }
- { os: ubuntu-latest, arch: s390x }
- { os: macos-14, configType: Debug }
- { os: macos-14, configType: Release }
- { os: macos-14, configType: examples }
- { os: macos-14, configType: shared }
- { os: macos-14, configType: asan+ubsan }
steps:
- uses: actions/checkout@v6
with:
submodules: true
- name: install TCC
if: ${{ matrix.config.configType == 'tcc' }}
run: |
pushd /tmp
git clone https://repo.or.cz/tinycc.git
cd tinycc
git checkout c21576f8a32715ab439690d18184b0e02022bbbd
./configure
make
sudo make install
tcc -v
popd
echo "CC=tcc" >> $GITHUB_ENV;
- name: Install extra dependencies
if: ${{ matrix.config.arch != '' }}
shell: 'sh'
run: |
sudo apt update && sudo apt install -y binfmt-support
- name: Setup Alpine
if: ${{ matrix.config.arch != '' }}
uses: jirutka/setup-alpine@v1
with:
arch: ${{ matrix.config.arch }}
packages: "build-base make cmake git"
- name: uname
run: uname -a
- name: Set build ENV vars
run: |
if [ "${{ matrix.config.configType }}" = "Debug" ]; then
echo "BUILD_TYPE=Debug" >> $GITHUB_ENV;
elif [ "${{ matrix.config.configType }}" = "examples" ]; then
echo "QJS_BUILD_EXAMPLES=ON" >> $GITHUB_ENV;
elif [ "${{ matrix.config.configType }}" = "shared" ]; then
echo "BUILD_SHARED_LIBS=ON" >> $GITHUB_ENV;
elif [ "${{ matrix.config.configType }}" = "asan+ubsan" ]; then
echo "BUILD_TYPE=RelWithDebInfo" >> $GITHUB_ENV;
echo "QJS_ENABLE_ASAN=ON" >> $GITHUB_ENV;
echo "QJS_ENABLE_UBSAN=ON" >> $GITHUB_ENV;
elif [ "${{ matrix.config.configType }}" = "msan" ]; then
echo "BUILD_TYPE=RelWithDebInfo" >> $GITHUB_ENV;
echo "QJS_ENABLE_MSAN=ON" >> $GITHUB_ENV;
echo "CC=clang" >> $GITHUB_ENV;
fi
- name: build
run: |
make \
BUILD_TYPE=$BUILD_TYPE \
QJS_BUILD_EXAMPLES=$QJS_BUILD_EXAMPLES \
BUILD_SHARED_LIBS=$BUILD_SHARED_LIBS \
QJS_ENABLE_ASAN=$QJS_ENABLE_ASAN \
QJS_ENABLE_UBSAN=$QJS_ENABLE_UBSAN \
QJS_ENABLE_MSAN=$QJS_ENABLE_MSAN
- name: stats
if: ${{ matrix.config.configType != 'examples' }}
run: |
make stats
- name: cxxtest
run: |
make cxxtest
- name: test
if: ${{ matrix.config.configType != 'examples' }}
run: |
make test
- name: test examples
if: ${{ matrix.config.configType == 'examples' }}
run: |
cp build/fib.so examples/
cp build/point.so examples/
./build/qjs examples/test_fib.js
./build/qjs examples/test_point.js
./build/qjs tests/test_bjson.js
./build/function_source
- name: test 262
if: ${{ matrix.config.runTest262 }}
run: |
git submodule update --init --checkout --depth 1
make test262
- name: test standalone
run: |
./build/qjs -c examples/hello.js -o hello
./hello
- name: test api
run: |
./build/api-test
windows-msvc:
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- { arch: x64, vsArch: x64, buildType: Debug, os: windows-latest }
- { arch: x64, vsArch: x64, buildType: Release, os: windows-latest }
- { arch: Win32, vsArch: x86, buildType: Debug, os: windows-latest }
- { arch: Win32, vsArch: x86, buildType: Release, os: windows-latest }
- { arch: ARM64, vsArch: arm64, buildType: Debug, os: windows-11-arm }
- { arch: ARM64, vsArch: arm64, buildType: Release, os: windows-11-arm }
steps:
- uses: actions/checkout@v6
- name: build
run: |
cmake -B build -DQJS_BUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -A ${{matrix.config.arch}}
cmake --build build --config ${{matrix.config.buildType}}
- name: stats
run: |
build\${{matrix.config.buildType}}\qjs.exe -qd
- name: test
run: |
cp build\${{matrix.config.buildType}}\fib.dll examples\
cp build\${{matrix.config.buildType}}\point.dll examples\
build\${{matrix.config.buildType}}\qjs.exe examples\test_fib.js
build\${{matrix.config.buildType}}\qjs.exe examples\test_point.js
build\${{matrix.config.buildType}}\run-test262.exe -c tests.conf
build\${{matrix.config.buildType}}\function_source.exe
- name: test standalone
run: |
build\${{matrix.config.buildType}}\qjs.exe -c examples\hello.js -o hello.exe
.\hello.exe
- name: test api
run: |
build\${{matrix.config.buildType}}\api-test.exe
- name: Set up Visual Studio shell
uses: egor-tensin/vs-shell@v2
with:
arch: ${{ matrix.config.vsArch }}
- name: cxxtest
run: |
cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc
cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc
windows-clang:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
buildType: [Debug, Release]
steps:
- uses: actions/checkout@v6
- name: build
run: |
git submodule update --init --checkout --depth 1
cmake -B build -DQJS_BUILD_EXAMPLES=ON -G "Visual Studio 17 2022" -T ClangCL
cmake --build build --config ${{matrix.buildType}}
- name: stats
run: |
build\${{matrix.buildType}}\qjs.exe -qd
- name: cxxtest
run: |
clang-cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc
clang-cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc
- name: test
run: |
cp build\${{matrix.buildType}}\fib.dll examples\
cp build\${{matrix.buildType}}\point.dll examples\
build\${{matrix.buildType}}\qjs.exe examples\test_fib.js
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
build\${{matrix.buildType}}\run-test262.exe -c tests.conf
build\${{matrix.buildType}}\function_source.exe
- name: test api
run: |
build\${{matrix.buildType}}\api-test.exe
windows-ninja:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
buildType: [Debug, Release]
steps:
- uses: actions/checkout@v6
- name: install ninja
run: |
choco install ninja
ninja.exe --version
- name: build
run: |
git submodule update --init --checkout --depth 1
cmake -B build -DQJS_BUILD_EXAMPLES=ON -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Ninja"
cmake --build build
- name: stats
run: |
build\qjs.exe -qd
- name: test
run: |
cp build\fib.dll examples\
cp build\point.dll examples\
build\qjs.exe examples\test_fib.js
build\qjs.exe examples\test_point.js
build\run-test262.exe -c tests.conf
build\function_source.exe
- name: test api
run: |
build\api-test.exe
windows-sdk:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
arch: [x64, Win32]
buildType: [Debug, Release]
steps:
- uses: actions/checkout@v6
- name: Install windows sdk
uses: ChristopheLav/windows-sdk-install@v1
with:
version-sdk: 26100
features: 'OptionId.DesktopCPPx86,OptionId.DesktopCPPx64'
- name: build
run: |
cmake -B build -DQJS_BUILD_EXAMPLES=ON -DCMAKE_SYSTEM_VERSION="10.0.26100.0" -A ${{matrix.arch}}
cmake --build build --config ${{matrix.buildType}}
- name: stats
run: |
build\${{matrix.buildType}}\qjs.exe -qd
- name: test
run: |
cp build\${{matrix.buildType}}\fib.dll examples\
cp build\${{matrix.buildType}}\point.dll examples\
build\${{matrix.buildType}}\qjs.exe examples\test_fib.js
build\${{matrix.buildType}}\qjs.exe examples\test_point.js
build\${{matrix.buildType}}\run-test262.exe -c tests.conf
build\${{matrix.buildType}}\function_source.exe
- name: test api
run: |
build\${{matrix.buildType}}\api-test.exe
windows-mingw:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
buildType: [Debug, Release]
sys:
- mingw32
- mingw64
- clang64
- ucrt64
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v6
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
update: true
msystem: ${{matrix.sys}}
install: >-
git
make
pacboy: >-
cmake:p
ninja:p
toolchain:p
- name: build
run: |
make BUILD_TYPE=${{matrix.buildType}}
- name: stats
run: |
make stats
ldd build/qjs
- name: cxxtest
if: ${{ matrix.sys != 'clang64' }}
run: |
make cxxtest
- name: cxxtest
if: ${{ matrix.sys == 'clang64' }}
run: |
make cxxtest CXX=clang++
- name: test
run: |
make test
- name: test standalone
run: |
./build/qjs -c examples/hello.js -o hello.exe
./hello
- name: test api
run: |
./build/api-test
windows-mingw-shared:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v6
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
install: >-
git
make
pacboy: >-
cmake:p
ninja:p
toolchain:p
- name: build
run: |
make BUILD_SHARED_LIBS=ON
ldd build/qjs
- name: stats
run: |
make stats
emscripten:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: mymindstorm/setup-emsdk@v14
- name: check emsdk
run: emcc -v
- name: build
run: |
emcmake cmake -B build -DQJS_BUILD_LIBC=ON
emmake make -C build qjs_wasm "-j$(getconf _NPROCESSORS_ONLN)"
- name: result
run: ls -lh build
wasi:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
- uses: jcbhmr/setup-wasmtime@v2
- name: setup wasi-sdk
run: |
wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.deb -P /tmp
sudo apt install /tmp/wasi-sdk*.deb
- name: test
run: |
cmake -B build -DCMAKE_TOOLCHAIN_FILE=/opt/wasi-sdk/share/cmake/wasi-sdk.cmake
make -C build qjs_exe
wasmtime run build/qjs -qd
echo "console.log('hello wasi!');" > t.js
wasmtime run --dir . build/qjs t.js
cygwin:
runs-on: windows-latest
defaults:
run:
shell: C:\cygwin\bin\bash.exe --login --norc -eo pipefail -o igncr '{0}'
env:
CYGWIN_NOWINPATH: 1
CHERE_INVOKING: 1
steps:
- name: Set up Cygwin
uses: cygwin/cygwin-install-action@master
with:
packages: make cmake gcc-g++ bash
- uses: actions/checkout@v6
- name: build
run: make
- name: stats
run: make stats
- name: cxxtest
run: |
make cxxtest
- name: test
run: make test
- name: test api
run: |
./build/api-test
openbsd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: build + test
uses: vmactions/openbsd-vm@v1
with:
usesh: true
prepare: |
pkg_add cmake gmake
run: |
gmake
gmake stats
freebsd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: build + test
uses: vmactions/freebsd-vm@v1
with:
usesh: true
prepare: |
pkg install -y cmake gmake
run: |
gmake
gmake stats
android:
runs-on: ubuntu-latest
container: reactnativecommunity/react-native-android:v13.0
steps:
- uses: actions/checkout@v6
- name: Configure android arm64
# see build options you can use in https://developer.android.com/ndk/guides/cmake
run: |
mkdir build
cd build
"$ANDROID_HOME/cmake/3.22.1/bin/cmake" "-DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/26.0.10792818/build/cmake/android.toolchain.cmake" -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-24 -DQJS_BUILD_LIBC=ON ..
- name: Build android arm64
run: |
"$ANDROID_HOME/cmake/3.22.1/bin/cmake" --build build --target qjs
ls -lh build
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
- name: configure
run: |
cmake -B build -GXcode -DCMAKE_SYSTEM_NAME:STRING=iOS -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL=NO -DQJS_BUILD_LIBC=ON
- name: build
run: |
cmake --build build --config Release --target qjs
ls -lh build
mimalloc-linux:
runs-on: ubuntu-24.04
env:
QJS_BUILD_CLI_WITH_MIMALLOC: ON
MIMALLOC_SHOW_STATS: 1
steps:
- uses: actions/checkout@v6
- name: install dependencies
run: |
sudo apt update && sudo apt -y install libmimalloc-dev
- name: build
run: |
make
- name: cxxtest
run: |
make cxxtest
- name: test
run: |
make test
mimalloc-macos:
runs-on: macos-latest
env:
QJS_BUILD_CLI_WITH_STATIC_MIMALLOC: ON
MIMALLOC_SHOW_STATS: 1
steps:
- uses: actions/checkout@v6
- name: install dependencies
run: |
brew install mimalloc
- name: build
run: |
make
- name: cxxtest
run: |
make cxxtest
- name: test
run: |
make test
amalgam:
strategy:
matrix:
# TODO(bnoordhuis) test on windows
config:
- { os: ubuntu-latest }
- { os: macos-latest }
runs-on: ${{ matrix.config.os }}
steps:
- uses: actions/checkout@v6
- name: build
run: |
make
- name: create amalgamation
run: |
make amalgam
- name: build amalgamation
run: |
unzip -d "$RUNNER_TEMP" build/quickjs-amalgam.zip
cc -Wall -I. -o "$RUNNER_TEMP/run-test262.o" -c run-test262.c
cc -Wall -I/ -DQJS_BUILD_LIBC -o "$RUNNER_TEMP/quickjs-amalgam.o" -c "$RUNNER_TEMP/quickjs-amalgam.c"
cc -o "$RUNNER_TEMP/run-test262" "$RUNNER_TEMP/run-test262.o" "$RUNNER_TEMP/quickjs-amalgam.o" -lm
- name: test
run: |
make test RUN262="$RUNNER_TEMP/run-test262"
jscheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: jscheck
run: |
make jscheck
parserless:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: build
run: |
make QJS_DISABLE_PARSER=ON QJS_BUILD_EXAMPLES=ON
- name: test
run: |
./build/hello
./build/hello_module
meson:
runs-on: ${{ matrix.platform }}
name: meson on ${{ matrix.platform }} (${{ matrix.mode.name }} ${{ matrix.flavor }}, ${{ matrix.features.name }})
strategy:
fail-fast: false
matrix:
flavor:
- debug
- release
features:
- name: default
args: ""
- name: libc
args: -Dlibc=true
- name: mimalloc
args: -Dcli_mimalloc=auto
mode:
- name: default
args: -Dtests=enabled
extra_envs: {}
# Alternative compiler setups
- name: gcc
args: -Dtests=enabled
extra_envs:
CC: gcc
CXX: g++
- name: clang
args: -Dtests=enabled
extra_envs:
CC: clang
CXX: clang++
- name: sanitize
args: >-
"-Db_sanitize=address,undefined"
extra_envs: {}
# This is for MSVC, which only supports AddressSanitizer.
# https://learn.microsoft.com/en-us/cpp/sanitizers/
- name: sanitize+asanonly
args: -Db_sanitize=address
extra_envs:
ASAN_OPTIONS: report_globals=0:halt_on_error=1:abort_on_error=1:print_summary=1
- name: clang+sanitize
args: >-
"-Db_sanitize=address,undefined"
extra_envs:
CC: clang
CXX: clang++
- name: clang+msan
args: -Db_sanitize=memory
extra_envs:
CC: clang
CXX: clang++
# default clang on GitHub hosted runners is from MSYS2.
# Use Visual Studio supplied clang-cl instead.
- name: clang-cl+sanitize
args: >-
"-Db_sanitize=address,undefined"
extra_envs:
CC: clang-cl
CXX: clang-cl
platform:
- ubuntu-latest
- windows-latest
- macos-latest
exclude:
# clang-cl only makes sense on windows.
- platform: ubuntu-latest
mode:
name: clang-cl+sanitize
- platform: macos-latest
mode:
name: clang-cl+sanitize
# Use clang-cl instead of MSYS2 clang.
#
# we already tested clang+sanitize on linux,
# if this doesn't work, it should be an issue for MSYS2 team to consider.
- platform: windows-latest
mode:
name: clang
- platform: windows-latest
mode:
name: clang+sanitize
- platform: windows-latest
mode:
name: clang+msan
# MSVC-only sanitizers
- platform: ubuntu-latest
mode:
name: sanitize+asanonly
- platform: macos-latest
mode:
name: sanitize+asanonly
- platform: windows-latest
mode:
name: sanitize
# clang is the default on macos
# also gcc is an alias to clang
- platform: macos-latest
mode:
name: clang
- platform: macos-latest
mode:
name: gcc
# gcc is the default on linux
- platform: ubuntu-latest
mode:
name: gcc
# only run sanitizer tests on linux
#
# gcc/clang's codegen shouldn't massively change across platforms,
# and linux supports most of the sanitizers.
- platform: macos-latest
mode:
name: clang+sanitize
- platform: macos-latest
mode:
# macos does not support msan
name: clang+msan
- platform: macos-latest
mode:
name: sanitize
steps:
- name: Setup meson
run: |
pipx install meson ninja
- name: Install mimalloc
if: ${{ matrix.platform == 'ubuntu-latest' && matrix.features.name == 'mimalloc' }}
run: sudo apt update && sudo apt -y install libmimalloc-dev
- name: Install mimalloc
if: ${{ matrix.platform == 'macos-latest' && matrix.features.name == 'mimalloc' }}
run: brew install mimalloc
# TODO: Install mimalloc on Windows
# You need to:
# - checkout mimalloc
# - `msbuild mimalloc\ide\vs2022\mimalloc.sln`
# - not cmake, because https://github.com/microsoft/mimalloc/issues/575#issuecomment-1112723975
# - it is possible to integrate vcpkg with meson, but:
# - 1. the above issue
# - 2. the vcpkg port of mimalloc is outdated, and still broken on server 2019
# - or maintain a meson port for mimalloc (and ensure it behaves correctly)
# - Make it findable with cmake
# - not the simpler pkg-config. although there was pkg-config in PATH,
# but that was from strawberry perl and thus broken
# ... good job, microsoft :))))
- name: Checkout
uses: actions/checkout@v6
- name: Activate MSVC and Configure
if: ${{ matrix.platform == 'windows-latest' }}
env: ${{ matrix.mode.extra_envs }}
run: |
meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} ${{ matrix.features.args }} --vsenv
- name: Configuring
if: ${{ matrix.platform != 'windows-latest' }}
env: ${{ matrix.mode.extra_envs }}
run: |
meson setup build-${{ matrix.flavor }} --buildtype=${{ matrix.flavor }} ${{ matrix.mode.args }} ${{ matrix.features.args }}
- name: Building
run: |
meson compile -C build-${{ matrix.flavor }}
- name: Running tests
env: ${{ matrix.mode.extra_envs }}
run: |
meson test -C build-${{ matrix.flavor }} --timeout-multiplier 5 --print-errorlogs
meson test --benchmark -C build-${{ matrix.flavor }} --timeout-multiplier 5 --print-errorlogs
- uses: actions/upload-artifact@v6
if: ${{ failure() }}
with:
name: ${{ matrix.platform }}-${{ matrix.mode.name }}-${{ matrix.features.name }}-${{ matrix.flavor }}-logs
path: build-${{ matrix.flavor }}/meson-logs
@@ -0,0 +1,49 @@
name: Docs
on:
push:
branches:
- master
paths:
- 'docs/**'
- '.github/workflows/*docs.yml'
jobs:
build:
name: Build Docusaurus
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: 'docs/.nvmrc'
- name: Install dependencies
working-directory: ./docs
run: npm install
- name: Build
working-directory: ./docs
run: npm run build
- name: Upload Build Artifact
uses: actions/upload-pages-artifact@v4
with:
path: docs/build
deploy:
name: Deploy to GitHub Pages
needs: build
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
# Deploy to the github-pages environment
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
@@ -0,0 +1,155 @@
name: release
on:
pull_request:
push:
tags:
- "v*.*.*"
jobs:
check_meson_version:
runs-on: ubuntu-22.04
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
steps:
- uses: actions/checkout@v6
- name: install meson and ninja
run: |
pip install --upgrade meson ninja
- name: check meson version
run: |
MESON_VERSION=$(meson introspect meson.build --projectinfo | jq -r '.version')
test "${{ github.ref_name }}" = "v${MESON_VERSION}"
linux:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
arch: [aarch64, riscv64, x86, x86_64]
steps:
- uses: actions/checkout@v6
- uses: jirutka/setup-alpine@v1
with:
arch: ${{matrix.arch}}
packages: "build-base make cmake"
- name: build
shell: alpine.sh {0}
run: |
mkdir build
cd build
cmake -DQJS_BUILD_CLI_STATIC=ON ..
cd ..
cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN)
cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN)
mv build/qjs build/qjs-linux-${{matrix.arch}}
mv build/qjsc build/qjsc-linux-${{matrix.arch}}
- name: check
shell: alpine.sh {0}
run: |
file build/*-linux-${{matrix.arch}}
- name: upload
uses: actions/upload-artifact@v6
with:
name: qjs-linux-${{matrix.arch}}
path: build/*-linux-${{matrix.arch}}
macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v6
- name: build
run: |
mkdir build
cd build
cmake -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" ..
make -j$(getconf _NPROCESSORS_ONLN)
make -C .. amalgam # writes build/quickjs-amalgam.zip
mv qjs qjs-darwin
mv qjsc qjsc-darwin
- name: check
run: |
lipo -info build/qjs-darwin build/qjsc-darwin
- name: upload amalgamation
uses: actions/upload-artifact@v6
with:
name: quickjs-amalgam.zip
path: build/quickjs-amalgam.zip
compression-level: 0 # already compressed
- name: upload
uses: actions/upload-artifact@v6
with:
name: qjs-darwin
path: build/*-darwin
windows:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
arch: [x86, x86_64]
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v6
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.arch == 'x86' && 'mingw32' || 'ucrt64' }}
install: >-
git
make
pacboy: >-
cmake:p
ninja:p
toolchain:p
- name: build
run: |
make
mv build/qjs.exe build/qjs-windows-${{matrix.arch}}.exe
mv build/qjsc.exe build/qjsc-windows-${{matrix.arch}}.exe
- name: check
run: |
file build/qjs-windows-${{matrix.arch}}.exe
ldd build/qjs-windows-${{matrix.arch}}.exe build/qjsc-windows-${{matrix.arch}}.exe
- name: upload
uses: actions/upload-artifact@v6
with:
name: qjs-windows-${{matrix.arch}}
path: build/*-windows-${{matrix.arch}}.exe
wasi:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v6
- name: setup wasi-sdk
run: |
wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.deb -P /tmp
sudo apt install /tmp/wasi-sdk*.deb
- name: build
run: |
cmake -B build -DCMAKE_TOOLCHAIN_FILE=/opt/wasi-sdk/share/cmake/wasi-sdk.cmake
make -C build qjs_exe
mv build/qjs build/qjs-wasi.wasm
- name: upload
uses: actions/upload-artifact@v6
with:
name: qjs-wasi
path: build/qjs-wasi.wasm
upload-to-release:
needs: [linux, macos, windows, wasi, check_meson_version]
runs-on: ubuntu-22.04
steps:
- name: get assets
uses: actions/download-artifact@v7
with:
path: build
merge-multiple: true
- run: ls -R build
- name: release
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
uses: softprops/action-gh-release@v2
with:
files: |
build/*
@@ -0,0 +1,23 @@
name: Test Docs
on:
pull_request:
paths:
- 'docs/**'
- '.github/workflows/*docs.yml'
jobs:
test-docs:
name: Test Docusaurus build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version-file: 'docs/.nvmrc'
- name: Install dependencies
working-directory: ./docs
run: npm install
- name: Build
working-directory: ./docs
run: npm run build
@@ -0,0 +1,32 @@
name: tsan
on:
push:
branches:
- master
paths:
- '**'
- '!.gitignore'
- '!LICENSE'
- '!README.md'
- '!docs/**'
- '!examples/**'
- '.github/workflows/tsan.yml'
- '.github/workflows/valgrind.yml'
workflow_dispatch:
jobs:
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: true
- name: build
run: |
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DQJS_ENABLE_TSAN=ON
cmake --build build -j`nproc`
- name: test
run: |
git submodule update --init --checkout --depth 1
./build/run-test262 -m -c test262.conf -c test262-fast.conf -a
@@ -0,0 +1,33 @@
name: valgrind
on:
push:
branches:
- master
paths:
- '**'
- '!.gitignore'
- '!LICENSE'
- '!README.md'
- '!docs/**'
- '!examples/**'
- '.github/workflows/tsan.yml'
- '.github/workflows/valgrind.yml'
workflow_dispatch:
jobs:
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
submodules: true
- name: install valgrind
run: sudo apt-get update && sudo apt-get install valgrind
- name: build
run: |
make BUILD_TYPE=RelWithDebInfo
- name: test
run: |
git submodule update --init --checkout --depth 1
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --error-exitcode=1 ./build/run-test262 -m -c test262.conf -c test262-fast.conf -a
@@ -0,0 +1,14 @@
*.a
*.orig
*.so
.obj/
build/
unicode/
.idea
cmake-*
.vs
out/
CMakeUserPresets.json
fuzz
.vscode/
microbench*.txt
@@ -0,0 +1,5 @@
[submodule "test262"]
path = test262
url = https://github.com/tc39/test262
shallow = true
update = none
@@ -0,0 +1,461 @@
cmake_minimum_required(VERSION 3.10)
project(quickjs LANGUAGES C)
include(CheckCCompilerFlag)
include(GNUInstallDirs)
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON)
set(CMAKE_C_STANDARD 11)
# MINGW doesn't exist in older cmake versions, newer versions don't know
# about CMAKE_COMPILER_IS_MINGW, and there is no unique CMAKE_C_COMPILER_ID
# for mingw-based compilers...
if(MINGW)
# do nothing
elseif(CMAKE_C_COMPILER MATCHES "mingw")
set(MINGW TRUE)
else()
set(MINGW FALSE)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "tvOS")
set(TVOS TRUE)
else()
set(TVOS FALSE)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "watchOS")
set(WATCHOS TRUE)
else()
set(WATCHOS FALSE)
endif()
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "No build type selected, default to Release")
set(CMAKE_BUILD_TYPE "Release")
endif()
message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode")
message(STATUS "Building with ${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION} on ${CMAKE_SYSTEM}")
macro(xcheck_add_c_compiler_flag FLAG)
string(REPLACE "-" "" FLAG_NO_HYPHEN ${FLAG})
check_c_compiler_flag(${FLAG} COMPILER_SUPPORTS_${FLAG_NO_HYPHEN})
if(COMPILER_SUPPORTS_${FLAG_NO_HYPHEN})
add_compile_options(${FLAG})
endif()
endmacro()
xcheck_add_c_compiler_flag(-Wall)
if(NOT MSVC AND NOT IOS AND NOT TVOS AND NOT WATCHOS)
xcheck_add_c_compiler_flag(-Werror)
xcheck_add_c_compiler_flag(-Wextra)
endif()
xcheck_add_c_compiler_flag(-Wformat=2)
xcheck_add_c_compiler_flag(-Wno-implicit-fallthrough)
xcheck_add_c_compiler_flag(-Wno-sign-compare)
xcheck_add_c_compiler_flag(-Wno-missing-field-initializers)
xcheck_add_c_compiler_flag(-Wno-unused-parameter)
xcheck_add_c_compiler_flag(-Wno-unused-but-set-variable)
xcheck_add_c_compiler_flag(-Wno-unused-result)
xcheck_add_c_compiler_flag(-Wno-stringop-truncation)
xcheck_add_c_compiler_flag(-Wno-array-bounds)
xcheck_add_c_compiler_flag(-funsigned-char)
# ClangCL is command line compatible with MSVC, so 'MSVC' is set.
if(MSVC)
xcheck_add_c_compiler_flag(-Wno-unsafe-buffer-usage)
xcheck_add_c_compiler_flag(-Wno-sign-conversion)
xcheck_add_c_compiler_flag(-Wno-nonportable-system-include-path)
xcheck_add_c_compiler_flag(-Wno-implicit-int-conversion)
xcheck_add_c_compiler_flag(-Wno-shorten-64-to-32)
xcheck_add_c_compiler_flag(-Wno-reserved-macro-identifier)
xcheck_add_c_compiler_flag(-Wno-reserved-identifier)
xcheck_add_c_compiler_flag(-Wdeprecated-declarations)
xcheck_add_c_compiler_flag(/experimental:c11atomics)
xcheck_add_c_compiler_flag(/wd4018) # -Wno-sign-conversion
xcheck_add_c_compiler_flag(/wd4061) # -Wno-implicit-fallthrough
xcheck_add_c_compiler_flag(/wd4100) # -Wno-unused-parameter
xcheck_add_c_compiler_flag(/wd4200) # -Wno-zero-length-array
xcheck_add_c_compiler_flag(/wd4242) # -Wno-shorten-64-to-32
xcheck_add_c_compiler_flag(/wd4244) # -Wno-shorten-64-to-32
xcheck_add_c_compiler_flag(/wd4245) # -Wno-sign-compare
xcheck_add_c_compiler_flag(/wd4267) # -Wno-shorten-64-to-32
xcheck_add_c_compiler_flag(/wd4388) # -Wno-sign-compare
xcheck_add_c_compiler_flag(/wd4389) # -Wno-sign-compare
xcheck_add_c_compiler_flag(/wd4456) # Hides previous local declaration
xcheck_add_c_compiler_flag(/wd4457) # Hides function parameter
xcheck_add_c_compiler_flag(/wd4710) # Function not inlined
xcheck_add_c_compiler_flag(/wd4711) # Function was inlined
xcheck_add_c_compiler_flag(/wd4820) # Padding added after construct
xcheck_add_c_compiler_flag(/wd4996) # -Wdeprecated-declarations
xcheck_add_c_compiler_flag(/wd5045) # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
endif()
# Set a 8MB default stack size on Windows.
# It defaults to 1MB on MSVC, which is the same as our current JS stack size,
# so it will overflow and crash otherwise.
# On MinGW it defaults to 2MB.
if(WIN32)
if(MSVC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:8388608")
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608")
endif()
endif()
# MacOS and GCC 11 or later need -Wno-maybe-uninitialized
# https://github.com/quickjs-ng/quickjs/issues/453
if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 11)
xcheck_add_c_compiler_flag(-Wno-maybe-uninitialized)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
add_compile_definitions(
_WASI_EMULATED_PROCESS_CLOCKS
_WASI_EMULATED_SIGNAL
)
add_link_options(
-lwasi-emulated-process-clocks
-lwasi-emulated-signal
)
endif()
if(CMAKE_BUILD_TYPE MATCHES "Debug")
xcheck_add_c_compiler_flag(/Od)
xcheck_add_c_compiler_flag(-O0)
xcheck_add_c_compiler_flag(-ggdb)
xcheck_add_c_compiler_flag(-fno-omit-frame-pointer)
endif()
macro(xoption OPTION_NAME OPTION_TEXT OPTION_DEFAULT)
option(${OPTION_NAME} ${OPTION_TEXT} ${OPTION_DEFAULT})
if(DEFINED ENV{${OPTION_NAME}})
# Allow setting the option through an environment variable.
set(${OPTION_NAME} $ENV{${OPTION_NAME}})
endif()
if(${OPTION_NAME})
add_definitions(-D${OPTION_NAME})
endif()
message(STATUS " ${OPTION_NAME}: ${${OPTION_NAME}}")
endmacro()
xoption(BUILD_SHARED_LIBS "Build a shared library" OFF)
if(BUILD_SHARED_LIBS)
message(STATUS "Building a shared library")
endif()
# note: QJS_ENABLE_TSAN is currently incompatible with the other sanitizers but we
# don't explicitly check for that because who knows what the future will bring?
# QJS_ENABLE_MSAN only works with clang at the time of writing; also not checked
# for the same reason
xoption(QJS_BUILD_EXAMPLES "Build examples" OFF)
xoption(QJS_BUILD_CLI_STATIC "Build a static qjs executable" OFF)
xoption(QJS_BUILD_CLI_WITH_MIMALLOC "Build the qjs executable with mimalloc" OFF)
xoption(QJS_BUILD_CLI_WITH_STATIC_MIMALLOC "Build the qjs executable with mimalloc (statically linked)" OFF)
xoption(QJS_DISABLE_PARSER "Disable JS source code parser" OFF)
xoption(QJS_ENABLE_ASAN "Enable AddressSanitizer (ASan)" OFF)
xoption(QJS_ENABLE_MSAN "Enable MemorySanitizer (MSan)" OFF)
xoption(QJS_ENABLE_TSAN "Enable ThreadSanitizer (TSan)" OFF)
xoption(QJS_ENABLE_UBSAN "Enable UndefinedBehaviorSanitizer (UBSan)" OFF)
if(QJS_ENABLE_ASAN)
message(STATUS "Building with ASan")
add_compile_options(
-fsanitize=address
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
add_link_options(
-fsanitize=address
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
endif()
if(QJS_ENABLE_MSAN)
message(STATUS "Building with MSan")
add_compile_options(
-fsanitize=memory
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
add_link_options(
-fsanitize=memory
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
endif()
if(QJS_ENABLE_TSAN)
message(STATUS "Building with TSan")
add_compile_options(
-fsanitize=thread
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
add_link_options(
-fsanitize=thread
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
endif()
if(QJS_ENABLE_UBSAN)
message(STATUS "Building with UBSan")
add_compile_options(
-fsanitize=undefined
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
add_link_options(
-fsanitize=undefined
-fno-sanitize-recover=all
-fno-omit-frame-pointer
)
endif()
# QuickJS library
#
xoption(QJS_BUILD_LIBC "Build standard library modules as part of the library" OFF)
macro(add_qjs_libc_if_needed target)
if(NOT QJS_BUILD_LIBC)
target_sources(${target} PRIVATE quickjs-libc.c)
endif()
endmacro()
macro(add_static_if_needed target)
if(QJS_BUILD_CLI_STATIC OR MINGW)
target_link_options(${target} PRIVATE -static)
if(MINGW)
target_link_options(${target} PRIVATE -static-libgcc)
endif()
endif()
endmacro()
set(qjs_sources
cutils.c
dtoa.c
libregexp.c
libunicode.c
quickjs.c
)
if(QJS_BUILD_LIBC)
list(APPEND qjs_sources quickjs-libc.c)
endif()
list(APPEND qjs_defines _GNU_SOURCE)
if(WIN32)
# NB: Windows 7 is EOL and we are only supporting in so far as it doesn't interfere with progress.
list(APPEND qjs_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0601)
endif()
if(TVOS)
list(APPEND qjs_defines _TVOS)
endif()
if(WATCHOS)
list(APPEND qjs_defines _WATCHOS)
endif()
list(APPEND qjs_libs ${CMAKE_DL_LIBS})
find_package(Threads)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI")
list(APPEND qjs_libs ${CMAKE_THREAD_LIBS_INIT})
endif()
# try to find libm
find_library(M_LIBRARIES m)
if(M_LIBRARIES OR CMAKE_C_COMPILER_ID STREQUAL "TinyCC")
list(APPEND qjs_libs m)
endif()
add_library(qjs ${qjs_sources})
target_compile_definitions(qjs PRIVATE ${qjs_defines})
target_include_directories(qjs PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(qjs PUBLIC ${qjs_libs})
if(EMSCRIPTEN)
add_executable(qjs_wasm ${qjs_sources})
target_link_options(qjs_wasm PRIVATE
# in emscripten 3.x, this will be set to 16k which is too small for quickjs. #write sth. to force github rebuild
-sSTACK_SIZE=2097152 # let it be 2m = 2 * 1024 * 1024 = 2097152, otherwise, stack overflow may be occured at bootstrap
-sNO_INVOKE_RUN
-sNO_EXIT_RUNTIME
-sMODULARIZE # do not mess the global
-sEXPORT_ES6 # export js file to morden es module
-sEXPORT_NAME=getQuickJs # give a name
-sTEXTDECODER=1 # it will be 2 if we use -Oz, and that will cause js -> c string convertion fail
-sNO_DEFAULT_TO_CXX # this project is pure c project, no need for c plus plus handle
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap
)
target_compile_definitions(qjs_wasm PRIVATE ${qjs_defines})
target_link_libraries(qjs_wasm m)
endif()
# QuickJS bytecode compiler
#
add_executable(qjsc
qjsc.c
)
add_qjs_libc_if_needed(qjsc)
add_static_if_needed(qjsc)
target_compile_definitions(qjsc PRIVATE ${qjs_defines})
target_link_libraries(qjsc qjs)
# QuickJS CLI
#
add_executable(qjs_exe
gen/repl.c
gen/standalone.c
qjs.c
)
add_qjs_libc_if_needed(qjs_exe)
add_static_if_needed(qjs_exe)
set_target_properties(qjs_exe PROPERTIES
OUTPUT_NAME "qjs"
)
target_compile_definitions(qjs_exe PRIVATE ${qjs_defines})
target_link_libraries(qjs_exe qjs)
if(NOT WIN32)
set_target_properties(qjs_exe PROPERTIES ENABLE_EXPORTS TRUE)
endif()
if(QJS_BUILD_CLI_WITH_MIMALLOC OR QJS_BUILD_CLI_WITH_STATIC_MIMALLOC)
find_package(mimalloc REQUIRED)
# Upstream mimalloc doesn't provide a way to know if both libraries are supported.
if(QJS_BUILD_CLI_WITH_STATIC_MIMALLOC)
target_link_libraries(qjs_exe mimalloc-static)
else()
target_link_libraries(qjs_exe mimalloc)
endif()
endif()
# Test262 runner
#
if(NOT EMSCRIPTEN)
add_executable(run-test262
run-test262.c
)
add_qjs_libc_if_needed(run-test262)
target_compile_definitions(run-test262 PRIVATE ${qjs_defines})
target_link_libraries(run-test262 qjs)
endif()
# Interrupt test
#
add_executable(api-test
api-test.c
)
target_compile_definitions(api-test PRIVATE ${qjs_defines})
target_link_libraries(api-test qjs)
# Unicode generator
#
add_executable(unicode_gen EXCLUDE_FROM_ALL
cutils.c
libunicode.c
unicode_gen.c
)
target_compile_definitions(unicode_gen PRIVATE ${qjs_defines})
add_executable(function_source
gen/function_source.c
)
add_qjs_libc_if_needed(function_source)
target_include_directories(function_source PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(function_source PRIVATE ${qjs_defines})
target_link_libraries(function_source qjs)
# Examples
#
if(QJS_BUILD_EXAMPLES)
add_executable(hello
gen/hello.c
)
add_qjs_libc_if_needed(hello)
target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(hello PRIVATE ${qjs_defines})
target_link_libraries(hello qjs)
add_executable(hello_module
gen/hello_module.c
)
add_qjs_libc_if_needed(hello_module)
target_include_directories(hello_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(hello_module PRIVATE ${qjs_defines})
target_link_libraries(hello_module qjs)
add_library(fib MODULE examples/fib.c)
set_target_properties(fib PROPERTIES
PREFIX ""
C_VISIBILITY_PRESET default
)
target_compile_definitions(fib PRIVATE JS_SHARED_LIBRARY)
if(WIN32)
target_link_libraries(fib qjs)
elseif(APPLE)
target_link_options(fib PRIVATE -undefined dynamic_lookup)
endif()
add_library(point MODULE examples/point.c)
set_target_properties(point PROPERTIES
PREFIX ""
C_VISIBILITY_PRESET default
)
target_compile_definitions(point PRIVATE JS_SHARED_LIBRARY)
if(WIN32)
target_link_libraries(point qjs)
elseif(APPLE)
target_link_options(point PRIVATE -undefined dynamic_lookup)
endif()
add_executable(test_fib
examples/fib.c
gen/test_fib.c
)
add_qjs_libc_if_needed(test_fib)
target_include_directories(test_fib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(test_fib PRIVATE ${qjs_defines})
target_link_libraries(test_fib qjs)
endif()
# Install target
#
file(STRINGS quickjs.h quickjs_h REGEX QJS_VERSION)
string(REGEX MATCH "QJS_VERSION_MAJOR ([0-9]*)" _ "${quickjs_h}")
set(QJS_VERSION_MAJOR ${CMAKE_MATCH_1})
string(REGEX MATCH "QJS_VERSION_MINOR ([0-9]*)" _ "${quickjs_h}")
set(QJS_VERSION_MINOR ${CMAKE_MATCH_1})
string(REGEX MATCH "QJS_VERSION_PATCH ([0-9]*)" _ "${quickjs_h}")
set(QJS_VERSION_PATCH ${CMAKE_MATCH_1})
set_target_properties(qjs PROPERTIES
VERSION ${QJS_VERSION_MAJOR}.${QJS_VERSION_MINOR}.${QJS_VERSION_PATCH}
SOVERSION ${QJS_VERSION_MAJOR}
)
install(FILES quickjs.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(QJS_BUILD_LIBC)
install(FILES quickjs-libc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endif()
if(NOT IOS AND NOT TVOS AND NOT WATCHOS)
install(TARGETS qjs_exe RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS qjsc RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
install(TARGETS qjs EXPORT qjsConfig
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT qjsConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/quickjs)
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(DIRECTORY examples DESTINATION ${CMAKE_INSTALL_DOCDIR})
+24
View File
@@ -0,0 +1,24 @@
The MIT License (MIT)
Copyright (c) 2017-2024 Fabrice Bellard
Copyright (c) 2017-2024 Charlie Gordon
Copyright (c) 2023-2025 Ben Noordhuis
Copyright (c) 2023-2025 Saúl Ibarra Corretgé
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+147
View File
@@ -0,0 +1,147 @@
#
# QuickJS Javascript Engine
#
# Copyright (c) 2017-2024 Fabrice Bellard
# Copyright (c) 2017-2024 Charlie Gordon
# Copyright (c) 2023-2025 Ben Noordhuis
# Copyright (c) 2023-2025 Saúl Ibarra Corretgé
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
BUILD_DIR=build
BUILD_TYPE?=Release
INSTALL_PREFIX?=/usr/local
QJS=$(BUILD_DIR)/qjs
QJSC=$(BUILD_DIR)/qjsc
RUN262=$(BUILD_DIR)/run-test262
JOBS?=$(shell getconf _NPROCESSORS_ONLN)
ifeq ($(JOBS),)
JOBS := $(shell sysctl -n hw.ncpu)
endif
ifeq ($(JOBS),)
JOBS := $(shell nproc)
endif
ifeq ($(JOBS),)
JOBS := 4
endif
all: $(QJS)
amalgam: TEMP := $(shell mktemp -d)
amalgam: $(QJS)
$(QJS) amalgam.js $(TEMP)/quickjs-amalgam.c
cp quickjs.h quickjs-libc.h $(TEMP)
cd $(TEMP) && zip -9 quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h
cp $(TEMP)/quickjs-amalgam.zip $(BUILD_DIR)
cd $(TEMP) && $(RM) quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h
$(RM) -d $(TEMP)
fuzz:
clang -g -O1 -fsanitize=address,undefined,fuzzer -o fuzz fuzz.c
./fuzz
$(BUILD_DIR):
cmake -B $(BUILD_DIR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DCMAKE_INSTALL_PREFIX=$(INSTALL_PREFIX)
$(QJS): $(BUILD_DIR)
cmake --build $(BUILD_DIR) -j $(JOBS)
$(QJSC): $(BUILD_DIR)
cmake --build $(BUILD_DIR) --target qjsc -j $(JOBS)
install: $(QJS) $(QJSC)
cmake --build $(BUILD_DIR) --target install
clean:
cmake --build $(BUILD_DIR) --target clean
codegen: $(QJSC)
$(QJSC) -ss -o gen/repl.c -m repl.js
$(QJSC) -ss -o gen/standalone.c -m standalone.js
$(QJSC) -e -o gen/function_source.c tests/function_source.js
$(QJSC) -e -o gen/hello.c examples/hello.js
$(QJSC) -e -o gen/hello_module.c -m examples/hello_module.js
$(QJSC) -e -o gen/test_fib.c -m examples/test_fib.js
$(QJSC) -C -ss -o builtin-array-fromasync.h builtin-array-fromasync.js
debug:
BUILD_TYPE=Debug $(MAKE)
distclean:
@rm -rf $(BUILD_DIR)
stats: $(QJS)
$(QJS) -qd
jscheck: CFLAGS=-I. -D_GNU_SOURCE -DJS_CHECK_JSVALUE -Wall -Werror -fsyntax-only -c -o /dev/null
jscheck:
$(CC) $(CFLAGS) api-test.c
$(CC) $(CFLAGS) ctest.c
$(CC) $(CFLAGS) fuzz.c
$(CC) $(CFLAGS) gen/function_source.c
$(CC) $(CFLAGS) gen/hello.c
$(CC) $(CFLAGS) gen/hello_module.c
$(CC) $(CFLAGS) gen/repl.c
$(CC) $(CFLAGS) gen/standalone.c
$(CC) $(CFLAGS) gen/test_fib.c
$(CC) $(CFLAGS) qjs.c
$(CC) $(CFLAGS) qjsc.c
$(CC) $(CFLAGS) quickjs-libc.c
$(CC) $(CFLAGS) quickjs.c
$(CC) $(CFLAGS) run-test262.c
# effectively .PHONY because it doesn't generate output
ctest: CFLAGS=-std=c11 -fsyntax-only -Wall -Wextra -Werror -pedantic
ctest: ctest.c quickjs.h
$(CC) $(CFLAGS) -DJS_NAN_BOXING=0 $<
$(CC) $(CFLAGS) -DJS_NAN_BOXING=1 $<
# effectively .PHONY because it doesn't generate output
cxxtest: CXXFLAGS=-std=c++11 -fsyntax-only -Wall -Wextra -Werror -pedantic
cxxtest: cxxtest.cc quickjs.h
$(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=0 $<
$(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=1 $<
test: $(QJS)
$(RUN262) -c tests.conf
test262: $(QJS)
$(RUN262) -m -c test262.conf -a
test262-fast: $(QJS)
$(RUN262) -m -c test262.conf -c test262-fast.conf -a
test262-update: $(QJS)
$(RUN262) -u -c test262.conf -a -t 1
test262-check: $(QJS)
$(RUN262) -m -c test262.conf -E -a
microbench: $(QJS)
$(QJS) tests/microbench.js
unicode_gen: $(BUILD_DIR)
cmake --build $(BUILD_DIR) --target unicode_gen
libunicode-table.h: unicode_gen
$(BUILD_DIR)/unicode_gen unicode $@
.PHONY: all amalgam ctest cxxtest debug fuzz jscheck install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC)
+24
View File
@@ -0,0 +1,24 @@
# ⚡️ QuickJS - A mighty JavaScript engine
## Overview
QuickJS is a small and embeddable JavaScript engine. It aims to support the latest
[ECMAScript] specification.
This project is a _fork_ of the [original QuickJS project] by Fabrice Bellard and Charlie Gordon, after it went dormant, with the intent of reigniting its development.
## Getting started
Head over to the [project website] for instructions on how to get started and more
documentation.
## Authors
[@bnoordhuis], [@saghul], and many more [contributors].
[ECMAScript]: https://tc39.es/ecma262/
[original QuickJS project]: https://bellard.org/quickjs
[@bnoordhuis]: https://github.com/bnoordhuis
[@saghul]: https://github.com/saghul
[contributors]: https://github.com/quickjs-ng/quickjs/graphs/contributors
[project website]: https://quickjs-ng.github.io/quickjs/
+49
View File
@@ -0,0 +1,49 @@
import {loadFile, writeFile} from "qjs:std"
const cutils_c = loadFile("cutils.c")
const cutils_h = loadFile("cutils.h")
const dtoa_c = loadFile("dtoa.c")
const dtoa_h = loadFile("dtoa.h")
const libregexp_c = loadFile("libregexp.c")
const libregexp_h = loadFile("libregexp.h")
const libregexp_opcode_h = loadFile("libregexp-opcode.h")
const libunicode_c = loadFile("libunicode.c")
const libunicode_h = loadFile("libunicode.h")
const libunicode_table_h = loadFile("libunicode-table.h")
const list_h = loadFile("list.h")
const quickjs_atom_h = loadFile("quickjs-atom.h")
const quickjs_c = loadFile("quickjs.c")
const quickjs_c_atomics_h = loadFile("quickjs-c-atomics.h")
const quickjs_h = loadFile("quickjs.h")
const quickjs_libc_c = loadFile("quickjs-libc.c")
const quickjs_libc_h = loadFile("quickjs-libc.h")
const quickjs_opcode_h = loadFile("quickjs-opcode.h")
const gen_builtin_array_fromasync_h = loadFile("builtin-array-fromasync.h")
let source = "#if defined(QJS_BUILD_LIBC) && defined(__linux__) && !defined(_GNU_SOURCE)\n"
+ "#define _GNU_SOURCE\n"
+ "#endif\n"
+ quickjs_c_atomics_h
+ cutils_h
+ dtoa_h
+ list_h
+ libunicode_h // exports lre_is_id_start, used by libregexp.h
+ libregexp_h
+ libunicode_table_h
+ quickjs_h
+ quickjs_c
+ cutils_c
+ dtoa_c
+ libregexp_c
+ libunicode_c
+ "#ifdef QJS_BUILD_LIBC\n"
+ quickjs_libc_h
+ quickjs_libc_c
+ "#endif // QJS_BUILD_LIBC\n"
source = source.replace(/#include "quickjs-atom.h"/g, quickjs_atom_h)
source = source.replace(/#include "quickjs-opcode.h"/g, quickjs_opcode_h)
source = source.replace(/#include "libregexp-opcode.h"/g, libregexp_opcode_h)
source = source.replace(/#include "builtin-array-fromasync.h"/g,
gen_builtin_array_fromasync_h)
source = source.replace(/#include "[^"]+"/g, "")
writeFile(execArgv[2] ?? "quickjs-amalgam.c", source)
+854
View File
@@ -0,0 +1,854 @@
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "quickjs.h"
#include "cutils.h"
static JSValue eval(JSContext *ctx, const char *code)
{
return JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_GLOBAL);
}
static JSValue cfunc_callback(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
return JS_ThrowTypeError(ctx, "from cfunc");
}
static JSValue cfuncdata_callback(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv,
int magic, JSValueConst *func_data)
{
return JS_ThrowTypeError(ctx, "from cfuncdata");
}
static JSValue cclosure_callback(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv,
int magic, void *func_data)
{
return JS_ThrowTypeError(ctx, "from cclosure");
}
static bool closure_finalized = false;
static void cclosure_opaque_finalize(void *opaque)
{
if ((intptr_t)opaque == 12)
closure_finalized = true;
}
static void cfunctions(void)
{
uint32_t length;
const char *s;
JSValue ret, stack;
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
JSValue cfunc = JS_NewCFunction(ctx, cfunc_callback, "cfunc", 42);
JSValue cfuncdata =
JS_NewCFunctionData2(ctx, cfuncdata_callback, "cfuncdata",
/*length*/1337, /*magic*/0, /*data_len*/0, NULL);
JSValue cclosure =
JS_NewCClosure(ctx, cclosure_callback, "cclosure", cclosure_opaque_finalize,
/*length*/0xC0DE, /*magic*/11, /*opaque*/(void*)12);
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global, "cfunc", cfunc);
JS_SetPropertyStr(ctx, global, "cfuncdata", cfuncdata);
JS_SetPropertyStr(ctx, global, "cclosure", cclosure);
JS_FreeValue(ctx, global);
ret = eval(ctx, "cfunc.name");
assert(!JS_IsException(ret));
assert(JS_IsString(ret));
s = JS_ToCString(ctx, ret);
JS_FreeValue(ctx, ret);
assert(s);
assert(!strcmp(s, "cfunc"));
JS_FreeCString(ctx, s);
ret = eval(ctx, "cfunc.length");
assert(!JS_IsException(ret));
assert(JS_IsNumber(ret));
assert(0 == JS_ToUint32(ctx, &length, ret));
assert(length == 42);
ret = eval(ctx, "cfuncdata.name");
assert(!JS_IsException(ret));
assert(JS_IsString(ret));
s = JS_ToCString(ctx, ret);
JS_FreeValue(ctx, ret);
assert(s);
assert(!strcmp(s, "cfuncdata"));
JS_FreeCString(ctx, s);
ret = eval(ctx, "cfuncdata.length");
assert(!JS_IsException(ret));
assert(JS_IsNumber(ret));
assert(0 == JS_ToUint32(ctx, &length, ret));
assert(length == 1337);
ret = eval(ctx, "cclosure.name");
assert(!JS_IsException(ret));
assert(JS_IsString(ret));
s = JS_ToCString(ctx, ret);
JS_FreeValue(ctx, ret);
assert(s);
assert(!strcmp(s, "cclosure"));
JS_FreeCString(ctx, s);
ret = eval(ctx, "cclosure.length");
assert(!JS_IsException(ret));
assert(JS_IsNumber(ret));
assert(0 == JS_ToUint32(ctx, &length, ret));
assert(length == 0xC0DE);
ret = eval(ctx, "cfunc()");
assert(JS_IsException(ret));
ret = JS_GetException(ctx);
assert(JS_IsError(ret));
stack = JS_GetPropertyStr(ctx, ret, "stack");
assert(JS_IsString(stack));
s = JS_ToCString(ctx, stack);
JS_FreeValue(ctx, stack);
assert(s);
assert(!strcmp(s, " at cfunc (native)\n at <eval> (<input>:1:1)\n"));
JS_FreeCString(ctx, s);
s = JS_ToCString(ctx, ret);
JS_FreeValue(ctx, ret);
assert(s);
assert(!strcmp(s, "TypeError: from cfunc"));
JS_FreeCString(ctx, s);
ret = eval(ctx, "cfuncdata()");
assert(JS_IsException(ret));
ret = JS_GetException(ctx);
assert(JS_IsError(ret));
stack = JS_GetPropertyStr(ctx, ret, "stack");
assert(JS_IsString(stack));
s = JS_ToCString(ctx, stack);
JS_FreeValue(ctx, stack);
assert(s);
assert(!strcmp(s, " at cfuncdata (native)\n at <eval> (<input>:1:1)\n"));
JS_FreeCString(ctx, s);
s = JS_ToCString(ctx, ret);
JS_FreeValue(ctx, ret);
assert(s);
assert(!strcmp(s, "TypeError: from cfuncdata"));
JS_FreeCString(ctx, s);
ret = eval(ctx, "cclosure()");
assert(JS_IsException(ret));
ret = JS_GetException(ctx);
assert(JS_IsError(ret));
stack = JS_GetPropertyStr(ctx, ret, "stack");
assert(JS_IsString(stack));
s = JS_ToCString(ctx, stack);
JS_FreeValue(ctx, stack);
assert(s);
assert(!strcmp(s, " at cclosure (native)\n at <eval> (<input>:1:1)\n"));
JS_FreeCString(ctx, s);
s = JS_ToCString(ctx, ret);
JS_FreeValue(ctx, ret);
assert(s);
assert(!strcmp(s, "TypeError: from cclosure"));
JS_FreeCString(ctx, s);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
assert(closure_finalized);
}
#define MAX_TIME 10
static int timeout_interrupt_handler(JSRuntime *rt, void *opaque)
{
int *time = (int *)opaque;
if (*time <= MAX_TIME)
*time += 1;
return *time > MAX_TIME;
}
static void sync_call(void)
{
static const char code[] =
"(function() { \
try { \
while (true) {} \
} catch (e) {} \
})();";
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
int time = 0;
JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time);
JSValue ret = eval(ctx, code);
assert(time > MAX_TIME);
assert(JS_IsException(ret));
JS_FreeValue(ctx, ret);
assert(JS_HasException(ctx));
JSValue e = JS_GetException(ctx);
assert(JS_IsUncatchableError(e));
JS_FreeValue(ctx, e);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void async_call(void)
{
static const char code[] =
"(async function() { \
const loop = async () => { \
await Promise.resolve(); \
while (true) {} \
}; \
await loop().catch(() => {}); \
})();";
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
int time = 0;
JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time);
JSValue ret = eval(ctx, code);
assert(!JS_IsException(ret));
JS_FreeValue(ctx, ret);
assert(JS_IsJobPending(rt));
int r = 0;
while (JS_IsJobPending(rt)) {
r = JS_ExecutePendingJob(rt, &ctx);
}
assert(time > MAX_TIME);
assert(r == -1);
assert(JS_HasException(ctx));
JSValue e = JS_GetException(ctx);
assert(JS_IsUncatchableError(e));
JS_FreeValue(ctx, e);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static JSValue save_value(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
assert(argc == 1);
JSValue *p = (JSValue *)JS_GetContextOpaque(ctx);
*p = JS_DupValue(ctx, argv[0]);
return JS_UNDEFINED;
}
static void async_call_stack_overflow(void)
{
static const char code[] =
"(async function() { \
const f = () => f(); \
try { \
await Promise.resolve(); \
f(); \
} catch (e) { \
save_value(e); \
} \
})();";
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
JSValue value = JS_UNDEFINED;
JS_SetContextOpaque(ctx, &value);
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global, "save_value", JS_NewCFunction(ctx, save_value, "save_value", 1));
JS_FreeValue(ctx, global);
JSValue ret = eval(ctx, code);
assert(!JS_IsException(ret));
JS_FreeValue(ctx, ret);
assert(JS_IsJobPending(rt));
int r = 0;
while (JS_IsJobPending(rt)) {
r = JS_ExecutePendingJob(rt, &ctx);
}
assert(r == 1);
assert(!JS_HasException(ctx));
assert(JS_IsError(value)); // stack overflow should be caught
JS_FreeValue(ctx, value);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
// https://github.com/quickjs-ng/quickjs/issues/914
static void raw_context_global_var(void)
{
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContextRaw(rt);
JS_AddIntrinsicEval(ctx);
{
JSValue ret = eval(ctx, "globalThis");
assert(JS_IsException(ret));
JS_FreeValue(ctx, ret);
}
{
JSValue ret = eval(ctx, "var x = 42");
assert(JS_IsUndefined(ret));
JS_FreeValue(ctx, ret);
}
{
JSValue ret = eval(ctx, "function f() {}");
assert(JS_IsUndefined(ret));
JS_FreeValue(ctx, ret);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void is_array(void)
{
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
{
JSValue ret = eval(ctx, "[]");
assert(!JS_IsException(ret));
assert(JS_IsArray(ret));
JS_FreeValue(ctx, ret);
}
{
JSValue ret = eval(ctx, "new Proxy([], {})");
assert(!JS_IsException(ret));
assert(!JS_IsArray(ret));
assert(JS_IsProxy(ret));
JSValue handler = JS_GetProxyHandler(ctx, ret);
JSValue target = JS_GetProxyTarget(ctx, ret);
assert(!JS_IsException(handler));
assert(!JS_IsException(target));
assert(!JS_IsProxy(handler));
assert(!JS_IsProxy(target));
assert(JS_IsObject(handler));
assert(JS_IsArray(target));
JS_FreeValue(ctx, handler);
JS_FreeValue(ctx, target);
JS_FreeValue(ctx, ret);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static int loader_calls;
static JSModuleDef *loader(JSContext *ctx, const char *name, void *opaque)
{
loader_calls++;
assert(!strcmp(name, "b"));
static const char code[] = "export function f(x){}";
JSValue ret = JS_Eval(ctx, code, strlen(code), "b",
JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY);
assert(!JS_IsException(ret));
JSModuleDef *m = JS_VALUE_GET_PTR(ret);
assert(m);
JS_FreeValue(ctx, ret);
return m;
}
static void module_serde(void)
{
JSRuntime *rt = JS_NewRuntime();
//JS_SetDumpFlags(rt, JS_DUMP_MODULE_RESOLVE);
JS_SetModuleLoaderFunc(rt, NULL, loader, NULL);
JSContext *ctx = JS_NewContext(rt);
static const char code[] = "import {f} from 'b'; f()";
assert(loader_calls == 0);
JSValue mod = JS_Eval(ctx, code, strlen(code), "a",
JS_EVAL_TYPE_MODULE|JS_EVAL_FLAG_COMPILE_ONLY);
assert(loader_calls == 1);
assert(!JS_IsException(mod));
assert(JS_IsModule(mod));
size_t len = 0;
uint8_t *buf = JS_WriteObject(ctx, &len, mod,
JS_WRITE_OBJ_BYTECODE|JS_WRITE_OBJ_REFERENCE);
assert(buf);
assert(len > 0);
JS_FreeValue(ctx, mod);
assert(loader_calls == 1);
mod = JS_ReadObject(ctx, buf, len, JS_READ_OBJ_BYTECODE);
js_free(ctx, buf);
assert(loader_calls == 1); // 'b' is returned from cache
assert(!JS_IsException(mod));
JSValue ret = JS_EvalFunction(ctx, mod);
assert(!JS_IsException(ret));
assert(JS_IsPromise(ret));
JSValue result = JS_PromiseResult(ctx, ret);
assert(!JS_IsException(result));
assert(JS_IsUndefined(result));
JS_FreeValue(ctx, result);
JS_FreeValue(ctx, ret);
JS_FreeValue(ctx, mod);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void runtime_cstring_free(void)
{
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
// string -> cstring + JS_FreeCStringRT
{
JSValue ret = eval(ctx, "\"testStringPleaseIgnore\"");
assert(JS_IsString(ret));
const char *s = JS_ToCString(ctx, ret);
assert(s);
assert(strcmp(s, "testStringPleaseIgnore") == 0);
JS_FreeCStringRT(rt, s);
JS_FreeValue(ctx, ret);
}
// string -> cstring + JS_FreeCStringRT, destroying the source value first
{
JSValue ret = eval(ctx, "\"testStringPleaseIgnore\"");
assert(JS_IsString(ret));
const char *s = JS_ToCString(ctx, ret);
assert(s);
JS_FreeValue(ctx, ret);
assert(strcmp(s, "testStringPleaseIgnore") == 0);
JS_FreeCStringRT(rt, s);
}
// number -> cstring + JS_FreeCStringRT
{
JSValue ret = eval(ctx, "123987");
assert(JS_IsNumber(ret));
const char *s = JS_ToCString(ctx, ret);
assert(s);
assert(strcmp(s, "123987") == 0);
JS_FreeCStringRT(rt, s);
JS_FreeValue(ctx, ret);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void two_byte_string(void)
{
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
{
JSValue v = JS_NewTwoByteString(ctx, NULL, 0);
assert(!JS_IsException(v));
const char *s = JS_ToCString(ctx, v);
assert(s);
assert(!strcmp(s, ""));
JS_FreeCString(ctx, s);
JS_FreeValue(ctx, v);
}
{
JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){'o','k'}, 2);
assert(!JS_IsException(v));
const char *s = JS_ToCString(ctx, v);
assert(s);
assert(!strcmp(s, "ok"));
JS_FreeCString(ctx, s);
JS_FreeValue(ctx, v);
}
{
JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){0xD800}, 1);
assert(!JS_IsException(v));
const char *s = JS_ToCString(ctx, v);
assert(s);
// questionable but surrogates don't map to UTF-8 without WTF-8
assert(!strcmp(s, "\xED\xA0\x80"));
JS_FreeCString(ctx, s);
JS_FreeValue(ctx, v);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void weak_map_gc_check(void)
{
static const char init_code[] =
"const map = new WeakMap(); \
function addItem() { \
const k = { \
text: 'a', \
}; \
map.set(k, {k}); \
}";
static const char test_code[] = "addItem()";
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
JSValue ret = eval(ctx, init_code);
assert(!JS_IsException(ret));
JSValue ret_test = eval(ctx, test_code);
assert(!JS_IsException(ret_test));
JS_RunGC(rt);
JSMemoryUsage memory_usage;
JS_ComputeMemoryUsage(rt, &memory_usage);
for (int i = 0; i < 3; i++) {
JSValue ret_test2 = eval(ctx, test_code);
assert(!JS_IsException(ret_test2));
JS_RunGC(rt);
JSMemoryUsage memory_usage2;
JS_ComputeMemoryUsage(rt, &memory_usage2);
assert(memory_usage.memory_used_count == memory_usage2.memory_used_count);
assert(memory_usage.memory_used_size == memory_usage2.memory_used_size);
JS_FreeValue(ctx, ret_test2);
}
JS_FreeValue(ctx, ret);
JS_FreeValue(ctx, ret_test);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
struct {
int hook_type_call_count[4];
} promise_hook_state;
static void promise_hook_cb(JSContext *ctx, JSPromiseHookType type,
JSValueConst promise, JSValueConst parent_promise,
void *opaque)
{
assert(type == JS_PROMISE_HOOK_INIT ||
type == JS_PROMISE_HOOK_BEFORE ||
type == JS_PROMISE_HOOK_AFTER ||
type == JS_PROMISE_HOOK_RESOLVE);
promise_hook_state.hook_type_call_count[type]++;
assert(opaque == (void *)&promise_hook_state);
if (!JS_IsUndefined(parent_promise)) {
JSValue global_object = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, global_object, "actual",
JS_DupValue(ctx, parent_promise));
JS_FreeValue(ctx, global_object);
}
}
static void promise_hook(void)
{
int *cc = promise_hook_state.hook_type_call_count;
JSContext *unused;
JSRuntime *rt = JS_NewRuntime();
//JS_SetDumpFlags(rt, JS_DUMP_PROMISE);
JS_SetPromiseHook(rt, promise_hook_cb, &promise_hook_state);
JSContext *ctx = JS_NewContext(rt);
JSValue global_object = JS_GetGlobalObject(ctx);
{
// empty module; creates an outer and inner module promise;
// JS_Eval returns the outer promise
JSValue ret = JS_Eval(ctx, "", 0, "<input>", JS_EVAL_TYPE_MODULE);
assert(!JS_IsException(ret));
assert(JS_IsPromise(ret));
assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret));
JS_FreeValue(ctx, ret);
assert(2 == cc[JS_PROMISE_HOOK_INIT]);
assert(0 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(0 == cc[JS_PROMISE_HOOK_AFTER]);
assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]);
assert(!JS_IsJobPending(rt));
}
memset(&promise_hook_state, 0, sizeof(promise_hook_state));
{
// module with unresolved promise; the outer and inner module promises
// are resolved but not the user's promise
static const char code[] = "new Promise(() => {})";
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_MODULE);
assert(!JS_IsException(ret));
assert(JS_IsPromise(ret));
assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise
JS_FreeValue(ctx, ret);
assert(3 == cc[JS_PROMISE_HOOK_INIT]);
assert(0 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(0 == cc[JS_PROMISE_HOOK_AFTER]);
assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]); // outer and inner module promise
assert(!JS_IsJobPending(rt));
}
memset(&promise_hook_state, 0, sizeof(promise_hook_state));
{
// module with resolved promise
static const char code[] = "new Promise((resolve,reject) => resolve())";
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_MODULE);
assert(!JS_IsException(ret));
assert(JS_IsPromise(ret));
assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise
JS_FreeValue(ctx, ret);
assert(3 == cc[JS_PROMISE_HOOK_INIT]);
assert(0 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(0 == cc[JS_PROMISE_HOOK_AFTER]);
assert(3 == cc[JS_PROMISE_HOOK_RESOLVE]);
assert(!JS_IsJobPending(rt));
}
memset(&promise_hook_state, 0, sizeof(promise_hook_state));
{
// module with rejected promise
static const char code[] = "new Promise((resolve,reject) => reject())";
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_MODULE);
assert(!JS_IsException(ret));
assert(JS_IsPromise(ret));
assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise
JS_FreeValue(ctx, ret);
assert(3 == cc[JS_PROMISE_HOOK_INIT]);
assert(0 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(0 == cc[JS_PROMISE_HOOK_AFTER]);
assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]);
assert(!JS_IsJobPending(rt));
}
memset(&promise_hook_state, 0, sizeof(promise_hook_state));
{
// module with promise chain
static const char code[] =
"globalThis.count = 0;"
"globalThis.actual = undefined;" // set by promise_hook_cb
"globalThis.expected = new Promise(resolve => resolve());"
"expected.then(_ => count++)";
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_MODULE);
assert(!JS_IsException(ret));
assert(JS_IsPromise(ret));
assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise
JS_FreeValue(ctx, ret);
assert(4 == cc[JS_PROMISE_HOOK_INIT]);
assert(0 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(0 == cc[JS_PROMISE_HOOK_AFTER]);
assert(3 == cc[JS_PROMISE_HOOK_RESOLVE]);
JSValue v = JS_GetPropertyStr(ctx, global_object, "count");
assert(!JS_IsException(v));
int32_t count;
assert(0 == JS_ToInt32(ctx, &count, v));
assert(0 == count);
JS_FreeValue(ctx, v);
assert(JS_IsJobPending(rt));
assert(1 == JS_ExecutePendingJob(rt, &unused));
assert(!JS_HasException(ctx));
assert(4 == cc[JS_PROMISE_HOOK_INIT]);
assert(0 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(0 == cc[JS_PROMISE_HOOK_AFTER]);
assert(4 == cc[JS_PROMISE_HOOK_RESOLVE]);
assert(!JS_IsJobPending(rt));
v = JS_GetPropertyStr(ctx, global_object, "count");
assert(!JS_IsException(v));
assert(0 == JS_ToInt32(ctx, &count, v));
assert(1 == count);
JS_FreeValue(ctx, v);
JSValue actual = JS_GetPropertyStr(ctx, global_object, "actual");
JSValue expected = JS_GetPropertyStr(ctx, global_object, "expected");
assert(!JS_IsException(actual));
assert(!JS_IsException(expected));
assert(JS_IsSameValue(ctx, actual, expected));
JS_FreeValue(ctx, actual);
JS_FreeValue(ctx, expected);
}
memset(&promise_hook_state, 0, sizeof(promise_hook_state));
{
// module with thenable; fires before and after hooks
static const char code[] =
"new Promise(resolve => resolve({then(resolve){ resolve() }}))";
JSValue ret = JS_Eval(ctx, code, strlen(code), "<input>", JS_EVAL_TYPE_MODULE);
assert(!JS_IsException(ret));
assert(JS_IsPromise(ret));
assert(JS_PROMISE_FULFILLED == JS_PromiseState(ctx, ret)); // outer module promise
JS_FreeValue(ctx, ret);
assert(3 == cc[JS_PROMISE_HOOK_INIT]);
assert(0 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(0 == cc[JS_PROMISE_HOOK_AFTER]);
assert(2 == cc[JS_PROMISE_HOOK_RESOLVE]);
assert(JS_IsJobPending(rt));
assert(1 == JS_ExecutePendingJob(rt, &unused));
assert(!JS_HasException(ctx));
assert(3 == cc[JS_PROMISE_HOOK_INIT]);
assert(1 == cc[JS_PROMISE_HOOK_BEFORE]);
assert(1 == cc[JS_PROMISE_HOOK_AFTER]);
assert(3 == cc[JS_PROMISE_HOOK_RESOLVE]);
assert(!JS_IsJobPending(rt));
}
JS_FreeValue(ctx, global_object);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void dump_memory_usage(void)
{
JSMemoryUsage stats;
JSRuntime *rt = NULL;
JSContext *ctx = NULL;
rt = JS_NewRuntime();
ctx = JS_NewContext(rt);
//JS_SetDumpFlags(rt, JS_DUMP_PROMISE);
static const char code[] =
"globalThis.count = 0;"
"globalThis.actual = undefined;" // set by promise_hook_cb
"globalThis.expected = new Promise(resolve => resolve());"
"expected.then(_ => count++)";
JSValue evalVal = JS_Eval(ctx, code, strlen(code), "<input>", 0);
JS_FreeValue(ctx, evalVal);
FILE *temp = tmpfile();
assert(temp != NULL);
JS_ComputeMemoryUsage(rt, &stats);
JS_DumpMemoryUsage(temp, &stats, rt);
// JS_DumpMemoryUsage(stdout, &stats, rt);
fclose(temp);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static void new_errors(void)
{
typedef struct {
const char name[16];
JSValue (*func)(JSContext *, const char *, ...);
} Entry;
static const Entry entries[] = {
{"Error", JS_NewPlainError},
{"InternalError", JS_NewInternalError},
{"RangeError", JS_NewRangeError},
{"ReferenceError", JS_NewReferenceError},
{"SyntaxError", JS_NewSyntaxError},
{"TypeError", JS_NewTypeError},
};
const Entry *e;
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
for (e = entries; e < endof(entries); e++) {
JSValue obj = (*e->func)(ctx, "the %s", "needle");
assert(!JS_IsException(obj));
assert(JS_IsObject(obj));
assert(JS_IsError(obj));
const char *haystack = JS_ToCString(ctx, obj);
char needle[256];
snprintf(needle, sizeof(needle), "%s: the needle", e->name);
assert(strstr(haystack, needle));
JS_FreeCString(ctx, haystack);
JSValue stack = JS_GetPropertyStr(ctx, obj, "stack");
assert(!JS_IsException(stack));
assert(JS_IsString(stack));
JS_FreeValue(ctx, stack);
JS_FreeValue(ctx, obj);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
static int gop_get_own_property(JSContext *ctx, JSPropertyDescriptor *desc,
JSValueConst obj, JSAtom prop)
{
const char *name;
int found;
found = 0;
name = JS_AtomToCString(ctx, prop);
if (!name)
return -1;
if (!strcmp(name, "answer")) {
found = 1;
*desc = (JSPropertyDescriptor){
.value = JS_NewInt32(ctx, 42),
.flags = JS_PROP_C_W_E | JS_PROP_HAS_VALUE,
};
}
JS_FreeCString(ctx, name);
return found;
}
static void global_object_prototype(void)
{
static const char code[] = "answer";
JSValue global_object, proto, ret;
JSClassID class_id;
JSRuntime *rt;
JSContext *ctx;
int32_t answer;
int res;
{
rt = JS_NewRuntime();
ctx = JS_NewContext(rt);
proto = JS_NewObject(ctx);
assert(JS_IsObject(proto));
JSCFunctionListEntry prop = JS_PROP_INT32_DEF("answer", 42, JS_PROP_C_W_E);
JS_SetPropertyFunctionList(ctx, proto, &prop, 1);
global_object = JS_GetGlobalObject(ctx);
res = JS_SetPrototype(ctx, global_object, proto);
assert(res == true);
JS_FreeValue(ctx, global_object);
JS_FreeValue(ctx, proto);
ret = eval(ctx, code);
assert(!JS_IsException(ret));
assert(JS_IsNumber(ret));
res = JS_ToInt32(ctx, &answer, ret);
assert(res == 0);
assert(answer == 42);
JS_FreeValue(ctx, ret);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
{
JSClassExoticMethods exotic = (JSClassExoticMethods){
.get_own_property = gop_get_own_property,
};
JSClassDef def = (JSClassDef){
.class_name = "Global Object",
.exotic = &exotic,
};
rt = JS_NewRuntime();
class_id = 0;
JS_NewClassID(rt, &class_id);
res = JS_NewClass(rt, class_id, &def);
assert(res == 0);
ctx = JS_NewContext(rt);
proto = JS_NewObjectClass(ctx, class_id);
assert(JS_IsObject(proto));
global_object = JS_GetGlobalObject(ctx);
res = JS_SetPrototype(ctx, global_object, proto);
assert(res == true);
JS_FreeValue(ctx, global_object);
JS_FreeValue(ctx, proto);
ret = eval(ctx, code);
assert(!JS_IsException(ret));
assert(JS_IsNumber(ret));
res = JS_ToInt32(ctx, &answer, ret);
assert(res == 0);
assert(answer == 42);
JS_FreeValue(ctx, ret);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
}
// https://github.com/quickjs-ng/quickjs/issues/1178
static void slice_string_tocstring(void)
{
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
JSValue ret = eval(ctx, "'.'.repeat(16384).slice(1, -1)");
assert(!JS_IsException(ret));
assert(JS_IsString(ret));
const char *str = JS_ToCString(ctx, ret);
assert(strlen(str) == 16382);
JS_FreeCString(ctx, str);
JS_FreeValue(ctx, ret);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
}
int main(void)
{
cfunctions();
sync_call();
async_call();
async_call_stack_overflow();
raw_context_global_var();
is_array();
module_serde();
runtime_cstring_free();
two_byte_string();
weak_map_gc_check();
promise_hook();
dump_memory_usage();
new_errors();
global_object_prototype();
slice_string_tocstring();
return 0;
}
@@ -0,0 +1,113 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include <inttypes.h>
const uint32_t qjsc_builtin_array_fromasync_size = 826;
const uint8_t qjsc_builtin_array_fromasync[826] = {
0x15, 0x0d, 0x01, 0x1a, 0x61, 0x73, 0x79, 0x6e,
0x63, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f,
0x72, 0x01, 0x10, 0x69, 0x74, 0x65, 0x72, 0x61,
0x74, 0x6f, 0x72, 0x01, 0x12, 0x61, 0x72, 0x72,
0x61, 0x79, 0x4c, 0x69, 0x6b, 0x65, 0x01, 0x0a,
0x6d, 0x61, 0x70, 0x46, 0x6e, 0x01, 0x0e, 0x74,
0x68, 0x69, 0x73, 0x41, 0x72, 0x67, 0x01, 0x0c,
0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x01, 0x02,
0x69, 0x01, 0x1a, 0x69, 0x73, 0x43, 0x6f, 0x6e,
0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72,
0x01, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x01, 0x0c,
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x01, 0x08,
0x69, 0x74, 0x65, 0x72, 0x01, 0x1c, 0x6e, 0x6f,
0x74, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63,
0x74, 0x69, 0x6f, 0x6e, 0x01, 0x08, 0x63, 0x61,
0x6c, 0x6c, 0x0c, 0x00, 0x02, 0x00, 0xa2, 0x01,
0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x01,
0xa4, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x43, 0x02,
0x01, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x01,
0x03, 0x05, 0xaa, 0x02, 0x00, 0x01, 0x40, 0xa0,
0x03, 0x00, 0x01, 0x40, 0xc6, 0x03, 0x00, 0x01,
0x40, 0xcc, 0x01, 0x00, 0x01, 0x40, 0xc8, 0x03,
0x00, 0x01, 0x40, 0x0c, 0x60, 0x02, 0x01, 0xf8,
0x01, 0x03, 0x0e, 0x01, 0x06, 0x05, 0x00, 0x86,
0x04, 0x11, 0xca, 0x03, 0x00, 0x01, 0x00, 0xcc,
0x03, 0x00, 0x01, 0x00, 0xce, 0x03, 0x00, 0x01,
0x00, 0xca, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff,
0x0f, 0x20, 0xcc, 0x03, 0x01, 0x01, 0x20, 0xce,
0x03, 0x01, 0x02, 0x20, 0xd0, 0x03, 0x02, 0x00,
0x20, 0xd2, 0x03, 0x02, 0x04, 0x20, 0xd4, 0x03,
0x02, 0x05, 0x20, 0xd6, 0x03, 0x02, 0x06, 0x20,
0xd8, 0x03, 0x02, 0x07, 0x20, 0x64, 0x06, 0x08,
0x20, 0x82, 0x01, 0x07, 0x09, 0x20, 0xda, 0x03,
0x0a, 0x08, 0x30, 0x82, 0x01, 0x0d, 0x0b, 0x20,
0xd4, 0x01, 0x0d, 0x0c, 0x20, 0x10, 0x00, 0x01,
0x00, 0xa0, 0x03, 0x01, 0x03, 0xc6, 0x03, 0x02,
0x03, 0xc8, 0x03, 0x04, 0x03, 0xaa, 0x02, 0x00,
0x03, 0xcc, 0x01, 0x03, 0x03, 0x08, 0xc4, 0x0d,
0x62, 0x02, 0x00, 0x62, 0x01, 0x00, 0x62, 0x00,
0x00, 0xd3, 0xcb, 0xd4, 0x11, 0xf4, 0xec, 0x08,
0x0e, 0x39, 0x46, 0x00, 0x00, 0x00, 0xdc, 0xcc,
0xd5, 0x11, 0xf4, 0xec, 0x08, 0x0e, 0x39, 0x46,
0x00, 0x00, 0x00, 0xdd, 0xcd, 0x62, 0x07, 0x00,
0x62, 0x06, 0x00, 0x62, 0x05, 0x00, 0x62, 0x04,
0x00, 0x62, 0x03, 0x00, 0xd4, 0x39, 0x46, 0x00,
0x00, 0x00, 0xb0, 0xec, 0x16, 0xd4, 0x98, 0x04,
0x1b, 0x00, 0x00, 0x00, 0xb0, 0xec, 0x0c, 0xdf,
0x11, 0x04, 0xee, 0x00, 0x00, 0x00, 0x21, 0x01,
0x00, 0x30, 0x06, 0xce, 0xb6, 0xc4, 0x04, 0xc3,
0x0d, 0xf7, 0xc4, 0x05, 0x09, 0xc4, 0x06, 0xd3,
0xe0, 0x48, 0xc4, 0x07, 0x63, 0x07, 0x00, 0x07,
0xad, 0xec, 0x0f, 0x0a, 0x11, 0x64, 0x06, 0x00,
0x0e, 0xd3, 0xe1, 0x48, 0x11, 0x64, 0x07, 0x00,
0x0e, 0x63, 0x07, 0x00, 0x07, 0xad, 0x6a, 0xa6,
0x00, 0x00, 0x00, 0x62, 0x08, 0x00, 0x06, 0x11,
0xf4, 0xed, 0x0c, 0x71, 0x43, 0x32, 0x00, 0x00,
0x00, 0xc4, 0x08, 0x0e, 0xee, 0x05, 0x0e, 0xd3,
0xee, 0xf2, 0x63, 0x08, 0x00, 0x8e, 0x11, 0xed,
0x03, 0x0e, 0xb6, 0x11, 0x64, 0x08, 0x00, 0x0e,
0x63, 0x05, 0x00, 0xec, 0x0c, 0xc3, 0x0d, 0x11,
0x63, 0x08, 0x00, 0x21, 0x01, 0x00, 0xee, 0x06,
0xe2, 0x63, 0x08, 0x00, 0xf1, 0x11, 0x64, 0x03,
0x00, 0x0e, 0x63, 0x04, 0x00, 0x63, 0x08, 0x00,
0xa7, 0x6a, 0x2a, 0x01, 0x00, 0x00, 0x62, 0x09,
0x00, 0xd3, 0x63, 0x04, 0x00, 0x48, 0xc4, 0x09,
0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x09, 0x00,
0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0xd4, 0xec,
0x17, 0xd4, 0x43, 0xef, 0x00, 0x00, 0x00, 0xd5,
0x63, 0x09, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03,
0x00, 0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0x5f,
0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00,
0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x09, 0x00,
0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e,
0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00,
0x00, 0xf3, 0x0e, 0xee, 0x9e, 0x62, 0x0a, 0x00,
0x63, 0x07, 0x00, 0x43, 0xef, 0x00, 0x00, 0x00,
0xd3, 0x24, 0x01, 0x00, 0xc4, 0x0a, 0x63, 0x05,
0x00, 0xec, 0x09, 0xc3, 0x0d, 0x11, 0x21, 0x00,
0x00, 0xee, 0x03, 0xe2, 0xf0, 0x11, 0x64, 0x03,
0x00, 0x0e, 0x6d, 0x8c, 0x00, 0x00, 0x00, 0x62,
0x0c, 0x00, 0x62, 0x0b, 0x00, 0x06, 0x11, 0xf4,
0xed, 0x13, 0x71, 0x43, 0x41, 0x00, 0x00, 0x00,
0xc4, 0x0b, 0x43, 0x6a, 0x00, 0x00, 0x00, 0xc4,
0x0c, 0x0e, 0xee, 0x10, 0x0e, 0x63, 0x0a, 0x00,
0x43, 0x6b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00,
0x8c, 0xee, 0xe0, 0x63, 0x0c, 0x00, 0xed, 0x4e,
0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x0b, 0x00,
0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0xd4, 0xec,
0x17, 0xd4, 0x43, 0xef, 0x00, 0x00, 0x00, 0xd5,
0x63, 0x0b, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03,
0x00, 0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0x5f,
0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00,
0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x0b, 0x00,
0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e,
0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00,
0x00, 0xf3, 0x0e, 0xee, 0x83, 0x0e, 0x06, 0x6e,
0x0d, 0x00, 0x00, 0x00, 0x0e, 0xee, 0x1e, 0x6e,
0x05, 0x00, 0x00, 0x00, 0x30, 0x63, 0x0a, 0x00,
0x42, 0x06, 0x00, 0x00, 0x00, 0xec, 0x0d, 0x63,
0x0a, 0x00, 0x43, 0x06, 0x00, 0x00, 0x00, 0x24,
0x00, 0x00, 0x0e, 0x6f, 0x63, 0x03, 0x00, 0x63,
0x04, 0x00, 0x44, 0x32, 0x00, 0x00, 0x00, 0x63,
0x03, 0x00, 0x2f, 0xc1, 0x00, 0x28, 0xc1, 0x00,
0xcf, 0x28,
};
@@ -0,0 +1,36 @@
;(function(Array, TypeError, asyncIterator, defineProperty, iterator) {
"use strict" // result.length=i should throw if .length is not writable
return async function fromAsync(arrayLike, mapFn=undefined, thisArg=undefined) {
if (mapFn !== undefined && typeof mapFn !== "function") throw new TypeError("not a function")
let result, i = 0, isConstructor = typeof this === "function"
let sync = false, method = arrayLike[asyncIterator]
if (method == null) sync = true, method = arrayLike[iterator]
if (method == null) {
let {length} = arrayLike
length = +length || 0
result = isConstructor ? new this(length) : Array(length)
while (i < length) {
let value = arrayLike[i]
if (sync) value = await value
if (mapFn) value = await mapFn.call(thisArg, value, i)
defineProperty(result, i++, {value, configurable: true, writable: true})
}
} else {
const iter = method.call(arrayLike)
result = isConstructor ? new this() : Array()
try {
for (;;) {
let {value, done} = await iter.next()
if (done) break
if (sync) value = await value
if (mapFn) value = await mapFn.call(thisArg, value, i)
defineProperty(result, i++, {value, configurable: true, writable: true})
}
} finally {
if (iter.return) iter.return()
}
}
result.length = i
return result
}
})
+17
View File
@@ -0,0 +1,17 @@
// note: file is not actually compiled, only checked for C syntax errors
#include "quickjs.h"
int main(void)
{
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
JS_FreeValue(ctx, JS_NAN);
JS_FreeValue(ctx, JS_UNDEFINED);
JS_FreeValue(ctx, JS_NewFloat64(ctx, 42));
// not a legal way of using JS_MKPTR but this is here
// to have the compiler syntax-check its definition
JS_FreeValue(ctx, JS_MKPTR(JS_TAG_UNINITIALIZED, 0));
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return 0;
}
File diff suppressed because it is too large Load Diff
+660
View File
@@ -0,0 +1,660 @@
/*
* C utilities
*
* Copyright (c) 2017 Fabrice Bellard
* Copyright (c) 2018 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef CUTILS_H
#define CUTILS_H
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
#if defined(_MSC_VER)
#include <winsock2.h>
#include <malloc.h>
#define alloca _alloca
#define ssize_t ptrdiff_t
#endif
#if defined(__APPLE__)
#include <malloc/malloc.h>
#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__GLIBC__)
#include <malloc.h>
#elif defined(__FreeBSD__)
#include <malloc_np.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
#if !defined(_WIN32) && !defined(EMSCRIPTEN) && !defined(__wasi__)
#include <errno.h>
#include <pthread.h>
#endif
#if !defined(_WIN32)
#include <limits.h>
#include <unistd.h>
#endif
#if defined(_MSC_VER) && !defined(__clang__)
# define likely(x) (x)
# define unlikely(x) (x)
# define force_inline __forceinline
# define no_inline __declspec(noinline)
# define __maybe_unused
# define __attribute__(x)
# define __attribute(x)
#else
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
# define force_inline inline __attribute__((always_inline))
# define no_inline __attribute__((noinline))
# define __maybe_unused __attribute__((unused))
#endif
#if defined(_MSC_VER) && !defined(__clang__)
#include <math.h>
#define INF INFINITY
#define NEG_INF -INFINITY
#else
#define INF (1.0/0.0)
#define NEG_INF (-1.0/0.0)
#endif
#ifndef offsetof
#define offsetof(type, field) ((size_t) &((type *)0)->field)
#endif
#ifndef countof
#define countof(x) (sizeof(x) / sizeof((x)[0]))
#ifndef endof
#define endof(x) ((x) + countof(x))
#endif
#endif
#ifndef container_of
/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
#endif
#if defined(_MSC_VER) || defined(__cplusplus)
#define minimum_length(n) n
#else
#define minimum_length(n) static n
#endif
/* Borrowed from Folly */
#ifndef JS_PRINTF_FORMAT
#ifdef _MSC_VER
#include <sal.h>
#define JS_PRINTF_FORMAT _Printf_format_string_
#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param)
#else
#define JS_PRINTF_FORMAT
#if !defined(__clang__) && defined(__GNUC__)
#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \
__attribute__((format(gnu_printf, format_param, dots_param)))
#else
#define JS_PRINTF_FORMAT_ATTR(format_param, dots_param) \
__attribute__((format(printf, format_param, dots_param)))
#endif
#endif
#endif
#if defined(PATH_MAX)
# define JS__PATH_MAX PATH_MAX
#elif defined(_WIN32)
# define JS__PATH_MAX 32767
#else
# define JS__PATH_MAX 8192
#endif
void js__pstrcpy(char *buf, int buf_size, const char *str);
char *js__pstrcat(char *buf, int buf_size, const char *s);
int js__strstart(const char *str, const char *val, const char **ptr);
int js__has_suffix(const char *str, const char *suffix);
static inline uint8_t is_be(void) {
union {
uint16_t a;
uint8_t b;
} u = { 0x100 };
return u.b;
}
static inline int max_int(int a, int b)
{
if (a > b)
return a;
else
return b;
}
static inline int min_int(int a, int b)
{
if (a < b)
return a;
else
return b;
}
static inline uint32_t max_uint32(uint32_t a, uint32_t b)
{
if (a > b)
return a;
else
return b;
}
static inline uint32_t min_uint32(uint32_t a, uint32_t b)
{
if (a < b)
return a;
else
return b;
}
static inline int64_t max_int64(int64_t a, int64_t b)
{
if (a > b)
return a;
else
return b;
}
static inline int64_t min_int64(int64_t a, int64_t b)
{
if (a < b)
return a;
else
return b;
}
/* WARNING: undefined if a = 0 */
static inline int clz32(unsigned int a)
{
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long index;
_BitScanReverse(&index, a);
return 31 - index;
#else
return __builtin_clz(a);
#endif
}
/* WARNING: undefined if a = 0 */
static inline int clz64(uint64_t a)
{
#if defined(_MSC_VER) && !defined(__clang__)
#if INTPTR_MAX == INT64_MAX
unsigned long index;
_BitScanReverse64(&index, a);
return 63 - index;
#else
if (a >> 32)
return clz32((unsigned)(a >> 32));
else
return clz32((unsigned)a) + 32;
#endif
#else
return __builtin_clzll(a);
#endif
}
/* WARNING: undefined if a = 0 */
static inline int ctz32(unsigned int a)
{
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long index;
_BitScanForward(&index, a);
return index;
#else
return __builtin_ctz(a);
#endif
}
/* WARNING: undefined if a = 0 */
static inline int ctz64(uint64_t a)
{
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long index;
_BitScanForward64(&index, a);
return index;
#else
return __builtin_ctzll(a);
#endif
}
static inline uint64_t get_u64(const uint8_t *tab)
{
uint64_t v;
memcpy(&v, tab, sizeof(v));
return v;
}
static inline int64_t get_i64(const uint8_t *tab)
{
int64_t v;
memcpy(&v, tab, sizeof(v));
return v;
}
static inline void put_u64(uint8_t *tab, uint64_t val)
{
memcpy(tab, &val, sizeof(val));
}
static inline uint32_t get_u32(const uint8_t *tab)
{
uint32_t v;
memcpy(&v, tab, sizeof(v));
return v;
}
static inline int32_t get_i32(const uint8_t *tab)
{
int32_t v;
memcpy(&v, tab, sizeof(v));
return v;
}
static inline void put_u32(uint8_t *tab, uint32_t val)
{
memcpy(tab, &val, sizeof(val));
}
static inline uint32_t get_u16(const uint8_t *tab)
{
uint16_t v;
memcpy(&v, tab, sizeof(v));
return v;
}
static inline int32_t get_i16(const uint8_t *tab)
{
int16_t v;
memcpy(&v, tab, sizeof(v));
return v;
}
static inline void put_u16(uint8_t *tab, uint16_t val)
{
memcpy(tab, &val, sizeof(val));
}
static inline uint32_t get_u8(const uint8_t *tab)
{
return *tab;
}
static inline int32_t get_i8(const uint8_t *tab)
{
return (int8_t)*tab;
}
static inline void put_u8(uint8_t *tab, uint8_t val)
{
*tab = val;
}
#ifndef bswap16
static inline uint16_t bswap16(uint16_t x)
{
return (x >> 8) | (x << 8);
}
#endif
#ifndef bswap32
static inline uint32_t bswap32(uint32_t v)
{
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
}
#endif
#ifndef bswap64
static inline uint64_t bswap64(uint64_t v)
{
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
((v & ((uint64_t)0xff << (6 * 8))) >> (5 * 8)) |
((v & ((uint64_t)0xff << (5 * 8))) >> (3 * 8)) |
((v & ((uint64_t)0xff << (4 * 8))) >> (1 * 8)) |
((v & ((uint64_t)0xff << (3 * 8))) << (1 * 8)) |
((v & ((uint64_t)0xff << (2 * 8))) << (3 * 8)) |
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
}
#endif
static inline void inplace_bswap16(uint8_t *tab) {
put_u16(tab, bswap16(get_u16(tab)));
}
static inline void inplace_bswap32(uint8_t *tab) {
put_u32(tab, bswap32(get_u32(tab)));
}
static inline double fromfp16(uint16_t v) {
double d, s;
int e;
if ((v & 0x7C00) == 0x7C00) {
d = (v & 0x3FF) ? NAN : INFINITY;
} else {
d = (v & 0x3FF) / 1024.;
e = (v & 0x7C00) >> 10;
if (e == 0) {
e = -14;
} else {
d += 1;
e -= 15;
}
d = scalbn(d, e);
}
s = (v & 0x8000) ? -1.0 : 1.0;
return d * s;
}
static inline uint16_t tofp16(double d) {
uint16_t f, s;
double t;
int e;
s = 0;
if (copysign(1, d) < 0) { // preserve sign when |d| is negative zero
d = -d;
s = 0x8000;
}
if (isinf(d))
return s | 0x7C00;
if (isnan(d))
return s | 0x7C01;
if (d == 0)
return s | 0;
d = 2 * frexp(d, &e);
e--;
if (e > 15)
return s | 0x7C00; // out of range, return +/-infinity
if (e < -25) {
d = 0;
e = 0;
} else if (e < -14) {
d = scalbn(d, e + 14);
e = 0;
} else {
d -= 1;
e += 15;
}
d *= 1024.;
f = (uint16_t)d;
t = d - f;
if (t < 0.5)
goto done;
if (t == 0.5)
if ((f & 1) == 0)
goto done;
// adjust for rounding
if (++f == 1024) {
f = 0;
if (++e == 31)
return s | 0x7C00; // out of range, return +/-infinity
}
done:
return s | (e << 10) | f;
}
static inline int isfp16nan(uint16_t v) {
return (v & 0x7FFF) > 0x7C00;
}
static inline int isfp16zero(uint16_t v) {
return (v & 0x7FFF) == 0;
}
/* XXX: should take an extra argument to pass slack information to the caller */
typedef void *DynBufReallocFunc(void *opaque, void *ptr, size_t size);
typedef struct DynBuf {
uint8_t *buf;
size_t size;
size_t allocated_size;
bool error; /* true if a memory allocation error occurred */
DynBufReallocFunc *realloc_func;
void *opaque; /* for realloc_func */
} DynBuf;
void dbuf_init(DynBuf *s);
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
int dbuf_realloc(DynBuf *s, size_t new_size);
int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len);
int dbuf_put(DynBuf *s, const void *data, size_t len);
int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
int dbuf_putc(DynBuf *s, uint8_t c);
int dbuf_putstr(DynBuf *s, const char *str);
static inline int dbuf_put_u16(DynBuf *s, uint16_t val)
{
return dbuf_put(s, (uint8_t *)&val, 2);
}
static inline int dbuf_put_u32(DynBuf *s, uint32_t val)
{
return dbuf_put(s, (uint8_t *)&val, 4);
}
static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
{
return dbuf_put(s, (uint8_t *)&val, 8);
}
int JS_PRINTF_FORMAT_ATTR(2, 3) dbuf_printf(DynBuf *s, JS_PRINTF_FORMAT const char *fmt, ...);
void dbuf_free(DynBuf *s);
static inline bool dbuf_error(DynBuf *s) {
return s->error;
}
static inline void dbuf_set_error(DynBuf *s)
{
s->error = true;
}
/*---- UTF-8 and UTF-16 handling ----*/
#define UTF8_CHAR_LEN_MAX 4
enum {
UTF8_PLAIN_ASCII = 0, // 7-bit ASCII plain text
UTF8_NON_ASCII = 1, // has non ASCII code points (8-bit or more)
UTF8_HAS_16BIT = 2, // has 16-bit code points
UTF8_HAS_NON_BMP1 = 4, // has non-BMP1 code points, needs UTF-16 surrogate pairs
UTF8_HAS_ERRORS = 8, // has encoding errors
};
int utf8_scan(const char *buf, size_t len, size_t *plen);
size_t utf8_encode_len(uint32_t c);
size_t utf8_encode(uint8_t buf[minimum_length(UTF8_CHAR_LEN_MAX)], uint32_t c);
uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp);
uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp);
size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len);
size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len);
size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len);
size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len);
static inline bool is_surrogate(uint32_t c)
{
return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
}
static inline bool is_hi_surrogate(uint32_t c)
{
return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
}
static inline bool is_lo_surrogate(uint32_t c)
{
return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
}
static inline uint32_t get_hi_surrogate(uint32_t c)
{
return (c >> 10) - (0x10000 >> 10) + 0xD800;
}
static inline uint32_t get_lo_surrogate(uint32_t c)
{
return (c & 0x3FF) | 0xDC00;
}
static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
{
return 65536 + 1024 * (hi & 1023) + (lo & 1023);
}
static inline int from_hex(int c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else
return -1;
}
static inline uint8_t is_upper_ascii(uint8_t c) {
return c >= 'A' && c <= 'Z';
}
static inline uint8_t to_upper_ascii(uint8_t c) {
return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
}
void rqsort(void *base, size_t nmemb, size_t size,
int (*cmp)(const void *, const void *, void *),
void *arg);
static inline uint64_t float64_as_uint64(double d)
{
union {
double d;
uint64_t u64;
} u;
u.d = d;
return u.u64;
}
static inline double uint64_as_float64(uint64_t u64)
{
union {
double d;
uint64_t u64;
} u;
u.u64 = u64;
return u.d;
}
int64_t js__gettimeofday_us(void);
uint64_t js__hrtime_ns(void);
static inline size_t js__malloc_usable_size(const void *ptr)
{
#if defined(__APPLE__)
return malloc_size(ptr);
#elif defined(_WIN32)
return _msize((void *)ptr);
#elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__GLIBC__)
return malloc_usable_size((void *)ptr);
#else
return 0;
#endif
}
int js_exepath(char* buffer, size_t* size);
/* Cross-platform threading APIs. */
#if defined(EMSCRIPTEN) || defined(__wasi__)
#define JS_HAVE_THREADS 0
#else
#define JS_HAVE_THREADS 1
#if defined(_WIN32)
#define JS_ONCE_INIT INIT_ONCE_STATIC_INIT
typedef INIT_ONCE js_once_t;
typedef CRITICAL_SECTION js_mutex_t;
typedef CONDITION_VARIABLE js_cond_t;
typedef HANDLE js_thread_t;
#else
#define JS_ONCE_INIT PTHREAD_ONCE_INIT
typedef pthread_once_t js_once_t;
typedef pthread_mutex_t js_mutex_t;
typedef pthread_cond_t js_cond_t;
typedef pthread_t js_thread_t;
#endif
void js_once(js_once_t *guard, void (*callback)(void));
void js_mutex_init(js_mutex_t *mutex);
void js_mutex_destroy(js_mutex_t *mutex);
void js_mutex_lock(js_mutex_t *mutex);
void js_mutex_unlock(js_mutex_t *mutex);
void js_cond_init(js_cond_t *cond);
void js_cond_destroy(js_cond_t *cond);
void js_cond_signal(js_cond_t *cond);
void js_cond_broadcast(js_cond_t *cond);
void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex);
int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout);
enum {
JS_THREAD_CREATE_DETACHED = 1,
};
// creates threads with 2 MB stacks (glibc default)
int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg,
int flags);
int js_thread_join(js_thread_t thrd);
#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */
// JS requires strict rounding behavior. Turn on 64-bits double precision
// and disable x87 80-bits extended precision for intermediate floating-point
// results. 0x300 is extended precision, 0x200 is double precision.
// Note that `*&cw` in the asm constraints looks redundant but isn't.
#if defined(__i386__) && !defined(_MSC_VER)
#define JS_X87_FPCW_SAVE_AND_ADJUST(cw) \
unsigned short cw; \
__asm__ __volatile__("fnstcw %0" : "=m"(*&cw)); \
do { \
unsigned short t = 0x200 | (cw & ~0x300); \
__asm__ __volatile__("fldcw %0" : /*empty*/ : "m"(*&t)); \
} while (0)
#define JS_X87_FPCW_RESTORE(cw) \
__asm__ __volatile__("fldcw %0" : /*empty*/ : "m"(*&cw))
#else
#define JS_X87_FPCW_SAVE_AND_ADJUST(cw)
#define JS_X87_FPCW_RESTORE(cw)
#endif
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* CUTILS_H */
@@ -0,0 +1,2 @@
// note: file is not actually compiled, only checked for C++ syntax errors
#include "ctest.c"
@@ -0,0 +1,20 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
@@ -0,0 +1 @@
18
@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
@@ -0,0 +1,63 @@
---
sidebar_position: 2
---
# Building
QuickJS uses [CMake] as its main build system, with an additional helper [Makefile].
:::note
Windows users will need to run the CMake commands manually.
:::
## Getting the source
```bash
git clone https://github.com/quickjs-ng/quickjs.git
cd quickjs
```
## Compiling everything
```bash
make
```
This will build the `qjs` and `qjsc` executables and other test tools. Head over [here](./cli) for
instructions on how to use them.
## Amalgamated builds
The amalgamated build rolls individual source files into a single big file.
It's a good choice for projects that want to use QuickJS without CMake.
Download quickjs-amalgam.zip from [Releases](https://github.com/quickjs-ng/quickjs/releases)
To enable the std, os and bjson modules, compile quickjs-amalgam.c with
`-DQJS_BUILD_LIBC`.
## Debug builds
```bash
make debug
```
This will produce a debug build without optimizations, suitable for developers.
## Running test262
```bash
make test262
```
This will run the test262 suite.
```bash
make test262-update
```
This will run the test262 suite and update the error / pass report, useful after
implementing a new feature that would alter the result of the test suite.
[CMake]: https://cmake.org
[Makefile]: https://www.gnu.org/software/make/
@@ -0,0 +1,130 @@
---
sidebar_position: 4
---
# The qjs and qjsc CLI tools
## `qjs` - The QuickJS JavaScript interpreter
The `qjs` executable runs the JavaScript interpreter. It includes a simple standard
library and REPL.
```
$ qjs
usage: qjs [options] [file [args]]
-h --help list options
-e --eval EXPR evaluate EXPR
-i --interactive go to interactive mode
-m --module load as ES6 module (default=autodetect)
--script load as ES6 script (default=autodetect)
-I --include file include an additional file
--std make 'std', 'os' and 'bjson' available to script
-T --trace trace memory allocation
-d --dump dump the memory usage stats
-D --dump-flags flags for dumping debug data (see DUMP_* defines)
-c --compile FILE compile the given JS file as a standalone executable
-o --out FILE output file for standalone executables
--exe select the executable to use as the base, defaults to the current one
--memory-limit n limit the memory usage to 'n' Kbytes
--stack-size n limit the stack size to 'n' Kbytes
--unhandled-rejection dump unhandled promise rejections
-q --quit just instantiate the interpreter and quit
```
The following dump flags are supported:
```
DUMP_BYTECODE_FINAL 0x01 /* dump pass 3 final byte code */
DUMP_BYTECODE_PASS2 0x02 /* dump pass 2 code */
DUMP_BYTECODE_PASS1 0x04 /* dump pass 1 code */
DUMP_BYTECODE_HEX 0x10 /* dump bytecode in hex */
DUMP_BYTECODE_PC2LINE 0x20 /* dump line number table */
DUMP_BYTECODE_STACK 0x40 /* dump compute_stack_size */
DUMP_BYTECODE_STEP 0x80 /* dump executed bytecode */
DUMP_READ_OBJECT 0x100 /* dump the marshalled objects at load time */
DUMP_FREE 0x200 /* dump every object free */
DUMP_GC 0x400 /* dump the occurrence of the automatic GC */
DUMP_GC_FREE 0x800 /* dump objects freed by the GC */
DUMP_MODULE_RESOLVE 0x1000 /* dump module resolution steps */
DUMP_PROMISE 0x2000 /* dump promise steps */
DUMP_LEAKS 0x4000 /* dump leaked objects and strings in JS_FreeRuntime */
DUMP_ATOM_LEAKS 0x8000 /* dump leaked atoms in JS_FreeRuntime */
DUMP_MEM 0x10000 /* dump memory usage in JS_FreeRuntime */
DUMP_OBJECTS 0x20000 /* dump objects in JS_FreeRuntime */
DUMP_ATOMS 0x40000 /* dump atoms in JS_FreeRuntime */
DUMP_SHAPES 0x80000 /* dump shapes in JS_FreeRuntime */
```
### Creating standalone executables
With the `qjs` CLI it's possible to create standalone executables that will bundle the given JavaScript file
alongside the binary.
```
$ qjs -c app.js -o app --exe qjs
```
The resulting `app` binary will have the same runtime dependencies as the `qjs` binary. This is acomplished
by compiling the target JavaScript file to bytecode and adding it a copy of the executable, with a little
trailer to help locate it. `--exe` expects the absolute path to `qjs`, e.g., `~/bin/qjs` or `$HOME/bin/qjs`.
Rather than using the current executable, it's possible to use the `--exe` switch to create standalone
executables for other platforms.
No JavaScript bundling is performed, the specified JS file cannot depend on other files. A bundler such
as `esbuild` can be used to generate an app bundle which can then be turned into the executable.
```
npx esbuild my-app/index.js \
--bundle \
--outfile=app.js \
--external:qjs:* \
--minify \
--target=es2023 \
--platform=neutral \
--format=esm \
--main-fields=main,module
```
## `qjsc` - The QuickJS JavaScript compiler
The `qjsc` executable runs the JavaScript compiler, it can generate bytecode from
source files which can then be embedded in an executable, or it can generate the necessary
scaffolding to build a C application which embeds QuickJS.
```
$ qjsc
usage: qjsc [options] [files]
options are:
-b output raw bytecode instead of C code
-e output main() and bytecode in a C file
-o output set the output filename
-n script_name set the script name (as used in stack traces)
-N cname set the C name of the generated data
-m compile as JavaScript module (default=autodetect)
-D module_name compile a dynamically loaded module or worker
-M module_name[,cname] add initialization code for an external C module
-p prefix set the prefix of the generated C names
-s strip the source code, specify twice to also strip debug info
-S n set the maximum stack size to 'n' bytes (default=262144)
```
Here is an example on how to create a standalone executable that embeds QuickJS
and the `examples/hello.js` JavaScript file:
```bash
# Make sure you are in the QuickJS source directory.
$ cc hello.c cutils.c dtoa.c libregexp.c libunicode.c quickjs.c quickjs-libc.c -I. -o hello
```
The resulting binary `hello` will be in the current directory.
```bash
$ ./hello
Hello World
```
:::note
See the ["Creating standalone executables"](#creating-standalone-executables) section for a simpler way.
:::
@@ -0,0 +1,7 @@
{
"label": "Developer Guide",
"position": 6,
"link": {
"type": "generated-index"
}
}
@@ -0,0 +1,3 @@
# API Reference
WIP.
@@ -0,0 +1,117 @@
# Internals
## Bytecode
The compiler generates bytecode directly with no intermediate
representation such as a parse tree, hence it is very fast. Several
optimizations passes are done over the generated bytecode.
A stack-based bytecode was chosen because it is simple and generates
compact code.
For each function, the maximum stack size is computed at compile time so that
no runtime stack overflow tests are needed.
A separate compressed line number table is maintained for the debug
information.
Access to closure variables is optimized and is almost as fast as local
variables.
Direct `eval` in strict mode is optimized.
## Runtime
### Strings
Strings are stored either as an 8 bit or a 16 bit array of
characters. Hence random access to characters is always fast.
The C API provides functions to convert JavaScript Strings to C UTF-8 encoded
strings. The most common case where the JavaScript string contains
only ASCII characters involves no copying.
### Objects
The object shapes (object prototype, property names and flags) are shared
between objects to save memory.
Arrays with no holes (except at the end of the array) are optimized.
TypedArray accesses are optimized.
### Atoms
Object property names and some strings are stored as Atoms (unique
strings) to save memory and allow fast comparison. Atoms are
represented as a 32 bit integer. Half of the atom range is reserved for
immediate integer literals from 0 to 2^31-1.
### Numbers
Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754
floating point values. Most operations have fast paths for the 32-bit
integer case.
### Garbage collection
Reference counting is used to free objects automatically and
deterministically. A separate cycle removal pass is done when the allocated
memory becomes too large. The cycle removal algorithm only uses the
reference counts and the object content, so no explicit garbage
collection roots need to be manipulated in the C code.
### JSValue
It is a JavaScript value which can be a primitive type (such as
Number, String, ...) or an Object. NaN boxing is used in the 32-bit version
to store 64-bit floating point numbers. The representation is
optimized so that 32-bit integers and reference counted values can be
efficiently tested.
In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The
rationale is that in 64-bit code memory usage is less critical.
In both cases (32 or 64 bits), JSValue exactly fits two CPU registers,
so it can be efficiently returned by C functions.
### Function call
The engine is optimized so that function calls are fast. The system
stack holds the JavaScript parameters and local variables.
### RegExp
A specific regular expression engine was developed. It is both small
and efficient and supports all the ES2020+ features including the
Unicode properties. As the JavaScript compiler, it directly generates
bytecode without a parse tree.
Backtracking with an explicit stack is used so that there is no
recursion on the system stack. Simple quantifiers are specifically
optimized to avoid recursions.
Infinite recursions coming from quantifiers with empty terms are
avoided.
The full regexp library weighs about 15 KiB (x86 code), excluding the
Unicode library.
### Unicode
A specific Unicode library was developed so that there is no
dependency on an external large Unicode library such as ICU. All the
Unicode tables are compressed while keeping a reasonable access
speed.
The library supports case conversion, Unicode normalization, Unicode
script queries, Unicode general category queries and all Unicode
binary properties.
The full Unicode library weighs about 45 KiB (x86 code).
### BigInt
BigInt is implemented with the [libbf](https://bellard.org/libbf) library.
It weights about 90 KiB (x86 code) and provides arbitrary precision IEEE 754 floating
point operations and transcendental functions with exact rounding.
@@ -0,0 +1,113 @@
---
sidebar_position: 1
---
# The QuickJS C API
The C API was designed to be simple and efficient. The C API is
defined in the header `quickjs.h`.
## Runtime and contexts
`JSRuntime` represents a JavaScript runtime corresponding to an
object heap. Several runtimes can exist at the same time but they
cannot exchange objects. Inside a given runtime, no multi-threading is
supported.
`JSContext` represents a JavaScript context (or Realm). Each
JSContext has its own global objects and system objects. There can be
several JSContexts per JSRuntime and they can share objects, similar
to frames of the same origin sharing JavaScript objects in a
web browser.
## JSValue
`JSValue` represents a JavaScript value which can be a primitive
type or an object. Reference counting is used, so it is important to
explicitly duplicate (`JS_DupValue()`, increment the reference
count) or free (`JS_FreeValue()`, decrement the reference count)
JSValues.
## C functions
C functions can be created with
`JS_NewCFunction()`. `JS_SetPropertyFunctionList()` is a
shortcut to easily add functions, setters and getters properties to a
given object.
Unlike other embedded JavaScript engines, there is no implicit stack,
so C functions get their parameters as normal C parameters. As a
general rule, C functions take constant `JSValue`s as parameters
(so they don't need to free them) and return a newly allocated (=live)
`JSValue`.
## Exceptions
Most C functions can return a JavaScript exception. It
must be explicitly tested and handled by the C code. The specific
`JSValue` `JS_EXCEPTION` indicates that an exception
occurred. The actual exception object is stored in the
`JSContext` and can be retrieved with `JS_GetException()`.
## Script evaluation
Use `JS_Eval()` to evaluate a script or module source.
If the script or module was compiled to bytecode with `qjsc`, it
can be evaluated by calling `js_std_eval_binary()`. The advantage
is that no compilation is needed so it is faster and smaller because
the compiler can be removed from the executable if no `eval` is
required.
Note: the bytecode format is linked to a given QuickJS
version. Moreover, no security check is done before its
execution. Hence the bytecode should not be loaded from untrusted
sources.
## JS Classes
C opaque data can be attached to a JavaScript object. The type of the
C opaque data is determined with the class ID (`JSClassID`) of
the object. Hence the first step is to register a new class ID and JS
class (`JS_NewClassID()`, `JS_NewClass()`). Then you can
create objects of this class with `JS_NewObjectClass()` and get or
set the C opaque point with `JS_GetOpaque()` / `JS_SetOpaque()`.
When defining a new JS class, it is possible to declare a finalizer
which is called when the object is destroyed. The finalizer should be
used to release C resources. It is invalid to execute JS code from
it. A `gc_mark` method can be provided so that the cycle removal
algorithm can find the other objects referenced by this object. Other
methods are available to define exotic object behaviors.
The Class ID are allocated per-runtime. The
`JSClass` are allocated per `JSRuntime`. `JS_SetClassProto()`
is used to define a prototype for a given class in a given
`JSContext`. `JS_NewObjectClass()` sets this prototype in the
created object.
Examples are available in `quickjs-libc.c`.
## C Modules
Native ES6 modules are supported and can be dynamically or statically
linked. The standard library `quickjs-libc.c` is a good example
of a native module.
## Memory handling
Use `JS_SetMemoryLimit()` to set a global memory allocation limit
to a given `JSRuntime`.
Custom memory allocation functions can be provided with `JS_NewRuntime2()`.
The maximum system stack size can be set with `JS_SetMaxStackSize()`.
## Execution timeout and interrupts
Use `JS_SetInterruptHandler()` to set a callback which is
regularly called by the engine when it is executing code. This
callback can be used to implement an execution timeout.
It is used by the command line interpreter to implement a
`Ctrl-C` handler.
@@ -0,0 +1,68 @@
# Differences with bellard/quickjs
This project aims to be a drop-in replacement for those already using QuickJS.
Minimal API changes might be necessary.
## Community development
NG is developed in the open, interacting with the wider community and through
these interactions many improvements have already been made, including the incorporation
of patches previously maintained in other forks.
Each PR is reviewed, iterated on, and merged in GitHub.
To date, NG has had over 40 distinct contributors and over 400 PRs.
## Consistent release cadence
As the project moves forward, a steady cadence of releases has been maintained, with an
average of a new release every 2 months.
## Testing
Since its inception testing has been a focus. Each PR is tested in over 50 configurations,
involving different operating systems, build types and sanitizers.
The `test262` suite is also ran for every change.
## Cross-platform support
In order to better support other platforms such as Windows the build system was
changed to use [CMake].
In addition, Windows is treated as a first class citizen, with the addition of support
for the MSVC compiler.
[CMake]: https://cmake.org/
## Performance
While being an interpreter limits the performance in comparison with other engines which
use a JIT, several significant performance improvements have been made:
- Opcode fusion
- Polymorphic inline caching
- Memory allocation improvements
- Improved parse speeds
## New ECMAScript APIs
The main focus of NG is to deliver state-of-the-art JavaScript features. Typically once they
are stable (stage 4) but sometimes even at earlier stages. Here is a non-exhaustive list
of ES features present in NG:
- Resizable ArrayBuffer
- Float16Array
- WeakRef
- FinalizationRegistry
- Iterator Helpers
- Promise.try
- Error.isError
- Set operations
Some non-standard but widely used APIs have also been added:
- V8's [stack trace API](https://v8.dev/docs/stack-trace-api)
- `Error.captureStackTrace`
- `Error.prepareStackTrace`
- `Error.stackTraceLimit`
@@ -0,0 +1,11 @@
---
sidebar_position: 7
---
# ECMAScript Features
QuickJS aims to support the latest available ECMAScript features once they hit the spec.
Progress on _test262_ compliance can be checked [here](https://test262.fyi/#|qjs_ng).
Due to size constraints it is unlikely QuickJS will ever support the [Intl](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) APIs.
@@ -0,0 +1,34 @@
---
sidebar_position: 3
---
# Installation
Installing QuickJS is simple, and we provide several ways to do so.
## Build from source
If you built it from source as outlined in [building](./building) you can just run:
```bash
make install
```
and it will be installed in your system. The default installation path is `/usr/local`.
## Using a prebuilt binary
Each [release on GitHub] includes binaries for several systems and architectures.
## Using jsvu
As of version 2.2.0 of `jsvu`, QuickJS-ng will be installed when the `quickjs` engine is requested.
```bash
npm install jsvu -g
```
[release on GitHub]: https://github.com/quickjs-ng/quickjs/releases
@@ -0,0 +1,33 @@
---
slug: /
sidebar_position: 1
sidebar_label: Welcome
---
# Welcome to QuickJS-NG
QuickJS is a small and embeddable JavaScript engine. It aims to support the latest
[ECMAScript] specification.
This project is a _fork_ of the [original QuickJS project] by Fabrice Bellard and Charlie Gordon, after it went dormant, with the intent of reigniting its development.
This project is focused on (but not limited to):
- Community development
- Testing
- Cross-platform support
- ES features
You can check the differences with the original project [here.](./diff)
:::note
This site is under construction, the entire API is not yet documented.
:::
## Getting Started
Head over to [building](./building) if you want to build QuickJS from source or [installation](./installation)
for installing it from prebuilt binaries.
[ECMAScript]: https://tc39.es/ecma262/
[original QuickJS project]: https://bellard.org/quickjs
@@ -0,0 +1,44 @@
# Projects using NG
Here is a list of projects currently using, supporting or migrating to QuickJS-NG.
If you want yours to be listed here, please open a PR!
## [txiki.js](https://github.com/saghul/txiki.js)
A tiny JavaScript runtime.
## [radare2](https://github.com/radareorg/radare2)
Reverse engineering framework.
## [rquickjs](https://github.com/DelSkayn/rquickjs)
High level Rust bindings.
## [llrt](https://github.com/awslabs/llrt)
Lightweight JS runtime for serverless applications.
## [nx.js](https://github.com/TooTallNate/nx.js)
JavaScript runtime for Nintendo Switch homebrew applications.
## [quickjs-rusty](https://github.com/Icemic/quickjs-rusty)
Rust wrapper focus on embedding-ready and no-pain type conversion and interoperability.
## [GodotJS](https://github.com/godotjs/GodotJS)
This project adds TypeScript/JavaScript support for Godot 4.x. It supports multiple javascript runtimes, including QuickJS-NG.
## [quickjs_es_runtime](https://github.com/HiRoFa/quickjs_es_runtime)
Rust wrapper with typescript, modules, promises, async/await and much more.
## [Lua jsregexp](https://github.com/kmarius/jsregexp)
JavaScript regular expressions for Lua.
## [Edbrowse](https://edbrowse.org)
A combination editor, web-browser, and mail client that is 100% text based.
@@ -0,0 +1,577 @@
---
sidebar_position: 5
---
# Standard library
The standard libary is provided as part of the `qjs` executable and the `quickjs-libc.c` source file
and it's not part of the core engine.
## Globals
### `argv0`
Provides the executable path.
### `scriptArgs`
Provides the command line arguments. The first argument is the script name.
### `print(...args)`
Print the arguments separated by spaces and a trailing newline.
### `console.log(...args)`
Same as `print()`.
### `navigator.userAgent`
Returns `quickjs-ng/<version>`.
### `gc()`
Shorthand for `std.gc()`.
## `qjs:bjson` module
### `bjson.write(obj, [flags])`
Serializes the given object into the QuickJS internal serialization format.
Returns an ArrayBuffer with the serialized data.
Supported flags:
- `WRITE_OBJ_BYTECODE`: allow serializing functions and modules
- `WRITE_OBJ_REFERENCE`: allow serializing object references
- `WRITE_OBJ_SAB`: allow serializing SharedArrayBuffer instances
- `WRITE_OBJ_STRIP_DEBUG`: strip debugging information when serializing
- `WRITE_OBJ_STRIP_SOURCE`: strip the source information when serializing
### `bjson.read(buf, [pos], [len], [flags])`
De-serialize the given ArrayBuffer (in QuickJS internal serialization format) back into a JavaScript value.
Supported flags:
- `READ_OBJ_BYTECODE`: allow de-serializing functions and modules
- `READ_OBJ_REFERENCE`: allow de-serializing object references
- `READ_OBJ_SAB`: allow de-serializing SharedArrayBuffer instances
## `qjs:os` module
The `os` module provides Operating System specific functions:
- low level file access
- signals
- timers
- basic asynchronous I/O
- workers (threads)
The OS functions usually return 0 if OK or an OS specific negative
error code.
### `open(filename, flags, mode = 0o666)`
Open a file. Return a handle or < 0 if error.
Supported flags:
- `O_RDONLY`
- `O_WRONLY`
- `O_RDWR`
- `O_APPEND`
- `O_CREAT`
- `O_EXCL`
- `O_TRUNC`
POSIX open flags.
- `O_TEXT`
(Windows specific). Open the file in text mode. The default is binary mode.
### `close(fd)`
Close the file handle `fd`.
### `seek(fd, offset, whence)`
Seek in the file. Use `std.SEEK_*` for
`whence`. `offset` is either a number or a BigInt. If
`offset` is a BigInt, a BigInt is returned too.
### `read(fd, buffer, offset, length)`
Read `length` bytes from the file handle `fd` to the
ArrayBuffer `buffer` at byte position `offset`.
Return the number of read bytes or < 0 if error.
### `write(fd, buffer, offset, length)`
Write `length` bytes to the file handle `fd` from the
ArrayBuffer `buffer` at byte position `offset`.
Return the number of written bytes or < 0 if error.
### `isatty(fd)`
Return `true` is `fd` is a TTY (terminal) handle.
### `ttyGetWinSize(fd)`
Return the TTY size as `[width, height]` or `null` if not available.
### `ttySetRaw(fd)`
Set the TTY in raw mode.
### `remove(filename)`
Remove a file. Return 0 if OK or `-errno`.
### `rename(oldname, newname)`
Rename a file. Return 0 if OK or `-errno`.
### `realpath(path)`
Return `[str, err]` where `str` is the canonicalized absolute
pathname of `path` and `err` the error code.
### `getcwd()`
Return `[str, err]` where `str` is the current working directory
and `err` the error code.
### `exePath()`
Returns the full path of the current executable or `undefined` if not available / supported.
### `chdir(path)`
Change the current directory. Return 0 if OK or `-errno`.
### `mkdir(path, mode = 0o777)`
Create a directory at `path`. Return 0 if OK or `-errno`.
### `stat(path)` / `lstat(path)`
Return `[obj, err]` where `obj` is an object containing the
file status of `path`. `err` is the error code. The
following fields are defined in `obj`: `dev`, `ino`, `mode`, `nlink`,
`uid`, `gid`, `rdev`, `size`, `blocks`, `atime`, `mtime`, `ctime`. The times are
specified in milliseconds since 1970. `lstat()` is the same as
`stat()` excepts that it returns information about the link
itself.
- `S_IFMT`
- `S_IFIFO`
- `S_IFCHR`
- `S_IFDIR`
- `S_IFBLK`
- `S_IFREG`
- `S_IFSOCK`
- `S_IFLNK`
- `S_ISGID`
- `S_ISUID`
Constants to interpret the `mode` property returned by
`stat()`. They have the same value as in the C system header
`sys/stat.h`.
### `utimes(path, atime, mtime)`
Change the access and modification times of the file `path`. The
times are specified in milliseconds since 1970. Return 0 if OK or `-errno`.
### `symlink(target, linkpath)`
Create a link at `linkpath` containing the string `target`. Return 0 if OK or `-errno`.
### `readlink(path)`
Return `[str, err]` where `str` is the link target and `err`
the error code.
### `readdir(path)`
Return `[array, err]` where `array` is an array of strings
containing the filenames of the directory `path`. `err` is
the error code. `array` contains at least `"."` and `".."`
if successful.
### `setReadHandler(fd, func)`
Add a read handler to the file handle `fd`. `func` is called
each time there is data pending for `fd`. A single read handler
per file handle is supported. Use `func = null` to remove the
handler.
### `setWriteHandler(fd, func)`
Add a write handler to the file handle `fd`. `func` is
called each time data can be written to `fd`. A single write
handler per file handle is supported. Use `func = null` to remove
the handler.
### `signal(signal, func)`
Call the function `func` when the signal `signal`
happens. Only a single handler per signal number is supported. Use
`null` to set the default handler or `undefined` to ignore
the signal. Signal handlers can only be defined in the main thread.
- `SIGINT`
- `SIGABRT`
- `SIGFPE`
- `SIGILL`
- `SIGSEGV`
- `SIGTERM`
POSIX signal numbers.
### `kill(pid, sig)`
Send the signal `sig` to the process `pid`.
### `exec(args[, options])`
Execute a process with the arguments `args`. `options` is an
object containing optional parameters:
- `block` - Boolean (default = true). If true, wait until the process is
terminated. In this case, `exec` return the exit code if positive
or the negated signal number if the process was interrupted by a
signal. If false, do not block and return the process id of the child.
- `usePath` - Boolean (default = true). If true, the file is searched in the
`PATH` environment variable.
- `file` - String (default = `args[0]`). Set the file to be executed.
- `cwd` - String. If present, set the working directory of the new process.
- `stdin`, `stdout`, `stderr` - If present, set the handle in the child for stdin, stdout or stderr.
- `env` - Object. If present, set the process environment from the object
key-value pairs. Otherwise use the same environment as the current
process.
- `uid` - Integer. If present, the process uid with `setuid`.
- `gid` - Integer. If present, the process gid with `setgid`.
- `groups` - Array of integer. If present, the supplementary
group IDs with `setgroup`.
### `waitpid(pid, options)`
`waitpid` Unix system call. Return the array `[ret, status]`.
`ret` contains `-errno` in case of error.
- `WNOHANG`
Constant for the `options` argument of `waitpid`.
### `dup(fd)`
`dup` Unix system call.
### `dup2(oldfd, newfd)`
`dup2` Unix system call.
### `pipe()`
`pipe` Unix system call. Return two handles as `[read_fd, write_fd]` or null in case of error.
### `sleep(delay_ms)`
Sleep during `delay_ms` milliseconds.
### `sleepAsync(delay_ms)`
Asynchronouse sleep during `delay_ms` milliseconds. Returns a promise. Example:
```js
await os.sleepAsync(500);
```
### `setTimeout(func, delay)`
Call the function `func` after `delay` ms. Return a timer ID.
### `clearTimeout(id)`
Cancel a timer.
### `platform`
Return a string representing the platform: `"linux"`, `"darwin"`, `"win32"` or `"js"`.
### `Worker(module_filename)`
Constructor to create a new thread (worker) with an API close to that of
`WebWorkers`. `module_filename` is a string specifying the
module filename which is executed in the newly created thread. As for
dynamically imported module, it is relative to the current script or
module path. Threads normally don't share any data and communicate
between each other with messages. Nested workers are not supported. An
example is available in `tests/test_worker.js`.
The worker class has the following static properties:
- `parent` - In the created worker, `Worker.parent` represents the parent
worker and is used to send or receive messages.
The worker instances have the following properties:
- `postMessage(msg)` - Send a message to the corresponding worker. `msg` is cloned in
the destination worker using an algorithm similar to the `HTML`
structured clone algorithm. `SharedArrayBuffer` are shared
between workers.
- `onmessage` - Getter and setter. Set a function which is called each time a
message is received. The function is called with a single
argument. It is an object with a `data` property containing the
received message. The thread is not terminated if there is at least
one non `null` `onmessage` handler.
## `qjs:std` module
The `std` module provides wrappers to libc (`stdlib.h` and `stdio.h`) and a few other utilities.
### `exit(n)`
Exit the process.
### `evalScript(str, options = undefined)`
Evaluate the string `str` as a script (global
eval). `options` is an optional object containing the following
optional properties:
- `backtrace_barrier` - Boolean (default = false). If true, error backtraces do not list the
stack frames below the evalScript.
- `async` - Boolean (default = false). If true, `await` is accepted in the
script and a promise is returned. The promise is resolved with an
object whose `value` property holds the value returned by the
script.
### `loadScript(filename)`
Evaluate the file `filename` as a script (global eval).
### `loadFile(filename, [options])`
Load the file `filename` and return it as a string assuming UTF-8
encoding. Return `null` in case of I/O error.
If `options.binary` is set to `true` a `Uint8Array` is returned instead.
### `writeFile(filename, data)`
Create the file `filename` and write `data` into it.
`data` can be a string, a typed array or an `ArrayBuffer`. `undefined` is
treated as the empty string.
When `data` is a string, the file is opened in text mode; otherwise it is
opened in binary mode. (This distinction is only relevant on Windows.)
Throws an exception if the file cannot be created or written to.
### `open(filename, flags, errorObj = undefined)`
Open a file (wrapper to the libc `fopen()`). Return the FILE
object or `null` in case of I/O error. If `errorObj` is not
undefined, set its `errno` property to the error code or to 0 if
no error occurred.
### `popen(command, flags, errorObj = undefined)`
Open a process by creating a pipe (wrapper to the libc
`popen()`). Return the FILE
object or `null` in case of I/O error. If `errorObj` is not
undefined, set its `errno` property to the error code or to 0 if
no error occurred.
### `fdopen(fd, flags, errorObj = undefined)`
Open a file from a file handle (wrapper to the libc
`fdopen()`). Return the FILE
object or null` in case of I/O error. If `errorObj` is not
undefined, set its `errno` property to the error code or to 0 if
no error occurred.
### `tmpfile(errorObj = undefined)`
Open a temporary file. Return the FILE
object or `null` in case of I/O error. If `errorObj` is not
undefined, set its `errno` property to the error code or to 0 if
no error occurred.
### `puts(str)`
Equivalent to `std.out.puts(str)`.
### `printf(fmt, ...args)`
Equivalent to `std.out.printf(fmt, ...args)`.
### `sprintf(fmt, ...args)`
Equivalent to the libc sprintf().
### `in`, `out`, `err`
Wrappers to the libc file `stdin`, `stdout`, `stderr`.
### `Error`
Enumeration object containing the integer value of common errors
(additional error codes may be defined):
- `EINVAL`
- `EIO`
- `EACCES`
- `EEXIST`
- `ENOSPC`
- `ENOSYS`
- `EBUSY`
- `ENOENT`
- `EPERM`
- `EPIPE`
### `strerror(errno)`
Return a string that describes the error `errno`.
### `gc()`
Manually invoke the cycle removal algorithm. The cycle removal
algorithm is automatically started when needed, so this function is
useful in case of specific memory constraints or for testing.
### `getenv(name)`
Return the value of the environment variable `name` or
`undefined` if it is not defined.
### `setenv(name, value)`
Set the value of the environment variable `name` to the string
`value`.
### `unsetenv(name)`
Delete the environment variable `name`.
### `getenviron()`
Return an object containing the environment variables as key-value pairs.
### `urlGet(url, options = undefined)`
Download `url` using the `curl` command line
utility. `options` is an optional object containing the following
optional properties:
- `binary` - Boolean (default = false). If true, the response is an ArrayBuffer
instead of a string. When a string is returned, the data is assumed
to be UTF-8 encoded.
- `full` - Boolean (default = false). If true, return the an object contains
the properties `response` (response content),
`responseHeaders` (headers separated by CRLF), `status`
(status code). `response` is `null` is case of protocol or
network error. If `full` is false, only the response is
returned if the status is between 200 and 299. Otherwise `null`
is returned.
### `FILE`
File object.
#### `close()`
Close the file. Return 0 if OK or `-errno` in case of I/O error.
#### `puts(str)`
Outputs the string with the UTF-8 encoding.
#### `printf(fmt, ...args)`
Formatted printf.
The same formats as the standard C library `printf` are
supported. Integer format types (e.g. `%d`) truncate the Numbers
or BigInts to 32 bits. Use the `l` modifier (e.g. `%ld`) to
truncate to 64 bits.
#### `flush()`
Flush the buffered file.
#### `seek(offset, whence)`
Seek to a give file position (whence is
`std.SEEK_*`). `offset` can be a number or a BigInt. Return
0 if OK or `-errno` in case of I/O error.
- `SEEK_SET`
- `SEEK_CUR`
- `SEEK_END`
Constants for seek().
#### `tell()`
Return the current file position.
#### `tello()`
Return the current file position as a BigInt.
#### `eof()`
Return true if end of file.
#### `fileno()`
Return the associated OS handle.
#### `error()`
Return true if there was an error.
#### `clearerr()`
Clear the error indication.
#### `read(buffer, position, length)`
Read `length` bytes from the file to the ArrayBuffer `buffer` at byte
position `position` (wrapper to the libc `fread`).
#### `write(buffer, position, length)`
Write `length` bytes to the file from the ArrayBuffer `buffer` at byte
position `position` (wrapper to the libc `fwrite`).
#### `getline()`
Return the next line from the file, assuming UTF-8 encoding, excluding
the trailing line feed.
#### `readAsArrayBuffer(max_size = undefined)`
Read `max_size` bytes from the file and return them as an ArrayBuffer.
If `max_size` is not present, the file is read until its end.
#### `readAsString(max_size = undefined)`
Read `max_size` bytes from the file and return them as a string
assuming UTF-8 encoding. If `max_size` is not present, the file
is read until its end.
#### `getByte()`
Return the next byte from the file. Return -1 if the end of file is reached.
#### `putByte(c)`
Write one byte to the file.
@@ -0,0 +1,20 @@
---
sidebar_position: 8
---
# Supported Platforms
| System | Supported versions | Notes |
|---|---|---|
| GNU/Linux | * | glibc and musl are supported |
| macOS | macOS >= 11 | Currently supported macOS releases |
| Windows | >= Windows 7* | VS >= 2022 and Clang are supported; requires `<stdatomic.h>` |
| FreeBSD | * | Limited testing |
| OpenBSD | * | Limited testing |
| NetBSD | * | Limited testing |
| Android | NDK >= 26.0.10792818 | Limited testing |
| iOS | * | Limited testing |
| MinGW | MinGW-w64 | |
| Other | N/A | Missing? Open a PR! |
- `*`: Windows 7 is EOL and only supported in this project as long as it doesn't interfere with its progress.
@@ -0,0 +1,114 @@
// @ts-check
// `@type` JSDoc annotations allow editor autocompletion and type checking
// (when paired with `@ts-check`).
// There are various equivalent ways to declare your Docusaurus config.
// See: https://docusaurus.io/docs/api/docusaurus-config
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'QuickJS-NG',
tagline: 'QuickJS, the Next Generation: a mighty JavaScript engine',
favicon: 'img/favicon.ico',
// Set the production url of your site here
url: 'https://quickjs-ng.github.io',
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/quickjs/',
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: 'quickjs-ng', // Usually your GitHub org/user name.
projectName: 'quickjs', // Usually your repo name.
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'throw',
// Even if you don't use internationalization, you can use this field to set
// useful metadata like html lang. For example, if your site is Chinese, you
// may want to replace "en" with "zh-Hans".
i18n: {
defaultLocale: 'en',
locales: ['en'],
},
presets: [
[
'classic',
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
routeBasePath: '/',
sidebarPath: './sidebars.js',
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl: 'https://github.com/quickjs-ng/quickjs/tree/master/docs/',
},
blog: false,
theme: {
customCss: './src/css/custom.css',
},
}),
],
],
themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
// Replace with your project's social card
image: 'img/docusaurus-social-card.jpg',
navbar: {
title: 'QuickJS-NG',
items: [
{
type: 'docSidebar',
sidebarId: 'docsSidebar',
position: 'left',
label: 'Documentation',
},
{
href: 'https://github.com/quickjs-ng/quickjs',
label: 'GitHub',
position: 'right',
},
],
},
footer: {
style: 'dark',
links: [
{
title: 'Docs',
items: [
],
},
{
title: 'Community',
items: [
{
label: 'GitHub Discussions',
href: 'https://github.com/quickjs-ng/quickjs/discussions',
},
{
label: 'Matrix',
href: 'https://matrix.to/#/%23quickjs-ng%3Amatrix.org?via=matrix.org',
},
],
},
{
title: 'More',
items: [
{
label: 'GitHub',
href: 'https://github.com/quickjs-ng/quickjs',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} QuickJS-NG project contributors.`,
},
prism: {
},
}),
};
export default config;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
{
"private": true,
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "3.5.2",
"@docusaurus/preset-classic": "3.5.2",
"@mdx-js/react": "3.0.1",
"clsx": "2.1.1",
"prism-react-renderer": "2.4.0",
"react": "18.3.1",
"react-dom": "18.3.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.5.2",
"@docusaurus/types": "3.5.2"
},
"browserslist": {
"production": [
">0.5%",
"not dead",
"not op_mini all"
],
"development": [
"last 3 chrome version",
"last 3 firefox version",
"last 5 safari version"
]
},
"engines": {
"node": ">=18.0"
}
}
@@ -0,0 +1,20 @@
/**
* Creating a sidebar enables you to:
- create an ordered group of docs
- render a sidebar for each doc of that group
- provide next/previous navigation
The sidebars can be generated from the filesystem, or explicitly defined here.
Create as many sidebars as you want.
*/
// @ts-check
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
// By default, Docusaurus generates a sidebar from the docs folder structure
docsSidebar: [{type: 'autogenerated', dirName: '.'}],
};
export default sidebars;
@@ -0,0 +1,30 @@
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
* work well for content-centric websites.
*/
/* You can override the default Infima variables here. */
:root {
--ifm-color-primary: #2e8555;
--ifm-color-primary-dark: #29784c;
--ifm-color-primary-darker: #277148;
--ifm-color-primary-darkest: #205d3b;
--ifm-color-primary-light: #33925d;
--ifm-color-primary-lighter: #359962;
--ifm-color-primary-lightest: #3cad6e;
--ifm-code-font-size: 95%;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
}
/* For readability concerns, you should choose a lighter palette in dark mode. */
[data-theme='dark'] {
--ifm-color-primary: #25c2a0;
--ifm-color-primary-dark: #21af90;
--ifm-color-primary-darker: #1fa588;
--ifm-color-primary-darkest: #1a8870;
--ifm-color-primary-light: #29d5b0;
--ifm-color-primary-lighter: #32d8b4;
--ifm-color-primary-lightest: #4fddbf;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because it is too large Load Diff
+87
View File
@@ -0,0 +1,87 @@
/*
* Tiny float64 printing and parsing library
*
* Copyright (c) 2024 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef DTOA_H
#define DTOA_H
//#define JS_DTOA_DUMP_STATS
/* maximum number of digits for fixed and frac formats */
#define JS_DTOA_MAX_DIGITS 101
/* radix != 10 is only supported with flags = JS_DTOA_FORMAT_FREE */
/* use as many digits as necessary */
#define JS_DTOA_FORMAT_FREE (0 << 0)
/* use n_digits significant digits (1 <= n_digits <= JS_DTOA_MAX_DIGITS) */
#define JS_DTOA_FORMAT_FIXED (1 << 0)
/* force fractional format: [-]dd.dd with n_digits fractional digits.
0 <= n_digits <= JS_DTOA_MAX_DIGITS */
#define JS_DTOA_FORMAT_FRAC (2 << 0)
#define JS_DTOA_FORMAT_MASK (3 << 0)
/* select exponential notation either in fixed or free format */
#define JS_DTOA_EXP_AUTO (0 << 2)
#define JS_DTOA_EXP_ENABLED (1 << 2)
#define JS_DTOA_EXP_DISABLED (2 << 2)
#define JS_DTOA_EXP_MASK (3 << 2)
#define JS_DTOA_MINUS_ZERO (1 << 4) /* show the minus sign for -0 */
/* only accepts integers (no dot, no exponent) */
#define JS_ATOD_INT_ONLY (1 << 0)
/* accept Oo and Ob prefixes in addition to 0x prefix if radix = 0 */
#define JS_ATOD_ACCEPT_BIN_OCT (1 << 1)
/* accept O prefix as octal if radix == 0 and properly formed (Annex B) */
#define JS_ATOD_ACCEPT_LEGACY_OCTAL (1 << 2)
/* accept _ between digits as a digit separator */
#define JS_ATOD_ACCEPT_UNDERSCORES (1 << 3)
typedef struct {
uint64_t mem[37];
} JSDTOATempMem;
typedef struct {
uint64_t mem[27];
} JSATODTempMem;
/* return a maximum bound of the string length */
int js_dtoa_max_len(double d, int radix, int n_digits, int flags);
/* return the string length */
int js_dtoa(char *buf, double d, int radix, int n_digits, int flags,
JSDTOATempMem *tmp_mem);
double js_atod(const char *str, const char **pnext, int radix, int flags,
JSATODTempMem *tmp_mem);
#ifdef JS_DTOA_DUMP_STATS
void js_dtoa_dump_stats(void);
#endif
/* additional exported functions */
size_t u32toa(char *buf, uint32_t n);
size_t i32toa(char *buf, int32_t n);
size_t u64toa(char *buf, uint64_t n);
size_t i64toa(char *buf, int64_t n);
size_t u64toa_radix(char *buf, uint64_t n, unsigned int radix);
size_t i64toa_radix(char *buf, int64_t n, unsigned int radix);
#endif /* DTOA_H */
@@ -0,0 +1,80 @@
/*
* QuickJS: Example of C module
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "../quickjs.h"
#define countof(x) (sizeof(x) / sizeof((x)[0]))
static int fib(int n)
{
if (n <= 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
static JSValue js_fib(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv)
{
int n, res;
if (JS_ToInt32(ctx, &n, argv[0]))
return JS_EXCEPTION;
res = fib(n);
return JS_NewInt32(ctx, res);
}
static const JSCFunctionListEntry js_fib_funcs[] = {
JS_CFUNC_DEF("fib", 1, js_fib ),
};
static int js_fib_init(JSContext *ctx, JSModuleDef *m)
{
return JS_SetModuleExportList(ctx, m, js_fib_funcs,
countof(js_fib_funcs));
}
#ifdef JS_SHARED_LIBRARY
#define JS_INIT_MODULE js_init_module
#else
#define JS_INIT_MODULE js_init_module_fib
#endif
#ifndef JS_EXTERN
#ifdef _WIN32
#define JS_EXTERN __declspec(dllexport)
#else
#define JS_EXTERN
#endif
#endif
JS_EXTERN JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_fib_init);
if (!m)
return NULL;
JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs));
return m;
}
@@ -0,0 +1,10 @@
/* fib module */
export function fib(n)
{
if (n <= 0)
return 0;
else if (n == 1)
return 1;
else
return fib(n - 1) + fib(n - 2);
}
@@ -0,0 +1 @@
console.log("Hello World");
@@ -0,0 +1,6 @@
/* example of JS module */
import { fib } from "./fib_module.js";
console.log("Hello World");
console.log("fib(10)=", fib(10));
@@ -0,0 +1,19 @@
shared_module(
'fib',
'fib.c',
name_prefix: '',
gnu_symbol_visibility: 'default',
c_args: ['-DJS_SHARED_LIBRARY'],
dependencies: host_system == 'windows' ? qjs_dep : [],
)
shared_module(
'point',
'point.c',
name_prefix: '',
gnu_symbol_visibility: 'default',
c_args: ['-DJS_SHARED_LIBRARY'],
dependencies: host_system == 'windows' ? qjs_dep : [],
)
@@ -0,0 +1,118 @@
/*
* PI computation in Javascript using the BigInt type
*/
"use strict";
/* return floor(log2(a)) for a > 0 and 0 for a = 0 */
function floor_log2(a)
{
var k_max, a1, k, i;
k_max = 0n;
while ((a >> (2n ** k_max)) != 0n) {
k_max++;
}
k = 0n;
a1 = a;
for(i = k_max - 1n; i >= 0n; i--) {
a1 = a >> (2n ** i);
if (a1 != 0n) {
a = a1;
k |= (1n << i);
}
}
return k;
}
/* return ceil(log2(a)) for a > 0 */
function ceil_log2(a)
{
return floor_log2(a - 1n) + 1n;
}
/* return floor(sqrt(a)) (not efficient but simple) */
function int_sqrt(a)
{
var l, u, s;
if (a == 0n)
return a;
l = ceil_log2(a);
u = 1n << ((l + 1n) / 2n);
/* u >= floor(sqrt(a)) */
for(;;) {
s = u;
u = ((a / s) + s) / 2n;
if (u >= s)
break;
}
return s;
}
/* return pi * 2**prec */
function calc_pi(prec) {
const CHUD_A = 13591409n;
const CHUD_B = 545140134n;
const CHUD_C = 640320n;
const CHUD_C3 = 10939058860032000n; /* C^3/24 */
const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */
/* return [P, Q, G] */
function chud_bs(a, b, need_G) {
var c, P, Q, G, P1, Q1, G1, P2, Q2, G2;
if (a == (b - 1n)) {
G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n);
P = G * (CHUD_B * b + CHUD_A);
if (b & 1n)
P = -P;
Q = b * b * b * CHUD_C3;
} else {
c = (a + b) >> 1n;
[P1, Q1, G1] = chud_bs(a, c, true);
[P2, Q2, G2] = chud_bs(c, b, need_G);
P = P1 * Q2 + P2 * G1;
Q = Q1 * Q2;
if (need_G)
G = G1 * G2;
else
G = 0n;
}
return [P, Q, G];
}
var n, P, Q, G;
/* number of serie terms */
n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n;
[P, Q, G] = chud_bs(0n, n, false);
Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A);
G = int_sqrt(CHUD_C << (2n * prec));
return (Q * G) >> prec;
}
function main(args) {
var r, n_digits, n_bits, out;
if (args.length < 1) {
print("usage: pi n_digits");
return;
}
n_digits = args[0] | 0;
/* we add more bits to reduce the probability of bad rounding for
the last digits */
n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n;
r = calc_pi(n_bits);
r = ((10n ** BigInt(n_digits)) * r) >> n_bits;
out = r.toString();
print(out[0] + "." + out.slice(1));
}
var args;
if (typeof scriptArgs != "undefined") {
args = scriptArgs;
args.shift();
} else if (typeof arguments != "undefined") {
args = arguments;
} else {
/* default: 1000 digits */
args=[1000];
}
main(args);
@@ -0,0 +1,160 @@
/*
* QuickJS: Example of C module with a class
*
* Copyright (c) 2019 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "../quickjs.h"
#include <math.h>
#define countof(x) (sizeof(x) / sizeof((x)[0]))
/* Point Class */
typedef struct {
int x;
int y;
} JSPointData;
static JSClassID js_point_class_id;
static void js_point_finalizer(JSRuntime *rt, JSValue val)
{
JSPointData *s = JS_GetOpaque(val, js_point_class_id);
/* Note: 's' can be NULL in case JS_SetOpaque() was not called */
js_free_rt(rt, s);
}
static JSValue js_point_ctor(JSContext *ctx,
JSValue new_target,
int argc, JSValue *argv)
{
JSPointData *s;
JSValue obj = JS_UNDEFINED;
JSValue proto;
s = js_mallocz(ctx, sizeof(*s));
if (!s)
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &s->x, argv[0]))
goto fail;
if (JS_ToInt32(ctx, &s->y, argv[1]))
goto fail;
/* using new_target to get the prototype is necessary when the
class is extended. */
proto = JS_GetPropertyStr(ctx, new_target, "prototype");
if (JS_IsException(proto))
goto fail;
obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id);
JS_FreeValue(ctx, proto);
if (JS_IsException(obj))
goto fail;
JS_SetOpaque(obj, s);
return obj;
fail:
js_free(ctx, s);
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
}
static JSValue js_point_get_xy(JSContext *ctx, JSValue this_val, int magic)
{
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
if (!s)
return JS_EXCEPTION;
if (magic == 0)
return JS_NewInt32(ctx, s->x);
else
return JS_NewInt32(ctx, s->y);
}
static JSValue js_point_set_xy(JSContext *ctx, JSValue this_val, JSValue val, int magic)
{
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
int v;
if (!s)
return JS_EXCEPTION;
if (JS_ToInt32(ctx, &v, val))
return JS_EXCEPTION;
if (magic == 0)
s->x = v;
else
s->y = v;
return JS_UNDEFINED;
}
static JSValue js_point_norm(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv)
{
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
if (!s)
return JS_EXCEPTION;
return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y));
}
static JSClassDef js_point_class = {
"Point",
.finalizer = js_point_finalizer,
};
static const JSCFunctionListEntry js_point_proto_funcs[] = {
JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0),
JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1),
JS_CFUNC_DEF("norm", 0, js_point_norm),
};
static int js_point_init(JSContext *ctx, JSModuleDef *m)
{
JSValue point_proto, point_class;
JSRuntime *rt = JS_GetRuntime(ctx);
/* create the Point class */
JS_NewClassID(rt, &js_point_class_id);
JS_NewClass(rt, js_point_class_id, &js_point_class);
point_proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
/* set proto.constructor and ctor.prototype */
JS_SetConstructor(ctx, point_class, point_proto);
JS_SetClassProto(ctx, js_point_class_id, point_proto);
JS_SetModuleExport(ctx, m, "Point", point_class);
return 0;
}
#ifndef JS_EXTERN
#ifdef _WIN32
#define JS_EXTERN __declspec(dllexport)
#else
#define JS_EXTERN
#endif
#endif
JS_EXTERN JSModuleDef *js_init_module(JSContext *ctx, const char *module_name)
{
JSModuleDef *m;
m = JS_NewCModule(ctx, module_name, js_point_init);
if (!m)
return NULL;
JS_AddModuleExport(ctx, m, "Point");
return m;
}
@@ -0,0 +1,8 @@
/* example of JS module importing a C module */
import * as os from "qjs:os";
const isWin = os.platform === 'win32';
const { fib } = await import(`./fib.${isWin ? 'dll' : 'so'}`);
console.log("Hello World");
console.log("fib(10)=", fib(10));
@@ -0,0 +1,43 @@
/* example of JS module importing a C module */
import * as os from "qjs:os";
const isWin = os.platform === 'win32';
const { Point } = await import(`./point.${isWin ? 'dll' : 'so'}`);
function assert(b, str)
{
if (b) {
return;
} else {
throw Error("assertion failed: " + str);
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y);
this.color = color;
}
get_color() {
return this.color;
}
};
function main()
{
var pt, pt2;
pt = new Point(2, 3);
assert(pt.x === 2);
assert(pt.y === 3);
pt.x = 4;
assert(pt.x === 4);
assert(pt.norm() == 5);
pt2 = new ColorPoint(2, 3, 0xffffff);
assert(pt2.x === 2);
assert(pt2.color === 0xffffff);
assert(pt2.get_color() === 0xffffff);
}
main();
+22
View File
@@ -0,0 +1,22 @@
// clang -g -O1 -fsanitize=fuzzer -o fuzz fuzz.c
#include "quickjs.h"
#include "quickjs.c"
#include "cutils.c"
#include "libregexp.c"
#include "libunicode.c"
#include <stdlib.h>
int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len)
{
JSRuntime *rt = JS_NewRuntime();
if (!rt)
exit(1);
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
exit(1);
JSValue val = JS_ReadObject(ctx, buf, len, /*flags*/0);
JS_FreeValue(ctx, val);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return 0;
}
@@ -0,0 +1,80 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_function_source_size = 324;
const uint8_t qjsc_function_source[324] = {
0x15, 0x05, 0x01, 0x30, 0x74, 0x65, 0x73, 0x74,
0x73, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x2e, 0x6a, 0x73, 0x01, 0x0c, 0x61, 0x63,
0x74, 0x75, 0x61, 0x6c, 0x01, 0x02, 0x66, 0x01,
0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x01,
0x34, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x20, 0x66, 0x28, 0x29, 0x20, 0x7b, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x34,
0x32, 0x20, 0x7d, 0x0d, 0xc6, 0x03, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x20, 0x0a, 0x01, 0xa2,
0x01, 0x00, 0x05, 0x00, 0x03, 0x02, 0x01, 0x74,
0x05, 0xc8, 0x03, 0x02, 0x00, 0x30, 0xca, 0x03,
0x04, 0x00, 0x70, 0xc8, 0x03, 0x04, 0x02, 0x70,
0x10, 0x00, 0x01, 0x00, 0xe4, 0x01, 0x00, 0x01,
0x00, 0xcc, 0x03, 0x00, 0x0d, 0xca, 0x03, 0x01,
0x01, 0x0c, 0x43, 0x0a, 0x01, 0xca, 0x03, 0x00,
0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0xbe,
0x2a, 0x28, 0xc6, 0x03, 0x03, 0x01, 0x00, 0x1a,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, 0x32,
0x20, 0x7d, 0x0c, 0x03, 0xc4, 0x04, 0x08, 0xce,
0x08, 0xec, 0x05, 0xc1, 0x00, 0xe4, 0x29, 0x04,
0xe7, 0x00, 0x00, 0x00, 0xe3, 0x62, 0x00, 0x00,
0xe0, 0x43, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00,
0x00, 0xcb, 0x63, 0x00, 0x00, 0x66, 0x00, 0x00,
0xb0, 0xec, 0x0b, 0x39, 0x96, 0x00, 0x00, 0x00,
0x63, 0x00, 0x00, 0xf1, 0x30, 0x62, 0x02, 0x00,
0x62, 0x01, 0x00, 0x39, 0x3b, 0x00, 0x00, 0x00,
0x66, 0x00, 0x00, 0x04, 0xe5, 0x00, 0x00, 0x00,
0x9e, 0x32, 0x01, 0x00, 0x03, 0x00, 0xcc, 0x63,
0x01, 0x00, 0x43, 0x38, 0x00, 0x00, 0x00, 0x24,
0x00, 0x00, 0xcd, 0x63, 0x02, 0x00, 0x66, 0x00,
0x00, 0xb0, 0xec, 0x0b, 0x39, 0x96, 0x00, 0x00,
0x00, 0x63, 0x02, 0x00, 0xf1, 0x30, 0x69, 0x02,
0x00, 0x69, 0x01, 0x00, 0x06, 0x2f, 0xc6, 0x03,
0x01, 0x01, 0x18, 0x00, 0x1c, 0x0a, 0x2a, 0x26,
0x03, 0x20, 0x1c, 0x1b, 0x0c, 0x00, 0x10, 0x08,
0x27, 0x11, 0x12, 0x67, 0x0d, 0x26, 0x03, 0x20,
0x1c, 0x1b, 0x0c, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
return ctx;
}
int main(int argc, char **argv)
{
int r;
JSRuntime *rt;
JSContext *ctx;
r = 0;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_function_source, qjsc_function_source_size, 0);
r = js_std_loop(ctx);
if (r) {
js_std_dump_error(ctx);
}
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return r;
}
@@ -0,0 +1,52 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_hello_size = 103;
const uint8_t qjsc_hello[103] = {
0x15, 0x04, 0x01, 0x22, 0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c,
0x6c, 0x6f, 0x2e, 0x6a, 0x73, 0x01, 0x0e, 0x63,
0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x01, 0x06,
0x6c, 0x6f, 0x67, 0x01, 0x16, 0x48, 0x65, 0x6c,
0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64,
0x0d, 0xc6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x20, 0x0a, 0x01, 0xa2, 0x01, 0x00, 0x00,
0x00, 0x03, 0x00, 0x00, 0x19, 0x00, 0x08, 0xec,
0x02, 0x29, 0x39, 0xe4, 0x00, 0x00, 0x00, 0x43,
0xe5, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00,
0x00, 0x24, 0x01, 0x00, 0x0e, 0x06, 0x2f, 0xc6,
0x03, 0x01, 0x01, 0x02, 0x48, 0x0e, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
return ctx;
}
int main(int argc, char **argv)
{
int r;
JSRuntime *rt;
JSContext *ctx;
r = 0;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);
r = js_std_loop(ctx);
if (r) {
js_std_dump_error(ctx);
}
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return r;
}
@@ -0,0 +1,106 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_fib_module_size = 290;
const uint8_t qjsc_fib_module[290] = {
0x15, 0x03, 0x01, 0x2c, 0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x62,
0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e,
0x6a, 0x73, 0x01, 0x06, 0x66, 0x69, 0x62, 0x01,
0x02, 0x6e, 0x0d, 0xc6, 0x03, 0x00, 0x01, 0x00,
0x00, 0xc8, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x20,
0x0a, 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x01,
0x01, 0x01, 0x09, 0x00, 0xc8, 0x03, 0x00, 0x01,
0x0c, 0x43, 0x0a, 0x01, 0xc8, 0x03, 0x01, 0x00,
0x01, 0x04, 0x01, 0x00, 0x1a, 0x01, 0xca, 0x03,
0x00, 0x01, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xd3,
0xb6, 0xa8, 0xec, 0x03, 0xb6, 0x28, 0xd3, 0xb7,
0xad, 0xec, 0x03, 0xb7, 0x28, 0xdf, 0xd3, 0xb7,
0x9f, 0xf1, 0xdf, 0xd3, 0xb8, 0x9f, 0xf1, 0x9e,
0x28, 0xc6, 0x03, 0x02, 0x08, 0x0e, 0x09, 0x0c,
0x27, 0x0a, 0x28, 0x02, 0x07, 0x08, 0x11, 0x0a,
0x07, 0x08, 0x07, 0x08, 0x8d, 0x01, 0x66, 0x75,
0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66,
0x69, 0x62, 0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28,
0x6e, 0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30,
0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c,
0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e,
0x20, 0x3d, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73,
0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e,
0x20, 0x66, 0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d,
0x20, 0x31, 0x29, 0x20, 0x2b, 0x20, 0x66, 0x69,
0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29,
0x3b, 0x0a, 0x7d, 0x08, 0xec, 0x05, 0xc1, 0x00,
0xe3, 0x29, 0x06, 0x2f, 0xc6, 0x03, 0x01, 0x01,
0x00, 0x00,
};
const uint32_t qjsc_hello_module_size = 187;
const uint8_t qjsc_hello_module[187] = {
0x15, 0x07, 0x01, 0x30, 0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c,
0x6c, 0x6f, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c,
0x65, 0x2e, 0x6a, 0x73, 0x01, 0x1e, 0x2e, 0x2f,
0x66, 0x69, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x75,
0x6c, 0x65, 0x2e, 0x6a, 0x73, 0x01, 0x06, 0x66,
0x69, 0x62, 0x01, 0x0e, 0x63, 0x6f, 0x6e, 0x73,
0x6f, 0x6c, 0x65, 0x01, 0x06, 0x6c, 0x6f, 0x67,
0x01, 0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20,
0x57, 0x6f, 0x72, 0x6c, 0x64, 0x01, 0x10, 0x66,
0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d,
0xc6, 0x03, 0x01, 0xc8, 0x03, 0x00, 0x00, 0x01,
0x00, 0xca, 0x03, 0x00, 0x00, 0x0c, 0x20, 0x0a,
0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x05, 0x01,
0x00, 0x32, 0x00, 0xca, 0x03, 0x00, 0x0c, 0x08,
0xec, 0x02, 0x29, 0x39, 0xe6, 0x00, 0x00, 0x00,
0x43, 0xe7, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00,
0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x39, 0xe6,
0x00, 0x00, 0x00, 0x43, 0xe7, 0x00, 0x00, 0x00,
0x04, 0xe9, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00,
0xbe, 0x0a, 0xf1, 0x24, 0x02, 0x00, 0x0e, 0x06,
0x2f, 0xc6, 0x03, 0x01, 0x01, 0x0c, 0x00, 0x04,
0x08, 0x00, 0x34, 0x10, 0x30, 0x0f, 0x34, 0x10,
0x2a, 0x20, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
js_std_eval_binary(ctx, qjsc_fib_module, qjsc_fib_module_size, 1);
return ctx;
}
int main(int argc, char **argv)
{
int r;
JSRuntime *rt;
JSContext *ctx;
r = 0;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_hello_module, qjsc_hello_module_size, 0);
r = js_std_loop(ctx);
if (r) {
js_std_dump_error(ctx);
}
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return r;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,323 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include <inttypes.h>
const uint32_t qjsc_standalone_size = 2511;
const uint8_t qjsc_standalone[2511] = {
0x15, 0x4e, 0x01, 0x1a, 0x73, 0x74, 0x61, 0x6e,
0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x2e, 0x6a,
0x73, 0x01, 0x0e, 0x71, 0x6a, 0x73, 0x3a, 0x73,
0x74, 0x64, 0x01, 0x0c, 0x71, 0x6a, 0x73, 0x3a,
0x6f, 0x73, 0x01, 0x12, 0x71, 0x6a, 0x73, 0x3a,
0x62, 0x6a, 0x73, 0x6f, 0x6e, 0x01, 0x22, 0x63,
0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x53, 0x74,
0x61, 0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65,
0x01, 0x1a, 0x72, 0x75, 0x6e, 0x53, 0x74, 0x61,
0x6e, 0x64, 0x61, 0x6c, 0x6f, 0x6e, 0x65, 0x01,
0x06, 0x73, 0x74, 0x64, 0x01, 0x04, 0x6f, 0x73,
0x01, 0x0a, 0x62, 0x6a, 0x73, 0x6f, 0x6e, 0x01,
0x28, 0x4a, 0x53, 0x5f, 0x52, 0x45, 0x41, 0x44,
0x5f, 0x4f, 0x42, 0x4a, 0x5f, 0x42, 0x59, 0x54,
0x45, 0x43, 0x4f, 0x44, 0x45, 0x01, 0x2a, 0x4a,
0x53, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x4f,
0x42, 0x4a, 0x5f, 0x52, 0x45, 0x46, 0x45, 0x52,
0x45, 0x4e, 0x43, 0x45, 0x01, 0x2a, 0x4a, 0x53,
0x5f, 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f,
0x42, 0x4a, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x43,
0x4f, 0x44, 0x45, 0x01, 0x2c, 0x4a, 0x53, 0x5f,
0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, 0x42,
0x4a, 0x5f, 0x52, 0x45, 0x46, 0x45, 0x52, 0x45,
0x4e, 0x43, 0x45, 0x01, 0x32, 0x4a, 0x53, 0x5f,
0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x4f, 0x42,
0x4a, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x50, 0x5f,
0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x01, 0x0e,
0x54, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72, 0x01,
0x16, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x41,
0x73, 0x63, 0x69, 0x69, 0x01, 0x16, 0x64, 0x65,
0x63, 0x6f, 0x64, 0x65, 0x41, 0x73, 0x63, 0x69,
0x69, 0x01, 0x06, 0x74, 0x78, 0x74, 0x01, 0x02,
0x63, 0x01, 0x14, 0x63, 0x68, 0x61, 0x72, 0x43,
0x6f, 0x64, 0x65, 0x41, 0x74, 0x01, 0x06, 0x6d,
0x61, 0x70, 0x01, 0x06, 0x62, 0x75, 0x66, 0x01,
0x18, 0x66, 0x72, 0x6f, 0x6d, 0x43, 0x68, 0x61,
0x72, 0x43, 0x6f, 0x64, 0x65, 0x01, 0x0c, 0x69,
0x6e, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x0e, 0x6f,
0x75, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x01, 0x12,
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x45, 0x78,
0x65, 0x01, 0x04, 0x6a, 0x73, 0x01, 0x08, 0x63,
0x6f, 0x64, 0x65, 0x01, 0x10, 0x62, 0x79, 0x74,
0x65, 0x63, 0x6f, 0x64, 0x65, 0x01, 0x16, 0x65,
0x78, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x4e, 0x61,
0x6d, 0x65, 0x01, 0x06, 0x65, 0x78, 0x65, 0x01,
0x0e, 0x65, 0x78, 0x65, 0x53, 0x69, 0x7a, 0x65,
0x01, 0x12, 0x6e, 0x65, 0x77, 0x42, 0x75, 0x66,
0x66, 0x65, 0x72, 0x01, 0x0c, 0x6e, 0x65, 0x77,
0x45, 0x78, 0x65, 0x01, 0x04, 0x64, 0x77, 0x01,
0x0a, 0x6e, 0x65, 0x77, 0x46, 0x64, 0x01, 0x10,
0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65,
0x01, 0x1e, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64,
0x20, 0x74, 0x6f, 0x20, 0x6f, 0x70, 0x65, 0x6e,
0x20, 0x01, 0x14, 0x65, 0x76, 0x61, 0x6c, 0x53,
0x63, 0x72, 0x69, 0x70, 0x74, 0x01, 0x18, 0x63,
0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x5f, 0x6f,
0x6e, 0x6c, 0x79, 0x01, 0x1c, 0x63, 0x6f, 0x6d,
0x70, 0x69, 0x6c, 0x65, 0x5f, 0x6d, 0x6f, 0x64,
0x75, 0x6c, 0x65, 0x01, 0x0a, 0x77, 0x72, 0x69,
0x74, 0x65, 0x01, 0x0e, 0x65, 0x78, 0x65, 0x50,
0x61, 0x74, 0x68, 0x01, 0x0a, 0x61, 0x72, 0x67,
0x76, 0x30, 0x01, 0x0c, 0x62, 0x69, 0x6e, 0x61,
0x72, 0x79, 0x01, 0x36, 0x66, 0x61, 0x69, 0x6c,
0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6f, 0x70,
0x65, 0x6e, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75,
0x74, 0x61, 0x62, 0x6c, 0x65, 0x3a, 0x20, 0x01,
0x0c, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x01,
0x10, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65,
0x72, 0x01, 0x08, 0x53, 0x69, 0x7a, 0x65, 0x01,
0x0a, 0x4d, 0x61, 0x67, 0x69, 0x63, 0x01, 0x12,
0x4d, 0x61, 0x67, 0x69, 0x63, 0x53, 0x69, 0x7a,
0x65, 0x01, 0x10, 0x44, 0x61, 0x74, 0x61, 0x53,
0x69, 0x7a, 0x65, 0x01, 0x12, 0x73, 0x65, 0x74,
0x55, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x01, 0x08,
0x6f, 0x70, 0x65, 0x6e, 0x01, 0x10, 0x4f, 0x5f,
0x57, 0x52, 0x4f, 0x4e, 0x4c, 0x59, 0x01, 0x0e,
0x4f, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x01,
0x0e, 0x4f, 0x5f, 0x54, 0x52, 0x55, 0x4e, 0x43,
0x01, 0x22, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64,
0x20, 0x74, 0x6f, 0x20, 0x63, 0x72, 0x65, 0x61,
0x74, 0x65, 0x20, 0x01, 0x14, 0x62, 0x79, 0x74,
0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x01,
0x0a, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x01, 0x3c,
0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74,
0x6f, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65, 0x20,
0x74, 0x6f, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75,
0x74, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x01, 0x08,
0x66, 0x69, 0x6c, 0x65, 0x01, 0x02, 0x72, 0x01,
0x0e, 0x74, 0x72, 0x61, 0x69, 0x6c, 0x65, 0x72,
0x01, 0x0a, 0x6d, 0x61, 0x67, 0x69, 0x63, 0x01,
0x0c, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x01,
0x04, 0x72, 0x62, 0x01, 0x08, 0x73, 0x65, 0x65,
0x6b, 0x01, 0x10, 0x53, 0x45, 0x45, 0x4b, 0x5f,
0x45, 0x4e, 0x44, 0x01, 0x18, 0x73, 0x65, 0x65,
0x6b, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x3a,
0x20, 0x01, 0x08, 0x72, 0x65, 0x61, 0x64, 0x01,
0x40, 0x63, 0x6f, 0x72, 0x72, 0x75, 0x70, 0x74,
0x65, 0x64, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72,
0x79, 0x2c, 0x20, 0x6d, 0x61, 0x67, 0x69, 0x63,
0x20, 0x6d, 0x69, 0x73, 0x6d, 0x61, 0x74, 0x63,
0x68, 0x01, 0x12, 0x67, 0x65, 0x74, 0x55, 0x69,
0x6e, 0x74, 0x33, 0x32, 0x01, 0x10, 0x53, 0x45,
0x45, 0x4b, 0x5f, 0x53, 0x45, 0x54, 0x01, 0x0a,
0x65, 0x72, 0x72, 0x6f, 0x72, 0x01, 0x14, 0x72,
0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6f,
0x72, 0x01, 0x16, 0x65, 0x76, 0x61, 0x6c, 0x5f,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x01, 0x10,
0x71, 0x75, 0x69, 0x63, 0x6b, 0x6a, 0x73, 0x32,
0x0d, 0xc6, 0x03, 0x03, 0xc8, 0x03, 0xca, 0x03,
0xcc, 0x03, 0x02, 0x00, 0x0b, 0xce, 0x03, 0x00,
0x0c, 0xd0, 0x03, 0x00, 0x03, 0x00, 0xfe, 0x01,
0x00, 0x01, 0xfe, 0x01, 0x01, 0x02, 0xfe, 0x01,
0x02, 0x00, 0x0c, 0x20, 0x02, 0x01, 0xa2, 0x01,
0x00, 0x00, 0x00, 0x02, 0x0d, 0x04, 0x58, 0x00,
0xd2, 0x03, 0x00, 0x0d, 0xd4, 0x03, 0x01, 0x0d,
0xd6, 0x03, 0x02, 0x0d, 0xd8, 0x03, 0x00, 0x0d,
0xda, 0x03, 0x01, 0x0d, 0xdc, 0x03, 0x02, 0x0d,
0xde, 0x03, 0x03, 0x0d, 0xe0, 0x03, 0x04, 0x0d,
0xe2, 0x03, 0x05, 0x0d, 0xe4, 0x03, 0x06, 0x01,
0xe6, 0x03, 0x07, 0x01, 0xce, 0x03, 0x08, 0x01,
0xd0, 0x03, 0x09, 0x01, 0x0c, 0x43, 0x02, 0x01,
0xe4, 0x03, 0x01, 0x00, 0x01, 0x05, 0x00, 0x01,
0x1e, 0x01, 0xe8, 0x03, 0x00, 0x01, 0x00, 0x0c,
0x42, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x03,
0x00, 0x00, 0x0a, 0x01, 0xea, 0x03, 0x00, 0x01,
0x00, 0xd3, 0x43, 0xf6, 0x00, 0x00, 0x00, 0xb6,
0x25, 0x01, 0x00, 0x39, 0xa7, 0x00, 0x00, 0x00,
0x11, 0xd3, 0x43, 0x5e, 0x00, 0x00, 0x00, 0xc2,
0x24, 0x01, 0x00, 0x43, 0xf7, 0x00, 0x00, 0x00,
0xc1, 0x00, 0x24, 0x01, 0x00, 0x21, 0x01, 0x00,
0x28, 0x0c, 0x43, 0x02, 0x01, 0xe6, 0x03, 0x01,
0x00, 0x01, 0x03, 0x00, 0x01, 0x21, 0x01, 0xf0,
0x03, 0x00, 0x01, 0x00, 0x0c, 0x42, 0x02, 0x01,
0x00, 0x01, 0x00, 0x01, 0x03, 0x00, 0x00, 0x0e,
0x01, 0xea, 0x03, 0x00, 0x01, 0x00, 0x39, 0x98,
0x00, 0x00, 0x00, 0x43, 0xf9, 0x00, 0x00, 0x00,
0xd3, 0x25, 0x01, 0x00, 0x39, 0x95, 0x00, 0x00,
0x00, 0x43, 0x7b, 0x00, 0x00, 0x00, 0xd3, 0x24,
0x01, 0x00, 0x43, 0xf7, 0x00, 0x00, 0x00, 0xc1,
0x00, 0x24, 0x01, 0x00, 0x43, 0x5c, 0x00, 0x00,
0x00, 0xc2, 0x25, 0x01, 0x00, 0x0c, 0x43, 0x02,
0x01, 0xce, 0x03, 0x03, 0x0a, 0x03, 0x07, 0x08,
0x00, 0x96, 0x04, 0x0d, 0xf4, 0x03, 0x00, 0x01,
0x00, 0xf6, 0x03, 0x00, 0x01, 0x00, 0xf8, 0x03,
0x00, 0x01, 0x00, 0xfa, 0x03, 0x01, 0x00, 0x30,
0xfc, 0x03, 0x01, 0x01, 0x30, 0xfe, 0x03, 0x01,
0x02, 0x30, 0x80, 0x04, 0x01, 0x03, 0x30, 0x82,
0x04, 0x01, 0x04, 0x30, 0x84, 0x04, 0x01, 0x05,
0x30, 0x86, 0x04, 0x01, 0x06, 0x30, 0x88, 0x04,
0x01, 0x07, 0x30, 0x8a, 0x04, 0x01, 0x08, 0x30,
0x8c, 0x04, 0x01, 0x09, 0x30, 0xd2, 0x03, 0x00,
0x0c, 0xd6, 0x03, 0x02, 0x0c, 0xdc, 0x03, 0x05,
0x0c, 0xde, 0x03, 0x06, 0x0c, 0xe0, 0x03, 0x07,
0x0c, 0xd4, 0x03, 0x01, 0x0c, 0xe2, 0x03, 0x08,
0x0c, 0xe4, 0x03, 0x09, 0x00, 0x62, 0x09, 0x00,
0x62, 0x08, 0x00, 0x62, 0x07, 0x00, 0x62, 0x06,
0x00, 0x62, 0x05, 0x00, 0x62, 0x04, 0x00, 0x62,
0x03, 0x00, 0x62, 0x02, 0x00, 0x62, 0x01, 0x00,
0x62, 0x00, 0x00, 0x66, 0x00, 0x00, 0x43, 0x07,
0x01, 0x00, 0x00, 0xd3, 0x24, 0x01, 0x00, 0xcb,
0x63, 0x00, 0x00, 0x97, 0xec, 0x19, 0x39, 0x96,
0x00, 0x00, 0x00, 0x11, 0x04, 0x08, 0x01, 0x00,
0x00, 0x43, 0x5d, 0x00, 0x00, 0x00, 0xd3, 0x24,
0x01, 0x00, 0x21, 0x01, 0x00, 0x30, 0x66, 0x00,
0x00, 0x43, 0x09, 0x01, 0x00, 0x00, 0x63, 0x00,
0x00, 0x0b, 0x0a, 0x4d, 0x0a, 0x01, 0x00, 0x00,
0x0a, 0x4d, 0x0b, 0x01, 0x00, 0x00, 0x24, 0x02,
0x00, 0xcc, 0x39, 0xa7, 0x00, 0x00, 0x00, 0x11,
0x66, 0x01, 0x00, 0x43, 0x0c, 0x01, 0x00, 0x00,
0x63, 0x01, 0x00, 0x66, 0x02, 0x00, 0x66, 0x03,
0x00, 0xa5, 0x66, 0x04, 0x00, 0xa5, 0x24, 0x02,
0x00, 0x21, 0x01, 0x00, 0xcd, 0xd5, 0x11, 0xb1,
0xec, 0x1c, 0x0e, 0x66, 0x05, 0x00, 0x43, 0x0d,
0x01, 0x00, 0x00, 0x24, 0x00, 0x00, 0x11, 0xb1,
0xec, 0x0c, 0x0e, 0x39, 0x8d, 0x00, 0x00, 0x00,
0x42, 0x0e, 0x01, 0x00, 0x00, 0xce, 0x66, 0x00,
0x00, 0x43, 0x07, 0x01, 0x00, 0x00, 0x63, 0x03,
0x00, 0x0b, 0x0a, 0x4d, 0x0f, 0x01, 0x00, 0x00,
0x24, 0x02, 0x00, 0xc4, 0x04, 0x63, 0x04, 0x00,
0x97, 0xec, 0x1b, 0x39, 0x96, 0x00, 0x00, 0x00,
0x11, 0x04, 0x10, 0x01, 0x00, 0x00, 0x43, 0x5d,
0x00, 0x00, 0x00, 0x63, 0x03, 0x00, 0x24, 0x01,
0x00, 0x21, 0x01, 0x00, 0x30, 0x63, 0x04, 0x00,
0xeb, 0xc4, 0x05, 0x63, 0x04, 0x00, 0x42, 0x11,
0x01, 0x00, 0x00, 0x43, 0x12, 0x01, 0x00, 0x00,
0x63, 0x05, 0x00, 0x63, 0x02, 0x00, 0xeb, 0x9e,
0x66, 0x06, 0x00, 0x42, 0x13, 0x01, 0x00, 0x00,
0x9e, 0x24, 0x01, 0x00, 0xc4, 0x06, 0x39, 0xa7,
0x00, 0x00, 0x00, 0x11, 0x63, 0x06, 0x00, 0x21,
0x01, 0x00, 0xc4, 0x07, 0x63, 0x07, 0x00, 0x43,
0x43, 0x00, 0x00, 0x00, 0x63, 0x02, 0x00, 0x63,
0x05, 0x00, 0x24, 0x02, 0x00, 0x0e, 0x63, 0x07,
0x00, 0x43, 0x43, 0x00, 0x00, 0x00, 0x5f, 0x07,
0x00, 0x66, 0x06, 0x00, 0x42, 0x14, 0x01, 0x00,
0x00, 0xf1, 0x63, 0x05, 0x00, 0x63, 0x02, 0x00,
0xeb, 0x9e, 0x24, 0x02, 0x00, 0x0e, 0x39, 0xb1,
0x00, 0x00, 0x00, 0x11, 0x63, 0x06, 0x00, 0x63,
0x05, 0x00, 0x63, 0x02, 0x00, 0xeb, 0x9e, 0x66,
0x06, 0x00, 0x42, 0x15, 0x01, 0x00, 0x00, 0x9e,
0x66, 0x06, 0x00, 0x42, 0x16, 0x01, 0x00, 0x00,
0x21, 0x03, 0x00, 0xc4, 0x08, 0x63, 0x08, 0x00,
0x43, 0x17, 0x01, 0x00, 0x00, 0xb6, 0x63, 0x05,
0x00, 0x0a, 0x24, 0x03, 0x00, 0x0e, 0x66, 0x05,
0x00, 0x43, 0x18, 0x01, 0x00, 0x00, 0xd4, 0x66,
0x05, 0x00, 0x42, 0x19, 0x01, 0x00, 0x00, 0x66,
0x05, 0x00, 0x42, 0x1a, 0x01, 0x00, 0x00, 0xa5,
0x66, 0x05, 0x00, 0x42, 0x1b, 0x01, 0x00, 0x00,
0xa5, 0xbf, 0xed, 0x01, 0x24, 0x03, 0x00, 0xc4,
0x09, 0x63, 0x09, 0x00, 0xb6, 0xa7, 0xec, 0x19,
0x39, 0x96, 0x00, 0x00, 0x00, 0x11, 0x04, 0x1c,
0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00, 0x00,
0xd4, 0x24, 0x01, 0x00, 0x21, 0x01, 0x00, 0x30,
0x66, 0x05, 0x00, 0x43, 0x0c, 0x01, 0x00, 0x00,
0x63, 0x09, 0x00, 0x63, 0x06, 0x00, 0xb6, 0x63,
0x06, 0x00, 0x42, 0x1d, 0x01, 0x00, 0x00, 0x24,
0x04, 0x00, 0xb6, 0xa7, 0xec, 0x1f, 0x66, 0x05,
0x00, 0x43, 0x1e, 0x01, 0x00, 0x00, 0x63, 0x09,
0x00, 0x24, 0x01, 0x00, 0x0e, 0x39, 0x96, 0x00,
0x00, 0x00, 0x11, 0x04, 0x1f, 0x01, 0x00, 0x00,
0x21, 0x01, 0x00, 0x30, 0x66, 0x05, 0x00, 0x43,
0x1e, 0x01, 0x00, 0x00, 0x63, 0x09, 0x00, 0x24,
0x01, 0x00, 0x29, 0x0c, 0x43, 0x02, 0x01, 0xd0,
0x03, 0x00, 0x09, 0x00, 0x07, 0x07, 0x00, 0xb4,
0x04, 0x09, 0xc0, 0x04, 0x01, 0x00, 0x30, 0x82,
0x04, 0x01, 0x01, 0x30, 0xc2, 0x04, 0x01, 0x02,
0x20, 0xc4, 0x04, 0x01, 0x03, 0x30, 0xc6, 0x04,
0x01, 0x04, 0x30, 0x8a, 0x04, 0x01, 0x05, 0x30,
0xc8, 0x04, 0x01, 0x06, 0x30, 0xfe, 0x03, 0x01,
0x07, 0x30, 0xfc, 0x03, 0x01, 0x08, 0x30, 0xd4,
0x03, 0x01, 0x0c, 0xd2, 0x03, 0x00, 0x0c, 0xe2,
0x03, 0x08, 0x0c, 0xe6, 0x03, 0x0a, 0x00, 0xd6,
0x03, 0x02, 0x0c, 0xd8, 0x03, 0x03, 0x0c, 0xda,
0x03, 0x04, 0x0c, 0x62, 0x08, 0x00, 0x62, 0x07,
0x00, 0x62, 0x06, 0x00, 0x62, 0x05, 0x00, 0x62,
0x04, 0x00, 0x62, 0x03, 0x00, 0x62, 0x02, 0x00,
0x62, 0x01, 0x00, 0x62, 0x00, 0x00, 0x66, 0x00,
0x00, 0x43, 0x0d, 0x01, 0x00, 0x00, 0x24, 0x00,
0x00, 0x11, 0xb1, 0xec, 0x0c, 0x0e, 0x39, 0x8d,
0x00, 0x00, 0x00, 0x42, 0x0e, 0x01, 0x00, 0x00,
0xcb, 0x66, 0x01, 0x00, 0x43, 0x18, 0x01, 0x00,
0x00, 0x63, 0x00, 0x00, 0x04, 0x25, 0x01, 0x00,
0x00, 0x24, 0x02, 0x00, 0xcc, 0x63, 0x01, 0x00,
0x97, 0xec, 0x1b, 0x39, 0x96, 0x00, 0x00, 0x00,
0x11, 0x04, 0x10, 0x01, 0x00, 0x00, 0x43, 0x5d,
0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x24, 0x01,
0x00, 0x21, 0x01, 0x00, 0x30, 0x63, 0x01, 0x00,
0x43, 0x26, 0x01, 0x00, 0x00, 0x66, 0x02, 0x00,
0x42, 0x13, 0x01, 0x00, 0x00, 0x8d, 0x66, 0x01,
0x00, 0x42, 0x27, 0x01, 0x00, 0x00, 0x24, 0x02,
0x00, 0xcd, 0x63, 0x02, 0x00, 0xb6, 0xa7, 0xec,
0x1c, 0x39, 0x96, 0x00, 0x00, 0x00, 0x11, 0x04,
0x28, 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00,
0x00, 0x63, 0x02, 0x00, 0x8d, 0x24, 0x01, 0x00,
0x21, 0x01, 0x00, 0x30, 0x39, 0xa7, 0x00, 0x00,
0x00, 0x11, 0x66, 0x02, 0x00, 0x42, 0x13, 0x01,
0x00, 0x00, 0x21, 0x01, 0x00, 0xce, 0x63, 0x01,
0x00, 0x43, 0x29, 0x01, 0x00, 0x00, 0x63, 0x03,
0x00, 0x42, 0x11, 0x01, 0x00, 0x00, 0xb6, 0x66,
0x02, 0x00, 0x42, 0x13, 0x01, 0x00, 0x00, 0x24,
0x03, 0x00, 0x0e, 0x39, 0xa7, 0x00, 0x00, 0x00,
0x11, 0x63, 0x03, 0x00, 0x42, 0x11, 0x01, 0x00,
0x00, 0xb6, 0x66, 0x02, 0x00, 0x42, 0x15, 0x01,
0x00, 0x00, 0x21, 0x03, 0x00, 0xc4, 0x04, 0xe2,
0x63, 0x04, 0x00, 0xf1, 0x66, 0x02, 0x00, 0x42,
0x14, 0x01, 0x00, 0x00, 0xb0, 0xec, 0x1c, 0x63,
0x01, 0x00, 0x43, 0x1e, 0x01, 0x00, 0x00, 0x24,
0x00, 0x00, 0x0e, 0x39, 0x96, 0x00, 0x00, 0x00,
0x11, 0x04, 0x2a, 0x01, 0x00, 0x00, 0x21, 0x01,
0x00, 0x30, 0x39, 0xb1, 0x00, 0x00, 0x00, 0x11,
0x63, 0x03, 0x00, 0x42, 0x11, 0x01, 0x00, 0x00,
0x66, 0x02, 0x00, 0x42, 0x15, 0x01, 0x00, 0x00,
0x66, 0x02, 0x00, 0x42, 0x16, 0x01, 0x00, 0x00,
0x21, 0x03, 0x00, 0xc4, 0x05, 0x63, 0x05, 0x00,
0x43, 0x2b, 0x01, 0x00, 0x00, 0xb6, 0x0a, 0x24,
0x02, 0x00, 0xc4, 0x06, 0x39, 0xa7, 0x00, 0x00,
0x00, 0x11, 0x63, 0x06, 0x00, 0x66, 0x02, 0x00,
0x42, 0x13, 0x01, 0x00, 0x00, 0x9f, 0x21, 0x01,
0x00, 0xc4, 0x07, 0x63, 0x01, 0x00, 0x43, 0x26,
0x01, 0x00, 0x00, 0x63, 0x06, 0x00, 0x66, 0x01,
0x00, 0x42, 0x2c, 0x01, 0x00, 0x00, 0x24, 0x02,
0x00, 0x11, 0x64, 0x02, 0x00, 0x0e, 0x63, 0x02,
0x00, 0xb6, 0xa7, 0xec, 0x28, 0x63, 0x01, 0x00,
0x43, 0x1e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00,
0x0e, 0x39, 0x96, 0x00, 0x00, 0x00, 0x11, 0x04,
0x28, 0x01, 0x00, 0x00, 0x43, 0x5d, 0x00, 0x00,
0x00, 0x63, 0x02, 0x00, 0x8d, 0x24, 0x01, 0x00,
0x21, 0x01, 0x00, 0x30, 0x63, 0x01, 0x00, 0x43,
0x29, 0x01, 0x00, 0x00, 0x63, 0x07, 0x00, 0x42,
0x11, 0x01, 0x00, 0x00, 0xb6, 0x63, 0x07, 0x00,
0xeb, 0x24, 0x03, 0x00, 0x0e, 0x63, 0x01, 0x00,
0x43, 0x2d, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00,
0xec, 0x1c, 0x63, 0x01, 0x00, 0x43, 0x1e, 0x01,
0x00, 0x00, 0x24, 0x00, 0x00, 0x0e, 0x39, 0x96,
0x00, 0x00, 0x00, 0x11, 0x04, 0x2e, 0x01, 0x00,
0x00, 0x21, 0x01, 0x00, 0x30, 0x63, 0x01, 0x00,
0x43, 0x1e, 0x01, 0x00, 0x00, 0x24, 0x00, 0x00,
0x0e, 0x66, 0x04, 0x00, 0x43, 0x29, 0x01, 0x00,
0x00, 0x63, 0x07, 0x00, 0x42, 0x11, 0x01, 0x00,
0x00, 0xb6, 0x63, 0x07, 0x00, 0xeb, 0x66, 0x05,
0x00, 0x66, 0x06, 0x00, 0xa5, 0x24, 0x04, 0x00,
0xc4, 0x08, 0x66, 0x01, 0x00, 0x43, 0x09, 0x01,
0x00, 0x00, 0x63, 0x08, 0x00, 0x0b, 0x0a, 0x4d,
0x2f, 0x01, 0x00, 0x00, 0x25, 0x02, 0x00, 0x08,
0xec, 0x16, 0xc1, 0x00, 0x60, 0x09, 0x00, 0xc1,
0x01, 0x60, 0x0a, 0x00, 0xc1, 0x02, 0x60, 0x0b,
0x00, 0xc1, 0x03, 0x60, 0x0c, 0x00, 0x29, 0xb7,
0xb6, 0xa0, 0xe6, 0xb7, 0xb9, 0xa0, 0x60, 0x04,
0x00, 0xb7, 0xb6, 0xa0, 0x60, 0x05, 0x00, 0xb7,
0xb9, 0xa0, 0x60, 0x06, 0x00, 0xb7, 0xba, 0xa0,
0x60, 0x07, 0x00, 0x0b, 0x04, 0x30, 0x01, 0x00,
0x00, 0x4d, 0x14, 0x01, 0x00, 0x00, 0xbe, 0x08,
0x4d, 0x15, 0x01, 0x00, 0x00, 0xba, 0x4d, 0x16,
0x01, 0x00, 0x00, 0xbe, 0x0c, 0x4d, 0x13, 0x01,
0x00, 0x00, 0x60, 0x08, 0x00, 0x06, 0x2f,
};
@@ -0,0 +1,80 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_test_fib_size = 294;
const uint8_t qjsc_test_fib[294] = {
0x15, 0x0e, 0x01, 0x28, 0x65, 0x78, 0x61, 0x6d,
0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73,
0x74, 0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73,
0x01, 0x0c, 0x71, 0x6a, 0x73, 0x3a, 0x6f, 0x73,
0x01, 0x04, 0x6f, 0x73, 0x01, 0x0a, 0x69, 0x73,
0x57, 0x69, 0x6e, 0x01, 0x06, 0x66, 0x69, 0x62,
0x01, 0x10, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f,
0x72, 0x6d, 0x01, 0x0a, 0x77, 0x69, 0x6e, 0x33,
0x32, 0x01, 0x0c, 0x2e, 0x2f, 0x66, 0x69, 0x62,
0x2e, 0x01, 0x06, 0x64, 0x6c, 0x6c, 0x01, 0x04,
0x73, 0x6f, 0x01, 0x0e, 0x63, 0x6f, 0x6e, 0x73,
0x6f, 0x6c, 0x65, 0x01, 0x06, 0x6c, 0x6f, 0x67,
0x01, 0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20,
0x57, 0x6f, 0x72, 0x6c, 0x64, 0x01, 0x10, 0x66,
0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d,
0xc6, 0x03, 0x01, 0xc8, 0x03, 0x00, 0x00, 0x01,
0x00, 0xfe, 0x01, 0x00, 0x01, 0x0c, 0x20, 0x0a,
0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03,
0x00, 0x73, 0x00, 0xca, 0x03, 0x00, 0x0d, 0xcc,
0x03, 0x00, 0x0d, 0xce, 0x03, 0x01, 0x0d, 0x08,
0xec, 0x02, 0x29, 0x66, 0x00, 0x00, 0x42, 0xe8,
0x00, 0x00, 0x00, 0x04, 0xe9, 0x00, 0x00, 0x00,
0xaf, 0xe4, 0x06, 0x11, 0xf4, 0xed, 0x0b, 0x71,
0x43, 0xe7, 0x00, 0x00, 0x00, 0xe5, 0x0e, 0xee,
0x24, 0x0e, 0x04, 0xea, 0x00, 0x00, 0x00, 0x43,
0x5d, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0xec,
0x08, 0x04, 0xeb, 0x00, 0x00, 0x00, 0xee, 0x06,
0x04, 0xec, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00,
0x36, 0x8c, 0xee, 0xd4, 0x39, 0xed, 0x00, 0x00,
0x00, 0x43, 0xee, 0x00, 0x00, 0x00, 0x04, 0xef,
0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x39,
0xed, 0x00, 0x00, 0x00, 0x43, 0xee, 0x00, 0x00,
0x00, 0x04, 0xf0, 0x00, 0x00, 0x00, 0x66, 0x02,
0x00, 0xbe, 0x0a, 0xf1, 0x24, 0x02, 0x00, 0x0e,
0x06, 0x2f, 0xc6, 0x03, 0x01, 0x01, 0x0e, 0x41,
0x3c, 0x00, 0x39, 0x06, 0x3b, 0x34, 0x10, 0x30,
0x0f, 0x34, 0x10, 0x2a, 0x20, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
{
extern JSModuleDef *js_init_module_os(JSContext *ctx, const char *name);
js_init_module_os(ctx, "qjs:os");
}
return ctx;
}
int main(int argc, char **argv)
{
int r;
JSRuntime *rt;
JSContext *ctx;
r = 0;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_test_fib, qjsc_test_fib_size, 0);
r = js_std_loop(ctx);
if (r) {
js_std_dump_error(ctx);
}
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return r;
}
@@ -0,0 +1,58 @@
/*
* Regular Expression Engine
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef DEF
DEF(invalid, 1) /* never used */
DEF(char8, 2) /* 7 bits in fact */
DEF(char16, 3)
DEF(char32, 5)
DEF(dot, 1)
DEF(any, 1) /* same as dot but match any character including line terminator */
DEF(line_start, 1)
DEF(line_end, 1)
DEF(goto, 5)
DEF(split_goto_first, 5)
DEF(split_next_first, 5)
DEF(match, 1)
DEF(save_start, 2) /* save start position */
DEF(save_end, 2) /* save end position, must come after saved_start */
DEF(save_reset, 3) /* reset save positions */
DEF(loop, 5) /* decrement the top the stack and goto if != 0 */
DEF(push_i32, 5) /* push integer on the stack */
DEF(drop, 1)
DEF(word_boundary, 1)
DEF(not_word_boundary, 1)
DEF(back_reference, 2)
DEF(backward_back_reference, 2) /* must come after back_reference */
DEF(range, 3) /* variable length */
DEF(range32, 3) /* variable length */
DEF(lookahead, 5)
DEF(negative_lookahead, 5)
DEF(push_char_pos, 1) /* push the character position on the stack */
DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */
DEF(prev, 1) /* go to the previous char */
DEF(simple_greedy_quant, 17)
#endif /* DEF */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,97 @@
/*
* Regular Expression Engine
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIBREGEXP_H
#define LIBREGEXP_H
#include <stdbool.h>
#include <stddef.h>
#include "libunicode.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LRE_FLAG_GLOBAL (1 << 0)
#define LRE_FLAG_IGNORECASE (1 << 1)
#define LRE_FLAG_MULTILINE (1 << 2)
#define LRE_FLAG_DOTALL (1 << 3)
#define LRE_FLAG_UNICODE (1 << 4)
#define LRE_FLAG_STICKY (1 << 5)
#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
#define LRE_FLAG_UNICODE_SETS (1 << 8)
#define LRE_RET_MEMORY_ERROR (-1)
#define LRE_RET_TIMEOUT (-2)
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
const char *buf, size_t buf_len, int re_flags,
void *opaque);
int lre_get_capture_count(const uint8_t *bc_buf);
int lre_get_flags(const uint8_t *bc_buf);
const char *lre_get_groupnames(const uint8_t *bc_buf);
int lre_exec(uint8_t **capture,
const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
int cbuf_type, void *opaque);
int lre_parse_escape(const uint8_t **pp, int allow_utf16);
bool lre_is_space(int c);
void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped);
/* must be provided by the user */
bool lre_check_stack_overflow(void *opaque, size_t alloca_size);
/* must be provided by the user, return non zero if time out */
int lre_check_timeout(void *opaque);
void *lre_realloc(void *opaque, void *ptr, size_t size);
/* JS identifier test */
extern uint32_t const lre_id_start_table_ascii[4];
extern uint32_t const lre_id_continue_table_ascii[4];
static inline int lre_js_is_ident_first(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
return lre_is_id_start(c);
}
}
static inline int lre_js_is_ident_next(int c)
{
if ((uint32_t)c < 128) {
return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1;
} else {
/* ZWNJ and ZWJ are accepted in identifiers */
return lre_is_id_continue(c) || c == 0x200C || c == 0x200D;
}
}
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* LIBREGEXP_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,126 @@
/*
* Unicode utilities
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIBUNICODE_H
#define LIBUNICODE_H
#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LRE_CC_RES_LEN_MAX 3
typedef enum {
UNICODE_NFC,
UNICODE_NFD,
UNICODE_NFKC,
UNICODE_NFKD,
} UnicodeNormalizationEnum;
int lre_case_conv(uint32_t *res, uint32_t c, int conv_type);
int lre_canonicalize(uint32_t c, bool is_unicode);
bool lre_is_cased(uint32_t c);
bool lre_is_case_ignorable(uint32_t c);
/* char ranges */
typedef struct {
int len; /* in points, always even */
int size;
uint32_t *points; /* points sorted by increasing value */
void *mem_opaque;
void *(*realloc_func)(void *opaque, void *ptr, size_t size);
} CharRange;
typedef enum {
CR_OP_UNION,
CR_OP_INTER,
CR_OP_XOR,
} CharRangeOpEnum;
void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
void cr_free(CharRange *cr);
int cr_realloc(CharRange *cr, int size);
int cr_copy(CharRange *cr, const CharRange *cr1);
static inline int cr_add_point(CharRange *cr, uint32_t v)
{
if (cr->len >= cr->size) {
if (cr_realloc(cr, cr->len + 1))
return -1;
}
cr->points[cr->len++] = v;
return 0;
}
static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2)
{
if ((cr->len + 2) > cr->size) {
if (cr_realloc(cr, cr->len + 2))
return -1;
}
cr->points[cr->len++] = c1;
cr->points[cr->len++] = c2;
return 0;
}
int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len);
static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2)
{
uint32_t b_pt[2];
b_pt[0] = c1;
b_pt[1] = c2 + 1;
return cr_union1(cr, b_pt, 2);
}
int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len,
const uint32_t *b_pt, int b_len, int op);
int cr_invert(CharRange *cr);
int cr_regexp_canonicalize(CharRange *cr, bool is_unicode);
bool lre_is_id_start(uint32_t c);
bool lre_is_id_continue(uint32_t c);
bool lre_is_white_space(uint32_t c);
int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len,
UnicodeNormalizationEnum n_type,
void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size));
/* Unicode character range functions */
int unicode_script(CharRange *cr,
const char *script_name, bool is_ext);
int unicode_general_category(CharRange *cr, const char *gc_name);
int unicode_prop(CharRange *cr, const char *prop_name);
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* LIBUNICODE_H */
+107
View File
@@ -0,0 +1,107 @@
/*
* Linux klist like system
*
* Copyright (c) 2016-2017 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef LIST_H
#define LIST_H
#ifndef NULL
#include <stddef.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct list_head {
struct list_head *prev;
struct list_head *next;
};
#define LIST_HEAD_INIT(el) { &(el), &(el) }
/* return the pointer of type 'type *' containing 'el' as field 'member' */
#define list_entry(el, type, member) container_of(el, type, member)
static inline void init_list_head(struct list_head *head)
{
head->prev = head;
head->next = head;
}
/* insert 'el' between 'prev' and 'next' */
static inline void __list_add(struct list_head *el,
struct list_head *prev, struct list_head *next)
{
prev->next = el;
el->prev = prev;
el->next = next;
next->prev = el;
}
/* add 'el' at the head of the list 'head' (= after element head) */
static inline void list_add(struct list_head *el, struct list_head *head)
{
__list_add(el, head, head->next);
}
/* add 'el' at the end of the list 'head' (= before element head) */
static inline void list_add_tail(struct list_head *el, struct list_head *head)
{
__list_add(el, head->prev, head);
}
static inline void list_del(struct list_head *el)
{
struct list_head *prev, *next;
prev = el->prev;
next = el->next;
prev->next = next;
next->prev = prev;
el->prev = NULL; /* fail safe */
el->next = NULL; /* fail safe */
}
static inline int list_empty(struct list_head *el)
{
return el->next == el;
}
#define list_for_each(el, head) \
for(el = (head)->next; el != (head); el = el->next)
#define list_for_each_safe(el, el1, head) \
for(el = (head)->next, el1 = el->next; el != (head); \
el = el1, el1 = el->next)
#define list_for_each_prev(el, head) \
for(el = (head)->prev; el != (head); el = el->prev)
#define list_for_each_prev_safe(el, el1, head) \
for(el = (head)->prev, el1 = el->prev; el != (head); \
el = el1, el1 = el->prev)
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* LIST_H */
+635
View File
@@ -0,0 +1,635 @@
project(
'quickjs-ng',
'c',
version: '0.11.0',
default_options: [
'c_std=gnu11,c11',
'warning_level=3',
'default_library=static',
],
license: 'MIT',
license_files: 'LICENSE',
meson_version: '>=1.3.0',
)
host_system = host_machine.system()
cc = meson.get_compiler('c')
qjs_gcc_warning_args = [
'-Wno-unsafe-buffer-usage',
'-Wno-sign-conversion',
'-Wno-nonportable-system-include-path',
'-Wno-implicit-int-conversion',
'-Wno-shorten-64-to-32',
'-Wno-reserved-macro-identifier',
'-Wno-reserved-identifier',
'-Wdeprecated-declarations',
'-Wno-implicit-fallthrough',
'-Wno-sign-compare',
'-Wno-missing-field-initializers',
'-Wno-unused-parameter',
'-Wno-unused-but-set-variable',
'-Wno-array-bounds',
'-Wno-format-truncation',
]
qjs_gcc_args = [
'-funsigned-char',
]
if host_system == 'darwin'
# https://github.com/quickjs-ng/quickjs/issues/453
qjs_gcc_warning_args += '-Wno-maybe-uninitialized'
endif
# https://github.com/microsoft/cpp-docs/tree/main/docs/error-messages/compiler-warnings
qjs_msvc_warning_args = [
'/wd4018', # -Wno-sign-conversion
'/wd4061', # -Wno-implicit-fallthrough
'/wd4100', # -Wno-unused-parameter
'/wd4200', # -Wno-zero-length-array
'/wd4242', # -Wno-shorten-64-to-32
'/wd4244', # -Wno-shorten-64-to-32
'/wd4245', # -Wno-sign-compare
'/wd4267', # -Wno-shorten-64-to-32
'/wd4388', # -Wno-sign-compare
'/wd4389', # -Wno-sign-compare
'/wd4710', # Function not inlined
'/wd4711', # Function was inlined
'/wd4820', # Padding added after construct
'/wd4996', # -Wdeprecated-declarations
'/wd5045', # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
]
qjs_msvc_args = [
'/experimental:c11atomics',
'/J', # -funsigned-char
]
if cc.get_argument_syntax() == 'msvc'
add_project_arguments(
cc.get_supported_arguments(qjs_msvc_warning_args),
cc.get_id().contains('clang') ? cc.get_supported_arguments(qjs_gcc_warning_args) : [],
qjs_msvc_args,
language: 'c',
)
else
add_project_arguments(
cc.get_supported_arguments(qjs_gcc_warning_args),
qjs_gcc_args,
language: 'c',
)
endif
if host_system == 'windows'
# Set a 8MB default stack size on Windows.
# It defaults to 1MB on MSVC, which is the same as our current JS stack size,
# so it will overflow and crash otherwise.
# On MinGW it defaults to 2MB.
stack_size = 8 * 1024 * 1024
if cc.get_argument_syntax() == 'msvc'
add_project_link_arguments(f'/STACK:@stack_size@', language: 'c')
else
add_project_link_arguments(f'-Wl,--stack,@stack_size@', language: 'c')
endif
endif
if meson.is_cross_build()
native_cc = meson.get_compiler('c', native: true)
if native_cc.get_argument_syntax() == 'msvc'
# https://github.com/microsoft/cpp-docs/tree/main/docs/error-messages/compiler-warnings
add_project_arguments(
native_cc.get_supported_arguments(qjs_msvc_warning_args),
native_cc.get_id().contains('clang') ? native_cc.get_supported_arguments(qjs_gcc_warning_args) : [],
qjs_msvc_args,
language: 'c',
native: true,
)
else
add_project_arguments(
native_cc.get_supported_arguments(qjs_gcc_warning_args),
qjs_gcc_args,
language: 'c',
native: true,
)
endif
endif
if get_option('debug')
add_project_arguments(
cc.get_supported_arguments('-fno-omit-frame-pointer'),
language: 'c',
)
endif
qjs_sys_deps = []
m_dep = cc.find_library('m', required: false)
qjs_sys_deps += m_dep
qjs_sys_deps += dependency('threads', required: false)
qjs_sys_deps += dependency('dl', required: false)
qjs_srcs = files(
'cutils.c',
'dtoa.c',
'libregexp.c',
'libunicode.c',
'quickjs.c',
)
qjs_hdrs = files(
'quickjs.h',
)
qjs_libc = get_option('libc')
qjs_libc_srcs = files('quickjs-libc.c')
qjs_libc_hdrs = files('quickjs-libc.h')
if qjs_libc
qjs_hdrs += qjs_libc_hdrs
endif
qjs_parser = get_option('parser')
qjs_c_args = ['-D_GNU_SOURCE']
if host_system == 'windows'
qjs_c_args += ['-DWIN32_LEAN_AND_MEAN', '-D_WIN32_WINNT=0x0601']
endif
if not qjs_parser
qjs_c_args += ['-DQJS_DISABLE_PARSER']
endif
qjs_libc_lib = static_library(
'quickjs-libc',
qjs_libc_srcs,
dependencies: qjs_sys_deps,
c_args: qjs_c_args,
gnu_symbol_visibility: 'hidden',
)
qjs_lib = library(
'qjs',
qjs_srcs,
# export public headers
generator(
find_program('cp', 'xcopy'),
output: ['@PLAINNAME@'],
arguments: ['@INPUT@', '@OUTPUT@'],
).process(qjs_hdrs),
dependencies: qjs_sys_deps,
link_whole: qjs_libc ? qjs_libc_lib : [],
c_args: qjs_c_args,
gnu_symbol_visibility: 'hidden',
install: true,
version: meson.project_version(),
)
qjs_export_variables = [
f'have_parser=@qjs_parser@'
]
qjs_dep = declare_dependency(
link_with: qjs_lib,
dependencies: qjs_sys_deps,
include_directories: qjs_lib.private_dir_include(),
variables: qjs_export_variables,
)
if host_system == 'emscripten'
qjs_wasm_export_name = 'getQuickJs'
executable(
'qjs_wasm',
qjs_srcs,
link_args: cc.get_supported_link_arguments(
# in emscripten 3.x, this will be set to 16k which is too small for quickjs.
'-sSTACK_SIZE=@0@'.format(2 * 1024 * 1024), # let it be 2m = 2 * 1024 * 1024, otherwise, stack overflow may be occured at bootstrap
'-sNO_INVOKE_RUN',
'-sNO_EXIT_RUNTIME',
'-sMODULARIZE', # do not mess the global
'-sEXPORT_ES6', # export js file to morden es module
'-sEXPORT_NAME=@0@'.format(qjs_wasm_export_name), # give a name
'-sTEXTDECODER=1', # it will be 2 if we use -Oz, and that will cause js -> c string convertion fail
'-sNO_DEFAULT_TO_CXX', # this project is pure c project, no need for c plus plus handle
'-sEXPORTED_RUNTIME_METHODS=ccall,cwrap',
),
dependencies: m_dep,
c_args: qjs_c_args,
)
endif
install_headers(qjs_hdrs, subdir: 'quickjs-ng')
if not meson.is_subproject()
docdir = get_option('docdir')
datadir = get_option('datadir')
if docdir == ''
docdir = datadir / 'doc' / meson.project_name()
endif
install_data(
'LICENSE',
install_dir: docdir,
install_tag: 'doc',
)
install_subdir(
'examples',
install_dir: docdir,
strip_directory: false,
install_tag: 'doc',
)
endif
meson.override_dependency('quickjs-ng', qjs_dep)
import('pkgconfig').generate(
qjs_lib,
subdirs: 'quickjs-ng',
name: 'quickjs-ng',
description: 'QuickJS, the Next Generation: a mighty JavaScript engine',
url: 'https://github.com/quickjs-ng/quickjs',
version: meson.project_version(),
variables: qjs_export_variables,
)
if not qjs_parser
subdir_done()
endif
# QuickJS bytecode compiler
qjsc_srcs = files(
'qjsc.c',
)
qjsc_exe = executable(
'qjsc',
qjsc_srcs,
c_args: qjs_c_args,
link_with: qjs_libc ? [] : qjs_libc_lib,
dependencies: qjs_dep,
install: true,
)
mimalloc_dep = []
mimalloc_sys_dep = dependency('mimalloc', required: get_option('cli_mimalloc'))
if mimalloc_sys_dep.found()
mimalloc_dep = declare_dependency(
dependencies: mimalloc_sys_dep,
compile_args: '-DQJS_USE_MIMALLOC',
)
endif
# QuickJS CLI
qjs_exe_srcs = files(
'gen/repl.c',
'gen/standalone.c',
'qjs.c',
)
qjs_exe = executable(
'qjs',
qjs_exe_srcs,
c_args: qjs_c_args,
link_with: qjs_libc ? [] : qjs_libc_lib,
dependencies: [qjs_dep, mimalloc_dep],
export_dynamic: true,
install: true,
)
if meson.is_cross_build()
mimalloc_native_dep = []
mimalloc_sys_native_dep = dependency('mimalloc', required: get_option('cli_mimalloc'), native: true)
if mimalloc_sys_dep.found()
mimalloc_native_dep = declare_dependency(
dependencies: mimalloc_sys_native_dep,
compile_args: '-DQJS_USE_MIMALLOC',
)
endif
qjs_sys_native_deps = [
native_cc.find_library('m', required: false),
dependency('threads', required: false, native: true),
dependency('dl', required: false, native: true),
]
qjs_native_lib = static_library(
'qjs_native',
qjs_srcs,
qjs_libc_srcs,
dependencies: qjs_sys_native_deps,
c_args: qjs_c_args,
gnu_symbol_visibility: 'hidden',
build_by_default: false,
native: true,
install: false,
)
meson.override_find_program(
'qjsc',
executable(
'qjsc_native',
qjsc_srcs,
c_args: qjs_c_args,
link_with: qjs_native_lib,
dependencies: qjs_sys_native_deps,
build_by_default: false,
native: true,
install: false,
),
)
meson.override_find_program(
'qjs',
executable(
'qjs_native',
qjs_exe_srcs,
c_args: qjs_c_args,
link_with: qjs_native_lib,
dependencies: [qjs_sys_native_deps, mimalloc_native_dep],
export_dynamic: true,
build_by_default: false,
native: true,
install: false,
),
)
else
meson.override_find_program('qjsc', qjsc_exe)
meson.override_find_program('qjs', qjs_exe)
endif
tests = get_option('tests').disable_auto_if(meson.is_subproject())
examples = get_option('examples').disable_auto_if(meson.is_subproject())
if tests.allowed()
if host_system != 'emscripten'
# Test262 runner
run262_exe = executable(
'run-test262',
'run-test262.c',
qjs_libc_srcs,
c_args: qjs_c_args,
dependencies: qjs_dep,
)
test(
'test',
run262_exe,
args: ['-c', files('tests.conf')],
workdir: meson.current_source_dir(),
)
foreach bench : [
'empty_loop',
'date_now',
'prop_read',
'prop_write',
'prop_create',
'prop_delete',
'array_read',
'array_write',
'array_prop_create',
'array_length_decr',
'array_hole_length_decr',
'array_push',
'array_pop',
'typed_array_read',
'typed_array_write',
'global_read',
'global_write',
'global_write_strict',
'local_destruct',
'global_destruct',
'global_destruct_strict',
'func_call',
'closure_var',
'int_arith',
'float_arith',
'map_set',
'map_delete',
'weak_map_set',
'weak_map_delete',
'array_for',
'array_for_in',
'array_for_of',
'math_min',
'object_null',
'regexp_ascii',
'regexp_utf16',
'string_build1',
'string_build2',
'string_slice1',
'string_slice2',
'string_slice3',
'sort_bench',
'int_to_string',
'int_toString',
'float_to_string',
'float_toString',
'float_toFixed',
'float_toPrecision',
'float_toExponential',
'string_to_int',
'string_to_float',
'bigint64_arith',
'bigint256_arith',
]
benchmark(
bench,
qjs_exe,
args: [files('tests/microbench.js'), bench],
)
endforeach
endif
# API test
test(
'api',
executable(
'api-test',
'api-test.c',
c_args: qjs_c_args,
dependencies: qjs_dep,
build_by_default: false,
),
)
# Function.toString() test
test(
'function_source',
executable(
'function_source',
'gen/function_source.c',
qjs_libc_srcs,
c_args: qjs_c_args,
dependencies: qjs_dep,
build_by_default: false,
),
)
endif
# Unicode generator
unicode_gen = executable(
'unicode_gen',
'cutils.c',
'unicode_gen.c',
c_args: qjs_c_args,
build_by_default: false,
)
run_target(
'libunicode-table.h',
command: [
unicode_gen,
meson.current_source_dir() / 'unicode',
files('libunicode-table.h'),
],
)
# bytecode to c source code for builtin and examples
alias_target('codegen',
run_target(
'codegen_repl.c',
command: [
qjsc_exe,
'-ss',
'-o', files('gen/repl.c'),
'-m',
'-n', 'repl.js',
files('repl.js'),
],
),
run_target(
'codegen_standalone.c',
command: [
qjsc_exe,
'-ss',
'-o', files('gen/standalone.c'),
'-m',
'-n', 'standalone.js',
files('standalone.js'),
],
),
run_target(
'codegen_function_source.c',
command: [
qjsc_exe,
'-e',
'-o', files('gen/function_source.c'),
'-n', 'tests/function_source.js',
files('tests/function_source.js'),
],
),
run_target(
'codegen_hello.c',
command: [
qjsc_exe,
'-e',
'-o', files('gen/hello.c'),
'-n', 'examples/hello.js',
files('examples/hello.js'),
],
),
run_target(
'codegen_hello_module.c',
command: [
qjsc_exe,
'-e',
'-o', files('gen/hello_module.c'),
'-m',
'-n', 'examples/hello_module.js',
files('examples/hello_module.js'),
],
),
run_target(
'codegen_test_fib.c',
command: [
qjsc_exe,
'-e',
'-o', files('gen/test_fib.c'),
'-m',
'-n', 'examples/test_fib.js',
files('examples/test_fib.js'),
],
),
run_target(
'codegen_builtin-array-fromasync.h',
command: [
qjsc_exe,
'-C',
'-ss',
'-o', files('builtin-array-fromasync.h'),
'-n', 'builtin-array-fromasync.js',
files('builtin-array-fromasync.js'),
],
),
)
if examples.allowed()
executable(
'hello',
'gen/hello.c',
qjs_libc_srcs,
c_args: qjs_c_args,
dependencies: qjs_dep,
)
executable(
'hello_module',
'gen/hello_module.c',
qjs_libc_srcs,
c_args: qjs_c_args,
dependencies: qjs_dep,
)
subdir('examples')
executable(
'test_fib',
'examples/fib.c',
'gen/test_fib.c',
qjs_libc_srcs,
c_args: qjs_c_args,
dependencies: qjs_dep,
export_dynamic: true,
)
endif
@@ -0,0 +1,6 @@
option('tests', type: 'feature', description: 'build tests')
option('examples', type: 'feature', description: 'build examples')
option('libc', type: 'boolean', value: false, description: 'build qjs standard library modules as part of the library')
option('cli_mimalloc', type: 'feature', value: 'disabled', description: 'build qjs cli with mimalloc')
option('docdir', type: 'string', description: 'documentation directory')
option('parser', type: 'boolean', value: true, description: 'Enable JS source code parser')
+748
View File
@@ -0,0 +1,748 @@
/*
* QuickJS stand alone interpreter
*
* Copyright (c) 2017-2021 Fabrice Bellard
* Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include "cutils.h"
#include "quickjs.h"
#include "quickjs-libc.h"
#ifdef QJS_USE_MIMALLOC
#include <mimalloc.h>
#endif
extern const uint8_t qjsc_repl[];
extern const uint32_t qjsc_repl_size;
extern const uint8_t qjsc_standalone[];
extern const uint32_t qjsc_standalone_size;
// Must match standalone.js
#define TRAILER_SIZE 12
static const char trailer_magic[] = "quickjs2";
static const int trailer_magic_size = sizeof(trailer_magic) - 1;
static const int trailer_size = TRAILER_SIZE;
static int qjs__argc;
static char **qjs__argv;
static bool is_standalone(const char *exe)
{
FILE *exe_f = fopen(exe, "rb");
if (!exe_f)
return false;
if (fseek(exe_f, -trailer_size, SEEK_END) < 0)
goto fail;
uint8_t buf[TRAILER_SIZE];
if (fread(buf, 1, trailer_size, exe_f) != trailer_size)
goto fail;
fclose(exe_f);
return !memcmp(buf, trailer_magic, trailer_magic_size);
fail:
fclose(exe_f);
return false;
}
static JSValue load_standalone_module(JSContext *ctx)
{
JSModuleDef *m;
JSValue obj, val;
obj = JS_ReadObject(ctx, qjsc_standalone, qjsc_standalone_size, JS_READ_OBJ_BYTECODE);
if (JS_IsException(obj))
goto exception;
assert(JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE);
if (JS_ResolveModule(ctx, obj) < 0) {
JS_FreeValue(ctx, obj);
goto exception;
}
if (js_module_set_import_meta(ctx, obj, false, true) < 0) {
JS_FreeValue(ctx, obj);
goto exception;
}
val = JS_EvalFunction(ctx, JS_DupValue(ctx, obj));
val = js_std_await(ctx, val);
if (JS_IsException(val)) {
JS_FreeValue(ctx, obj);
exception:
js_std_dump_error(ctx);
exit(1);
}
JS_FreeValue(ctx, val);
m = JS_VALUE_GET_PTR(obj);
JS_FreeValue(ctx, obj);
return JS_GetModuleNamespace(ctx, m);
}
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
const char *filename, int eval_flags)
{
bool use_realpath;
JSValue val;
int ret;
if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) {
/* for the modules, we compile then run to be able to set
import.meta */
val = JS_Eval(ctx, buf, buf_len, filename,
eval_flags | JS_EVAL_FLAG_COMPILE_ONLY);
if (!JS_IsException(val)) {
// ex. "<cmdline>" pr "/dev/stdin"
use_realpath =
!(*filename == '<' || !strncmp(filename, "/dev/", 5));
if (js_module_set_import_meta(ctx, val, use_realpath, true) < 0) {
js_std_dump_error(ctx);
ret = -1;
goto end;
}
val = JS_EvalFunction(ctx, val);
}
val = js_std_await(ctx, val);
} else {
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
}
if (JS_IsException(val)) {
js_std_dump_error(ctx);
ret = -1;
} else {
ret = 0;
}
end:
JS_FreeValue(ctx, val);
return ret;
}
static int eval_file(JSContext *ctx, const char *filename, int module)
{
uint8_t *buf;
int ret, eval_flags;
size_t buf_len;
buf = js_load_file(ctx, &buf_len, filename);
if (!buf) {
perror(filename);
exit(1);
}
if (module < 0) {
module = (js__has_suffix(filename, ".mjs") ||
JS_DetectModule((const char *)buf, buf_len));
}
if (module)
eval_flags = JS_EVAL_TYPE_MODULE;
else
eval_flags = JS_EVAL_TYPE_GLOBAL;
ret = eval_buf(ctx, buf, buf_len, filename, eval_flags);
js_free(ctx, buf);
return ret;
}
static int64_t parse_limit(const char *arg) {
char *p;
unsigned long unit = 1024; /* default to traditional KB */
double d = strtod(arg, &p);
if (p == arg) {
fprintf(stderr, "Invalid limit: %s\n", arg);
return -1;
}
if (*p) {
switch (*p++) {
case 'b': case 'B': unit = 1UL << 0; break;
case 'k': case 'K': unit = 1UL << 10; break; /* IEC kibibytes */
case 'm': case 'M': unit = 1UL << 20; break; /* IEC mebibytes */
case 'g': case 'G': unit = 1UL << 30; break; /* IEC gigibytes */
default:
fprintf(stderr, "Invalid limit: %s, unrecognized suffix, only k,m,g are allowed\n", arg);
return -1;
}
if (*p) {
fprintf(stderr, "Invalid limit: %s, only one suffix allowed\n", arg);
return -1;
}
}
return (int64_t)(d * unit);
}
static JSValue js_gc(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
JS_RunGC(JS_GetRuntime(ctx));
return JS_UNDEFINED;
}
static JSValue js_navigator_get_userAgent(JSContext *ctx, JSValueConst this_val)
{
char version[32];
snprintf(version, sizeof(version), "quickjs-ng/%s", JS_GetVersion());
return JS_NewString(ctx, version);
}
static const JSCFunctionListEntry navigator_proto_funcs[] = {
JS_CGETSET_DEF2("userAgent", js_navigator_get_userAgent, NULL, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE),
JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Navigator", JS_PROP_CONFIGURABLE),
};
static const JSCFunctionListEntry global_obj[] = {
JS_CFUNC_DEF("gc", 0, js_gc),
};
/* also used to initialize the worker context */
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx;
ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
/* system modules */
js_init_module_std(ctx, "qjs:std");
js_init_module_os(ctx, "qjs:os");
js_init_module_bjson(ctx, "qjs:bjson");
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyFunctionList(ctx, global, global_obj, countof(global_obj));
JSValue args = JS_NewArray(ctx);
int i;
for(i = 0; i < qjs__argc; i++) {
JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, qjs__argv[i]));
}
JS_SetPropertyStr(ctx, global, "execArgv", args);
JS_SetPropertyStr(ctx, global, "argv0", JS_NewString(ctx, qjs__argv[0]));
JSValue navigator_proto = JS_NewObject(ctx);
JS_SetPropertyFunctionList(ctx, navigator_proto, navigator_proto_funcs, countof(navigator_proto_funcs));
JSValue navigator = JS_NewObjectProto(ctx, navigator_proto);
JS_DefinePropertyValueStr(ctx, global, "navigator", navigator, JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE);
JS_FreeValue(ctx, global);
JS_FreeValue(ctx, navigator_proto);
return ctx;
}
struct trace_malloc_data {
uint8_t *base;
};
static inline unsigned long long js_trace_malloc_ptr_offset(uint8_t *ptr,
struct trace_malloc_data *dp)
{
return ptr - dp->base;
}
static void JS_PRINTF_FORMAT_ATTR(2, 3) js_trace_malloc_printf(void *opaque, JS_PRINTF_FORMAT const char *fmt, ...)
{
va_list ap;
int c;
va_start(ap, fmt);
while ((c = *fmt++) != '\0') {
if (c == '%') {
/* only handle %p and %zd */
if (*fmt == 'p') {
uint8_t *ptr = va_arg(ap, void *);
if (ptr == NULL) {
printf("NULL");
} else {
printf("H%+06lld.%zd",
js_trace_malloc_ptr_offset(ptr, opaque),
js__malloc_usable_size(ptr));
}
fmt++;
continue;
}
if (fmt[0] == 'z' && fmt[1] == 'd') {
size_t sz = va_arg(ap, size_t);
printf("%zd", sz);
fmt += 2;
continue;
}
}
putc(c, stdout);
}
va_end(ap);
}
static void js_trace_malloc_init(struct trace_malloc_data *s)
{
free(s->base = malloc(8));
}
static void *js_trace_calloc(void *opaque, size_t count, size_t size)
{
void *ptr;
ptr = calloc(count, size);
js_trace_malloc_printf(opaque, "C %zd %zd -> %p\n", count, size, ptr);
return ptr;
}
static void *js_trace_malloc(void *opaque, size_t size)
{
void *ptr;
ptr = malloc(size);
js_trace_malloc_printf(opaque, "A %zd -> %p\n", size, ptr);
return ptr;
}
static void js_trace_free(void *opaque, void *ptr)
{
if (!ptr)
return;
js_trace_malloc_printf(opaque, "F %p\n", ptr);
free(ptr);
}
static void *js_trace_realloc(void *opaque, void *ptr, size_t size)
{
js_trace_malloc_printf(opaque, "R %zd %p", size, ptr);
ptr = realloc(ptr, size);
js_trace_malloc_printf(opaque, " -> %p\n", ptr);
return ptr;
}
static const JSMallocFunctions trace_mf = {
js_trace_calloc,
js_trace_malloc,
js_trace_free,
js_trace_realloc,
js__malloc_usable_size
};
#ifdef QJS_USE_MIMALLOC
static void *js_mi_calloc(void *opaque, size_t count, size_t size)
{
return mi_calloc(count, size);
}
static void *js_mi_malloc(void *opaque, size_t size)
{
return mi_malloc(size);
}
static void js_mi_free(void *opaque, void *ptr)
{
if (!ptr)
return;
mi_free(ptr);
}
static void *js_mi_realloc(void *opaque, void *ptr, size_t size)
{
return mi_realloc(ptr, size);
}
static const JSMallocFunctions mi_mf = {
js_mi_calloc,
js_mi_malloc,
js_mi_free,
js_mi_realloc,
mi_malloc_usable_size
};
#endif
#define PROG_NAME "qjs"
void help(void)
{
printf("QuickJS-ng version %s\n"
"usage: " PROG_NAME " [options] [file [args]]\n"
"-h --help list options\n"
"-e --eval EXPR evaluate EXPR\n"
"-i --interactive go to interactive mode\n"
"-C --script load as JS classic script (default=autodetect)\n"
"-m --module load as ES module (default=autodetect)\n"
"-I --include file include an additional file\n"
" --std make 'std', 'os' and 'bjson' available to script\n"
"-T --trace trace memory allocation\n"
"-d --dump dump the memory usage stats\n"
"-D --dump-flags flags for dumping debug data (see DUMP_* defines)\n"
"-c --compile FILE compile the given JS file as a standalone executable\n"
"-o --out FILE output file for standalone executables\n"
" --exe select the executable to use as the base, defaults to the current one\n"
" --memory-limit n limit the memory usage to 'n' Kbytes\n"
" --stack-size n limit the stack size to 'n' Kbytes\n"
"-q --quit just instantiate the interpreter and quit\n", JS_GetVersion());
exit(1);
}
int main(int argc, char **argv)
{
JSRuntime *rt;
JSContext *ctx;
JSValue ret = JS_UNDEFINED;
struct trace_malloc_data trace_data = { NULL };
int r = 0;
int optind = 1;
char exebuf[JS__PATH_MAX];
size_t exebuf_size = sizeof(exebuf);
char *compile_file = NULL;
char *exe = NULL;
char *expr = NULL;
char *dump_flags_str = NULL;
char *out = NULL;
int standalone = 0;
int interactive = 0;
int dump_memory = 0;
int dump_flags = 0;
int trace_memory = 0;
int empty_run = 0;
int module = -1;
int load_std = 0;
char *include_list[32];
int i, include_count = 0;
int64_t memory_limit = -1;
int64_t stack_size = -1;
/* save for later */
qjs__argc = argc;
qjs__argv = argv;
/* check if this is a standalone executable */
if (!js_exepath(exebuf, &exebuf_size) && is_standalone(exebuf)) {
standalone = 1;
goto start;
}
dump_flags_str = getenv("QJS_DUMP_FLAGS");
dump_flags = dump_flags_str ? strtol(dump_flags_str, NULL, 16) : 0;
/* cannot use getopt because we want to pass the command line to
the script */
while (optind < argc && *argv[optind] == '-') {
char *arg = argv[optind] + 1;
const char *longopt = "";
char *optarg = NULL;
/* a single - is not an option, it also stops argument scanning */
if (!*arg)
break;
optind++;
if (*arg == '-') {
longopt = arg + 1;
optarg = strchr(longopt, '=');
if (optarg)
*optarg++ = '\0';
arg += strlen(arg);
/* -- stops argument scanning */
if (!*longopt)
break;
}
for (; *arg || *longopt; longopt = "") {
char opt = *arg;
if (opt) {
arg++;
if (!optarg && *arg)
optarg = arg;
}
if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) {
help();
continue;
}
if (opt == 'e' || !strcmp(longopt, "eval")) {
if (!optarg) {
if (optind >= argc) {
fprintf(stderr, "qjs: missing expression for -e\n");
exit(1);
}
optarg = argv[optind++];
}
expr = optarg;
break;
}
if (opt == 'I' || !strcmp(longopt, "include")) {
if (optind >= argc) {
fprintf(stderr, "expecting filename");
exit(1);
}
if (include_count >= countof(include_list)) {
fprintf(stderr, "too many included files");
exit(1);
}
include_list[include_count++] = argv[optind++];
continue;
}
if (opt == 'i' || !strcmp(longopt, "interactive")) {
interactive++;
continue;
}
if (opt == 'm' || !strcmp(longopt, "module")) {
module = 1;
continue;
}
if (opt == 'C' || !strcmp(longopt, "script")) {
module = 0;
continue;
}
if (opt == 'd' || !strcmp(longopt, "dump")) {
dump_memory++;
continue;
}
if (opt == 'D' || !strcmp(longopt, "dump-flags")) {
dump_flags = optarg ? strtol(optarg, NULL, 16) : 0;
break;
}
if (opt == 'T' || !strcmp(longopt, "trace")) {
trace_memory++;
continue;
}
if (!strcmp(longopt, "std")) {
load_std = 1;
continue;
}
if (opt == 'q' || !strcmp(longopt, "quit")) {
empty_run++;
continue;
}
if (!strcmp(longopt, "memory-limit")) {
if (!optarg) {
if (optind >= argc) {
fprintf(stderr, "expecting memory limit");
exit(1);
}
optarg = argv[optind++];
}
memory_limit = parse_limit(optarg);
break;
}
if (!strcmp(longopt, "stack-size")) {
if (!optarg) {
if (optind >= argc) {
fprintf(stderr, "expecting stack size");
exit(1);
}
optarg = argv[optind++];
}
stack_size = parse_limit(optarg);
break;
}
if (opt == 'c' || !strcmp(longopt, "compile")) {
if (!optarg) {
if (optind >= argc) {
fprintf(stderr, "qjs: missing file for -c\n");
exit(1);
}
optarg = argv[optind++];
}
compile_file = optarg;
break;
}
if (opt == 'o' || !strcmp(longopt, "out")) {
if (!optarg) {
if (optind >= argc) {
fprintf(stderr, "qjs: missing file for -o\n");
exit(1);
}
optarg = argv[optind++];
}
out = optarg;
break;
}
if (!strcmp(longopt, "exe")) {
if (!optarg) {
if (optind >= argc) {
fprintf(stderr, "qjs: missing file for --exe\n");
exit(1);
}
optarg = argv[optind++];
}
exe = optarg;
break;
}
if (opt) {
fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
} else {
fprintf(stderr, "qjs: unknown option '--%s'\n", longopt);
}
help();
}
}
if (compile_file && !out)
help();
start:
if (trace_memory) {
js_trace_malloc_init(&trace_data);
rt = JS_NewRuntime2(&trace_mf, &trace_data);
} else {
#ifdef QJS_USE_MIMALLOC
rt = JS_NewRuntime2(&mi_mf, NULL);
#else
rt = JS_NewRuntime();
#endif
}
if (!rt) {
fprintf(stderr, "qjs: cannot allocate JS runtime\n");
exit(2);
}
if (memory_limit >= 0)
JS_SetMemoryLimit(rt, (size_t)memory_limit);
if (stack_size >= 0)
JS_SetMaxStackSize(rt, (size_t)stack_size);
if (dump_flags != 0)
JS_SetDumpFlags(rt, dump_flags);
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
ctx = JS_NewCustomContext(rt);
if (!ctx) {
fprintf(stderr, "qjs: cannot allocate JS context\n");
exit(2);
}
/* loader for ES6 modules */
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
/* exit on unhandled promise rejections */
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker, NULL);
if (!empty_run) {
js_std_add_helpers(ctx, argc - optind, argv + optind);
/* make 'std' and 'os' visible to non module code */
if (load_std) {
const char *str =
"import * as bjson from 'qjs:bjson';\n"
"import * as std from 'qjs:std';\n"
"import * as os from 'qjs:os';\n"
"globalThis.bjson = bjson;\n"
"globalThis.std = std;\n"
"globalThis.os = os;\n";
eval_buf(ctx, str, strlen(str), "<input>", JS_EVAL_TYPE_MODULE);
}
for(i = 0; i < include_count; i++) {
if (eval_file(ctx, include_list[i], 0))
goto fail;
}
if (standalone) {
JSValue ns = load_standalone_module(ctx);
if (JS_IsException(ns))
goto fail;
JSValue func = JS_GetPropertyStr(ctx, ns, "runStandalone");
JS_FreeValue(ctx, ns);
if (JS_IsException(func))
goto fail;
ret = JS_Call(ctx, func, JS_UNDEFINED, 0, NULL);
JS_FreeValue(ctx, func);
} else if (compile_file) {
JSValue ns = load_standalone_module(ctx);
if (JS_IsException(ns))
goto fail;
JSValue func = JS_GetPropertyStr(ctx, ns, "compileStandalone");
JS_FreeValue(ctx, ns);
if (JS_IsException(func))
goto fail;
JSValue args[3];
args[0] = JS_NewString(ctx, compile_file);
args[1] = JS_NewString(ctx, out);
args[2] = exe != NULL ? JS_NewString(ctx, exe) : JS_UNDEFINED;
ret = JS_Call(ctx, func, JS_UNDEFINED, 3, (JSValueConst *)args);
JS_FreeValue(ctx, func);
JS_FreeValue(ctx, args[0]);
JS_FreeValue(ctx, args[1]);
JS_FreeValue(ctx, args[2]);
} else if (expr) {
int flags = module ? JS_EVAL_TYPE_MODULE : 0;
if (eval_buf(ctx, expr, strlen(expr), "<cmdline>", flags))
goto fail;
} else if (optind >= argc) {
/* interactive mode */
interactive = 1;
} else {
const char *filename;
filename = argv[optind];
if (eval_file(ctx, filename, module))
goto fail;
}
if (interactive) {
JS_SetHostPromiseRejectionTracker(rt, NULL, NULL);
js_std_eval_binary(ctx, qjsc_repl, qjsc_repl_size, 0);
}
if (standalone || compile_file) {
if (JS_IsException(ret)) {
r = 1;
} else {
JS_FreeValue(ctx, ret);
r = js_std_loop(ctx);
}
} else {
r = js_std_loop(ctx);
}
if (r) {
js_std_dump_error(ctx);
goto fail;
}
}
if (dump_memory) {
JSMemoryUsage stats;
JS_ComputeMemoryUsage(rt, &stats);
JS_DumpMemoryUsage(stdout, &stats, rt);
}
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
if (empty_run && dump_memory) {
clock_t t[5];
double best[5] = {0};
int i, j;
for (i = 0; i < 100; i++) {
t[0] = clock();
rt = JS_NewRuntime();
t[1] = clock();
ctx = JS_NewContext(rt);
t[2] = clock();
JS_FreeContext(ctx);
t[3] = clock();
JS_FreeRuntime(rt);
t[4] = clock();
for (j = 4; j > 0; j--) {
double ms = 1000.0 * (t[j] - t[j - 1]) / CLOCKS_PER_SEC;
if (i == 0 || best[j] > ms)
best[j] = ms;
}
}
printf("\nInstantiation times (ms): %.3f = %.3f+%.3f+%.3f+%.3f\n",
best[1] + best[2] + best[3] + best[4],
best[1], best[2], best[3], best[4]);
}
return 0;
fail:
js_std_free_handlers(rt);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return 1;
}
+673
View File
@@ -0,0 +1,673 @@
/*
* QuickJS command line compiler
*
* Copyright (c) 2018-2024 Fabrice Bellard
* Copyright (c) 2023-2025 Ben Noordhuis
* Copyright (c) 2023-2025 Saúl Ibarra Corretgé
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include "cutils.h"
#include "quickjs-libc.h"
typedef enum {
OUTPUT_C,
OUTPUT_C_MAIN,
OUTPUT_RAW,
} OutputTypeEnum;
typedef struct {
char *name;
char *short_name;
int flags;
} namelist_entry_t;
typedef struct namelist_t {
namelist_entry_t *array;
int count;
int size;
} namelist_t;
static namelist_t cname_list;
static namelist_t cmodule_list;
static namelist_t init_module_list;
static OutputTypeEnum output_type;
static FILE *outfile;
static const char *c_ident_prefix = "qjsc_";
static int strip;
void namelist_add(namelist_t *lp, const char *name, const char *short_name,
int flags)
{
namelist_entry_t *e;
if (lp->count == lp->size) {
size_t newsize = lp->size + (lp->size >> 1) + 4;
namelist_entry_t *a =
realloc(lp->array, sizeof(lp->array[0]) * newsize);
/* XXX: check for realloc failure */
lp->array = a;
lp->size = newsize;
}
e = &lp->array[lp->count++];
e->name = strdup(name);
if (short_name)
e->short_name = strdup(short_name);
else
e->short_name = NULL;
e->flags = flags;
}
void namelist_free(namelist_t *lp)
{
while (lp->count > 0) {
namelist_entry_t *e = &lp->array[--lp->count];
free(e->name);
free(e->short_name);
}
free(lp->array);
lp->array = NULL;
lp->size = 0;
}
namelist_entry_t *namelist_find(namelist_t *lp, const char *name)
{
int i;
for(i = 0; i < lp->count; i++) {
namelist_entry_t *e = &lp->array[i];
if (!strcmp(e->name, name))
return e;
}
return NULL;
}
static void get_c_name(char *buf, size_t buf_size, const char *file)
{
const char *p, *r;
size_t len, i;
int c;
char *q;
p = strrchr(file, '/');
if (!p)
p = file;
else
p++;
r = strrchr(p, '.');
if (!r)
len = strlen(p);
else
len = r - p;
js__pstrcpy(buf, buf_size, c_ident_prefix);
q = buf + strlen(buf);
for(i = 0; i < len; i++) {
c = p[i];
if (!((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z'))) {
c = '_';
}
if ((q - buf) < buf_size - 1)
*q++ = c;
}
*q = '\0';
}
static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
{
size_t i, col;
col = 0;
for(i = 0; i < len; i++) {
fprintf(f, " 0x%02x,", buf[i]);
if (++col == 8) {
fprintf(f, "\n");
col = 0;
}
}
if (col != 0)
fprintf(f, "\n");
}
static void output_object_code(JSContext *ctx,
FILE *fo, JSValue obj, const char *c_name,
bool load_only)
{
uint8_t *out_buf;
size_t out_buf_len;
int flags = JS_WRITE_OBJ_BYTECODE;
if (strip) {
flags |= JS_WRITE_OBJ_STRIP_SOURCE;
if (strip > 1)
flags |= JS_WRITE_OBJ_STRIP_DEBUG;
}
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
if (!out_buf) {
js_std_dump_error(ctx);
exit(1);
}
namelist_add(&cname_list, c_name, NULL, load_only);
if (output_type == OUTPUT_RAW) {
fwrite(out_buf, 1, out_buf_len, fo);
} else {
fprintf(fo, "const uint32_t %s_size = %u;\n\n",
c_name, (unsigned int)out_buf_len);
fprintf(fo, "const uint8_t %s[%u] = {\n",
c_name, (unsigned int)out_buf_len);
dump_hex(fo, out_buf, out_buf_len);
fprintf(fo, "};\n\n");
}
js_free(ctx, out_buf);
}
static int js_module_dummy_init(JSContext *ctx, JSModuleDef *m)
{
/* should never be called when compiling JS code */
abort();
return -1; // pacify compiler
}
static void find_unique_cname(char *cname, size_t cname_size)
{
char cname1[1024];
int suffix_num;
size_t len, max_len;
assert(cname_size >= 32);
/* find a C name not matching an existing module C name by
adding a numeric suffix */
len = strlen(cname);
max_len = cname_size - 16;
if (len > max_len)
cname[max_len] = '\0';
suffix_num = 1;
for(;;) {
snprintf(cname1, sizeof(cname1), "%s_%d", cname, suffix_num);
if (!namelist_find(&cname_list, cname1))
break;
suffix_num++;
}
js__pstrcpy(cname, cname_size, cname1);
}
JSModuleDef *jsc_module_loader(JSContext *ctx,
const char *module_name, void *opaque)
{
JSModuleDef *m;
namelist_entry_t *e;
/* check if it is a declared C or system module */
e = namelist_find(&cmodule_list, module_name);
if (e) {
/* add in the static init module list */
namelist_add(&init_module_list, e->name, e->short_name, 0);
/* create a dummy module */
m = JS_NewCModule(ctx, module_name, js_module_dummy_init);
} else if (js__has_suffix(module_name, ".so")) {
JS_ThrowReferenceError(ctx, "%s: dynamically linking to shared libraries not supported",
module_name);
return NULL;
} else {
size_t buf_len;
uint8_t *buf;
JSValue func_val;
char cname[1000];
buf = js_load_file(ctx, &buf_len, module_name);
if (!buf) {
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
module_name);
return NULL;
}
/* compile the module */
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
js_free(ctx, buf);
if (JS_IsException(func_val))
return NULL;
get_c_name(cname, sizeof(cname), module_name);
if (namelist_find(&cname_list, cname)) {
find_unique_cname(cname, sizeof(cname));
}
output_object_code(ctx, outfile, func_val, cname, true);
/* the module is already referenced, so we must free it */
m = JS_VALUE_GET_PTR(func_val);
JS_FreeValue(ctx, func_val);
}
return m;
}
static void compile_file(JSContext *ctx, FILE *fo,
const char *filename,
const char *script_name,
const char *c_name1,
int module)
{
uint8_t *buf;
char c_name[1024];
int eval_flags;
JSValue obj;
size_t buf_len;
buf = js_load_file(ctx, &buf_len, filename);
if (!buf) {
fprintf(stderr, "Could not load '%s'\n", filename);
exit(1);
}
eval_flags = JS_EVAL_FLAG_COMPILE_ONLY;
if (module < 0) {
module = (js__has_suffix(filename, ".mjs") ||
JS_DetectModule((const char *)buf, buf_len));
}
if (module)
eval_flags |= JS_EVAL_TYPE_MODULE;
else
eval_flags |= JS_EVAL_TYPE_GLOBAL;
obj = JS_Eval(ctx, (const char *)buf, buf_len, script_name ? script_name : filename, eval_flags);
if (JS_IsException(obj)) {
js_std_dump_error(ctx);
exit(1);
}
js_free(ctx, buf);
if (c_name1) {
js__pstrcpy(c_name, sizeof(c_name), c_name1);
} else {
get_c_name(c_name, sizeof(c_name), filename);
}
output_object_code(ctx, fo, obj, c_name, false);
JS_FreeValue(ctx, obj);
}
static const char main_c_template1[] =
"int main(int argc, char **argv)\n"
"{\n"
" int r;\n"
" JSRuntime *rt;\n"
" JSContext *ctx;\n"
" r = 0;\n"
" rt = JS_NewRuntime();\n"
" js_std_set_worker_new_context_func(JS_NewCustomContext);\n"
" js_std_init_handlers(rt);\n"
;
static const char main_c_template2[] =
" r = js_std_loop(ctx);\n"
" if (r) {\n"
" js_std_dump_error(ctx);\n"
" }\n"
" js_std_free_handlers(rt);\n"
" JS_FreeContext(ctx);\n"
" JS_FreeRuntime(rt);\n"
" return r;\n"
"}\n";
#define PROG_NAME "qjsc"
void help(void)
{
printf("QuickJS-ng Compiler version %s\n"
"usage: " PROG_NAME " [options] [files]\n"
"\n"
"options are:\n"
"-b output raw bytecode instead of C code\n"
"-e output main() and bytecode in a C file\n"
"-o output set the output filename\n"
"-n script_name set the script name (as used in stack traces)\n"
"-N cname set the C name of the generated data\n"
"-C compile as JS classic script (default=autodetect)\n"
"-m compile as ES module (default=autodetect)\n"
"-D module_name compile a dynamically loaded module or worker\n"
"-M module_name[,cname] add initialization code for an external C module\n"
"-p prefix set the prefix of the generated C names\n"
"-P do not add default system modules\n"
"-s strip the source code, specify twice to also strip debug info\n"
"-S n set the maximum stack size to 'n' bytes (default=%d)\n",
JS_GetVersion(),
JS_DEFAULT_STACK_SIZE);
exit(1);
}
// TODO(bnoordhuis) share with qjs.c maybe
static int64_t parse_limit(const char *arg) {
char *p;
unsigned long unit = 1; // bytes for backcompat; qjs defaults to kilobytes
double d = strtod(arg, &p);
if (p == arg) {
fprintf(stderr, "qjsc: invalid limit: %s\n", arg);
return -1;
}
if (*p) {
switch (*p++) {
case 'b': case 'B': unit = 1UL << 0; break;
case 'k': case 'K': unit = 1UL << 10; break; /* IEC kibibytes */
case 'm': case 'M': unit = 1UL << 20; break; /* IEC mebibytes */
case 'g': case 'G': unit = 1UL << 30; break; /* IEC gigibytes */
default:
fprintf(stderr, "qjsc: invalid limit: %s, unrecognized suffix, only k,m,g are allowed\n", arg);
return -1;
}
if (*p) {
fprintf(stderr, "qjsc: invalid limit: %s, only one suffix allowed\n", arg);
return -1;
}
}
return (int64_t)(d * unit);
}
static void check_hasarg(int optind, int argc, int opt)
{
if (optind >= argc) {
fprintf(stderr, "qjsc: missing file for -%c\n", opt);
exit(1);
}
}
int main(int argc, char **argv)
{
int optind = 1;
int i;
const char *out_filename, *cname, *script_name;
char cfilename[1024];
FILE *fo;
JSRuntime *rt;
JSContext *ctx;
int module;
size_t stack_size;
namelist_t dynamic_module_list;
bool load_system_modules = true;
out_filename = NULL;
script_name = NULL;
output_type = OUTPUT_C;
cname = NULL;
module = -1;
strip = 0;
stack_size = 0;
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
while (optind < argc && *argv[optind] == '-') {
char *arg = argv[optind] + 1;
const char *longopt = "";
char *optarg = NULL;
/* a single - is not an option, it also stops argument scanning */
if (!*arg)
break;
optind++;
if (*arg == '-') {
longopt = arg + 1;
optarg = strchr(longopt, '=');
if (optarg)
*optarg++ = '\0';
arg += strlen(arg);
/* -- stops argument scanning */
if (!*longopt)
break;
}
for (; *arg || *longopt; longopt = "") {
char opt = *arg;
if (opt) {
arg++;
if (!optarg && *arg)
optarg = arg;
}
if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) {
help();
continue;
}
if (opt == 'b') {
output_type = OUTPUT_RAW;
continue;
}
if (opt == 'o') {
if (!optarg) {
check_hasarg(optind, argc, opt);
optarg = argv[optind++];
}
out_filename = optarg;
continue;
}
if (opt == 'e') {
output_type = OUTPUT_C_MAIN;
continue;
}
if (opt == 'n') {
if (!optarg) {
check_hasarg(optind, argc, opt);
optarg = argv[optind++];
}
script_name = optarg;
continue;
}
if (opt == 'N') {
if (!optarg) {
check_hasarg(optind, argc, opt);
optarg = argv[optind++];
}
cname = optarg;
continue;
}
if (opt == 'C') {
module = 0;
continue;
}
if (opt == 'm') {
module = 1;
continue;
}
if (opt == 'M') {
char *p;
char path[1024];
char cname[1024];
if (!optarg) {
check_hasarg(optind, argc, opt);
optarg = argv[optind++];
}
js__pstrcpy(path, sizeof(path), optarg);
p = strchr(path, ',');
if (p) {
*p = '\0';
js__pstrcpy(cname, sizeof(cname), p + 1);
} else {
get_c_name(cname, sizeof(cname), path);
}
namelist_add(&cmodule_list, path, cname, 0);
continue;
}
if (opt == 'D') {
if (!optarg) {
check_hasarg(optind, argc, opt);
optarg = argv[optind++];
}
namelist_add(&dynamic_module_list, optarg, NULL, 0);
continue;
}
if (opt == 'P') {
load_system_modules = false;
continue;
}
if (opt == 's') {
strip++;
continue;
}
if (opt == 'p') {
if (!optarg) {
check_hasarg(optind, argc, opt);
optarg = argv[optind++];
}
c_ident_prefix = optarg;
continue;
}
if (opt == 'S') {
if (!optarg) {
check_hasarg(optind, argc, opt);
optarg = argv[optind++];
}
stack_size = parse_limit(optarg);
continue;
}
help();
}
}
if (load_system_modules) {
/* add system modules */
namelist_add(&cmodule_list, "qjs:std", "std", 0);
namelist_add(&cmodule_list, "qjs:os", "os", 0);
namelist_add(&cmodule_list, "qjs:bjson", "bjson", 0);
namelist_add(&cmodule_list, "std", "std", 0);
namelist_add(&cmodule_list, "os", "os", 0);
namelist_add(&cmodule_list, "bjson", "bjson", 0);
}
if (optind >= argc)
help();
if (!out_filename)
out_filename = "out.c";
js__pstrcpy(cfilename, sizeof(cfilename), out_filename);
if (output_type == OUTPUT_RAW)
fo = fopen(cfilename, "wb");
else
fo = fopen(cfilename, "w");
if (!fo) {
perror(cfilename);
exit(1);
}
outfile = fo;
rt = JS_NewRuntime();
ctx = JS_NewContext(rt);
/* loader for ES6 modules */
JS_SetModuleLoaderFunc(rt, NULL, jsc_module_loader, NULL);
if (output_type != OUTPUT_RAW) {
fprintf(fo, "/* File generated automatically by the QuickJS-ng compiler. */\n"
"\n"
);
}
if (output_type == OUTPUT_C_MAIN) {
fprintf(fo, "#include \"quickjs-libc.h\"\n"
"\n"
);
} else if (output_type == OUTPUT_C) {
fprintf(fo, "#include <inttypes.h>\n"
"\n"
);
}
for(i = optind; i < argc; i++) {
const char *filename = argv[i];
compile_file(ctx, fo, filename, script_name, cname, module);
cname = NULL;
}
for(i = 0; i < dynamic_module_list.count; i++) {
if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
fprintf(stderr, "Could not load dynamic module '%s'\n",
dynamic_module_list.array[i].name);
exit(1);
}
}
if (output_type == OUTPUT_C_MAIN) {
fprintf(fo,
"static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
"{\n"
" JSContext *ctx = JS_NewContext(rt);\n"
" if (!ctx)\n"
" return NULL;\n");
/* add the precompiled modules (XXX: could modify the module
loader instead) */
for(i = 0; i < init_module_list.count; i++) {
namelist_entry_t *e = &init_module_list.array[i];
/* initialize the static C modules */
fprintf(fo,
" {\n"
" extern JSModuleDef *js_init_module_%s(JSContext *ctx, const char *name);\n"
" js_init_module_%s(ctx, \"%s\");\n"
" }\n",
e->short_name, e->short_name, e->name);
}
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
if (e->flags) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n",
e->name, e->name);
}
}
fprintf(fo,
" return ctx;\n"
"}\n\n");
fputs(main_c_template1, fo);
if (stack_size != 0) {
fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
(unsigned int)stack_size);
}
/* add the module loader */
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
fprintf(fo,
" ctx = JS_NewCustomContext(rt);\n"
" js_std_add_helpers(ctx, argc, argv);\n");
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
if (!e->flags) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n",
e->name, e->name);
}
}
fputs(main_c_template2, fo);
}
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
fclose(fo);
namelist_free(&cname_list);
namelist_free(&cmodule_list);
namelist_free(&init_module_list);
return 0;
}
@@ -0,0 +1,265 @@
/*
* QuickJS atom definitions
*
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef DEF
/* Note: first atoms are considered as keywords in the parser */
DEF(null, "null") /* must be first */
DEF(false, "false")
DEF(true, "true")
DEF(if, "if")
DEF(else, "else")
DEF(return, "return")
DEF(var, "var")
DEF(this, "this")
DEF(delete, "delete")
DEF(void, "void")
DEF(typeof, "typeof")
DEF(new, "new")
DEF(in, "in")
DEF(instanceof, "instanceof")
DEF(do, "do")
DEF(while, "while")
DEF(for, "for")
DEF(break, "break")
DEF(continue, "continue")
DEF(switch, "switch")
DEF(case, "case")
DEF(default, "default")
DEF(throw, "throw")
DEF(try, "try")
DEF(catch, "catch")
DEF(finally, "finally")
DEF(function, "function")
DEF(debugger, "debugger")
DEF(with, "with")
/* FutureReservedWord */
DEF(class, "class")
DEF(const, "const")
DEF(enum, "enum")
DEF(export, "export")
DEF(extends, "extends")
DEF(import, "import")
DEF(super, "super")
/* FutureReservedWords when parsing strict mode code */
DEF(implements, "implements")
DEF(interface, "interface")
DEF(let, "let")
DEF(package, "package")
DEF(private, "private")
DEF(protected, "protected")
DEF(public, "public")
DEF(static, "static")
DEF(yield, "yield")
DEF(await, "await")
/* empty string */
DEF(empty_string, "")
/* identifiers */
DEF(keys, "keys")
DEF(size, "size")
DEF(length, "length")
DEF(message, "message")
DEF(cause, "cause")
DEF(errors, "errors")
DEF(stack, "stack")
DEF(name, "name")
DEF(toString, "toString")
DEF(toLocaleString, "toLocaleString")
DEF(valueOf, "valueOf")
DEF(eval, "eval")
DEF(prototype, "prototype")
DEF(constructor, "constructor")
DEF(configurable, "configurable")
DEF(writable, "writable")
DEF(enumerable, "enumerable")
DEF(value, "value")
DEF(get, "get")
DEF(set, "set")
DEF(of, "of")
DEF(__proto__, "__proto__")
DEF(undefined, "undefined")
DEF(number, "number")
DEF(boolean, "boolean")
DEF(string, "string")
DEF(object, "object")
DEF(symbol, "symbol")
DEF(integer, "integer")
DEF(unknown, "unknown")
DEF(arguments, "arguments")
DEF(callee, "callee")
DEF(caller, "caller")
DEF(_eval_, "<eval>")
DEF(_ret_, "<ret>")
DEF(_var_, "<var>")
DEF(_arg_var_, "<arg_var>")
DEF(_with_, "<with>")
DEF(lastIndex, "lastIndex")
DEF(target, "target")
DEF(index, "index")
DEF(input, "input")
DEF(defineProperties, "defineProperties")
DEF(apply, "apply")
DEF(join, "join")
DEF(concat, "concat")
DEF(split, "split")
DEF(construct, "construct")
DEF(getPrototypeOf, "getPrototypeOf")
DEF(setPrototypeOf, "setPrototypeOf")
DEF(isExtensible, "isExtensible")
DEF(preventExtensions, "preventExtensions")
DEF(has, "has")
DEF(deleteProperty, "deleteProperty")
DEF(defineProperty, "defineProperty")
DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor")
DEF(ownKeys, "ownKeys")
DEF(add, "add")
DEF(done, "done")
DEF(next, "next")
DEF(values, "values")
DEF(source, "source")
DEF(flags, "flags")
DEF(global, "global")
DEF(unicode, "unicode")
DEF(raw, "raw")
DEF(new_target, "new.target")
DEF(this_active_func, "this.active_func")
DEF(home_object, "<home_object>")
DEF(computed_field, "<computed_field>")
DEF(static_computed_field, "<static_computed_field>") /* must come after computed_fields */
DEF(class_fields_init, "<class_fields_init>")
DEF(brand, "<brand>")
DEF(hash_constructor, "#constructor")
DEF(as, "as")
DEF(from, "from")
DEF(fromAsync, "fromAsync")
DEF(meta, "meta")
DEF(_default_, "*default*")
DEF(_star_, "*")
DEF(Module, "Module")
DEF(then, "then")
DEF(resolve, "resolve")
DEF(reject, "reject")
DEF(promise, "promise")
DEF(proxy, "proxy")
DEF(revoke, "revoke")
DEF(async, "async")
DEF(exec, "exec")
DEF(groups, "groups")
DEF(indices, "indices")
DEF(status, "status")
DEF(reason, "reason")
DEF(globalThis, "globalThis")
DEF(bigint, "bigint")
DEF(not_equal, "not-equal")
DEF(timed_out, "timed-out")
DEF(ok, "ok")
DEF(toJSON, "toJSON")
DEF(maxByteLength, "maxByteLength")
/* class names */
DEF(Object, "Object")
DEF(Array, "Array")
DEF(Error, "Error")
DEF(Number, "Number")
DEF(String, "String")
DEF(Boolean, "Boolean")
DEF(Symbol, "Symbol")
DEF(Arguments, "Arguments")
DEF(Math, "Math")
DEF(JSON, "JSON")
DEF(Date, "Date")
DEF(Function, "Function")
DEF(GeneratorFunction, "GeneratorFunction")
DEF(ForInIterator, "ForInIterator")
DEF(RegExp, "RegExp")
DEF(ArrayBuffer, "ArrayBuffer")
DEF(SharedArrayBuffer, "SharedArrayBuffer")
/* must keep same order as class IDs for typed arrays */
DEF(Uint8ClampedArray, "Uint8ClampedArray")
DEF(Int8Array, "Int8Array")
DEF(Uint8Array, "Uint8Array")
DEF(Int16Array, "Int16Array")
DEF(Uint16Array, "Uint16Array")
DEF(Int32Array, "Int32Array")
DEF(Uint32Array, "Uint32Array")
DEF(BigInt64Array, "BigInt64Array")
DEF(BigUint64Array, "BigUint64Array")
DEF(Float16Array, "Float16Array")
DEF(Float32Array, "Float32Array")
DEF(Float64Array, "Float64Array")
DEF(DataView, "DataView")
DEF(BigInt, "BigInt")
DEF(WeakRef, "WeakRef")
DEF(FinalizationRegistry, "FinalizationRegistry")
DEF(Map, "Map")
DEF(Set, "Set") /* Map + 1 */
DEF(WeakMap, "WeakMap") /* Map + 2 */
DEF(WeakSet, "WeakSet") /* Map + 3 */
DEF(Iterator, "Iterator")
DEF(IteratorConcat, "Iterator Concat")
DEF(IteratorHelper, "Iterator Helper")
DEF(IteratorWrap, "Iterator Wrap")
DEF(Map_Iterator, "Map Iterator")
DEF(Set_Iterator, "Set Iterator")
DEF(Array_Iterator, "Array Iterator")
DEF(String_Iterator, "String Iterator")
DEF(RegExp_String_Iterator, "RegExp String Iterator")
DEF(Generator, "Generator")
DEF(Proxy, "Proxy")
DEF(Promise, "Promise")
DEF(PromiseResolveFunction, "PromiseResolveFunction")
DEF(PromiseRejectFunction, "PromiseRejectFunction")
DEF(AsyncFunction, "AsyncFunction")
DEF(AsyncFunctionResolve, "AsyncFunctionResolve")
DEF(AsyncFunctionReject, "AsyncFunctionReject")
DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction")
DEF(AsyncGenerator, "AsyncGenerator")
DEF(EvalError, "EvalError")
DEF(RangeError, "RangeError")
DEF(ReferenceError, "ReferenceError")
DEF(SyntaxError, "SyntaxError")
DEF(TypeError, "TypeError")
DEF(URIError, "URIError")
DEF(InternalError, "InternalError")
DEF(DOMException, "DOMException")
DEF(CallSite, "CallSite")
/* private symbols */
DEF(Private_brand, "<brand>")
/* symbols */
DEF(Symbol_toPrimitive, "Symbol.toPrimitive")
DEF(Symbol_iterator, "Symbol.iterator")
DEF(Symbol_match, "Symbol.match")
DEF(Symbol_matchAll, "Symbol.matchAll")
DEF(Symbol_replace, "Symbol.replace")
DEF(Symbol_search, "Symbol.search")
DEF(Symbol_split, "Symbol.split")
DEF(Symbol_toStringTag, "Symbol.toStringTag")
DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable")
DEF(Symbol_hasInstance, "Symbol.hasInstance")
DEF(Symbol_species, "Symbol.species")
DEF(Symbol_unscopables, "Symbol.unscopables")
DEF(Symbol_asyncIterator, "Symbol.asyncIterator")
#endif /* DEF */
@@ -0,0 +1,54 @@
/*
* QuickJS C atomics definitions
*
* Copyright (c) 2023 Marcin Kolny
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__)
// Use GCC builtins for version < 4.9
# if((__GNUC__ << 16) + __GNUC_MINOR__ < ((4) << 16) + 9)
# define GCC_BUILTIN_ATOMICS
# endif
#endif
#ifdef GCC_BUILTIN_ATOMICS
#define atomic_fetch_add(obj, arg) \
__atomic_fetch_add(obj, arg, __ATOMIC_SEQ_CST)
#define atomic_compare_exchange_strong(obj, expected, desired) \
__atomic_compare_exchange_n(obj, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#define atomic_exchange(obj, desired) \
__atomic_exchange_n (obj, desired, __ATOMIC_SEQ_CST)
#define atomic_load(obj) \
__atomic_load_n(obj, __ATOMIC_SEQ_CST)
#define atomic_store(obj, desired) \
__atomic_store_n(obj, desired, __ATOMIC_SEQ_CST)
#define atomic_fetch_or(obj, arg) \
__atomic_fetch_or(obj, arg, __ATOMIC_SEQ_CST)
#define atomic_fetch_xor(obj, arg) \
__atomic_fetch_xor(obj, arg, __ATOMIC_SEQ_CST)
#define atomic_fetch_and(obj, arg) \
__atomic_fetch_and(obj, arg, __ATOMIC_SEQ_CST)
#define atomic_fetch_sub(obj, arg) \
__atomic_fetch_sub(obj, arg, __ATOMIC_SEQ_CST)
#define _Atomic
#else
#include <stdatomic.h>
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,81 @@
/*
* QuickJS C library
*
* Copyright (c) 2017-2018 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QUICKJS_LIBC_H
#define QUICKJS_LIBC_H
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "quickjs.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__GNUC__) || defined(__clang__)
#define JS_EXTERN __attribute__((visibility("default")))
#else
#define JS_EXTERN /* nothing */
#endif
JS_EXTERN JSModuleDef *js_init_module_std(JSContext *ctx,
const char *module_name);
JS_EXTERN JSModuleDef *js_init_module_os(JSContext *ctx,
const char *module_name);
JS_EXTERN JSModuleDef *js_init_module_bjson(JSContext *ctx,
const char *module_name);
JS_EXTERN void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
JS_EXTERN int js_std_loop(JSContext *ctx);
JS_EXTERN JSValue js_std_await(JSContext *ctx, JSValue obj);
JS_EXTERN void js_std_init_handlers(JSRuntime *rt);
JS_EXTERN void js_std_free_handlers(JSRuntime *rt);
JS_EXTERN void js_std_dump_error(JSContext *ctx);
JS_EXTERN uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len,
const char *filename);
JS_EXTERN int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
bool use_realpath, bool is_main);
JS_EXTERN JSModuleDef *js_module_loader(JSContext *ctx,
const char *module_name, void *opaque);
JS_EXTERN void js_std_eval_binary(JSContext *ctx, const uint8_t *buf,
size_t buf_len, int flags);
JS_EXTERN void js_std_promise_rejection_tracker(JSContext *ctx,
JSValueConst promise,
JSValueConst reason,
bool is_handled,
void *opaque);
// Defaults to JS_NewRuntime, no-op if compiled without worker support.
// Call before creating the first worker thread.
JS_EXTERN void js_std_set_worker_new_runtime_func(JSRuntime *(*func)(void));
// Defaults to JS_NewContext, no-op if compiled without worker support.
// Call before creating the first worker thread.
JS_EXTERN void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
#undef JS_EXTERN
#ifdef __cplusplus
} /* extern "C" { */
#endif
#endif /* QUICKJS_LIBC_H */
@@ -0,0 +1,371 @@
/*
* QuickJS opcode definitions
*
* Copyright (c) 2017-2018 Fabrice Bellard
* Copyright (c) 2017-2018 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifdef FMT
FMT(none)
FMT(none_int)
FMT(none_loc)
FMT(none_arg)
FMT(none_var_ref)
FMT(u8)
FMT(i8)
FMT(loc8)
FMT(const8)
FMT(label8)
FMT(u16)
FMT(i16)
FMT(label16)
FMT(npop)
FMT(npopx)
FMT(npop_u16)
FMT(loc)
FMT(arg)
FMT(var_ref)
FMT(u32)
FMT(u32x2)
FMT(i32)
FMT(const)
FMT(label)
FMT(atom)
FMT(atom_u8)
FMT(atom_u16)
FMT(atom_label_u8)
FMT(atom_label_u16)
FMT(label_u16)
#undef FMT
#endif /* FMT */
#ifdef DEF
#ifndef def
#define def(id, size, n_pop, n_push, f) DEF(id, size, n_pop, n_push, f)
#endif
DEF(invalid, 1, 0, 0, none) /* never emitted */
/* push values */
DEF( push_i32, 5, 0, 1, i32)
DEF( push_const, 5, 0, 1, const)
DEF( fclosure, 5, 0, 1, const) /* must follow push_const */
DEF(push_atom_value, 5, 0, 1, atom)
DEF( private_symbol, 5, 0, 1, atom)
DEF( undefined, 1, 0, 1, none)
DEF( null, 1, 0, 1, none)
DEF( push_this, 1, 0, 1, none) /* only used at the start of a function */
DEF( push_false, 1, 0, 1, none)
DEF( push_true, 1, 0, 1, none)
DEF( object, 1, 0, 1, none)
DEF( special_object, 2, 0, 1, u8) /* only used at the start of a function */
DEF( rest, 3, 0, 1, u16) /* only used at the start of a function */
DEF( drop, 1, 1, 0, none) /* a -> */
DEF( nip, 1, 2, 1, none) /* a b -> b */
DEF( nip1, 1, 3, 2, none) /* a b c -> b c */
DEF( dup, 1, 1, 2, none) /* a -> a a */
DEF( dup1, 1, 2, 3, none) /* a b -> a a b */
DEF( dup2, 1, 2, 4, none) /* a b -> a b a b */
DEF( dup3, 1, 3, 6, none) /* a b c -> a b c a b c */
DEF( insert2, 1, 2, 3, none) /* obj a -> a obj a (dup_x1) */
DEF( insert3, 1, 3, 4, none) /* obj prop a -> a obj prop a (dup_x2) */
DEF( insert4, 1, 4, 5, none) /* this obj prop a -> a this obj prop a */
DEF( perm3, 1, 3, 3, none) /* obj a b -> a obj b */
DEF( perm4, 1, 4, 4, none) /* obj prop a b -> a obj prop b */
DEF( perm5, 1, 5, 5, none) /* this obj prop a b -> a this obj prop b */
DEF( swap, 1, 2, 2, none) /* a b -> b a */
DEF( swap2, 1, 4, 4, none) /* a b c d -> c d a b */
DEF( rot3l, 1, 3, 3, none) /* x a b -> a b x */
DEF( rot3r, 1, 3, 3, none) /* a b x -> x a b */
DEF( rot4l, 1, 4, 4, none) /* x a b c -> a b c x */
DEF( rot5l, 1, 5, 5, none) /* x a b c d -> a b c d x */
DEF(call_constructor, 3, 2, 1, npop) /* func new.target args -> ret. arguments are not counted in n_pop */
DEF( call, 3, 1, 1, npop) /* arguments are not counted in n_pop */
DEF( tail_call, 3, 1, 0, npop) /* arguments are not counted in n_pop */
DEF( call_method, 3, 2, 1, npop) /* arguments are not counted in n_pop */
DEF(tail_call_method, 3, 2, 0, npop) /* arguments are not counted in n_pop */
DEF( array_from, 3, 0, 1, npop) /* arguments are not counted in n_pop */
DEF( apply, 3, 3, 1, u16)
DEF( return, 1, 1, 0, none)
DEF( return_undef, 1, 0, 0, none)
DEF(check_ctor_return, 1, 1, 2, none)
DEF( check_ctor, 1, 0, 0, none)
DEF( init_ctor, 1, 0, 1, none)
DEF( check_brand, 1, 2, 2, none) /* this_obj func -> this_obj func */
DEF( add_brand, 1, 2, 0, none) /* this_obj home_obj -> */
DEF( return_async, 1, 1, 0, none)
DEF( throw, 1, 1, 0, none)
DEF( throw_error, 6, 0, 0, atom_u8)
DEF( eval, 5, 1, 1, npop_u16) /* func args... -> ret_val */
DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
bytecode string */
DEF( get_super, 1, 1, 1, none)
DEF( import, 1, 1, 1, none) /* dynamic module import */
DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */
DEF( get_var, 5, 0, 1, atom) /* throw an exception if the variable does not exist */
DEF( put_var, 5, 1, 0, atom) /* must come after get_var */
DEF( put_var_init, 5, 1, 0, atom) /* must come after put_var. Used to initialize a global lexical variable */
DEF( put_var_strict, 5, 2, 0, atom) /* for strict mode variable write */
DEF( get_ref_value, 1, 2, 3, none)
DEF( put_ref_value, 1, 3, 0, none)
DEF( define_var, 6, 0, 0, atom_u8)
DEF(check_define_var, 6, 0, 0, atom_u8)
DEF( define_func, 6, 1, 0, atom_u8)
// order matters, see IC counterparts
DEF( get_field, 5, 1, 1, atom)
DEF( get_field2, 5, 1, 2, atom)
DEF( put_field, 5, 2, 0, atom)
DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
DEF( get_array_el, 1, 2, 1, none)
DEF( get_array_el2, 1, 2, 2, none) /* obj prop -> obj value */
DEF( put_array_el, 1, 3, 0, none)
DEF(get_super_value, 1, 3, 1, none) /* this obj prop -> value */
DEF(put_super_value, 1, 4, 0, none) /* this obj prop value -> */
DEF( define_field, 5, 2, 1, atom)
DEF( set_name, 5, 1, 1, atom)
DEF(set_name_computed, 1, 2, 2, none)
DEF( set_proto, 1, 2, 1, none)
DEF(set_home_object, 1, 2, 2, none)
DEF(define_array_el, 1, 3, 2, none)
DEF( append, 1, 3, 2, none) /* append enumerated object, update length */
DEF(copy_data_properties, 2, 3, 3, u8)
DEF( define_method, 6, 2, 1, atom_u8)
DEF(define_method_computed, 2, 3, 1, u8) /* must come after define_method */
DEF( define_class, 6, 2, 2, atom_u8) /* parent ctor -> ctor proto */
DEF( define_class_computed, 6, 3, 3, atom_u8) /* field_name parent ctor -> field_name ctor proto (class with computed name) */
DEF( get_loc, 3, 0, 1, loc)
DEF( put_loc, 3, 1, 0, loc) /* must come after get_loc */
DEF( set_loc, 3, 1, 1, loc) /* must come after put_loc */
DEF( get_arg, 3, 0, 1, arg)
DEF( put_arg, 3, 1, 0, arg) /* must come after get_arg */
DEF( set_arg, 3, 1, 1, arg) /* must come after put_arg */
DEF( get_var_ref, 3, 0, 1, var_ref)
DEF( put_var_ref, 3, 1, 0, var_ref) /* must come after get_var_ref */
DEF( set_var_ref, 3, 1, 1, var_ref) /* must come after put_var_ref */
DEF(set_loc_uninitialized, 3, 0, 0, loc)
DEF( get_loc_check, 3, 0, 1, loc)
DEF( put_loc_check, 3, 1, 0, loc) /* must come after get_loc_check */
DEF( put_loc_check_init, 3, 1, 0, loc)
DEF(get_var_ref_check, 3, 0, 1, var_ref)
DEF(put_var_ref_check, 3, 1, 0, var_ref) /* must come after get_var_ref_check */
DEF(put_var_ref_check_init, 3, 1, 0, var_ref)
DEF( close_loc, 3, 0, 0, loc)
DEF( if_false, 5, 1, 0, label)
DEF( if_true, 5, 1, 0, label) /* must come after if_false */
DEF( goto, 5, 0, 0, label) /* must come after if_true */
DEF( catch, 5, 0, 1, label)
DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
DEF( to_object, 1, 1, 1, none)
//DEF( to_string, 1, 1, 1, none)
DEF( to_propkey, 1, 1, 1, none)
DEF( to_propkey2, 1, 2, 2, none)
DEF( with_get_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF( with_put_var, 10, 2, 1, atom_label_u8) /* must be in the same order as scope_xxx */
DEF(with_delete_var, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF( with_make_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF( with_get_ref, 10, 1, 0, atom_label_u8) /* must be in the same order as scope_xxx */
DEF(with_get_ref_undef, 10, 1, 0, atom_label_u8)
DEF( make_loc_ref, 7, 0, 2, atom_u16)
DEF( make_arg_ref, 7, 0, 2, atom_u16)
DEF(make_var_ref_ref, 7, 0, 2, atom_u16)
DEF( make_var_ref, 5, 0, 2, atom)
DEF( for_in_start, 1, 1, 1, none)
DEF( for_of_start, 1, 1, 3, none)
DEF(for_await_of_start, 1, 1, 3, none)
DEF( for_in_next, 1, 1, 3, none)
DEF( for_of_next, 2, 3, 5, u8)
DEF(iterator_check_object, 1, 1, 1, none)
DEF(iterator_get_value_done, 1, 1, 2, none)
DEF( iterator_close, 1, 3, 0, none)
DEF( iterator_next, 1, 4, 4, none)
DEF( iterator_call, 2, 4, 5, u8)
DEF( initial_yield, 1, 0, 0, none)
DEF( yield, 1, 1, 2, none)
DEF( yield_star, 1, 1, 2, none)
DEF(async_yield_star, 1, 1, 2, none)
DEF( await, 1, 1, 1, none)
/* arithmetic/logic operations */
DEF( neg, 1, 1, 1, none)
DEF( plus, 1, 1, 1, none)
DEF( dec, 1, 1, 1, none)
DEF( inc, 1, 1, 1, none)
DEF( post_dec, 1, 1, 2, none)
DEF( post_inc, 1, 1, 2, none)
DEF( dec_loc, 2, 0, 0, loc8)
DEF( inc_loc, 2, 0, 0, loc8)
DEF( add_loc, 2, 1, 0, loc8)
DEF( not, 1, 1, 1, none)
DEF( lnot, 1, 1, 1, none)
DEF( typeof, 1, 1, 1, none)
DEF( delete, 1, 2, 1, none)
DEF( delete_var, 5, 0, 1, atom)
/* warning: order matters (see js_parse_assign_expr) */
DEF( mul, 1, 2, 1, none)
DEF( div, 1, 2, 1, none)
DEF( mod, 1, 2, 1, none)
DEF( add, 1, 2, 1, none)
DEF( sub, 1, 2, 1, none)
DEF( shl, 1, 2, 1, none)
DEF( sar, 1, 2, 1, none)
DEF( shr, 1, 2, 1, none)
DEF( and, 1, 2, 1, none)
DEF( xor, 1, 2, 1, none)
DEF( or, 1, 2, 1, none)
DEF( pow, 1, 2, 1, none)
DEF( lt, 1, 2, 1, none)
DEF( lte, 1, 2, 1, none)
DEF( gt, 1, 2, 1, none)
DEF( gte, 1, 2, 1, none)
DEF( instanceof, 1, 2, 1, none)
DEF( in, 1, 2, 1, none)
DEF( eq, 1, 2, 1, none)
DEF( neq, 1, 2, 1, none)
DEF( strict_eq, 1, 2, 1, none)
DEF( strict_neq, 1, 2, 1, none)
DEF(is_undefined_or_null, 1, 1, 1, none)
DEF( private_in, 1, 2, 1, none)
DEF(push_bigint_i32, 5, 0, 1, i32)
/* must be the last non short and non temporary opcode */
DEF( nop, 1, 0, 0, none)
/* temporary opcodes: never emitted in the final bytecode */
def( enter_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( leave_scope, 3, 0, 0, u16) /* emitted in phase 1, removed in phase 2 */
def( label, 5, 0, 0, label) /* emitted in phase 1, removed in phase 3 */
def(scope_get_var_undef, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_put_var, 7, 1, 0, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_delete_var, 7, 0, 1, atom_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_make_ref, 11, 0, 2, atom_label_u16) /* emitted in phase 1, removed in phase 2 */
def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
def(scope_in_private_field, 7, 1, 1, atom_u16) /* obj -> res emitted in phase 1, removed in phase 2 */
def(get_field_opt_chain, 5, 1, 1, atom) /* emitted in phase 1, removed in phase 2 */
def(get_array_el_opt_chain, 1, 2, 1, none) /* emitted in phase 1, removed in phase 2 */
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
DEF( push_minus1, 1, 0, 1, none_int)
DEF( push_0, 1, 0, 1, none_int)
DEF( push_1, 1, 0, 1, none_int)
DEF( push_2, 1, 0, 1, none_int)
DEF( push_3, 1, 0, 1, none_int)
DEF( push_4, 1, 0, 1, none_int)
DEF( push_5, 1, 0, 1, none_int)
DEF( push_6, 1, 0, 1, none_int)
DEF( push_7, 1, 0, 1, none_int)
DEF( push_i8, 2, 0, 1, i8)
DEF( push_i16, 3, 0, 1, i16)
DEF( push_const8, 2, 0, 1, const8)
DEF( fclosure8, 2, 0, 1, const8) /* must follow push_const8 */
DEF(push_empty_string, 1, 0, 1, none)
DEF( get_loc8, 2, 0, 1, loc8)
DEF( put_loc8, 2, 1, 0, loc8)
DEF( set_loc8, 2, 1, 1, loc8)
DEF( get_loc0_loc1, 1, 0, 2, none_loc)
DEF( get_loc0, 1, 0, 1, none_loc)
DEF( get_loc1, 1, 0, 1, none_loc)
DEF( get_loc2, 1, 0, 1, none_loc)
DEF( get_loc3, 1, 0, 1, none_loc)
DEF( put_loc0, 1, 1, 0, none_loc)
DEF( put_loc1, 1, 1, 0, none_loc)
DEF( put_loc2, 1, 1, 0, none_loc)
DEF( put_loc3, 1, 1, 0, none_loc)
DEF( set_loc0, 1, 1, 1, none_loc)
DEF( set_loc1, 1, 1, 1, none_loc)
DEF( set_loc2, 1, 1, 1, none_loc)
DEF( set_loc3, 1, 1, 1, none_loc)
DEF( get_arg0, 1, 0, 1, none_arg)
DEF( get_arg1, 1, 0, 1, none_arg)
DEF( get_arg2, 1, 0, 1, none_arg)
DEF( get_arg3, 1, 0, 1, none_arg)
DEF( put_arg0, 1, 1, 0, none_arg)
DEF( put_arg1, 1, 1, 0, none_arg)
DEF( put_arg2, 1, 1, 0, none_arg)
DEF( put_arg3, 1, 1, 0, none_arg)
DEF( set_arg0, 1, 1, 1, none_arg)
DEF( set_arg1, 1, 1, 1, none_arg)
DEF( set_arg2, 1, 1, 1, none_arg)
DEF( set_arg3, 1, 1, 1, none_arg)
DEF( get_var_ref0, 1, 0, 1, none_var_ref)
DEF( get_var_ref1, 1, 0, 1, none_var_ref)
DEF( get_var_ref2, 1, 0, 1, none_var_ref)
DEF( get_var_ref3, 1, 0, 1, none_var_ref)
DEF( put_var_ref0, 1, 1, 0, none_var_ref)
DEF( put_var_ref1, 1, 1, 0, none_var_ref)
DEF( put_var_ref2, 1, 1, 0, none_var_ref)
DEF( put_var_ref3, 1, 1, 0, none_var_ref)
DEF( set_var_ref0, 1, 1, 1, none_var_ref)
DEF( set_var_ref1, 1, 1, 1, none_var_ref)
DEF( set_var_ref2, 1, 1, 1, none_var_ref)
DEF( set_var_ref3, 1, 1, 1, none_var_ref)
DEF( get_length, 1, 1, 1, none)
DEF( if_false8, 2, 1, 0, label8)
DEF( if_true8, 2, 1, 0, label8) /* must come after if_false8 */
DEF( goto8, 2, 0, 0, label8) /* must come after if_true8 */
DEF( goto16, 3, 0, 0, label16)
DEF( call0, 1, 1, 1, npopx)
DEF( call1, 1, 1, 1, npopx)
DEF( call2, 1, 1, 1, npopx)
DEF( call3, 1, 1, 1, npopx)
DEF( is_undefined, 1, 1, 1, none)
DEF( is_null, 1, 1, 1, none)
DEF(typeof_is_undefined, 1, 1, 1, none)
DEF( typeof_is_function, 1, 1, 1, none)
#undef DEF
#undef def
#endif /* DEF */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,129 @@
import * as std from "qjs:std";
import * as os from "qjs:os";
import * as bjson from "qjs:bjson";
// See quickjs.h
const JS_READ_OBJ_BYTECODE = 1 << 0;
const JS_READ_OBJ_REFERENCE = 1 << 3;
const JS_WRITE_OBJ_BYTECODE = 1 << 0;
const JS_WRITE_OBJ_REFERENCE = 1 << 3;
const JS_WRITE_OBJ_STRIP_SOURCE = 1 << 4;
/**
* Trailer for standalone binaries. When some code gets bundled with the qjs
* executable we add a 12 byte trailer. The first 8 bytes are the magic
* string that helps us understand this is a standalone binary, and the
* remaining 4 are the offset (from the beginning of the binary) where the
* bundled data is located.
*
* The offset is stored as a 32bit little-endian number.
*/
const Trailer = {
Magic: 'quickjs2',
MagicSize: 8,
DataSize: 4,
Size: 12
};
function encodeAscii(txt) {
return new Uint8Array(txt.split('').map(c => c.charCodeAt(0)));
}
function decodeAscii(buf) {
return Array.from(buf).map(c => String.fromCharCode(c)).join('')
}
export function compileStandalone(inFile, outFile, targetExe) {
// Step 1: compile the source file to bytecode
const js = std.loadFile(inFile);
if (!js) {
throw new Error(`failed to open ${inFile}`);
}
const code = std.evalScript(js, {
compile_only: true,
compile_module: true
});
const bytecode = new Uint8Array(bjson.write(code, JS_WRITE_OBJ_BYTECODE | JS_WRITE_OBJ_REFERENCE | JS_WRITE_OBJ_STRIP_SOURCE));
// Step 2: copy the bytecode to the end of the executable and add a marker.
const exeFileName = targetExe ?? os.exePath() ?? globalThis.argv0;
const exe = std.loadFile(exeFileName, { binary: true });
if (!exe) {
throw new Error(`failed to open executable: ${exeFileName}`);
}
const exeSize = exe.length;
const newBuffer = exe.buffer.transfer(exeSize + bytecode.length + Trailer.Size);
const newExe = new Uint8Array(newBuffer);
newExe.set(bytecode, exeSize);
newExe.set(encodeAscii(Trailer.Magic), exeSize + bytecode.length);
const dw = new DataView(newBuffer, exeSize + bytecode.length + Trailer.MagicSize, Trailer.DataSize);
dw.setUint32(0, exeSize, true /* little-endian */);
// We use os.open() so we can set the permissions mask.
const newFd = os.open(outFile, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o755);
if (newFd < 0) {
throw new Error(`failed to create ${outFile}`);
}
if (os.write(newFd, newBuffer, 0, newBuffer.byteLength) < 0) {
os.close(newFd);
throw new Error(`failed to write to output file`);
}
os.close(newFd);
}
export function runStandalone() {
const file = os.exePath() ?? globalThis.argv0;
const exe = std.open(file, 'rb');
if (!exe) {
throw new Error(`failed to open executable: ${file}`);
}
let r = exe.seek(-Trailer.Size, std.SEEK_END);
if (r < 0) {
throw new Error(`seek error: ${-r}`);
}
const trailer = new Uint8Array(Trailer.Size);
exe.read(trailer.buffer, 0, Trailer.Size);
const magic = new Uint8Array(trailer.buffer, 0, Trailer.MagicSize);
// Shouldn't happen since qjs.c checks for it.
if (decodeAscii(magic) !== Trailer.Magic) {
exe.close();
throw new Error('corrupted binary, magic mismatch');
}
const dw = new DataView(trailer.buffer, Trailer.MagicSize, Trailer.DataSize);
const offset = dw.getUint32(0, true /* little-endian */);
const bytecode = new Uint8Array(offset - Trailer.Size);
r = exe.seek(offset, std.SEEK_SET);
if (r < 0) {
exe.close();
throw new Error(`seek error: ${-r}`);
}
exe.read(bytecode.buffer, 0, bytecode.length);
if (exe.error()) {
exe.close();
throw new Error('read error');
}
exe.close();
const code = bjson.read(bytecode.buffer, 0, bytecode.length, JS_READ_OBJ_BYTECODE | JS_READ_OBJ_REFERENCE);
return std.evalScript(code, {
eval_module: true
});
}
@@ -0,0 +1,132 @@
[exclude]
# list excluded tests and directories here for faster operation
# lengthy constructed regexp (>500 ms)
test262/test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js
test262/test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js
# slow notifications (> 600 ms)
test262/test/built-ins/Atomics/notify/notify-in-order-one-time.js
test262/test/built-ins/Atomics/notify/notify-in-order.js
test262/test/built-ins/Atomics/wait/bigint/waiterlist-order-of-operations-is-fifo.js
test262/test/built-ins/Atomics/wait/waiterlist-order-of-operations-is-fifo.js
# lengthy constructed regexp (>200 ms)
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-plus-quantifier-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-plus-quantifier-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-plus-quantifier-flags-u.js
test262/test/built-ins/RegExp/character-class-escape-non-whitespace.js
# 417 lengty tests with huge constructed regexp (>200 ms)
test262/test/built-ins/RegExp/property-escapes/generated/
# lengthy constructed URLS (>200 ms)
test262/test/built-ins/decodeURI/S15.1.3.1_A1.2_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.2_T2.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.10_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T2.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T3.js
test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.2_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.2_T2.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.10_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T2.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T3.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js
# lengthy comment tests
test262/test/language/comments/S7.4_A5.js
test262/test/language/comments/S7.4_A6.js
# lengthy unicode level tests
test262/test/language/identifiers/start-unicode-5.2.0-class-escaped.js
test262/test/language/identifiers/start-unicode-5.2.0-class.js
test262/test/language/identifiers/start-unicode-8.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-8.0.0-class.js
test262/test/language/identifiers/start-unicode-9.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-9.0.0-class.js
test262/test/language/identifiers/start-unicode-10.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-10.0.0-class.js
test262/test/language/identifiers/start-unicode-13.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-13.0.0-class.js
test262/test/language/identifiers/start-unicode-15.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-15.0.0-class.js
# Atomics tests with 2 second delays
test262/test/built-ins/Atomics/notify/bigint/notify-all-on-loc.js
test262/test/built-ins/Atomics/notify/negative-count.js
test262/test/built-ins/Atomics/notify/notify-all-on-loc.js
test262/test/built-ins/Atomics/notify/notify-all.js
test262/test/built-ins/Atomics/notify/notify-nan.js
test262/test/built-ins/Atomics/notify/notify-one.js
test262/test/built-ins/Atomics/notify/notify-two.js
test262/test/built-ins/Atomics/notify/notify-zero.js
# Atomics tests with 400 millisecond delays
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-no-operation.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-add.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-and.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-compareExchange.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-exchange.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-or.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-store.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-sub.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-xor.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-no-operation.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-add.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-and.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-compareExchange.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-exchange.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-or.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-store.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-sub.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-xor.js
# Atomics tests with 200 millisecond delays
test262/test/built-ins/Atomics/notify/count-defaults-to-infinity-missing.js
test262/test/built-ins/Atomics/notify/count-defaults-to-infinity-undefined.js
test262/test/built-ins/Atomics/notify/notify-renotify-noop.js
test262/test/built-ins/Atomics/notify/undefined-index-defaults-to-zero.js
test262/test/built-ins/Atomics/wait/bigint/false-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/bigint/nan-for-timeout.js
test262/test/built-ins/Atomics/wait/bigint/negative-timeout-agent.js
test262/test/built-ins/Atomics/wait/bigint/value-not-equal.js
test262/test/built-ins/Atomics/wait/bigint/was-woken-before-timeout.js
test262/test/built-ins/Atomics/wait/false-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/nan-for-timeout.js
test262/test/built-ins/Atomics/wait/negative-timeout-agent.js
test262/test/built-ins/Atomics/wait/null-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/object-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/poisoned-object-for-timeout-throws-agent.js
test262/test/built-ins/Atomics/wait/symbol-for-index-throws-agent.js
test262/test/built-ins/Atomics/wait/symbol-for-timeout-throws-agent.js
test262/test/built-ins/Atomics/wait/symbol-for-value-throws-agent.js
test262/test/built-ins/Atomics/wait/true-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/undefined-for-timeout.js
test262/test/built-ins/Atomics/wait/undefined-index-defaults-to-zero.js
test262/test/built-ins/Atomics/wait/value-not-equal.js
test262/test/built-ins/Atomics/wait/wait-index-value-not-equal.js
test262/test/built-ins/Atomics/wait/was-woken-before-timeout.js
# lengthy regexp literal construction (>500 ms)
test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js
test262/test/language/literals/regexp/S7.8.5_A1.4_T2.js
test262/test/language/literals/regexp/S7.8.5_A2.1_T2.js
test262/test/language/literals/regexp/S7.8.5_A2.4_T2.js
# lengthy built-ins tests (100-200 ms)
test262/test/built-ins/Function/prototype/toString/built-in-function-object.js
test262/test/built-ins/decodeURI/S15.1.3.1_A2.4_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.4_T1.js
test262/test/built-ins/encodeURI/S15.1.3.3_A2.3_T1.js
test262/test/built-ins/encodeURIComponent/S15.1.3.4_A2.3_T1.js
test262/test/language/expressions/dynamic-import/await-import-evaluation.js
@@ -0,0 +1,399 @@
[config]
# general settings for test262 ES6 version
# handle tests tagged as [noStrict]: yes, no, skip
nostrict=yes
# handle tests tagged as [strictOnly]: yes, no, skip
strict=yes
# test mode: default, default-nostrict, default-strict, strict, nostrict, both, all
mode=default
# handle tests flagged as [async]: yes, no, skip
# for these, load 'harness/doneprintHandle.js' prior to test
# and expect `print('Test262:AsyncTestComplete')` to be called for
# successful termination
async=yes
# handle tests flagged as [module]: yes, no, skip
module=yes
# output error messages: yes, no
verbose=yes
# load harness files from this directory
harnessdir=test262/harness
# names of harness include files to skip
#harnessexclude=
# name of the error file for known errors
errorfile=test262_errors.txt
# exclude tests enumerated in this file (see also [exclude] section)
#excludefile=test262_exclude.txt
# enumerate tests from this directory
testdir=test262/test
[features]
# Standard language features and proposed extensions
# list the features that are included
# skipped features are tagged as such to avoid warnings
# Keep this list alpha-sorted (:sort i in vim)
__getter__
__proto__
__setter__
AggregateError
align-detached-buffer-semantics-with-web-reality
arbitrary-module-namespace-names
array-find-from-last
array-grouping
Array.fromAsync
Array.prototype.at
Array.prototype.flat
Array.prototype.flatMap
Array.prototype.includes
Array.prototype.values
ArrayBuffer
arraybuffer-transfer
arrow-function
async-functions
async-iteration
Atomics.pause=!tcc
Atomics.waitAsync=skip
Atomics=!tcc # atomics are broken in recent versions of tcc
BigInt
caller
canonical-tz=skip
change-array-by-copy
class
class-fields-private
class-fields-private-in
class-fields-public
class-methods-private
class-static-block
class-static-fields-private
class-static-fields-public
class-static-methods-private
coalesce-expression
computed-property-names
const
cross-realm
DataView
DataView.prototype.getFloat32
DataView.prototype.getFloat64
DataView.prototype.getInt16
DataView.prototype.getInt32
DataView.prototype.getInt8
DataView.prototype.getUint16
DataView.prototype.getUint32
DataView.prototype.setUint8
decorators=skip
default-parameters
destructuring-assignment
destructuring-binding
dynamic-import
error-cause
Error.isError
explicit-resource-management=skip
exponentiation
export-star-as-namespace-from-module
FinalizationRegistry
Float16Array
Float32Array
Float64Array
for-in-order
for-of
generators
globalThis
hashbang
host-gc-required=skip
immutable-arraybuffer=skip
import-assertions=skip
import-attributes=skip
import-defer=skip
import.meta
Int16Array
Int32Array
Int8Array
Intl-enumeration=skip
intl-normative-optional=skip
Intl.DateTimeFormat-datetimestyle=skip
Intl.DateTimeFormat-dayPeriod=skip
Intl.DateTimeFormat-extend-timezonename=skip
Intl.DateTimeFormat-formatRange=skip
Intl.DateTimeFormat-fractionalSecondDigits=skip
Intl.DisplayNames-v2=skip
Intl.DisplayNames=skip
Intl.DurationFormat=skip
Intl.ListFormat=skip
Intl.Locale-info=skip
Intl.Locale=skip
Intl.NumberFormat-unified=skip
Intl.NumberFormat-v3=skip
Intl.RelativeTimeFormat=skip
Intl.Segmenter=skip
IsHTMLDDA
iterator-helpers
iterator-sequencing
joint-iteration=skip
json-modules=skip
json-parse-with-source=skip
json-superset
legacy-regexp=skip
let
logical-assignment-operators
Map
Math.sumPrecise
new.target
nonextensible-applies-to-private=skip
numeric-separator-literal
object-rest
object-spread
Object.fromEntries
Object.hasOwn
Object.is
optional-catch-binding
optional-chaining
Promise
promise-try
promise-with-resolvers
Promise.allSettled
Promise.any
Promise.prototype.finally
Proxy
proxy-missing-checks
Reflect
Reflect.construct
Reflect.set
Reflect.setPrototypeOf
regexp-dotall
regexp-duplicate-named-groups=skip
regexp-lookbehind
regexp-match-indices
regexp-modifiers=skip
regexp-named-groups
regexp-unicode-property-escapes
regexp-v-flag
RegExp.escape
resizable-arraybuffer
rest-parameters
Set
set-methods
ShadowRealm=skip
SharedArrayBuffer
source-phase-imports-module-source=skip
source-phase-imports=skip
stable-array-sort
stable-typedarray-sort
string-trimming
String.fromCodePoint
String.prototype.at
String.prototype.endsWith
String.prototype.includes
String.prototype.isWellFormed
String.prototype.matchAll
String.prototype.replaceAll
String.prototype.toWellFormed
String.prototype.trimEnd
String.prototype.trimStart
super
Symbol
Symbol.asyncIterator
Symbol.hasInstance
Symbol.isConcatSpreadable
Symbol.iterator
Symbol.match
Symbol.matchAll
Symbol.prototype.description
Symbol.replace
Symbol.search
Symbol.species
Symbol.split
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables
symbols-as-weakmap-keys
tail-call-optimization=skip
template
Temporal=skip
top-level-await
TypedArray
TypedArray.prototype.at
u180e
Uint16Array
Uint32Array
Uint8Array
uint8array-base64=skip
Uint8ClampedArray
upsert
WeakMap
WeakRef
WeakSet
well-formed-json-stringify
[exclude]
# list excluded tests and directories here
# intl not supported
test262/test/intl402/
# incompatible with the "caller" feature
test262/test/built-ins/Function/prototype/restricted-property-caller.js
test262/test/built-ins/Function/prototype/restricted-property-arguments.js
test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
# slow tests
#test262/test/built-ins/RegExp/CharacterClassEscapes/
#test262/test/built-ins/RegExp/property-escapes/
# in progress regexp-v-flag support, see https://github.com/quickjs-ng/quickjs/issues/228
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-13.1.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-14.0.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-15.0.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-15.1.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-string-literal.js
# frequently broken, sometimes contain engine-dependent tests
test262/test/staging/
[tests]
# list test files or use config.testdir
@@ -0,0 +1,93 @@
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-as-for-in-lhs.js:27: SyntaxError: invalid for in/of left hand-side
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-as-for-of-lhs.js:27: SyntaxError: invalid for in/of left hand-side
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-compound-assignment.js:33: SyntaxError: invalid assignment left-hand side
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-postfix-update.js:27: SyntaxError: invalid increment/decrement operand
test262/test/annexB/language/expressions/assignmenttargettype/callexpression-in-prefix-update.js:27: SyntaxError: invalid increment/decrement operand
test262/test/annexB/language/expressions/assignmenttargettype/callexpression.js:33: SyntaxError: invalid assignment left-hand side
test262/test/annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js:20: SyntaxError: invalid assignment left-hand side
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js:64: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js:64: strict mode: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js:69: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js:69: strict mode: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js:59: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js:59: strict mode: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js:64: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js:64: strict mode: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js:74: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js:74: strict mode: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js:81: TypeError: $DONE() not called
test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js:81: strict mode: TypeError: $DONE() not called
test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Unknown.js:16: SyntaxError: unknown unicode script
test262/test/built-ins/RegExp/property-escapes/generated/Script_-_Unknown.js:16: strict mode: SyntaxError: unknown unicode script
test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Unknown.js:16: SyntaxError: unknown unicode script
test262/test/built-ins/RegExp/property-escapes/generated/Script_Extensions_-_Unknown.js:16: strict mode: SyntaxError: unknown unicode script
test262/test/built-ins/RegExp/property-escapes/special-property-value-Script_Extensions-Unknown.js:14: SyntaxError: unknown unicode script
test262/test/built-ins/RegExp/property-escapes/special-property-value-Script_Extensions-Unknown.js:14: strict mode: SyntaxError: unknown unicode script
test262/test/built-ins/RegExp/prototype/exec/regexp-builtin-exec-v-u-flag.js:45: Test262Error: Actual argument [null] shouldn't be primitive. Unicode property escapes with v flag
test262/test/built-ins/RegExp/prototype/exec/regexp-builtin-exec-v-u-flag.js:45: strict mode: Test262Error: Actual argument [null] shouldn't be primitive. Unicode property escapes with v flag
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-16.0.js:16: Test262Error: `\p{RGI_Emoji}` should match 🇨🇶 (U+01F1E8 U+01F1F6)
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-16.0.js:16: strict mode: Test262Error: `\p{RGI_Emoji}` should match 🇨🇶 (U+01F1E8 U+01F1F6)
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-17.0.js:16: Test262Error: `\p{RGI_Emoji}` should match 👨🏻‍🐰‍👨🏼 (U+01F468 U+01F3FB U+00200D U+01F430 U+00200D U+01F468 U+01F3FC)
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-17.0.js:16: strict mode: Test262Error: `\p{RGI_Emoji}` should match 👨🏻‍🐰‍👨🏼 (U+01F468 U+01F3FB U+00200D U+01F430 U+00200D U+01F468 U+01F3FC)
test262/test/built-ins/String/prototype/match/regexp-prototype-match-v-u-flag.js:10: Test262Error: Actual argument [null] shouldn't be primitive. Unicode property escapes with v flag
test262/test/built-ins/String/prototype/match/regexp-prototype-match-v-u-flag.js:10: strict mode: Test262Error: Actual argument [null] shouldn't be primitive. Unicode property escapes with v flag
test262/test/built-ins/String/prototype/matchAll/regexp-prototype-matchAll-v-u-flag.js:73: Test262Error: Actual [] and expected [𠮷, 𠮷, 𠮷, 0, 3, 6] should have the same contents.
test262/test/built-ins/String/prototype/matchAll/regexp-prototype-matchAll-v-u-flag.js:73: strict mode: Test262Error: Actual [] and expected [𠮷, 𠮷, 𠮷, 0, 3, 6] should have the same contents.
test262/test/built-ins/String/prototype/replace/regexp-prototype-replace-v-u-flag.js:9: Test262Error: Unicode property escapes with v flag Expected SameValue(«"𠮷a𠮷b𠮷"», «"XaXbX"») to be true
test262/test/built-ins/String/prototype/replace/regexp-prototype-replace-v-u-flag.js:9: strict mode: Test262Error: Unicode property escapes with v flag Expected SameValue(«"𠮷a𠮷b𠮷"», «"XaXbX"») to be true
test262/test/built-ins/String/prototype/search/regexp-prototype-search-v-flag.js:9: Test262Error: Unicode property escapes with v flag Expected SameValue(«-1», «0») to be true
test262/test/built-ins/String/prototype/search/regexp-prototype-search-v-flag.js:9: strict mode: Test262Error: Unicode property escapes with v flag Expected SameValue(«-1», «0») to be true
test262/test/built-ins/String/prototype/search/regexp-prototype-search-v-u-flag.js:9: Test262Error: Unicode property escapes with v flag Expected SameValue(«-1», «0») to be true
test262/test/built-ins/String/prototype/search/regexp-prototype-search-v-u-flag.js:9: strict mode: Test262Error: Unicode property escapes with v flag Expected SameValue(«-1», «0») to be true
test262/test/built-ins/TypedArray/prototype/lastIndexOf/negative-index-and-resize-to-smaller.js:23: Test262Error: For index -1 Expected SameValue(«-1», «2») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/lastIndexOf/negative-index-and-resize-to-smaller.js:23: strict mode: Test262Error: For index -1 Expected SameValue(«-1», «2») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js:24: Test262Error: Actual [20, 30, 40, 60] and expected [20, 20, 20, 60] should have the same contents. (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/slice/speciesctor-return-same-buffer-with-offset.js:24: strict mode: Test262Error: Actual [20, 30, 40, 60] and expected [20, 20, 20, 60] should have the same contents. (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/subarray/byteoffset-with-detached-buffer.js:44: RangeError: invalid offset (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/subarray/byteoffset-with-detached-buffer.js:44: strict mode: RangeError: invalid offset (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/negative-index-resize-to-in-bounds.js:22: Test262Error: Expected a RangeError to be thrown but no exception was thrown at all (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/negative-index-resize-to-in-bounds.js:22: strict mode: Test262Error: Expected a RangeError to be thrown but no exception was thrown at all (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/negative-index-resize-to-out-of-bounds.js:22: Test262Error: Expected a RangeError to be thrown but no exception was thrown at all (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/negative-index-resize-to-out-of-bounds.js:22: strict mode: Test262Error: Expected a RangeError to be thrown but no exception was thrown at all (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js:35: Test262Error: value should not be coerced Expected SameValue(«22», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-prototype-chain-set.js:35: strict mode: Test262Error: value should not be coerced Expected SameValue(«22», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js:35: Test262Error: value should not be coerced Expected SameValue(«32», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-canonical-invalid-index-reflect-set.js:35: strict mode: Test262Error: value should not be coerced Expected SameValue(«32», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-prototype-chain-set.js:35: Test262Error: value should not be coerced Expected SameValue(«110», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-prototype-chain-set.js:35: strict mode: Test262Error: value should not be coerced Expected SameValue(«110», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-reflect-set.js:35: Test262Error: value should not be coerced Expected SameValue(«160», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-canonical-invalid-index-reflect-set.js:35: strict mode: Test262Error: value should not be coerced Expected SameValue(«160», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-object.js:19: Test262Error: valueOf is not called Expected SameValue(«1», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-object.js:19: strict mode: Test262Error: valueOf is not called Expected SameValue(«1», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-typed-array.js:19: Test262Error: valueOf is not called Expected SameValue(«1», «0») to be true
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds-receiver-is-not-typed-array.js:19: strict mode: Test262Error: valueOf is not called Expected SameValue(«1», «0») to be true
test262/test/language/destructuring/binding/keyed-destructuring-property-reference-target-evaluation-order-with-bindings.js:73: Test262Error: Actual [binding::source, binding::sourceKey, sourceKey, get source, binding::defaultValue, binding::varTarget] and expected [binding::source, binding::sourceKey, sourceKey, binding::varTarget, get source, binding::defaultValue] should have the same contents.
test262/test/language/expressions/assignment/destructuring/iterator-destructuring-property-reference-target-evaluation-order.js:42: Test262Error: Actual [source, iterator, target, target-key, target-key-tostring, iterator-step, iterator-done, set] and expected [source, iterator, target, target-key, iterator-step, iterator-done, target-key-tostring, set] should have the same contents.
test262/test/language/expressions/assignment/destructuring/iterator-destructuring-property-reference-target-evaluation-order.js:42: strict mode: Test262Error: Actual [source, iterator, target, target-key, target-key-tostring, iterator-step, iterator-done, set] and expected [source, iterator, target, target-key, iterator-step, iterator-done, target-key-tostring, set] should have the same contents.
test262/test/language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order-with-bindings.js:37: Test262Error: Actual [binding::source, binding::sourceKey, sourceKey, binding::target, binding::targetKey, targetKey, get source, binding::defaultValue, set target] and expected [binding::source, binding::sourceKey, sourceKey, binding::target, binding::targetKey, get source, binding::defaultValue, targetKey, set target] should have the same contents.
test262/test/language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order.js:32: Test262Error: Actual [source, source-key, source-key-tostring, target, target-key, target-key-tostring, get, set] and expected [source, source-key, source-key-tostring, target, target-key, get, target-key-tostring, set] should have the same contents.
test262/test/language/expressions/assignment/destructuring/keyed-destructuring-property-reference-target-evaluation-order.js:32: strict mode: Test262Error: Actual [source, source-key, source-key-tostring, target, target-key, target-key-tostring, get, set] and expected [source, source-key, source-key-tostring, target, target-key, get, target-key-tostring, set] should have the same contents.
test262/test/language/expressions/assignment/target-member-computed-reference.js:22: Test262Error: Expected a DummyError but got a Test262Error
test262/test/language/expressions/assignment/target-member-computed-reference.js:22: strict mode: Test262Error: Expected a DummyError but got a Test262Error
test262/test/language/expressions/assignment/target-super-computed-reference.js:20: Test262Error: Expected a DummyError but got a Test262Error
test262/test/language/expressions/assignment/target-super-computed-reference.js:20: strict mode: Test262Error: Expected a DummyError but got a Test262Error
test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: strict mode: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/expressions/object/computed-property-name-topropertykey-before-value-evaluation.js:31: Test262Error: Expected SameValue(«"bad"», «"ok"») to be true
test262/test/language/expressions/object/computed-property-name-topropertykey-before-value-evaluation.js:31: strict mode: Test262Error: Expected SameValue(«"bad"», «"ok"») to be true
test262/test/language/module-code/ambiguous-export-bindings/import-and-export-propagates-binding.js:75: SyntaxError: export 'foo' in module 'test262/test/language/module-code/ambiguous-export-bindings/imp' is ambiguous
test262/test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from-and-import-star-as-and-export.js:74: SyntaxError: export 'foo' in module 'test262/test/language/module-code/ambiguous-export-bindings/nam' is ambiguous
test262/test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-export-star-as-from.js:75: SyntaxError: export 'foo' in module 'test262/test/language/module-code/ambiguous-export-bindings/nam' is ambiguous
test262/test/language/module-code/ambiguous-export-bindings/namespace-unambiguous-if-import-star-as-and-export.js:74: SyntaxError: export 'foo' in module 'test262/test/language/module-code/ambiguous-export-bindings/nam' is ambiguous
test262/test/language/module-code/top-level-await/module-graphs-does-not-hang.js:10: TypeError: $DONE() not called
test262/test/language/module-code/top-level-await/rejection-order.js:20: TypeError: $DONE() not called
test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js:40: SyntaxError: invalid property name
test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js:40: strict mode: SyntaxError: invalid property name
test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js:40: SyntaxError: invalid property name
test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js:40: strict mode: SyntaxError: invalid property name
test262/test/language/statements/with/get-binding-value-call-with-proxy-env.js:39: Test262Error: Actual [has:Object, get:Symbol(Symbol.unscopables), get:Object] and expected [has:Object, get:Symbol(Symbol.unscopables), has:Object, get:Object] should have the same contents.
test262/test/language/statements/with/get-binding-value-idref-with-proxy-env.js:39: Test262Error: Actual [has:Object, get:Symbol(Symbol.unscopables), get:Object] and expected [has:Object, get:Symbol(Symbol.unscopables), has:Object, get:Object] should have the same contents.
test262/test/language/statements/with/get-mutable-binding-binding-deleted-in-get-unscopables-strict-mode.js:21: Test262Error: Expected a ReferenceError to be thrown but no exception was thrown at all
test262/test/language/statements/with/set-mutable-binding-binding-deleted-with-typed-array-in-proto-chain.js:20: Test262Error: Expected SameValue(«[object Object]», «undefined») to be true
test262/test/language/statements/with/set-mutable-binding-idref-compound-assign-with-proxy-env.js:58: Test262Error: Actual [has:p, get:Symbol(Symbol.unscopables), get:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] and expected [has:p, get:Symbol(Symbol.unscopables), has:p, get:p, has:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] should have the same contents.
test262/test/language/statements/with/set-mutable-binding-idref-with-proxy-env.js:50: Test262Error: Actual [has:p, get:Symbol(Symbol.unscopables), set:p, getOwnPropertyDescriptor:p, defineProperty:p] and expected [has:p, get:Symbol(Symbol.unscopables), has:p, set:p, getOwnPropertyDescriptor:p, defineProperty:p] should have the same contents.
+11
View File
@@ -0,0 +1,11 @@
[config]
local=yes
verbose=yes
testdir=tests
[exclude]
tests/empty.js
tests/fixture_cyclic_import.js
tests/microbench.js
tests/test_worker_module.js
tests/fixture_string_exports.js
@@ -0,0 +1,49 @@
export function assert(actual, expected, message) {
if (arguments.length === 1)
expected = true;
if (typeof actual === typeof expected) {
if (actual === expected) {
if (actual !== 0 || (1 / actual) === (1 / expected))
return;
}
if (typeof actual === 'number') {
if (isNaN(actual) && isNaN(expected))
return;
}
if (typeof actual === 'object') {
if (actual !== null && expected !== null
&& actual.constructor === expected.constructor
&& actual.toString() === expected.toString())
return;
}
}
throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" +
(message ? " (" + message + ")" : ""));
}
export function assertThrows(err, func)
{
var ex;
ex = false;
try {
func();
} catch(e) {
ex = true;
assert(e instanceof err);
}
assert(ex, true, "exception expected");
}
export function assertArrayEquals(a, b)
{
if (!Array.isArray(a) || !Array.isArray(b))
return assert(false);
assert(a.length, b.length);
a.forEach((value, idx) => {
assert(b[idx], value);
});
}
@@ -0,0 +1,16 @@
import {assert} from "./assert.js"
let caught = 0
for (let i = 1; i <= 32; i++) {
const prefix = "(:?".repeat(i)
const suffix = "|)+".repeat(i)
const between = "(?:a|)+"
try {
new RegExp(prefix + between + suffix)
} catch (e) {
assert(e instanceof SyntaxError)
assert(e.message, "out of memory")
caught++
}
}
assert(caught, 12) // subject to change
@@ -0,0 +1,6 @@
/*---
flags: [qjs:track-promise-rejections]
---*/
Promise.reject().catch(() => print('oops'))
Promise.resolve().then(() => print('ok'))
@@ -0,0 +1,6 @@
/*---
flags: [qjs:track-promise-rejections]
---*/
const error = await Promise.resolve().then(() => Promise.reject('reject')).catch(e => e)
print('Got this error:', error)
@@ -0,0 +1,7 @@
/*---
flags: [qjs:track-promise-rejections]
---*/
const promise = Promise.reject('reject')
const error = await Promise.resolve().then(() => promise).catch(e => e)
print('Got this error:', error)
@@ -0,0 +1,7 @@
/*---
flags: [qjs:no-detect-module]
negative:
phase: parse
type: SyntaxError
---*/
const undefined = 42 // SyntaxError at global scope
@@ -0,0 +1,4 @@
/*---
flags: [qjs:no-detect-module, module]
---*/
const undefined = 42 // not a SyntaxError at toplevel module scope
@@ -0,0 +1,4 @@
/*---
flags: [qjs:no-detect-module]
---*/
{ const undefined = 42 } // not a SyntaxError, not at global scope
@@ -0,0 +1,4 @@
/*---
flags: [qjs:no-detect-module]
---*/
;(function() { const undefined = 42 })() // not a SyntaxError, not at global scope
@@ -0,0 +1,4 @@
"use strict";
const u8 = new Uint8Array(1);
u8[100] = 123; // Should not throw.
@@ -0,0 +1,9 @@
import { assert, assertThrows } from "../assert.js";
const ab = new ArrayBuffer(1);
const u8 = new Uint8Array(ab);
assert(!ab.detached);
// Detach the ArrayBuffer.
ab.transfer();
assert(ab.detached);
u8[100] = 123; // Doesn't throw.
assertThrows(TypeError, () => Object.defineProperty(u8, "100", { value: 123 }));
@@ -0,0 +1,7 @@
import { assert, assertThrows } from "../assert.js";
const ab = new ArrayBuffer(16, { maxByteLength: 32 });
const u8 = new Uint8Array(ab, 16);
ab.resize(8);
assert(ab.byteLength, 8);
u8[1] = 123; // Doesn't throw.
assertThrows(TypeError, () => Object.defineProperty(u8, "1", { value: 123 }));

Some files were not shown because too many files have changed in this diff Show More