qjs interpreterqjsc compilerqjscalc applicationstd moduleos moduleqjsc compilerQuickJS is a small and embeddable Javascript engine that supports ES2020 specifications including modules, asynchronous generators, and proxy.
It optionally supports mathematical extensions such as large integers (BigInt), large floating point numbers (BigFloat), and operator overloading.
Official site: https://bellard.org/quickjs/
Chinese site: https://github.com/quickjs-zh/
QuickJS QQ Group 1: 598609506 .
Chinese Wiki: https://github.com/quickjs-zh/QuickJS/wiki
Click to view the specific content of QuickJS benchmark test
Provides Makefiles that can be compiled on Linux or MacOS/X. Preliminary Windows support can be obtained by cross-compiling on Linux hosts using the MinGW tool.
If you want to select a specific option, edit the top of Makefile and run make .
Execute make install using root to install compiled binary and support files to /usr/local (this is not required to use QuickJS).
Note : You can refer to QuickJS Chinese documentation on compilation and installation under Windows and compilation and installation under Linux.
qjs is a command line parser (Read-Eval-Print Loop). You can pass Javascript files and/or expressions as parameters to execute them:
./qjs examples/hello.js
qjsc is a command line compiler:
./qjsc -o hello examples/hello.js
./hello
Generate a hello executable file without external dependencies.
qjsbn and qjscbn are the corresponding interpreters and compilers with mathematical extensions:
./qjsbn examples/pi.js 1000
Display 1000 digits of PI
./qjsbnc -o pi examples/pi.js
./pi 1000
Compile and execute PI program.
qjs interpreterUsage: qjs [options] [files]
Options:
-h
--help
List of options.
-e `EXPR`
--eval `EXPR`
Perform EXPR.
-i
--interactive
Go to interactive mode (it is not the default mode when the file is served on the command line).
-m
--module
Load as ES6 module (default is .mjs file extension).
Advanced options include:
-d
--dump
Transfer memory usage statistics.
-q
--quit
Just instantiate the interpreter and exit.
qjsc compilerUsage: qjsc [options] [files]
Options:
-c
Only the bytecode in the C file is output, and the default is to output the executable file.
-e
main() The output and bytecode in the C file, the default is the output executable file.
-o output
Set the output file name (default = out.c or a.out).
-N cname
Sets the C name of the generated data.
-m
Compile as a Javascript module (default is the .mjs extension).
-M module_name[,cname]
Add the initialization code for external C modules. Check out c_module example.
-x
Byte swap output (for cross-compilation only).
-flto
Use link time optimization. Compilation is slower, but executables are smaller and faster. This option is automatically set when using the option -fno-x .
-fno-[eval|string-normalize|regexp|json|proxy|map|typedarray|promise]
Disable the selected language feature to generate smaller executable files.
qjscalc application The qjscalc application is a superset of the qjsbn command line interpreter that implements a Javascript calculator with arbitrary large integers and floating point numbers, fractions, complex numbers, polynomials, and matrices. The source code is in qjscalc.js. More documentation and web versions are available on http://numcalc.com.
Run make test to run some built-in tests included in the QuickJS archive.
The QuickJS archive contains the test262 runner program.
For reference, the complete test262 test is provided in the archive qjs-tests-yyyy-mm-dd.tar.xz. You just need to unzip it into the QuickJS source directory.
Alternatively, test262 test can be installed:
git clone https://github.com/tc39/test262.git test262
cd test262
git checkout 94b1e80ab3440413df916cd56d29c5a2fa2ac451
patch -p1 < ../tests/test262.patch
cd ..
The patch adds implementation-specific harness functions and optimizes inefficient RegExp character classes and Unicode attribute escape tests (the test itself will not be modified, only the slow string initialization function is optimized).
The test can run
make test2
For more information, run ./run-test262 to see the options for test262 runner. The configuration file test262.conf and test262bn.conf contain options to run various tests.
ES2019 specification 2, which includes Annex B (legacy Web compatibility) and Unicode-related features, is already basically supported. The following features are not supported yet:
JSON parsers are currently supported by a wider range than the specification.
ECMA402 (International API) is not supported yet.
"use strip" does not retain debug information (including function source code) to save memory. The "use strict" directive can apply global scripts, or specific functions.#! at the beginning of the script will be ignored. Mathematics extensions are available in the qjsbn version and are fully backward compatible with standard Javascript. Check out jsbignum.pdf for more information.
BigInt (large integer) TC39 is already supported.BigFloat supports: any large floating point number in cardinality 2."use bigint" enables bigint mode, and BigInt is an integer by default."use math" enables mathematical mode where division and power operators on integers produce fractions. By default, floating point literals are the default value and integers are the default value of BigInt.ES6 module fully supports. The default name resolution rules are as follows:
. or .. is the path relative to the current module.. or .. is a system module such as std or os ..so and is a native module using the QuickJS C API. By default, the standard library is included in the command line interpreter. It contains two modules std and os and some global objects.
scriptArgs
Provide command line parameters. The first parameter is the script name.
print(...args)
Prints parameters separated by spaces and trailing newlines.
console.log(...args)
Same as print().
std module The std module provides wrappers for libc stdlib.h and stdio.h and some other utilities.
Export available:
exit(n)
Exit the process.
evalScript(str)
Run the string str scripted (global eval).
loadScript(filename)
Run the filename script (global eval).
Error(errno)
std.Error constructor. The error instance contains the fields errno (Error code) and message (result of std.Error.strerror(errno) ).
The constructor contains the following fields:
EINVAL
EIO
EACCES
EEXIST
ENOSPC
ENOSYS
EBUSY
ENOENT
EPERM
EPIPE
Commonly wrong integer values (additional error codes can be defined).
strerror(errno)
Returns the string errno that describes the error.
open(filename, flags)
Open a file (libc's wrapper fopen() ). Throw std.Error in I/O error
tmpfile()
Open a temporary file. Throw std.Error in I/O error.
puts(str)
It is equivalent to std.out.puts(str) .
printf(fmt, ...args)
Equivalent to std.out.printf(fmt, ...args)
sprintf(fmt, ...args)
Equivalent to libc's sprintf().
in
out
err
Wrap stdin , stdout , stderr of libc file.
SEEK_SET
SEEK_CUR
SEEK_END
constants of seek()
global
References to global objects.
gc()
Manually call the loop deletion algorithm. The loop removal algorithm automatically starts when needed, so this feature is very useful when specific memory limits or testing.
getenv(name)
Returns the value name of the environment variable, or undefined if undefined.
FILE prototype:
close()
Close the file.
puts(str)
Use UTF-8 encoding to output strings.
printf(fmt, ...args)
Format printf, the same as libc printf format.
flush()
Refresh the buffered file.
seek(offset, whence)
Looking for a specific file location (from where std.SEEK_* ). Throw std.Error in I/O error.
tell()
Return to the current file location.
eof()
Return true if the file ends.
fileno()
Returns the associated OS handle.
read(buffer, position, length)
From the file position in byte position, read the length byte to the ArrayBuffer buffer (libc's wrapper fread ).
write(buffer, position, length)
Write length bytes in the ArrayBuffer buffer starting with position of the byte position to the file (libc's wrapper fread ).
getline()
Returns the next line in the file, assuming it is UTF-8 encoding, excluding trailing newlines.
getByte()
Returns the next byte in the file.
putByte(c)
Write a byte to the file.
os module os module provides operating system specific functions:
If OK, the OS function usually returns 0, or the OS returns a specific error code.
Export functions available:
open(filename, flags, mode = 0o666)
Open a file. If error, return a handle or <0.
O_RDONLY
O_WRONLY
O_RDWR
O_APPEND
O_CREAT
O_EXCL
O_TRUNC
POSIX Open Sign.
O_TEXT
(Windows-specific). Open the file in text mode. Default is binary mode.
close(fd)
Close file handle fd .
seek(fd, offset, whence)
Looking for files. Use std.SEEK_* or whence .
read(fd, buffer, offset, length)
Starting from the file handle fd with the byte position offset , read the length byte to the ArrayBuffer buffer . Returns the number of bytes read, and if an error occurs, it returns a value less than 0.
write(fd, buffer, offset, length)
Write the length byte in the ArrayBuffer buffer starting with the byte position offset the file handle fd . Returns the number of bytes written, and if an error occurs, a value less than 0 is returned.
isatty(fd)
fd is a TTY (terminal) handle that returns true .
ttyGetWinSize(fd)
Returns the TTY size [width, height] or null if unavailable.
ttySetRaw(fd)
Set TTY in original mode.
remove(filename)
Delete the file. Return 0 if normal, return <0 if error
rename(oldname, newname)
Rename the file. Return 0 if normal, return <0 if error
setReadHandler(fd, func)
Add the read handler to the file handle fd . fd calls func every time there is data to be added to process. Supports a single read handler for each file handle. Use func = null to delete the handle.
setWriteHandler(fd, func)
Add the write handler to the file handle fd . fd calls func every time there is data to be written to process. Supports a write handler for each file handle. Use `func = null to delete the handle.
signal(signal, func)
Call func when signal occurs. Only one handler is supported per signal number. Use the default processed or undefined ignore signals set by null .
SIGINT
SIGABRT
SIGFPE
SIGILL
SIGSEGV
SIGTERM
POSIX signal number.
setTimeout(func, delay)
Call the function func after delay milliseconds. Returns the handle to the timer.
clearTimer(handle)
Cancel the timer.
platform
Returns the string representing the platform: "linux" , "darwin" , "win32" or "js" .
The C API is simple and effective. The C API is defined in the quickjs.h header.
JSRuntime represents the JavaScript runtime corresponding to the object heap. Multiple runtimes can exist at the same time, but they cannot swap objects. Within a given runtime, multithreading is not supported.
JSContext represents a JavaScript context (or domain). Each JSContext has its own global and system objects. There can be multiple JSContexts in JSRuntime, and they can share objects, similar to frameworks with the same source sharing JavaScript objects in a web browser.
JSValue represents a JavaScript value, which can be a primitive type or an object. Use reference counts, so it is important to explicitly copy ( JS_DupValue() , increase reference count) or release ( JS_FreeValue() , decrease reference count) JSValues.
Use JS_NewCFunction() to create C functions. JS_SetPropertyFunctionList() is an easy way to easily add function, setter, and getter properties to a given object.
Unlike other embedded JavaScript engines, QuickJS does not have an implicit stack, so the C function passes its parameters as normal C parameters. The general rule is that C functions take JSValue as arguments (so they don't need to be freed) and return a newly allocated (active) JSValue .
Exception: Most C functions can return a Javascript exception. It must be explicitly tested and processed through C code. A specific JSValue , that is, JS_EXCEPTION , indicates that an exception has occurred. The actual exception object is stored in JSContext and can be retrieved using JS_GetException() .
Use JS_Eval() to evaluate script or module source code.
If the script or module has been compiled into bytecode using qjsc , then using JS_EvalBinary() can achieve the same result. The advantage is that it does not require compilation, so it is faster and smaller in size, because if eval is not required, the compiler can be removed from the executable.
Note: The bytecode format is associated with a specific QuickJS version. Additionally, no security checks were performed before execution. Therefore, bytecode should not be loaded from untrusted sources. This is why there is no option in qjsc to output bytecode to binary files.
C's opaque data can be attached to JavaScript objects. The type of C opaque data is determined by the object's class ID ( JSClassID ). Therefore, the first step is to register a new class ID and JS class ( JS_NewClassID() , JS_NewClass() ). You can then create an object of that class using JS_NewObjectClass() and use JS_GetOpaque() / JS_SetOpaque() to get or set an opaque pointer to C.
When defining a new JS class, you can declare a destructor that is called when the object is destroyed. A gc_mark method can be provided so that the loop removal algorithm can find other objects referenced by the object. There are other methods that can be used to define heterogeneous object behavior.
Class ID is allocated globally (i.e. applicable to all runtimes). JSClass is allocated in each JSRuntime . JS_SetClassProto() is used to define prototypes for a given class in a given JSContext . JS_NewObjectClass() sets this prototype in the created object.
Examples are provided in js_libc.c.
Native ES6 modules that support dynamic or static links. Check out the test_bjson and bjson.so examples. The standard library js_libc.c is also a good example of native modules.
Set global memory allocation limits for a given JSRuntime using JS_SetMemoryLimit() .
JS_NewRuntime2() can provide custom memory allocation functions.
JS_SetMaxStackSize() can be set using the maximum system stack size
Use JS_SetInterruptHandler() to set up a callback function that is called regularly when the engine executes the code. This callback function can be used to implement execution timeout.
The command line interpreter uses it to implement the Ctrl-C handler.
The compiler generates bytecode directly, without intermediate representations (such as parse trees), so it is very fast. Several optimization steps are performed on the generated bytecode.
Stack-based bytecode is selected because it is simple and the generated code is compact.
For each function, the maximum stack size is calculated at compile time, so there is no need for runtime stack overflow tests.
A separate compressed row number table is maintained for debugging information.
Access to closure variables is optimized and is almost as fast as local variables.
Direct eval in strict mode is optimized.
qjsc compiler The qjsc compiler generates C source code from Javascript files. By default, C source code is compiled using the system compiler ( gcc or clang ).
The generated C source code contains the bytecode of the compiled function or module. If a complete executable is required, it also contains a main() function that contains the necessary C code to initialize the Javascript engine and load and execute compiled functions and modules.
Javascript code can be mixed with C modules.
To generate smaller executables, specific Javascript features, especially eval or regular expressions, can be disabled. Code removal is linked to the system compiler-dependent link-time optimization.
qjsc works by compiling scripts or modules and then serializing them into binary format. A subset of this format (excluding functions or modules) can be used as binary JSON. Sample test_bjson.js shows how to use it.
Warning: Binary JSON format may change without notice and should not be used to store persistent data. test_bjson.js example is only used to test functions in binary object format.
Strings are stored as 8-bit or 16-bit character arrays. Therefore, random access to characters is always fast.
The C API provides functions to convert Javascript strings into C UTF-8 encoded strings. The most common case is that Javascript strings contain only ASCII strings and do not involve copying.
Object shapes (object prototype, attribute name, and flag) are shared among objects to save memory.
Optimized arrays without holes (except at the end of the array).
TypedArray access is optimized.
The object property name and some strings are stored as atoms (unique strings) to save memory and allow for quick comparisons. Atoms are represented as 32-bit integers. Half of the atomic range is reserved for immediate integer face value from 0 to 2^{31}-1.
Numbers can be represented as 32-bit signed integers or 64-bit IEEE-754 floating point values. Most operations have fast paths for 32-bit integer cases.
Reference count is used to automatically and accurately release objects. When the allocated memory becomes too large, a separate loop removal operation is performed. The loop removal algorithm uses only reference counts and object content, so there is no need to explicitly manipulate the garbage collection root in C code.
JSValue is a Javascript value that can be a primitive type (such as Number, String, etc.) or an object. In the 32-bit version, NaN boxing is used to store 64-bit floating point numbers. The representation is optimized to efficiently test 32-bit integer and reference count values.
In 64-bit code, the size of JSValue is 128 bits and is not boxed using NaN. The reason is that in 64-bit code, memory usage is not that critical.
In both cases (32-bit or 64-bit), JSValue fits exactly two CPU registers, so it can be returned efficiently by C functions.
The engine has been optimized, so the function calls are fast. The system stack contains Javascript parameters and local variables.
A specific regular expression engine was developed. It is small and efficient and supports all ES2019 features, including Unicode properties. As a Javascript compiler, it directly generates bytecode without a parse tree.
Use explicit stack backtracking so that there is no recursion on the system stack. Simple quantizers are specially optimized to avoid recursion.
Infinite recursion from a quantizer with empty terms is avoided.
The weight of the complete regular expression library is approximately 15 KiB (x86 code), excluding the Unicode library.
A specific Unicode library is developed, so it does not depend on external large Unicode libraries such as ICUs. Compress all Unicode tables while maintaining reasonable access speeds.
The library supports case conversion, Unicode normalization, Unicode script queries, Unicode general category queries, and all Unicode binary properties.
The complete Unicode library weighs approximately 45 KiB (x86 code).
BigInt and BigFloat are implemented using the libbf library libbf library. It has about 60 KiB (x86 code) and provides IEEE 754 floating point operations with arbitrary precision and transcendent functions with precise rounding.
QuickJS is released under the MIT protocol.
Unless otherwise stated, the copyright of QuickJS source belongs to Fabrice Bellard and Charlie Gordon.
https://github.com/tc39/test262
https://tc39.github.io/ecma262/
We believe that the current tail call specification is too complex and has limited actual benefits.
https://bellard.org/libbf
QuickJS-QuickJS library under iOS
QuickJS - Android QuickJS library under Android
quickjs-rs Rust's QuickJS library
Quickjspp C++ QuickJS library
go-quickjs Go's QuickJS library
txiki.js The tiny JavaScript runtime built with QuickJS, libuv and ❤️
QuickJS-Pascal Quickjs FreePascal / Delphi Bindings