├── docs ├── .nvmrc ├── static │ ├── .nojekyll │ └── img │ │ └── favicon.ico ├── docs │ ├── developer-guide │ │ ├── api.md │ │ ├── _category_.json │ │ ├── internals.md │ │ └── intro.md │ ├── es_features.md │ ├── supported_platforms.md │ ├── installation.md │ ├── intro.md │ ├── projects.md │ ├── building.md │ ├── diff.md │ └── cli.md ├── babel.config.js ├── .gitignore ├── sidebars.js ├── src │ └── css │ │ └── custom.css ├── package.json └── docusaurus.config.js ├── tests ├── empty.js ├── detect_module │ ├── 0.js │ ├── 2.js │ ├── 1.js │ ├── 4.js │ └── 3.js ├── bug999.js ├── bug832.js ├── bug645 │ ├── 0.js │ ├── 2.js │ └── 1.js ├── str-pad-leak.js ├── fixture_cyclic_import.js ├── bug633 │ ├── 2.js │ ├── 1.js │ ├── 3.js │ └── 0.js ├── bug775.js ├── bug652.js ├── bug776.js ├── bug39 │ ├── 1.js │ ├── 2.js │ └── 3.js ├── bug904.js ├── bug988.js ├── destructured-export.js ├── bug741.js ├── function_source.js ├── test_cyclic_import.js ├── bug648.js ├── test_worker_module.js ├── bug858.js ├── test_worker.js ├── test_queue_microtask.js ├── assert.js ├── test_bigint.js ├── test_closure.js ├── test_loop.js ├── test_std.js └── test_bjson.js ├── examples ├── hello.js ├── hello_module.js ├── fib_module.js ├── test_fib.js ├── meson.build ├── test_point.js ├── fib.c ├── pi_bigint.js └── point.c ├── .gitattributes ├── cxxtest.cc ├── .gitmodules ├── .gitignore ├── tests.conf ├── meson_options.txt ├── unicode_download.sh ├── ctest.c ├── .github └── workflows │ ├── test-docs.yml │ ├── tsan.yml │ ├── valgrind.yml │ ├── docs.yml │ └── release.yml ├── fuzz.c ├── README.md ├── LICENSE ├── gen ├── hello.c ├── test_fib.c ├── function_source.c └── hello_module.c ├── builtin-array-fromasync.js ├── amalgam.js ├── libregexp-opcode.h ├── quickjs-c-atomics.h ├── quickjs-libc.h ├── list.h ├── libregexp.h ├── libunicode.h ├── standalone.js ├── Makefile ├── builtin-array-fromasync.h ├── xsum.h ├── test262-fast.conf ├── unicode_gen_def.h ├── quickjs-atom.h ├── test262_errors.txt └── meson.build /docs/.nvmrc: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /tests/empty.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/detect_module/0.js: -------------------------------------------------------------------------------- 1 | await undefined 2 | -------------------------------------------------------------------------------- /examples/hello.js: -------------------------------------------------------------------------------- 1 | console.log("Hello World"); 2 | -------------------------------------------------------------------------------- /docs/docs/developer-guide/api.md: -------------------------------------------------------------------------------- 1 | # API Reference 2 | 3 | WIP. 4 | -------------------------------------------------------------------------------- /tests/detect_module/2.js: -------------------------------------------------------------------------------- 1 | await = 42 // parsed as classic script 2 | -------------------------------------------------------------------------------- /tests/detect_module/1.js: -------------------------------------------------------------------------------- 1 | const p = Promise.resolve(42) 2 | await p 3 | -------------------------------------------------------------------------------- /tests/bug999.js: -------------------------------------------------------------------------------- 1 | function* f(r){ return r } // must return r 2 | [...f({})] 3 | 4 | -------------------------------------------------------------------------------- /tests/bug832.js: -------------------------------------------------------------------------------- 1 | const m = await import("./empty.js") 2 | print(m) // should not throw 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Don't show changes in generated files when doing git diff 2 | 3 | gen/** -diff 4 | 5 | -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tatut/quickjs/master/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /cxxtest.cc: -------------------------------------------------------------------------------- 1 | // note: file is not actually compiled, only checked for C++ syntax errors 2 | #include "ctest.c" 3 | -------------------------------------------------------------------------------- /tests/bug645/0.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const u8 = new Uint8Array(1); 4 | u8[100] = 123; // Should not throw. 5 | -------------------------------------------------------------------------------- /tests/str-pad-leak.js: -------------------------------------------------------------------------------- 1 | var v1 = ''; 2 | try { 3 | var v2 = v1.padEnd(2147483620, 0); 4 | } catch(_) {} 5 | 6 | -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /tests/fixture_cyclic_import.js: -------------------------------------------------------------------------------- 1 | import * as a from "./test_cyclic_import.js" 2 | export function f(x) { return 2 * a.g(x) } 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test262"] 2 | path = test262 3 | url = https://github.com/tc39/test262 4 | shallow = true 5 | update = none 6 | -------------------------------------------------------------------------------- /tests/bug633/2.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | flags: [qjs:no-detect-module] 3 | ---*/ 4 | { const undefined = 42 } // not a SyntaxError, not at global scope 5 | -------------------------------------------------------------------------------- /tests/detect_module/4.js: -------------------------------------------------------------------------------- 1 | // imports should classify it as a module, even when not at the top 2 | os.now() 3 | import * as os from "qjs:os" 4 | -------------------------------------------------------------------------------- /tests/bug633/1.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | flags: [qjs:no-detect-module, module] 3 | ---*/ 4 | const undefined = 42 // not a SyntaxError at toplevel module scope 5 | -------------------------------------------------------------------------------- /tests/bug633/3.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | flags: [qjs:no-detect-module] 3 | ---*/ 4 | ;(function() { const undefined = 42 })() // not a SyntaxError, not at global scope 5 | -------------------------------------------------------------------------------- /tests/bug775.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | negative: 3 | phase: runtime 4 | type: RangeError 5 | ---*/ 6 | function f() { f() } // was problematic under ASan 7 | f() 8 | -------------------------------------------------------------------------------- /tests/bug652.js: -------------------------------------------------------------------------------- 1 | import { assert } from "./assert.js" 2 | const ref = new WeakRef({}) 3 | const val = ref.deref() // should not throw 4 | assert(val, undefined) 5 | -------------------------------------------------------------------------------- /docs/docs/developer-guide/_category_.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Developer Guide", 3 | "position": 6, 4 | "link": { 5 | "type": "generated-index" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tests/bug776.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | negative: 3 | phase: runtime 4 | type: RangeError 5 | ---*/ 6 | function f() { f.apply(null) } // was problematic under ASan 7 | f() 8 | -------------------------------------------------------------------------------- /examples/hello_module.js: -------------------------------------------------------------------------------- 1 | /* example of JS module */ 2 | 3 | import { fib } from "./fib_module.js"; 4 | 5 | console.log("Hello World"); 6 | console.log("fib(10)=", fib(10)); 7 | -------------------------------------------------------------------------------- /tests/bug39/1.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | flags: [qjs:track-promise-rejections] 3 | ---*/ 4 | 5 | Promise.reject().catch(() => print('oops')) 6 | Promise.resolve().then(() => print('ok')) 7 | -------------------------------------------------------------------------------- /tests/bug633/0.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | flags: [qjs:no-detect-module] 3 | negative: 4 | phase: parse 5 | type: SyntaxError 6 | ---*/ 7 | const undefined = 42 // SyntaxError at global scope 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.a 2 | *.orig 3 | *.so 4 | .obj/ 5 | build/ 6 | unicode/ 7 | .idea 8 | cmake-* 9 | .vs 10 | out/ 11 | CMakeUserPresets.json 12 | fuzz 13 | .vscode/ 14 | microbench*.txt 15 | -------------------------------------------------------------------------------- /tests.conf: -------------------------------------------------------------------------------- 1 | [config] 2 | local=yes 3 | verbose=yes 4 | testdir=tests 5 | 6 | [exclude] 7 | tests/empty.js 8 | tests/fixture_cyclic_import.js 9 | tests/microbench.js 10 | tests/test_worker_module.js 11 | -------------------------------------------------------------------------------- /tests/bug39/2.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | flags: [qjs:track-promise-rejections] 3 | ---*/ 4 | 5 | const error = await Promise.resolve().then(() => Promise.reject('reject')).catch(e => e) 6 | print('Got this error:', error) 7 | -------------------------------------------------------------------------------- /tests/bug904.js: -------------------------------------------------------------------------------- 1 | import {assert, assertThrows} from "./assert.js" 2 | let calls = 0 3 | Error.prepareStackTrace = function() { calls++ } 4 | function f() { f() } 5 | assertThrows(RangeError, f) 6 | assert(calls, 0) 7 | -------------------------------------------------------------------------------- /tests/detect_module/3.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | negative: 3 | phase: parse 4 | type: SyntaxError 5 | ---*/ 6 | // the import statement makes it a module but `await = 42` is a SyntaxError 7 | import * as _ from "dummy" 8 | await = 42 9 | -------------------------------------------------------------------------------- /examples/fib_module.js: -------------------------------------------------------------------------------- 1 | /* fib module */ 2 | export function fib(n) 3 | { 4 | if (n <= 0) 5 | return 0; 6 | else if (n == 1) 7 | return 1; 8 | else 9 | return fib(n - 1) + fib(n - 2); 10 | } 11 | -------------------------------------------------------------------------------- /tests/bug39/3.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | flags: [qjs:track-promise-rejections] 3 | ---*/ 4 | 5 | const promise = Promise.reject('reject') 6 | const error = await Promise.resolve().then(() => promise).catch(e => e) 7 | print('Got this error:', error) 8 | -------------------------------------------------------------------------------- /examples/test_fib.js: -------------------------------------------------------------------------------- 1 | /* example of JS module importing a C module */ 2 | import * as os from "qjs:os"; 3 | 4 | const isWin = os.platform === 'win32'; 5 | const { fib } = await import(`./fib.${isWin ? 'dll' : 'so'}`); 6 | 7 | console.log("Hello World"); 8 | console.log("fib(10)=", fib(10)); 9 | -------------------------------------------------------------------------------- /tests/bug988.js: -------------------------------------------------------------------------------- 1 | import {assert} from "./assert.js" 2 | const expected = [97,98,99] 3 | const ab = new ArrayBuffer(0, {maxByteLength:3}) 4 | const dv = new DataView(ab) 5 | ab.resize(3) 6 | for (const [i,v] of Object.entries(expected)) dv.setUint8(i, v) 7 | for (const [i,v] of Object.entries(expected)) assert(v, dv.getUint8(i)) 8 | -------------------------------------------------------------------------------- /tests/destructured-export.js: -------------------------------------------------------------------------------- 1 | import { assert, assertArrayEquals } from "./assert.js"; 2 | import * as mod from "./destructured-export.js"; 3 | 4 | export const { a, b, c } = { a: 1, b: 2, c: 3 }; 5 | export const d = 4; 6 | 7 | assert(typeof mod === 'object'); 8 | assertArrayEquals(Object.keys(mod), ["a", "b", "c", "d"]); 9 | -------------------------------------------------------------------------------- /tests/bug645/2.js: -------------------------------------------------------------------------------- 1 | import { assert, assertThrows } from "../assert.js"; 2 | const ab = new ArrayBuffer(16, { maxByteLength: 32 }); 3 | const u8 = new Uint8Array(ab, 16); 4 | ab.resize(8); 5 | assert(ab.byteLength, 8); 6 | u8[1] = 123; // Doesn't throw. 7 | assertThrows(TypeError, () => Object.defineProperty(u8, "1", { value: 123 })); 8 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /tests/bug741.js: -------------------------------------------------------------------------------- 1 | import {assert} from "./assert.js" 2 | 3 | while (1) label: break 4 | 5 | var i = 0 6 | while (i < 3) label: { 7 | if (i > 0) 8 | break 9 | i++ 10 | } 11 | assert(i, 1) 12 | 13 | for (;;) label: break 14 | 15 | for (i = 0; i < 3; i++) label: { 16 | if (i > 0) 17 | break 18 | } 19 | assert(i, 1) 20 | -------------------------------------------------------------------------------- /tests/bug645/1.js: -------------------------------------------------------------------------------- 1 | import { assert, assertThrows } from "../assert.js"; 2 | const ab = new ArrayBuffer(1); 3 | const u8 = new Uint8Array(ab); 4 | assert(!ab.detached); 5 | // Detach the ArrayBuffer. 6 | ab.transfer(); 7 | assert(ab.detached); 8 | u8[100] = 123; // Doesn't throw. 9 | assertThrows(TypeError, () => Object.defineProperty(u8, "100", { value: 123 })); 10 | -------------------------------------------------------------------------------- /tests/function_source.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | const expect = "function f() { return 42 }" 3 | function f() { return 42 } 4 | 5 | { 6 | const actual = f.toString() 7 | if (actual !== expect) throw Error(actual) 8 | } 9 | 10 | { 11 | const f = eval(expect + "f") 12 | const actual = f.toString() 13 | if (actual !== expect) throw Error(actual) 14 | } 15 | -------------------------------------------------------------------------------- /tests/test_cyclic_import.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | negative: 3 | phase: resolution 4 | type: SyntaxError 5 | ---*/ 6 | // FIXME(bnoordhuis) shouldn't throw SyntaxError but that's still better 7 | // than segfaulting, see https://github.com/quickjs-ng/quickjs/issues/567 8 | import {assert} from "./assert.js" 9 | import {f} from "./fixture_cyclic_import.js" 10 | export {f} 11 | export function g(x) { return x + 1 } 12 | assert(f(1), 4) 13 | -------------------------------------------------------------------------------- /tests/bug648.js: -------------------------------------------------------------------------------- 1 | /*--- 2 | negative: 3 | phase: runtime 4 | type: Error 5 | ---*/ 6 | let finrec = new FinalizationRegistry(v => {}) 7 | let object = {object:"object"} 8 | finrec.register(object, {held:"held"}, {token:"token"}) 9 | object = undefined 10 | // abrupt termination should not leak |held| 11 | // unfortunately only shows up in qjs, not run-test262, 12 | // but still good to have a regression test 13 | throw Error("ok") 14 | -------------------------------------------------------------------------------- /docs/docs/es_features.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 7 3 | --- 4 | 5 | # ECMAScript Features 6 | 7 | QuickJS aims to support the latest available ECMAScript features once they hit the spec. 8 | 9 | Progress on _test262_ compliance can be checked [here](https://test262.fyi/#|qjs_ng). 10 | 11 | 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. 12 | -------------------------------------------------------------------------------- /examples/meson.build: -------------------------------------------------------------------------------- 1 | shared_module( 2 | 'fib', 3 | 'fib.c', 4 | 5 | name_prefix: '', 6 | gnu_symbol_visibility: 'default', 7 | c_args: ['-DJS_SHARED_LIBRARY'], 8 | dependencies: host_system == 'windows' ? qjs_dep : [], 9 | ) 10 | 11 | shared_module( 12 | 'point', 13 | 'point.c', 14 | 15 | name_prefix: '', 16 | gnu_symbol_visibility: 'default', 17 | c_args: ['-DJS_SHARED_LIBRARY'], 18 | dependencies: host_system == 'windows' ? qjs_dep : [], 19 | ) 20 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('tests', type: 'feature', description: 'build tests') 2 | option('examples', type: 'feature', description: 'build examples') 3 | option('libc', type: 'boolean', value: false, description: 'build qjs standard library modules as part of the library') 4 | option('cli_mimalloc', type: 'feature', value: 'disabled', description: 'build qjs cli with mimalloc') 5 | option('docdir', type: 'string', description: 'documentation directory') 6 | option('disable_parser', type: 'boolean', value: false, description: 'Disable JS source code parser') 7 | -------------------------------------------------------------------------------- /unicode_download.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | url="ftp://ftp.unicode.org/Public/16.0.0/ucd" 5 | emoji_url="${url}/emoji/emoji-data.txt" 6 | 7 | files="CaseFolding.txt DerivedNormalizationProps.txt PropList.txt \ 8 | SpecialCasing.txt CompositionExclusions.txt ScriptExtensions.txt \ 9 | UnicodeData.txt DerivedCoreProperties.txt NormalizationTest.txt Scripts.txt \ 10 | PropertyValueAliases.txt" 11 | 12 | mkdir -p unicode 13 | 14 | for f in $files; do 15 | g="${url}/${f}" 16 | wget $g -O unicode/$f 17 | done 18 | 19 | wget $emoji_url -O unicode/emoji-data.txt 20 | -------------------------------------------------------------------------------- /ctest.c: -------------------------------------------------------------------------------- 1 | // note: file is not actually compiled, only checked for C syntax errors 2 | #include "quickjs.h" 3 | 4 | int main(void) 5 | { 6 | JSRuntime *rt = JS_NewRuntime(); 7 | JSContext *ctx = JS_NewContext(rt); 8 | JS_FreeValue(ctx, JS_NAN); 9 | JS_FreeValue(ctx, JS_UNDEFINED); 10 | JS_FreeValue(ctx, JS_NewFloat64(ctx, 42)); 11 | // not a legal way of using JS_MKPTR but this is here 12 | // to have the compiler syntax-check its definition 13 | JS_FreeValue(ctx, JS_MKPTR(JS_TAG_UNINITIALIZED, 0)); 14 | JS_FreeContext(ctx); 15 | JS_FreeRuntime(rt); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/test-docs.yml: -------------------------------------------------------------------------------- 1 | name: Test Docs 2 | 3 | on: 4 | pull_request: 5 | paths: 6 | - 'docs/**' 7 | - '.github/workflows/*docs.yml' 8 | 9 | jobs: 10 | test-docs: 11 | name: Test Docusaurus build 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - uses: actions/setup-node@v4 16 | with: 17 | node-version-file: 'docs/.nvmrc' 18 | - name: Install dependencies 19 | working-directory: ./docs 20 | run: npm install 21 | - name: Build 22 | working-directory: ./docs 23 | run: npm run build 24 | -------------------------------------------------------------------------------- /docs/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | docsSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | }; 19 | 20 | export default sidebars; 21 | -------------------------------------------------------------------------------- /fuzz.c: -------------------------------------------------------------------------------- 1 | // clang -g -O1 -fsanitize=fuzzer -o fuzz fuzz.c 2 | #include "quickjs.h" 3 | #include "quickjs.c" 4 | #include "cutils.c" 5 | #include "libregexp.c" 6 | #include "libunicode.c" 7 | #include "xsum.c" 8 | #include 9 | 10 | int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) 11 | { 12 | JSRuntime *rt = JS_NewRuntime(); 13 | if (!rt) 14 | exit(1); 15 | JSContext *ctx = JS_NewContext(rt); 16 | if (!ctx) 17 | exit(1); 18 | JSValue val = JS_ReadObject(ctx, buf, len, /*flags*/0); 19 | JS_FreeValue(ctx, val); 20 | JS_FreeContext(ctx); 21 | JS_FreeRuntime(rt); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /docs/docs/supported_platforms.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 8 3 | --- 4 | 5 | # Supported Platforms 6 | 7 | | System | Supported versions | Notes | 8 | |---|---|---| 9 | | GNU/Linux | * | glibc and musl are supported | 10 | | macOS | macOS >= 11 | Currently supported macOS releases | 11 | | Windows | >= Windows 7* | VS >= 2022 and Clang are supported; requires `` | 12 | | FreeBSD | * | Limited testing | 13 | | OpenBSD | * | Limited testing | 14 | | NetBSD | * | Limited testing | 15 | | Android | NDK >= 26.0.10792818 | Limited testing | 16 | | iOS | * | Limited testing | 17 | | MinGW | MinGW-w64 | | 18 | | Other | N/A | Missing? Open a PR! | 19 | 20 | - `*`: Windows 7 is EOL and only supported in this project as long as it doesn't interfere with its progress. 21 | -------------------------------------------------------------------------------- /tests/test_worker_module.js: -------------------------------------------------------------------------------- 1 | /* Worker code for test_worker.js */ 2 | import * as os from "qjs:os"; 3 | 4 | var parent = os.Worker.parent; 5 | 6 | function handle_msg(e) { 7 | var ev = e.data; 8 | // print("child_recv", JSON.stringify(ev)); 9 | switch(ev.type) { 10 | case "abort": 11 | parent.postMessage({ type: "done" }); 12 | break; 13 | case "sab": 14 | /* modify the SharedArrayBuffer */ 15 | ev.buf[2] = 10; 16 | parent.postMessage({ type: "sab_done", buf: ev.buf }); 17 | break; 18 | } 19 | } 20 | 21 | function worker_main() { 22 | var i; 23 | 24 | parent.onmessage = handle_msg; 25 | for(i = 0; i < 10; i++) { 26 | parent.postMessage({ type: "num", num: i }); 27 | } 28 | } 29 | 30 | worker_main(); 31 | -------------------------------------------------------------------------------- /docs/docs/installation.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 3 3 | --- 4 | 5 | # Installation 6 | 7 | Installing QuickJS is simple, and we provide several ways to do so. 8 | 9 | 10 | ## Build from source 11 | 12 | If you built it from source as outlined in [building](./building) you can just run: 13 | 14 | ```bash 15 | make install 16 | ``` 17 | 18 | and it will be installed in your system. The default installation path is `/usr/local`. 19 | 20 | 21 | ## Using a prebuilt binary 22 | 23 | Each [release on GitHub] includes binaries for several systems and architectures. 24 | 25 | 26 | ## Using jsvu 27 | 28 | As of version 2.2.0 of `jsvu`, QuickJS-ng will be installed when the `quickjs` engine is requested. 29 | 30 | ```bash 31 | npm install jsvu -g 32 | ``` 33 | 34 | [release on GitHub]: https://github.com/quickjs-ng/quickjs/releases 35 | -------------------------------------------------------------------------------- /.github/workflows/tsan.yml: -------------------------------------------------------------------------------- 1 | name: tsan 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - '**' 9 | - '!.gitignore' 10 | - '!LICENSE' 11 | - '!README.md' 12 | - '!docs/**' 13 | - '!examples/**' 14 | - '.github/workflows/tsan.yml' 15 | - '.github/workflows/valgrind.yml' 16 | workflow_dispatch: 17 | 18 | jobs: 19 | linux: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | submodules: true 25 | - name: build 26 | run: | 27 | cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DQJS_ENABLE_TSAN=ON 28 | cmake --build build -j`nproc` 29 | - name: test 30 | run: | 31 | git submodule update --init --checkout --depth 1 32 | ./build/run-test262 -m -c test262.conf -c test262-fast.conf -a 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚡️ QuickJS - A mighty JavaScript engine 2 | 3 | ## Overview 4 | 5 | QuickJS is a small and embeddable JavaScript engine. It aims to support the latest 6 | [ECMAScript] specification. 7 | 8 | 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. 9 | 10 | ## Getting started 11 | 12 | Head over to the [project website] for instructions on how to get started and more 13 | documentation. 14 | 15 | ## Authors 16 | 17 | [@bnoordhuis], [@saghul], and many more [contributors]. 18 | 19 | [ECMAScript]: https://tc39.es/ecma262/ 20 | [original QuickJS project]: https://bellard.org/quickjs 21 | [@bnoordhuis]: https://github.com/bnoordhuis 22 | [@saghul]: https://github.com/saghul 23 | [contributors]: https://github.com/quickjs-ng/quickjs/graphs/contributors 24 | [project website]: https://quickjs-ng.github.io/quickjs/ 25 | -------------------------------------------------------------------------------- /tests/bug858.js: -------------------------------------------------------------------------------- 1 | import {assert} from "./assert.js"; 2 | 3 | Error.stackTraceLimit = Infinity; 4 | assert(Error.stackTraceLimit === Infinity); 5 | assert(new Error("error").stack.includes("bug858.js")); // stack should not be empty 6 | 7 | Error.stackTraceLimit = -Infinity; 8 | assert(Error.stackTraceLimit === -Infinity); 9 | assert(!new Error("error").stack.includes("bug858.js")); // stack should be empty 10 | 11 | Error.stackTraceLimit = NaN; 12 | assert(Number.isNaN(Error.stackTraceLimit)); 13 | assert(!new Error("error").stack.includes("bug858.js")); // stack should be empty 14 | 15 | Error.stackTraceLimit = -0; 16 | assert(Object.is(Error.stackTraceLimit, -0)); 17 | assert(!new Error("error").stack.includes("bug858.js")); // stack should be empty 18 | 19 | const obj = { valueOf() { throw "evil" } }; 20 | Error.stackTraceLimit = obj; 21 | assert(Error.stackTraceLimit === obj); 22 | try { 23 | throw new Error("fail") 24 | } catch (e) { 25 | assert(e.message.includes("fail")); 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/valgrind.yml: -------------------------------------------------------------------------------- 1 | name: valgrind 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - '**' 9 | - '!.gitignore' 10 | - '!LICENSE' 11 | - '!README.md' 12 | - '!docs/**' 13 | - '!examples/**' 14 | - '.github/workflows/tsan.yml' 15 | - '.github/workflows/valgrind.yml' 16 | workflow_dispatch: 17 | 18 | jobs: 19 | linux: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | with: 24 | submodules: true 25 | - name: install valgrind 26 | run: sudo apt-get update && sudo apt-get install valgrind 27 | - name: build 28 | run: | 29 | make BUILD_TYPE=RelWithDebInfo 30 | - name: test 31 | run: | 32 | git submodule update --init --checkout --depth 1 33 | 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 34 | -------------------------------------------------------------------------------- /examples/test_point.js: -------------------------------------------------------------------------------- 1 | /* example of JS module importing a C module */ 2 | import * as os from "qjs:os"; 3 | 4 | const isWin = os.platform === 'win32'; 5 | const { Point } = await import(`./point.${isWin ? 'dll' : 'so'}`); 6 | 7 | function assert(b, str) 8 | { 9 | if (b) { 10 | return; 11 | } else { 12 | throw Error("assertion failed: " + str); 13 | } 14 | } 15 | 16 | class ColorPoint extends Point { 17 | constructor(x, y, color) { 18 | super(x, y); 19 | this.color = color; 20 | } 21 | get_color() { 22 | return this.color; 23 | } 24 | }; 25 | 26 | function main() 27 | { 28 | var pt, pt2; 29 | 30 | pt = new Point(2, 3); 31 | assert(pt.x === 2); 32 | assert(pt.y === 3); 33 | pt.x = 4; 34 | assert(pt.x === 4); 35 | assert(pt.norm() == 5); 36 | 37 | pt2 = new ColorPoint(2, 3, 0xffffff); 38 | assert(pt2.x === 2); 39 | assert(pt2.color === 0xffffff); 40 | assert(pt2.get_color() === 0xffffff); 41 | } 42 | 43 | main(); 44 | -------------------------------------------------------------------------------- /docs/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: / 3 | sidebar_position: 1 4 | sidebar_label: Welcome 5 | --- 6 | 7 | # Welcome to QuickJS-NG 8 | 9 | QuickJS is a small and embeddable JavaScript engine. It aims to support the latest 10 | [ECMAScript] specification. 11 | 12 | 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. 13 | 14 | This project is focused on (but not limited to): 15 | 16 | - Community development 17 | - Testing 18 | - Cross-platform support 19 | - ES features 20 | 21 | You can check the differences with the original project [here.](./diff) 22 | 23 | :::note 24 | This site is under construction, the entire API is not yet documented. 25 | ::: 26 | 27 | ## Getting Started 28 | 29 | Head over to [building](./building) if you want to build QuickJS from source or [installation](./installation) 30 | for installing it from prebuilt binaries. 31 | 32 | [ECMAScript]: https://tc39.es/ecma262/ 33 | [original QuickJS project]: https://bellard.org/quickjs 34 | -------------------------------------------------------------------------------- /docs/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #2e8555; 10 | --ifm-color-primary-dark: #29784c; 11 | --ifm-color-primary-darker: #277148; 12 | --ifm-color-primary-darkest: #205d3b; 13 | --ifm-color-primary-light: #33925d; 14 | --ifm-color-primary-lighter: #359962; 15 | --ifm-color-primary-lightest: #3cad6e; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #25c2a0; 23 | --ifm-color-primary-dark: #21af90; 24 | --ifm-color-primary-darker: #1fa588; 25 | --ifm-color-primary-darkest: #1a8870; 26 | --ifm-color-primary-light: #29d5b0; 27 | --ifm-color-primary-lighter: #32d8b4; 28 | --ifm-color-primary-lightest: #4fddbf; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | } 31 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "docusaurus": "docusaurus", 5 | "start": "docusaurus start", 6 | "build": "docusaurus build", 7 | "swizzle": "docusaurus swizzle", 8 | "deploy": "docusaurus deploy", 9 | "clear": "docusaurus clear", 10 | "serve": "docusaurus serve", 11 | "write-translations": "docusaurus write-translations", 12 | "write-heading-ids": "docusaurus write-heading-ids" 13 | }, 14 | "dependencies": { 15 | "@docusaurus/core": "3.5.2", 16 | "@docusaurus/preset-classic": "3.5.2", 17 | "@mdx-js/react": "3.0.1", 18 | "clsx": "2.1.1", 19 | "prism-react-renderer": "2.4.0", 20 | "react": "18.3.1", 21 | "react-dom": "18.3.1" 22 | }, 23 | "devDependencies": { 24 | "@docusaurus/module-type-aliases": "3.5.2", 25 | "@docusaurus/types": "3.5.2" 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.5%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 3 chrome version", 35 | "last 3 firefox version", 36 | "last 5 safari version" 37 | ] 38 | }, 39 | "engines": { 40 | "node": ">=18.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /docs/docs/projects.md: -------------------------------------------------------------------------------- 1 | # Projects using NG 2 | 3 | Here is a list of projects currently using, supporting or migrating to QuickJS-NG. 4 | If you want yours to be listed here, please open a PR! 5 | 6 | ## [txiki.js](https://github.com/saghul/txiki.js) 7 | 8 | A tiny JavaScript runtime. 9 | 10 | ## [radare2](https://github.com/radareorg/radare2) 11 | 12 | Reverse engineering framework. 13 | 14 | ## [rquickjs](https://github.com/DelSkayn/rquickjs) 15 | 16 | High level Rust bindings. 17 | 18 | ## [llrt](https://github.com/awslabs/llrt) 19 | 20 | Lightweight JS runtime for serverless applications. 21 | 22 | ## [nx.js](https://github.com/TooTallNate/nx.js) 23 | 24 | JavaScript runtime for Nintendo Switch homebrew applications. 25 | 26 | ## [quickjs-rusty](https://github.com/Icemic/quickjs-rusty) 27 | 28 | Rust wrapper focus on embedding-ready and no-pain type conversion and interoperability. 29 | 30 | ## [GodotJS](https://github.com/godotjs/GodotJS) 31 | 32 | This project adds TypeScript/JavaScript support for Godot 4.x. It supports multiple javascript runtimes, including QuickJS-NG. 33 | 34 | ## [quickjs_es_runtime](https://github.com/HiRoFa/quickjs_es_runtime) 35 | 36 | Rust wrapper with typescript, modules, promises, async/await and much more. 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017-2024 Fabrice Bellard 4 | Copyright (c) 2017-2024 Charlie Gordon 5 | Copyright (c) 2023-2025 Ben Noordhuis 6 | Copyright (c) 2023-2025 Saúl Ibarra Corretgé 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /tests/test_worker.js: -------------------------------------------------------------------------------- 1 | import * as os from "qjs:os"; 2 | import { assert } from "./assert.js"; 3 | 4 | var worker; 5 | 6 | function test_worker() 7 | { 8 | var counter; 9 | 10 | worker = new os.Worker("./test_worker_module.js"); 11 | 12 | counter = 0; 13 | worker.onmessage = function (e) { 14 | var ev = e.data; 15 | // print("recv", JSON.stringify(ev)); 16 | switch(ev.type) { 17 | case "num": 18 | assert(ev.num, counter); 19 | counter++; 20 | if (counter == 10) { 21 | /* test SharedArrayBuffer modification */ 22 | let sab = new SharedArrayBuffer(10); 23 | let buf = new Uint8Array(sab); 24 | worker.postMessage({ type: "sab", buf: buf }); 25 | } 26 | break; 27 | case "sab_done": 28 | { 29 | let buf = ev.buf; 30 | /* check that the SharedArrayBuffer was modified */ 31 | assert(buf[2], 10); 32 | worker.postMessage({ type: "abort" }); 33 | } 34 | break; 35 | case "done": 36 | /* terminate */ 37 | worker.onmessage = null; 38 | break; 39 | } 40 | }; 41 | } 42 | 43 | test_worker(); 44 | -------------------------------------------------------------------------------- /tests/test_queue_microtask.js: -------------------------------------------------------------------------------- 1 | import { assert, assertArrayEquals, assertThrows } from "./assert.js"; 2 | 3 | function test_types() { 4 | assertThrows(TypeError, () => queueMicrotask(), "no argument"); 5 | assertThrows(TypeError, () => queueMicrotask(undefined), "undefined"); 6 | assertThrows(TypeError, () => queueMicrotask(null), "null"); 7 | assertThrows(TypeError, () => queueMicrotask(0), "0"); 8 | assertThrows(TypeError, () => queueMicrotask({ handleEvent() { } }), "an event handler object"); 9 | assertThrows(TypeError, () => queueMicrotask("window.x = 5;"), "a string"); 10 | } 11 | 12 | function test_async() { 13 | let called = false; 14 | queueMicrotask(() => { 15 | called = true; 16 | }); 17 | assert(!called); 18 | } 19 | 20 | function test_arguments() { 21 | queueMicrotask(function () { // note: intentionally not an arrow function 22 | assert(arguments.length === 0); 23 | }, "x", "y"); 24 | }; 25 | 26 | function test_async_order() { 27 | const happenings = []; 28 | Promise.resolve().then(() => happenings.push("a")); 29 | queueMicrotask(() => happenings.push("b")); 30 | Promise.reject().catch(() => happenings.push("c")); 31 | queueMicrotask(() => { 32 | assertArrayEquals(happenings, ["a", "b", "c"]); 33 | }); 34 | } 35 | 36 | test_types(); 37 | test_async(); 38 | test_arguments(); 39 | test_async_order(); 40 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'docs/**' 9 | - '.github/workflows/*docs.yml' 10 | 11 | jobs: 12 | build: 13 | name: Build Docusaurus 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: actions/setup-node@v4 18 | with: 19 | node-version-file: 'docs/.nvmrc' 20 | - name: Install dependencies 21 | working-directory: ./docs 22 | run: npm install 23 | - name: Build 24 | working-directory: ./docs 25 | run: npm run build 26 | - name: Upload Build Artifact 27 | uses: actions/upload-pages-artifact@v3 28 | with: 29 | path: docs/build 30 | 31 | deploy: 32 | name: Deploy to GitHub Pages 33 | needs: build 34 | 35 | # Grant GITHUB_TOKEN the permissions required to make a Pages deployment 36 | permissions: 37 | pages: write # to deploy to Pages 38 | id-token: write # to verify the deployment originates from an appropriate source 39 | 40 | # Deploy to the github-pages environment 41 | environment: 42 | name: github-pages 43 | url: ${{ steps.deployment.outputs.page_url }} 44 | 45 | runs-on: ubuntu-latest 46 | steps: 47 | - name: Deploy to GitHub Pages 48 | id: deployment 49 | uses: actions/deploy-pages@v4 50 | -------------------------------------------------------------------------------- /tests/assert.js: -------------------------------------------------------------------------------- 1 | export function assert(actual, expected, message) { 2 | if (arguments.length === 1) 3 | expected = true; 4 | 5 | if (typeof actual === typeof expected) { 6 | if (actual === expected) { 7 | if (actual !== 0 || (1 / actual) === (1 / expected)) 8 | return; 9 | } 10 | if (typeof actual === 'number') { 11 | if (isNaN(actual) && isNaN(expected)) 12 | return; 13 | } 14 | if (typeof actual === 'object') { 15 | if (actual !== null && expected !== null 16 | && actual.constructor === expected.constructor 17 | && actual.toString() === expected.toString()) 18 | return; 19 | } 20 | } 21 | throw Error("assertion failed: got |" + actual + "|" + 22 | ", expected |" + expected + "|" + 23 | (message ? " (" + message + ")" : "")); 24 | } 25 | 26 | export function assertThrows(err, func) 27 | { 28 | var ex; 29 | ex = false; 30 | try { 31 | func(); 32 | } catch(e) { 33 | ex = true; 34 | assert(e instanceof err); 35 | } 36 | assert(ex, true, "exception expected"); 37 | } 38 | 39 | export function assertArrayEquals(a, b) 40 | { 41 | if (!Array.isArray(a) || !Array.isArray(b)) 42 | return assert(false); 43 | 44 | assert(a.length, b.length); 45 | 46 | a.forEach((value, idx) => { 47 | assert(b[idx], value); 48 | }); 49 | } 50 | -------------------------------------------------------------------------------- /docs/docs/building.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 2 3 | --- 4 | 5 | # Building 6 | 7 | QuickJS uses [CMake] as its main build system, with an additional helper [Makefile]. 8 | 9 | :::note 10 | Windows users will need to run the CMake commands manually. 11 | ::: 12 | 13 | ## Getting the source 14 | 15 | ```bash 16 | git clone https://github.com/quickjs-ng/quickjs.git 17 | cd quickjs 18 | ``` 19 | 20 | ## Compiling everything 21 | 22 | ```bash 23 | make 24 | ``` 25 | 26 | This will build the `qjs` and `qjsc` executables and other test tools. Head over [here](./cli) for 27 | instructions on how to use them. 28 | 29 | ## Amalgamated builds 30 | 31 | The amalgamated build rolls individual source files into a single big file. 32 | It's a good choice for projects that want to use QuickJS without CMake. 33 | 34 | Download quickjs-amalgam.zip from https://github.com/quickjs-ng/quickjs/releases 35 | 36 | To enable the std, os and bjson modules, compile quickjs-amalgam.c with 37 | `-DQJS_BUILD_LIBC`. 38 | 39 | ## Debug builds 40 | 41 | ```bash 42 | make debug 43 | ``` 44 | 45 | This will produce a debug build without optimizations, suitable for developers. 46 | 47 | ## Running test262 48 | 49 | ```bash 50 | make test262 51 | ``` 52 | 53 | This will run the test262 suite. 54 | 55 | ```bash 56 | make test262-update 57 | ``` 58 | 59 | This will run the test262 suite and update the error / pass report, useful after 60 | implementing a new feature that would alter the result of the test suite. 61 | 62 | [CMake]: https://cmake.org 63 | [Makefile]: https://www.gnu.org/software/make/ 64 | -------------------------------------------------------------------------------- /gen/hello.c: -------------------------------------------------------------------------------- 1 | /* File generated automatically by the QuickJS-ng compiler. */ 2 | 3 | #include "quickjs-libc.h" 4 | 5 | const uint32_t qjsc_hello_size = 103; 6 | 7 | const uint8_t qjsc_hello[103] = { 8 | 0x14, 0x04, 0x01, 0x22, 0x65, 0x78, 0x61, 0x6d, 9 | 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 10 | 0x6c, 0x6f, 0x2e, 0x6a, 0x73, 0x01, 0x0e, 0x63, 11 | 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x01, 0x06, 12 | 0x6c, 0x6f, 0x67, 0x01, 0x16, 0x48, 0x65, 0x6c, 13 | 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 14 | 0x0d, 0xc2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 15 | 0x0c, 0x20, 0x0a, 0x01, 0xa2, 0x01, 0x00, 0x00, 16 | 0x00, 0x03, 0x00, 0x00, 0x19, 0x00, 0x08, 0xec, 17 | 0x02, 0x29, 0x39, 0xe2, 0x00, 0x00, 0x00, 0x43, 18 | 0xe3, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 19 | 0x00, 0x24, 0x01, 0x00, 0x0e, 0x06, 0x2f, 0xc2, 20 | 0x03, 0x01, 0x01, 0x02, 0x48, 0x0e, 0x00, 21 | }; 22 | 23 | static JSContext *JS_NewCustomContext(JSRuntime *rt) 24 | { 25 | JSContext *ctx = JS_NewContext(rt); 26 | if (!ctx) 27 | return NULL; 28 | return ctx; 29 | } 30 | 31 | int main(int argc, char **argv) 32 | { 33 | int r; 34 | JSRuntime *rt; 35 | JSContext *ctx; 36 | r = 0; 37 | rt = JS_NewRuntime(); 38 | js_std_set_worker_new_context_func(JS_NewCustomContext); 39 | js_std_init_handlers(rt); 40 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 41 | ctx = JS_NewCustomContext(rt); 42 | js_std_add_helpers(ctx, argc, argv); 43 | js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0); 44 | r = js_std_loop(ctx); 45 | if (r) { 46 | js_std_dump_error(ctx); 47 | } 48 | js_std_free_handlers(rt); 49 | JS_FreeContext(ctx); 50 | JS_FreeRuntime(rt); 51 | return r; 52 | } 53 | -------------------------------------------------------------------------------- /builtin-array-fromasync.js: -------------------------------------------------------------------------------- 1 | ;(function(Array, TypeError, asyncIterator, defineProperty, iterator) { 2 | "use strict" // result.length=i should throw if .length is not writable 3 | return async function fromAsync(arrayLike, mapFn=undefined, thisArg=undefined) { 4 | if (mapFn !== undefined && typeof mapFn !== "function") throw new TypeError("not a function") 5 | let result, i = 0, isConstructor = typeof this === "function" 6 | let sync = false, method = arrayLike[asyncIterator] 7 | if (method == null) sync = true, method = arrayLike[iterator] 8 | if (method == null) { 9 | let {length} = arrayLike 10 | length = +length || 0 11 | result = isConstructor ? new this(length) : Array(length) 12 | while (i < length) { 13 | let value = arrayLike[i] 14 | if (sync) value = await value 15 | if (mapFn) value = await mapFn.call(thisArg, value, i) 16 | defineProperty(result, i++, {value, configurable: true, writable: true}) 17 | } 18 | } else { 19 | const iter = method.call(arrayLike) 20 | result = isConstructor ? new this() : Array() 21 | try { 22 | for (;;) { 23 | let {value, done} = await iter.next() 24 | if (done) break 25 | if (sync) value = await value 26 | if (mapFn) value = await mapFn.call(thisArg, value, i) 27 | defineProperty(result, i++, {value, configurable: true, writable: true}) 28 | } 29 | } finally { 30 | if (iter.return) iter.return() 31 | } 32 | } 33 | result.length = i 34 | return result 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /amalgam.js: -------------------------------------------------------------------------------- 1 | import {loadFile, writeFile} from "qjs:std" 2 | 3 | const cutils_c = loadFile("cutils.c") 4 | const cutils_h = loadFile("cutils.h") 5 | const libregexp_c = loadFile("libregexp.c") 6 | const libregexp_h = loadFile("libregexp.h") 7 | const libregexp_opcode_h = loadFile("libregexp-opcode.h") 8 | const libunicode_c = loadFile("libunicode.c") 9 | const libunicode_h = loadFile("libunicode.h") 10 | const libunicode_table_h = loadFile("libunicode-table.h") 11 | const list_h = loadFile("list.h") 12 | const quickjs_atom_h = loadFile("quickjs-atom.h") 13 | const quickjs_c = loadFile("quickjs.c") 14 | const quickjs_c_atomics_h = loadFile("quickjs-c-atomics.h") 15 | const quickjs_h = loadFile("quickjs.h") 16 | const quickjs_libc_c = loadFile("quickjs-libc.c") 17 | const quickjs_libc_h = loadFile("quickjs-libc.h") 18 | const quickjs_opcode_h = loadFile("quickjs-opcode.h") 19 | const xsum_c = loadFile("xsum.c") 20 | const xsum_h = loadFile("xsum.h") 21 | const gen_builtin_array_fromasync_h = loadFile("builtin-array-fromasync.h") 22 | 23 | let source = "#if defined(QJS_BUILD_LIBC) && defined(__linux__) && !defined(_GNU_SOURCE)\n" 24 | + "#define _GNU_SOURCE\n" 25 | + "#endif\n" 26 | + quickjs_c_atomics_h 27 | + cutils_h 28 | + list_h 29 | + libunicode_h // exports lre_is_id_start, used by libregexp.h 30 | + libregexp_h 31 | + libunicode_table_h 32 | + xsum_h 33 | + quickjs_h 34 | + quickjs_c 35 | + cutils_c 36 | + libregexp_c 37 | + libunicode_c 38 | + xsum_c 39 | + "#ifdef QJS_BUILD_LIBC\n" 40 | + quickjs_libc_h 41 | + quickjs_libc_c 42 | + "#endif // QJS_BUILD_LIBC\n" 43 | source = source.replace(/#include "quickjs-atom.h"/g, quickjs_atom_h) 44 | source = source.replace(/#include "quickjs-opcode.h"/g, quickjs_opcode_h) 45 | source = source.replace(/#include "libregexp-opcode.h"/g, libregexp_opcode_h) 46 | source = source.replace(/#include "builtin-array-fromasync.h"/g, 47 | gen_builtin_array_fromasync_h) 48 | source = source.replace(/#include "[^"]+"/g, "") 49 | writeFile(execArgv[2] ?? "quickjs-amalgam.c", source) 50 | -------------------------------------------------------------------------------- /docs/docs/diff.md: -------------------------------------------------------------------------------- 1 | # Differences with bellard/quickjs 2 | 3 | This project aims to be a drop-in replacement for those already using QuickJS. 4 | Minimal API changes might be necessary. 5 | 6 | ## Community development 7 | 8 | NG is developed in the open, interacting with the wider community and through 9 | these interactions many improvements have already been made, including the incorporation 10 | of patches previously maintained in other forks. 11 | 12 | Each PR is reviewed, iterated on, and merged in GitHub. 13 | 14 | To date, NG has had over 40 distinct contributors and over 400 PRs. 15 | 16 | ## Consistent release cadence 17 | 18 | As the project moves forward, a steady cadence of releases has been maintained, with an 19 | average of a new release every 2 months. 20 | 21 | ## Testing 22 | 23 | Since its inception testing has been a focus. Each PR is tested in over 50 configurations, 24 | involving different operating systems, build types and sanitizers. 25 | 26 | The `test262` suite is also ran for every change. 27 | 28 | ## Cross-platform support 29 | 30 | In order to better support other platforms such as Windows the build system was 31 | changed to use [CMake]. 32 | 33 | In addition, Windows is treated as a first class citizen, with the addition of support 34 | for the MSVC compiler. 35 | 36 | [CMake]: https://cmake.org/ 37 | 38 | ## Performance 39 | 40 | While being an interpreter limits the performance in comparison with other engines which 41 | use a JIT, several significant performance improvements have been made: 42 | 43 | - Opcode fusion 44 | - Polymorphic inline caching 45 | - Memory allocation improvements 46 | - Improved parse speeds 47 | 48 | ## New ECMAScript APIs 49 | 50 | The main focus of NG is to deliver state-of-the-art JavaScript features. Typically once they 51 | are stable (stage 4) but sometimes even at earlier stages. Here is a non-exhaustive list 52 | of ES features present in NG: 53 | 54 | - Resizable ArrayBuffer 55 | - Float16Array 56 | - WeakRef 57 | - FinalizationRegistry 58 | - Iterator Helpers 59 | - Promise.try 60 | - Error.isError 61 | - Set operations 62 | 63 | Some non-standard but widely used APIs have also been added: 64 | 65 | - V8's [stack trace API](https://v8.dev/docs/stack-trace-api) 66 | - `Error.captureStackTrace` 67 | - `Error.prepareStackTrace` 68 | - `Error.stackTraceLimit` 69 | -------------------------------------------------------------------------------- /libregexp-opcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #ifdef DEF 26 | 27 | DEF(invalid, 1) /* never used */ 28 | DEF(char8, 2) /* 7 bits in fact */ 29 | DEF(char16, 3) 30 | DEF(char32, 5) 31 | DEF(dot, 1) 32 | DEF(any, 1) /* same as dot but match any character including line terminator */ 33 | DEF(line_start, 1) 34 | DEF(line_end, 1) 35 | DEF(goto, 5) 36 | DEF(split_goto_first, 5) 37 | DEF(split_next_first, 5) 38 | DEF(match, 1) 39 | DEF(save_start, 2) /* save start position */ 40 | DEF(save_end, 2) /* save end position, must come after saved_start */ 41 | DEF(save_reset, 3) /* reset save positions */ 42 | DEF(loop, 5) /* decrement the top the stack and goto if != 0 */ 43 | DEF(push_i32, 5) /* push integer on the stack */ 44 | DEF(drop, 1) 45 | DEF(word_boundary, 1) 46 | DEF(not_word_boundary, 1) 47 | DEF(back_reference, 2) 48 | DEF(backward_back_reference, 2) /* must come after back_reference */ 49 | DEF(range, 3) /* variable length */ 50 | DEF(range32, 3) /* variable length */ 51 | DEF(lookahead, 5) 52 | DEF(negative_lookahead, 5) 53 | DEF(push_char_pos, 1) /* push the character position on the stack */ 54 | DEF(check_advance, 1) /* pop one stack element and check that it is different from the character position */ 55 | DEF(prev, 1) /* go to the previous char */ 56 | DEF(simple_greedy_quant, 17) 57 | 58 | #endif /* DEF */ 59 | -------------------------------------------------------------------------------- /quickjs-c-atomics.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS C atomics definitions 3 | * 4 | * Copyright (c) 2023 Marcin Kolny 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__clang__) 26 | // Use GCC builtins for version < 4.9 27 | # if((__GNUC__ << 16) + __GNUC_MINOR__ < ((4) << 16) + 9) 28 | # define GCC_BUILTIN_ATOMICS 29 | # endif 30 | #endif 31 | 32 | #ifdef GCC_BUILTIN_ATOMICS 33 | #define atomic_fetch_add(obj, arg) \ 34 | __atomic_fetch_add(obj, arg, __ATOMIC_SEQ_CST) 35 | #define atomic_compare_exchange_strong(obj, expected, desired) \ 36 | __atomic_compare_exchange_n(obj, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) 37 | #define atomic_exchange(obj, desired) \ 38 | __atomic_exchange_n (obj, desired, __ATOMIC_SEQ_CST) 39 | #define atomic_load(obj) \ 40 | __atomic_load_n(obj, __ATOMIC_SEQ_CST) 41 | #define atomic_store(obj, desired) \ 42 | __atomic_store_n(obj, desired, __ATOMIC_SEQ_CST) 43 | #define atomic_fetch_or(obj, arg) \ 44 | __atomic_fetch_or(obj, arg, __ATOMIC_SEQ_CST) 45 | #define atomic_fetch_xor(obj, arg) \ 46 | __atomic_fetch_xor(obj, arg, __ATOMIC_SEQ_CST) 47 | #define atomic_fetch_and(obj, arg) \ 48 | __atomic_fetch_and(obj, arg, __ATOMIC_SEQ_CST) 49 | #define atomic_fetch_sub(obj, arg) \ 50 | __atomic_fetch_sub(obj, arg, __ATOMIC_SEQ_CST) 51 | #define _Atomic 52 | #else 53 | #include 54 | #endif 55 | -------------------------------------------------------------------------------- /examples/fib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS: Example of C module 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include "../quickjs.h" 25 | 26 | #define countof(x) (sizeof(x) / sizeof((x)[0])) 27 | 28 | static int fib(int n) 29 | { 30 | if (n <= 0) 31 | return 0; 32 | else if (n == 1) 33 | return 1; 34 | else 35 | return fib(n - 1) + fib(n - 2); 36 | } 37 | 38 | static JSValue js_fib(JSContext *ctx, JSValue this_val, 39 | int argc, JSValue *argv) 40 | { 41 | int n, res; 42 | if (JS_ToInt32(ctx, &n, argv[0])) 43 | return JS_EXCEPTION; 44 | res = fib(n); 45 | return JS_NewInt32(ctx, res); 46 | } 47 | 48 | static const JSCFunctionListEntry js_fib_funcs[] = { 49 | JS_CFUNC_DEF("fib", 1, js_fib ), 50 | }; 51 | 52 | static int js_fib_init(JSContext *ctx, JSModuleDef *m) 53 | { 54 | return JS_SetModuleExportList(ctx, m, js_fib_funcs, 55 | countof(js_fib_funcs)); 56 | } 57 | 58 | #ifdef JS_SHARED_LIBRARY 59 | #define JS_INIT_MODULE js_init_module 60 | #else 61 | #define JS_INIT_MODULE js_init_module_fib 62 | #endif 63 | 64 | #ifndef JS_EXTERN 65 | #ifdef _WIN32 66 | #define JS_EXTERN __declspec(dllexport) 67 | #else 68 | #define JS_EXTERN 69 | #endif 70 | #endif 71 | 72 | JS_EXTERN JSModuleDef *JS_INIT_MODULE(JSContext *ctx, const char *module_name) 73 | { 74 | JSModuleDef *m; 75 | m = JS_NewCModule(ctx, module_name, js_fib_init); 76 | if (!m) 77 | return NULL; 78 | JS_AddModuleExportList(ctx, m, js_fib_funcs, countof(js_fib_funcs)); 79 | return m; 80 | } 81 | -------------------------------------------------------------------------------- /tests/test_bigint.js: -------------------------------------------------------------------------------- 1 | import { assert, assertThrows } from "./assert.js"; 2 | 3 | 4 | function bigint_pow(a, n) 5 | { 6 | var r, i; 7 | r = 1n; 8 | for(i = 0n; i < n; i++) 9 | r *= a; 10 | return r; 11 | } 12 | 13 | /* a must be < b */ 14 | function test_less(a, b) 15 | { 16 | assert(a < b); 17 | assert(!(b < a)); 18 | assert(a <= b); 19 | assert(!(b <= a)); 20 | assert(b > a); 21 | assert(!(a > b)); 22 | assert(b >= a); 23 | assert(!(a >= b)); 24 | assert(a != b); 25 | assert(!(a == b)); 26 | } 27 | 28 | /* a must be numerically equal to b */ 29 | function test_eq(a, b) 30 | { 31 | assert(a == b); 32 | assert(b == a); 33 | assert(!(a != b)); 34 | assert(!(b != a)); 35 | assert(a <= b); 36 | assert(b <= a); 37 | assert(!(a < b)); 38 | assert(a >= b); 39 | assert(b >= a); 40 | assert(!(a > b)); 41 | } 42 | 43 | function test_bigint1() 44 | { 45 | var a, r; 46 | 47 | test_less(2n, 3n); 48 | test_eq(3n, 3n); 49 | 50 | test_less(2, 3n); 51 | test_eq(3, 3n); 52 | 53 | test_less(2.1, 3n); 54 | test_eq(Math.sqrt(4), 2n); 55 | 56 | a = bigint_pow(3n, 100n); 57 | assert((a - 1n) != a); 58 | assert(a, 515377520732011331036461129765621272702107522001n); 59 | assert(a, 0x5a4653ca673768565b41f775d6947d55cf3813d1n); 60 | 61 | r = 1n << 31n; 62 | assert(r, 2147483648n, "1 << 31n === 2147483648n"); 63 | 64 | r = 1n << 32n; 65 | assert(r, 4294967296n, "1 << 32n === 4294967296n"); 66 | 67 | assert(String(-9223372036854775808n), "-9223372036854775808"); 68 | } 69 | 70 | function test_bigint2() 71 | { 72 | assert(BigInt(""), 0n); 73 | assert(BigInt(" 123"), 123n); 74 | assert(BigInt(" 123 "), 123n); 75 | assertThrows(SyntaxError, () => { BigInt("+") } ); 76 | assertThrows(SyntaxError, () => { BigInt("-") } ); 77 | assertThrows(SyntaxError, () => { BigInt("\x00a") } ); 78 | assertThrows(SyntaxError, () => { BigInt(" 123 r") } ); 79 | } 80 | 81 | function test_bigint_map() 82 | { 83 | var m = new Map(); 84 | assert(m.size, 0); 85 | 86 | for (let i = 0n; i < 1337n; i++) { 87 | const r = m.set(i, i.toString()); 88 | assert(r, m); 89 | } 90 | assert(m.size, 1337); 91 | 92 | for (let i = 0n; i < 1337n; i++) { 93 | const r = m.get(i); 94 | assert(r, i.toString()); 95 | } 96 | assert(m.get(1337n), undefined); 97 | assert(m.size, 1337); 98 | 99 | for (let i = 0n; i < 1337n; i++) 100 | assert(m.delete(i)); 101 | assert(!m.delete(1337n)); 102 | assert(m.size, 0); 103 | } 104 | 105 | test_bigint1(); 106 | test_bigint2(); 107 | test_bigint_map(); 108 | -------------------------------------------------------------------------------- /quickjs-libc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS C library 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef QUICKJS_LIBC_H 25 | #define QUICKJS_LIBC_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "quickjs.h" 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name); 38 | JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); 39 | JSModuleDef *js_init_module_bjson(JSContext *ctx, const char *module_name); 40 | void js_std_add_helpers(JSContext *ctx, int argc, char **argv); 41 | int js_std_loop(JSContext *ctx); 42 | JSValue js_std_await(JSContext *ctx, JSValue obj); 43 | void js_std_init_handlers(JSRuntime *rt); 44 | void js_std_free_handlers(JSRuntime *rt); 45 | void js_std_dump_error(JSContext *ctx); 46 | uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); 47 | int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, 48 | bool use_realpath, bool is_main); 49 | JSModuleDef *js_module_loader(JSContext *ctx, 50 | const char *module_name, void *opaque); 51 | void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, 52 | int flags); 53 | void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, 54 | JSValueConst reason, 55 | bool is_handled, void *opaque); 56 | void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); 57 | 58 | #ifdef __cplusplus 59 | } /* extern "C" { */ 60 | #endif 61 | 62 | #endif /* QUICKJS_LIBC_H */ 63 | -------------------------------------------------------------------------------- /gen/test_fib.c: -------------------------------------------------------------------------------- 1 | /* File generated automatically by the QuickJS-ng compiler. */ 2 | 3 | #include "quickjs-libc.h" 4 | 5 | const uint32_t qjsc_test_fib_size = 294; 6 | 7 | const uint8_t qjsc_test_fib[294] = { 8 | 0x14, 0x0e, 0x01, 0x28, 0x65, 0x78, 0x61, 0x6d, 9 | 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 10 | 0x74, 0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 11 | 0x01, 0x0c, 0x71, 0x6a, 0x73, 0x3a, 0x6f, 0x73, 12 | 0x01, 0x04, 0x6f, 0x73, 0x01, 0x0a, 0x69, 0x73, 13 | 0x57, 0x69, 0x6e, 0x01, 0x06, 0x66, 0x69, 0x62, 14 | 0x01, 0x10, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 15 | 0x72, 0x6d, 0x01, 0x0a, 0x77, 0x69, 0x6e, 0x33, 16 | 0x32, 0x01, 0x0c, 0x2e, 0x2f, 0x66, 0x69, 0x62, 17 | 0x2e, 0x01, 0x06, 0x64, 0x6c, 0x6c, 0x01, 0x04, 18 | 0x73, 0x6f, 0x01, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 19 | 0x6f, 0x6c, 0x65, 0x01, 0x06, 0x6c, 0x6f, 0x67, 20 | 0x01, 0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 21 | 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x01, 0x10, 0x66, 22 | 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 23 | 0xc2, 0x03, 0x01, 0xc4, 0x03, 0x00, 0x00, 0x01, 24 | 0x00, 0xfe, 0x01, 0x00, 0x01, 0x0c, 0x20, 0x0a, 25 | 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 26 | 0x00, 0x73, 0x00, 0xc6, 0x03, 0x00, 0x0d, 0xc8, 27 | 0x03, 0x00, 0x0d, 0xca, 0x03, 0x01, 0x0d, 0x08, 28 | 0xec, 0x02, 0x29, 0x66, 0x00, 0x00, 0x42, 0xe6, 29 | 0x00, 0x00, 0x00, 0x04, 0xe7, 0x00, 0x00, 0x00, 30 | 0xaf, 0xe4, 0x06, 0x11, 0xf4, 0xed, 0x0b, 0x71, 31 | 0x43, 0xe5, 0x00, 0x00, 0x00, 0xe5, 0x0e, 0xee, 32 | 0x24, 0x0e, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x43, 33 | 0x5d, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0xec, 34 | 0x08, 0x04, 0xe9, 0x00, 0x00, 0x00, 0xee, 0x06, 35 | 0x04, 0xea, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 36 | 0x36, 0x8c, 0xee, 0xd4, 0x39, 0xeb, 0x00, 0x00, 37 | 0x00, 0x43, 0xec, 0x00, 0x00, 0x00, 0x04, 0xed, 38 | 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x39, 39 | 0xeb, 0x00, 0x00, 0x00, 0x43, 0xec, 0x00, 0x00, 40 | 0x00, 0x04, 0xee, 0x00, 0x00, 0x00, 0x66, 0x02, 41 | 0x00, 0xbe, 0x0a, 0xf1, 0x24, 0x02, 0x00, 0x0e, 42 | 0x06, 0x2f, 0xc2, 0x03, 0x01, 0x01, 0x0e, 0x41, 43 | 0x3c, 0x00, 0x39, 0x06, 0x3b, 0x34, 0x10, 0x30, 44 | 0x0f, 0x34, 0x10, 0x2a, 0x20, 0x00, 45 | }; 46 | 47 | static JSContext *JS_NewCustomContext(JSRuntime *rt) 48 | { 49 | JSContext *ctx = JS_NewContext(rt); 50 | if (!ctx) 51 | return NULL; 52 | { 53 | extern JSModuleDef *js_init_module_os(JSContext *ctx, const char *name); 54 | js_init_module_os(ctx, "qjs:os"); 55 | } 56 | return ctx; 57 | } 58 | 59 | int main(int argc, char **argv) 60 | { 61 | int r; 62 | JSRuntime *rt; 63 | JSContext *ctx; 64 | r = 0; 65 | rt = JS_NewRuntime(); 66 | js_std_set_worker_new_context_func(JS_NewCustomContext); 67 | js_std_init_handlers(rt); 68 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 69 | ctx = JS_NewCustomContext(rt); 70 | js_std_add_helpers(ctx, argc, argv); 71 | js_std_eval_binary(ctx, qjsc_test_fib, qjsc_test_fib_size, 0); 72 | r = js_std_loop(ctx); 73 | if (r) { 74 | js_std_dump_error(ctx); 75 | } 76 | js_std_free_handlers(rt); 77 | JS_FreeContext(ctx); 78 | JS_FreeRuntime(rt); 79 | return r; 80 | } 81 | -------------------------------------------------------------------------------- /gen/function_source.c: -------------------------------------------------------------------------------- 1 | /* File generated automatically by the QuickJS-ng compiler. */ 2 | 3 | #include "quickjs-libc.h" 4 | 5 | const uint32_t qjsc_function_source_size = 324; 6 | 7 | const uint8_t qjsc_function_source[324] = { 8 | 0x14, 0x05, 0x01, 0x30, 0x74, 0x65, 0x73, 0x74, 9 | 0x73, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 10 | 0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 11 | 0x65, 0x2e, 0x6a, 0x73, 0x01, 0x0c, 0x61, 0x63, 12 | 0x74, 0x75, 0x61, 0x6c, 0x01, 0x02, 0x66, 0x01, 13 | 0x0c, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x01, 14 | 0x34, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 15 | 0x6e, 0x20, 0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, 16 | 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, 17 | 0x32, 0x20, 0x7d, 0x0d, 0xc2, 0x03, 0x00, 0x00, 18 | 0x00, 0x00, 0x00, 0x0c, 0x20, 0x0a, 0x01, 0xa2, 19 | 0x01, 0x00, 0x05, 0x00, 0x03, 0x02, 0x01, 0x74, 20 | 0x05, 0xc4, 0x03, 0x02, 0x00, 0x30, 0xc6, 0x03, 21 | 0x04, 0x00, 0x70, 0xc4, 0x03, 0x04, 0x02, 0x70, 22 | 0x10, 0x00, 0x01, 0x00, 0xe4, 0x01, 0x00, 0x01, 23 | 0x00, 0xc8, 0x03, 0x00, 0x0d, 0xc6, 0x03, 0x01, 24 | 0x01, 0x0c, 0x43, 0x0a, 0x01, 0xc6, 0x03, 0x00, 25 | 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0xbe, 26 | 0x2a, 0x28, 0xc2, 0x03, 0x03, 0x01, 0x00, 0x1a, 27 | 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 28 | 0x20, 0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, 0x72, 29 | 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, 0x32, 30 | 0x20, 0x7d, 0x0c, 0x03, 0xc4, 0x04, 0x08, 0xce, 31 | 0x08, 0xec, 0x05, 0xc1, 0x00, 0xe4, 0x29, 0x04, 32 | 0xe5, 0x00, 0x00, 0x00, 0xe3, 0x62, 0x00, 0x00, 33 | 0xe0, 0x43, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 34 | 0x00, 0xcb, 0x63, 0x00, 0x00, 0x66, 0x00, 0x00, 35 | 0xb0, 0xec, 0x0b, 0x39, 0x96, 0x00, 0x00, 0x00, 36 | 0x63, 0x00, 0x00, 0xf1, 0x30, 0x62, 0x02, 0x00, 37 | 0x62, 0x01, 0x00, 0x39, 0x3b, 0x00, 0x00, 0x00, 38 | 0x66, 0x00, 0x00, 0x04, 0xe3, 0x00, 0x00, 0x00, 39 | 0x9e, 0x32, 0x01, 0x00, 0x03, 0x00, 0xcc, 0x63, 40 | 0x01, 0x00, 0x43, 0x38, 0x00, 0x00, 0x00, 0x24, 41 | 0x00, 0x00, 0xcd, 0x63, 0x02, 0x00, 0x66, 0x00, 42 | 0x00, 0xb0, 0xec, 0x0b, 0x39, 0x96, 0x00, 0x00, 43 | 0x00, 0x63, 0x02, 0x00, 0xf1, 0x30, 0x69, 0x02, 44 | 0x00, 0x69, 0x01, 0x00, 0x06, 0x2f, 0xc2, 0x03, 45 | 0x01, 0x01, 0x18, 0x00, 0x1c, 0x0a, 0x2a, 0x26, 46 | 0x03, 0x20, 0x1c, 0x1b, 0x0c, 0x00, 0x10, 0x08, 47 | 0x27, 0x11, 0x12, 0x67, 0x0d, 0x26, 0x03, 0x20, 48 | 0x1c, 0x1b, 0x0c, 0x00, 49 | }; 50 | 51 | static JSContext *JS_NewCustomContext(JSRuntime *rt) 52 | { 53 | JSContext *ctx = JS_NewContext(rt); 54 | if (!ctx) 55 | return NULL; 56 | return ctx; 57 | } 58 | 59 | int main(int argc, char **argv) 60 | { 61 | int r; 62 | JSRuntime *rt; 63 | JSContext *ctx; 64 | r = 0; 65 | rt = JS_NewRuntime(); 66 | js_std_set_worker_new_context_func(JS_NewCustomContext); 67 | js_std_init_handlers(rt); 68 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 69 | ctx = JS_NewCustomContext(rt); 70 | js_std_add_helpers(ctx, argc, argv); 71 | js_std_eval_binary(ctx, qjsc_function_source, qjsc_function_source_size, 0); 72 | r = js_std_loop(ctx); 73 | if (r) { 74 | js_std_dump_error(ctx); 75 | } 76 | js_std_free_handlers(rt); 77 | JS_FreeContext(ctx); 78 | JS_FreeRuntime(rt); 79 | return r; 80 | } 81 | -------------------------------------------------------------------------------- /examples/pi_bigint.js: -------------------------------------------------------------------------------- 1 | /* 2 | * PI computation in Javascript using the BigInt type 3 | */ 4 | "use strict"; 5 | 6 | /* return floor(log2(a)) for a > 0 and 0 for a = 0 */ 7 | function floor_log2(a) 8 | { 9 | var k_max, a1, k, i; 10 | k_max = 0n; 11 | while ((a >> (2n ** k_max)) != 0n) { 12 | k_max++; 13 | } 14 | k = 0n; 15 | a1 = a; 16 | for(i = k_max - 1n; i >= 0n; i--) { 17 | a1 = a >> (2n ** i); 18 | if (a1 != 0n) { 19 | a = a1; 20 | k |= (1n << i); 21 | } 22 | } 23 | return k; 24 | } 25 | 26 | /* return ceil(log2(a)) for a > 0 */ 27 | function ceil_log2(a) 28 | { 29 | return floor_log2(a - 1n) + 1n; 30 | } 31 | 32 | /* return floor(sqrt(a)) (not efficient but simple) */ 33 | function int_sqrt(a) 34 | { 35 | var l, u, s; 36 | if (a == 0n) 37 | return a; 38 | l = ceil_log2(a); 39 | u = 1n << ((l + 1n) / 2n); 40 | /* u >= floor(sqrt(a)) */ 41 | for(;;) { 42 | s = u; 43 | u = ((a / s) + s) / 2n; 44 | if (u >= s) 45 | break; 46 | } 47 | return s; 48 | } 49 | 50 | /* return pi * 2**prec */ 51 | function calc_pi(prec) { 52 | const CHUD_A = 13591409n; 53 | const CHUD_B = 545140134n; 54 | const CHUD_C = 640320n; 55 | const CHUD_C3 = 10939058860032000n; /* C^3/24 */ 56 | const CHUD_BITS_PER_TERM = 47.11041313821584202247; /* log2(C/12)*3 */ 57 | 58 | /* return [P, Q, G] */ 59 | function chud_bs(a, b, need_G) { 60 | var c, P, Q, G, P1, Q1, G1, P2, Q2, G2; 61 | if (a == (b - 1n)) { 62 | G = (2n * b - 1n) * (6n * b - 1n) * (6n * b - 5n); 63 | P = G * (CHUD_B * b + CHUD_A); 64 | if (b & 1n) 65 | P = -P; 66 | Q = b * b * b * CHUD_C3; 67 | } else { 68 | c = (a + b) >> 1n; 69 | [P1, Q1, G1] = chud_bs(a, c, true); 70 | [P2, Q2, G2] = chud_bs(c, b, need_G); 71 | P = P1 * Q2 + P2 * G1; 72 | Q = Q1 * Q2; 73 | if (need_G) 74 | G = G1 * G2; 75 | else 76 | G = 0n; 77 | } 78 | return [P, Q, G]; 79 | } 80 | 81 | var n, P, Q, G; 82 | /* number of serie terms */ 83 | n = BigInt(Math.ceil(Number(prec) / CHUD_BITS_PER_TERM)) + 10n; 84 | [P, Q, G] = chud_bs(0n, n, false); 85 | Q = (CHUD_C / 12n) * (Q << prec) / (P + Q * CHUD_A); 86 | G = int_sqrt(CHUD_C << (2n * prec)); 87 | return (Q * G) >> prec; 88 | } 89 | 90 | function main(args) { 91 | var r, n_digits, n_bits, out; 92 | if (args.length < 1) { 93 | print("usage: pi n_digits"); 94 | return; 95 | } 96 | n_digits = args[0] | 0; 97 | 98 | /* we add more bits to reduce the probability of bad rounding for 99 | the last digits */ 100 | n_bits = BigInt(Math.ceil(n_digits * Math.log2(10))) + 32n; 101 | r = calc_pi(n_bits); 102 | r = ((10n ** BigInt(n_digits)) * r) >> n_bits; 103 | out = r.toString(); 104 | print(out[0] + "." + out.slice(1)); 105 | } 106 | 107 | var args; 108 | if (typeof scriptArgs != "undefined") { 109 | args = scriptArgs; 110 | args.shift(); 111 | } else if (typeof arguments != "undefined") { 112 | args = arguments; 113 | } else { 114 | /* default: 1000 digits */ 115 | args=[1000]; 116 | } 117 | 118 | main(args); 119 | -------------------------------------------------------------------------------- /list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Linux klist like system 3 | * 4 | * Copyright (c) 2016-2017 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIST_H 25 | #define LIST_H 26 | 27 | #ifndef NULL 28 | #include 29 | #endif 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | struct list_head { 36 | struct list_head *prev; 37 | struct list_head *next; 38 | }; 39 | 40 | #define LIST_HEAD_INIT(el) { &(el), &(el) } 41 | 42 | /* return the pointer of type 'type *' containing 'el' as field 'member' */ 43 | #define list_entry(el, type, member) container_of(el, type, member) 44 | 45 | static inline void init_list_head(struct list_head *head) 46 | { 47 | head->prev = head; 48 | head->next = head; 49 | } 50 | 51 | /* insert 'el' between 'prev' and 'next' */ 52 | static inline void __list_add(struct list_head *el, 53 | struct list_head *prev, struct list_head *next) 54 | { 55 | prev->next = el; 56 | el->prev = prev; 57 | el->next = next; 58 | next->prev = el; 59 | } 60 | 61 | /* add 'el' at the head of the list 'head' (= after element head) */ 62 | static inline void list_add(struct list_head *el, struct list_head *head) 63 | { 64 | __list_add(el, head, head->next); 65 | } 66 | 67 | /* add 'el' at the end of the list 'head' (= before element head) */ 68 | static inline void list_add_tail(struct list_head *el, struct list_head *head) 69 | { 70 | __list_add(el, head->prev, head); 71 | } 72 | 73 | static inline void list_del(struct list_head *el) 74 | { 75 | struct list_head *prev, *next; 76 | prev = el->prev; 77 | next = el->next; 78 | prev->next = next; 79 | next->prev = prev; 80 | el->prev = NULL; /* fail safe */ 81 | el->next = NULL; /* fail safe */ 82 | } 83 | 84 | static inline int list_empty(struct list_head *el) 85 | { 86 | return el->next == el; 87 | } 88 | 89 | #define list_for_each(el, head) \ 90 | for(el = (head)->next; el != (head); el = el->next) 91 | 92 | #define list_for_each_safe(el, el1, head) \ 93 | for(el = (head)->next, el1 = el->next; el != (head); \ 94 | el = el1, el1 = el->next) 95 | 96 | #define list_for_each_prev(el, head) \ 97 | for(el = (head)->prev; el != (head); el = el->prev) 98 | 99 | #define list_for_each_prev_safe(el, el1, head) \ 100 | for(el = (head)->prev, el1 = el->prev; el != (head); \ 101 | el = el1, el1 = el->prev) 102 | 103 | #ifdef __cplusplus 104 | } /* extern "C" { */ 105 | #endif 106 | 107 | #endif /* LIST_H */ 108 | -------------------------------------------------------------------------------- /libregexp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Regular Expression Engine 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBREGEXP_H 25 | #define LIBREGEXP_H 26 | 27 | #include 28 | #include 29 | 30 | #include "libunicode.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | #define LRE_FLAG_GLOBAL (1 << 0) 37 | #define LRE_FLAG_IGNORECASE (1 << 1) 38 | #define LRE_FLAG_MULTILINE (1 << 2) 39 | #define LRE_FLAG_DOTALL (1 << 3) 40 | #define LRE_FLAG_UNICODE (1 << 4) 41 | #define LRE_FLAG_STICKY (1 << 5) 42 | #define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */ 43 | #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ 44 | #define LRE_FLAG_UNICODE_SETS (1 << 8) 45 | 46 | #define LRE_RET_MEMORY_ERROR (-1) 47 | #define LRE_RET_TIMEOUT (-2) 48 | 49 | uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, 50 | const char *buf, size_t buf_len, int re_flags, 51 | void *opaque); 52 | int lre_get_capture_count(const uint8_t *bc_buf); 53 | int lre_get_flags(const uint8_t *bc_buf); 54 | const char *lre_get_groupnames(const uint8_t *bc_buf); 55 | int lre_exec(uint8_t **capture, 56 | const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen, 57 | int cbuf_type, void *opaque); 58 | 59 | int lre_parse_escape(const uint8_t **pp, int allow_utf16); 60 | bool lre_is_space(int c); 61 | 62 | void lre_byte_swap(uint8_t *buf, size_t len, bool is_byte_swapped); 63 | 64 | /* must be provided by the user */ 65 | bool lre_check_stack_overflow(void *opaque, size_t alloca_size); 66 | /* must be provided by the user, return non zero if time out */ 67 | int lre_check_timeout(void *opaque); 68 | void *lre_realloc(void *opaque, void *ptr, size_t size); 69 | 70 | /* JS identifier test */ 71 | extern uint32_t const lre_id_start_table_ascii[4]; 72 | extern uint32_t const lre_id_continue_table_ascii[4]; 73 | 74 | static inline int lre_js_is_ident_first(int c) 75 | { 76 | if ((uint32_t)c < 128) { 77 | return (lre_id_start_table_ascii[c >> 5] >> (c & 31)) & 1; 78 | } else { 79 | return lre_is_id_start(c); 80 | } 81 | } 82 | 83 | static inline int lre_js_is_ident_next(int c) 84 | { 85 | if ((uint32_t)c < 128) { 86 | return (lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1; 87 | } else { 88 | /* ZWNJ and ZWJ are accepted in identifiers */ 89 | return lre_is_id_continue(c) || c == 0x200C || c == 0x200D; 90 | } 91 | } 92 | 93 | #ifdef __cplusplus 94 | } /* extern "C" { */ 95 | #endif 96 | 97 | #endif /* LIBREGEXP_H */ 98 | -------------------------------------------------------------------------------- /docs/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // `@type` JSDoc annotations allow editor autocompletion and type checking 3 | // (when paired with `@ts-check`). 4 | // There are various equivalent ways to declare your Docusaurus config. 5 | // See: https://docusaurus.io/docs/api/docusaurus-config 6 | 7 | /** @type {import('@docusaurus/types').Config} */ 8 | const config = { 9 | title: 'QuickJS-NG', 10 | tagline: 'QuickJS, the Next Generation: a mighty JavaScript engine', 11 | favicon: 'img/favicon.ico', 12 | 13 | // Set the production url of your site here 14 | url: 'https://quickjs-ng.github.io', 15 | // Set the // pathname under which your site is served 16 | // For GitHub pages deployment, it is often '//' 17 | baseUrl: '/quickjs/', 18 | 19 | // GitHub pages deployment config. 20 | // If you aren't using GitHub pages, you don't need these. 21 | organizationName: 'quickjs-ng', // Usually your GitHub org/user name. 22 | projectName: 'quickjs', // Usually your repo name. 23 | 24 | onBrokenLinks: 'throw', 25 | onBrokenMarkdownLinks: 'throw', 26 | 27 | // Even if you don't use internationalization, you can use this field to set 28 | // useful metadata like html lang. For example, if your site is Chinese, you 29 | // may want to replace "en" with "zh-Hans". 30 | i18n: { 31 | defaultLocale: 'en', 32 | locales: ['en'], 33 | }, 34 | 35 | presets: [ 36 | [ 37 | 'classic', 38 | /** @type {import('@docusaurus/preset-classic').Options} */ 39 | ({ 40 | docs: { 41 | routeBasePath: '/', 42 | sidebarPath: './sidebars.js', 43 | // Please change this to your repo. 44 | // Remove this to remove the "edit this page" links. 45 | editUrl: 'https://github.com/quickjs-ng/quickjs/tree/master/docs/', 46 | }, 47 | blog: false, 48 | theme: { 49 | customCss: './src/css/custom.css', 50 | }, 51 | }), 52 | ], 53 | ], 54 | 55 | themeConfig: 56 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 57 | ({ 58 | // Replace with your project's social card 59 | image: 'img/docusaurus-social-card.jpg', 60 | navbar: { 61 | title: 'QuickJS-NG', 62 | items: [ 63 | { 64 | type: 'docSidebar', 65 | sidebarId: 'docsSidebar', 66 | position: 'left', 67 | label: 'Documentation', 68 | }, 69 | { 70 | href: 'https://github.com/quickjs-ng/quickjs', 71 | label: 'GitHub', 72 | position: 'right', 73 | }, 74 | ], 75 | }, 76 | footer: { 77 | style: 'dark', 78 | links: [ 79 | { 80 | title: 'Docs', 81 | items: [ 82 | ], 83 | }, 84 | { 85 | title: 'Community', 86 | items: [ 87 | { 88 | label: 'GitHub Discussions', 89 | href: 'https://github.com/quickjs-ng/quickjs/discussions', 90 | }, 91 | { 92 | label: 'Matrix', 93 | href: 'https://matrix.to/#/%23quickjs-ng%3Amatrix.org?via=matrix.org', 94 | }, 95 | ], 96 | }, 97 | { 98 | title: 'More', 99 | items: [ 100 | { 101 | label: 'GitHub', 102 | href: 'https://github.com/quickjs-ng/quickjs', 103 | }, 104 | ], 105 | }, 106 | ], 107 | copyright: `Copyright © ${new Date().getFullYear()} QuickJS-NG project contributors.`, 108 | }, 109 | prism: { 110 | }, 111 | }), 112 | }; 113 | 114 | export default config; 115 | -------------------------------------------------------------------------------- /libunicode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Unicode utilities 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #ifndef LIBUNICODE_H 25 | #define LIBUNICODE_H 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #define LRE_CC_RES_LEN_MAX 3 36 | 37 | typedef enum { 38 | UNICODE_NFC, 39 | UNICODE_NFD, 40 | UNICODE_NFKC, 41 | UNICODE_NFKD, 42 | } UnicodeNormalizationEnum; 43 | 44 | int lre_case_conv(uint32_t *res, uint32_t c, int conv_type); 45 | int lre_canonicalize(uint32_t c, bool is_unicode); 46 | bool lre_is_cased(uint32_t c); 47 | bool lre_is_case_ignorable(uint32_t c); 48 | 49 | /* char ranges */ 50 | 51 | typedef struct { 52 | int len; /* in points, always even */ 53 | int size; 54 | uint32_t *points; /* points sorted by increasing value */ 55 | void *mem_opaque; 56 | void *(*realloc_func)(void *opaque, void *ptr, size_t size); 57 | } CharRange; 58 | 59 | typedef enum { 60 | CR_OP_UNION, 61 | CR_OP_INTER, 62 | CR_OP_XOR, 63 | } CharRangeOpEnum; 64 | 65 | void cr_init(CharRange *cr, void *mem_opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 66 | void cr_free(CharRange *cr); 67 | int cr_realloc(CharRange *cr, int size); 68 | int cr_copy(CharRange *cr, const CharRange *cr1); 69 | 70 | static inline int cr_add_point(CharRange *cr, uint32_t v) 71 | { 72 | if (cr->len >= cr->size) { 73 | if (cr_realloc(cr, cr->len + 1)) 74 | return -1; 75 | } 76 | cr->points[cr->len++] = v; 77 | return 0; 78 | } 79 | 80 | static inline int cr_add_interval(CharRange *cr, uint32_t c1, uint32_t c2) 81 | { 82 | if ((cr->len + 2) > cr->size) { 83 | if (cr_realloc(cr, cr->len + 2)) 84 | return -1; 85 | } 86 | cr->points[cr->len++] = c1; 87 | cr->points[cr->len++] = c2; 88 | return 0; 89 | } 90 | 91 | int cr_union1(CharRange *cr, const uint32_t *b_pt, int b_len); 92 | 93 | static inline int cr_union_interval(CharRange *cr, uint32_t c1, uint32_t c2) 94 | { 95 | uint32_t b_pt[2]; 96 | b_pt[0] = c1; 97 | b_pt[1] = c2 + 1; 98 | return cr_union1(cr, b_pt, 2); 99 | } 100 | 101 | int cr_op(CharRange *cr, const uint32_t *a_pt, int a_len, 102 | const uint32_t *b_pt, int b_len, int op); 103 | 104 | int cr_invert(CharRange *cr); 105 | int cr_regexp_canonicalize(CharRange *cr, bool is_unicode); 106 | 107 | bool lre_is_id_start(uint32_t c); 108 | bool lre_is_id_continue(uint32_t c); 109 | bool lre_is_white_space(uint32_t c); 110 | 111 | int unicode_normalize(uint32_t **pdst, const uint32_t *src, int src_len, 112 | UnicodeNormalizationEnum n_type, 113 | void *opaque, void *(*realloc_func)(void *opaque, void *ptr, size_t size)); 114 | 115 | /* Unicode character range functions */ 116 | 117 | int unicode_script(CharRange *cr, 118 | const char *script_name, bool is_ext); 119 | int unicode_general_category(CharRange *cr, const char *gc_name); 120 | int unicode_prop(CharRange *cr, const char *prop_name); 121 | 122 | #ifdef __cplusplus 123 | } /* extern "C" { */ 124 | #endif 125 | 126 | #endif /* LIBUNICODE_H */ 127 | -------------------------------------------------------------------------------- /standalone.js: -------------------------------------------------------------------------------- 1 | import * as std from "qjs:std"; 2 | import * as os from "qjs:os"; 3 | import * as bjson from "qjs:bjson"; 4 | 5 | // See quickjs.h 6 | const JS_READ_OBJ_BYTECODE = 1 << 0; 7 | const JS_READ_OBJ_REFERENCE = 1 << 3; 8 | const JS_WRITE_OBJ_BYTECODE = 1 << 0; 9 | const JS_WRITE_OBJ_REFERENCE = 1 << 3; 10 | const JS_WRITE_OBJ_STRIP_SOURCE = 1 << 4; 11 | 12 | /** 13 | * Trailer for standalone binaries. When some code gets bundled with the qjs 14 | * executable we add a 12 byte trailer. The first 8 bytes are the magic 15 | * string that helps us understand this is a standalone binary, and the 16 | * remaining 4 are the offset (from the beginning of the binary) where the 17 | * bundled data is located. 18 | * 19 | * The offset is stored as a 32bit little-endian number. 20 | */ 21 | const Trailer = { 22 | Magic: 'quickjs2', 23 | MagicSize: 8, 24 | DataSize: 4, 25 | Size: 12 26 | }; 27 | 28 | function encodeAscii(txt) { 29 | return new Uint8Array(txt.split('').map(c => c.charCodeAt(0))); 30 | } 31 | 32 | function decodeAscii(buf) { 33 | return Array.from(buf).map(c => String.fromCharCode(c)).join('') 34 | } 35 | 36 | export function compileStandalone(inFile, outFile, targetExe) { 37 | // Step 1: compile the source file to bytecode 38 | const js = std.loadFile(inFile); 39 | 40 | if (!js) { 41 | throw new Error(`failed to open ${inFile}`); 42 | } 43 | 44 | const code = std.evalScript(js, { 45 | compile_only: true, 46 | compile_module: true 47 | }); 48 | const bytecode = new Uint8Array(bjson.write(code, JS_WRITE_OBJ_BYTECODE | JS_WRITE_OBJ_REFERENCE | JS_WRITE_OBJ_STRIP_SOURCE)); 49 | 50 | // Step 2: copy the bytecode to the end of the executable and add a marker. 51 | const exeFileName = targetExe ?? os.exePath() ?? globalThis.argv0; 52 | const exe = std.loadFile(exeFileName, { binary: true }); 53 | 54 | if (!exe) { 55 | throw new Error(`failed to open executable: ${exeFileName}`); 56 | } 57 | 58 | const exeSize = exe.length; 59 | const newBuffer = exe.buffer.transfer(exeSize + bytecode.length + Trailer.Size); 60 | const newExe = new Uint8Array(newBuffer); 61 | 62 | newExe.set(bytecode, exeSize); 63 | newExe.set(encodeAscii(Trailer.Magic), exeSize + bytecode.length); 64 | 65 | const dw = new DataView(newBuffer, exeSize + bytecode.length + Trailer.MagicSize, Trailer.DataSize); 66 | 67 | dw.setUint32(0, exeSize, true /* little-endian */); 68 | 69 | // We use os.open() so we can set the permissions mask. 70 | const newFd = os.open(outFile, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o755); 71 | 72 | if (newFd < 0) { 73 | throw new Error(`failed to create ${outFile}`); 74 | } 75 | if (os.write(newFd, newBuffer, 0, newBuffer.byteLength) < 0) { 76 | os.close(newFd); 77 | throw new Error(`failed to write to output file`); 78 | } 79 | os.close(newFd); 80 | } 81 | 82 | export function runStandalone() { 83 | const file = os.exePath() ?? globalThis.argv0; 84 | const exe = std.open(file, 'rb'); 85 | 86 | if (!exe) { 87 | throw new Error(`failed to open executable: ${file}`); 88 | } 89 | 90 | let r = exe.seek(-Trailer.Size, std.SEEK_END); 91 | if (r < 0) { 92 | throw new Error(`seek error: ${-r}`); 93 | } 94 | 95 | const trailer = new Uint8Array(Trailer.Size); 96 | 97 | exe.read(trailer.buffer, 0, Trailer.Size); 98 | 99 | const magic = new Uint8Array(trailer.buffer, 0, Trailer.MagicSize); 100 | 101 | // Shouldn't happen since qjs.c checks for it. 102 | if (decodeAscii(magic) !== Trailer.Magic) { 103 | exe.close(); 104 | throw new Error('corrupted binary, magic mismatch'); 105 | } 106 | 107 | const dw = new DataView(trailer.buffer, Trailer.MagicSize, Trailer.DataSize); 108 | const offset = dw.getUint32(0, true /* little-endian */); 109 | const bytecode = new Uint8Array(offset - Trailer.Size); 110 | 111 | r = exe.seek(offset, std.SEEK_SET); 112 | if (r < 0) { 113 | exe.close(); 114 | throw new Error(`seek error: ${-r}`); 115 | } 116 | 117 | exe.read(bytecode.buffer, 0, bytecode.length); 118 | if (exe.error()) { 119 | exe.close(); 120 | throw new Error('read error'); 121 | } 122 | exe.close(); 123 | 124 | const code = bjson.read(bytecode.buffer, 0, bytecode.length, JS_READ_OBJ_BYTECODE | JS_READ_OBJ_REFERENCE); 125 | 126 | return std.evalScript(code, { 127 | eval_module: true 128 | }); 129 | } 130 | -------------------------------------------------------------------------------- /gen/hello_module.c: -------------------------------------------------------------------------------- 1 | /* File generated automatically by the QuickJS-ng compiler. */ 2 | 3 | #include "quickjs-libc.h" 4 | 5 | const uint32_t qjsc_fib_module_size = 290; 6 | 7 | const uint8_t qjsc_fib_module[290] = { 8 | 0x14, 0x03, 0x01, 0x2c, 0x65, 0x78, 0x61, 0x6d, 9 | 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x62, 10 | 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 11 | 0x6a, 0x73, 0x01, 0x06, 0x66, 0x69, 0x62, 0x01, 12 | 0x02, 0x6e, 0x0d, 0xc2, 0x03, 0x00, 0x01, 0x00, 13 | 0x00, 0xc4, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x20, 14 | 0x0a, 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x01, 15 | 0x01, 0x01, 0x09, 0x00, 0xc4, 0x03, 0x00, 0x01, 16 | 0x0c, 0x43, 0x0a, 0x01, 0xc4, 0x03, 0x01, 0x00, 17 | 0x01, 0x04, 0x01, 0x00, 0x1a, 0x01, 0xc6, 0x03, 18 | 0x00, 0x01, 0x00, 0xc4, 0x03, 0x00, 0x00, 0xd3, 19 | 0xb6, 0xa8, 0xec, 0x03, 0xb6, 0x28, 0xd3, 0xb7, 20 | 0xad, 0xec, 0x03, 0xb7, 0x28, 0xdf, 0xd3, 0xb7, 21 | 0x9f, 0xf1, 0xdf, 0xd3, 0xb8, 0x9f, 0xf1, 0x9e, 22 | 0x28, 0xc2, 0x03, 0x02, 0x08, 0x0e, 0x09, 0x0c, 23 | 0x27, 0x0a, 0x28, 0x02, 0x07, 0x08, 0x11, 0x0a, 24 | 0x07, 0x08, 0x07, 0x08, 0x8d, 0x01, 0x66, 0x75, 25 | 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 26 | 0x69, 0x62, 0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a, 27 | 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 28 | 0x6e, 0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a, 29 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 30 | 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 31 | 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 32 | 0x73, 0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 33 | 0x20, 0x3d, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, 34 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 35 | 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, 36 | 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 37 | 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 38 | 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 39 | 0x20, 0x66, 0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d, 40 | 0x20, 0x31, 0x29, 0x20, 0x2b, 0x20, 0x66, 0x69, 41 | 0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29, 42 | 0x3b, 0x0a, 0x7d, 0x08, 0xec, 0x05, 0xc1, 0x00, 43 | 0xe3, 0x29, 0x06, 0x2f, 0xc2, 0x03, 0x01, 0x01, 44 | 0x00, 0x00, 45 | }; 46 | 47 | const uint32_t qjsc_hello_module_size = 187; 48 | 49 | const uint8_t qjsc_hello_module[187] = { 50 | 0x14, 0x07, 0x01, 0x30, 0x65, 0x78, 0x61, 0x6d, 51 | 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 52 | 0x6c, 0x6f, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 53 | 0x65, 0x2e, 0x6a, 0x73, 0x01, 0x1e, 0x2e, 0x2f, 54 | 0x66, 0x69, 0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 55 | 0x6c, 0x65, 0x2e, 0x6a, 0x73, 0x01, 0x06, 0x66, 56 | 0x69, 0x62, 0x01, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 57 | 0x6f, 0x6c, 0x65, 0x01, 0x06, 0x6c, 0x6f, 0x67, 58 | 0x01, 0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 59 | 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x01, 0x10, 0x66, 60 | 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 61 | 0xc2, 0x03, 0x01, 0xc4, 0x03, 0x00, 0x00, 0x01, 62 | 0x00, 0xc6, 0x03, 0x00, 0x00, 0x0c, 0x20, 0x0a, 63 | 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x05, 0x01, 64 | 0x00, 0x32, 0x00, 0xc6, 0x03, 0x00, 0x0c, 0x08, 65 | 0xec, 0x02, 0x29, 0x39, 0xe4, 0x00, 0x00, 0x00, 66 | 0x43, 0xe5, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 67 | 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x39, 0xe4, 68 | 0x00, 0x00, 0x00, 0x43, 0xe5, 0x00, 0x00, 0x00, 69 | 0x04, 0xe7, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 70 | 0xbe, 0x0a, 0xf1, 0x24, 0x02, 0x00, 0x0e, 0x06, 71 | 0x2f, 0xc2, 0x03, 0x01, 0x01, 0x0c, 0x00, 0x04, 72 | 0x08, 0x00, 0x34, 0x10, 0x30, 0x0f, 0x34, 0x10, 73 | 0x2a, 0x20, 0x00, 74 | }; 75 | 76 | static JSContext *JS_NewCustomContext(JSRuntime *rt) 77 | { 78 | JSContext *ctx = JS_NewContext(rt); 79 | if (!ctx) 80 | return NULL; 81 | js_std_eval_binary(ctx, qjsc_fib_module, qjsc_fib_module_size, 1); 82 | return ctx; 83 | } 84 | 85 | int main(int argc, char **argv) 86 | { 87 | int r; 88 | JSRuntime *rt; 89 | JSContext *ctx; 90 | r = 0; 91 | rt = JS_NewRuntime(); 92 | js_std_set_worker_new_context_func(JS_NewCustomContext); 93 | js_std_init_handlers(rt); 94 | JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); 95 | ctx = JS_NewCustomContext(rt); 96 | js_std_add_helpers(ctx, argc, argv); 97 | js_std_eval_binary(ctx, qjsc_hello_module, qjsc_hello_module_size, 0); 98 | r = js_std_loop(ctx); 99 | if (r) { 100 | js_std_dump_error(ctx); 101 | } 102 | js_std_free_handlers(rt); 103 | JS_FreeContext(ctx); 104 | JS_FreeRuntime(rt); 105 | return r; 106 | } 107 | -------------------------------------------------------------------------------- /docs/docs/developer-guide/internals.md: -------------------------------------------------------------------------------- 1 | # Internals 2 | 3 | ## Bytecode 4 | 5 | The compiler generates bytecode directly with no intermediate 6 | representation such as a parse tree, hence it is very fast. Several 7 | optimizations passes are done over the generated bytecode. 8 | 9 | A stack-based bytecode was chosen because it is simple and generates 10 | compact code. 11 | 12 | For each function, the maximum stack size is computed at compile time so that 13 | no runtime stack overflow tests are needed. 14 | 15 | A separate compressed line number table is maintained for the debug 16 | information. 17 | 18 | Access to closure variables is optimized and is almost as fast as local 19 | variables. 20 | 21 | Direct `eval` in strict mode is optimized. 22 | 23 | ## Runtime 24 | 25 | ### Strings 26 | 27 | Strings are stored either as an 8 bit or a 16 bit array of 28 | characters. Hence random access to characters is always fast. 29 | 30 | The C API provides functions to convert JavaScript Strings to C UTF-8 encoded 31 | strings. The most common case where the JavaScript string contains 32 | only ASCII characters involves no copying. 33 | 34 | ### Objects 35 | 36 | The object shapes (object prototype, property names and flags) are shared 37 | between objects to save memory. 38 | 39 | Arrays with no holes (except at the end of the array) are optimized. 40 | 41 | TypedArray accesses are optimized. 42 | 43 | ### Atoms 44 | 45 | Object property names and some strings are stored as Atoms (unique 46 | strings) to save memory and allow fast comparison. Atoms are 47 | represented as a 32 bit integer. Half of the atom range is reserved for 48 | immediate integer literals from 0 to 2^31-1. 49 | 50 | ### Numbers 51 | 52 | Numbers are represented either as 32-bit signed integers or 64-bit IEEE-754 53 | floating point values. Most operations have fast paths for the 32-bit 54 | integer case. 55 | 56 | ### Garbage collection 57 | 58 | Reference counting is used to free objects automatically and 59 | deterministically. A separate cycle removal pass is done when the allocated 60 | memory becomes too large. The cycle removal algorithm only uses the 61 | reference counts and the object content, so no explicit garbage 62 | collection roots need to be manipulated in the C code. 63 | 64 | ### JSValue 65 | 66 | It is a JavaScript value which can be a primitive type (such as 67 | Number, String, ...) or an Object. NaN boxing is used in the 32-bit version 68 | to store 64-bit floating point numbers. The representation is 69 | optimized so that 32-bit integers and reference counted values can be 70 | efficiently tested. 71 | 72 | In 64-bit code, JSValue are 128-bit large and no NaN boxing is used. The 73 | rationale is that in 64-bit code memory usage is less critical. 74 | 75 | In both cases (32 or 64 bits), JSValue exactly fits two CPU registers, 76 | so it can be efficiently returned by C functions. 77 | 78 | ### Function call 79 | 80 | The engine is optimized so that function calls are fast. The system 81 | stack holds the JavaScript parameters and local variables. 82 | 83 | ### RegExp 84 | 85 | A specific regular expression engine was developed. It is both small 86 | and efficient and supports all the ES2020+ features including the 87 | Unicode properties. As the JavaScript compiler, it directly generates 88 | bytecode without a parse tree. 89 | 90 | Backtracking with an explicit stack is used so that there is no 91 | recursion on the system stack. Simple quantifiers are specifically 92 | optimized to avoid recursions. 93 | 94 | Infinite recursions coming from quantifiers with empty terms are 95 | avoided. 96 | 97 | The full regexp library weighs about 15 KiB (x86 code), excluding the 98 | Unicode library. 99 | 100 | ### Unicode 101 | 102 | A specific Unicode library was developed so that there is no 103 | dependency on an external large Unicode library such as ICU. All the 104 | Unicode tables are compressed while keeping a reasonable access 105 | speed. 106 | 107 | The library supports case conversion, Unicode normalization, Unicode 108 | script queries, Unicode general category queries and all Unicode 109 | binary properties. 110 | 111 | The full Unicode library weighs about 45 KiB (x86 code). 112 | 113 | ### BigInt 114 | 115 | BigInt is implemented with the [libbf](https://bellard.org/libbf) library. 116 | It weights about 90 KiB (x86 code) and provides arbitrary precision IEEE 754 floating 117 | point operations and transcendental functions with exact rounding. 118 | -------------------------------------------------------------------------------- /docs/docs/developer-guide/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # The QuickJS C API 6 | 7 | The C API was designed to be simple and efficient. The C API is 8 | defined in the header `quickjs.h`. 9 | 10 | ## Runtime and contexts 11 | 12 | `JSRuntime` represents a JavaScript runtime corresponding to an 13 | object heap. Several runtimes can exist at the same time but they 14 | cannot exchange objects. Inside a given runtime, no multi-threading is 15 | supported. 16 | 17 | `JSContext` represents a JavaScript context (or Realm). Each 18 | JSContext has its own global objects and system objects. There can be 19 | several JSContexts per JSRuntime and they can share objects, similar 20 | to frames of the same origin sharing JavaScript objects in a 21 | web browser. 22 | 23 | ## JSValue 24 | 25 | `JSValue` represents a JavaScript value which can be a primitive 26 | type or an object. Reference counting is used, so it is important to 27 | explicitly duplicate (`JS_DupValue()`, increment the reference 28 | count) or free (`JS_FreeValue()`, decrement the reference count) 29 | JSValues. 30 | 31 | ## C functions 32 | 33 | C functions can be created with 34 | `JS_NewCFunction()`. `JS_SetPropertyFunctionList()` is a 35 | shortcut to easily add functions, setters and getters properties to a 36 | given object. 37 | 38 | Unlike other embedded JavaScript engines, there is no implicit stack, 39 | so C functions get their parameters as normal C parameters. As a 40 | general rule, C functions take constant `JSValue`s as parameters 41 | (so they don't need to free them) and return a newly allocated (=live) 42 | `JSValue`. 43 | 44 | ## Exceptions 45 | 46 | Most C functions can return a JavaScript exception. It 47 | must be explicitly tested and handled by the C code. The specific 48 | `JSValue` `JS_EXCEPTION` indicates that an exception 49 | occurred. The actual exception object is stored in the 50 | `JSContext` and can be retrieved with `JS_GetException()`. 51 | 52 | ## Script evaluation 53 | 54 | Use `JS_Eval()` to evaluate a script or module source. 55 | 56 | If the script or module was compiled to bytecode with `qjsc`, it 57 | can be evaluated by calling `js_std_eval_binary()`. The advantage 58 | is that no compilation is needed so it is faster and smaller because 59 | the compiler can be removed from the executable if no `eval` is 60 | required. 61 | 62 | Note: the bytecode format is linked to a given QuickJS 63 | version. Moreover, no security check is done before its 64 | execution. Hence the bytecode should not be loaded from untrusted 65 | sources. 66 | 67 | ## JS Classes 68 | 69 | C opaque data can be attached to a JavaScript object. The type of the 70 | C opaque data is determined with the class ID (`JSClassID`) of 71 | the object. Hence the first step is to register a new class ID and JS 72 | class (`JS_NewClassID()`, `JS_NewClass()`). Then you can 73 | create objects of this class with `JS_NewObjectClass()` and get or 74 | set the C opaque point with `JS_GetOpaque()` / `JS_SetOpaque()`. 75 | 76 | When defining a new JS class, it is possible to declare a finalizer 77 | which is called when the object is destroyed. The finalizer should be 78 | used to release C resources. It is invalid to execute JS code from 79 | it. A `gc_mark` method can be provided so that the cycle removal 80 | algorithm can find the other objects referenced by this object. Other 81 | methods are available to define exotic object behaviors. 82 | 83 | The Class ID are allocated per-runtime. The 84 | `JSClass` are allocated per `JSRuntime`. `JS_SetClassProto()` 85 | is used to define a prototype for a given class in a given 86 | `JSContext`. `JS_NewObjectClass()` sets this prototype in the 87 | created object. 88 | 89 | Examples are available in `quickjs-libc.c`. 90 | 91 | ## C Modules 92 | 93 | Native ES6 modules are supported and can be dynamically or statically 94 | linked. The standard library `quickjs-libc.c` is a good example 95 | of a native module. 96 | 97 | ## Memory handling 98 | 99 | Use `JS_SetMemoryLimit()` to set a global memory allocation limit 100 | to a given `JSRuntime`. 101 | 102 | Custom memory allocation functions can be provided with `JS_NewRuntime2()`. 103 | 104 | The maximum system stack size can be set with `JS_SetMaxStackSize()`. 105 | 106 | ## Execution timeout and interrupts 107 | 108 | Use `JS_SetInterruptHandler()` to set a callback which is 109 | regularly called by the engine when it is executing code. This 110 | callback can be used to implement an execution timeout. 111 | 112 | It is used by the command line interpreter to implement a 113 | `Ctrl-C` handler. 114 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | pull_request: 5 | push: 6 | tags: 7 | - "v*.*.*" 8 | 9 | jobs: 10 | linux: 11 | runs-on: ubuntu-22.04 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | arch: [aarch64, riscv64, x86, x86_64] 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: jirutka/setup-alpine@v1 19 | with: 20 | arch: ${{matrix.arch}} 21 | packages: "build-base make cmake" 22 | - name: build 23 | shell: alpine.sh {0} 24 | run: | 25 | mkdir build 26 | cd build 27 | cmake -DQJS_BUILD_CLI_STATIC=ON .. 28 | cd .. 29 | cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN) 30 | cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN) 31 | mv build/qjs build/qjs-linux-${{matrix.arch}} 32 | mv build/qjsc build/qjsc-linux-${{matrix.arch}} 33 | - name: check 34 | shell: alpine.sh {0} 35 | run: | 36 | file build/*-linux-${{matrix.arch}} 37 | - name: upload 38 | uses: actions/upload-artifact@v4 39 | with: 40 | name: qjs-linux-${{matrix.arch}} 41 | path: build/*-linux-${{matrix.arch}} 42 | 43 | macos: 44 | runs-on: macos-latest 45 | steps: 46 | - uses: actions/checkout@v4 47 | - name: build 48 | run: | 49 | mkdir build 50 | cd build 51 | cmake -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" .. 52 | make -j$(getconf _NPROCESSORS_ONLN) 53 | make -C .. amalgam # writes build/quickjs-amalgam.zip 54 | mv qjs qjs-darwin 55 | mv qjsc qjsc-darwin 56 | - name: check 57 | run: | 58 | lipo -info build/qjs-darwin build/qjsc-darwin 59 | - name: upload amalgamation 60 | uses: actions/upload-artifact@v4 61 | with: 62 | name: quickjs-amalgam.zip 63 | path: build/quickjs-amalgam.zip 64 | compression-level: 0 # already compressed 65 | - name: upload 66 | uses: actions/upload-artifact@v4 67 | with: 68 | name: qjs-darwin 69 | path: build/*-darwin 70 | 71 | windows: 72 | runs-on: windows-latest 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | arch: [x86, x86_64] 77 | defaults: 78 | run: 79 | shell: msys2 {0} 80 | steps: 81 | - uses: actions/checkout@v4 82 | - name: Setup MSYS2 83 | uses: msys2/setup-msys2@v2 84 | with: 85 | msystem: ${{ matrix.arch == 'x86' && 'mingw32' || 'ucrt64' }} 86 | install: >- 87 | git 88 | make 89 | pacboy: >- 90 | cmake:p 91 | ninja:p 92 | toolchain:p 93 | - name: build 94 | run: | 95 | make 96 | mv build/qjs.exe build/qjs-windows-${{matrix.arch}}.exe 97 | mv build/qjsc.exe build/qjsc-windows-${{matrix.arch}}.exe 98 | - name: check 99 | run: | 100 | file build/qjs-windows-${{matrix.arch}}.exe 101 | ldd build/qjs-windows-${{matrix.arch}}.exe build/qjsc-windows-${{matrix.arch}}.exe 102 | - name: upload 103 | uses: actions/upload-artifact@v4 104 | with: 105 | name: qjs-windows-${{matrix.arch}} 106 | path: build/*-windows-${{matrix.arch}}.exe 107 | 108 | wasi: 109 | runs-on: ubuntu-22.04 110 | steps: 111 | - uses: actions/checkout@v4 112 | - name: setup wasi-sdk 113 | run: | 114 | wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-x86_64-linux.deb -P /tmp 115 | sudo apt install /tmp/wasi-sdk*.deb 116 | - name: build 117 | run: | 118 | cmake -B build -DCMAKE_TOOLCHAIN_FILE=/opt/wasi-sdk/share/cmake/wasi-sdk.cmake 119 | make -C build qjs_exe 120 | mv build/qjs build/qjs-wasi.wasm 121 | - name: upload 122 | uses: actions/upload-artifact@v4 123 | with: 124 | name: qjs-wasi 125 | path: build/qjs-wasi.wasm 126 | 127 | upload-to-release: 128 | needs: [linux, macos, windows, wasi] 129 | runs-on: ubuntu-22.04 130 | steps: 131 | - name: get assets 132 | uses: actions/download-artifact@v4 133 | with: 134 | path: build 135 | merge-multiple: true 136 | - run: ls -R build 137 | - name: release 138 | if: ${{ startsWith(github.ref, 'refs/tags/v') }} 139 | uses: softprops/action-gh-release@v1 140 | with: 141 | files: | 142 | build/* 143 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # QuickJS Javascript Engine 3 | # 4 | # Copyright (c) 2017-2024 Fabrice Bellard 5 | # Copyright (c) 2017-2024 Charlie Gordon 6 | # Copyright (c) 2023-2025 Ben Noordhuis 7 | # Copyright (c) 2023-2025 Saúl Ibarra Corretgé 8 | # 9 | # Permission is hereby granted, free of charge, to any person obtaining a copy 10 | # of this software and associated documentation files (the "Software"), to deal 11 | # in the Software without restriction, including without limitation the rights 12 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | # copies of the Software, and to permit persons to whom the Software is 14 | # furnished to do so, subject to the following conditions: 15 | # 16 | # The above copyright notice and this permission notice shall be included in 17 | # all copies or substantial portions of the Software. 18 | # 19 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | # THE SOFTWARE. 26 | 27 | BUILD_DIR=build 28 | BUILD_TYPE?=Release 29 | INSTALL_PREFIX?=/usr/local 30 | 31 | QJS=$(BUILD_DIR)/qjs 32 | QJSC=$(BUILD_DIR)/qjsc 33 | RUN262=$(BUILD_DIR)/run-test262 34 | 35 | JOBS?=$(shell getconf _NPROCESSORS_ONLN) 36 | ifeq ($(JOBS),) 37 | JOBS := $(shell sysctl -n hw.ncpu) 38 | endif 39 | ifeq ($(JOBS),) 40 | JOBS := $(shell nproc) 41 | endif 42 | ifeq ($(JOBS),) 43 | JOBS := 4 44 | endif 45 | 46 | all: $(QJS) 47 | 48 | amalgam: TEMP := $(shell mktemp -d) 49 | amalgam: $(QJS) 50 | $(QJS) amalgam.js $(TEMP)/quickjs-amalgam.c 51 | cp quickjs.h quickjs-libc.h $(TEMP) 52 | cd $(TEMP) && zip -9 quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h 53 | cp $(TEMP)/quickjs-amalgam.zip $(BUILD_DIR) 54 | cd $(TEMP) && $(RM) quickjs-amalgam.zip quickjs-amalgam.c quickjs.h quickjs-libc.h 55 | $(RM) -d $(TEMP) 56 | 57 | fuzz: 58 | clang -g -O1 -fsanitize=address,undefined,fuzzer -o fuzz fuzz.c 59 | ./fuzz 60 | 61 | $(BUILD_DIR): 62 | cmake -B $(BUILD_DIR) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DCMAKE_INSTALL_PREFIX=$(INSTALL_PREFIX) 63 | 64 | $(QJS): $(BUILD_DIR) 65 | cmake --build $(BUILD_DIR) -j $(JOBS) 66 | 67 | $(QJSC): $(BUILD_DIR) 68 | cmake --build $(BUILD_DIR) --target qjsc -j $(JOBS) 69 | 70 | install: $(QJS) $(QJSC) 71 | cmake --build $(BUILD_DIR) --target install 72 | 73 | clean: 74 | cmake --build $(BUILD_DIR) --target clean 75 | 76 | codegen: $(QJSC) 77 | $(QJSC) -ss -o gen/repl.c -m repl.js 78 | $(QJSC) -ss -o gen/standalone.c -m standalone.js 79 | $(QJSC) -e -o gen/function_source.c tests/function_source.js 80 | $(QJSC) -e -o gen/hello.c examples/hello.js 81 | $(QJSC) -e -o gen/hello_module.c -m examples/hello_module.js 82 | $(QJSC) -e -o gen/test_fib.c -M examples/fib.so,fib -m examples/test_fib.js 83 | $(QJSC) -C -ss -o builtin-array-fromasync.h builtin-array-fromasync.js 84 | 85 | debug: 86 | BUILD_TYPE=Debug $(MAKE) 87 | 88 | distclean: 89 | @rm -rf $(BUILD_DIR) 90 | 91 | stats: $(QJS) 92 | $(QJS) -qd 93 | 94 | jscheck: CFLAGS=-I. -D_GNU_SOURCE -DJS_CHECK_JSVALUE -Wall -Werror -fsyntax-only -c -o /dev/null 95 | jscheck: 96 | $(CC) $(CFLAGS) api-test.c 97 | $(CC) $(CFLAGS) ctest.c 98 | $(CC) $(CFLAGS) fuzz.c 99 | $(CC) $(CFLAGS) gen/function_source.c 100 | $(CC) $(CFLAGS) gen/hello.c 101 | $(CC) $(CFLAGS) gen/hello_module.c 102 | $(CC) $(CFLAGS) gen/repl.c 103 | $(CC) $(CFLAGS) gen/standalone.c 104 | $(CC) $(CFLAGS) gen/test_fib.c 105 | $(CC) $(CFLAGS) qjs.c 106 | $(CC) $(CFLAGS) qjsc.c 107 | $(CC) $(CFLAGS) quickjs-libc.c 108 | $(CC) $(CFLAGS) quickjs.c 109 | $(CC) $(CFLAGS) run-test262.c 110 | 111 | # effectively .PHONY because it doesn't generate output 112 | ctest: CFLAGS=-std=c11 -fsyntax-only -Wall -Wextra -Werror -pedantic 113 | ctest: ctest.c quickjs.h 114 | $(CC) $(CFLAGS) -DJS_NAN_BOXING=0 $< 115 | $(CC) $(CFLAGS) -DJS_NAN_BOXING=1 $< 116 | 117 | # effectively .PHONY because it doesn't generate output 118 | cxxtest: CXXFLAGS=-std=c++11 -fsyntax-only -Wall -Wextra -Werror -pedantic 119 | cxxtest: cxxtest.cc quickjs.h 120 | $(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=0 $< 121 | $(CXX) $(CXXFLAGS) -DJS_NAN_BOXING=1 $< 122 | 123 | test: $(QJS) 124 | $(RUN262) -c tests.conf 125 | 126 | test262: $(QJS) 127 | $(RUN262) -m -c test262.conf -a 128 | 129 | test262-fast: $(QJS) 130 | $(RUN262) -m -c test262.conf -c test262-fast.conf -a 131 | 132 | test262-update: $(QJS) 133 | $(RUN262) -u -c test262.conf -a -t 1 134 | 135 | test262-check: $(QJS) 136 | $(RUN262) -m -c test262.conf -E -a 137 | 138 | microbench: $(QJS) 139 | $(QJS) tests/microbench.js 140 | 141 | unicode_gen: $(BUILD_DIR) 142 | cmake --build $(BUILD_DIR) --target unicode_gen 143 | 144 | libunicode-table.h: unicode_gen 145 | $(BUILD_DIR)/unicode_gen unicode $@ 146 | 147 | .PHONY: all amalgam ctest cxxtest debug fuzz jscheck install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC) 148 | -------------------------------------------------------------------------------- /tests/test_closure.js: -------------------------------------------------------------------------------- 1 | // This test cannot use imports because it needs to run in non-strict mode. 2 | 3 | function assert(actual, expected, message) { 4 | if (arguments.length == 1) 5 | expected = true; 6 | 7 | if (actual === expected) 8 | return; 9 | 10 | if (actual !== null && expected !== null 11 | && typeof actual == 'object' && typeof expected == 'object' 12 | && actual.toString() === expected.toString()) 13 | return; 14 | 15 | throw Error("assertion failed: got |" + actual + "|" + 16 | ", expected |" + expected + "|" + 17 | (message ? " (" + message + ")" : "")); 18 | } 19 | 20 | /*----------------*/ 21 | 22 | var log_str = ""; 23 | 24 | function log(str) 25 | { 26 | log_str += str + ","; 27 | } 28 | 29 | function f(a, b, c) 30 | { 31 | var x = 10; 32 | log("a="+a); 33 | function g(d) { 34 | function h() { 35 | log("d=" + d); 36 | log("x=" + x); 37 | } 38 | log("b=" + b); 39 | log("c=" + c); 40 | h(); 41 | } 42 | g(4); 43 | return g; 44 | } 45 | 46 | var g1 = f(1, 2, 3); 47 | g1(5); 48 | 49 | assert(log_str, "a=1,b=2,c=3,d=4,x=10,b=2,c=3,d=5,x=10,", "closure1"); 50 | 51 | function test_closure1() 52 | { 53 | function f2() 54 | { 55 | var val = 1; 56 | 57 | function set(a) { 58 | val = a; 59 | } 60 | function get(a) { 61 | return val; 62 | } 63 | return { "set": set, "get": get }; 64 | } 65 | 66 | var obj = f2(); 67 | obj.set(10); 68 | var r; 69 | r = obj.get(); 70 | assert(r, 10, "closure2"); 71 | } 72 | 73 | function test_closure2() 74 | { 75 | var expr_func = function myfunc1(n) { 76 | function myfunc2(n) { 77 | return myfunc1(n - 1); 78 | } 79 | if (n == 0) 80 | return 0; 81 | else 82 | return myfunc2(n); 83 | }; 84 | var r; 85 | r = expr_func(1); 86 | assert(r, 0, "expr_func"); 87 | } 88 | 89 | function test_closure3() 90 | { 91 | function fib(n) 92 | { 93 | if (n <= 0) 94 | return 0; 95 | else if (n == 1) 96 | return 1; 97 | else 98 | return fib(n - 1) + fib(n - 2); 99 | } 100 | 101 | var fib_func = function fib1(n) 102 | { 103 | if (n <= 0) 104 | return 0; 105 | else if (n == 1) 106 | return 1; 107 | else 108 | return fib1(n - 1) + fib1(n - 2); 109 | }; 110 | 111 | assert(fib(6), 8, "fib"); 112 | assert(fib_func(6), 8, "fib_func"); 113 | } 114 | 115 | function test_arrow_function() 116 | { 117 | "use strict"; 118 | 119 | function f1() { 120 | return (() => arguments)(); 121 | } 122 | function f2() { 123 | return (() => this)(); 124 | } 125 | function f3() { 126 | return (() => eval("this"))(); 127 | } 128 | function f4() { 129 | return (() => eval("new.target"))(); 130 | } 131 | var a; 132 | 133 | a = f1(1, 2); 134 | assert(a.length, 2); 135 | assert(a[0] === 1 && a[1] === 2); 136 | 137 | assert(f2.call("this_val"), "this_val"); 138 | assert(f3.call("this_val"), "this_val"); 139 | assert(new f4(), f4); 140 | 141 | var o1 = { f() { return this; } }; 142 | var o2 = { f() { 143 | return (() => eval("super.f()"))(); 144 | } }; 145 | o2.__proto__ = o1; 146 | 147 | assert(o2.f(), o2); 148 | } 149 | 150 | function test_with() 151 | { 152 | var o1 = { x: "o1", y: "o1" }; 153 | var x = "local"; 154 | eval('var z="var_obj";'); 155 | assert(z, "var_obj"); 156 | with (o1) { 157 | assert(x, "o1"); 158 | assert(eval("x"), "o1"); 159 | var f = function () { 160 | o2 = { x: "o2" }; 161 | with (o2) { 162 | assert(x, "o2"); 163 | assert(y, "o1"); 164 | assert(z, "var_obj"); 165 | assert(eval("x"), "o2"); 166 | assert(eval("y"), "o1"); 167 | assert(eval("z"), "var_obj"); 168 | assert(eval('eval("x")'), "o2"); 169 | } 170 | }; 171 | f(); 172 | } 173 | } 174 | 175 | function test_eval_closure() 176 | { 177 | var tab; 178 | 179 | tab = []; 180 | for(let i = 0; i < 3; i++) { 181 | eval("tab.push(function g1() { return i; })"); 182 | } 183 | for(let i = 0; i < 3; i++) { 184 | assert(tab[i](), i); 185 | } 186 | 187 | tab = []; 188 | for(let i = 0; i < 3; i++) { 189 | let f = function f() { 190 | eval("tab.push(function g2() { return i; })"); 191 | }; 192 | f(); 193 | } 194 | for(let i = 0; i < 3; i++) { 195 | assert(tab[i](), i); 196 | } 197 | } 198 | 199 | function test_eval_const() 200 | { 201 | const a = 1; 202 | var success = false; 203 | var f = function () { 204 | eval("a = 1"); 205 | }; 206 | try { 207 | f(); 208 | } catch(e) { 209 | success = (e instanceof TypeError); 210 | } 211 | assert(success); 212 | } 213 | 214 | test_closure1(); 215 | test_closure2(); 216 | test_closure3(); 217 | test_arrow_function(); 218 | test_with(); 219 | test_eval_closure(); 220 | test_eval_const(); 221 | -------------------------------------------------------------------------------- /docs/docs/cli.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 4 3 | --- 4 | 5 | # The qjs and qjsc CLI tools 6 | 7 | ## `qjs` - The QuickJS JavaScript interpreter 8 | 9 | The `qjs` executable runs the JavaScript interpreter. It includes a simple standard 10 | library and REPL. 11 | 12 | ``` 13 | $ qjs 14 | usage: qjs [options] [file [args]] 15 | -h --help list options 16 | -e --eval EXPR evaluate EXPR 17 | -i --interactive go to interactive mode 18 | -m --module load as ES6 module (default=autodetect) 19 | --script load as ES6 script (default=autodetect) 20 | -I --include file include an additional file 21 | --std make 'std', 'os' and 'bjson' available to script 22 | -T --trace trace memory allocation 23 | -d --dump dump the memory usage stats 24 | -D --dump-flags flags for dumping debug data (see DUMP_* defines) 25 | -c --compile FILE compile the given JS file as a standalone executable 26 | -o --out FILE output file for standalone executables 27 | --exe select the executable to use as the base, defaults to the current one 28 | --memory-limit n limit the memory usage to 'n' Kbytes 29 | --stack-size n limit the stack size to 'n' Kbytes 30 | --unhandled-rejection dump unhandled promise rejections 31 | -q --quit just instantiate the interpreter and quit 32 | ``` 33 | 34 | The following dump flags are supported: 35 | 36 | ``` 37 | DUMP_BYTECODE_FINAL 0x01 /* dump pass 3 final byte code */ 38 | DUMP_BYTECODE_PASS2 0x02 /* dump pass 2 code */ 39 | DUMP_BYTECODE_PASS1 0x04 /* dump pass 1 code */ 40 | DUMP_BYTECODE_HEX 0x10 /* dump bytecode in hex */ 41 | DUMP_BYTECODE_PC2LINE 0x20 /* dump line number table */ 42 | DUMP_BYTECODE_STACK 0x40 /* dump compute_stack_size */ 43 | DUMP_BYTECODE_STEP 0x80 /* dump executed bytecode */ 44 | DUMP_READ_OBJECT 0x100 /* dump the marshalled objects at load time */ 45 | DUMP_FREE 0x200 /* dump every object free */ 46 | DUMP_GC 0x400 /* dump the occurrence of the automatic GC */ 47 | DUMP_GC_FREE 0x800 /* dump objects freed by the GC */ 48 | DUMP_MODULE_RESOLVE 0x1000 /* dump module resolution steps */ 49 | DUMP_PROMISE 0x2000 /* dump promise steps */ 50 | DUMP_LEAKS 0x4000 /* dump leaked objects and strings in JS_FreeRuntime */ 51 | DUMP_ATOM_LEAKS 0x8000 /* dump leaked atoms in JS_FreeRuntime */ 52 | DUMP_MEM 0x10000 /* dump memory usage in JS_FreeRuntime */ 53 | DUMP_OBJECTS 0x20000 /* dump objects in JS_FreeRuntime */ 54 | DUMP_ATOMS 0x40000 /* dump atoms in JS_FreeRuntime */ 55 | DUMP_SHAPES 0x80000 /* dump shapes in JS_FreeRuntime */ 56 | ``` 57 | 58 | ### Creating standalone executables 59 | 60 | With the `qjs` CLI it's possible to create standalone executables that will bundle the given JavaScript file 61 | alongside the binary. 62 | 63 | ``` 64 | $ qjs -c app.js -o app --exe qjs 65 | ``` 66 | 67 | The resulting `app` binary will have the same runtime dependencies as the `qjs` binary. This is acomplished 68 | by compiling the target JavaScript file to bytecode and adding it a copy of the executable, with a little 69 | trailer to help locate it. `--exe` expects the absolute path to `qjs`, e.g., `~/bin/qjs` or `$HOME/bin/qjs`. 70 | 71 | Rather than using the current executable, it's possible to use the `--exe` switch to create standalone 72 | executables for other platforms. 73 | 74 | No JavaScript bundling is performed, the specified JS file cannot depend on other files. A bundler such 75 | as `esbuild` can be used to generate an app bundle which can then be turned into the executable. 76 | 77 | ``` 78 | npx esbuild my-app/index.js \ 79 | --bundle \ 80 | --outfile=app.js \ 81 | --external:qjs:* \ 82 | --minify \ 83 | --target=es2023 \ 84 | --platform=neutral \ 85 | --format=esm \ 86 | --main-fields=main,module 87 | ``` 88 | 89 | ## `qjsc` - The QuickJS JavaScript compiler 90 | 91 | The `qjsc` executable runs the JavaScript compiler, it can generate bytecode from 92 | source files which can then be embedded in an executable, or it can generate the necessary 93 | scaffolding to build a C application which embeds QuickJS. 94 | 95 | ``` 96 | $ qjsc 97 | usage: qjsc [options] [files] 98 | 99 | options are: 100 | -b output raw bytecode instead of C code 101 | -e output main() and bytecode in a C file 102 | -o output set the output filename 103 | -n script_name set the script name (as used in stack traces) 104 | -N cname set the C name of the generated data 105 | -m compile as JavaScript module (default=autodetect) 106 | -D module_name compile a dynamically loaded module or worker 107 | -M module_name[,cname] add initialization code for an external C module 108 | -p prefix set the prefix of the generated C names 109 | -s strip the source code, specify twice to also strip debug info 110 | -S n set the maximum stack size to 'n' bytes (default=262144) 111 | ``` 112 | 113 | Here is an example on how to create a standalone executable that embeds QuickJS 114 | and the `examples/hello.js` JavaScript file: 115 | 116 | ```bash 117 | # Make sure you are in the QuickJS source directory. 118 | $ cc hello.c cutils.c libbf.c libregexp.c libunicode.c quickjs.c quickjs-libc.c -I. -o hello 119 | ``` 120 | 121 | The resulting binary `hello` will be in the current directory. 122 | 123 | ```bash 124 | $ ./hello 125 | Hello World 126 | ``` 127 | 128 | :::note 129 | See the ["Creating standalone executables"](#creating-standalone-executables) section for a simpler way. 130 | ::: 131 | -------------------------------------------------------------------------------- /examples/point.c: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS: Example of C module with a class 3 | * 4 | * Copyright (c) 2019 Fabrice Bellard 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | #include "../quickjs.h" 25 | #include 26 | 27 | #define countof(x) (sizeof(x) / sizeof((x)[0])) 28 | 29 | /* Point Class */ 30 | 31 | typedef struct { 32 | int x; 33 | int y; 34 | } JSPointData; 35 | 36 | static JSClassID js_point_class_id; 37 | 38 | static void js_point_finalizer(JSRuntime *rt, JSValue val) 39 | { 40 | JSPointData *s = JS_GetOpaque(val, js_point_class_id); 41 | /* Note: 's' can be NULL in case JS_SetOpaque() was not called */ 42 | js_free_rt(rt, s); 43 | } 44 | 45 | static JSValue js_point_ctor(JSContext *ctx, 46 | JSValue new_target, 47 | int argc, JSValue *argv) 48 | { 49 | JSPointData *s; 50 | JSValue obj = JS_UNDEFINED; 51 | JSValue proto; 52 | 53 | s = js_mallocz(ctx, sizeof(*s)); 54 | if (!s) 55 | return JS_EXCEPTION; 56 | if (JS_ToInt32(ctx, &s->x, argv[0])) 57 | goto fail; 58 | if (JS_ToInt32(ctx, &s->y, argv[1])) 59 | goto fail; 60 | /* using new_target to get the prototype is necessary when the 61 | class is extended. */ 62 | proto = JS_GetPropertyStr(ctx, new_target, "prototype"); 63 | if (JS_IsException(proto)) 64 | goto fail; 65 | obj = JS_NewObjectProtoClass(ctx, proto, js_point_class_id); 66 | JS_FreeValue(ctx, proto); 67 | if (JS_IsException(obj)) 68 | goto fail; 69 | JS_SetOpaque(obj, s); 70 | return obj; 71 | fail: 72 | js_free(ctx, s); 73 | JS_FreeValue(ctx, obj); 74 | return JS_EXCEPTION; 75 | } 76 | 77 | static JSValue js_point_get_xy(JSContext *ctx, JSValue this_val, int magic) 78 | { 79 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); 80 | if (!s) 81 | return JS_EXCEPTION; 82 | if (magic == 0) 83 | return JS_NewInt32(ctx, s->x); 84 | else 85 | return JS_NewInt32(ctx, s->y); 86 | } 87 | 88 | static JSValue js_point_set_xy(JSContext *ctx, JSValue this_val, JSValue val, int magic) 89 | { 90 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); 91 | int v; 92 | if (!s) 93 | return JS_EXCEPTION; 94 | if (JS_ToInt32(ctx, &v, val)) 95 | return JS_EXCEPTION; 96 | if (magic == 0) 97 | s->x = v; 98 | else 99 | s->y = v; 100 | return JS_UNDEFINED; 101 | } 102 | 103 | static JSValue js_point_norm(JSContext *ctx, JSValue this_val, 104 | int argc, JSValue *argv) 105 | { 106 | JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); 107 | if (!s) 108 | return JS_EXCEPTION; 109 | return JS_NewFloat64(ctx, sqrt((double)s->x * s->x + (double)s->y * s->y)); 110 | } 111 | 112 | static JSClassDef js_point_class = { 113 | "Point", 114 | .finalizer = js_point_finalizer, 115 | }; 116 | 117 | static const JSCFunctionListEntry js_point_proto_funcs[] = { 118 | JS_CGETSET_MAGIC_DEF("x", js_point_get_xy, js_point_set_xy, 0), 119 | JS_CGETSET_MAGIC_DEF("y", js_point_get_xy, js_point_set_xy, 1), 120 | JS_CFUNC_DEF("norm", 0, js_point_norm), 121 | }; 122 | 123 | static int js_point_init(JSContext *ctx, JSModuleDef *m) 124 | { 125 | JSValue point_proto, point_class; 126 | JSRuntime *rt = JS_GetRuntime(ctx); 127 | 128 | /* create the Point class */ 129 | JS_NewClassID(rt, &js_point_class_id); 130 | JS_NewClass(rt, js_point_class_id, &js_point_class); 131 | 132 | point_proto = JS_NewObject(ctx); 133 | JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs)); 134 | 135 | point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0); 136 | /* set proto.constructor and ctor.prototype */ 137 | JS_SetConstructor(ctx, point_class, point_proto); 138 | JS_SetClassProto(ctx, js_point_class_id, point_proto); 139 | 140 | JS_SetModuleExport(ctx, m, "Point", point_class); 141 | return 0; 142 | } 143 | 144 | #ifndef JS_EXTERN 145 | #ifdef _WIN32 146 | #define JS_EXTERN __declspec(dllexport) 147 | #else 148 | #define JS_EXTERN 149 | #endif 150 | #endif 151 | 152 | JS_EXTERN JSModuleDef *js_init_module(JSContext *ctx, const char *module_name) 153 | { 154 | JSModuleDef *m; 155 | m = JS_NewCModule(ctx, module_name, js_point_init); 156 | if (!m) 157 | return NULL; 158 | JS_AddModuleExport(ctx, m, "Point"); 159 | return m; 160 | } 161 | -------------------------------------------------------------------------------- /builtin-array-fromasync.h: -------------------------------------------------------------------------------- 1 | /* File generated automatically by the QuickJS-ng compiler. */ 2 | 3 | #include 4 | 5 | const uint32_t qjsc_builtin_array_fromasync_size = 826; 6 | 7 | const uint8_t qjsc_builtin_array_fromasync[826] = { 8 | 0x14, 0x0d, 0x01, 0x1a, 0x61, 0x73, 0x79, 0x6e, 9 | 0x63, 0x49, 0x74, 0x65, 0x72, 0x61, 0x74, 0x6f, 10 | 0x72, 0x01, 0x10, 0x69, 0x74, 0x65, 0x72, 0x61, 11 | 0x74, 0x6f, 0x72, 0x01, 0x12, 0x61, 0x72, 0x72, 12 | 0x61, 0x79, 0x4c, 0x69, 0x6b, 0x65, 0x01, 0x0a, 13 | 0x6d, 0x61, 0x70, 0x46, 0x6e, 0x01, 0x0e, 0x74, 14 | 0x68, 0x69, 0x73, 0x41, 0x72, 0x67, 0x01, 0x0c, 15 | 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x01, 0x02, 16 | 0x69, 0x01, 0x1a, 0x69, 0x73, 0x43, 0x6f, 0x6e, 17 | 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x6f, 0x72, 18 | 0x01, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x01, 0x0c, 19 | 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x01, 0x08, 20 | 0x69, 0x74, 0x65, 0x72, 0x01, 0x1c, 0x6e, 0x6f, 21 | 0x74, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6e, 0x63, 22 | 0x74, 0x69, 0x6f, 0x6e, 0x01, 0x08, 0x63, 0x61, 23 | 0x6c, 0x6c, 0x0c, 0x00, 0x02, 0x00, 0xa2, 0x01, 24 | 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 25 | 0xa4, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x43, 0x02, 26 | 0x01, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x01, 27 | 0x03, 0x05, 0xaa, 0x02, 0x00, 0x01, 0x40, 0x9e, 28 | 0x03, 0x00, 0x01, 0x40, 0xc2, 0x03, 0x00, 0x01, 29 | 0x40, 0xcc, 0x01, 0x00, 0x01, 0x40, 0xc4, 0x03, 30 | 0x00, 0x01, 0x40, 0x0c, 0x60, 0x02, 0x01, 0xf8, 31 | 0x01, 0x03, 0x0e, 0x01, 0x06, 0x05, 0x00, 0x86, 32 | 0x04, 0x11, 0xc6, 0x03, 0x00, 0x01, 0x00, 0xc8, 33 | 0x03, 0x00, 0x01, 0x00, 0xca, 0x03, 0x00, 0x01, 34 | 0x00, 0xc6, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff, 35 | 0x0f, 0x20, 0xc8, 0x03, 0x01, 0x01, 0x20, 0xca, 36 | 0x03, 0x01, 0x02, 0x20, 0xcc, 0x03, 0x02, 0x00, 37 | 0x20, 0xce, 0x03, 0x02, 0x04, 0x20, 0xd0, 0x03, 38 | 0x02, 0x05, 0x20, 0xd2, 0x03, 0x02, 0x06, 0x20, 39 | 0xd4, 0x03, 0x02, 0x07, 0x20, 0x64, 0x06, 0x08, 40 | 0x20, 0x82, 0x01, 0x07, 0x09, 0x20, 0xd6, 0x03, 41 | 0x0a, 0x08, 0x30, 0x82, 0x01, 0x0d, 0x0b, 0x20, 42 | 0xd4, 0x01, 0x0d, 0x0c, 0x20, 0x10, 0x00, 0x01, 43 | 0x00, 0x9e, 0x03, 0x01, 0x03, 0xc2, 0x03, 0x02, 44 | 0x03, 0xc4, 0x03, 0x04, 0x03, 0xaa, 0x02, 0x00, 45 | 0x03, 0xcc, 0x01, 0x03, 0x03, 0x08, 0xc4, 0x0d, 46 | 0x62, 0x02, 0x00, 0x62, 0x01, 0x00, 0x62, 0x00, 47 | 0x00, 0xd3, 0xcb, 0xd4, 0x11, 0xf4, 0xec, 0x08, 48 | 0x0e, 0x39, 0x46, 0x00, 0x00, 0x00, 0xdc, 0xcc, 49 | 0xd5, 0x11, 0xf4, 0xec, 0x08, 0x0e, 0x39, 0x46, 50 | 0x00, 0x00, 0x00, 0xdd, 0xcd, 0x62, 0x07, 0x00, 51 | 0x62, 0x06, 0x00, 0x62, 0x05, 0x00, 0x62, 0x04, 52 | 0x00, 0x62, 0x03, 0x00, 0xd4, 0x39, 0x46, 0x00, 53 | 0x00, 0x00, 0xb0, 0xec, 0x16, 0xd4, 0x98, 0x04, 54 | 0x1b, 0x00, 0x00, 0x00, 0xb0, 0xec, 0x0c, 0xdf, 55 | 0x11, 0x04, 0xec, 0x00, 0x00, 0x00, 0x21, 0x01, 56 | 0x00, 0x30, 0x06, 0xce, 0xb6, 0xc4, 0x04, 0xc3, 57 | 0x0d, 0xf7, 0xc4, 0x05, 0x09, 0xc4, 0x06, 0xd3, 58 | 0xe0, 0x48, 0xc4, 0x07, 0x63, 0x07, 0x00, 0x07, 59 | 0xad, 0xec, 0x0f, 0x0a, 0x11, 0x64, 0x06, 0x00, 60 | 0x0e, 0xd3, 0xe1, 0x48, 0x11, 0x64, 0x07, 0x00, 61 | 0x0e, 0x63, 0x07, 0x00, 0x07, 0xad, 0x6a, 0xa6, 62 | 0x00, 0x00, 0x00, 0x62, 0x08, 0x00, 0x06, 0x11, 63 | 0xf4, 0xed, 0x0c, 0x71, 0x43, 0x32, 0x00, 0x00, 64 | 0x00, 0xc4, 0x08, 0x0e, 0xee, 0x05, 0x0e, 0xd3, 65 | 0xee, 0xf2, 0x63, 0x08, 0x00, 0x8e, 0x11, 0xed, 66 | 0x03, 0x0e, 0xb6, 0x11, 0x64, 0x08, 0x00, 0x0e, 67 | 0x63, 0x05, 0x00, 0xec, 0x0c, 0xc3, 0x0d, 0x11, 68 | 0x63, 0x08, 0x00, 0x21, 0x01, 0x00, 0xee, 0x06, 69 | 0xe2, 0x63, 0x08, 0x00, 0xf1, 0x11, 0x64, 0x03, 70 | 0x00, 0x0e, 0x63, 0x04, 0x00, 0x63, 0x08, 0x00, 71 | 0xa7, 0x6a, 0x2a, 0x01, 0x00, 0x00, 0x62, 0x09, 72 | 0x00, 0xd3, 0x63, 0x04, 0x00, 0x48, 0xc4, 0x09, 73 | 0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x09, 0x00, 74 | 0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0xd4, 0xec, 75 | 0x17, 0xd4, 0x43, 0xed, 0x00, 0x00, 0x00, 0xd5, 76 | 0x63, 0x09, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03, 77 | 0x00, 0x8c, 0x11, 0x64, 0x09, 0x00, 0x0e, 0x5f, 78 | 0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00, 79 | 0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x09, 0x00, 80 | 0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e, 81 | 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00, 82 | 0x00, 0xf3, 0x0e, 0xee, 0x9e, 0x62, 0x0a, 0x00, 83 | 0x63, 0x07, 0x00, 0x43, 0xed, 0x00, 0x00, 0x00, 84 | 0xd3, 0x24, 0x01, 0x00, 0xc4, 0x0a, 0x63, 0x05, 85 | 0x00, 0xec, 0x09, 0xc3, 0x0d, 0x11, 0x21, 0x00, 86 | 0x00, 0xee, 0x03, 0xe2, 0xf0, 0x11, 0x64, 0x03, 87 | 0x00, 0x0e, 0x6d, 0x8c, 0x00, 0x00, 0x00, 0x62, 88 | 0x0c, 0x00, 0x62, 0x0b, 0x00, 0x06, 0x11, 0xf4, 89 | 0xed, 0x13, 0x71, 0x43, 0x41, 0x00, 0x00, 0x00, 90 | 0xc4, 0x0b, 0x43, 0x6a, 0x00, 0x00, 0x00, 0xc4, 91 | 0x0c, 0x0e, 0xee, 0x10, 0x0e, 0x63, 0x0a, 0x00, 92 | 0x43, 0x6b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 93 | 0x8c, 0xee, 0xe0, 0x63, 0x0c, 0x00, 0xed, 0x4e, 94 | 0x63, 0x06, 0x00, 0xec, 0x0a, 0x63, 0x0b, 0x00, 95 | 0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0xd4, 0xec, 96 | 0x17, 0xd4, 0x43, 0xed, 0x00, 0x00, 0x00, 0xd5, 97 | 0x63, 0x0b, 0x00, 0x63, 0x04, 0x00, 0x24, 0x03, 98 | 0x00, 0x8c, 0x11, 0x64, 0x0b, 0x00, 0x0e, 0x5f, 99 | 0x04, 0x00, 0x63, 0x03, 0x00, 0x63, 0x04, 0x00, 100 | 0x92, 0x64, 0x04, 0x00, 0x0b, 0x63, 0x0b, 0x00, 101 | 0x4d, 0x41, 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3e, 102 | 0x00, 0x00, 0x00, 0x0a, 0x4d, 0x3f, 0x00, 0x00, 103 | 0x00, 0xf3, 0x0e, 0xee, 0x83, 0x0e, 0x06, 0x6e, 104 | 0x0d, 0x00, 0x00, 0x00, 0x0e, 0xee, 0x1e, 0x6e, 105 | 0x05, 0x00, 0x00, 0x00, 0x30, 0x63, 0x0a, 0x00, 106 | 0x42, 0x06, 0x00, 0x00, 0x00, 0xec, 0x0d, 0x63, 107 | 0x0a, 0x00, 0x43, 0x06, 0x00, 0x00, 0x00, 0x24, 108 | 0x00, 0x00, 0x0e, 0x6f, 0x63, 0x03, 0x00, 0x63, 109 | 0x04, 0x00, 0x44, 0x32, 0x00, 0x00, 0x00, 0x63, 110 | 0x03, 0x00, 0x2f, 0xc1, 0x00, 0x28, 0xc1, 0x00, 111 | 0xcf, 0x28, 112 | }; 113 | 114 | -------------------------------------------------------------------------------- /xsum.h: -------------------------------------------------------------------------------- 1 | /* INTERFACE TO FUNCTIONS FOR EXACT SUMMATION. */ 2 | 3 | /* Copyright 2015, 2018, 2021 Radford M. Neal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #ifndef XSUM_H 26 | #define XSUM_H 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | 33 | /* CONSTANTS DEFINING THE FLOATING POINT FORMAT. */ 34 | 35 | typedef double xsum_flt; /* C floating point type sums are done for */ 36 | 37 | typedef int64_t xsum_int; /* Signed integer type for a fp value */ 38 | typedef uint64_t xsum_uint; /* Unsigned integer type for a fp value */ 39 | typedef int_fast16_t xsum_expint; /* Integer type for holding an exponent */ 40 | 41 | #define XSUM_MANTISSA_BITS 52 /* Bits in fp mantissa, excludes implict 1 */ 42 | #define XSUM_EXP_BITS 11 /* Bits in fp exponent */ 43 | 44 | #define XSUM_MANTISSA_MASK \ 45 | (((xsum_int)1 << XSUM_MANTISSA_BITS) - 1) /* Mask for mantissa bits */ 46 | 47 | #define XSUM_EXP_MASK \ 48 | ((1 << XSUM_EXP_BITS) - 1) /* Mask for exponent */ 49 | 50 | #define XSUM_EXP_BIAS \ 51 | ((1 << (XSUM_EXP_BITS-1)) - 1) /* Bias added to signed exponent */ 52 | 53 | #define XSUM_SIGN_BIT \ 54 | (XSUM_MANTISSA_BITS + XSUM_EXP_BITS) /* Position of sign bit */ 55 | 56 | #define XSUM_SIGN_MASK \ 57 | ((xsum_uint)1 << XSUM_SIGN_BIT) /* Mask for sign bit */ 58 | 59 | 60 | /* CONSTANTS DEFINING THE SMALL ACCUMULATOR FORMAT. */ 61 | 62 | #define XSUM_SCHUNK_BITS 64 /* Bits in chunk of the small accumulator */ 63 | typedef int64_t xsum_schunk; /* Integer type of small accumulator chunk */ 64 | 65 | #define XSUM_LOW_EXP_BITS 5 /* # of low bits of exponent, in one chunk */ 66 | 67 | #define XSUM_LOW_EXP_MASK \ 68 | ((1 << XSUM_LOW_EXP_BITS) - 1) /* Mask for low-order exponent bits */ 69 | 70 | #define XSUM_HIGH_EXP_BITS \ 71 | (XSUM_EXP_BITS - XSUM_LOW_EXP_BITS) /* # of high exponent bits for index */ 72 | 73 | #define XSUM_HIGH_EXP_MASK \ 74 | ((1 << HIGH_EXP_BITS) - 1) /* Mask for high-order exponent bits */ 75 | 76 | #define XSUM_SCHUNKS \ 77 | ((1 << XSUM_HIGH_EXP_BITS) + 3) /* # of chunks in small accumulator */ 78 | 79 | #define XSUM_LOW_MANTISSA_BITS \ 80 | (1 << XSUM_LOW_EXP_BITS) /* Bits in low part of mantissa */ 81 | 82 | #define XSUM_HIGH_MANTISSA_BITS \ 83 | (XSUM_MANTISSA_BITS - XSUM_LOW_MANTISSA_BITS) /* Bits in high part */ 84 | 85 | #define XSUM_LOW_MANTISSA_MASK \ 86 | (((xsum_int)1 << XSUM_LOW_MANTISSA_BITS) - 1) /* Mask for low bits */ 87 | 88 | #define XSUM_SMALL_CARRY_BITS \ 89 | ((XSUM_SCHUNK_BITS-1) - XSUM_MANTISSA_BITS) /* Bits sums can carry into */ 90 | 91 | #define XSUM_SMALL_CARRY_TERMS \ 92 | ((1 << XSUM_SMALL_CARRY_BITS) - 1) /* # terms can add before need prop. */ 93 | 94 | typedef struct 95 | { xsum_schunk chunk[XSUM_SCHUNKS]; /* Chunks making up small accumulator */ 96 | xsum_int Inf; /* If non-zero, +Inf, -Inf, or NaN */ 97 | xsum_int NaN; /* If non-zero, a NaN value with payload */ 98 | int adds_until_propagate; /* Number of remaining adds before carry */ 99 | } xsum_small_accumulator; /* propagation must be done again */ 100 | 101 | 102 | /* TYPE FOR LENGTHS OF ARRAYS. Must be a signed integer type. Set to 103 | ptrdiff_t here on the assumption that this will be big enough, but 104 | not unnecessarily big, which seems to be true. */ 105 | 106 | typedef ptrdiff_t xsum_length; 107 | 108 | 109 | /* FUNCTIONS FOR EXACT SUMMATION, WITH POSSIBLE DIVISION BY AN INTEGER. */ 110 | 111 | void xsum_small_init (xsum_small_accumulator *restrict); 112 | void xsum_small_add1 (xsum_small_accumulator *restrict, xsum_flt); 113 | void xsum_small_addv (xsum_small_accumulator *restrict, 114 | const xsum_flt *restrict, xsum_length); 115 | void xsum_small_add_sqnorm (xsum_small_accumulator *restrict, 116 | const xsum_flt *restrict, xsum_length); 117 | void xsum_small_add_dot (xsum_small_accumulator *restrict, 118 | const xsum_flt *, const xsum_flt *, xsum_length); 119 | void xsum_small_add_accumulator (xsum_small_accumulator *, 120 | xsum_small_accumulator *); 121 | void xsum_small_negate (xsum_small_accumulator *restrict); 122 | xsum_flt xsum_small_round (xsum_small_accumulator *restrict); 123 | 124 | xsum_flt xsum_small_div_unsigned (xsum_small_accumulator *restrict, unsigned); 125 | xsum_flt xsum_small_div_int (xsum_small_accumulator *restrict, int); 126 | 127 | 128 | /* DEBUG FLAG. Set to non-zero for debug ouptut. Ignored unless xsum.c 129 | is compiled with -DDEBUG. */ 130 | 131 | extern int xsum_debug; 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /tests/test_loop.js: -------------------------------------------------------------------------------- 1 | // This test cannot use imports because it needs to run in non-strict mode. 2 | 3 | function assert(actual, expected, message) { 4 | if (arguments.length == 1) 5 | expected = true; 6 | 7 | if (actual === expected) 8 | return; 9 | 10 | if (actual !== null && expected !== null 11 | && typeof actual == 'object' && typeof expected == 'object' 12 | && actual.toString() === expected.toString()) 13 | return; 14 | 15 | throw Error("assertion failed: got |" + actual + "|" + 16 | ", expected |" + expected + "|" + 17 | (message ? " (" + message + ")" : "")); 18 | } 19 | 20 | /*----------------*/ 21 | 22 | function test_while() 23 | { 24 | var i, c; 25 | i = 0; 26 | c = 0; 27 | while (i < 3) { 28 | c++; 29 | i++; 30 | } 31 | assert(c, 3); 32 | } 33 | 34 | function test_while_break() 35 | { 36 | var i, c; 37 | i = 0; 38 | c = 0; 39 | while (i < 3) { 40 | c++; 41 | if (i == 1) 42 | break; 43 | i++; 44 | } 45 | assert(c === 2 && i === 1); 46 | } 47 | 48 | function test_do_while() 49 | { 50 | var i, c; 51 | i = 0; 52 | c = 0; 53 | do { 54 | c++; 55 | i++; 56 | } while (i < 3); 57 | assert(c === 3 && i === 3); 58 | } 59 | 60 | function test_for() 61 | { 62 | var i, c; 63 | c = 0; 64 | for(i = 0; i < 3; i++) { 65 | c++; 66 | } 67 | assert(c === 3 && i === 3); 68 | 69 | c = 0; 70 | for(var j = 0; j < 3; j++) { 71 | c++; 72 | } 73 | assert(c === 3 && j === 3); 74 | } 75 | 76 | function test_for_in() 77 | { 78 | var i, tab, a, b; 79 | 80 | tab = []; 81 | for(i in {x:1, y: 2}) { 82 | tab.push(i); 83 | } 84 | assert(tab.toString(), "x,y", "for_in"); 85 | 86 | /* prototype chain test */ 87 | a = {x:2, y: 2, "1": 3}; 88 | b = {"4" : 3 }; 89 | Object.setPrototypeOf(a, b); 90 | tab = []; 91 | for(i in a) { 92 | tab.push(i); 93 | } 94 | assert(tab.toString(), "1,x,y,4", "for_in"); 95 | 96 | /* non enumerable properties hide enumerables ones in the 97 | prototype chain */ 98 | a = {y: 2, "1": 3}; 99 | Object.defineProperty(a, "x", { value: 1 }); 100 | b = {"x" : 3 }; 101 | Object.setPrototypeOf(a, b); 102 | tab = []; 103 | for(i in a) { 104 | tab.push(i); 105 | } 106 | assert(tab.toString(), "1,y", "for_in"); 107 | 108 | /* array optimization */ 109 | a = []; 110 | for(i = 0; i < 10; i++) 111 | a.push(i); 112 | tab = []; 113 | for(i in a) { 114 | tab.push(i); 115 | } 116 | assert(tab.toString(), "0,1,2,3,4,5,6,7,8,9", "for_in"); 117 | 118 | /* iterate with a field */ 119 | a={x:0}; 120 | tab = []; 121 | for(a.x in {x:1, y: 2}) { 122 | tab.push(a.x); 123 | } 124 | assert(tab.toString(), "x,y", "for_in"); 125 | 126 | /* iterate with a variable field */ 127 | a=[0]; 128 | tab = []; 129 | for(a[0] in {x:1, y: 2}) { 130 | tab.push(a[0]); 131 | } 132 | assert(tab.toString(), "x,y", "for_in"); 133 | 134 | /* variable definition in the for in */ 135 | tab = []; 136 | for(var j in {x:1, y: 2}) { 137 | tab.push(j); 138 | } 139 | assert(tab.toString(), "x,y", "for_in"); 140 | 141 | /* variable assigment in the for in */ 142 | tab = []; 143 | for(var k = 2 in {x:1, y: 2}) { 144 | tab.push(k); 145 | } 146 | assert(tab.toString(), "x,y", "for_in"); 147 | } 148 | 149 | function test_for_in2() 150 | { 151 | var i; 152 | tab = []; 153 | for(i in {x:1, y: 2, z:3}) { 154 | if (i === "y") 155 | continue; 156 | tab.push(i); 157 | } 158 | assert(tab.toString() == "x,z"); 159 | 160 | tab = []; 161 | for(i in {x:1, y: 2, z:3}) { 162 | if (i === "z") 163 | break; 164 | tab.push(i); 165 | } 166 | assert(tab.toString() == "x,y"); 167 | } 168 | 169 | function test_for_break() 170 | { 171 | var i, c; 172 | c = 0; 173 | L1: for(i = 0; i < 3; i++) { 174 | c++; 175 | if (i == 0) 176 | continue; 177 | while (1) { 178 | break L1; 179 | } 180 | } 181 | assert(c === 2 && i === 1); 182 | } 183 | 184 | function test_switch1() 185 | { 186 | var i, a, s; 187 | s = ""; 188 | for(i = 0; i < 3; i++) { 189 | a = "?"; 190 | switch(i) { 191 | case 0: 192 | a = "a"; 193 | break; 194 | case 1: 195 | a = "b"; 196 | break; 197 | default: 198 | a = "c"; 199 | break; 200 | } 201 | s += a; 202 | } 203 | assert(s === "abc" && i === 3); 204 | } 205 | 206 | function test_switch2() 207 | { 208 | var i, a, s; 209 | s = ""; 210 | for(i = 0; i < 4; i++) { 211 | a = "?"; 212 | switch(i) { 213 | case 0: 214 | a = "a"; 215 | break; 216 | case 1: 217 | a = "b"; 218 | break; 219 | case 2: 220 | continue; 221 | default: 222 | a = "" + i; 223 | break; 224 | } 225 | s += a; 226 | } 227 | assert(s === "ab3" && i === 4); 228 | } 229 | 230 | function test_try_catch1() 231 | { 232 | try { 233 | throw "hello"; 234 | } catch (e) { 235 | assert(e, "hello", "catch"); 236 | return; 237 | } 238 | assert(false, "catch"); 239 | } 240 | 241 | function test_try_catch2() 242 | { 243 | var a; 244 | try { 245 | a = 1; 246 | } catch (e) { 247 | a = 2; 248 | } 249 | assert(a, 1, "catch"); 250 | } 251 | 252 | function test_try_catch3() 253 | { 254 | var s; 255 | s = ""; 256 | try { 257 | s += "t"; 258 | } catch (e) { 259 | s += "c"; 260 | } finally { 261 | s += "f"; 262 | } 263 | assert(s, "tf", "catch"); 264 | } 265 | 266 | function test_try_catch4() 267 | { 268 | var s; 269 | s = ""; 270 | try { 271 | s += "t"; 272 | throw "c"; 273 | } catch (e) { 274 | s += e; 275 | } finally { 276 | s += "f"; 277 | } 278 | assert(s, "tcf", "catch"); 279 | } 280 | 281 | function test_try_catch5() 282 | { 283 | var s; 284 | s = ""; 285 | for(;;) { 286 | try { 287 | s += "t"; 288 | break; 289 | s += "b"; 290 | } finally { 291 | s += "f"; 292 | } 293 | } 294 | assert(s, "tf", "catch"); 295 | } 296 | 297 | function test_try_catch6() 298 | { 299 | function f() { 300 | try { 301 | s += 't'; 302 | return 1; 303 | } finally { 304 | s += "f"; 305 | } 306 | } 307 | var s = ""; 308 | assert(f() === 1); 309 | assert(s, "tf", "catch6"); 310 | } 311 | 312 | function test_try_catch7() 313 | { 314 | var s; 315 | s = ""; 316 | 317 | try { 318 | try { 319 | s += "t"; 320 | throw "a"; 321 | } finally { 322 | s += "f"; 323 | } 324 | } catch(e) { 325 | s += e; 326 | } finally { 327 | s += "g"; 328 | } 329 | assert(s, "tfag", "catch"); 330 | } 331 | 332 | function test_try_catch8() 333 | { 334 | var i, s; 335 | 336 | s = ""; 337 | for(var i in {x:1, y:2}) { 338 | try { 339 | s += i; 340 | throw "a"; 341 | } catch (e) { 342 | s += e; 343 | } finally { 344 | s += "f"; 345 | } 346 | } 347 | assert(s === "xafyaf"); 348 | } 349 | 350 | test_while(); 351 | test_while_break(); 352 | test_do_while(); 353 | test_for(); 354 | test_for_break(); 355 | test_switch1(); 356 | test_switch2(); 357 | test_for_in(); 358 | test_for_in2(); 359 | 360 | test_try_catch1(); 361 | test_try_catch2(); 362 | test_try_catch3(); 363 | test_try_catch4(); 364 | test_try_catch5(); 365 | test_try_catch6(); 366 | test_try_catch7(); 367 | test_try_catch8(); 368 | -------------------------------------------------------------------------------- /test262-fast.conf: -------------------------------------------------------------------------------- 1 | [exclude] 2 | # list excluded tests and directories here for faster operation 3 | 4 | # lengthy constructed regexp (>500 ms) 5 | test262/test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js 6 | test262/test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js 7 | 8 | # slow notifications (> 600 ms) 9 | test262/test/built-ins/Atomics/notify/notify-in-order-one-time.js 10 | test262/test/built-ins/Atomics/notify/notify-in-order.js 11 | test262/test/built-ins/Atomics/wait/bigint/waiterlist-order-of-operations-is-fifo.js 12 | test262/test/built-ins/Atomics/wait/waiterlist-order-of-operations-is-fifo.js 13 | 14 | # lengthy constructed regexp (>200 ms) 15 | test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-flags-u.js 16 | test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-plus-quantifier-flags-u.js 17 | test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-flags-u.js 18 | test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-plus-quantifier-flags-u.js 19 | test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-flags-u.js 20 | test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-plus-quantifier-flags-u.js 21 | test262/test/built-ins/RegExp/character-class-escape-non-whitespace.js 22 | 23 | # 417 lengty tests with huge constructed regexp (>200 ms) 24 | test262/test/built-ins/RegExp/property-escapes/generated/ 25 | 26 | # lengthy constructed URLS (>200 ms) 27 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.2_T1.js 28 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.2_T2.js 29 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.10_T1.js 30 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T1.js 31 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js 32 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js 33 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T2.js 34 | test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T3.js 35 | test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js 36 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.2_T1.js 37 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.2_T2.js 38 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.10_T1.js 39 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T1.js 40 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js 41 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js 42 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T2.js 43 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T3.js 44 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js 45 | 46 | # lengthy comment tests 47 | test262/test/language/comments/S7.4_A5.js 48 | test262/test/language/comments/S7.4_A6.js 49 | 50 | # lengthy unicode level tests 51 | test262/test/language/identifiers/start-unicode-5.2.0-class-escaped.js 52 | test262/test/language/identifiers/start-unicode-5.2.0-class.js 53 | test262/test/language/identifiers/start-unicode-8.0.0-class-escaped.js 54 | test262/test/language/identifiers/start-unicode-8.0.0-class.js 55 | test262/test/language/identifiers/start-unicode-9.0.0-class-escaped.js 56 | test262/test/language/identifiers/start-unicode-9.0.0-class.js 57 | test262/test/language/identifiers/start-unicode-10.0.0-class-escaped.js 58 | test262/test/language/identifiers/start-unicode-10.0.0-class.js 59 | test262/test/language/identifiers/start-unicode-13.0.0-class-escaped.js 60 | test262/test/language/identifiers/start-unicode-13.0.0-class.js 61 | test262/test/language/identifiers/start-unicode-15.0.0-class-escaped.js 62 | test262/test/language/identifiers/start-unicode-15.0.0-class.js 63 | 64 | # Atomics tests with 2 second delays 65 | test262/test/built-ins/Atomics/notify/bigint/notify-all-on-loc.js 66 | test262/test/built-ins/Atomics/notify/negative-count.js 67 | test262/test/built-ins/Atomics/notify/notify-all-on-loc.js 68 | test262/test/built-ins/Atomics/notify/notify-all.js 69 | test262/test/built-ins/Atomics/notify/notify-nan.js 70 | test262/test/built-ins/Atomics/notify/notify-one.js 71 | test262/test/built-ins/Atomics/notify/notify-two.js 72 | test262/test/built-ins/Atomics/notify/notify-zero.js 73 | 74 | # Atomics tests with 400 millisecond delays 75 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-no-operation.js 76 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-add.js 77 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-and.js 78 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-compareExchange.js 79 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-exchange.js 80 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-or.js 81 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-store.js 82 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-sub.js 83 | test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-xor.js 84 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-no-operation.js 85 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-add.js 86 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-and.js 87 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-compareExchange.js 88 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-exchange.js 89 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-or.js 90 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-store.js 91 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-sub.js 92 | test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-xor.js 93 | 94 | # Atomics tests with 200 millisecond delays 95 | test262/test/built-ins/Atomics/notify/count-defaults-to-infinity-missing.js 96 | test262/test/built-ins/Atomics/notify/count-defaults-to-infinity-undefined.js 97 | test262/test/built-ins/Atomics/notify/notify-renotify-noop.js 98 | test262/test/built-ins/Atomics/notify/undefined-index-defaults-to-zero.js 99 | test262/test/built-ins/Atomics/wait/bigint/false-for-timeout-agent.js 100 | test262/test/built-ins/Atomics/wait/bigint/nan-for-timeout.js 101 | test262/test/built-ins/Atomics/wait/bigint/negative-timeout-agent.js 102 | test262/test/built-ins/Atomics/wait/bigint/value-not-equal.js 103 | test262/test/built-ins/Atomics/wait/bigint/was-woken-before-timeout.js 104 | test262/test/built-ins/Atomics/wait/false-for-timeout-agent.js 105 | test262/test/built-ins/Atomics/wait/nan-for-timeout.js 106 | test262/test/built-ins/Atomics/wait/negative-timeout-agent.js 107 | test262/test/built-ins/Atomics/wait/null-for-timeout-agent.js 108 | test262/test/built-ins/Atomics/wait/object-for-timeout-agent.js 109 | test262/test/built-ins/Atomics/wait/poisoned-object-for-timeout-throws-agent.js 110 | test262/test/built-ins/Atomics/wait/symbol-for-index-throws-agent.js 111 | test262/test/built-ins/Atomics/wait/symbol-for-timeout-throws-agent.js 112 | test262/test/built-ins/Atomics/wait/symbol-for-value-throws-agent.js 113 | test262/test/built-ins/Atomics/wait/true-for-timeout-agent.js 114 | test262/test/built-ins/Atomics/wait/undefined-for-timeout.js 115 | test262/test/built-ins/Atomics/wait/undefined-index-defaults-to-zero.js 116 | test262/test/built-ins/Atomics/wait/value-not-equal.js 117 | test262/test/built-ins/Atomics/wait/wait-index-value-not-equal.js 118 | test262/test/built-ins/Atomics/wait/was-woken-before-timeout.js 119 | 120 | # lengthy regexp literal construction (>500 ms) 121 | test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js 122 | test262/test/language/literals/regexp/S7.8.5_A1.4_T2.js 123 | test262/test/language/literals/regexp/S7.8.5_A2.1_T2.js 124 | test262/test/language/literals/regexp/S7.8.5_A2.4_T2.js 125 | 126 | # lengthy built-ins tests (100-200 ms) 127 | test262/test/built-ins/Function/prototype/toString/built-in-function-object.js 128 | test262/test/built-ins/decodeURI/S15.1.3.1_A2.4_T1.js 129 | test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.4_T1.js 130 | test262/test/built-ins/encodeURI/S15.1.3.3_A2.3_T1.js 131 | test262/test/built-ins/encodeURIComponent/S15.1.3.4_A2.3_T1.js 132 | test262/test/language/expressions/dynamic-import/await-import-evaluation.js 133 | -------------------------------------------------------------------------------- /unicode_gen_def.h: -------------------------------------------------------------------------------- 1 | #ifdef UNICODE_GENERAL_CATEGORY 2 | DEF(Cn, "Unassigned") /* must be zero */ 3 | DEF(Lu, "Uppercase_Letter") 4 | DEF(Ll, "Lowercase_Letter") 5 | DEF(Lt, "Titlecase_Letter") 6 | DEF(Lm, "Modifier_Letter") 7 | DEF(Lo, "Other_Letter") 8 | DEF(Mn, "Nonspacing_Mark") 9 | DEF(Mc, "Spacing_Mark") 10 | DEF(Me, "Enclosing_Mark") 11 | DEF(Nd, "Decimal_Number,digit") 12 | DEF(Nl, "Letter_Number") 13 | DEF(No, "Other_Number") 14 | DEF(Sm, "Math_Symbol") 15 | DEF(Sc, "Currency_Symbol") 16 | DEF(Sk, "Modifier_Symbol") 17 | DEF(So, "Other_Symbol") 18 | DEF(Pc, "Connector_Punctuation") 19 | DEF(Pd, "Dash_Punctuation") 20 | DEF(Ps, "Open_Punctuation") 21 | DEF(Pe, "Close_Punctuation") 22 | DEF(Pi, "Initial_Punctuation") 23 | DEF(Pf, "Final_Punctuation") 24 | DEF(Po, "Other_Punctuation") 25 | DEF(Zs, "Space_Separator") 26 | DEF(Zl, "Line_Separator") 27 | DEF(Zp, "Paragraph_Separator") 28 | DEF(Cc, "Control,cntrl") 29 | DEF(Cf, "Format") 30 | DEF(Cs, "Surrogate") 31 | DEF(Co, "Private_Use") 32 | /* synthetic properties */ 33 | DEF(LC, "Cased_Letter") 34 | DEF(L, "Letter") 35 | DEF(M, "Mark,Combining_Mark") 36 | DEF(N, "Number") 37 | DEF(S, "Symbol") 38 | DEF(P, "Punctuation,punct") 39 | DEF(Z, "Separator") 40 | DEF(C, "Other") 41 | #endif 42 | 43 | #ifdef UNICODE_SCRIPT 44 | /* scripts aliases names in PropertyValueAliases.txt */ 45 | DEF(Unknown, "Zzzz") 46 | DEF(Adlam, "Adlm") 47 | DEF(Ahom, "Ahom") 48 | DEF(Anatolian_Hieroglyphs, "Hluw") 49 | DEF(Arabic, "Arab") 50 | DEF(Armenian, "Armn") 51 | DEF(Avestan, "Avst") 52 | DEF(Balinese, "Bali") 53 | DEF(Bamum, "Bamu") 54 | DEF(Bassa_Vah, "Bass") 55 | DEF(Batak, "Batk") 56 | DEF(Bengali, "Beng") 57 | DEF(Bhaiksuki, "Bhks") 58 | DEF(Bopomofo, "Bopo") 59 | DEF(Brahmi, "Brah") 60 | DEF(Braille, "Brai") 61 | DEF(Buginese, "Bugi") 62 | DEF(Buhid, "Buhd") 63 | DEF(Canadian_Aboriginal, "Cans") 64 | DEF(Carian, "Cari") 65 | DEF(Caucasian_Albanian, "Aghb") 66 | DEF(Chakma, "Cakm") 67 | DEF(Cham, "Cham") 68 | DEF(Cherokee, "Cher") 69 | DEF(Chorasmian, "Chrs") 70 | DEF(Common, "Zyyy") 71 | DEF(Coptic, "Copt,Qaac") 72 | DEF(Cuneiform, "Xsux") 73 | DEF(Cypriot, "Cprt") 74 | DEF(Cyrillic, "Cyrl") 75 | DEF(Cypro_Minoan, "Cpmn") 76 | DEF(Deseret, "Dsrt") 77 | DEF(Devanagari, "Deva") 78 | DEF(Dives_Akuru, "Diak") 79 | DEF(Dogra, "Dogr") 80 | DEF(Duployan, "Dupl") 81 | DEF(Egyptian_Hieroglyphs, "Egyp") 82 | DEF(Elbasan, "Elba") 83 | DEF(Elymaic, "Elym") 84 | DEF(Ethiopic, "Ethi") 85 | DEF(Georgian, "Geor") 86 | DEF(Glagolitic, "Glag") 87 | DEF(Gothic, "Goth") 88 | DEF(Garay, "Gara") 89 | DEF(Grantha, "Gran") 90 | DEF(Greek, "Grek") 91 | DEF(Gujarati, "Gujr") 92 | DEF(Gunjala_Gondi, "Gong") 93 | DEF(Gurmukhi, "Guru") 94 | DEF(Gurung_Khema, "Gukh") 95 | DEF(Han, "Hani") 96 | DEF(Hangul, "Hang") 97 | DEF(Hanifi_Rohingya, "Rohg") 98 | DEF(Hanunoo, "Hano") 99 | DEF(Hatran, "Hatr") 100 | DEF(Hebrew, "Hebr") 101 | DEF(Hiragana, "Hira") 102 | DEF(Imperial_Aramaic, "Armi") 103 | DEF(Inherited, "Zinh,Qaai") 104 | DEF(Inscriptional_Pahlavi, "Phli") 105 | DEF(Inscriptional_Parthian, "Prti") 106 | DEF(Javanese, "Java") 107 | DEF(Kaithi, "Kthi") 108 | DEF(Kannada, "Knda") 109 | DEF(Katakana, "Kana") 110 | DEF(Kawi, "Kawi") 111 | DEF(Kayah_Li, "Kali") 112 | DEF(Kharoshthi, "Khar") 113 | DEF(Khmer, "Khmr") 114 | DEF(Khojki, "Khoj") 115 | DEF(Khitan_Small_Script, "Kits") 116 | DEF(Khudawadi, "Sind") 117 | DEF(Kirat_Rai, "Krai") 118 | DEF(Lao, "Laoo") 119 | DEF(Latin, "Latn") 120 | DEF(Lepcha, "Lepc") 121 | DEF(Limbu, "Limb") 122 | DEF(Linear_A, "Lina") 123 | DEF(Linear_B, "Linb") 124 | DEF(Lisu, "Lisu") 125 | DEF(Lycian, "Lyci") 126 | DEF(Lydian, "Lydi") 127 | DEF(Makasar, "Maka") 128 | DEF(Mahajani, "Mahj") 129 | DEF(Malayalam, "Mlym") 130 | DEF(Mandaic, "Mand") 131 | DEF(Manichaean, "Mani") 132 | DEF(Marchen, "Marc") 133 | DEF(Masaram_Gondi, "Gonm") 134 | DEF(Medefaidrin, "Medf") 135 | DEF(Meetei_Mayek, "Mtei") 136 | DEF(Mende_Kikakui, "Mend") 137 | DEF(Meroitic_Cursive, "Merc") 138 | DEF(Meroitic_Hieroglyphs, "Mero") 139 | DEF(Miao, "Plrd") 140 | DEF(Modi, "Modi") 141 | DEF(Mongolian, "Mong") 142 | DEF(Mro, "Mroo") 143 | DEF(Multani, "Mult") 144 | DEF(Myanmar, "Mymr") 145 | DEF(Nabataean, "Nbat") 146 | DEF(Nag_Mundari, "Nagm") 147 | DEF(Nandinagari, "Nand") 148 | DEF(New_Tai_Lue, "Talu") 149 | DEF(Newa, "Newa") 150 | DEF(Nko, "Nkoo") 151 | DEF(Nushu, "Nshu") 152 | DEF(Nyiakeng_Puachue_Hmong, "Hmnp") 153 | DEF(Ogham, "Ogam") 154 | DEF(Ol_Chiki, "Olck") 155 | DEF(Ol_Onal, "Onao") 156 | DEF(Old_Hungarian, "Hung") 157 | DEF(Old_Italic, "Ital") 158 | DEF(Old_North_Arabian, "Narb") 159 | DEF(Old_Permic, "Perm") 160 | DEF(Old_Persian, "Xpeo") 161 | DEF(Old_Sogdian, "Sogo") 162 | DEF(Old_South_Arabian, "Sarb") 163 | DEF(Old_Turkic, "Orkh") 164 | DEF(Old_Uyghur, "Ougr") 165 | DEF(Oriya, "Orya") 166 | DEF(Osage, "Osge") 167 | DEF(Osmanya, "Osma") 168 | DEF(Pahawh_Hmong, "Hmng") 169 | DEF(Palmyrene, "Palm") 170 | DEF(Pau_Cin_Hau, "Pauc") 171 | DEF(Phags_Pa, "Phag") 172 | DEF(Phoenician, "Phnx") 173 | DEF(Psalter_Pahlavi, "Phlp") 174 | DEF(Rejang, "Rjng") 175 | DEF(Runic, "Runr") 176 | DEF(Samaritan, "Samr") 177 | DEF(Saurashtra, "Saur") 178 | DEF(Sharada, "Shrd") 179 | DEF(Shavian, "Shaw") 180 | DEF(Siddham, "Sidd") 181 | DEF(SignWriting, "Sgnw") 182 | DEF(Sinhala, "Sinh") 183 | DEF(Sogdian, "Sogd") 184 | DEF(Sora_Sompeng, "Sora") 185 | DEF(Soyombo, "Soyo") 186 | DEF(Sundanese, "Sund") 187 | DEF(Sunuwar, "Sunu") 188 | DEF(Syloti_Nagri, "Sylo") 189 | DEF(Syriac, "Syrc") 190 | DEF(Tagalog, "Tglg") 191 | DEF(Tagbanwa, "Tagb") 192 | DEF(Tai_Le, "Tale") 193 | DEF(Tai_Tham, "Lana") 194 | DEF(Tai_Viet, "Tavt") 195 | DEF(Takri, "Takr") 196 | DEF(Tamil, "Taml") 197 | DEF(Tangut, "Tang") 198 | DEF(Telugu, "Telu") 199 | DEF(Thaana, "Thaa") 200 | DEF(Thai, "Thai") 201 | DEF(Tibetan, "Tibt") 202 | DEF(Tifinagh, "Tfng") 203 | DEF(Tirhuta, "Tirh") 204 | DEF(Tangsa, "Tnsa") 205 | DEF(Todhri, "Todr") 206 | DEF(Toto, "Toto") 207 | DEF(Tulu_Tigalari, "Tutg") 208 | DEF(Ugaritic, "Ugar") 209 | DEF(Vai, "Vaii") 210 | DEF(Vithkuqi, "Vith") 211 | DEF(Wancho, "Wcho") 212 | DEF(Warang_Citi, "Wara") 213 | DEF(Yezidi, "Yezi") 214 | DEF(Yi, "Yiii") 215 | DEF(Zanabazar_Square, "Zanb") 216 | #endif 217 | 218 | #ifdef UNICODE_PROP_LIST 219 | /* Prop list not exported to regexp */ 220 | DEF(Hyphen, "") 221 | DEF(Other_Math, "") 222 | DEF(Other_Alphabetic, "") 223 | DEF(Other_Lowercase, "") 224 | DEF(Other_Uppercase, "") 225 | DEF(Other_Grapheme_Extend, "") 226 | DEF(Other_Default_Ignorable_Code_Point, "") 227 | DEF(Other_ID_Start, "") 228 | DEF(Other_ID_Continue, "") 229 | DEF(Prepended_Concatenation_Mark, "") 230 | /* additional computed properties for smaller tables */ 231 | DEF(ID_Continue1, "") 232 | DEF(XID_Start1, "") 233 | DEF(XID_Continue1, "") 234 | DEF(Changes_When_Titlecased1, "") 235 | DEF(Changes_When_Casefolded1, "") 236 | DEF(Changes_When_NFKC_Casefolded1, "") 237 | 238 | /* Prop list exported to JS */ 239 | DEF(ASCII_Hex_Digit, "AHex") 240 | DEF(Bidi_Control, "Bidi_C") 241 | DEF(Dash, "") 242 | DEF(Deprecated, "Dep") 243 | DEF(Diacritic, "Dia") 244 | DEF(Extender, "Ext") 245 | DEF(Hex_Digit, "Hex") 246 | DEF(IDS_Unary_Operator, "IDSU") 247 | DEF(IDS_Binary_Operator, "IDSB") 248 | DEF(IDS_Trinary_Operator, "IDST") 249 | DEF(Ideographic, "Ideo") 250 | DEF(Join_Control, "Join_C") 251 | DEF(Logical_Order_Exception, "LOE") 252 | DEF(Modifier_Combining_Mark, "MCM") 253 | DEF(Noncharacter_Code_Point, "NChar") 254 | DEF(Pattern_Syntax, "Pat_Syn") 255 | DEF(Pattern_White_Space, "Pat_WS") 256 | DEF(Quotation_Mark, "QMark") 257 | DEF(Radical, "") 258 | DEF(Regional_Indicator, "RI") 259 | DEF(Sentence_Terminal, "STerm") 260 | DEF(Soft_Dotted, "SD") 261 | DEF(Terminal_Punctuation, "Term") 262 | DEF(Unified_Ideograph, "UIdeo") 263 | DEF(Variation_Selector, "VS") 264 | DEF(White_Space, "space") 265 | DEF(Bidi_Mirrored, "Bidi_M") 266 | DEF(Emoji, "") 267 | DEF(Emoji_Component, "EComp") 268 | DEF(Emoji_Modifier, "EMod") 269 | DEF(Emoji_Modifier_Base, "EBase") 270 | DEF(Emoji_Presentation, "EPres") 271 | DEF(Extended_Pictographic, "ExtPict") 272 | DEF(Default_Ignorable_Code_Point, "DI") 273 | DEF(ID_Start, "IDS") 274 | DEF(Case_Ignorable, "CI") 275 | 276 | /* other binary properties */ 277 | DEF(ASCII,"") 278 | DEF(Alphabetic, "Alpha") 279 | DEF(Any, "") 280 | DEF(Assigned,"") 281 | DEF(Cased, "") 282 | DEF(Changes_When_Casefolded, "CWCF") 283 | DEF(Changes_When_Casemapped, "CWCM") 284 | DEF(Changes_When_Lowercased, "CWL") 285 | DEF(Changes_When_NFKC_Casefolded, "CWKCF") 286 | DEF(Changes_When_Titlecased, "CWT") 287 | DEF(Changes_When_Uppercased, "CWU") 288 | DEF(Grapheme_Base, "Gr_Base") 289 | DEF(Grapheme_Extend, "Gr_Ext") 290 | DEF(ID_Continue, "IDC") 291 | DEF(ID_Compat_Math_Start, "") 292 | DEF(ID_Compat_Math_Continue, "") 293 | DEF(Lowercase, "Lower") 294 | DEF(Math, "") 295 | DEF(Uppercase, "Upper") 296 | DEF(XID_Continue, "XIDC") 297 | DEF(XID_Start, "XIDS") 298 | 299 | /* internal tables with index */ 300 | DEF(Cased1, "") 301 | 302 | /* unused by us */ 303 | DEF(InCB, "") 304 | 305 | #endif 306 | -------------------------------------------------------------------------------- /quickjs-atom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QuickJS atom definitions 3 | * 4 | * Copyright (c) 2017-2018 Fabrice Bellard 5 | * Copyright (c) 2017-2018 Charlie Gordon 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | 26 | #ifdef DEF 27 | 28 | /* Note: first atoms are considered as keywords in the parser */ 29 | DEF(null, "null") /* must be first */ 30 | DEF(false, "false") 31 | DEF(true, "true") 32 | DEF(if, "if") 33 | DEF(else, "else") 34 | DEF(return, "return") 35 | DEF(var, "var") 36 | DEF(this, "this") 37 | DEF(delete, "delete") 38 | DEF(void, "void") 39 | DEF(typeof, "typeof") 40 | DEF(new, "new") 41 | DEF(in, "in") 42 | DEF(instanceof, "instanceof") 43 | DEF(do, "do") 44 | DEF(while, "while") 45 | DEF(for, "for") 46 | DEF(break, "break") 47 | DEF(continue, "continue") 48 | DEF(switch, "switch") 49 | DEF(case, "case") 50 | DEF(default, "default") 51 | DEF(throw, "throw") 52 | DEF(try, "try") 53 | DEF(catch, "catch") 54 | DEF(finally, "finally") 55 | DEF(function, "function") 56 | DEF(debugger, "debugger") 57 | DEF(with, "with") 58 | /* FutureReservedWord */ 59 | DEF(class, "class") 60 | DEF(const, "const") 61 | DEF(enum, "enum") 62 | DEF(export, "export") 63 | DEF(extends, "extends") 64 | DEF(import, "import") 65 | DEF(super, "super") 66 | /* FutureReservedWords when parsing strict mode code */ 67 | DEF(implements, "implements") 68 | DEF(interface, "interface") 69 | DEF(let, "let") 70 | DEF(package, "package") 71 | DEF(private, "private") 72 | DEF(protected, "protected") 73 | DEF(public, "public") 74 | DEF(static, "static") 75 | DEF(yield, "yield") 76 | DEF(await, "await") 77 | 78 | /* empty string */ 79 | DEF(empty_string, "") 80 | /* identifiers */ 81 | DEF(keys, "keys") 82 | DEF(size, "size") 83 | DEF(length, "length") 84 | DEF(message, "message") 85 | DEF(cause, "cause") 86 | DEF(errors, "errors") 87 | DEF(stack, "stack") 88 | DEF(name, "name") 89 | DEF(toString, "toString") 90 | DEF(toLocaleString, "toLocaleString") 91 | DEF(valueOf, "valueOf") 92 | DEF(eval, "eval") 93 | DEF(prototype, "prototype") 94 | DEF(constructor, "constructor") 95 | DEF(configurable, "configurable") 96 | DEF(writable, "writable") 97 | DEF(enumerable, "enumerable") 98 | DEF(value, "value") 99 | DEF(get, "get") 100 | DEF(set, "set") 101 | DEF(of, "of") 102 | DEF(__proto__, "__proto__") 103 | DEF(undefined, "undefined") 104 | DEF(number, "number") 105 | DEF(boolean, "boolean") 106 | DEF(string, "string") 107 | DEF(object, "object") 108 | DEF(symbol, "symbol") 109 | DEF(integer, "integer") 110 | DEF(unknown, "unknown") 111 | DEF(arguments, "arguments") 112 | DEF(callee, "callee") 113 | DEF(caller, "caller") 114 | DEF(_eval_, "") 115 | DEF(_ret_, "") 116 | DEF(_var_, "") 117 | DEF(_arg_var_, "") 118 | DEF(_with_, "") 119 | DEF(lastIndex, "lastIndex") 120 | DEF(target, "target") 121 | DEF(index, "index") 122 | DEF(input, "input") 123 | DEF(defineProperties, "defineProperties") 124 | DEF(apply, "apply") 125 | DEF(join, "join") 126 | DEF(concat, "concat") 127 | DEF(split, "split") 128 | DEF(construct, "construct") 129 | DEF(getPrototypeOf, "getPrototypeOf") 130 | DEF(setPrototypeOf, "setPrototypeOf") 131 | DEF(isExtensible, "isExtensible") 132 | DEF(preventExtensions, "preventExtensions") 133 | DEF(has, "has") 134 | DEF(deleteProperty, "deleteProperty") 135 | DEF(defineProperty, "defineProperty") 136 | DEF(getOwnPropertyDescriptor, "getOwnPropertyDescriptor") 137 | DEF(ownKeys, "ownKeys") 138 | DEF(add, "add") 139 | DEF(done, "done") 140 | DEF(next, "next") 141 | DEF(values, "values") 142 | DEF(source, "source") 143 | DEF(flags, "flags") 144 | DEF(global, "global") 145 | DEF(unicode, "unicode") 146 | DEF(raw, "raw") 147 | DEF(new_target, "new.target") 148 | DEF(this_active_func, "this.active_func") 149 | DEF(home_object, "") 150 | DEF(computed_field, "") 151 | DEF(static_computed_field, "") /* must come after computed_fields */ 152 | DEF(class_fields_init, "") 153 | DEF(brand, "") 154 | DEF(hash_constructor, "#constructor") 155 | DEF(as, "as") 156 | DEF(from, "from") 157 | DEF(fromAsync, "fromAsync") 158 | DEF(meta, "meta") 159 | DEF(_default_, "*default*") 160 | DEF(_star_, "*") 161 | DEF(Module, "Module") 162 | DEF(then, "then") 163 | DEF(resolve, "resolve") 164 | DEF(reject, "reject") 165 | DEF(promise, "promise") 166 | DEF(proxy, "proxy") 167 | DEF(revoke, "revoke") 168 | DEF(async, "async") 169 | DEF(exec, "exec") 170 | DEF(groups, "groups") 171 | DEF(indices, "indices") 172 | DEF(status, "status") 173 | DEF(reason, "reason") 174 | DEF(globalThis, "globalThis") 175 | DEF(bigint, "bigint") 176 | DEF(not_equal, "not-equal") 177 | DEF(timed_out, "timed-out") 178 | DEF(ok, "ok") 179 | DEF(toJSON, "toJSON") 180 | DEF(maxByteLength, "maxByteLength") 181 | /* class names */ 182 | DEF(Object, "Object") 183 | DEF(Array, "Array") 184 | DEF(Error, "Error") 185 | DEF(Number, "Number") 186 | DEF(String, "String") 187 | DEF(Boolean, "Boolean") 188 | DEF(Symbol, "Symbol") 189 | DEF(Arguments, "Arguments") 190 | DEF(Math, "Math") 191 | DEF(JSON, "JSON") 192 | DEF(Date, "Date") 193 | DEF(Function, "Function") 194 | DEF(GeneratorFunction, "GeneratorFunction") 195 | DEF(ForInIterator, "ForInIterator") 196 | DEF(RegExp, "RegExp") 197 | DEF(ArrayBuffer, "ArrayBuffer") 198 | DEF(SharedArrayBuffer, "SharedArrayBuffer") 199 | /* must keep same order as class IDs for typed arrays */ 200 | DEF(Uint8ClampedArray, "Uint8ClampedArray") 201 | DEF(Int8Array, "Int8Array") 202 | DEF(Uint8Array, "Uint8Array") 203 | DEF(Int16Array, "Int16Array") 204 | DEF(Uint16Array, "Uint16Array") 205 | DEF(Int32Array, "Int32Array") 206 | DEF(Uint32Array, "Uint32Array") 207 | DEF(BigInt64Array, "BigInt64Array") 208 | DEF(BigUint64Array, "BigUint64Array") 209 | DEF(Float16Array, "Float16Array") 210 | DEF(Float32Array, "Float32Array") 211 | DEF(Float64Array, "Float64Array") 212 | DEF(DataView, "DataView") 213 | DEF(BigInt, "BigInt") 214 | DEF(WeakRef, "WeakRef") 215 | DEF(FinalizationRegistry, "FinalizationRegistry") 216 | DEF(Map, "Map") 217 | DEF(Set, "Set") /* Map + 1 */ 218 | DEF(WeakMap, "WeakMap") /* Map + 2 */ 219 | DEF(WeakSet, "WeakSet") /* Map + 3 */ 220 | DEF(Iterator, "Iterator") 221 | DEF(IteratorHelper, "Iterator Helper") 222 | DEF(IteratorWrap, "Iterator Wrap") 223 | DEF(Map_Iterator, "Map Iterator") 224 | DEF(Set_Iterator, "Set Iterator") 225 | DEF(Array_Iterator, "Array Iterator") 226 | DEF(String_Iterator, "String Iterator") 227 | DEF(RegExp_String_Iterator, "RegExp String Iterator") 228 | DEF(Generator, "Generator") 229 | DEF(Proxy, "Proxy") 230 | DEF(Promise, "Promise") 231 | DEF(PromiseResolveFunction, "PromiseResolveFunction") 232 | DEF(PromiseRejectFunction, "PromiseRejectFunction") 233 | DEF(AsyncFunction, "AsyncFunction") 234 | DEF(AsyncFunctionResolve, "AsyncFunctionResolve") 235 | DEF(AsyncFunctionReject, "AsyncFunctionReject") 236 | DEF(AsyncGeneratorFunction, "AsyncGeneratorFunction") 237 | DEF(AsyncGenerator, "AsyncGenerator") 238 | DEF(EvalError, "EvalError") 239 | DEF(RangeError, "RangeError") 240 | DEF(ReferenceError, "ReferenceError") 241 | DEF(SyntaxError, "SyntaxError") 242 | DEF(TypeError, "TypeError") 243 | DEF(URIError, "URIError") 244 | DEF(InternalError, "InternalError") 245 | DEF(CallSite, "CallSite") 246 | /* private symbols */ 247 | DEF(Private_brand, "") 248 | /* symbols */ 249 | DEF(Symbol_toPrimitive, "Symbol.toPrimitive") 250 | DEF(Symbol_iterator, "Symbol.iterator") 251 | DEF(Symbol_match, "Symbol.match") 252 | DEF(Symbol_matchAll, "Symbol.matchAll") 253 | DEF(Symbol_replace, "Symbol.replace") 254 | DEF(Symbol_search, "Symbol.search") 255 | DEF(Symbol_split, "Symbol.split") 256 | DEF(Symbol_toStringTag, "Symbol.toStringTag") 257 | DEF(Symbol_isConcatSpreadable, "Symbol.isConcatSpreadable") 258 | DEF(Symbol_hasInstance, "Symbol.hasInstance") 259 | DEF(Symbol_species, "Symbol.species") 260 | DEF(Symbol_unscopables, "Symbol.unscopables") 261 | DEF(Symbol_asyncIterator, "Symbol.asyncIterator") 262 | 263 | #endif /* DEF */ 264 | -------------------------------------------------------------------------------- /tests/test_std.js: -------------------------------------------------------------------------------- 1 | import * as std from "qjs:std"; 2 | import * as os from "qjs:os"; 3 | import { assert } from "./assert.js"; 4 | 5 | const isWin = os.platform === 'win32'; 6 | const isCygwin = os.platform === 'cygwin'; 7 | 8 | 9 | function test_printf() 10 | { 11 | assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc"); 12 | assert(std.sprintf("%010d", 123), "0000000123"); 13 | assert(std.sprintf("%x", -2), "fffffffe"); 14 | assert(std.sprintf("%lx", -2), "fffffffffffffffe"); 15 | assert(std.sprintf("%10.1f", 2.1), " 2.1"); 16 | assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13"); 17 | assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff"); 18 | } 19 | 20 | function test_file1() 21 | { 22 | var f, len, str, size, buf, ret, i, str1, ab; 23 | 24 | f = std.tmpfile(); 25 | str = "hello world\n"; 26 | f.puts(str); 27 | 28 | f.seek(0, std.SEEK_SET); 29 | ab = f.readAsArrayBuffer(); 30 | assert([...new Uint8Array(ab)], str.split("").map(c => c.charCodeAt(0))); 31 | 32 | f.seek(0, std.SEEK_SET); 33 | str1 = f.readAsString(); 34 | assert(str1, str); 35 | 36 | f.seek(0, std.SEEK_END); 37 | size = f.tell(); 38 | assert(size, str.length); 39 | 40 | f.seek(0, std.SEEK_SET); 41 | 42 | buf = new Uint8Array(size); 43 | ret = f.read(buf.buffer, 0, size); 44 | assert(ret, size); 45 | for(i = 0; i < size; i++) 46 | assert(buf[i], str.charCodeAt(i)); 47 | 48 | f.close(); 49 | } 50 | 51 | function test_file2() 52 | { 53 | var f, str, i, size; 54 | f = std.tmpfile(); 55 | str = "hello world\n"; 56 | size = str.length; 57 | for(i = 0; i < size; i++) 58 | f.putByte(str.charCodeAt(i)); 59 | f.seek(0, std.SEEK_SET); 60 | for(i = 0; i < size; i++) { 61 | assert(str.charCodeAt(i), f.getByte()); 62 | } 63 | assert(f.getByte(), -1); 64 | f.close(); 65 | } 66 | 67 | function test_getline() 68 | { 69 | var f, line, line_count, lines, i; 70 | 71 | lines = ["hello world", "line 1", "line 2" ]; 72 | f = std.tmpfile(); 73 | for(i = 0; i < lines.length; i++) { 74 | f.puts(lines[i], "\n"); 75 | } 76 | 77 | f.seek(0, std.SEEK_SET); 78 | assert(!f.eof()); 79 | line_count = 0; 80 | for(;;) { 81 | line = f.getline(); 82 | if (line === null) 83 | break; 84 | assert(line, lines[line_count]); 85 | line_count++; 86 | } 87 | assert(f.eof()); 88 | assert(line_count, lines.length); 89 | 90 | f.close(); 91 | } 92 | 93 | function test_popen() 94 | { 95 | var str, f, fname = "tmp_file.txt"; 96 | var ta, content = "hello world"; 97 | var cmd = isWin ? "type" : "cat"; 98 | 99 | ta = new Uint8Array([...content].map(c => c.charCodeAt(0))); 100 | std.writeFile(fname, ta); 101 | assert(std.loadFile(fname), content); 102 | std.writeFile(fname, ta.buffer); 103 | assert(std.loadFile(fname), content); 104 | std.writeFile(fname, content); 105 | assert(std.loadFile(fname), content); 106 | 107 | // popen pipe is unidirectional so mode should 108 | // be either read or write but not both 109 | let caught = false; 110 | try { 111 | std.popen(cmd, "rw"); 112 | } catch (e) { 113 | assert(/invalid file mode/.test(e.message)); 114 | caught = true; 115 | } 116 | assert(caught); 117 | 118 | /* execute shell command */ 119 | f = std.popen(cmd + " " + fname, "r"); 120 | str = f.readAsString(); 121 | f.close(); 122 | 123 | assert(str, content); 124 | 125 | os.remove(fname); 126 | } 127 | 128 | function test_os() 129 | { 130 | var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path; 131 | 132 | // XXX(bnoordhuis) disabled because stdio is not a tty on CI 133 | //assert(os.isatty(0)); 134 | 135 | fdir = "test_tmp_dir"; 136 | fname = "tmp_file.txt"; 137 | fpath = fdir + "/" + fname; 138 | link_path = fdir + "/test_link"; 139 | 140 | os.remove(link_path); 141 | os.remove(fpath); 142 | os.remove(fdir); 143 | 144 | err = os.mkdir(fdir, 0o755); 145 | assert(err, 0); 146 | 147 | fd = os.open(fpath, os.O_RDWR | os.O_CREAT | os.O_TRUNC); 148 | assert(fd >= 0); 149 | 150 | buf = new Uint8Array(10); 151 | for(i = 0; i < buf.length; i++) 152 | buf[i] = i; 153 | assert(os.write(fd, buf.buffer, 0, buf.length), buf.length); 154 | 155 | assert(os.seek(fd, 0, std.SEEK_SET), 0); 156 | buf2 = new Uint8Array(buf.length); 157 | assert(os.read(fd, buf2.buffer, 0, buf2.length), buf2.length); 158 | 159 | for(i = 0; i < buf.length; i++) 160 | assert(buf[i] == buf2[i]); 161 | 162 | if (typeof BigInt !== "undefined") { 163 | assert(os.seek(fd, BigInt(6), std.SEEK_SET), BigInt(6)); 164 | assert(os.read(fd, buf2.buffer, 0, 1), 1); 165 | assert(buf[6] == buf2[0]); 166 | } 167 | 168 | assert(os.close(fd), 0); 169 | 170 | [files, err] = os.readdir(fdir); 171 | assert(err, 0); 172 | assert(files.length >= 3); 173 | assert(files.includes(fname)); 174 | assert(files.includes(".")); 175 | assert(files.includes("..")); 176 | 177 | fdate = 10000; 178 | 179 | err = os.utimes(fpath, fdate, fdate); 180 | assert(err, 0); 181 | 182 | [st, err] = os.stat(fpath); 183 | assert(err, 0); 184 | assert(st.mode & os.S_IFMT, os.S_IFREG); 185 | assert(st.mtime, fdate); 186 | 187 | if (!isWin) { 188 | err = os.symlink(fname, link_path); 189 | assert(err, 0); 190 | 191 | [st, err] = os.lstat(link_path); 192 | assert(err, 0); 193 | assert(st.mode & os.S_IFMT, os.S_IFLNK); 194 | 195 | [buf, err] = os.readlink(link_path); 196 | assert(err, 0); 197 | assert(buf, fname); 198 | 199 | assert(os.remove(link_path) === 0); 200 | } 201 | 202 | [buf, err] = os.getcwd(); 203 | assert(err, 0); 204 | 205 | [buf2, err] = os.realpath("."); 206 | assert(err, 0); 207 | 208 | assert(buf, buf2); 209 | 210 | assert(os.remove(fpath) === 0); 211 | 212 | fd = os.open(fpath, os.O_RDONLY); 213 | assert(fd < 0); 214 | 215 | assert(os.remove(fdir) === 0); 216 | } 217 | 218 | function test_os_exec() 219 | { 220 | var ret, fds, pid, f, status; 221 | 222 | ret = os.exec(["true"]); 223 | assert(ret, 0); 224 | 225 | ret = os.exec(["/bin/sh", "-c", "exit 1"], { usePath: false }); 226 | assert(ret, 1); 227 | 228 | fds = os.pipe(); 229 | pid = os.exec(["sh", "-c", "echo $FOO"], { 230 | stdout: fds[1], 231 | block: false, 232 | env: { FOO: "hello" }, 233 | } ); 234 | assert(pid >= 0); 235 | os.close(fds[1]); /* close the write end (as it is only in the child) */ 236 | f = std.fdopen(fds[0], "r"); 237 | assert(f.getline(), "hello"); 238 | assert(f.getline(), null); 239 | f.close(); 240 | [ret, status] = os.waitpid(pid, 0); 241 | assert(ret, pid); 242 | assert(status & 0x7f, 0); /* exited */ 243 | assert(status >> 8, 0); /* exit code */ 244 | 245 | pid = os.exec(["cat"], { block: false } ); 246 | assert(pid >= 0); 247 | os.kill(pid, os.SIGTERM); 248 | [ret, status] = os.waitpid(pid, 0); 249 | assert(ret, pid); 250 | // Flaky on cygwin for unclear reasons, see 251 | // https://github.com/quickjs-ng/quickjs/issues/184 252 | if (!isCygwin) { 253 | assert(status & 0x7f, os.SIGTERM); 254 | } 255 | } 256 | 257 | function test_interval() 258 | { 259 | var t = os.setInterval(f, 1); 260 | function f() { 261 | if (++f.count === 3) os.clearInterval(t); 262 | } 263 | f.count = 0; 264 | } 265 | 266 | function test_timeout() 267 | { 268 | var th, i; 269 | 270 | /* just test that a timer can be inserted and removed */ 271 | th = []; 272 | for(i = 0; i < 3; i++) 273 | th[i] = os.setTimeout(function () { }, 1000); 274 | for(i = 0; i < 3; i++) 275 | os.clearTimeout(th[i]); 276 | } 277 | 278 | function test_timeout_order() 279 | { 280 | var s = ""; 281 | os.setTimeout(a, 0); 282 | os.setTimeout(b, 100); 283 | os.setTimeout(d, 700); 284 | function a() { s += "a"; os.setTimeout(c, 300); } 285 | function b() { s += "b"; } 286 | function c() { s += "c"; } 287 | function d() { assert(s, "abc"); } // not "acb" 288 | } 289 | 290 | function test_stdio_close() 291 | { 292 | for (const f of [std.in, std.out, std.err]) { 293 | let caught = false; 294 | try { 295 | f.close(); 296 | } catch (e) { 297 | assert(/cannot close stdio/.test(e.message)); 298 | caught = true; 299 | } 300 | assert(caught); 301 | } 302 | } 303 | 304 | test_printf(); 305 | test_file1(); 306 | test_file2(); 307 | test_getline(); 308 | test_popen(); 309 | test_os(); 310 | !isWin && test_os_exec(); 311 | test_interval(); 312 | test_timeout(); 313 | test_timeout_order(); 314 | test_stdio_close(); 315 | -------------------------------------------------------------------------------- /tests/test_bjson.js: -------------------------------------------------------------------------------- 1 | import * as std from "qjs:std"; 2 | import * as bjson from "qjs:bjson"; 3 | import { assert } from "./assert.js"; 4 | 5 | function base64decode(s) { 6 | var A = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 7 | var n = s.indexOf("="); 8 | if (n < 0) n = s.length; 9 | if (n & 3 === 1) throw Error("bad base64"); // too much padding 10 | var r = new Uint8Array(3 * (n>>2) + (n>>1 & 1) + (n & 1)); 11 | var a, b, c, d, i, j; 12 | a = b = c = d = i = j = 0; 13 | while (i+3 < n) { 14 | a = A.indexOf(s[i++]); 15 | b = A.indexOf(s[i++]); 16 | c = A.indexOf(s[i++]); 17 | d = A.indexOf(s[i++]); 18 | if (~63 & (a|b|c|d)) throw Error("bad base64"); 19 | r[j++] = a<<2 | b>>4; 20 | r[j++] = 255 & b<<4 | c>>2; 21 | r[j++] = 255 & c<<6 | d; 22 | } 23 | switch (n & 3) { 24 | case 2: 25 | a = A.indexOf(s[i++]); 26 | b = A.indexOf(s[i++]); 27 | if (~63 & (a|b)) throw Error("bad base64"); 28 | if (b & 15) throw Error("bad base64"); 29 | r[j++] = a<<2 | b>>4; 30 | break; 31 | case 3: 32 | a = A.indexOf(s[i++]); 33 | b = A.indexOf(s[i++]); 34 | c = A.indexOf(s[i++]); 35 | if (~63 & (a|b|c)) throw Error("bad base64"); 36 | if (c & 3) throw Error("bad base64"); 37 | r[j++] = a<<2 | b>>4; 38 | r[j++] = 255 & b<<4 | c>>2; 39 | break; 40 | } 41 | return r.buffer; 42 | } 43 | 44 | function toHex(a) 45 | { 46 | var i, s = "", tab, v; 47 | tab = new Uint8Array(a); 48 | for(i = 0; i < tab.length; i++) { 49 | v = tab[i].toString(16); 50 | if (v.length < 2) 51 | v = "0" + v; 52 | if (i !== 0) 53 | s += " "; 54 | s += v; 55 | } 56 | return s; 57 | } 58 | 59 | function isArrayLike(a) 60 | { 61 | return Array.isArray(a) || 62 | (a instanceof Uint8ClampedArray) || 63 | (a instanceof Uint8Array) || 64 | (a instanceof Uint16Array) || 65 | (a instanceof Uint32Array) || 66 | (a instanceof Int8Array) || 67 | (a instanceof Int16Array) || 68 | (a instanceof Int32Array) || 69 | (a instanceof Float16Array) || 70 | (a instanceof Float32Array) || 71 | (a instanceof Float64Array); 72 | } 73 | 74 | function toStr(a) 75 | { 76 | var s, i, props, prop; 77 | 78 | switch(typeof(a)) { 79 | case "object": 80 | if (a === null) 81 | return "null"; 82 | if (a instanceof Date) { 83 | s = "Date(" + toStr(a.valueOf()) + ")"; 84 | } else if (a instanceof Number) { 85 | s = "Number(" + toStr(a.valueOf()) + ")"; 86 | } else if (a instanceof String) { 87 | s = "String(" + toStr(a.valueOf()) + ")"; 88 | } else if (a instanceof Boolean) { 89 | s = "Boolean(" + toStr(a.valueOf()) + ")"; 90 | } else if (isArrayLike(a)) { 91 | s = "["; 92 | for(i = 0; i < a.length; i++) { 93 | if (i != 0) 94 | s += ","; 95 | s += toStr(a[i]); 96 | } 97 | s += "]"; 98 | } else { 99 | props = Object.keys(a); 100 | s = "{"; 101 | for(i = 0; i < props.length; i++) { 102 | if (i != 0) 103 | s += ","; 104 | prop = props[i]; 105 | s += prop + ":" + toStr(a[prop]); 106 | } 107 | s += "}"; 108 | } 109 | return s; 110 | case "undefined": 111 | return "undefined"; 112 | case "string": 113 | return JSON.stringify(a); 114 | case "number": 115 | if (a == 0 && 1 / a < 0) 116 | return "-0"; 117 | else 118 | return a.toString(); 119 | break; 120 | default: 121 | return a.toString(); 122 | } 123 | } 124 | 125 | function bjson_test(a) 126 | { 127 | var buf, r, a_str, r_str; 128 | a_str = toStr(a); 129 | buf = bjson.write(a); 130 | if (0) { 131 | print(a_str, "->", toHex(buf)); 132 | } 133 | r = bjson.read(buf, 0, buf.byteLength); 134 | r_str = toStr(r); 135 | if (a_str != r_str) { 136 | print(a_str); 137 | print(r_str); 138 | assert(false); 139 | } 140 | } 141 | 142 | function bjson_test_arraybuffer() 143 | { 144 | var buf, array_buffer; 145 | 146 | array_buffer = new ArrayBuffer(4); 147 | assert(array_buffer.byteLength, 4); 148 | assert(array_buffer.maxByteLength, 4); 149 | assert(array_buffer.resizable, false); 150 | buf = bjson.write(array_buffer); 151 | array_buffer = bjson.read(buf, 0, buf.byteLength); 152 | assert(array_buffer.byteLength, 4); 153 | assert(array_buffer.maxByteLength, 4); 154 | assert(array_buffer.resizable, false); 155 | 156 | array_buffer = new ArrayBuffer(4, {maxByteLength: 4}); 157 | assert(array_buffer.byteLength, 4); 158 | assert(array_buffer.maxByteLength, 4); 159 | assert(array_buffer.resizable, true); 160 | buf = bjson.write(array_buffer); 161 | array_buffer = bjson.read(buf, 0, buf.byteLength); 162 | assert(array_buffer.byteLength, 4); 163 | assert(array_buffer.maxByteLength, 4); 164 | assert(array_buffer.resizable, true); 165 | 166 | array_buffer = new ArrayBuffer(4, {maxByteLength: 8}); 167 | assert(array_buffer.byteLength, 4); 168 | assert(array_buffer.maxByteLength, 8); 169 | assert(array_buffer.resizable, true); 170 | buf = bjson.write(array_buffer); 171 | array_buffer = bjson.read(buf, 0, buf.byteLength); 172 | assert(array_buffer.byteLength, 4); 173 | assert(array_buffer.maxByteLength, 8); 174 | assert(array_buffer.resizable, true); 175 | } 176 | 177 | /* test multiple references to an object including circular 178 | references */ 179 | function bjson_test_reference() 180 | { 181 | var array, buf, i, n, array_buffer; 182 | n = 16; 183 | array = []; 184 | for(i = 0; i < n; i++) 185 | array[i] = {}; 186 | array_buffer = new ArrayBuffer(n); 187 | for(i = 0; i < n; i++) { 188 | array[i].next = array[(i + 1) % n]; 189 | array[i].idx = i; 190 | array[i].typed_array = new Uint8Array(array_buffer, i, 1); 191 | } 192 | buf = bjson.write(array, bjson.WRITE_OBJ_REFERENCE); 193 | 194 | array = bjson.read(buf, 0, buf.byteLength, bjson.READ_OBJ_REFERENCE); 195 | 196 | /* check the result */ 197 | for(i = 0; i < n; i++) { 198 | assert(array[i].next, array[(i + 1) % n]); 199 | assert(array[i].idx, i); 200 | assert(array[i].typed_array.buffer, array_buffer); 201 | assert(array[i].typed_array.length, 1); 202 | assert(array[i].typed_array.byteOffset, i); 203 | } 204 | } 205 | 206 | function bjson_test_regexp() 207 | { 208 | var buf, r; 209 | 210 | bjson_test(/xyzzy/); 211 | bjson_test(/xyzzy/digu); 212 | 213 | buf = bjson.write(/(?<𝓓𝓸𝓰>dog)/); 214 | r = bjson.read(buf, 0, buf.byteLength); 215 | assert("sup dog".match(r).groups["𝓓𝓸𝓰"], "dog"); 216 | } 217 | 218 | function bjson_test_map() 219 | { 220 | var buf, r, xs; 221 | 222 | xs = [["key", "value"]]; 223 | buf = bjson.write(new Map(xs)); 224 | r = bjson.read(buf, 0, buf.byteLength); 225 | assert(r instanceof Map); 226 | assert([...r].toString(), xs.toString()); 227 | } 228 | 229 | function bjson_test_set() 230 | { 231 | var buf, r, xs; 232 | 233 | xs = ["one", "two", "three"]; 234 | buf = bjson.write(new Set(xs)); 235 | r = bjson.read(buf, 0, buf.byteLength); 236 | assert(r instanceof Set); 237 | assert([...r].toString(), xs.toString()); 238 | } 239 | 240 | function bjson_test_symbol() 241 | { 242 | var buf, r, o; 243 | 244 | o = {[Symbol.toStringTag]: "42"}; 245 | buf = bjson.write(o); 246 | r = bjson.read(buf, 0, buf.byteLength); 247 | assert(o.toString(), r.toString()); 248 | 249 | o = Symbol('foo'); 250 | buf = bjson.write(o); 251 | r = bjson.read(buf, 0, buf.byteLength); 252 | assert(o.toString(), r.toString()); 253 | assert(o !== r); 254 | 255 | o = Symbol.for('foo'); 256 | buf = bjson.write(o); 257 | r = bjson.read(buf, 0, buf.byteLength); 258 | assert(o, r); 259 | 260 | o = Symbol.toStringTag; 261 | buf = bjson.write(o); 262 | r = bjson.read(buf, 0, buf.byteLength); 263 | assert(o, r); 264 | } 265 | 266 | function bjson_test_bytecode() 267 | { 268 | var buf, o, r, e, i; 269 | 270 | o = std.evalScript(";(function f(o){ return o.i })", {compile_only: true}); 271 | buf = bjson.write(o, /*JS_WRITE_OBJ_BYTECODE*/(1 << 0)); 272 | try { 273 | bjson.read(buf, 0, buf.byteLength); 274 | } catch (_e) { 275 | e = _e; 276 | } 277 | assert(String(e), "SyntaxError: no bytecode allowed"); 278 | 279 | o = bjson.read(buf, 0, buf.byteLength, /*JS_READ_OBJ_BYTECODE*/(1 << 0)); 280 | assert(String(o), "[function bytecode]"); 281 | o = std.evalScript(o, {eval_function: true}); 282 | for (i = 0; i < 42; i++) o({i}); // exercise o.i IC 283 | } 284 | 285 | function bjson_test_fuzz() 286 | { 287 | var corpus = [ 288 | "FBAAAAAABGA=", 289 | "FObm5oIt", 290 | "FAARABMGBgYGBgYGBgYGBv////8QABEALxH/vy8R/78=", 291 | "FAAIfwAK/////3//////////////////////////////3/8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAD5+fn5+fn5+fn5+fkAAAAAAAYAqw==", 292 | ]; 293 | for (var input of corpus) { 294 | var buf = base64decode(input); 295 | try { 296 | bjson.read(buf, 0, buf.byteLength); 297 | } catch (e) { 298 | if (/invalid version/.test(e.message)) throw e; // corpus needs update 299 | } 300 | } 301 | } 302 | 303 | function bjson_test_all() 304 | { 305 | var obj; 306 | 307 | bjson_test({x:1, y:2, if:3}); 308 | bjson_test([1, 2, 3]); 309 | bjson_test([1.0, "aa", true, false, undefined, null, NaN, -Infinity, -0.0]); 310 | if (typeof BigInt !== "undefined") { 311 | bjson_test([BigInt("1"), -BigInt("0x123456789"), 312 | BigInt("0x123456789abcdef123456789abcdef")]); 313 | } 314 | 315 | bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]); 316 | 317 | bjson_test(new Int32Array([123123, 222111, -32222])); 318 | bjson_test(new Float16Array([1024, 1024.5])); 319 | bjson_test(new Float64Array([123123, 222111.5])); 320 | 321 | /* tested with a circular reference */ 322 | obj = {}; 323 | obj.x = obj; 324 | try { 325 | bjson.write(obj); 326 | assert(false); 327 | } catch(e) { 328 | assert(e instanceof TypeError); 329 | } 330 | 331 | bjson_test_arraybuffer(); 332 | bjson_test_reference(); 333 | bjson_test_regexp(); 334 | bjson_test_map(); 335 | bjson_test_set(); 336 | bjson_test_symbol(); 337 | bjson_test_bytecode(); 338 | bjson_test_fuzz(); 339 | } 340 | 341 | bjson_test_all(); 342 | -------------------------------------------------------------------------------- /test262_errors.txt: -------------------------------------------------------------------------------- 1 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js:64: TypeError: $DONE() not called 2 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/iterator-result-poisoned-wrapper.js:64: strict mode: TypeError: $DONE() not called 3 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js:69: TypeError: $DONE() not called 4 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/next-result-poisoned-wrapper.js:69: strict mode: TypeError: $DONE() not called 5 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js:59: TypeError: $DONE() not called 6 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-iterator-next-rejected-promise-close.js:59: strict mode: TypeError: $DONE() not called 7 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js:64: TypeError: $DONE() not called 8 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/next/yield-next-rejected-promise-close.js:64: strict mode: TypeError: $DONE() not called 9 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js:74: TypeError: $DONE() not called 10 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/iterator-result-rejected-promise-close.js:74: strict mode: TypeError: $DONE() not called 11 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js:81: TypeError: $DONE() not called 12 | test262/test/built-ins/AsyncFromSyncIteratorPrototype/throw/throw-result-poisoned-wrapper.js:81: strict mode: TypeError: $DONE() not called 13 | test262/test/built-ins/RegExp/prototype/exec/regexp-builtin-exec-v-u-flag.js:45: Test262Error: Actual argument shouldn't be nullish. Unicode property escapes with v flag 14 | test262/test/built-ins/RegExp/prototype/exec/regexp-builtin-exec-v-u-flag.js:45: strict mode: Test262Error: Actual argument shouldn't be nullish. Unicode property escapes with v flag 15 | test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-16.0.js:16: Test262Error: `\p{RGI_Emoji}` should match 🇨🇶 (U+01F1E8 U+01F1F6) 16 | 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) 17 | test262/test/built-ins/String/prototype/match/regexp-prototype-match-v-u-flag.js:10: Test262Error: Actual argument shouldn't be nullish. Unicode property escapes with v flag 18 | test262/test/built-ins/String/prototype/match/regexp-prototype-match-v-u-flag.js:10: strict mode: Test262Error: Actual argument shouldn't be nullish. Unicode property escapes with v flag 19 | 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. 20 | 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. 21 | 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 22 | 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 23 | 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 24 | 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 25 | 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 26 | 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 27 | 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 28 | 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 29 | 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 30 | 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 31 | 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 32 | 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 33 | 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 34 | 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 35 | 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 36 | 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 37 | 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 38 | 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 39 | 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. 40 | 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. 41 | 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. 42 | 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. 43 | 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. 44 | 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. 45 | test262/test/language/expressions/assignment/target-member-computed-reference.js:22: Test262Error: Expected a DummyError but got a Test262Error 46 | test262/test/language/expressions/assignment/target-member-computed-reference.js:22: strict mode: Test262Error: Expected a DummyError but got a Test262Error 47 | test262/test/language/expressions/assignment/target-super-computed-reference.js:20: Test262Error: Expected a DummyError but got a Test262Error 48 | test262/test/language/expressions/assignment/target-super-computed-reference.js:20: strict mode: Test262Error: Expected a DummyError but got a Test262Error 49 | test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: unexpected error type: Test262: This statement should not be evaluated. 50 | test262/test/language/expressions/in/private-field-invalid-assignment-target.js:23: strict mode: unexpected error type: Test262: This statement should not be evaluated. 51 | test262/test/language/expressions/object/computed-property-name-topropertykey-before-value-evaluation.js:31: Test262Error: Expected SameValue(«"bad"», «"ok"») to be true 52 | test262/test/language/expressions/object/computed-property-name-topropertykey-before-value-evaluation.js:31: strict mode: Test262Error: Expected SameValue(«"bad"», «"ok"») to be true 53 | test262/test/language/module-code/top-level-await/module-graphs-does-not-hang.js:10: TypeError: $DONE() not called 54 | test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js:40: SyntaxError: invalid property name 55 | test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-get-followed-by-generator-asi.js:40: strict mode: SyntaxError: invalid property name 56 | test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js:40: SyntaxError: invalid property name 57 | test262/test/language/statements/class/elements/syntax/valid/grammar-field-named-set-followed-by-generator-asi.js:40: strict mode: SyntaxError: invalid property name 58 | 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. 59 | 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. 60 | 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 61 | 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 62 | 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. 63 | 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. 64 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'quickjs-ng', 3 | 'c', 4 | version: '0.8.0', 5 | default_options: [ 6 | 'c_std=gnu11,c11', 7 | 'warning_level=3', 8 | 'default_library=static', 9 | ], 10 | license: 'MIT', 11 | license_files: 'LICENSE', 12 | meson_version: '>=1.3.0', 13 | ) 14 | 15 | host_system = host_machine.system() 16 | cc = meson.get_compiler('c') 17 | 18 | qjs_gcc_warning_args = [ 19 | '-Wno-unsafe-buffer-usage', 20 | '-Wno-sign-conversion', 21 | '-Wno-nonportable-system-include-path', 22 | '-Wno-implicit-int-conversion', 23 | '-Wno-shorten-64-to-32', 24 | '-Wno-reserved-macro-identifier', 25 | '-Wno-reserved-identifier', 26 | '-Wdeprecated-declarations', 27 | 28 | '-Wno-implicit-fallthrough', 29 | '-Wno-sign-compare', 30 | '-Wno-missing-field-initializers', 31 | '-Wno-unused-parameter', 32 | '-Wno-unused-but-set-variable', 33 | '-Wno-array-bounds', 34 | '-Wno-format-truncation', 35 | ] 36 | qjs_gcc_args = [ 37 | '-funsigned-char', 38 | ] 39 | 40 | if host_system == 'darwin' 41 | # https://github.com/quickjs-ng/quickjs/issues/453 42 | qjs_gcc_warning_args += '-Wno-maybe-uninitialized' 43 | endif 44 | 45 | # https://github.com/microsoft/cpp-docs/tree/main/docs/error-messages/compiler-warnings 46 | qjs_msvc_warning_args = [ 47 | '/wd4018', # -Wno-sign-conversion 48 | '/wd4061', # -Wno-implicit-fallthrough 49 | '/wd4100', # -Wno-unused-parameter 50 | '/wd4200', # -Wno-zero-length-array 51 | '/wd4242', # -Wno-shorten-64-to-32 52 | '/wd4244', # -Wno-shorten-64-to-32 53 | '/wd4245', # -Wno-sign-compare 54 | '/wd4267', # -Wno-shorten-64-to-32 55 | '/wd4388', # -Wno-sign-compare 56 | '/wd4389', # -Wno-sign-compare 57 | '/wd4710', # Function not inlined 58 | '/wd4711', # Function was inlined 59 | '/wd4820', # Padding added after construct 60 | '/wd4996', # -Wdeprecated-declarations 61 | '/wd5045', # Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified 62 | ] 63 | qjs_msvc_args = [ 64 | '/experimental:c11atomics', 65 | '/J', # -funsigned-char 66 | ] 67 | 68 | if cc.get_argument_syntax() == 'msvc' 69 | add_project_arguments( 70 | cc.get_supported_arguments(qjs_msvc_warning_args), 71 | cc.get_id().contains('clang') ? cc.get_supported_arguments(qjs_gcc_warning_args) : [], 72 | qjs_msvc_args, 73 | language: 'c', 74 | ) 75 | else 76 | add_project_arguments( 77 | cc.get_supported_arguments(qjs_gcc_warning_args), 78 | qjs_gcc_args, 79 | language: 'c', 80 | ) 81 | endif 82 | 83 | if host_system == 'windows' 84 | # Set a 8MB default stack size on Windows. 85 | # It defaults to 1MB on MSVC, which is the same as our current JS stack size, 86 | # so it will overflow and crash otherwise. 87 | # On MinGW it defaults to 2MB. 88 | stack_size = 8 * 1024 * 1024 89 | if cc.get_argument_syntax() == 'msvc' 90 | add_project_link_arguments(f'/STACK:@stack_size@', language: 'c') 91 | else 92 | add_project_link_arguments(f'-Wl,--stack,@stack_size@', language: 'c') 93 | endif 94 | endif 95 | 96 | if meson.is_cross_build() 97 | native_cc = meson.get_compiler('c', native: true) 98 | 99 | if native_cc.get_argument_syntax() == 'msvc' 100 | # https://github.com/microsoft/cpp-docs/tree/main/docs/error-messages/compiler-warnings 101 | add_project_arguments( 102 | native_cc.get_supported_arguments(qjs_msvc_warning_args), 103 | native_cc.get_id().contains('clang') ? native_cc.get_supported_arguments(qjs_gcc_warning_args) : [], 104 | qjs_msvc_args, 105 | 106 | language: 'c', 107 | native: true, 108 | ) 109 | else 110 | add_project_arguments( 111 | native_cc.get_supported_arguments(qjs_gcc_warning_args), 112 | qjs_gcc_args, 113 | 114 | language: 'c', 115 | native: true, 116 | ) 117 | endif 118 | endif 119 | if get_option('debug') 120 | add_project_arguments( 121 | cc.get_supported_arguments('-fno-omit-frame-pointer'), 122 | language: 'c', 123 | ) 124 | endif 125 | if get_option('disable_parser') 126 | add_project_arguments( 127 | ['-DQJS_DISABLE_PARSER'], 128 | language: 'c', 129 | ) 130 | endif 131 | 132 | qjs_sys_deps = [] 133 | 134 | m_dep = cc.find_library('m', required: false) 135 | qjs_sys_deps += m_dep 136 | qjs_sys_deps += dependency('threads', required: false) 137 | qjs_sys_deps += dependency('dl', required: false) 138 | 139 | qjs_srcs = files( 140 | 'cutils.c', 141 | 'libregexp.c', 142 | 'libunicode.c', 143 | 'quickjs.c', 144 | 'xsum.c' 145 | ) 146 | qjs_hdrs = files( 147 | 'quickjs.h', 148 | ) 149 | 150 | qjs_libc = get_option('libc') 151 | qjs_libc_srcs = files('quickjs-libc.c') 152 | qjs_libc_hdrs = files('quickjs-libc.h') 153 | 154 | if qjs_libc 155 | qjs_hdrs += qjs_libc_hdrs 156 | endif 157 | 158 | qjs_c_args = ['-D_GNU_SOURCE'] 159 | 160 | if host_system == 'windows' 161 | qjs_c_args += ['-DWIN32_LEAN_AND_MEAN', '-D_WIN32_WINNT=0x0602'] 162 | endif 163 | 164 | qjs_libc_lib = static_library( 165 | 'quickjs-libc', 166 | qjs_libc_srcs, 167 | 168 | dependencies: qjs_sys_deps, 169 | c_args: qjs_c_args, 170 | gnu_symbol_visibility: 'hidden', 171 | ) 172 | 173 | qjs_lib = library( 174 | 'qjs', 175 | qjs_srcs, 176 | 177 | # export public headers 178 | generator( 179 | find_program('cp', 'xcopy'), 180 | output: ['@PLAINNAME@'], 181 | arguments: ['@INPUT@', '@OUTPUT@'], 182 | ).process(qjs_hdrs), 183 | 184 | dependencies: qjs_sys_deps, 185 | link_whole: qjs_libc ? qjs_libc_lib : [], 186 | c_args: qjs_c_args, 187 | gnu_symbol_visibility: 'hidden', 188 | 189 | install: true, 190 | version: meson.project_version(), 191 | ) 192 | 193 | qjs_dep = declare_dependency( 194 | link_with: qjs_lib, 195 | dependencies: qjs_sys_deps, 196 | include_directories: qjs_lib.private_dir_include(), 197 | ) 198 | 199 | if host_system == 'emscripten' 200 | qjs_wasm_export_name = 'getQuickJs' 201 | executable( 202 | 'qjs_wasm', 203 | qjs_srcs, 204 | link_args: cc.get_supported_link_arguments( 205 | # in emscripten 3.x, this will be set to 16k which is too small for quickjs. 206 | '-sSTACK_SIZE=@0@'.format(2 * 1024 * 1024), # let it be 2m = 2 * 1024 * 1024, otherwise, stack overflow may be occured at bootstrap 207 | '-sNO_INVOKE_RUN', 208 | '-sNO_EXIT_RUNTIME', 209 | '-sMODULARIZE', # do not mess the global 210 | '-sEXPORT_ES6', # export js file to morden es module 211 | '-sEXPORT_NAME=@0@'.format(qjs_wasm_export_name), # give a name 212 | '-sTEXTDECODER=1', # it will be 2 if we use -Oz, and that will cause js -> c string convertion fail 213 | '-sNO_DEFAULT_TO_CXX', # this project is pure c project, no need for c plus plus handle 214 | '-sEXPORTED_RUNTIME_METHODS=ccall,cwrap', 215 | ), 216 | dependencies: m_dep, 217 | c_args: qjs_c_args, 218 | ) 219 | endif 220 | 221 | install_headers(qjs_hdrs, subdir: 'quickjs-ng') 222 | 223 | if not meson.is_subproject() 224 | docdir = get_option('docdir') 225 | datadir = get_option('datadir') 226 | 227 | if docdir == '' 228 | docdir = datadir / 'doc' / meson.project_name() 229 | endif 230 | install_data( 231 | 'LICENSE', 232 | install_dir: docdir, 233 | 234 | install_tag: 'doc', 235 | ) 236 | install_subdir( 237 | 'examples', 238 | install_dir: docdir, 239 | 240 | strip_directory: false, 241 | install_tag: 'doc', 242 | ) 243 | endif 244 | 245 | meson.override_dependency('quickjs-ng', qjs_dep) 246 | 247 | import('pkgconfig').generate( 248 | qjs_lib, 249 | subdirs: 'quickjs-ng', 250 | name: 'quickjs-ng', 251 | description: 'QuickJS, the Next Generation: a mighty JavaScript engine', 252 | url: 'https://github.com/quickjs-ng/quickjs', 253 | version: meson.project_version(), 254 | ) 255 | 256 | # QuickJS bytecode compiler 257 | qjsc_srcs = files( 258 | 'qjsc.c', 259 | ) 260 | qjsc_exe = executable( 261 | 'qjsc', 262 | qjsc_srcs, 263 | 264 | c_args: qjs_c_args, 265 | link_with: qjs_libc ? [] : qjs_libc_lib, 266 | dependencies: qjs_dep, 267 | 268 | install: true, 269 | ) 270 | 271 | mimalloc_dep = [] 272 | mimalloc_sys_dep = dependency('mimalloc', required: get_option('cli_mimalloc')) 273 | if mimalloc_sys_dep.found() 274 | mimalloc_dep = declare_dependency( 275 | dependencies: mimalloc_sys_dep, 276 | compile_args: '-DQJS_USE_MIMALLOC', 277 | ) 278 | endif 279 | 280 | # QuickJS CLI 281 | qjs_exe_srcs = files( 282 | 'gen/repl.c', 283 | 'gen/standalone.c', 284 | 'qjs.c', 285 | ) 286 | qjs_exe = executable( 287 | 'qjs', 288 | qjs_exe_srcs, 289 | 290 | c_args: qjs_c_args, 291 | link_with: qjs_libc ? [] : qjs_libc_lib, 292 | dependencies: [qjs_dep, mimalloc_dep], 293 | 294 | install: true, 295 | ) 296 | 297 | if meson.is_cross_build() 298 | mimalloc_native_dep = [] 299 | mimalloc_sys_native_dep = dependency('mimalloc', required: get_option('cli_mimalloc'), native: true) 300 | if mimalloc_sys_dep.found() 301 | mimalloc_native_dep = declare_dependency( 302 | dependencies: mimalloc_sys_native_dep, 303 | compile_args: '-DQJS_USE_MIMALLOC', 304 | ) 305 | endif 306 | 307 | qjs_sys_native_deps = [ 308 | native_cc.find_library('m', required: false), 309 | dependency('threads', required: false, native: true), 310 | dependency('dl', required: false, native: true), 311 | ] 312 | qjs_native_lib = static_library( 313 | 'qjs_native', 314 | qjs_srcs, 315 | qjs_libc_srcs, 316 | 317 | dependencies: qjs_sys_native_deps, 318 | c_args: qjs_c_args, 319 | gnu_symbol_visibility: 'hidden', 320 | 321 | build_by_default: false, 322 | native: true, 323 | install: false, 324 | ) 325 | 326 | meson.override_find_program( 327 | 'qjsc', 328 | executable( 329 | 'qjsc_native', 330 | qjsc_srcs, 331 | 332 | c_args: qjs_c_args, 333 | link_with: qjs_native_lib, 334 | dependencies: qjs_sys_native_deps, 335 | 336 | build_by_default: false, 337 | native: true, 338 | install: false, 339 | ), 340 | ) 341 | meson.override_find_program( 342 | 'qjs', 343 | executable( 344 | 'qjs_native', 345 | qjs_exe_srcs, 346 | 347 | c_args: qjs_c_args, 348 | link_with: qjs_native_lib, 349 | dependencies: [qjs_sys_native_deps, mimalloc_native_dep], 350 | 351 | build_by_default: false, 352 | native: true, 353 | install: false, 354 | ), 355 | ) 356 | else 357 | meson.override_find_program('qjsc', qjsc_exe) 358 | meson.override_find_program('qjs', qjs_exe) 359 | endif 360 | 361 | tests = get_option('tests').disable_auto_if(meson.is_subproject()) 362 | examples = get_option('examples').disable_auto_if(meson.is_subproject()) 363 | 364 | if tests.allowed() 365 | if host_system != 'emscripten' 366 | # Test262 runner 367 | run262_exe = executable( 368 | 'run-test262', 369 | 'run-test262.c', 370 | qjs_libc_srcs, 371 | 372 | c_args: qjs_c_args, 373 | dependencies: qjs_dep, 374 | ) 375 | 376 | test( 377 | 'test', 378 | run262_exe, 379 | args: ['-c', files('tests.conf')], 380 | workdir: meson.current_source_dir(), 381 | ) 382 | 383 | foreach bench : [ 384 | 'empty_loop', 385 | 386 | 'date_now', 387 | 388 | 'prop_read', 389 | 'prop_write', 390 | 'prop_create', 391 | 'prop_delete', 392 | 393 | 'array_read', 394 | 'array_write', 395 | 'array_prop_create', 396 | 'array_length_decr', 397 | 'array_hole_length_decr', 398 | 'array_push', 399 | 'array_pop', 400 | 401 | 'typed_array_read', 402 | 'typed_array_write', 403 | 404 | 'global_read', 405 | 'global_write', 406 | 'global_write_strict', 407 | 408 | 'local_destruct', 409 | 'global_destruct', 410 | 'global_destruct_strict', 411 | 412 | 'func_call', 413 | 'closure_var', 414 | 415 | 'int_arith', 416 | 'float_arith', 417 | 418 | 'set_collection_add', 419 | 420 | 'array_for', 421 | 'array_for_in', 422 | 'array_for_of', 423 | 424 | 'math_min', 425 | 426 | 'regexp_ascii', 427 | 'regexp_utf16', 428 | 429 | 'string_build1', 430 | 'string_build2', 431 | 432 | 'sort_bench', 433 | 434 | 'int_to_string', 435 | 'int_toString', 436 | 437 | 'float_to_string', 438 | 'float_toString', 439 | 'float_toFixed', 440 | 'float_toPrecision', 441 | 'float_toExponential', 442 | 443 | 'string_to_int', 444 | 'string_to_float', 445 | 446 | 'bigint64_arith', 447 | 'bigint256_arith', 448 | ] 449 | benchmark( 450 | bench, 451 | qjs_exe, 452 | args: [files('tests/microbench.js'), bench], 453 | ) 454 | endforeach 455 | endif 456 | 457 | # API test 458 | test( 459 | 'api', 460 | executable( 461 | 'api-test', 462 | 'api-test.c', 463 | 464 | c_args: qjs_c_args, 465 | dependencies: qjs_dep, 466 | ), 467 | ) 468 | endif 469 | 470 | # Unicode generator 471 | executable( 472 | 'unicode_gen', 473 | 'cutils.c', 474 | 'libunicode.c', 475 | 'unicode_gen.c', 476 | 477 | c_args: qjs_c_args, 478 | build_by_default: false, 479 | ) 480 | 481 | executable( 482 | 'function_source', 483 | 'gen/function_source.c', 484 | qjs_libc_srcs, 485 | 486 | c_args: qjs_c_args, 487 | dependencies: qjs_dep, 488 | ) 489 | 490 | if examples.allowed() 491 | executable( 492 | 'hello', 493 | 'gen/hello.c', 494 | qjs_libc_srcs, 495 | 496 | c_args: qjs_c_args, 497 | dependencies: qjs_dep, 498 | ) 499 | 500 | executable( 501 | 'hello_module', 502 | 'gen/hello_module.c', 503 | qjs_libc_srcs, 504 | 505 | c_args: qjs_c_args, 506 | dependencies: qjs_dep, 507 | ) 508 | 509 | subdir('examples') 510 | 511 | executable( 512 | 'test_fib', 513 | 'examples/fib.c', 514 | 'gen/test_fib.c', 515 | qjs_libc_srcs, 516 | 517 | c_args: qjs_c_args, 518 | dependencies: qjs_dep, 519 | export_dynamic: true, 520 | ) 521 | endif 522 | --------------------------------------------------------------------------------