Compare commits

..

211 commits

Author SHA1 Message Date
Andrew Johnson
136f5a2c66 Cleanup unused-variable warnings 2024-06-24 17:35:01 +02:00
Saúl Ibarra Corretgé
2ea0848616 Add CI for Windows x86 + MSVC 2024-06-17 09:59:46 +02:00
startewho
a008f1c098 Fix the Windows x86 MSVC build
Fixes: https://github.com/quickjs-ng/quickjs/issues/430
2024-06-17 09:59:46 +02:00
Saúl Ibarra Corretgé
c98d445b63 Save cur_pc on delete OP
Fixes: https://github.com/quickjs-ng/quickjs/issues/431
2024-06-13 12:23:12 +02:00
Saúl Ibarra Corretgé
b09ad82622 Now working on 0.6.0 2024-06-07 22:26:48 +02:00
Saúl Ibarra Corretgé
e1e8112f98 Fix uploading all built artifacts to a release 2024-06-07 22:25:01 +02:00
Saúl Ibarra Corretgé
0827b37f8c Set version to 0.5.0 2024-06-07 22:11:28 +02:00
KaruroChori
ed8f73413c Add getter for GC threshold 2024-06-07 22:07:38 +02:00
Tom Lienard
d3da56b630 Sync TLA implementation with upstream
Fixes: https://github.com/quickjs-ng/quickjs/issues/339
2024-06-07 15:46:44 +02:00
Saúl Ibarra Corretgé
a4e48a6a65
Add riscv64 builds to CI 2024-06-07 08:29:50 +02:00
KaruroChori
6efe30b4b4
Improve macro compatibility with C++
Fixes: https://github.com/quickjs-ng/quickjs/issues/425
2024-06-07 08:29:12 +02:00
Charlie Gordon
e36f4bc4b6 add missing include files in headers 2024-06-06 21:09:10 +02:00
nekosu
22c10224ac fix: missing math.h for NAN 2024-06-06 10:26:02 +02:00
nekosu
8ac7c0d51f fix: nested member access 2024-06-05 14:57:09 +02:00
Saúl Ibarra Corretgé
e5673a8e68 Add JS_ToBigUint64
Fixes: https://github.com/quickjs-ng/quickjs/issues/376
2024-06-04 19:03:26 +02:00
Frère Jérôme
c7bd41197a Explicit cast in JS_NewInt64 & JS_NewUint32
This avoids the two GCC -Wconversion warnings in this public header, which is useful when using extensive error reporting from the compiler, and treating warnings as errors.
2024-06-04 00:54:56 +02:00
Saúl Ibarra Corretgé
1746ab8e28 Make Linux aarch64 binaries on release too
Fixes: https://github.com/quickjs-ng/quickjs/discussions/417
2024-05-30 09:01:56 +02:00
Charlie Gordon
3eaea6c4cf Improve number conversions
- pass string length to `js_atof()` instead of end pointer
- get string length from `bf_ftoa()` in `js_bigint_to_string1`
2024-05-27 10:23:21 +02:00
Saúl Ibarra Corretgé
bb4878dd50 Add JS_ThrowPlainError
It's a helper for doing the following steps:

- Building an Error object
- Attaching a formatted message
- Throwing the object

Fixes: https://github.com/quickjs-ng/quickjs/issues/375
2024-05-27 10:11:49 +02:00
Icemic
569f51fba2 Add JS_GetLength 2024-05-27 08:41:40 +02:00
Icemic
9a2a246b51 Add JS_FreePropertyEnum corresponding to JS_GetOwnPropertyNames 2024-05-27 08:41:40 +02:00
Charlie Gordon
921c1eef50
Simpler utf8_decode (#414)
- no longer pass the array length to `utf8_decode`
- add `utf8_decode_len` for border cases
- use switch based dispatch in `utf8_decode_len` to work around a gcc 12.2 optimizer bug
2024-05-27 08:15:52 +02:00
Charlie Gordon
9e67b47c0d
Improve number to string conversions (#400)
integer conversions:
- improve `u32toa_radix` and `u64toa_radix`, add `i32toa_radix`
- use `i32toa_radix` for small ints in `js_number_toString`

floating point conversions (`js_dtoa`):
- complete rewrite with fewer calls to `snprintf`
- remove `JS_DTOA_FORMAT`, define 4 possible modes for `js_dtoa`
- remove the radix argument in `js_dtoa`
- merge `js_dtoa1` into `js_dtoa`
- add `js_dtoa_infinite` for non finite values
- simplify sign handling
- handle locale specific decimal point transparently

helper function `js_fcvt`:
- simplify `js_fcvt`, remove `js_fcvt1`, reduce overhead
- round up manually instead of using `fesetround(FE_UPWARD)`.

helper function `js_ecvt`:
- document `js_ecvt` and `js_ecvt1` behavior
- avoid redundant `js_ecvt1` calls in `js_ecvt`
- fixed buffer contents, no buffer copies
- simplify decimal point handling
- round up manually instead of using `fesetround(FE_UPWARD)`.

miscellaneous:
- remove `CONFIG_PRINTF_RNDN`. This fixes some of the conversion errors
  on Windows. Updated the tests accordingly
- this fixes a v8.sh bug on macOS: `0.5.toFixed(0)` used to produce `0` instead of `1`
- add regression tests, update test_conv unit tests
- add benchmarks for `toFixed`, `toPrecision` and `toExponential` number methods
- benchmarks show all conversions are now 40 to 45% faster (M2)
2024-05-26 08:06:36 +02:00
Charlie Gordon
139b51fe4b
Simplify number parsing (#386)
- use single test in `js_strtod` loop.
- use more explicit `ATOD_xxx` flags
- remove `ATOD_TYPE_MASK`, use `ATOD_WANT_BIG_INT` instead
- remove unused arguments `flags` and `pexponent` in `js_string_to_bigint`
- merge `js_atof` and `js_atof2`, remove `slimb_t *pexponent` argument
- simplify and document `js_atof` parser, remove cumbersome labels,
- simplify `js_parseInt` test for zero radix for `ATOD_ACCEPT_HEX_PREFIX`
- simplify `next_token` number parsing, handle legacy octal in parser only
- simplify `JS_StringToBigInt`, use flags only.
- remove unused `slimb_t exponent` token field
- add number syntax tests
2024-05-26 00:17:04 +02:00
Charlie Gordon
1baa6763f8
Improve UTF-8 decoding and encoding functions (#410)
Ensure proper UTF-8 encoding (1 to 4 bytes).
Handle invalid encodings (return 0xFFFD and consume a single byte)
Individually encoded surrogate code points are accepted.

- add `utf8_scan()` to analyze a byte array for UTF-8 contents
  detects invalid encoding, computes number of codepoints and content kind:
  plain ASCII, 8-bit, 16-bit or larger codepoints.
- add `utf8_encode_len(c)` to compute the number of bytes to encode `c`
- rename `unicode_to_utf8` as `utf8_encode`
- rename `unicode_from_utf8` as `utf8_decode`
- add `utf8_decode_buf8(dest, size, src, len)` to decode a UTF-8 encoded
  byte array known to contain only ASCII and 8-bit codepoints.
- add `utf8_decode_buf16(dest, size, src, len)` to decode a UTF-8 encoded
  byte array into an array of 16-bit codepoints using UTF-16 surrogate pairs
  for non-BMP1 codepoints.
- add `utf8_encode_buf8(dest, size, src, len)` to encode an array of 8-bit
  codepoints as a UTF-8 encoded null terminated string
- add `utf16_encode_buf8(dest, size, src, len)` to decode an array of 16-bit
  codepoints (including surrogate pairs) as a UTF-8 encoded null terminated string
- detect invalid UTF-8 encoding in RegExp parser
- simplify `JS_AtomGetStrRT`, `JS_NewStringLen` using the above functions
- simplify UTF-8 decoding and error testing
2024-05-21 14:08:33 +02:00
KaruroChori
f588210641
Cherrypick https://github.com/bellard/quickjs/pull/289 (#404)
Co-authored-by: karurochari <nope>
2024-05-18 10:15:34 +02:00
Charlie Gordon
5a7e578482
Improve parsing error messages (#405)
- output more informative error messages in `js_parse_expect`.

The previous code was bogus:
```
    return js_parse_error(s, "expecting '%c'", tok);
```
this was causing a bug on `eval("do;")` where `tok` is `TOK_WHILE` (-70, 0xBA)
creating an invalid UTF-8 encoding (lone trailing byte).
This would ultimately have caused a failure in `JS_ThrowError2` if `JS_NewString`
failed when converting the error message to a string if the conversion detected the invalid
UTF-8 encoding and throwed an error (it currently does not, but should).

- test for `JS_NewString` failure in `JS_ThrowError2`
- test for `JS_FreeCString` failure in run-test262.c
- add more test cases
2024-05-14 20:36:10 +02:00
KaruroChori
99c6719b7d
Fix invalid exception for class method with name "get"
Ref: https://github.com/bellard/quickjs/pull/258
2024-05-14 09:16:26 +02:00
Jonathan Barronville
5ca3c509d0
Fixed CMakeLists.txt for Emscripten builds (#403)
Prevent compilation of __run-test262__  for Emscripten (fails due to the `ftw()` usage, but not needed anyway).
2024-05-14 08:44:46 +02:00
Charlie Gordon
b81d4deee4
Improve internal string allocation methods (#398)
String values are allocated as temporary or final results. This commit
attempts to improve the consistency and performance of this step.

- define `JS_NewString` as an inline function to allow simple expansion
  of `strlen()` for string literals
- document string contents constraints regarding UTF-8 encoding.
- rename `js_new_string8` as `js_new_string8_len`. takes `const char *`.
- new inline function `js_new_string8` takes `const char *`, computes
  string length with `strlen` and calls `js_new_string8_len`. No overhead
  for string literals
- rename `js_new_string16` to `js_new_string16_len`
- use internal string allocation functions where appropriate, remove overhead
- allocate extra byte for null terminator in source code string
2024-05-10 12:43:35 +02:00
Charlie Gordon
f9ecc1a598
Fix encoding bug in js_dtoa_radix (#399)
- fix radix conversion rounding code: incrementing the digit
  does not work for '9'.  We can assume ASCII so it works for
  all other digits, especially all letters
- also avoid recomputing the string length
2024-05-07 19:35:34 +02:00
Saúl Ibarra Corretgé
6cb1301305 Accept "kmg" suffixes for memory limits
Switch the default in the CLI to kilobytes too.
2024-05-06 11:22:16 +02:00
Saúl Ibarra Corretgé
e5ae6cf106 Fix handling of memory limit
Default to 0, which is "disabled", just like the stack limit.
2024-05-06 11:22:16 +02:00
Saúl Ibarra Corretgé
2050bc782a Fix CLI memory stats output 2024-05-05 19:12:42 +02:00
Saúl Ibarra Corretgé
840ce4e719 Make sure repos are updated before installing valgrind in CI 2024-04-23 19:54:12 +02:00
Saúl Ibarra Corretgé
38f9e429e4 Update gcc-4.8 CI to Ubuntu 18.04 2024-04-23 18:37:31 +02:00
Saúl Ibarra Corretgé
3241b46220 Remove unused variable 2024-04-22 11:48:04 +02:00
Charlie Gordon
f227746c6e
Add util.inspect emulation in REPL (#387)
- output values with controlable depth and detail
- add `.hidden` and `.depth` directives
- remove `eval_mode`
- add `use_strict` and `.strict` meta command
- add missing closures on global objects
- save and load command history to/from `~/.qjs_history`
- use USEPROFILE variable on Windows in addition to HOME
- use the same style names as util.inspect
2024-04-21 08:46:17 +02:00
Charlie Gordon
a77873d657
Optimize String.fromCharCode and String.fromCodePoint (#391)
- test for common case: single integer argument and create string directly
2024-04-21 08:28:02 +02:00
Charlie Gordon
83726bb00c
Add utility functions for string to integer conversions (#366)
* Add utility functions, improve integer conversion functions

- move `is_be()` to cutils.h
- add `is_upper_ascii()` and `to_upper_ascii()`
- add extensive benchmark for integer conversion variants in **tests/test_conv.c**
- add `u32toa()`, `i32toa()`, `u64toa()`, `i64toa()` based on register shift variant
- add  `u32toa_radix()`, `u64toa_radix()`, `i64toa_radix()` based on length_loop variant
- use direct converters instead of `snprintf()`
- copy NaN and Infinity directly in `js_dtoa1()`
- optimize `js_number_toString()` for small integers
- use `JS_NewStringLen()` instead of `JS_NewString()` when possible
- add more precise conversion tests in microbench.js
- disable some benchmark tests for gcc (they cause ASAN failures)
2024-04-19 11:35:44 +02:00
Charlie Gordon
f326a7a195
Add strip option in qjsc to reduce object size (#388)
- `-s` strips the source code
- `-ss` strips source and line/column numbers information
- `qjsc repl.js` generates an object size of **105726** bytes
- `qjsc -s repl.js` generates an object size of **20853** bytes
- `qjsc -ss repl.js` generates an object size of only **16147** bytes
- compile repl.js with `-ss`
- bump byte code version to 12
2024-04-19 08:41:12 +02:00
Charlie Gordon
43dc65d605
Fix potential conversion errors (#384)
- fix undefined behavior in double to int conversions
- do not pass an `int64_t` to `js_bool()`
2024-04-16 23:18:02 +02:00
Charlie Gordon
70a60f0aa1
Add REPL dark and light color themes (#383)
- detect terminal background from COLORFGBG environment variable
- add `.dark` and `.light` meta commands
- catch `loadScript` exceptions
2024-04-16 14:18:37 +02:00
bptato
29b45337f0
Fix member accesses for non-decimal numeric literals (#377)
* Fix member accesses for non-decimal numeric literals
    e.g. 0x0.a should return undefined, not SyntaxError.
* Remove ineffective non-decimal float parsing code and redundant checks on `is_float && radix != 10`
    (The code already wasn't doing anything because of the `is_float` check.)
2024-04-16 14:17:50 +02:00
Charlie Gordon
5797f2a716
Improve DUMP_READ_OBJECT (#382)
- improve `JS_DumpString`: use `L` prefix for wide strings
- dump variable kind and flags for locals and closures
- disassemble byte code in DUMP_READ_OBJECT
- pass start_pos to `dump_byte_code` and `dump_single_byte_code`
- write constant pool before function bytecode (bump version to 11)
- update generated code
2024-04-16 09:24:21 +02:00
Cryse Hillmes
2c47b7beb1
Expose public equality comparison and sameness public API. (#373)
* Expose public equality comparison and sameness public API.
- add `JS_IsEqual` (operator `==`), returns an `int`: `-1` if an exception was thrown
- add `JS_IsStrictEqual` (operator `===`) always succeeds, returns a `JS_BOOL`
- add `JS_IsSameValue` always succeeds, returns a `JS_BOOL`
- add `JS_IsSameValueZero` always succeeds, returns a `JS_BOOL`
2024-04-16 08:46:22 +02:00
Saúl Ibarra Corretgé
18c632c754 Fix performance.now() to return a double 2024-04-15 16:16:04 +02:00
Charlie Gordon
7597fc7fb0
Fix potential atom leak in JS_ReadFunctionTag (#380) 2024-04-15 14:03:24 +02:00
Null
8dcdb92047
fix crash in js_typed_array_slice caused by memory overlap (#379)
Use memmove instead of memcpy to prevent UB.
Fixes: https://github.com/quickjs-ng/quickjs/issues/378
Co-authored-by: zhang.yuping <zhangyuping.ypz@bytedance.com>
2024-04-15 06:40:00 +02:00
Charlie Gordon
4fb2e38b8a
Simplify arrow function parsing (#360)
- parse arrow functions only in `js_parse_cond_expr`
- remove `PF_ARROW_FUNC` flag and simplify parsing functions with flags
2024-04-14 02:44:34 +02:00
Charlie Gordon
16e7661fa0
Improve dump option support (#344)
- DUMP_XXX defined as nothing or 0 produces unconditional output
- DUMP_XXX defined as a bitmask produces conditional output based
    on command line option -d<bitmask>
- add `JS_SetDumpFlags()` to select active dump options
- accept -d[<hex mask>] and --dump[=<hex mask>] to specify active
    dump options, generalize command line option handling
- improve DUMP_READ_OBJECT output, fix indentation issue
2024-04-14 02:00:19 +02:00
Saúl Ibarra Corretgé
bb674c0c3b
Add iOS build to CI 2024-04-12 12:24:18 +02:00
Saúl Ibarra Corretgé
38fa7d7cf6 Fix crash in FinalizationRegistry when the observed object is GC'd
In the pathological case shown in
https://github.com/quickjs-ng/quickjs/issues/367 both the object and the
registry will be destroyed as part of the GC phase of JS_FreeRuntime.
When the GC sweep happens it's possible we are holding on to a corpse so
avoid calling the registry callback in that case.

This is similar to how Weak{Map,Set} deal with iterators being freed as
part of a cycle.

Fixes: https://github.com/quickjs-ng/quickjs/issues/367
2024-04-12 12:23:58 +02:00
Ben Noordhuis
325ce95c5e
Remove js_unlikely macro (#370)
It was a wrapper around gcc's __builtin_expect macro but it was only
used in three places and not in a way that suggests it really helps
branch prediction on modern (or even not so modern) CPUs.

Refs: https://github.com/quickjs-ng/quickjs/issues/369
2024-04-12 12:21:20 +02:00
Charlie Gordon
b20aad8d1a
Add faster test262 test target (#362)
* Add faster test262 test target
- add test262-fast.conf with lengthy tests disabled
- add test262-fast corresponding target
- make valgrind use test262-fast
2024-04-09 10:36:49 +02:00
Charlie Gordon
6d801de3e5
Improve js_array_lastIndexOf and friends (#359)
- special case fast arrays in `js_array_lastIndexOf`
- simplify `js_array_indexOf` and `js_array_includes` for consistency.
2024-04-08 23:08:49 +02:00
Charlie Gordon
0658d9c3e9
Fix js_math_imul (#356)
- follow ECMA specification
- remove implementation defined signed conversion
2024-04-08 22:50:39 +02:00
Charlie Gordon
97c918662b
Fix crashes in DUMP output (#350)
- avoid crashing on invalid atoms in `JS_AtomGetStrRT`
- do not dump objects and function_bytecode during
  `JS_GC_PHASE_REMOVE_CYCLES` phase
- fix crash in `print_lines` on null source
2024-04-08 21:25:01 +02:00
Charlie Gordon
56593f419b
Fix JS_ReadString for wide strings on big endian targets (#354)
swap words of wide character strings upon loading on a big endian target.
2024-04-08 17:02:20 +02:00
Charlie Gordon
f62b90daa2
Improve REPL directive support (#348)
* Improve REPL directive support

- use . on column 0 as directive prefix
- use `directives` object properties for genericity
- accept non ambiguous directive abbreviations
- reject invalid directive with extra characters
- simplify `handle_directive` and `handle_cmd`
- document ".help" instead of "\h"
- document ".load"
2024-04-08 15:34:30 +02:00
Charlie Gordon
d308a13579
Use string_get for clarity (#352) 2024-04-07 19:35:32 +02:00
Charlie Gordon
3f06c95558
Use more functions for explicit surrogate handling (#353)
- add `is_surrogate`, `get_hi_surrogate` and `get_lo_surrogate`
- use surrogate functions instead of hard coded computations
2024-04-07 18:19:55 +02:00
Charlie Gordon
1db884b140
Unify JS_DumpValue functions (#349)
- merge `JS_DumpValue(ctx, val)` and `JS_DumpValueShort(rt, val)` as `JS_DumpValue(rt, val)`
- remove unused `JS_PrintValue(ctx, val)`
2024-04-07 16:25:55 +02:00
Charlie Gordon
b8a2cf40d8
Fix fix-js-get-string AM/PM computation for Date.prototype.toLocaleString (#355)
- Fix AM/PM computation for Date.prototype.toLocalString: 11:00 and 23:00 used to convert to -1:00
2024-04-07 16:25:03 +02:00
Charlie Gordon
d61988211c
Accept shell scripts in JS_DetectModule (#358)
- use `skip_shebang` in `JS_DetectModule` before scanning for
  `import` statements
2024-04-07 16:23:50 +02:00
Charlie Gordon
15c6a773b6
remove v8 output files in make clean (#357) 2024-04-07 16:22:54 +02:00
Saúl Ibarra Corretgé
c33b8c9b13 Add Windows + Ninja to CI 2024-04-07 00:08:19 +02:00
Saúl Ibarra Corretgé
7fe17cc2d3 Remove unnecessary shell change in CI 2024-04-07 00:08:19 +02:00
Saúl Ibarra Corretgé
573a60bfc7 Fix compilation on MSVC 2022 in release mode
Fixes: https://github.com/quickjs-ng/quickjs/issues/309
2024-04-07 00:08:19 +02:00
Saúl Ibarra Corretgé
51608ce6d2 Fix CI to make actual release builds on Windows
CMAKE_BUILD_TYPE only applies on single-configuration generators: https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html

For multi-configuration generators like Visual Studio (or Xcode) --config needs to be used in order to build that specific configuration.
2024-04-07 00:08:19 +02:00
Charlie Gordon
fd99929f5d
Improve completion in REPL (#343)
* Improve completion in REPL

- refine `get_context_object` to avoid throwing errors (eg: q.<TAB>)
- do not call `eval` in `get_context_object` to avoid throwing errors
  and reduce bloat caused by variable closures.
- support completion of directives
2024-04-06 21:37:19 +02:00
Charlie Gordon
02c06d0036
fix memory leaks in run-test262 (#345) 2024-04-05 12:06:40 +02:00
Saúl Ibarra Corretgé
8c861c130e Update ci.yml 2024-04-04 16:58:36 +02:00
Saúl Ibarra Corretgé
8a03548736 Run macOS CI on both amd64 and aarch64 2024-04-04 16:58:36 +02:00
Charlie Gordon
c15ef1f8dc
Add JS_TryGetProperty (#337)
* Optimize `JS_GetPropertyInt64` and `JS_TryGetPropertyInt64`

- add `js_get_fast_array_element()` to special case arrays and typed arrays
- use `js_get_fast_array_element()` in `JS_GetPropertyValue()`,
  `JS_TryGetPropertyInt64()` and `JS_GetPropertyInt64()`.
- simplify `js_array_at()`
2024-04-03 05:10:08 +02:00
Saúl Ibarra Corretgé
569b238ec4
Add cross-platform Atomics support
Fixes: https://github.com/quickjs-ng/quickjs/issues/1
2024-04-02 21:50:42 +02:00
Charlie Gordon
0de570988a
Fix strict name conformity cases (#335)
- reject *future strict reserved words* in `js_parse_function_check_names()`.
- add tests for reserved names in tests/test_language.js
- allow running tests/test_language.js with v8
- update v8.txt
2024-03-30 17:15:25 +01:00
Charlie Gordon
8b56215cc2
Fix more v8 errors (#336)
- change error message for `Object.create` invalid property descriptor
- disable v8 test cases for deprecated legacy RegExp static properties
  and invalid left hand side error type
- update v8.txt
- fix v8.sh behavior for single tests
2024-03-30 13:11:37 +01:00
Ben Noordhuis
f80a5b08cf
Implement setInterval() (#338)
Coincidentally fixes a timer ordering bug for which a regression test
has been added.

Fixes: https://github.com/quickjs-ng/quickjs/issues/279
2024-03-30 09:36:38 +01:00
Charlie Gordon
93d1742fc4
Small fixes in Date.parse (#333)
* Small fixes in Date.parse

- reject AM/PM suffix for hours > 12
- stricter time parser (fixes last v8 test)
- add explanatory comments
2024-03-27 12:48:08 +01:00
Ben Noordhuis
c7ca3febd3
Don't serialize IC opcodes (#334)
Translate IC opcodes to their non-IC variants before writing them out.
Before this commit they were not byte-swapped properly, breaking the
ability to load serialized bytecode containing ICs on systems with
different endianness. Inline caches are recomputed as needed now.

A pleasing side effect of this change is that serialized bytecode is,
on average, a little smaller because fewer atoms are duplicated now.
2024-03-27 12:07:11 +01:00
Charlie Gordon
f02ed184a2
Fix more error cases (#332)
* Fix more error cases

- fix more cases of missing `sf->cur_pc`.
- use more precise error messages for number conversion methods
- add test cases in test_builtin.js
- updated v8 test results
2024-03-26 13:22:37 +01:00
Saúl Ibarra Corretgé
c076339899 Expose JS_GetPropertyInt64 in the public API 2024-03-26 07:59:00 +01:00
Saúl Ibarra Corretgé
b8341ecafa Don't expose JS_{Get,Set}PropertyInternal in the public API 2024-03-26 07:59:00 +01:00
Charlie Gordon
3b50de4848
Improve consistency of JS_NewFloat64 API (#319)
* Improve consistency of JS_NewFloat64 API

- `JS_NewFloat64()` always creates a `JS_TAG_FLOAT64` value
- internal `js_float64()` always creates a `JS_TAG_FLOAT64` value
- add `js_int64` internal function for consistency
- rename `float_is_int32` as `double_is_int32`
- handle `INT32_MIN` in `double_is_int32`, use (somewhat) faster alternative
- add `js_number(d)` to create a `JS_TAG_FLOAT64` or a `JS_TAG_INT` value
  if possible
- add `JS_NewNumber()` API for the same purpose
- use non testing constructor for infinities in `js_atof2`
- always store internal time value as a float64
- merge `JS_NewBigInt64_1` into `JS_NewBigInt64`
- use comparisons instead of `(int32_t)` casts (implementation defined behavior)
2024-03-25 08:29:04 +01:00
Saúl Ibarra Corretgé
18f2898f52
Fix fully initializing JSStackFrame (#328)
Fixes: https://github.com/quickjs-ng/quickjs/issues/323
2024-03-24 22:06:57 +01:00
Saúl Ibarra Corretgé
1796b36db7 Remove JS_VALUE_GET_STRING from the public API
JSString is not part of the API.
2024-03-24 21:01:15 +01:00
Saúl Ibarra Corretgé
4a66289af4 Add JS_Newsymbol, an API for creating symbols
Example usage:

~~~
JSValue global = JS_GetGlobalObject(ctx);
JSValue sym = JS_NewSymbol(ctx, "my.secret.thing", TRUE);
JSAtom atom = JS_ValueToAtom(ctx, sym);
JS_DefinePropertyValue(ctx, global, atom, JS_NewString(ctx, "qjs!"), JS_PROP_C_W_E);
JS_FreeAtom(ctx, atom);
JS_FreeValue(ctx, sym);
JS_FreeValue(ctx, global);
~~~
2024-03-24 21:00:54 +01:00
Charlie Gordon
5e5b00c48c
Improve string parsing and JSON parsing (#316)
* Improve string parsing and JSON parsing

- fix JSON parsing of non ASCII string contents
- more precise string parsing errors
- more precise JSON parsing errors
- add `JS_ParseState::buf_start` to compute line/column
- fix HTML comment detection at start of source code
- improve v8 Failure messages (pulled and modified `formatFailureText` from **mjsunit.js**) 
- ignore more v8 tests
2024-03-22 11:19:36 +01:00
Saúl Ibarra Corretgé
3781c2a6db Add valgrind to CI
Fixes: https://github.com/quickjs-ng/quickjs/issues/71
2024-03-20 20:03:05 +01:00
Saúl Ibarra Corretgé
72cebeaf2a Remove unused variables in REPL 2024-03-20 11:50:06 +01:00
Saúl Ibarra Corretgé
dd2427785f Check for RegExp objects before going the standard object path in REPL 2024-03-20 11:50:06 +01:00
aabajyan
48cb3ac410 Do not link to pthread when targeting Android
I had issues compiling this for Android, and as it turns out, pthread functionality
is part of Bionic itself and linking is not required.
2024-03-20 07:30:39 +01:00
Enno Boland
8db7d24f98 fix compiler warning: -Wunused-variable 2024-03-18 12:34:45 +01:00
Charlie Gordon
5f8c636cef
Add os.getpid (#320) 2024-03-17 20:01:06 +01:00
Ben Noordhuis
99e4e0d55e
Disable ASLR, upgrade Ubuntu CI images (#321)
After much tinkering with libuv's CI, I finally figured out that ASLR
is the root cause for the ASan and MSan failures. Newer kernels use
bigger PIE slides and the sanitizer runtimes don't know how to handle
those (yet - looks like it's been fixed upstream.)

Refs: https://github.com/quickjs-ng/quickjs/pull/315
Refs: https://github.com/libuv/libuv/pull/4365
2024-03-17 19:59:24 +01:00
Charlie Gordon
3a55b803b0
Make Object.prototype an immutable prototype object (#317)
* make `Object.prototype` an immutable prototype object
* throw an exception on `Object.setPrototypeOf(Object.prototype, xxx)`
* do not throw an exception for `Reflect.setPrototypeOf(Object.prototype, xxx)`
2024-03-16 08:53:29 +01:00
Charlie Gordon
5aef8b67b1
fix potential memory leak (#318)
- fix memory leak in `js_std_file_printf`
- fix `errno` clobber in `js_os_stat`
2024-03-16 08:51:58 +01:00
Ben Noordhuis
5d2202cad0
Pin Ubuntu CI images to 20.04 (#315)
GitHub recently upgraded the ubuntu-latest images and I suspect that is
the cause of the linux-asan and linux-msan failures. Pin to the old LTS
for now.

Fixes: https://github.com/quickjs-ng/quickjs/issues/314
2024-03-15 10:49:33 +01:00
Charlie Gordon
45f8dc247c
Improve JSON parser conformity (#303)
- add JSON specific parsers for strings and numbers
- update JSON parse error messages
- fix `JSON.stringify` handling of boxed objects
- parse Flags in v8 mjsunit test files
- update v8.txt
2024-03-14 08:19:11 +01:00
Ben Noordhuis
761ad7856f
Fix tcc build action (#311)
Clone the full repo, otherwise the known-good commit we want to test
against won't be available.
2024-03-14 00:06:48 +01:00
Saúl Ibarra Corretgé
7c7b72a74e Update README, add fork information 2024-03-12 20:00:41 +01:00
Saúl Ibarra Corretgé
50dcc707e0 Add TCC workflows to CI 2024-03-12 11:01:33 +01:00
Saúl Ibarra Corretgé
473bd1d531 Fix Android build
dlmalloc has been removed and the NDK now exposes a malloc.h header with
malloc_usable_size exposed, so use that.

Also remove the duplication in js__malloc_usable_size.

Fixes: https://github.com/quickjs-ng/quickjs/issues/304
2024-03-12 10:26:10 +01:00
Saúl Ibarra Corretgé
e859eae483 Add Android CI 2024-03-12 10:26:10 +01:00
Saúl Ibarra Corretgé
5b1d9e4194 Now working on 0.5.0 2024-03-11 11:23:43 +01:00
Saúl Ibarra Corretgé
d64967b73f Add wasi release job dependency 2024-03-11 11:23:11 +01:00
Saúl Ibarra Corretgé
99a7fbb276 Set version to 0.4.1 2024-03-11 11:16:31 +01:00
Saúl Ibarra Corretgé
d7a2025238 Fix not building qjsc during release process 2024-03-11 11:15:57 +01:00
Saúl Ibarra Corretgé
125373836d Now working on 0.5.0 2024-03-11 11:01:45 +01:00
Saúl Ibarra Corretgé
434fecda17 Set version to 0.4.0 2024-03-11 11:01:00 +01:00
Charlie Gordon
aaa208ac8f
Improve error handling (#297)
* Improve error handling

- throw RangeError for invalid string length
- throw RangeError for stack overflow with updated message
- fix case for `BigInt` error messages
- refine stack check for `next_token` and `json_next_token`
- throw SyntaxError for too many variables, arguments, parameters...
- v8.js: disable v8 specific tests
- v8.js: disable Realm object tests
- v8.js: disable MODULE tests
- v8.js: disable RegExp static properties tests
- use more precise error messages
- reorder property lookup in `js_obj_to_desc()` according to ECMA
- set global object's [Symbol.toStringTag] to "global"
- fix error message for duplicate parameter name in strict mode
2024-03-10 17:04:06 +01:00
Saúl Ibarra Corretgé
f2a91e86c7 Remove custom __getClass method 2024-03-10 16:55:10 +01:00
Charlie Gordon
8d0d9391f9
Unbreak repl string output (#300)
- fix incorrect argument in s = `JSON.stringify(s);`
- add closures for `RegExp` and `JSON`
2024-03-10 13:32:33 +01:00
Tyler Rockwood
33e38bec00 Enable direct dispatch for WASI
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
2024-03-10 11:06:52 +01:00
Charlie Gordon
648a8f5be1
Improve Date.parse (#289)
* Improve `Date.parse()`

- rewrite `Date.parse()` with separate parsers
- return `NaN` for out of bounds field values as specified
- add `js_tzabbr` and `string_get_tzabbr` to handle timezone abbreviations
- improve `string_get_milliseconds` readability
- accept up to 9 decimals for millisecond fraction but truncate at 3
- accept many more alternative date/time formats
- add test cases in **tests/test_builtin.js**
- produce readable output for `Date` objects in repl 
- use `JSON.stringify` to output `Date` and `string` values in **repl.js**
- remove `String.prototype.__quote`
- add `minimum_length` macro to specify argument array sizes (C99 except MSVC)
- v8.js: parse all environment variables and output them, update **v8.txt**
2024-03-10 10:34:26 +01:00
Saúl Ibarra Corretgé
c61336c4fc Update checkout actions
Fixes: https://github.com/quickjs-ng/quickjs/issues/292
2024-03-07 11:15:15 +01:00
Saúl Ibarra Corretgé
d49a14ba3a Release WASM / WASI build artifacts too 2024-03-07 10:24:10 +01:00
Saúl Ibarra Corretgé
4d052a7e71 Log endianness when dumping memory stats 2024-03-06 11:21:50 +01:00
Saúl Ibarra Corretgé
215f246974 Add Big Endian CI target 2024-03-06 11:21:50 +01:00
henrydf
4d6c98115b
Fix Emscripten build
Co-authored-by: Henry <henrydf2018@gmail.com>
2024-03-06 08:56:45 +01:00
Charlie Gordon
5abbeacc62
Fix bug in GET_PREV_CHAR macro (#278)
* Fix bug in `GET_PREV_CHAR` macro

- pass `cbuf_type` variable to `XXX_CHAR` macros in `lre_exec_backtrack()`
- improve readability of these macros
- fix `GET_PREV_CHAR` macro: `cptr` was decremented twice on invalid high surrogate.
- minimize non functional changes
2024-03-03 17:12:52 +01:00
Aful
d11f5f600d
Implement getTimezoneOffset for Win32 (#291)
Retrieves the current time zone settings with GetTimeZoneInformation to calculate time zone offset
2024-03-03 16:23:48 +01:00
Charlie Gordon
708dbcbf5b
Fix big endian serialization (#269)
* Fix big endian serialization

Big endian serialization was broken because:
- it partially relied on `WORDS_ENDIAN` (unconditionally undef'd in cutils.h)
- endianness was not handled at all in the bc reader.
- `bc_tag_str` was missing the `"RegExp"` string
- `lre_byte_swap()` was broken for `REOP_range` and `REOP_range32`

Modifications:
- remove `WORDS_ENDIAN`
- use `bc_put_u32()` / `bc_put_u64()` in `JS_WriteBigInt()`
- use `bc_get_u32()` / `bc_get_u64()` in `JS_ReadBigInt()`
- handle host endianness in `bc_get_u16()`, `bc_get_u32()`, `bc_get_u64()` and
  `JS_ReadFunctionBytecode()`
- handle optional littleEndian argument as specified in
  `js_dataview_getValue()` and `js_dataview_setValue()`
- fix `bc_tag_str` and `lre_byte_swap()`
2024-03-02 18:38:29 +01:00
Ben Noordhuis
f406d6f78c
Accept /[\-]/u as a valid regular expression (#288)
The non-Unicode version of the pattern was already accepted.

test262 tests it in an inverted sense in
test/built-ins/RegExp/unicode_restricted_identity_escape.js but
it appears to be per spec and both V8 and Spidermonkey accept it.

Fixes: https://github.com/quickjs-ng/quickjs/issues/286
2024-03-02 13:29:15 +01:00
Charlie Gordon
7dd2868856
Improve Number.prototype.toString for radix other than 10 (#284)
- fix the conversions for integers and exact fractions
- approximate approach for other cases.
- bypass floating point conversions for JS_TAG_INT values
- avoid divisions for base 10 integer conversions

Fixes: https://github.com/quickjs-ng/quickjs/issues/242
2024-03-01 17:49:46 +01:00
Tyler Rockwood
ec4f957ca1
Add methods to detect arrays (#282)
I have a use case where a user can hand me many different kinds of
types, array buffer, uint8array, or a string, and I need to be able to
distingush between them.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
2024-02-28 12:17:18 +01:00
Tyler Rockwood
377e6a6c06 Fix JS_INVALID_PROMISE_STATE macro 2024-02-26 18:37:30 +01:00
Tyler Rockwood
d168361207 Add documentation for promise APIs
Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
2024-02-23 19:49:52 +01:00
Charlie Gordon
47e07b25aa
Fix Map hash bug (#281)
- `map_hash_key` must generate the same key for JS_INT and JS_FLOAT64
   with the same value
- add test cases in tests/test_builtin.js
2024-02-23 11:57:43 +01:00
Ben Noordhuis
2d1473efbc
Revert "Fix sloppy mode arguments uninitialized value use" (#276)
This reverts commit f8b3a2e93c.

No longer necessary after commit 90d8c6bae0.
2024-02-23 11:55:51 +01:00
Charlie Gordon
79d417a90d Simplify and clarify URL quoting js_std_urlGet 2024-02-23 11:55:29 +01:00
Felix S
ed49e0f39e Fix shell injection bug in std.urlGet
Refs: https://github.com/bellard/quickjs/pull/61
2024-02-23 11:55:29 +01:00
Charlie Gordon
ef4d8ab2ed
Force evaluation order in set_date_fields (#268) 2024-02-22 14:08:29 +01:00
Tyler Rockwood
33f72491a9
Add method to GetClassID (#275)
* Add method to GetClassID

If you want to extend a built-in class you need it's class ID and there
is no robust way to get that without this accessor.

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>

* introduce constant for invalid class ID

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>

---------

Signed-off-by: Tyler Rockwood <rockwood@redpanda.com>
2024-02-20 09:29:08 +01:00
Ben Noordhuis
b257545b6f
Better output from JS_ToCString() on exception (#274)
`ToString(object)` can fail when there is a pending exception. Add a
special case for exception objects to help debugging. Getting an empty
string when the real error was "InternalError: stack overflow" is rage
inducing.

Fixes: https://github.com/quickjs-ng/quickjs/issues/273
2024-02-19 16:31:17 +01:00
Ben Noordhuis
56d60020f4
Fix tcc build, remove PACK macro (#271)
There was no definition of the macro for compilers that were not gcc,
clang or msvc. While it would be easy to add one, a better approach is
to switch to memcpy() and avoid type punning altogether.

Fixes: https://github.com/quickjs-ng/quickjs/issues/270
2024-02-18 13:39:33 +01:00
Cotton Hou
b37627d2c1 CI to silent wget by -nv (--no-verbose) 2024-02-16 08:57:15 +01:00
Ben Noordhuis
a0f507735d
Remove unnecessary ssize_t posix-ism (#265)
ssize_t is not always available and the cast it was used in wasn't
necessary in the first place, the value already has the right type.
2024-02-15 11:32:48 +01:00
Saúl Ibarra Corretgé
fb03ca24d2 Add WASI support 2024-02-14 08:59:15 +01:00
Saúl Ibarra Corretgé
7f928d289f Check-in all generated C files
Closes: https://github.com/quickjs-ng/quickjs/issues/262
2024-02-13 09:49:57 +01:00
Saúl Ibarra Corretgé
7ded62c536 Align module export API with upstream
Partially reverts
6868fb9e25
but the same behavior can be implemented in userland by getting the
module ns and querying its properties.

Ref: c6cc6a9a5e
Fixes: https://github.com/quickjs-ng/quickjs/issues/259
2024-02-12 11:00:31 +01:00
Marc Redemske
359a118562 Add qjsc to release artifacts 2024-02-12 10:32:02 +01:00
Rob Loach
229b07b9b2 android: Additional malloc_usable_size() fixes 2024-01-31 07:39:53 +01:00
Juan Campa
ca176d4e8b Fix memory usage of rt->class_count 2024-01-29 22:29:07 +01:00
Rob Loach
412c0011bb android: In NDK, malloc_usable_size() was renamed to dlmalloc_usable_size() 2024-01-29 22:28:58 +01:00
Guilherme Bernal
6868fb9e25 feat: Added functions to get access to module exports 2024-01-18 18:42:37 +01:00
Ben Noordhuis
e995085d0c Fix evaluation order of computed properties
The evaluation order is observable. Align with what test262 expects.
2024-01-16 12:43:35 +01:00
Jason
48e4c63a0e
Add support for compiling with Microsoft Visual Studio C++ (MSVC) (#246) 2024-01-16 12:42:05 +01:00
Andries Hiemstra
5f6171c722
removed some unused vars (#245) 2024-01-04 16:55:56 +01:00
Ben Noordhuis
4b138c8923
Run V8 spec conformance test suite (#243)
The shell script runs the tests and diffs stdout against v8.txt.
Lines added/removed means tests were broken/fixed.

Future work is to a) fix failing tests, and b) enable more tests.

A number are disabled for various reasons and mjsunit subdirectories are
currently skipped. Need to decide on a case-by-case basis what is and
isn't relevant to us.

At the moment about 430 tests are run of which approx. 80% pass.
2024-01-02 07:47:40 +01:00
Ben Noordhuis
9f9bf3c9ab
Fix for/in iteration over proxy objects (#241) 2023-12-30 22:47:32 +01:00
Ben Noordhuis
b5d6cea20e
Fix Reflect typed array element conversion (#240) 2023-12-30 10:45:33 +01:00
Ben Noordhuis
05fb3d9dc8
Fix Reflect with detached ArrayBuffer (#239) 2023-12-29 15:10:45 +01:00
Ben Noordhuis
64c9ac5392
Fix run-test262 dynamic import (#237)
Make basename imports resolve relative to the file under test.
2023-12-27 10:19:58 +01:00
Nathan Rajlich
440fc1b96b
Fix getTimezoneOffset() when tm_gmtoff is not available (#224) 2023-12-24 09:34:14 +01:00
Saúl Ibarra Corretgé
2fb838c803 Fix UB in js_dtoa1 2023-12-23 00:11:41 +01:00
Fabrice Bellard
fad030bef2 reduced JS_MAX_LOCAL_VARS (github issue #123) 2023-12-23 00:11:41 +01:00
Saúl Ibarra Corretgé
bfb4b35722 Fix: 'for of' expression cannot start with 'async'
Ref: 7cefa7b121
2023-12-23 00:11:41 +01:00
Saúl Ibarra Corretgé
7ef2ed6363 Remove incorrect await in async yield*
Ref: 43420235d5
2023-12-23 00:11:41 +01:00
Saúl Ibarra Corretgé
0a640f5040 Add container_of macro
Ref: c3599515c8
2023-12-23 00:11:41 +01:00
Fabrice Bellard
c1a3b64382 Safer typed array finalizer 2023-12-23 00:11:41 +01:00
Saúl Ibarra Corretgé
b8402ad388 Fix js_strtod with large integers
Ref: a96f440746
2023-12-23 00:11:41 +01:00
Nathan Rajlich
119f2c1b4c
Add support for cmake -DDEBUG_LEAKS=1 (#230)
I want to do a Release build (so that assert is disabled), but still
log leaks. This adds the option to enable that through CMake.
2023-12-22 21:30:10 +01:00
Nathan Rajlich
f94fbe2f8a Make performance configurable 2023-12-22 12:11:29 +01:00
Ben Noordhuis
f0ef9e1593
Implement RegExp 'v' flag, part 1 (#229)
This commit implements the flag itself and teaches the regex engine to
reject previously accepted patterns when in unicodeSets mode.

Refs: https://github.com/quickjs-ng/quickjs/issues/228
2023-12-21 19:37:31 +01:00
Saúl Ibarra Corretgé
d1852b5ea2 Remove unnecessary casts
Follow-up to https://github.com/quickjs-ng/quickjs/pull/195
2023-12-20 09:02:28 +01:00
Saúl Ibarra Corretgé
c29ae8d08c Now working on 0.4.0 2023-12-19 22:58:20 +01:00
Saúl Ibarra Corretgé
2d0b6d8ade Set version to 0.3.0 2023-12-19 22:46:31 +01:00
Saúl Ibarra Corretgé
4c929c5b6b Implement Error.stackTraceLimit
We default to 10 with a max cap of 64.

Ref: https://v8.dev/docs/stack-trace-api
2023-12-19 22:45:36 +01:00
Saúl Ibarra Corretgé
555d837334 Implement Error.prepareStackTrace support
Based on V8's API: https://v8.dev/docs/stack-trace-api.

Bits picked from Frida: 78fd25fed8

Closes: https://github.com/quickjs-ng/quickjs/issues/134
2023-12-19 15:36:44 +01:00
Ben Noordhuis
471e821570
Fix typo in #undef (#222) 2023-12-16 15:11:28 +01:00
Saúl Ibarra Corretgé
8934101a67 Drop non-standard Error properties 2023-12-16 01:09:49 +01:00
Ben Noordhuis
5cbf8727a6
Retain function source code in serialized bytecode (#218)
Also fix a small memory leak in the output from `qjsc -e`.

Fixes: https://github.com/quickjs-ng/quickjs/issues/217
2023-12-16 01:01:26 +01:00
Saúl Ibarra Corretgé
7474b28036 Remove unused member from JSContext 2023-12-16 00:44:31 +01:00
Ben Noordhuis
35e6bfceb1
Partially port bellard/quickjs@58f374ef42 (#214)
This commit merges JS_SetPropertyGeneric into JS_SetPropertyInternal2
and obsoletes commit b51b510 and partially obsoletes commit 8baafc4;
detachment and negative zero handling now fall out naturally.
2023-12-15 00:03:18 +01:00
Ben Noordhuis
ba8b80f112
Remove broken JS_READ_OBJ_ROM_DATA flag (#216)
This JS_ReadObject() flag no longer works for bytecode. The IC opcodes
are patched during execution.

Fixes: https://github.com/quickjs-ng/quickjs/issues/206
Refs: https://github.com/quickjs-ng/quickjs/pull/120
2023-12-14 15:25:29 +01:00
Saúl Ibarra Corretgé
e5812862f9 Fix 'return' handling with 'yield' in 'for of' or with finally blocks
Ref: 4bb8c35da7
2023-12-14 11:49:14 +01:00
Saúl Ibarra Corretgé
39901e2b86 Fix async generator in case of exception in implicit await in the 'return' statement
Ref: 57105c7f23
2023-12-14 11:49:14 +01:00
Fabrice Bellard
864a66459b Raise an error if a private method is added twice to an object 2023-12-14 11:49:14 +01:00
Ben Noordhuis
b51b5100b0
Handle negative zero typed array indices correctly (#212)
`ta["-0"] = 42` is a thing and not just any thing but a decidedly weird
thing: it completes successful, sets no property, but still evaluates
the value for side effects.
2023-12-14 11:12:55 +01:00
Ben Noordhuis
5168db1965
Handle TypedArray detach during iteration (#209)
Per spec: detaching the TA mid-iteration is allowed.

TypedArray.prototype.sort should not throw an exception when that
happens and now no longer does.
2023-12-13 08:55:01 +01:00
Ben Noordhuis
8baafc46bd
Don't throw OOB exception for detached typed array (#208)
`a[42] = 1` where a is a detached typed array should not throw but
`Object.defineProperty()` still should. Add a check and a flag that
distinguishes between the two cases.
2023-12-12 23:14:33 +01:00
Ben Noordhuis
b478329cdd
Remove JSFunctionBytecode.has_debug flag (#207)
And merge the debug struct into JSFunctionBytecode because it is now
always present.

Refs: https://github.com/quickjs-ng/quickjs/pull/193#pullrequestreview-1774511177
2023-12-12 00:10:52 +01:00
Saúl Ibarra Corretgé
030a0ddf3f Add navigator.userAgent to qjs CLI 2023-12-11 22:46:01 +01:00
Ben Noordhuis
bace4f635e
Record source column positions (#193)
And:
- display them in stack traces
- expose them as Function.prototype.columnNumber

OP_line_num is renamed to OP_source_loc and the pc2line data structure
is extended with the column number in zigzag encoding.

The bytecode version number BC_VERSION is incremented because pc2line
data is read and written by JS_ReadObject() and JS_WriteObject() when
it is present.

Fixes: https://github.com/quickjs-ng/quickjs/issues/149
2023-12-11 22:36:13 +01:00
Ben Noordhuis
40771c9103
Disable flaky test on Cygwin (#202)
Unclear why sending a SIGQUIT signal sometimes works and sometimes
doesn't but it's probably some kind of race condition in Cygwin's
emulation layer.

Fixes: https://github.com/quickjs-ng/quickjs/issues/184
2023-12-11 22:02:32 +01:00
Saúl Ibarra Corretgé
de44a37ae9 Fix not rebuilding source 2023-12-11 09:59:32 +01:00
Ben Noordhuis
dbed7be3cb
Handle TypedArray detach during iteration (#201)
Per spec: detaching the TA mid-iteration is allowed and should not
not throw an exception.

In the case of TypedArray.prototype.set, because iteration over the
source array is observable, we cannot bail out early when the TA is
first detached.
2023-12-11 09:22:02 +01:00
Ben Noordhuis
f7f1906989
Switch to SIGTERM in child process test (#203)
The hope is that switching from SIGQUIT to SIGTERM will resolve the
test's flakiness on Cygwin.

Refs: https://github.com/quickjs-ng/quickjs/issues/184
2023-12-11 09:21:19 +01:00
Ben Noordhuis
315096461b
Implement TypedArray.prototype.with (#200) 2023-12-10 21:25:31 +01:00
Ben Noordhuis
83dfc635f1
Implement TypedArray.prototype.toSorted (#199) 2023-12-10 21:23:52 +01:00
Ben Noordhuis
05f00a87f7
Implement TypedArray.prototype.toReversed (#198) 2023-12-10 21:21:21 +01:00
Fabrice Bellard
baf50f9236 fixed duplicate static private setter/getter test 2023-12-10 21:03:48 +01:00
Fabrice Bellard
e8b97048d4 Symbol.species is no longer used in TypedArray constructor from a TypedArray 2023-12-10 21:03:48 +01:00
Fabrice Bellard
46996ff258 fixed delete super.x error 2023-12-10 21:03:48 +01:00
Ben Noordhuis
67d90092fe Add regression test for previous commit 2023-12-10 21:03:48 +01:00
Fabrice Bellard
30e4767e67 fixed lexical scope of 'this' with eval (github issue #192) 2023-12-10 21:03:48 +01:00
Ben Noordhuis
f1b7b6da71
Replace JSValueConst with JSValue (#195)
JSValueConst was only used for the now removed CONFIG_CHECK_JSVALUE
build mode. It is kept around as an alias for JSValue in quickjs.h to
avoid breaking everyone's source builds but remove it everywhere else.
2023-12-10 15:15:42 +01:00
Ben Noordhuis
4d57997ee7
Remove CONFIG_CHECK_JSVALUE build mode (#194)
It doesn't produce a working build and I'm somewhat skeptical that
its purported goal of catching reference counting bugs still works.
2023-12-10 13:50:26 +01:00
Ben Noordhuis
4c1b9f8c7f
Fix OP_FMT_none_loc bytecode dumping (#192)
Commit f404980 ("Add fused get_loc0_loc1 opcode") introduced an
off-by-one (sometimes negative) array index bug because OP_get_loc1_loc1
replaced OP_get_loc0 as the first OP_FMT_none_loc opcode.
2023-12-09 23:46:54 +01:00
Ben Noordhuis
f6ed206bd5
Change regexp flags field from uint8 to uint16 (#185)
I need the extra bits to store the 'v' flag as described in
https://github.com/tc39/proposal-regexp-v-flag
2023-12-09 16:47:05 +01:00
Ben Noordhuis
6bd3d5660e
Use JS_ToBigIntFree() instead of JS_ToBigInt() (#190)
Reduces reference count juggling in the happy path and, to a lesser
extent, in error paths.
2023-12-09 14:54:54 +01:00
Ben Noordhuis
4fc814311a
Remove js_new_bf() (#189)
And replace the open-coded JS_NewBigInt() logic at its one call site
with the real thing.
2023-12-09 14:54:33 +01:00
Ben Noordhuis
d17129035d
Remove duplicate JS_GetBigInt call (#188) 2023-12-09 14:54:13 +01:00
Ben Noordhuis
f7d2169999
Rename LRE_FLAG_UTF16 to LRE_FLAG_UNICODE (#186)
Prep work for https://github.com/tc39/proposal-regexp-v-flag a.k.a.
UnicodeSets.
2023-12-08 10:58:00 +01:00
Ben Noordhuis
42b708622c
Use named constant for regexp bytecode size field (#183) 2023-12-07 23:00:32 +01:00
Saúl Ibarra Corretgé
9539e3cc65 Fix private field setters
Ref: 55a4878a60
2023-12-07 22:21:48 +01:00
Felipe Gasper
9de152667f
Add NetBSD support (#177) 2023-12-07 15:48:31 +01:00
Saúl Ibarra Corretgé
7542b14c5b Fix Makefile rebuilding every target 2023-12-07 11:34:52 +01:00
Saúl Ibarra Corretgé
622ce2cc9d Detect JOBS in a more portable way 2023-12-07 10:59:11 +01:00
48 changed files with 16064 additions and 5395 deletions

View file

@ -15,6 +15,15 @@ on:
- master - master
jobs: jobs:
codegen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: build
run: |
make codegen
- name: Check if the git repository is clean
run: $(exit $(git status --porcelain --untracked-files=no | head -255 | wc -l)) || (echo "Dirty git tree"; git diff; exit 1)
linux: linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@ -22,7 +31,7 @@ jobs:
matrix: matrix:
buildType: [Debug, Release] buildType: [Debug, Release]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: build - name: build
@ -38,13 +47,17 @@ jobs:
if: ${{ matrix.buildType == 'Release' }} if: ${{ matrix.buildType == 'Release' }}
run: | run: |
time make test262 time make test262
- name: test v8 mjsunit
if: ${{ matrix.buildType == 'Release' }}
run: |
./v8.sh
linux-32bits: linux-32bits:
runs-on: ubuntu-latest runs-on: ubuntu-latest
defaults: defaults:
run: run:
shell: alpine.sh {0} shell: alpine.sh {0}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1 - uses: jirutka/setup-alpine@v1
with: with:
arch: x86 arch: x86
@ -58,40 +71,77 @@ jobs:
- name: test - name: test
run: | run: |
make test make test
linux-gcc48: linux-riscv64:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: defaults:
image: ubuntu:14.04 run:
shell: alpine.sh {0}
steps: steps:
- name: install dependencies - uses: actions/checkout@v3
run: | - uses: jirutka/setup-alpine@v1
apt update && apt -y install make gcc-4.8 wget time software-properties-common
# git in default ppa repository is too old to run submodule checkout
add-apt-repository -y ppa:git-core/ppa
apt update
apt install -y git
wget https://github.com/Kitware/CMake/releases/download/v3.28.0-rc5/cmake-3.28.0-rc5-linux-x86_64.sh
sh cmake-3.28.0-rc5-linux-x86_64.sh --skip-license --prefix=/usr
- name: checkout
uses: actions/checkout@v3
with: with:
submodules: true arch: riscv64
packages: "build-base make cmake"
- name: build - name: build
run: | run: |
CC=gcc-4.8 make make
- name: stats - name: stats
run: | run: |
make stats make stats
- name: test - name: test
run: | run: |
make test make test
- name: test 262 linux-s390x:
runs-on: ubuntu-latest
defaults:
run:
shell: alpine.sh {0}
steps:
- uses: actions/checkout@v3
- uses: jirutka/setup-alpine@v1
with:
arch: s390x
packages: "build-base make cmake"
- name: build
run: | run: |
time make test262 make
- name: stats
run: |
make stats
- name: test
run: |
make test
linux-gcc48:
runs-on: ubuntu-latest
container:
image: ubuntu:18.04
steps:
- name: install dependencies
run: |
apt update && apt -y install make gcc-4.8 cmake software-properties-common
# git in default ppa repository is too old to run submodule checkout
add-apt-repository -y ppa:git-core/ppa
apt update && apt install -y git
- name: checkout
uses: actions/checkout@v3
with:
submodules: true
- name: build
env:
CC: gcc-4.8
run: |
mkdir build
cd build
cmake ..
cd ..
make -C build -j$(getconf _NPROCESSORS_ONLN)
- name: stats
run: |
./build/qjs -qd
linux-examples: linux-examples:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
make BUILD_EXAMPLES=ON make BUILD_EXAMPLES=ON
@ -109,10 +159,11 @@ jobs:
./build/qjs examples/test_fib.js ./build/qjs examples/test_fib.js
./build/qjs examples/test_point.js ./build/qjs examples/test_point.js
./build/qjs tests/test_bjson.js ./build/qjs tests/test_bjson.js
./build/function_source
linux-shared: linux-shared:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
make BUILD_SHARED_LIBS=ON make BUILD_SHARED_LIBS=ON
@ -123,9 +174,13 @@ jobs:
linux-asan: linux-asan:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
# ASLR with big PIE slides does not work well with [AM]San
- name: disable ASLR
run: |
sudo sysctl -w kernel.randomize_va_space=0
- name: build - name: build
run: | run: |
make CONFIG_ASAN=ON make CONFIG_ASAN=ON
@ -142,9 +197,13 @@ jobs:
linux-msan: linux-msan:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
# ASLR with big PIE slides does not work well with [AM]San
- name: disable ASLR
run: |
sudo sysctl -w kernel.randomize_va_space=0
- name: build - name: build
env: env:
CC: clang CC: clang
@ -158,7 +217,7 @@ jobs:
linux-ubsan: linux-ubsan:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: build - name: build
@ -174,15 +233,41 @@ jobs:
UBSAN_OPTIONS: halt_on_error=1 UBSAN_OPTIONS: halt_on_error=1
run: | run: |
time make test262 time make test262
linux-tcc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: install TCC
run: |
pushd /tmp
git clone https://repo.or.cz/tinycc.git
cd tinycc
git checkout 9d2068c6309dc50dfdbbc30a5d6757683d3f884c
./configure
make
sudo make install
tcc -v
popd
- name: build
env:
CC: tcc
run: |
make
- name: stats
run: |
make stats
macos: macos:
runs-on: macos-latest runs-on: ${{ matrix.os }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
buildType: [Debug, Release] buildType: [Debug, Release]
os: [macos-12, macos-14]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
make BUILD_TYPE=${{matrix.buildType}} make BUILD_TYPE=${{matrix.buildType}}
@ -193,9 +278,13 @@ jobs:
run: | run: |
make test make test
macos-examples: macos-examples:
runs-on: macos-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-12, macos-14]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
make BUILD_EXAMPLES=ON make BUILD_EXAMPLES=ON
@ -213,10 +302,15 @@ jobs:
./build/qjs examples/test_fib.js ./build/qjs examples/test_fib.js
./build/qjs examples/test_point.js ./build/qjs examples/test_point.js
./build/qjs tests/test_bjson.js ./build/qjs tests/test_bjson.js
./build/function_source
macos-shared: macos-shared:
runs-on: macos-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-12, macos-14]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
make BUILD_SHARED_LIBS=ON make BUILD_SHARED_LIBS=ON
@ -225,9 +319,13 @@ jobs:
run: | run: |
make stats make stats
macos-asan: macos-asan:
runs-on: macos-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-12, macos-14]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
make CONFIG_ASAN=ON make CONFIG_ASAN=ON
@ -237,9 +335,13 @@ jobs:
run: | run: |
make test make test
macos-ubsan: macos-ubsan:
runs-on: macos-latest runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-12, macos-14]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
make CONFIG_UBSAN=ON make CONFIG_UBSAN=ON
@ -249,6 +351,35 @@ jobs:
run: | run: |
make test make test
windows-msvc:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
arch: [x64, Win32]
buildType: [Debug, Release]
steps:
- uses: actions/checkout@v4
- name: build
run: |
cmake -B build -G "Visual Studio 17 2022" -A ${{matrix.arch}}
cmake --build build --config ${{matrix.buildType}} --target qjs_exe
cmake --build build --config ${{matrix.buildType}} --target function_source
- name: stats
run: |
build\${{matrix.buildType}}\qjs.exe -qd
- name: test
run: |
build\${{matrix.buildType}}\qjs.exe tests\test_bigint.js
build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
build\${{matrix.buildType}}\qjs.exe tests\test_language.js
build\${{matrix.buildType}}\qjs.exe tests\test_builtin.js
build\${{matrix.buildType}}\qjs.exe tests\test_loop.js
build\${{matrix.buildType}}\qjs.exe tests\test_std.js
build\${{matrix.buildType}}\qjs.exe tests\test_worker.js
build\${{matrix.buildType}}\qjs.exe tests\test_queue_microtask.js
build\${{matrix.buildType}}\function_source.exe
windows-clang: windows-clang:
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
@ -256,24 +387,58 @@ jobs:
matrix: matrix:
buildType: [Debug, Release] buildType: [Debug, Release]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
cmake -B build -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Visual Studio 17 2022" -T ClangCL cmake -B build -G "Visual Studio 17 2022" -T ClangCL
cmake --build build --target qjs_exe cmake --build build --config ${{matrix.buildType}} --target qjs_exe
cmake --build build --config ${{matrix.buildType}} --target function_source
- name: stats - name: stats
run: | run: |
cmd /r build\Debug\qjs.exe -qd build\${{matrix.buildType}}\qjs.exe -qd
- name: test - name: test
run: | run: |
cmd /r build\Debug\qjs.exe tests\test_bigint.js build\${{matrix.buildType}}\qjs.exe tests\test_bigint.js
cmd /r build\Debug\qjs.exe tests\test_closure.js build\${{matrix.buildType}}\qjs.exe tests\test_closure.js
cmd /r build\Debug\qjs.exe tests\test_language.js build\${{matrix.buildType}}\qjs.exe tests\test_language.js
cmd /r build\Debug\qjs.exe tests\test_builtin.js build\${{matrix.buildType}}\qjs.exe tests\test_builtin.js
cmd /r build\Debug\qjs.exe tests\test_loop.js build\${{matrix.buildType}}\qjs.exe tests\test_loop.js
cmd /r build\Debug\qjs.exe tests\test_std.js build\${{matrix.buildType}}\qjs.exe tests\test_std.js
cmd /r build\Debug\qjs.exe tests\test_worker.js build\${{matrix.buildType}}\qjs.exe tests\test_worker.js
cmd /r build\Debug\qjs.exe tests\test_queue_microtask.js build\${{matrix.buildType}}\qjs.exe tests\test_queue_microtask.js
build\${{matrix.buildType}}\function_source.exe
windows-ninja:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
buildType: [Debug, Release]
steps:
- uses: actions/checkout@v4
- name: install ninja
run: |
choco install ninja
ninja.exe --version
- name: build
run: |
cmake -B build -DCMAKE_BUILD_TYPE=${{matrix.buildType}} -G "Ninja"
cmake --build build --target qjs_exe
cmake --build build --target function_source
- name: stats
run: |
build\qjs.exe -qd
- name: test
run: |
build\qjs.exe tests\test_bigint.js
build\qjs.exe tests\test_closure.js
build\qjs.exe tests\test_language.js
build\qjs.exe tests\test_builtin.js
build\qjs.exe tests\test_loop.js
build\qjs.exe tests\test_std.js
build\qjs.exe tests\test_worker.js
build\qjs.exe tests\test_queue_microtask.js
build\function_source.exe
windows-mingw: windows-mingw:
runs-on: windows-latest runs-on: windows-latest
@ -290,7 +455,7 @@ jobs:
run: run:
shell: msys2 {0} shell: msys2 {0}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup MSYS2 - name: Setup MSYS2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
@ -318,7 +483,7 @@ jobs:
run: run:
shell: msys2 {0} shell: msys2 {0}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup MSYS2 - name: Setup MSYS2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
@ -340,7 +505,7 @@ jobs:
emscripten: emscripten:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: mymindstorm/setup-emsdk@v13 - uses: mymindstorm/setup-emsdk@v13
- name: check emsdk - name: check emsdk
run: emcc -v run: emcc -v
@ -350,6 +515,22 @@ jobs:
emmake make -C build qjs_wasm -j$(getconf _NPROCESSORS_ONLN) emmake make -C build qjs_wasm -j$(getconf _NPROCESSORS_ONLN)
- name: result - name: result
run: ls -lh build run: ls -lh build
wasi:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: jcbhmr/setup-wasmtime@v2
- name: setup wasi-sdk
run: |
wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/wasi-sdk_21.0_amd64.deb -P /tmp
sudo apt install /tmp/wasi-sdk*.deb
- name: test
run: |
cmake -B build -DCMAKE_TOOLCHAIN_FILE=/opt/wasi-sdk/share/cmake/wasi-sdk.cmake
make -C build qjs_exe
wasmtime run build/qjs -qd
echo "console.log('hello wasi!');" > t.js
wasmtime run --dir . build/qjs t.js
cygwin: cygwin:
runs-on: windows-latest runs-on: windows-latest
@ -365,7 +546,7 @@ jobs:
with: with:
packages: make cmake gcc-g++ bash packages: make cmake gcc-g++ bash
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: make run: make
@ -379,29 +560,70 @@ jobs:
openbsd: openbsd:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build + test - name: build + test
uses: vmactions/openbsd-vm@v1 uses: vmactions/openbsd-vm@v1
with: with:
usesh: true usesh: true
prepare: | prepare: |
pkg_add cmake pkg_add cmake gmake
run: | run: |
cmake -B build gmake
cmake --build build -j $(sysctl -n hw.ncpu) gmake stats
./build/qjs -qd
freebsd: freebsd:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build + test - name: build + test
uses: vmactions/freebsd-vm@v1 uses: vmactions/freebsd-vm@v1
with: with:
usesh: true usesh: true
prepare: | prepare: |
pkg install -y cmake pkg install -y cmake gmake
run: | run: |
cmake -B build gmake
cmake --build build -j $(sysctl -n hw.ncpu) gmake stats
./build/qjs -qd
netbsd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: build + test
uses: vmactions/netbsd-vm@v1
with:
usesh: true
prepare: |
/usr/sbin/pkg_add cmake gmake
run: |
gmake
gmake stats
gmake test
android:
runs-on: ubuntu-latest
container: reactnativecommunity/react-native-android:v13.0
steps:
- uses: actions/checkout@v4
- name: Configure android arm64
# see build options you can use in https://developer.android.com/ndk/guides/cmake
run: |
mkdir build
cd build
$ANDROID_HOME/cmake/3.22.1/bin/cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_HOME/ndk/26.0.10792818/build/cmake/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="arm64-v8a" -DANDROID_PLATFORM=android-24 -DBUILD_QJS_LIBC=ON ..
- name: Build android arm64
run: |
$ANDROID_HOME/cmake/3.22.1/bin/cmake --build build --target qjs
ls -lh build
ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: configure
run: |
cmake -B build -GXcode -DCMAKE_SYSTEM_NAME:STRING=iOS -DCMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED:BOOL=NO -DBUILD_QJS_LIBC=ON
- name: build
run: |
cmake --build build --config Release --target qjs
ls -lh build

View file

@ -6,10 +6,66 @@ on:
- "v*.*.*" - "v*.*.*"
jobs: jobs:
linux-x86: linux-aarch64:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1
with:
arch: aarch64
packages: "build-base make cmake"
- name: build
shell: alpine.sh {0}
run: |
mkdir build
cd build
cmake -DBUILD_STATIC_QJS_EXE=ON ..
cd ..
cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN)
cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN)
mv build/qjs build/qjs-linux-aarch64
mv build/qjsc build/qjsc-linux-aarch64
- name: check
shell: alpine.sh {0}
run: |
file build/*-linux-aarch64
- name: upload
uses: actions/upload-artifact@v3
with:
name: qjs
path: build/*-linux-aarch64
linux-riscv64:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1
with:
arch: riscv64
packages: "build-base make cmake"
- name: build
shell: alpine.sh {0}
run: |
mkdir build
cd build
cmake -DBUILD_STATIC_QJS_EXE=ON ..
cd ..
cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN)
cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN)
mv build/qjs build/qjs-linux-riscv64
mv build/qjsc build/qjsc-linux-riscv64
- name: check
shell: alpine.sh {0}
run: |
file build/*-linux-riscv64
- name: upload
uses: actions/upload-artifact@v3
with:
name: qjs
path: build/*-linux-riscv64
linux-x86:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1 - uses: jirutka/setup-alpine@v1
with: with:
arch: x86 arch: x86
@ -22,21 +78,23 @@ jobs:
cmake -DBUILD_STATIC_QJS_EXE=ON .. cmake -DBUILD_STATIC_QJS_EXE=ON ..
cd .. cd ..
cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN) cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN)
cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN)
mv build/qjs build/qjs-linux-x86 mv build/qjs build/qjs-linux-x86
mv build/qjsc build/qjsc-linux-x86
- name: check - name: check
shell: alpine.sh {0} shell: alpine.sh {0}
run: | run: |
file build/qjs-linux-x86 file build/*-linux-x86
- name: upload - name: upload
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: qjs name: qjs
path: build/qjs-linux-x86 path: build/*-linux-x86
linux-x86_64: linux-x86_64:
runs-on: ubuntu-latest runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- uses: jirutka/setup-alpine@v1 - uses: jirutka/setup-alpine@v1
with: with:
arch: x86_64 arch: x86_64
@ -49,21 +107,23 @@ jobs:
cmake -DBUILD_STATIC_QJS_EXE=ON .. cmake -DBUILD_STATIC_QJS_EXE=ON ..
cd .. cd ..
cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN) cmake --build build --target qjs_exe -j$(getconf _NPROCESSORS_ONLN)
cmake --build build --target qjsc -j$(getconf _NPROCESSORS_ONLN)
mv build/qjs build/qjs-linux-x86_64 mv build/qjs build/qjs-linux-x86_64
mv build/qjsc build/qjsc-linux-x86_64
- name: check - name: check
shell: alpine.sh {0} shell: alpine.sh {0}
run: | run: |
file build/qjs-linux-x86_64 file build/*-linux-x86_64
- name: upload - name: upload
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: qjs name: qjs
path: build/qjs-linux-x86_64 path: build/*-linux-x86_64
macos: macos:
runs-on: macos-latest runs-on: macos-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: build - name: build
run: | run: |
mkdir build mkdir build
@ -71,14 +131,15 @@ jobs:
cmake -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" .. cmake -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" ..
make -j$(getconf _NPROCESSORS_ONLN) make -j$(getconf _NPROCESSORS_ONLN)
mv qjs qjs-darwin mv qjs qjs-darwin
mv qjsc qjsc-darwin
- name: check - name: check
run: | run: |
lipo -info build/qjs-darwin lipo -info build/qjs-darwin build/qjsc-darwin
- name: upload - name: upload
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: qjs name: qjs
path: build/qjs-darwin path: build/*-darwin
windows-x86: windows-x86:
runs-on: windows-latest runs-on: windows-latest
@ -86,7 +147,7 @@ jobs:
run: run:
shell: msys2 {0} shell: msys2 {0}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup MSYS2 - name: Setup MSYS2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
@ -102,14 +163,15 @@ jobs:
run: | run: |
make make
mv build/qjs.exe build/qjs-windows-x86.exe mv build/qjs.exe build/qjs-windows-x86.exe
mv build/qjsc.exe build/qjsc-windows-x86.exe
- name: check - name: check
run: | run: |
ldd build/qjs-windows-x86.exe ldd build/qjs-windows-x86.exe build/qjsc-windows-x86.exe
- name: upload - name: upload
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: qjs name: qjs
path: build/qjs-windows-x86.exe path: build/*-windows-x86.exe
windows-x86_64: windows-x86_64:
runs-on: windows-latest runs-on: windows-latest
@ -117,7 +179,7 @@ jobs:
run: run:
shell: msys2 {0} shell: msys2 {0}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Setup MSYS2 - name: Setup MSYS2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
@ -133,18 +195,38 @@ jobs:
run: | run: |
make make
mv build/qjs.exe build/qjs-windows-x86_64.exe mv build/qjs.exe build/qjs-windows-x86_64.exe
mv build/qjsc.exe build/qjsc-windows-x86_64.exe
- name: check - name: check
run: | run: |
ldd build/qjs-windows-x86_64.exe ldd build/qjs-windows-x86_64.exe build/qjsc-windows-x86_64.exe
- name: upload - name: upload
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: qjs name: qjs
path: build/qjs-windows-x86_64.exe path: build/*-windows-x86_64.exe
wasi:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: setup wasi-sdk
run: |
wget -nv https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/wasi-sdk_21.0_amd64.deb -P /tmp
sudo apt install /tmp/wasi-sdk*.deb
- name: build
run: |
cmake -B build -DCMAKE_TOOLCHAIN_FILE=/opt/wasi-sdk/share/cmake/wasi-sdk.cmake
make -C build qjs_exe
mv build/qjs build/qjs-wasi.wasm
- name: upload
uses: actions/upload-artifact@v3
with:
name: qjs
path: build/qjs-wasi.wasm
upload-to-release: upload-to-release:
needs: [linux-x86, linux-x86_64, macos, windows-x86, windows-x86_64] needs: [linux-aarch64, linux-riscv64, linux-x86, linux-x86_64, macos, windows-x86, windows-x86_64, wasi]
runs-on: ubuntu-latest runs-on: ubuntu-20.04
steps: steps:
- name: get assets - name: get assets
uses: actions/download-artifact@v3 uses: actions/download-artifact@v3
@ -154,8 +236,5 @@ jobs:
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
files: | files: |
build/qjs/qjs-linux-x86_64 build/qjs/qjs-*
build/qjs/qjs-linux-x86 build/qjs/qjsc-*
build/qjs/qjs-windows-x86.exe
build/qjs/qjs-windows-x86_64.exe
build/qjs/qjs-darwin

23
.github/workflows/valgrind.yml vendored Normal file
View file

@ -0,0 +1,23 @@
name: valgrind
on:
push:
branches:
- master
workflow_dispatch:
jobs:
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true
- name: install valgrind
run: sudo apt-get update && sudo apt-get install valgrind
- name: build
run: |
make BUILD_TYPE=RelWithDebInfo
- name: test
run: |
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

2
.gitignore vendored
View file

@ -5,3 +5,5 @@
build/ build/
unicode/ unicode/
test262_*.txt test262_*.txt
.idea
cmake-*

View file

@ -5,9 +5,6 @@ project(quickjs LANGUAGES C)
include(CheckCCompilerFlag) include(CheckCCompilerFlag)
include(GNUInstallDirs) include(GNUInstallDirs)
# TODO:
# - Support cross-compilation
set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS ON) set(CMAKE_C_EXTENSIONS ON)
@ -30,7 +27,7 @@ macro(xcheck_add_c_compiler_flag FLAG)
endmacro() endmacro()
xcheck_add_c_compiler_flag(-Wall) xcheck_add_c_compiler_flag(-Wall)
if(NOT MSVC) if(NOT MSVC AND NOT IOS)
xcheck_add_c_compiler_flag(-Werror) xcheck_add_c_compiler_flag(-Werror)
xcheck_add_c_compiler_flag(-Wextra) xcheck_add_c_compiler_flag(-Wextra)
endif() endif()
@ -38,7 +35,6 @@ xcheck_add_c_compiler_flag(-Wno-implicit-fallthrough)
xcheck_add_c_compiler_flag(-Wno-sign-compare) xcheck_add_c_compiler_flag(-Wno-sign-compare)
xcheck_add_c_compiler_flag(-Wno-missing-field-initializers) xcheck_add_c_compiler_flag(-Wno-missing-field-initializers)
xcheck_add_c_compiler_flag(-Wno-unused-parameter) xcheck_add_c_compiler_flag(-Wno-unused-parameter)
xcheck_add_c_compiler_flag(-Wno-unused-variable)
xcheck_add_c_compiler_flag(-Wno-unused-but-set-variable) xcheck_add_c_compiler_flag(-Wno-unused-but-set-variable)
xcheck_add_c_compiler_flag(-Wno-array-bounds) xcheck_add_c_compiler_flag(-Wno-array-bounds)
xcheck_add_c_compiler_flag(-Wno-format-truncation) xcheck_add_c_compiler_flag(-Wno-format-truncation)
@ -54,7 +50,18 @@ if(MSVC)
xcheck_add_c_compiler_flag(-Wno-reserved-macro-identifier) xcheck_add_c_compiler_flag(-Wno-reserved-macro-identifier)
xcheck_add_c_compiler_flag(-Wno-reserved-identifier) xcheck_add_c_compiler_flag(-Wno-reserved-identifier)
xcheck_add_c_compiler_flag(-Wdeprecated-declarations) xcheck_add_c_compiler_flag(-Wdeprecated-declarations)
add_compile_definitions(WIN32_LEAN_AND_MEAN) xcheck_add_c_compiler_flag(/experimental:c11atomics)
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "WASI")
add_compile_definitions(
_WASI_EMULATED_PROCESS_CLOCKS
_WASI_EMULATED_SIGNAL
)
add_link_options(
-lwasi-emulated-process-clocks
-lwasi-emulated-signal
)
endif() endif()
if(CMAKE_BUILD_TYPE MATCHES "Debug") if(CMAKE_BUILD_TYPE MATCHES "Debug")
@ -145,25 +152,44 @@ if(BUILD_QJS_LIBC)
list(APPEND qjs_sources quickjs-libc.c) list(APPEND qjs_sources quickjs-libc.c)
endif() endif()
list(APPEND qjs_defines _GNU_SOURCE) list(APPEND qjs_defines _GNU_SOURCE)
if(WIN32)
list(APPEND qjs_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602)
endif()
list(APPEND qjs_libs qjs ${CMAKE_DL_LIBS}) list(APPEND qjs_libs qjs ${CMAKE_DL_LIBS})
find_package(Threads)
if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI")
list(APPEND qjs_libs ${CMAKE_THREAD_LIBS_INIT})
endif()
if(NOT MSVC) if(NOT MSVC)
list(APPEND qjs_libs m pthread) list(APPEND qjs_libs m)
endif() endif()
add_library(qjs ${qjs_sources}) add_library(qjs ${qjs_sources})
target_compile_definitions(qjs PRIVATE ${qjs_defines}) target_compile_definitions(qjs PRIVATE ${qjs_defines})
if (CMAKE_BUILD_TYPE MATCHES Debug) if(CMAKE_BUILD_TYPE MATCHES Debug OR DUMP_LEAKS)
target_compile_definitions(qjs PRIVATE target_compile_definitions(qjs PRIVATE
DUMP_LEAKS DUMP_LEAKS
) )
endif() endif()
target_include_directories(qjs PUBLIC target_include_directories(qjs PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
) )
if(EMSCRIPTEN) if(EMSCRIPTEN)
add_executable(qjs_wasm ${qjs_sources}) add_executable(qjs_wasm ${qjs_sources})
target_link_options(qjs_wasm PRIVATE
# in emscripten 3.x, this will be set to 16k which is too small for quickjs. #write sth. to force github rebuild
-sSTACK_SIZE=2097152 # let it be 2m = 2 * 1024 * 1024 = 2097152, otherwise, stack overflow may be occured at bootstrap
-sNO_INVOKE_RUN
-sNO_EXIT_RUNTIME
-sMODULARIZE # do not mess the global
-sEXPORT_ES6 # export js file to morden es module
-sEXPORT_NAME=getQuickJs # give a name
-sTEXTDECODER=1 # it will be 2 if we use -Oz, and that will cause js -> c string convertion fail
-sNO_DEFAULT_TO_CXX # this project is pure c project, no need for c plus plus handle
-sEXPORTED_RUNTIME_METHODS=ccall,cwrap
)
target_compile_definitions(qjs_wasm PRIVATE ${qjs_defines}) target_compile_definitions(qjs_wasm PRIVATE ${qjs_defines})
target_link_libraries(qjs_wasm m) target_link_libraries(qjs_wasm m)
endif() endif()
@ -183,19 +209,10 @@ target_link_libraries(qjsc ${qjs_libs})
# QuickJS CLI # QuickJS CLI
# #
add_custom_command(
OUTPUT repl.c
COMMAND qjsc -o ./repl.c -m ${CMAKE_CURRENT_SOURCE_DIR}/repl.js
DEPENDS qjsc
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Compile repl.js to bytecode"
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/repl.js
)
add_executable(qjs_exe add_executable(qjs_exe
gen/repl.c
qjs.c qjs.c
quickjs-libc.c quickjs-libc.c
${CMAKE_CURRENT_BINARY_DIR}/repl.c
) )
set_target_properties(qjs_exe PROPERTIES set_target_properties(qjs_exe PROPERTIES
OUTPUT_NAME "qjs" OUTPUT_NAME "qjs"
@ -217,7 +234,7 @@ endif()
# #
# run-test262 uses pthreads. # run-test262 uses pthreads.
if(NOT WIN32) if(NOT WIN32 AND NOT EMSCRIPTEN)
add_executable(run-test262 add_executable(run-test262
quickjs-libc.c quickjs-libc.c
run-test262.c run-test262.c
@ -236,37 +253,28 @@ add_executable(unicode_gen EXCLUDE_FROM_ALL
) )
target_compile_definitions(unicode_gen PRIVATE ${qjs_defines}) target_compile_definitions(unicode_gen PRIVATE ${qjs_defines})
add_executable(function_source
gen/function_source.c
quickjs-libc.c
)
target_include_directories(function_source PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(function_source PRIVATE ${qjs_defines})
target_link_libraries(function_source ${qjs_libs})
# Examples # Examples
# #
if(BUILD_EXAMPLES AND NOT WIN32) if(BUILD_EXAMPLES AND NOT WIN32)
add_custom_command(
OUTPUT hello.c
COMMAND qjsc -e -o hello.c ${CMAKE_CURRENT_SOURCE_DIR}/examples/hello.js
DEPENDS qjsc
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Compile hello.js to a C file with bytecode embeddee"
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/examples/hello.js
)
add_executable(hello add_executable(hello
${CMAKE_CURRENT_BINARY_DIR}/hello.c gen/hello.c
quickjs-libc.c quickjs-libc.c
) )
target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(hello PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(hello PRIVATE ${qjs_defines}) target_compile_definitions(hello PRIVATE ${qjs_defines})
target_link_libraries(hello ${qjs_libs}) target_link_libraries(hello ${qjs_libs})
add_custom_command(
OUTPUT hello_module.c
COMMAND qjsc -e -o hello_module.c -m ${CMAKE_CURRENT_SOURCE_DIR}/examples/hello_module.js
DEPENDS qjsc
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Compile hello_module.js to a C file with bytecode embeddee"
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/examples/hello_module.js
)
add_executable(hello_module add_executable(hello_module
${CMAKE_CURRENT_BINARY_DIR}/hello_module.c gen/hello_module.c
quickjs-libc.c quickjs-libc.c
) )
target_include_directories(hello_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(hello_module PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
@ -305,17 +313,9 @@ if(BUILD_EXAMPLES AND NOT WIN32)
endif() endif()
endif() endif()
add_custom_command(
OUTPUT test_fib.c
COMMAND qjsc -e -o test_fib.c -M ${CMAKE_CURRENT_SOURCE_DIR}/examples/fib.so,fib -m ${CMAKE_CURRENT_SOURCE_DIR}/examples/test_fib.js
DEPENDS qjsc
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Compile test_fib.js to a C file with bytecode embedded"
SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/examples/test_fib.js
)
add_executable(test_fib add_executable(test_fib
${CMAKE_CURRENT_BINARY_DIR}/test_fib.c
examples/fib.c examples/fib.c
gen/test_fib.c
quickjs-libc.c quickjs-libc.c
) )
target_include_directories(test_fib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(test_fib PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
@ -323,28 +323,33 @@ if(BUILD_EXAMPLES AND NOT WIN32)
target_link_libraries(test_fib ${qjs_libs}) target_link_libraries(test_fib ${qjs_libs})
endif() endif()
add_executable(test_conv
tests/test_conv.c
)
# Install target # Install target
# #
file(STRINGS quickjs.h quickjs_h REGEX QJS_VERSION) if(NOT IOS)
string(REGEX MATCHALL "([0-9])" QJS_VERSION "${quickjs_h}") file(STRINGS quickjs.h quickjs_h REGEX QJS_VERSION)
list(GET QJS_VERSION 0 QJS_VERSION_MAJOR) string(REGEX MATCHALL "([0-9])" QJS_VERSION "${quickjs_h}")
list(GET QJS_VERSION 1 QJS_VERSION_MINOR) list(GET QJS_VERSION 0 QJS_VERSION_MAJOR)
list(GET QJS_VERSION 2 QJS_VERSION_PATCH) list(GET QJS_VERSION 1 QJS_VERSION_MINOR)
set_target_properties(qjs PROPERTIES list(GET QJS_VERSION 2 QJS_VERSION_PATCH)
VERSION ${QJS_VERSION_MAJOR}.${QJS_VERSION_MINOR}.${QJS_VERSION_PATCH} set_target_properties(qjs PROPERTIES
SOVERSION ${QJS_VERSION_MAJOR} VERSION ${QJS_VERSION_MAJOR}.${QJS_VERSION_MINOR}.${QJS_VERSION_PATCH}
) SOVERSION ${QJS_VERSION_MAJOR}
install(FILES quickjs.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) )
if(BUILD_QJS_LIBC) install(FILES quickjs.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES quickjs-libc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) if(BUILD_QJS_LIBC)
install(FILES quickjs-libc.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
endif()
install(TARGETS qjs_exe RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS qjs EXPORT qjsConfig
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT qjsConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/quickjs)
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(DIRECTORY examples DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif() endif()
install(TARGETS qjs_exe RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
install(TARGETS qjs EXPORT qjsConfig
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(EXPORT qjsConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/quickjs)
install(FILES LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR})
install(DIRECTORY examples DESTINATION ${CMAKE_INSTALL_DOCDIR})

View file

@ -26,11 +26,21 @@
BUILD_DIR=build BUILD_DIR=build
BUILD_TYPE?=Release BUILD_TYPE?=Release
JOBS?=$(shell getconf _NPROCESSORS_ONLN)
QJS=$(BUILD_DIR)/qjs QJS=$(BUILD_DIR)/qjs
QJSC=$(BUILD_DIR)/qjsc
RUN262=$(BUILD_DIR)/run-test262 RUN262=$(BUILD_DIR)/run-test262
JOBS?=$(shell getconf _NPROCESSORS_ONLN)
ifeq ($(JOBS),)
JOBS := $(shell sysctl -n hw.ncpu)
endif
ifeq ($(JOBS),)
JOBS := $(shell nproc)
endif
ifeq ($(JOBS),)
JOBS := 4
endif
all: $(QJS) all: $(QJS)
@ -40,12 +50,26 @@ $(BUILD_DIR):
$(QJS): $(BUILD_DIR) $(QJS): $(BUILD_DIR)
cmake --build $(BUILD_DIR) -j $(JOBS) cmake --build $(BUILD_DIR) -j $(JOBS)
install: $(QJS) $(QJSC): $(BUILD_DIR)
cmake --build $(BUILD_DIR) --target qjsc -j $(JOBS)
$(BUILD_DIR)/test_conv: $(BUILD_DIR) tests/test_conv.c
cmake --build $(BUILD_DIR) --target test_conv
install: $(QJS) $(QJSC)
cmake --build $(BUILD_DIR) --target install cmake --build $(BUILD_DIR) --target install
clean: clean:
@rm -f v8.txt[1-9]*
cmake --build $(BUILD_DIR) --target clean cmake --build $(BUILD_DIR) --target clean
codegen: $(QJSC)
$(QJSC) -ss -o gen/repl.c -m repl.js
$(QJSC) -e -o gen/function_source.c tests/function_source.js
$(QJSC) -e -o gen/hello.c examples/hello.js
$(QJSC) -e -o gen/hello_module.c -m examples/hello_module.js
$(QJSC) -e -o gen/test_fib.c -M examples/fib.so,fib -m examples/test_fib.js
debug: debug:
BUILD_TYPE=Debug $(MAKE) BUILD_TYPE=Debug $(MAKE)
@ -65,9 +89,15 @@ test: $(QJS)
$(QJS) tests/test_worker.js $(QJS) tests/test_worker.js
$(QJS) tests/test_queue_microtask.js $(QJS) tests/test_queue_microtask.js
testconv: $(BUILD_DIR)/test_conv
$(BUILD_DIR)/test_conv
test262: $(QJS) test262: $(QJS)
$(RUN262) -m -c test262.conf -a $(RUN262) -m -c test262.conf -a
test262-fast: $(QJS)
$(RUN262) -m -c test262.conf -c test262-fast.conf -a
test262-update: $(QJS) test262-update: $(QJS)
$(RUN262) -u -c test262.conf -a $(RUN262) -u -c test262.conf -a
@ -83,4 +113,4 @@ unicode_gen: $(BUILD_DIR)
libunicode-table.h: unicode_gen libunicode-table.h: unicode_gen
$(BUILD_DIR)/unicode_gen unicode $@ $(BUILD_DIR)/unicode_gen unicode $@
.PHONY: all build debug install clean distclean stats test test262 test262-update test262-check microbench unicode_gen .PHONY: all debug install clean codegen distclean stats test test262 test262-update test262-check microbench unicode_gen $(QJS) $(QJSC)

View file

@ -1,7 +1,22 @@
# ⚡️ QuickJS - A mighty JavaScript engine # ⚡️ QuickJS - A mighty JavaScript engine
Friendly [QuickJS](https://bellard.org/quickjs) fork focused on reigniting the project. Friendly [QuickJS]() fork focused on reigniting the project.
🚧 Work in progress. ## Overview
test. In October 2023 [@bnoordhuis] and [@saghul] decided to fork the [QuickJS] project with
the aim of reigniting it. They reached out to the original authors ([@bellard] and [@chqrlie])
about their intentions.
As of December 2023 the initial goal was somewhat accomplished. [@bellard] resumed working on
the project and both parties have been pulling patches from each other since.
As of early 2024 both projects agree the proper path forward involves merging both projects
and combining the efforts. While that may take a while, since both projects diverged in certain
areas, there is willingness to go in this direction from both sides.
[QuickJS]: https://bellard.org/quickjs
[@bellard]: https://github.com/bellard
[@bnoordhuis]: https://github.com/bnoordhuis
[@chqrlie]: https://github.com/chqrlie
[@saghul]: https://github.com/saghul

904
cutils.c
View file

@ -34,6 +34,9 @@
#include "cutils.h" #include "cutils.h"
#undef NANOSEC
#define NANOSEC ((uint64_t) 1e9)
#pragma GCC visibility push(default) #pragma GCC visibility push(default)
void pstrcpy(char *buf, int buf_size, const char *str) void pstrcpy(char *buf, int buf_size, const char *str)
@ -129,7 +132,7 @@ int dbuf_realloc(DynBuf *s, size_t new_size)
return 0; return 0;
} }
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len) int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len)
{ {
size_t end; size_t end;
end = offset + len; end = offset + len;
@ -141,7 +144,7 @@ int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len)
return 0; return 0;
} }
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len) int dbuf_put(DynBuf *s, const void *data, size_t len)
{ {
if (unlikely((s->size + len) > s->allocated_size)) { if (unlikely((s->size + len) > s->allocated_size)) {
if (dbuf_realloc(s, s->size + len)) if (dbuf_realloc(s, s->size + len))
@ -210,56 +213,85 @@ void dbuf_free(DynBuf *s)
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
} }
/* Note: at most 31 bits are encoded. At most UTF8_CHAR_LEN_MAX bytes /*--- UTF-8 utility functions --*/
are output. */
int unicode_to_utf8(uint8_t *buf, unsigned int c)
{
uint8_t *q = buf;
if (c < 0x80) { /* Note: only encode valid codepoints (0x0000..0x10FFFF).
*q++ = c; At most UTF8_CHAR_LEN_MAX bytes are output. */
} else {
if (c < 0x800) { /* Compute the number of bytes of the UTF-8 encoding for a codepoint
*q++ = (c >> 6) | 0xc0; `c` is a code-point.
} else { Returns the number of bytes. If a codepoint is beyond 0x10FFFF the
if (c < 0x10000) { return value is 3 as the codepoint would be encoded as 0xFFFD.
*q++ = (c >> 12) | 0xe0; */
} else { size_t utf8_encode_len(uint32_t c)
if (c < 0x00200000) { {
*q++ = (c >> 18) | 0xf0; if (c < 0x80)
} else { return 1;
if (c < 0x04000000) { if (c < 0x800)
*q++ = (c >> 24) | 0xf8; return 2;
} else if (c < 0x80000000) { if (c < 0x10000)
*q++ = (c >> 30) | 0xfc; return 3;
*q++ = ((c >> 24) & 0x3f) | 0x80; if (c < 0x110000)
} else { return 4;
return 0; return 3;
}
*q++ = ((c >> 18) & 0x3f) | 0x80;
}
*q++ = ((c >> 12) & 0x3f) | 0x80;
}
*q++ = ((c >> 6) & 0x3f) | 0x80;
}
*q++ = (c & 0x3f) | 0x80;
}
return q - buf;
} }
static const unsigned int utf8_min_code[5] = { /* Encode a codepoint in UTF-8
0x80, 0x800, 0x10000, 0x00200000, 0x04000000, `buf` points to an array of at least `UTF8_CHAR_LEN_MAX` bytes
}; `c` is a code-point.
Returns the number of bytes. If a codepoint is beyond 0x10FFFF the
static const unsigned char utf8_first_code_mask[5] = { return value is 3 and the codepoint is encoded as 0xFFFD.
0x1f, 0xf, 0x7, 0x3, 0x1, No null byte is stored after the encoded bytes.
}; Return value is in range 1..4
*/
/* return -1 if error. *pp is not updated in this case. max_len must size_t utf8_encode(uint8_t *buf, uint32_t c)
be >= 1. The maximum length for a UTF8 byte sequence is 6 bytes. */
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
{ {
int l, c, b, i; if (c < 0x80) {
buf[0] = c;
return 1;
}
if (c < 0x800) {
buf[0] = (c >> 6) | 0xC0;
buf[1] = (c & 0x3F) | 0x80;
return 2;
}
if (c < 0x10000) {
buf[0] = (c >> 12) | 0xE0;
buf[1] = ((c >> 6) & 0x3F) | 0x80;
buf[2] = (c & 0x3F) | 0x80;
return 3;
}
if (c < 0x110000) {
buf[0] = (c >> 18) | 0xF0;
buf[1] = ((c >> 12) & 0x3F) | 0x80;
buf[2] = ((c >> 6) & 0x3F) | 0x80;
buf[3] = (c & 0x3F) | 0x80;
return 4;
}
buf[0] = (0xFFFD >> 12) | 0xE0;
buf[1] = ((0xFFFD >> 6) & 0x3F) | 0x80;
buf[2] = (0xFFFD & 0x3F) | 0x80;
return 3;
}
/* Decode a single code point from a UTF-8 encoded array of bytes
`p` is a valid pointer to an array of bytes
`pp` is a valid pointer to a `const uint8_t *` to store a pointer
to the byte following the current sequence.
Return the code point at `p`, in the range `0..0x10FFFF`
Return 0xFFFD on error. Only a single byte is consumed in this case
The maximum length for a UTF-8 byte sequence is 4 bytes.
This implements the algorithm specified in whatwg.org, except it accepts
UTF-8 encoded surrogates as JavaScript allows them in strings.
The source string is assumed to have at least UTF8_CHAR_LEN_MAX bytes
or be null terminated.
If `p[0]` is '\0', the return value is `0` and the byte is consumed.
cf: https://encoding.spec.whatwg.org/#utf-8-encoder
*/
uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp)
{
uint32_t c;
uint8_t lower, upper;
c = *p++; c = *p++;
if (c < 0x80) { if (c < 0x80) {
@ -267,51 +299,533 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
return c; return c;
} }
switch(c) { switch(c) {
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xC2: case 0xC3:
case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xC4: case 0xC5: case 0xC6: case 0xC7:
case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xC8: case 0xC9: case 0xCA: case 0xCB:
case 0xcc: case 0xcd: case 0xce: case 0xcf: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xD0: case 0xD1: case 0xD2: case 0xD3:
case 0xd4: case 0xd5: case 0xd6: case 0xd7: case 0xD4: case 0xD5: case 0xD6: case 0xD7:
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xD8: case 0xD9: case 0xDA: case 0xDB:
case 0xdc: case 0xdd: case 0xde: case 0xdf: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
l = 1; if (*p >= 0x80 && *p <= 0xBF) {
*pp = p + 1;
return ((c - 0xC0) << 6) + (*p - 0x80);
}
// otherwise encoding error
break; break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xE0:
case 0xe4: case 0xe5: case 0xe6: case 0xe7: lower = 0xA0; /* reject invalid encoding */
case 0xe8: case 0xe9: case 0xea: case 0xeb: goto need2;
case 0xec: case 0xed: case 0xee: case 0xef: case 0xE1: case 0xE2: case 0xE3:
l = 2; case 0xE4: case 0xE5: case 0xE6: case 0xE7:
case 0xE8: case 0xE9: case 0xEA: case 0xEB:
case 0xEC: case 0xED: case 0xEE: case 0xEF:
lower = 0x80;
need2:
if (*p >= lower && *p <= 0xBF && p[1] >= 0x80 && p[1] <= 0xBF) {
*pp = p + 2;
return ((c - 0xE0) << 12) + ((*p - 0x80) << 6) + (p[1] - 0x80);
}
// otherwise encoding error
break; break;
case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xF0:
case 0xf4: case 0xf5: case 0xf6: case 0xf7: lower = 0x90; /* reject invalid encoding */
l = 3; upper = 0xBF;
break; goto need3;
case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xF4:
l = 4; lower = 0x80;
break; upper = 0x8F; /* reject values above 0x10FFFF */
case 0xfc: case 0xfd: goto need3;
l = 5; case 0xF1: case 0xF2: case 0xF3:
lower = 0x80;
upper = 0xBF;
need3:
if (*p >= lower && *p <= upper && p[1] >= 0x80 && p[1] <= 0xBF
&& p[2] >= 0x80 && p[2] <= 0xBF) {
*pp = p + 3;
return ((c - 0xF0) << 18) + ((*p - 0x80) << 12) +
((p[1] - 0x80) << 6) + (p[2] - 0x80);
}
// otherwise encoding error
break; break;
default: default:
return -1; // invalid lead byte
break;
} }
/* check that we have enough characters */
if (l > (max_len - 1))
return -1;
c &= utf8_first_code_mask[l - 1];
for(i = 0; i < l; i++) {
b = *p++;
if (b < 0x80 || b >= 0xc0)
return -1;
c = (c << 6) | (b & 0x3f);
}
if (c < utf8_min_code[l - 1])
return -1;
*pp = p; *pp = p;
return c; return 0xFFFD;
} }
uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp) {
switch (max_len) {
case 0:
*pp = p;
return 0xFFFD;
case 1:
if (*p < 0x80)
goto good;
break;
case 2:
if (*p < 0xE0)
goto good;
break;
case 3:
if (*p < 0xF0)
goto good;
break;
default:
good:
return utf8_decode(p, pp);
}
*pp = p + 1;
return 0xFFFD;
}
/* Scan a UTF-8 encoded buffer for content type
`buf` is a valid pointer to a UTF-8 encoded string
`len` is the number of bytes to scan
`plen` points to a `size_t` variable to receive the number of units
Return value is a mask of bits.
- `UTF8_PLAIN_ASCII`: return value for 7-bit ASCII plain text
- `UTF8_NON_ASCII`: bit for non ASCII code points (8-bit or more)
- `UTF8_HAS_16BIT`: bit for 16-bit code points
- `UTF8_HAS_NON_BMP1`: bit for non-BMP1 code points, needs UTF-16 surrogate pairs
- `UTF8_HAS_ERRORS`: bit for encoding errors
*/
int utf8_scan(const char *buf, size_t buf_len, size_t *plen)
{
const uint8_t *p, *p_end, *p_next;
size_t i, len;
int kind;
uint8_t cbits;
kind = UTF8_PLAIN_ASCII;
cbits = 0;
len = buf_len;
// TODO: handle more than 1 byte at a time
for (i = 0; i < buf_len; i++)
cbits |= buf[i];
if (cbits >= 0x80) {
p = (const uint8_t *)buf;
p_end = p + buf_len;
kind = UTF8_NON_ASCII;
len = 0;
while (p < p_end) {
len++;
if (*p++ >= 0x80) {
/* parse UTF-8 sequence, check for encoding error */
uint32_t c = utf8_decode_len(p - 1, p_end - (p - 1), &p_next);
if (p_next == p)
kind |= UTF8_HAS_ERRORS;
p = p_next;
if (c > 0xFF) {
kind |= UTF8_HAS_16BIT;
if (c > 0xFFFF) {
len++;
kind |= UTF8_HAS_NON_BMP1;
}
}
}
}
}
*plen = len;
return kind;
}
/* Decode a string encoded in UTF-8 into an array of bytes
`src` points to the source string. It is assumed to be correctly encoded
and only contains code points below 0x800
`src_len` is the length of the source string
`dest` points to the destination array, it can be null if `dest_len` is `0`
`dest_len` is the length of the destination array. A null
terminator is stored at the end of the array unless `dest_len` is `0`.
*/
size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len)
{
const uint8_t *p, *p_end;
size_t i;
p = (const uint8_t *)src;
p_end = p + src_len;
for (i = 0; p < p_end; i++) {
uint32_t c = *p++;
if (c >= 0xC0)
c = (c << 6) + *p++ - ((0xC0 << 6) + 0x80);
if (i < dest_len)
dest[i] = c;
}
if (i < dest_len)
dest[i] = '\0';
else if (dest_len > 0)
dest[dest_len - 1] = '\0';
return i;
}
/* Decode a string encoded in UTF-8 into an array of 16-bit words
`src` points to the source string. It is assumed to be correctly encoded.
`src_len` is the length of the source string
`dest` points to the destination array, it can be null if `dest_len` is `0`
`dest_len` is the length of the destination array. No null terminator is
stored at the end of the array.
*/
size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len)
{
const uint8_t *p, *p_end;
size_t i;
p = (const uint8_t *)src;
p_end = p + src_len;
for (i = 0; p < p_end; i++) {
uint32_t c = *p++;
if (c >= 0x80) {
/* parse utf-8 sequence */
c = utf8_decode_len(p - 1, p_end - (p - 1), &p);
/* encoding errors are converted as 0xFFFD and use a single byte */
if (c > 0xFFFF) {
if (i < dest_len)
dest[i] = get_hi_surrogate(c);
i++;
c = get_lo_surrogate(c);
}
}
if (i < dest_len)
dest[i] = c;
}
return i;
}
/* Encode a buffer of 8-bit bytes as a UTF-8 encoded string
`src` points to the source buffer.
`src_len` is the length of the source buffer
`dest` points to the destination array, it can be null if `dest_len` is `0`
`dest_len` is the length in bytes of the destination array. A null
terminator is stored at the end of the array unless `dest_len` is `0`.
*/
size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len)
{
size_t i, j;
uint32_t c;
for (i = j = 0; i < src_len; i++) {
c = src[i];
if (c < 0x80) {
if (j + 1 >= dest_len)
goto overflow;
dest[j++] = c;
} else {
if (j + 2 >= dest_len)
goto overflow;
dest[j++] = (c >> 6) | 0xC0;
dest[j++] = (c & 0x3F) | 0x80;
}
}
if (j < dest_len)
dest[j] = '\0';
return j;
overflow:
if (j < dest_len)
dest[j] = '\0';
while (i < src_len)
j += 1 + (src[i++] >= 0x80);
return j;
}
/* Encode a buffer of 16-bit code points as a UTF-8 encoded string
`src` points to the source buffer.
`src_len` is the length of the source buffer
`dest` points to the destination array, it can be null if `dest_len` is `0`
`dest_len` is the length in bytes of the destination array. A null
terminator is stored at the end of the array unless `dest_len` is `0`.
*/
size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len)
{
size_t i, j;
uint32_t c;
for (i = j = 0; i < src_len;) {
c = src[i++];
if (c < 0x80) {
if (j + 1 >= dest_len)
goto overflow;
dest[j++] = c;
} else {
if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i]))
c = from_surrogate(c, src[i++]);
if (j + utf8_encode_len(c) >= dest_len)
goto overflow;
j += utf8_encode((uint8_t *)dest + j, c);
}
}
if (j < dest_len)
dest[j] = '\0';
return j;
overflow:
i -= 1 + (c > 0xFFFF);
if (j < dest_len)
dest[j] = '\0';
while (i < src_len) {
c = src[i++];
if (c < 0x80) {
j++;
} else {
if (is_hi_surrogate(c) && i < src_len && is_lo_surrogate(src[i]))
c = from_surrogate(c, src[i++]);
j += utf8_encode_len(c);
}
}
return j;
}
/*--- integer to string conversions --*/
/* All conversion functions:
- require a destination array `buf` of sufficient length
- write the string representation at the beginning of `buf`
- null terminate the string
- return the string length
*/
/* 2 <= base <= 36 */
char const digits36[36] = "0123456789abcdefghijklmnopqrstuvwxyz";
#define USE_SPECIAL_RADIX_10 1 // special case base 10 radix conversions
#define USE_SINGLE_CASE_FAST 1 // special case single digit numbers
/* using u32toa_shift variant */
#define gen_digit(buf, c) if (is_be()) \
buf = (buf >> 8) | ((uint64_t)(c) << ((sizeof(buf) - 1) * 8)); \
else \
buf = (buf << 8) | (c)
size_t u7toa_shift(char dest[minimum_length(8)], uint32_t n)
{
size_t len = 1;
uint64_t buf = 0;
while (n >= 10) {
uint32_t quo = n % 10;
n /= 10;
gen_digit(buf, '0' + quo);
len++;
}
gen_digit(buf, '0' + n);
memcpy(dest, &buf, sizeof buf);
return len;
}
size_t u07toa_shift(char dest[minimum_length(8)], uint32_t n, size_t len)
{
size_t i;
dest += len;
dest[7] = '\0';
for (i = 7; i-- > 1;) {
uint32_t quo = n % 10;
n /= 10;
dest[i] = (char)('0' + quo);
}
dest[i] = (char)('0' + n);
return len + 7;
}
size_t u32toa(char buf[minimum_length(11)], uint32_t n)
{
#ifdef USE_SINGLE_CASE_FAST /* 10% */
if (n < 10) {
buf[0] = (char)('0' + n);
buf[1] = '\0';
return 1;
}
#endif
#define TEN_POW_7 10000000
if (n >= TEN_POW_7) {
uint32_t quo = n / TEN_POW_7;
n %= TEN_POW_7;
size_t len = u7toa_shift(buf, quo);
return u07toa_shift(buf, n, len);
}
return u7toa_shift(buf, n);
}
size_t u64toa(char buf[minimum_length(21)], uint64_t n)
{
if (likely(n < 0x100000000))
return u32toa(buf, n);
size_t len;
if (n >= TEN_POW_7) {
uint64_t n1 = n / TEN_POW_7;
n %= TEN_POW_7;
if (n1 >= TEN_POW_7) {
uint32_t quo = n1 / TEN_POW_7;
n1 %= TEN_POW_7;
len = u7toa_shift(buf, quo);
len = u07toa_shift(buf, n1, len);
} else {
len = u7toa_shift(buf, n1);
}
return u07toa_shift(buf, n, len);
}
return u7toa_shift(buf, n);
}
size_t i32toa(char buf[minimum_length(12)], int32_t n)
{
if (likely(n >= 0))
return u32toa(buf, n);
buf[0] = '-';
return 1 + u32toa(buf + 1, -(uint32_t)n);
}
size_t i64toa(char buf[minimum_length(22)], int64_t n)
{
if (likely(n >= 0))
return u64toa(buf, n);
buf[0] = '-';
return 1 + u64toa(buf + 1, -(uint64_t)n);
}
/* using u32toa_radix_length variant */
static uint8_t const radix_shift[64] = {
0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned base)
{
int shift;
#ifdef USE_SPECIAL_RADIX_10
if (likely(base == 10))
return u32toa(buf, n);
#endif
if (n < base) {
buf[0] = digits36[n];
buf[1] = '\0';
return 1;
}
shift = radix_shift[base & 63];
if (shift) {
uint32_t mask = (1 << shift) - 1;
size_t len = (32 - clz32(n) + shift - 1) / shift;
size_t last = n & mask;
char *end = buf + len;
n >>= shift;
*end-- = '\0';
*end-- = digits36[last];
while (n >= base) {
size_t quo = n & mask;
n >>= shift;
*end-- = digits36[quo];
}
*end = digits36[n];
return len;
} else {
size_t len = 2;
size_t last = n % base;
n /= base;
uint32_t nbase = base;
while (n >= nbase) {
nbase *= base;
len++;
}
char *end = buf + len;
*end-- = '\0';
*end-- = digits36[last];
while (n >= base) {
size_t quo = n % base;
n /= base;
*end-- = digits36[quo];
}
*end = digits36[n];
return len;
}
}
size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned base)
{
int shift;
#ifdef USE_SPECIAL_RADIX_10
if (likely(base == 10))
return u64toa(buf, n);
#endif
shift = radix_shift[base & 63];
if (shift) {
if (n < base) {
buf[0] = digits36[n];
buf[1] = '\0';
return 1;
}
uint64_t mask = (1 << shift) - 1;
size_t len = (64 - clz64(n) + shift - 1) / shift;
size_t last = n & mask;
char *end = buf + len;
n >>= shift;
*end-- = '\0';
*end-- = digits36[last];
while (n >= base) {
size_t quo = n & mask;
n >>= shift;
*end-- = digits36[quo];
}
*end = digits36[n];
return len;
} else {
if (likely(n < 0x100000000))
return u32toa_radix(buf, n, base);
size_t last = n % base;
n /= base;
uint64_t nbase = base;
size_t len = 2;
while (n >= nbase) {
nbase *= base;
len++;
}
char *end = buf + len;
*end-- = '\0';
*end-- = digits36[last];
while (n >= base) {
size_t quo = n % base;
n /= base;
*end-- = digits36[quo];
}
*end = digits36[n];
return len;
}
}
size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned int base)
{
if (likely(n >= 0))
return u32toa_radix(buf, n, base);
buf[0] = '-';
return 1 + u32toa_radix(buf + 1, -(uint32_t)n, base);
}
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base)
{
if (likely(n >= 0))
return u64toa_radix(buf, n, base);
buf[0] = '-';
return 1 + u64toa_radix(buf + 1, -(uint64_t)n, base);
}
#undef gen_digit
#undef TEN_POW_7
#undef USE_SPECIAL_RADIX_10
#undef USE_SINGLE_CASE_FAST
/*---- sorting with opaque argument ----*/
typedef void (*exchange_f)(void *a, void *b, size_t size); typedef void (*exchange_f)(void *a, void *b, size_t size);
typedef int (*cmp_f)(const void *, const void *, void *opaque); typedef int (*cmp_f)(const void *, const void *, void *opaque);
@ -611,6 +1125,8 @@ void rqsort(void *base, size_t nmemb, size_t size, cmp_f cmp, void *opaque)
} }
} }
/*---- Portable time functions ----*/
#if defined(_MSC_VER) #if defined(_MSC_VER)
// From: https://stackoverflow.com/a/26085827 // From: https://stackoverflow.com/a/26085827
static int gettimeofday_msvc(struct timeval *tp, struct timezone *tzp) static int gettimeofday_msvc(struct timeval *tp, struct timezone *tzp)
@ -649,7 +1165,7 @@ uint64_t js__hrtime_ns(void) {
* performance counter interval, integer math could cause this computation * performance counter interval, integer math could cause this computation
* to overflow. Therefore we resort to floating point math. * to overflow. Therefore we resort to floating point math.
*/ */
scaled_freq = (double) frequency.QuadPart / 1e9; scaled_freq = (double) frequency.QuadPart / NANOSEC;
result = (double) counter.QuadPart / scaled_freq; result = (double) counter.QuadPart / scaled_freq;
return (uint64_t) result; return (uint64_t) result;
} }
@ -660,7 +1176,7 @@ uint64_t js__hrtime_ns(void) {
if (clock_gettime(CLOCK_MONOTONIC, &t)) if (clock_gettime(CLOCK_MONOTONIC, &t))
abort(); abort();
return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; return t.tv_sec * NANOSEC + t.tv_nsec;
} }
#endif #endif
@ -674,4 +1190,218 @@ int64_t js__gettimeofday_us(void) {
return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec; return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec;
} }
/*--- Cross-platform threading APIs. ----*/
#if !defined(EMSCRIPTEN) && !defined(__wasi__)
#if defined(_WIN32)
typedef void (*js__once_cb)(void);
typedef struct {
js__once_cb callback;
} js__once_data_t;
static BOOL WINAPI js__once_inner(INIT_ONCE *once, void *param, void **context) {
js__once_data_t *data = param;
data->callback();
return TRUE;
}
void js_once(js_once_t *guard, js__once_cb callback) {
js__once_data_t data = { .callback = callback };
InitOnceExecuteOnce(guard, js__once_inner, (void*) &data, NULL);
}
void js_mutex_init(js_mutex_t *mutex) {
InitializeCriticalSection(mutex);
}
void js_mutex_destroy(js_mutex_t *mutex) {
DeleteCriticalSection(mutex);
}
void js_mutex_lock(js_mutex_t *mutex) {
EnterCriticalSection(mutex);
}
void js_mutex_unlock(js_mutex_t *mutex) {
LeaveCriticalSection(mutex);
}
void js_cond_init(js_cond_t *cond) {
InitializeConditionVariable(cond);
}
void js_cond_destroy(js_cond_t *cond) {
/* nothing to do */
(void) cond;
}
void js_cond_signal(js_cond_t *cond) {
WakeConditionVariable(cond);
}
void js_cond_broadcast(js_cond_t *cond) {
WakeAllConditionVariable(cond);
}
void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) {
if (!SleepConditionVariableCS(cond, mutex, INFINITE))
abort();
}
int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) {
if (SleepConditionVariableCS(cond, mutex, (DWORD)(timeout / 1e6)))
return 0;
if (GetLastError() != ERROR_TIMEOUT)
abort();
return -1;
}
#else /* !defined(_WIN32) */
void js_once(js_once_t *guard, void (*callback)(void)) {
if (pthread_once(guard, callback))
abort();
}
void js_mutex_init(js_mutex_t *mutex) {
if (pthread_mutex_init(mutex, NULL))
abort();
}
void js_mutex_destroy(js_mutex_t *mutex) {
if (pthread_mutex_destroy(mutex))
abort();
}
void js_mutex_lock(js_mutex_t *mutex) {
if (pthread_mutex_lock(mutex))
abort();
}
void js_mutex_unlock(js_mutex_t *mutex) {
if (pthread_mutex_unlock(mutex))
abort();
}
void js_cond_init(js_cond_t *cond) {
#if defined(__APPLE__) && defined(__MACH__)
if (pthread_cond_init(cond, NULL))
abort();
#else
pthread_condattr_t attr;
if (pthread_condattr_init(&attr))
abort();
if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC))
abort();
if (pthread_cond_init(cond, &attr))
abort();
if (pthread_condattr_destroy(&attr))
abort();
#endif
}
void js_cond_destroy(js_cond_t *cond) {
#if defined(__APPLE__) && defined(__MACH__)
/* It has been reported that destroying condition variables that have been
* signalled but not waited on can sometimes result in application crashes.
* See https://codereview.chromium.org/1323293005.
*/
pthread_mutex_t mutex;
struct timespec ts;
int err;
if (pthread_mutex_init(&mutex, NULL))
abort();
if (pthread_mutex_lock(&mutex))
abort();
ts.tv_sec = 0;
ts.tv_nsec = 1;
err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
if (err != 0 && err != ETIMEDOUT)
abort();
if (pthread_mutex_unlock(&mutex))
abort();
if (pthread_mutex_destroy(&mutex))
abort();
#endif /* defined(__APPLE__) && defined(__MACH__) */
if (pthread_cond_destroy(cond))
abort();
}
void js_cond_signal(js_cond_t *cond) {
if (pthread_cond_signal(cond))
abort();
}
void js_cond_broadcast(js_cond_t *cond) {
if (pthread_cond_broadcast(cond))
abort();
}
void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) {
#if defined(__APPLE__) && defined(__MACH__)
int r;
errno = 0;
r = pthread_cond_wait(cond, mutex);
/* Workaround for a bug in OS X at least up to 13.6
* See https://github.com/libuv/libuv/issues/4165
*/
if (r == EINVAL && errno == EBUSY)
return;
if (r)
abort();
#else
if (pthread_cond_wait(cond, mutex))
abort();
#endif
}
int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) {
int r;
struct timespec ts;
#if !defined(__APPLE__)
timeout += js__hrtime_ns();
#endif
ts.tv_sec = timeout / NANOSEC;
ts.tv_nsec = timeout % NANOSEC;
#if defined(__APPLE__) && defined(__MACH__)
r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
#else
r = pthread_cond_timedwait(cond, mutex, &ts);
#endif
if (r == 0)
return 0;
if (r == ETIMEDOUT)
return -1;
abort();
/* Pacify some compilers. */
return -1;
}
#endif
#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */
#pragma GCC visibility pop #pragma GCC visibility pop

256
cutils.h
View file

@ -26,13 +26,13 @@
#define CUTILS_H #define CUTILS_H
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <inttypes.h> #include <inttypes.h>
/* set if CPU is big endian */ #if defined(_WIN32)
#undef WORDS_BIGENDIAN
#if defined(_MSC_VER)
#include <windows.h> #include <windows.h>
#endif
#if defined(_MSC_VER)
#include <winsock2.h> #include <winsock2.h>
#include <malloc.h> #include <malloc.h>
#define alloca _alloca #define alloca _alloca
@ -40,17 +40,57 @@
#endif #endif
#if defined(__APPLE__) #if defined(__APPLE__)
#include <malloc/malloc.h> #include <malloc/malloc.h>
#elif defined(__linux__) || defined(__CYGWIN__) #elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__)
#include <malloc.h> #include <malloc.h>
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
#include <malloc_np.h> #include <malloc_np.h>
#endif #endif
#if !defined(_WIN32)
#include <errno.h>
#include <pthread.h>
#endif
#define likely(x) __builtin_expect(!!(x), 1) #if defined(_MSC_VER) && !defined(__clang__)
#define unlikely(x) __builtin_expect(!!(x), 0) # define likely(x) (x)
#define force_inline inline __attribute__((always_inline)) # define unlikely(x) (x)
#define no_inline __attribute__((noinline)) # define force_inline __forceinline
#define __maybe_unused __attribute__((unused)) # define no_inline __declspec(noinline)
# define __maybe_unused
# define __attribute__(x)
# define __attribute(x)
# include <intrin.h>
static void *__builtin_frame_address(unsigned int level) {
return (void *)((char*)_AddressOfReturnAddress() - sizeof(int *) - level * sizeof(int *));
}
#else
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
# define force_inline inline __attribute__((always_inline))
# define no_inline __attribute__((noinline))
# define __maybe_unused __attribute__((unused))
#endif
// https://stackoverflow.com/a/6849629
#undef FORMAT_STRING
#if _MSC_VER >= 1400
# include <sal.h>
# if _MSC_VER > 1400
# define FORMAT_STRING(p) _Printf_format_string_ p
# else
# define FORMAT_STRING(p) __format_string p
# endif /* FORMAT_STRING */
#else
# define FORMAT_STRING(p) p
#endif /* _MSC_VER */
#if defined(_MSC_VER) && !defined(__clang__)
#include <math.h>
#define INF INFINITY
#define NEG_INF -INFINITY
#else
#define INF (1.0/0.0)
#define NEG_INF (-1.0/0.0)
#endif
#define xglue(x, y) x ## y #define xglue(x, y) x ## y
#define glue(x, y) xglue(x, y) #define glue(x, y) xglue(x, y)
@ -66,6 +106,16 @@
#define endof(x) ((x) + countof(x)) #define endof(x) ((x) + countof(x))
#endif #endif
#endif #endif
#ifndef container_of
/* return the pointer of type 'type *' containing 'ptr' as field 'member' */
#define container_of(ptr, type, member) ((type *)((uint8_t *)(ptr) - offsetof(type, member)))
#endif
#if !defined(_MSC_VER) && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define minimum_length(n) static n
#else
#define minimum_length(n) n
#endif
typedef int BOOL; typedef int BOOL;
@ -81,6 +131,14 @@ char *pstrcat(char *buf, int buf_size, const char *s);
int strstart(const char *str, const char *val, const char **ptr); int strstart(const char *str, const char *val, const char **ptr);
int has_suffix(const char *str, const char *suffix); int has_suffix(const char *str, const char *suffix);
static inline uint8_t is_be(void) {
union {
uint16_t a;
uint8_t b;
} u = { 0x100 };
return u.b;
}
static inline int max_int(int a, int b) static inline int max_int(int a, int b)
{ {
if (a > b) if (a > b)
@ -132,82 +190,113 @@ static inline int64_t min_int64(int64_t a, int64_t b)
/* WARNING: undefined if a = 0 */ /* WARNING: undefined if a = 0 */
static inline int clz32(unsigned int a) static inline int clz32(unsigned int a)
{ {
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long index;
_BitScanReverse(&index, a);
return 31 - index;
#else
return __builtin_clz(a); return __builtin_clz(a);
#endif
} }
/* WARNING: undefined if a = 0 */ /* WARNING: undefined if a = 0 */
static inline int clz64(uint64_t a) static inline int clz64(uint64_t a)
{ {
#if defined(_MSC_VER) && !defined(__clang__)
#if INTPTR_MAX == INT64_MAX
unsigned long index;
_BitScanReverse64(&index, a);
return 63 - index;
#else
if (a >> 32)
return clz32((unsigned)(a >> 32));
else
return clz32((unsigned)a) + 32;
#endif
#else
return __builtin_clzll(a); return __builtin_clzll(a);
#endif
} }
/* WARNING: undefined if a = 0 */ /* WARNING: undefined if a = 0 */
static inline int ctz32(unsigned int a) static inline int ctz32(unsigned int a)
{ {
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long index;
_BitScanForward(&index, a);
return index;
#else
return __builtin_ctz(a); return __builtin_ctz(a);
#endif
} }
/* WARNING: undefined if a = 0 */ /* WARNING: undefined if a = 0 */
static inline int ctz64(uint64_t a) static inline int ctz64(uint64_t a)
{ {
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long index;
_BitScanForward64(&index, a);
return index;
#else
return __builtin_ctzll(a); return __builtin_ctzll(a);
#endif
} }
struct __attribute__((packed)) packed_u64 {
uint64_t v;
};
struct __attribute__((packed)) packed_u32 {
uint32_t v;
};
struct __attribute__((packed)) packed_u16 {
uint16_t v;
};
static inline uint64_t get_u64(const uint8_t *tab) static inline uint64_t get_u64(const uint8_t *tab)
{ {
return ((const struct packed_u64 *)tab)->v; uint64_t v;
memcpy(&v, tab, sizeof(v));
return v;
} }
static inline int64_t get_i64(const uint8_t *tab) static inline int64_t get_i64(const uint8_t *tab)
{ {
return (int64_t)((const struct packed_u64 *)tab)->v; int64_t v;
memcpy(&v, tab, sizeof(v));
return v;
} }
static inline void put_u64(uint8_t *tab, uint64_t val) static inline void put_u64(uint8_t *tab, uint64_t val)
{ {
((struct packed_u64 *)tab)->v = val; memcpy(tab, &val, sizeof(val));
} }
static inline uint32_t get_u32(const uint8_t *tab) static inline uint32_t get_u32(const uint8_t *tab)
{ {
return ((const struct packed_u32 *)tab)->v; uint32_t v;
memcpy(&v, tab, sizeof(v));
return v;
} }
static inline int32_t get_i32(const uint8_t *tab) static inline int32_t get_i32(const uint8_t *tab)
{ {
return (int32_t)((const struct packed_u32 *)tab)->v; int32_t v;
memcpy(&v, tab, sizeof(v));
return v;
} }
static inline void put_u32(uint8_t *tab, uint32_t val) static inline void put_u32(uint8_t *tab, uint32_t val)
{ {
((struct packed_u32 *)tab)->v = val; memcpy(tab, &val, sizeof(val));
} }
static inline uint32_t get_u16(const uint8_t *tab) static inline uint32_t get_u16(const uint8_t *tab)
{ {
return ((const struct packed_u16 *)tab)->v; uint16_t v;
memcpy(&v, tab, sizeof(v));
return v;
} }
static inline int32_t get_i16(const uint8_t *tab) static inline int32_t get_i16(const uint8_t *tab)
{ {
return (int16_t)((const struct packed_u16 *)tab)->v; int16_t v;
memcpy(&v, tab, sizeof(v));
return v;
} }
static inline void put_u16(uint8_t *tab, uint16_t val) static inline void put_u16(uint8_t *tab, uint16_t val)
{ {
((struct packed_u16 *)tab)->v = val; memcpy(tab, &val, sizeof(val));
} }
static inline uint32_t get_u8(const uint8_t *tab) static inline uint32_t get_u8(const uint8_t *tab)
@ -225,17 +314,22 @@ static inline void put_u8(uint8_t *tab, uint8_t val)
*tab = val; *tab = val;
} }
#ifndef bswap16
static inline uint16_t bswap16(uint16_t x) static inline uint16_t bswap16(uint16_t x)
{ {
return (x >> 8) | (x << 8); return (x >> 8) | (x << 8);
} }
#endif
#ifndef bswap32
static inline uint32_t bswap32(uint32_t v) static inline uint32_t bswap32(uint32_t v)
{ {
return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) | return ((v & 0xff000000) >> 24) | ((v & 0x00ff0000) >> 8) |
((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24); ((v & 0x0000ff00) << 8) | ((v & 0x000000ff) << 24);
} }
#endif
#ifndef bswap64
static inline uint64_t bswap64(uint64_t v) static inline uint64_t bswap64(uint64_t v)
{ {
return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) | return ((v & ((uint64_t)0xff << (7 * 8))) >> (7 * 8)) |
@ -247,6 +341,7 @@ static inline uint64_t bswap64(uint64_t v)
((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) | ((v & ((uint64_t)0xff << (1 * 8))) << (5 * 8)) |
((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8)); ((v & ((uint64_t)0xff << (0 * 8))) << (7 * 8));
} }
#endif
static inline void inplace_bswap16(uint8_t *tab) { static inline void inplace_bswap16(uint8_t *tab) {
put_u16(tab, bswap16(get_u16(tab))); put_u16(tab, bswap16(get_u16(tab)));
@ -271,8 +366,8 @@ typedef struct DynBuf {
void dbuf_init(DynBuf *s); void dbuf_init(DynBuf *s);
void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func); void dbuf_init2(DynBuf *s, void *opaque, DynBufReallocFunc *realloc_func);
int dbuf_realloc(DynBuf *s, size_t new_size); int dbuf_realloc(DynBuf *s, size_t new_size);
int dbuf_write(DynBuf *s, size_t offset, const uint8_t *data, size_t len); int dbuf_write(DynBuf *s, size_t offset, const void *data, size_t len);
int dbuf_put(DynBuf *s, const uint8_t *data, size_t len); int dbuf_put(DynBuf *s, const void *data, size_t len);
int dbuf_put_self(DynBuf *s, size_t offset, size_t len); int dbuf_put_self(DynBuf *s, size_t offset, size_t len);
int dbuf_putc(DynBuf *s, uint8_t c); int dbuf_putc(DynBuf *s, uint8_t c);
int dbuf_putstr(DynBuf *s, const char *str); int dbuf_putstr(DynBuf *s, const char *str);
@ -289,7 +384,7 @@ static inline int dbuf_put_u64(DynBuf *s, uint64_t val)
return dbuf_put(s, (uint8_t *)&val, 8); return dbuf_put(s, (uint8_t *)&val, 8);
} }
int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s, int __attribute__((format(printf, 2, 3))) dbuf_printf(DynBuf *s,
const char *fmt, ...); FORMAT_STRING(const char *fmt), ...);
void dbuf_free(DynBuf *s); void dbuf_free(DynBuf *s);
static inline BOOL dbuf_error(DynBuf *s) { static inline BOOL dbuf_error(DynBuf *s) {
return s->error; return s->error;
@ -299,19 +394,50 @@ static inline void dbuf_set_error(DynBuf *s)
s->error = TRUE; s->error = TRUE;
} }
#define UTF8_CHAR_LEN_MAX 6 /*---- UTF-8 and UTF-16 handling ----*/
int unicode_to_utf8(uint8_t *buf, unsigned int c); #define UTF8_CHAR_LEN_MAX 4
int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp);
enum {
UTF8_PLAIN_ASCII = 0, // 7-bit ASCII plain text
UTF8_NON_ASCII = 1, // has non ASCII code points (8-bit or more)
UTF8_HAS_16BIT = 2, // has 16-bit code points
UTF8_HAS_NON_BMP1 = 4, // has non-BMP1 code points, needs UTF-16 surrogate pairs
UTF8_HAS_ERRORS = 8, // has encoding errors
};
int utf8_scan(const char *buf, size_t len, size_t *plen);
size_t utf8_encode_len(uint32_t c);
size_t utf8_encode(uint8_t *buf, uint32_t c);
uint32_t utf8_decode_len(const uint8_t *p, size_t max_len, const uint8_t **pp);
uint32_t utf8_decode(const uint8_t *p, const uint8_t **pp);
size_t utf8_decode_buf8(uint8_t *dest, size_t dest_len, const char *src, size_t src_len);
size_t utf8_decode_buf16(uint16_t *dest, size_t dest_len, const char *src, size_t src_len);
size_t utf8_encode_buf8(char *dest, size_t dest_len, const uint8_t *src, size_t src_len);
size_t utf8_encode_buf16(char *dest, size_t dest_len, const uint16_t *src, size_t src_len);
static inline BOOL is_surrogate(uint32_t c)
{
return (c >> 11) == (0xD800 >> 11); // 0xD800-0xDFFF
}
static inline BOOL is_hi_surrogate(uint32_t c) static inline BOOL is_hi_surrogate(uint32_t c)
{ {
return 54 == (c >> 10); // 0xD800-0xDBFF return (c >> 10) == (0xD800 >> 10); // 0xD800-0xDBFF
} }
static inline BOOL is_lo_surrogate(uint32_t c) static inline BOOL is_lo_surrogate(uint32_t c)
{ {
return 55 == (c >> 10); // 0xDC00-0xDFFF return (c >> 10) == (0xDC00 >> 10); // 0xDC00-0xDFFF
}
static inline uint32_t get_hi_surrogate(uint32_t c)
{
return (c >> 10) - (0x10000 >> 10) + 0xD800;
}
static inline uint32_t get_lo_surrogate(uint32_t c)
{
return (c & 0x3FF) | 0xDC00;
} }
static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo) static inline uint32_t from_surrogate(uint32_t hi, uint32_t lo)
@ -331,6 +457,24 @@ static inline int from_hex(int c)
return -1; return -1;
} }
static inline uint8_t is_upper_ascii(uint8_t c) {
return c >= 'A' && c <= 'Z';
}
static inline uint8_t to_upper_ascii(uint8_t c) {
return c >= 'a' && c <= 'z' ? c - 'a' + 'A' : c;
}
extern char const digits36[36];
size_t u32toa(char buf[minimum_length(11)], uint32_t n);
size_t i32toa(char buf[minimum_length(12)], int32_t n);
size_t u64toa(char buf[minimum_length(21)], uint64_t n);
size_t i64toa(char buf[minimum_length(22)], int64_t n);
size_t u32toa_radix(char buf[minimum_length(33)], uint32_t n, unsigned int base);
size_t i32toa_radix(char buf[minimum_length(34)], int32_t n, unsigned base);
size_t u64toa_radix(char buf[minimum_length(65)], uint64_t n, unsigned int base);
size_t i64toa_radix(char buf[minimum_length(66)], int64_t n, unsigned int base);
void rqsort(void *base, size_t nmemb, size_t size, void rqsort(void *base, size_t nmemb, size_t size,
int (*cmp)(const void *, const void *, void *), int (*cmp)(const void *, const void *, void *),
void *arg); void *arg);
@ -344,11 +488,43 @@ static inline size_t js__malloc_usable_size(const void *ptr)
return malloc_size(ptr); return malloc_size(ptr);
#elif defined(_WIN32) #elif defined(_WIN32)
return _msize((void *)ptr); return _msize((void *)ptr);
#elif defined(__linux__) || defined(__FreeBSD__) #elif defined(__linux__) || defined(__ANDROID__) || defined(__CYGWIN__) || defined(__FreeBSD__)
return malloc_usable_size((void *)ptr); return malloc_usable_size((void *)ptr);
#else #else
return 0; return 0;
#endif #endif
} }
/* Cross-platform threading APIs. */
#if !defined(EMSCRIPTEN) && !defined(__wasi__)
#if defined(_WIN32)
#define JS_ONCE_INIT INIT_ONCE_STATIC_INIT
typedef INIT_ONCE js_once_t;
typedef CRITICAL_SECTION js_mutex_t;
typedef CONDITION_VARIABLE js_cond_t;
#else
#define JS_ONCE_INIT PTHREAD_ONCE_INIT
typedef pthread_once_t js_once_t;
typedef pthread_mutex_t js_mutex_t;
typedef pthread_cond_t js_cond_t;
#endif
void js_once(js_once_t *guard, void (*callback)(void));
void js_mutex_init(js_mutex_t *mutex);
void js_mutex_destroy(js_mutex_t *mutex);
void js_mutex_lock(js_mutex_t *mutex);
void js_mutex_unlock(js_mutex_t *mutex);
void js_cond_init(js_cond_t *cond);
void js_cond_destroy(js_cond_t *cond);
void js_cond_signal(js_cond_t *cond);
void js_cond_broadcast(js_cond_t *cond);
void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex);
int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout);
#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */
#endif /* CUTILS_H */ #endif /* CUTILS_H */

View file

@ -330,6 +330,11 @@ optional properties:
@item backtrace_barrier @item backtrace_barrier
Boolean (default = false). If true, error backtraces do not list the Boolean (default = false). If true, error backtraces do not list the
stack frames below the evalScript. stack frames below the evalScript.
@item async
Boolean (default = false). If true, @code{await} is accepted in the
script and a promise is returned. The promise is resolved with an
object whose @code{value} property holds the value returned by the
script.
@end table @end table
@item loadScript(filename) @item loadScript(filename)
@ -717,6 +722,12 @@ write_fd]} or null in case of error.
@item sleep(delay_ms) @item sleep(delay_ms)
Sleep during @code{delay_ms} milliseconds. Sleep during @code{delay_ms} milliseconds.
@item sleepAsync(delay_ms)
Asynchronouse sleep during @code{delay_ms} milliseconds. Returns a promise. Example:
@example
await os.sleepAsync(500);
@end example
@item setTimeout(func, delay) @item setTimeout(func, delay)
Call the function @code{func} after @code{delay} ms. Return a handle Call the function @code{func} after @code{delay} ms. Return a handle
to the timer. to the timer.

View file

@ -35,8 +35,8 @@ static int fib(int n)
return fib(n - 1) + fib(n - 2); return fib(n - 1) + fib(n - 2);
} }
static JSValue js_fib(JSContext *ctx, JSValueConst this_val, static JSValue js_fib(JSContext *ctx, JSValue this_val,
int argc, JSValueConst *argv) int argc, JSValue *argv)
{ {
int n, res; int n, res;
if (JS_ToInt32(ctx, &n, argv[0])) if (JS_ToInt32(ctx, &n, argv[0]))

View file

@ -43,8 +43,8 @@ static void js_point_finalizer(JSRuntime *rt, JSValue val)
} }
static JSValue js_point_ctor(JSContext *ctx, static JSValue js_point_ctor(JSContext *ctx,
JSValueConst new_target, JSValue new_target,
int argc, JSValueConst *argv) int argc, JSValue *argv)
{ {
JSPointData *s; JSPointData *s;
JSValue obj = JS_UNDEFINED; JSValue obj = JS_UNDEFINED;
@ -74,7 +74,7 @@ static JSValue js_point_ctor(JSContext *ctx,
return JS_EXCEPTION; return JS_EXCEPTION;
} }
static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic) static JSValue js_point_get_xy(JSContext *ctx, JSValue this_val, int magic)
{ {
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
if (!s) if (!s)
@ -85,7 +85,7 @@ static JSValue js_point_get_xy(JSContext *ctx, JSValueConst this_val, int magic)
return JS_NewInt32(ctx, s->y); return JS_NewInt32(ctx, s->y);
} }
static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue val, int magic) static JSValue js_point_set_xy(JSContext *ctx, JSValue this_val, JSValue val, int magic)
{ {
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
int v; int v;
@ -100,8 +100,8 @@ static JSValue js_point_set_xy(JSContext *ctx, JSValueConst this_val, JSValue va
return JS_UNDEFINED; return JS_UNDEFINED;
} }
static JSValue js_point_norm(JSContext *ctx, JSValueConst this_val, static JSValue js_point_norm(JSContext *ctx, JSValue this_val,
int argc, JSValueConst *argv) int argc, JSValue *argv)
{ {
JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id); JSPointData *s = JS_GetOpaque2(ctx, this_val, js_point_class_id);
if (!s) if (!s)

82
gen/function_source.c Normal file
View file

@ -0,0 +1,82 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_function_source_size = 384;
const uint8_t qjsc_function_source[384] = {
0x0c, 0x06, 0x0c, 0x61, 0x63, 0x74, 0x75, 0x61,
0x6c, 0x02, 0x66, 0x30, 0x74, 0x65, 0x73, 0x74,
0x73, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69,
0x6f, 0x6e, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x2e, 0x6a, 0x73, 0x0c, 0x65, 0x78, 0x70,
0x65, 0x63, 0x74, 0x14, 0x75, 0x73, 0x65, 0x20,
0x73, 0x74, 0x72, 0x69, 0x63, 0x74, 0x34, 0x66,
0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20,
0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, 0x32, 0x20,
0x7d, 0x0c, 0x00, 0xfa, 0x01, 0x9e, 0x01, 0x00,
0x06, 0x00, 0x03, 0x00, 0x01, 0xa0, 0x01, 0x06,
0xa0, 0x01, 0x00, 0x00, 0x00, 0xb2, 0x03, 0x02,
0x00, 0x30, 0xb4, 0x03, 0x04, 0x00, 0x70, 0xb2,
0x03, 0x04, 0x03, 0x70, 0x10, 0x00, 0x01, 0x00,
0xe0, 0x01, 0x00, 0x01, 0x00, 0x0c, 0x43, 0xfa,
0x01, 0xb4, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x03, 0x00, 0xbb, 0x2a, 0x28, 0xb6, 0x03,
0x03, 0x01, 0x04, 0x02, 0x1e, 0x0c, 0x0e, 0x1a,
0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x66, 0x28, 0x29, 0x20, 0x7b, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x34, 0x32,
0x20, 0x7d, 0x0c, 0x03, 0xc1, 0x05, 0x08, 0xc1,
0x04, 0x3f, 0xdc, 0x00, 0x00, 0x00, 0x80, 0x3f,
0xda, 0x00, 0x00, 0x00, 0x40, 0x3e, 0xdc, 0x00,
0x00, 0x00, 0x80, 0xbe, 0x00, 0x40, 0xda, 0x00,
0x00, 0x00, 0x00, 0x04, 0xdd, 0x00, 0x00, 0x00,
0xc8, 0x04, 0xde, 0x00, 0x00, 0x00, 0x3a, 0xdc,
0x00, 0x00, 0x00, 0x61, 0x01, 0x00, 0x38, 0xda,
0x00, 0x00, 0x00, 0x42, 0x36, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0xc9, 0x06, 0xc8, 0x62, 0x01,
0x00, 0x38, 0xdc, 0x00, 0x00, 0x00, 0xaf, 0xe9,
0x0b, 0x38, 0x92, 0x00, 0x00, 0x00, 0x62, 0x01,
0x00, 0xee, 0x2f, 0x61, 0x03, 0x00, 0x61, 0x02,
0x00, 0x38, 0x39, 0x00, 0x00, 0x00, 0x38, 0xdc,
0x00, 0x00, 0x00, 0x04, 0xda, 0x00, 0x00, 0x00,
0x9d, 0x31, 0x01, 0x00, 0x04, 0x00, 0xca, 0x62,
0x02, 0x00, 0x42, 0x36, 0x00, 0x00, 0x00, 0x24,
0x00, 0x00, 0xcb, 0x06, 0xc8, 0x62, 0x03, 0x00,
0x38, 0xdc, 0x00, 0x00, 0x00, 0xaf, 0xe9, 0x0b,
0x38, 0x92, 0x00, 0x00, 0x00, 0x62, 0x03, 0x00,
0xee, 0x2f, 0x68, 0x03, 0x00, 0x68, 0x02, 0x00,
0xc4, 0x28, 0xb6, 0x03, 0x01, 0x01, 0x28, 0x60,
0x01, 0x49, 0x02, 0x21, 0x1a, 0x1b, 0x04, 0x1e,
0x1d, 0x12, 0x26, 0x49, 0x1d, 0x0c, 0x06, 0x11,
0x18, 0x2a, 0x1c, 0x37, 0x41, 0x21, 0x1c, 0x34,
0x18, 0x1b, 0x04, 0x26, 0x11, 0x3f, 0x1d, 0x0c,
0x06, 0x11, 0x18, 0x2a, 0x1c, 0x53, 0x41, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
return ctx;
}
int main(int argc, char **argv)
{
JSRuntime *rt;
JSContext *ctx;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_function_source, qjsc_function_source_size, 0);
js_std_loop(ctx);
JS_FreeContext(ctx);
js_std_free_handlers(rt);
JS_FreeRuntime(rt);
return 0;
}

46
gen/hello.c Normal file
View file

@ -0,0 +1,46 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_hello_size = 89;
const uint8_t qjsc_hello[89] = {
0x0c, 0x04, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f,
0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x48,
0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72,
0x6c, 0x64, 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
0x6f, 0x2e, 0x6a, 0x73, 0x0c, 0x00, 0xfa, 0x00,
0x9e, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00,
0x14, 0x01, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x38,
0xd9, 0x00, 0x00, 0x00, 0x42, 0xda, 0x00, 0x00,
0x00, 0x04, 0xdb, 0x00, 0x00, 0x00, 0x24, 0x01,
0x00, 0xcc, 0x28, 0xb8, 0x03, 0x01, 0x01, 0x00,
0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
return ctx;
}
int main(int argc, char **argv)
{
JSRuntime *rt;
JSContext *ctx;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);
js_std_loop(ctx);
JS_FreeContext(ctx);
js_std_free_handlers(rt);
JS_FreeRuntime(rt);
return 0;
}

102
gen/hello_module.c Normal file
View file

@ -0,0 +1,102 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_fib_module_size = 311;
const uint8_t qjsc_fib_module[311] = {
0x0c, 0x03, 0x2c, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x66, 0x69, 0x62, 0x5f,
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x6a,
0x73, 0x06, 0x66, 0x69, 0x62, 0x02, 0x6e, 0x0d,
0xb2, 0x03, 0x00, 0x01, 0x00, 0x00, 0xb4, 0x03,
0x00, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e,
0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09,
0x00, 0xb4, 0x03, 0x00, 0x01, 0x0c, 0x43, 0xfa,
0x01, 0xb4, 0x03, 0x01, 0x00, 0x01, 0x04, 0x01,
0x00, 0x1a, 0x01, 0xb6, 0x03, 0x00, 0x01, 0x00,
0xb4, 0x03, 0x00, 0x00, 0xd0, 0xb3, 0xa7, 0xe9,
0x03, 0xb3, 0x28, 0xd0, 0xb4, 0xac, 0xe9, 0x03,
0xb4, 0x28, 0xdc, 0xd0, 0xb4, 0x9e, 0xee, 0xdc,
0xd0, 0xb5, 0x9e, 0xee, 0x9d, 0x28, 0xb2, 0x03,
0x02, 0x08, 0x20, 0x04, 0x00, 0x07, 0x06, 0x07,
0x06, 0x12, 0x09, 0x08, 0x07, 0x07, 0x10, 0x07,
0x06, 0x07, 0x06, 0x12, 0x13, 0x08, 0x07, 0x08,
0x16, 0x0c, 0x0c, 0x07, 0x04, 0x0c, 0x0a, 0x0c,
0x0c, 0x07, 0x04, 0x8d, 0x01, 0x66, 0x75, 0x6e,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x66, 0x69,
0x62, 0x28, 0x6e, 0x29, 0x0a, 0x7b, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e,
0x20, 0x3c, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72,
0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x30, 0x3b,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73,
0x65, 0x20, 0x69, 0x66, 0x20, 0x28, 0x6e, 0x20,
0x3d, 0x3d, 0x20, 0x31, 0x29, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65,
0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x3b, 0x0a,
0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65,
0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20,
0x66, 0x69, 0x62, 0x28, 0x6e, 0x20, 0x2d, 0x20,
0x31, 0x29, 0x20, 0x2b, 0x20, 0x66, 0x69, 0x62,
0x28, 0x6e, 0x20, 0x2d, 0x20, 0x32, 0x29, 0x3b,
0x0a, 0x7d, 0x08, 0xe9, 0x05, 0xbe, 0x00, 0xe0,
0x29, 0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x06,
0x01, 0x01, 0x00, 0x07, 0x14, 0x02, 0x00,
};
const uint32_t qjsc_hello_module_size = 178;
const uint8_t qjsc_hello_module[178] = {
0x0c, 0x07, 0x30, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
0x6f, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
0x2e, 0x6a, 0x73, 0x1e, 0x2e, 0x2f, 0x66, 0x69,
0x62, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
0x2e, 0x6a, 0x73, 0x06, 0x66, 0x69, 0x62, 0x0e,
0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x06,
0x6c, 0x6f, 0x67, 0x16, 0x48, 0x65, 0x6c, 0x6c,
0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x10,
0x66, 0x69, 0x62, 0x28, 0x31, 0x30, 0x29, 0x3d,
0x0d, 0xb2, 0x03, 0x01, 0xb4, 0x03, 0x00, 0x00,
0x01, 0x00, 0xb6, 0x03, 0x00, 0x00, 0x0c, 0x20,
0xfa, 0x01, 0x9e, 0x01, 0x00, 0x00, 0x00, 0x05,
0x01, 0x00, 0x32, 0x00, 0xb6, 0x03, 0x00, 0x0c,
0x08, 0xe9, 0x02, 0x29, 0x38, 0xdc, 0x00, 0x00,
0x00, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xde,
0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x0e, 0x38,
0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd, 0x00, 0x00,
0x00, 0x04, 0xdf, 0x00, 0x00, 0x00, 0x65, 0x00,
0x00, 0xbb, 0x0a, 0xee, 0x24, 0x02, 0x00, 0x0e,
0x06, 0x2e, 0xb2, 0x03, 0x01, 0x01, 0x0a, 0x01,
0x01, 0x00, 0x04, 0x0a, 0x02, 0x62, 0x00, 0x4d,
0x30, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
js_std_eval_binary(ctx, qjsc_fib_module, qjsc_fib_module_size, 1);
return ctx;
}
int main(int argc, char **argv)
{
JSRuntime *rt;
JSContext *ctx;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_hello_module, qjsc_hello_module_size, 0);
js_std_loop(ctx);
JS_FreeContext(ctx);
js_std_free_handlers(rt);
JS_FreeRuntime(rt);
return 0;
}

2847
gen/repl.c Normal file

File diff suppressed because it is too large Load diff

59
gen/test_fib.c Normal file
View file

@ -0,0 +1,59 @@
/* File generated automatically by the QuickJS-ng compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_test_fib_size = 167;
const uint8_t qjsc_test_fib[167] = {
0x0c, 0x07, 0x28, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
0x5f, 0x66, 0x69, 0x62, 0x2e, 0x6a, 0x73, 0x10,
0x2e, 0x2f, 0x66, 0x69, 0x62, 0x2e, 0x73, 0x6f,
0x06, 0x66, 0x69, 0x62, 0x0e, 0x63, 0x6f, 0x6e,
0x73, 0x6f, 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67,
0x16, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57,
0x6f, 0x72, 0x6c, 0x64, 0x10, 0x66, 0x69, 0x62,
0x28, 0x31, 0x30, 0x29, 0x3d, 0x0d, 0xb2, 0x03,
0x01, 0xb4, 0x03, 0x00, 0x00, 0x01, 0x00, 0xb6,
0x03, 0x00, 0x00, 0x0c, 0x20, 0xfa, 0x01, 0x9e,
0x01, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x32,
0x00, 0xb6, 0x03, 0x00, 0x0c, 0x08, 0xe9, 0x02,
0x29, 0x38, 0xdc, 0x00, 0x00, 0x00, 0x42, 0xdd,
0x00, 0x00, 0x00, 0x04, 0xde, 0x00, 0x00, 0x00,
0x24, 0x01, 0x00, 0x0e, 0x38, 0xdc, 0x00, 0x00,
0x00, 0x42, 0xdd, 0x00, 0x00, 0x00, 0x04, 0xdf,
0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0xbb, 0x0a,
0xee, 0x24, 0x02, 0x00, 0x0e, 0x06, 0x2e, 0xb2,
0x03, 0x01, 0x01, 0x0a, 0x01, 0x01, 0x00, 0x04,
0x0a, 0x02, 0x62, 0x00, 0x4d, 0x30, 0x00,
};
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
{
extern JSModuleDef *js_init_module_fib(JSContext *ctx, const char *name);
js_init_module_fib(ctx, "examples/fib.so");
}
return ctx;
}
int main(int argc, char **argv)
{
JSRuntime *rt;
JSContext *ctx;
rt = JS_NewRuntime();
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
ctx = JS_NewCustomContext(rt);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_test_fib, qjsc_test_fib_size, 0);
js_std_loop(ctx);
JS_FreeContext(ctx);
js_std_free_handlers(rt);
JS_FreeRuntime(rt);
return 0;
}

View file

@ -63,13 +63,15 @@ typedef enum {
#define TMP_BUF_SIZE 128 #define TMP_BUF_SIZE 128
// invariant: is_unicode ^ unicode_sets (or neither, but not both)
typedef struct { typedef struct {
DynBuf byte_code; DynBuf byte_code;
const uint8_t *buf_ptr; const uint8_t *buf_ptr;
const uint8_t *buf_end; const uint8_t *buf_end;
const uint8_t *buf_start; const uint8_t *buf_start;
int re_flags; int re_flags;
BOOL is_utf16; BOOL is_unicode;
BOOL unicode_sets;
BOOL ignore_case; BOOL ignore_case;
BOOL dotall; BOOL dotall;
int capture_count; int capture_count;
@ -101,10 +103,11 @@ static const REOpCode reopcode_info[REOP_COUNT] = {
}; };
#define RE_HEADER_FLAGS 0 #define RE_HEADER_FLAGS 0
#define RE_HEADER_CAPTURE_COUNT 1 #define RE_HEADER_CAPTURE_COUNT 2
#define RE_HEADER_STACK_SIZE 2 #define RE_HEADER_STACK_SIZE 3
#define RE_HEADER_BYTECODE_LEN 4
#define RE_HEADER_LEN 7 #define RE_HEADER_LEN 8
static inline int is_digit(int c) { static inline int is_digit(int c) {
return c >= '0' && c <= '9'; return c >= '0' && c <= '9';
@ -121,11 +124,11 @@ static int dbuf_insert(DynBuf *s, int pos, int len)
} }
/* canonicalize with the specific JS regexp rules */ /* canonicalize with the specific JS regexp rules */
static uint32_t lre_canonicalize(uint32_t c, BOOL is_utf16) static uint32_t lre_canonicalize(uint32_t c, BOOL is_unicode)
{ {
uint32_t res[LRE_CC_RES_LEN_MAX]; uint32_t res[LRE_CC_RES_LEN_MAX];
int len; int len;
if (is_utf16) { if (is_unicode) {
if (likely(c < 128)) { if (likely(c < 128)) {
if (c >= 'A' && c <= 'Z') if (c >= 'A' && c <= 'Z')
c = c - 'A' + 'a'; c = c - 'A' + 'a';
@ -279,16 +282,16 @@ static __maybe_unused void lre_dump_bytecode(const uint8_t *buf,
assert(buf_len >= RE_HEADER_LEN); assert(buf_len >= RE_HEADER_LEN);
re_flags= buf[0]; re_flags = lre_get_flags(buf);
bc_len = get_u32(buf + 3); bc_len = get_u32(buf + RE_HEADER_BYTECODE_LEN);
assert(bc_len + RE_HEADER_LEN <= buf_len); assert(bc_len + RE_HEADER_LEN <= buf_len);
printf("flags: 0x%x capture_count=%d stack_size=%d\n", printf("flags: 0x%x capture_count=%d stack_size=%d\n",
re_flags, buf[1], buf[2]); re_flags, buf[RE_HEADER_CAPTURE_COUNT], buf[RE_HEADER_STACK_SIZE]);
if (re_flags & LRE_FLAG_NAMED_GROUPS) { if (re_flags & LRE_FLAG_NAMED_GROUPS) {
const char *p; const char *p;
p = (char *)buf + RE_HEADER_LEN + bc_len; p = (char *)buf + RE_HEADER_LEN + bc_len;
printf("named groups: "); printf("named groups: ");
for(i = 1; i < buf[1]; i++) { for(i = 1; i < buf[RE_HEADER_CAPTURE_COUNT]; i++) {
if (i != 1) if (i != 1)
printf(","); printf(",");
printf("<%s>", p); printf("<%s>", p);
@ -709,7 +712,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr,
static int get_class_atom(REParseState *s, CharRange *cr, static int get_class_atom(REParseState *s, CharRange *cr,
const uint8_t **pp, BOOL inclass) const uint8_t **pp, BOOL inclass)
{ {
const uint8_t *p; const uint8_t *p, *p_next;
uint32_t c; uint32_t c;
int ret; int ret;
@ -750,10 +753,10 @@ static int get_class_atom(REParseState *s, CharRange *cr,
if ((c >= 'a' && c <= 'z') || if ((c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') || (c >= 'A' && c <= 'Z') ||
(((c >= '0' && c <= '9') || c == '_') && (((c >= '0' && c <= '9') || c == '_') &&
inclass && !s->is_utf16)) { /* Annex B.1.4 */ inclass && !s->is_unicode)) { /* Annex B.1.4 */
c &= 0x1f; c &= 0x1f;
p++; p++;
} else if (s->is_utf16) { } else if (s->is_unicode) {
goto invalid_escape; goto invalid_escape;
} else { } else {
/* otherwise return '\' and 'c' */ /* otherwise return '\' and 'c' */
@ -763,7 +766,7 @@ static int get_class_atom(REParseState *s, CharRange *cr,
break; break;
case 'p': case 'p':
case 'P': case 'P':
if (s->is_utf16) { if (s->is_unicode) {
if (parse_unicode_property(s, cr, &p, (c == 'P'))) if (parse_unicode_property(s, cr, &p, (c == 'P')))
return -1; return -1;
c = CLASS_RANGE_BASE; c = CLASS_RANGE_BASE;
@ -772,14 +775,17 @@ static int get_class_atom(REParseState *s, CharRange *cr,
/* fall thru */ /* fall thru */
default: default:
p--; p--;
ret = lre_parse_escape(&p, s->is_utf16 * 2); ret = lre_parse_escape(&p, s->is_unicode * 2);
if (ret >= 0) { if (ret >= 0) {
c = ret; c = ret;
} else { } else {
if (ret == -2 && *p != '\0' && strchr("^$\\.*+?()[]{}|/", *p)) { if (ret == -2 && *p != '\0' && strchr("^$\\.*+?()[]{}|/", *p)) {
/* always valid to escape these characters */ /* always valid to escape these characters */
goto normal_char; goto normal_char;
} else if (s->is_utf16) { } else if (s->is_unicode) {
// special case: allowed inside [] but not outside
if (ret == -2 && *p == '-' && inclass)
goto normal_char;
invalid_escape: invalid_escape:
return re_parse_error(s, "invalid escape sequence in regular expression"); return re_parse_error(s, "invalid escape sequence in regular expression");
} else { } else {
@ -798,15 +804,18 @@ static int get_class_atom(REParseState *s, CharRange *cr,
/* fall thru */ /* fall thru */
default: default:
normal_char: normal_char:
/* normal char */ p++;
if (c >= 128) { if (c >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); c = utf8_decode(p - 1, &p_next);
if ((unsigned)c > 0xffff && !s->is_utf16) { if (p_next == p)
/* XXX: should handle non BMP-1 code points */ return re_parse_error(s, "invalid UTF-8 sequence");
p = p_next;
if (c > 0xFFFF && !s->is_unicode) {
// TODO(chqrlie): should handle non BMP-1 code points in
// the calling function and no require the source string
// to be CESU-8 encoded if not s->is_unicode
return re_parse_error(s, "malformed unicode char"); return re_parse_error(s, "malformed unicode char");
} }
} else {
p++;
} }
break; break;
} }
@ -852,6 +861,8 @@ static int re_emit_range(REParseState *s, const CharRange *cr)
return 0; return 0;
} }
// s->unicode turns patterns like []] into syntax errors
// s->unicode_sets turns more patterns into errors, like [a-] or [[]
static int re_parse_char_class(REParseState *s, const uint8_t **pp) static int re_parse_char_class(REParseState *s, const uint8_t **pp)
{ {
const uint8_t *p; const uint8_t *p;
@ -863,21 +874,47 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
cr_init(cr, s->opaque, lre_realloc); cr_init(cr, s->opaque, lre_realloc);
p = *pp; p = *pp;
p++; /* skip '[' */ p++; /* skip '[' */
if (s->unicode_sets) {
static const char verboten[] =
"()[{}/-|" "\0"
"&&!!##$$%%**++,,..::;;<<==>>??@@``~~" "\0"
"^^^_^^";
const char *s = verboten;
int n = 1;
do {
if (!memcmp(s, p, n))
if (p[n] == ']')
goto invalid_class_range;
s += n;
if (!*s) {
s++;
n++;
}
} while (n < 4);
}
invert = FALSE; invert = FALSE;
if (*p == '^') { if (*p == '^') {
p++; p++;
invert = TRUE; invert = TRUE;
} }
for(;;) { for(;;) {
if (*p == ']') if (*p == ']')
break; break;
c1 = get_class_atom(s, cr1, &p, TRUE); c1 = get_class_atom(s, cr1, &p, TRUE);
if ((int)c1 < 0) if ((int)c1 < 0)
goto fail; goto fail;
if (*p == '-' && p[1] == ']' && s->unicode_sets) {
if (c1 >= CLASS_RANGE_BASE)
cr_free(cr1);
goto invalid_class_range;
}
if (*p == '-' && p[1] != ']') { if (*p == '-' && p[1] != ']') {
const uint8_t *p0 = p + 1; const uint8_t *p0 = p + 1;
if (c1 >= CLASS_RANGE_BASE) { if (c1 >= CLASS_RANGE_BASE) {
if (s->is_utf16) { if (s->is_unicode) {
cr_free(cr1); cr_free(cr1);
goto invalid_class_range; goto invalid_class_range;
} }
@ -889,7 +926,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp)
goto fail; goto fail;
if (c2 >= CLASS_RANGE_BASE) { if (c2 >= CLASS_RANGE_BASE) {
cr_free(cr1); cr_free(cr1);
if (s->is_utf16) { if (s->is_unicode) {
goto invalid_class_range; goto invalid_class_range;
} }
/* Annex B: match '-' character */ /* Annex B: match '-' character */
@ -1071,35 +1108,35 @@ static int re_is_simple_quantifier(const uint8_t *bc_buf, int bc_buf_len)
/* '*pp' is the first char after '<' */ /* '*pp' is the first char after '<' */
static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp) static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
{ {
const uint8_t *p, *p1; const uint8_t *p, *p_next;
uint32_t c, d; uint32_t c, d;
char *q; char *q;
p = *pp; p = *pp;
q = buf; q = buf;
for(;;) { for(;;) {
c = *p; c = *p++;
if (c == '\\') { if (c == '\\') {
p++;
if (*p != 'u') if (*p != 'u')
return -1; return -1;
c = lre_parse_escape(&p, 2); // accept surrogate pairs c = lre_parse_escape(&p, 2); // accept surrogate pairs
if ((int)c < 0)
return -1;
} else if (c == '>') { } else if (c == '>') {
break; break;
} else if (c >= 128) { } else if (c >= 0x80) {
c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p); c = utf8_decode(p - 1, &p_next);
if (p_next == p)
return -1;
p = p_next;
if (is_hi_surrogate(c)) { if (is_hi_surrogate(c)) {
d = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p1); d = utf8_decode(p, &p_next);
if (is_lo_surrogate(d)) { if (is_lo_surrogate(d)) {
c = from_surrogate(c, d); c = from_surrogate(c, d);
p = p1; p = p_next;
} }
} }
} else {
p++;
} }
if (c > 0x10FFFF)
return -1;
if (q == buf) { if (q == buf) {
if (!lre_js_is_ident_first(c)) if (!lre_js_is_ident_first(c))
return -1; return -1;
@ -1109,16 +1146,15 @@ static int re_parse_group_name(char *buf, int buf_size, const uint8_t **pp)
} }
if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size) if ((q - buf + UTF8_CHAR_LEN_MAX + 1) > buf_size)
return -1; return -1;
if (c < 128) { if (c < 0x80) {
*q++ = c; *q++ = c;
} else { } else {
q += unicode_to_utf8((uint8_t*)q, c); q += utf8_encode((uint8_t*)q, c);
} }
} }
if (q == buf) if (q == buf)
return -1; return -1;
*q = '\0'; *q = '\0';
p++;
*pp = p; *pp = p;
return 0; return 0;
} }
@ -1247,7 +1283,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
re_emit_op(s, REOP_prev); re_emit_op(s, REOP_prev);
break; break;
case '{': case '{':
if (s->is_utf16) { if (s->is_unicode) {
return re_parse_error(s, "syntax error"); return re_parse_error(s, "syntax error");
} else if (!is_digit(p[1])) { } else if (!is_digit(p[1])) {
/* Annex B: we accept '{' not followed by digits as a /* Annex B: we accept '{' not followed by digits as a
@ -1299,7 +1335,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
lookahead: lookahead:
/* Annex B allows lookahead to be used as an atom for /* Annex B allows lookahead to be used as an atom for
the quantifiers */ the quantifiers */
if (!s->is_utf16 && !is_backward_lookahead) { if (!s->is_unicode && !is_backward_lookahead) {
last_atom_start = s->byte_code.size; last_atom_start = s->byte_code.size;
last_capture_count = s->capture_count; last_capture_count = s->capture_count;
} }
@ -1375,7 +1411,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
/* annex B: we tolerate invalid group names in non /* annex B: we tolerate invalid group names in non
unicode mode if there is no named capture unicode mode if there is no named capture
definition */ definition */
if (s->is_utf16 || re_has_named_captures(s)) if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "expecting group name"); return re_parse_error(s, "expecting group name");
else else
goto parse_class_atom; goto parse_class_atom;
@ -1383,7 +1419,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
p1 += 3; p1 += 3;
if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf), if (re_parse_group_name(s->u.tmp_buf, sizeof(s->u.tmp_buf),
&p1)) { &p1)) {
if (s->is_utf16 || re_has_named_captures(s)) if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "invalid group name"); return re_parse_error(s, "invalid group name");
else else
goto parse_class_atom; goto parse_class_atom;
@ -1394,7 +1430,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
after (inefficient, but hopefully not common */ after (inefficient, but hopefully not common */
c = re_parse_captures(s, &dummy_res, s->u.tmp_buf); c = re_parse_captures(s, &dummy_res, s->u.tmp_buf);
if (c < 0) { if (c < 0) {
if (s->is_utf16 || re_has_named_captures(s)) if (s->is_unicode || re_has_named_captures(s))
return re_parse_error(s, "group name not defined"); return re_parse_error(s, "group name not defined");
else else
goto parse_class_atom; goto parse_class_atom;
@ -1406,7 +1442,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
case '0': case '0':
p += 2; p += 2;
c = 0; c = 0;
if (s->is_utf16) { if (s->is_unicode) {
if (is_digit(*p)) { if (is_digit(*p)) {
return re_parse_error(s, "invalid decimal escape in regular expression"); return re_parse_error(s, "invalid decimal escape in regular expression");
} }
@ -1428,7 +1464,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
c = parse_digits(&p, FALSE); c = parse_digits(&p, FALSE);
if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) { if (c < 0 || (c >= s->capture_count && c >= re_count_captures(s))) {
if (!s->is_utf16) { if (!s->is_unicode) {
/* Annex B.1.4: accept legacy octal */ /* Annex B.1.4: accept legacy octal */
p = q; p = q;
if (*p <= '7') { if (*p <= '7') {
@ -1470,7 +1506,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
break; break;
case ']': case ']':
case '}': case '}':
if (s->is_utf16) if (s->is_unicode)
return re_parse_error(s, "syntax error"); return re_parse_error(s, "syntax error");
goto parse_class_atom; goto parse_class_atom;
default: default:
@ -1492,7 +1528,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
return -1; return -1;
} else { } else {
if (s->ignore_case) if (s->ignore_case)
c = lre_canonicalize(c, s->is_utf16); c = lre_canonicalize(c, s->is_unicode);
if (c <= 0x7f) if (c <= 0x7f)
re_emit_op_u8(s, REOP_char8, c); re_emit_op_u8(s, REOP_char8, c);
else if (c <= 0xffff) else if (c <= 0xffff)
@ -1530,7 +1566,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
/* As an extension (see ES6 annex B), we accept '{' not /* As an extension (see ES6 annex B), we accept '{' not
followed by digits as a normal atom */ followed by digits as a normal atom */
if (!is_digit(p[1])) { if (!is_digit(p[1])) {
if (s->is_utf16) if (s->is_unicode)
goto invalid_quant_count; goto invalid_quant_count;
break; break;
} }
@ -1549,7 +1585,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
quant_max = INT32_MAX; /* infinity */ quant_max = INT32_MAX; /* infinity */
} }
} }
if (*p != '}' && !s->is_utf16) { if (*p != '}' && !s->is_unicode) {
/* Annex B: normal atom if invalid '{' syntax */ /* Annex B: normal atom if invalid '{' syntax */
p = p1; p = p1;
break; break;
@ -1838,10 +1874,11 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
s->buf_end = s->buf_ptr + buf_len; s->buf_end = s->buf_ptr + buf_len;
s->buf_start = s->buf_ptr; s->buf_start = s->buf_ptr;
s->re_flags = re_flags; s->re_flags = re_flags;
s->is_utf16 = ((re_flags & LRE_FLAG_UTF16) != 0); s->is_unicode = ((re_flags & LRE_FLAG_UNICODE) != 0);
is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0); is_sticky = ((re_flags & LRE_FLAG_STICKY) != 0);
s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0); s->ignore_case = ((re_flags & LRE_FLAG_IGNORECASE) != 0);
s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0); s->dotall = ((re_flags & LRE_FLAG_DOTALL) != 0);
s->unicode_sets = ((re_flags & LRE_FLAG_UNICODE_SETS) != 0);
s->capture_count = 1; s->capture_count = 1;
s->total_capture_count = -1; s->total_capture_count = -1;
s->has_named_captures = -1; s->has_named_captures = -1;
@ -1849,7 +1886,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
dbuf_init2(&s->byte_code, opaque, lre_realloc); dbuf_init2(&s->byte_code, opaque, lre_realloc);
dbuf_init2(&s->group_names, opaque, lre_realloc); dbuf_init2(&s->group_names, opaque, lre_realloc);
dbuf_putc(&s->byte_code, re_flags); /* first element is the flags */ dbuf_put_u16(&s->byte_code, re_flags); /* first element is the flags */
dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */ dbuf_putc(&s->byte_code, 0); /* second element is the number of captures */
dbuf_putc(&s->byte_code, 0); /* stack size */ dbuf_putc(&s->byte_code, 0); /* stack size */
dbuf_put_u32(&s->byte_code, 0); /* bytecode length */ dbuf_put_u32(&s->byte_code, 0); /* bytecode length */
@ -1896,12 +1933,14 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count; s->byte_code.buf[RE_HEADER_CAPTURE_COUNT] = s->capture_count;
s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size; s->byte_code.buf[RE_HEADER_STACK_SIZE] = stack_size;
put_u32(s->byte_code.buf + 3, s->byte_code.size - RE_HEADER_LEN); put_u32(s->byte_code.buf + RE_HEADER_BYTECODE_LEN,
s->byte_code.size - RE_HEADER_LEN);
/* add the named groups if needed */ /* add the named groups if needed */
if (s->group_names.size > (s->capture_count - 1)) { if (s->group_names.size > (s->capture_count - 1)) {
dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size); dbuf_put(&s->byte_code, s->group_names.buf, s->group_names.size);
s->byte_code.buf[RE_HEADER_FLAGS] |= LRE_FLAG_NAMED_GROUPS; put_u16(s->byte_code.buf + RE_HEADER_FLAGS,
LRE_FLAG_NAMED_GROUPS | lre_get_flags(s->byte_code.buf));
} }
dbuf_free(&s->group_names); dbuf_free(&s->group_names);
@ -1927,86 +1966,86 @@ static BOOL is_word_char(uint32_t c)
(c == '_')); (c == '_'));
} }
#define GET_CHAR(c, cptr, cbuf_end) \ #define GET_CHAR(c, cptr, cbuf_end, cbuf_type) \
do { \ do { \
if (cbuf_type == 0) { \ if (cbuf_type == 0) { \
c = *cptr++; \ c = *cptr++; \
} else { \ } else { \
const uint16_t *_p = (uint16_t *)cptr; \ const uint16_t *_p = (const uint16_t *)cptr; \
const uint16_t *_end = (uint16_t *)cbuf_end; \ const uint16_t *_end = (const uint16_t *)cbuf_end; \
c = *_p++; \ c = *_p++; \
if (is_hi_surrogate(c)) \ if (is_hi_surrogate(c)) \
if (cbuf_type == 2) \ if (cbuf_type == 2) \
if (_p < _end) \ if (_p < _end) \
if (is_lo_surrogate(*_p)) \ if (is_lo_surrogate(*_p)) \
c = from_surrogate(c, *_p++); \ c = from_surrogate(c, *_p++); \
cptr = (void *) _p; \ cptr = (const void *)_p; \
} \ } \
} while (0) } while (0)
#define PEEK_CHAR(c, cptr, cbuf_end) \ #define PEEK_CHAR(c, cptr, cbuf_end, cbuf_type) \
do { \ do { \
if (cbuf_type == 0) { \ if (cbuf_type == 0) { \
c = cptr[0]; \ c = cptr[0]; \
} else { \ } else { \
const uint16_t *_p = (uint16_t *)cptr; \ const uint16_t *_p = (const uint16_t *)cptr; \
const uint16_t *_end = (uint16_t *)cbuf_end; \ const uint16_t *_end = (const uint16_t *)cbuf_end; \
c = *_p++; \ c = *_p++; \
if (is_hi_surrogate(c)) \ if (is_hi_surrogate(c)) \
if (cbuf_type == 2) \ if (cbuf_type == 2) \
if (_p < _end) \ if (_p < _end) \
if (is_lo_surrogate(*_p)) \ if (is_lo_surrogate(*_p)) \
c = from_surrogate(c, *_p++); \ c = from_surrogate(c, *_p); \
} \ } \
} while (0) } while (0)
#define PEEK_PREV_CHAR(c, cptr, cbuf_start) \ #define PEEK_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
do { \ do { \
if (cbuf_type == 0) { \ if (cbuf_type == 0) { \
c = cptr[-1]; \ c = cptr[-1]; \
} else { \ } else { \
const uint16_t *_p = (uint16_t *)cptr - 1; \ const uint16_t *_p = (const uint16_t *)cptr - 1; \
const uint16_t *_start = (uint16_t *)cbuf_start; \ const uint16_t *_start = (const uint16_t *)cbuf_start; \
c = *_p; \ c = *_p; \
if (is_lo_surrogate(c)) \ if (is_lo_surrogate(c)) \
if (cbuf_type == 2) \ if (cbuf_type == 2) \
if (_p > _start) \ if (_p > _start) \
if (is_hi_surrogate(*--_p)) \ if (is_hi_surrogate(_p[-1])) \
c = from_surrogate(*_p, c); \ c = from_surrogate(*--_p, c); \
} \ } \
} while (0) } while (0)
#define GET_PREV_CHAR(c, cptr, cbuf_start) \ #define GET_PREV_CHAR(c, cptr, cbuf_start, cbuf_type) \
do { \ do { \
if (cbuf_type == 0) { \ if (cbuf_type == 0) { \
cptr--; \ cptr--; \
c = cptr[0]; \ c = cptr[0]; \
} else { \ } else { \
const uint16_t *_p = (uint16_t *)cptr - 1; \ const uint16_t *_p = (const uint16_t *)cptr - 1; \
const uint16_t *_start = (uint16_t *)cbuf_start; \ const uint16_t *_start = (const uint16_t *)cbuf_start; \
c = *_p; \ c = *_p; \
if (is_lo_surrogate(c)) \ if (is_lo_surrogate(c)) \
if (cbuf_type == 2) \ if (cbuf_type == 2) \
if (_p > _start) \ if (_p > _start) \
if (is_hi_surrogate(*--_p)) \ if (is_hi_surrogate(_p[-1])) \
c = from_surrogate(*_p, c); \ c = from_surrogate(*--_p, c); \
cptr = (void *) _p; \ cptr = (const void *)_p; \
} \ } \
} while (0) } while (0)
#define PREV_CHAR(cptr, cbuf_start) \ #define PREV_CHAR(cptr, cbuf_start, cbuf_type) \
do { \ do { \
if (cbuf_type == 0) { \ if (cbuf_type == 0) { \
cptr--; \ cptr--; \
} else { \ } else { \
const uint16_t *_p = (uint16_t *)cptr - 1; \ const uint16_t *_p = (const uint16_t *)cptr - 1; \
const uint16_t *_start = (uint16_t *)cbuf_start; \ const uint16_t *_start = (const uint16_t *)cbuf_start; \
if (is_lo_surrogate(*_p)) \ if (is_lo_surrogate(*_p)) \
if (cbuf_type == 2) \ if (cbuf_type == 2) \
if (_p > _start) \ if (_p > _start) \
if (is_hi_surrogate(_p[-1])) \ if (is_hi_surrogate(_p[-1])) \
_p--; \ _p--; \
cptr = (void *) _p; \ cptr = (const void *)_p; \
} \ } \
} while (0) } while (0)
@ -2037,7 +2076,7 @@ typedef struct {
int stack_size_max; int stack_size_max;
BOOL multi_line; BOOL multi_line;
BOOL ignore_case; BOOL ignore_case;
BOOL is_utf16; BOOL is_unicode;
void *opaque; /* used for stack overflow check */ void *opaque; /* used for stack overflow check */
size_t state_size; size_t state_size;
@ -2146,7 +2185,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
/* go backward */ /* go backward */
char_count = get_u32(pc + 12); char_count = get_u32(pc + 12);
for(i = 0; i < char_count; i++) { for(i = 0; i < char_count; i++) {
PREV_CHAR(cptr, s->cbuf); PREV_CHAR(cptr, s->cbuf, cbuf_type);
} }
pc = (pc + 16) + (int)get_u32(pc); pc = (pc + 16) + (int)get_u32(pc);
rs->cptr = cptr; rs->cptr = cptr;
@ -2185,9 +2224,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
test_char: test_char:
if (cptr >= cbuf_end) if (cptr >= cbuf_end)
goto no_match; goto no_match;
GET_CHAR(c, cptr, cbuf_end); GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) { if (s->ignore_case) {
c = lre_canonicalize(c, s->is_utf16); c = lre_canonicalize(c, s->is_unicode);
} }
if (val != c) if (val != c)
goto no_match; goto no_match;
@ -2232,7 +2271,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
break; break;
if (!s->multi_line) if (!s->multi_line)
goto no_match; goto no_match;
PEEK_PREV_CHAR(c, cptr, s->cbuf); PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
if (!is_line_terminator(c)) if (!is_line_terminator(c))
goto no_match; goto no_match;
break; break;
@ -2241,21 +2280,21 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
break; break;
if (!s->multi_line) if (!s->multi_line)
goto no_match; goto no_match;
PEEK_CHAR(c, cptr, cbuf_end); PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
if (!is_line_terminator(c)) if (!is_line_terminator(c))
goto no_match; goto no_match;
break; break;
case REOP_dot: case REOP_dot:
if (cptr == cbuf_end) if (cptr == cbuf_end)
goto no_match; goto no_match;
GET_CHAR(c, cptr, cbuf_end); GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (is_line_terminator(c)) if (is_line_terminator(c))
goto no_match; goto no_match;
break; break;
case REOP_any: case REOP_any:
if (cptr == cbuf_end) if (cptr == cbuf_end)
goto no_match; goto no_match;
GET_CHAR(c, cptr, cbuf_end); GET_CHAR(c, cptr, cbuf_end, cbuf_type);
break; break;
case REOP_save_start: case REOP_save_start:
case REOP_save_end: case REOP_save_end:
@ -2309,14 +2348,14 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
if (cptr == s->cbuf) { if (cptr == s->cbuf) {
v1 = FALSE; v1 = FALSE;
} else { } else {
PEEK_PREV_CHAR(c, cptr, s->cbuf); PEEK_PREV_CHAR(c, cptr, s->cbuf, cbuf_type);
v1 = is_word_char(c); v1 = is_word_char(c);
} }
/* current char */ /* current char */
if (cptr >= cbuf_end) { if (cptr >= cbuf_end) {
v2 = FALSE; v2 = FALSE;
} else { } else {
PEEK_CHAR(c, cptr, cbuf_end); PEEK_CHAR(c, cptr, cbuf_end, cbuf_type);
v2 = is_word_char(c); v2 = is_word_char(c);
} }
if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode)) if (v1 ^ v2 ^ (REOP_not_word_boundary - opcode))
@ -2341,11 +2380,11 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
while (cptr1 < cptr1_end) { while (cptr1 < cptr1_end) {
if (cptr >= cbuf_end) if (cptr >= cbuf_end)
goto no_match; goto no_match;
GET_CHAR(c1, cptr1, cptr1_end); GET_CHAR(c1, cptr1, cptr1_end, cbuf_type);
GET_CHAR(c2, cptr, cbuf_end); GET_CHAR(c2, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) { if (s->ignore_case) {
c1 = lre_canonicalize(c1, s->is_utf16); c1 = lre_canonicalize(c1, s->is_unicode);
c2 = lre_canonicalize(c2, s->is_utf16); c2 = lre_canonicalize(c2, s->is_unicode);
} }
if (c1 != c2) if (c1 != c2)
goto no_match; goto no_match;
@ -2355,11 +2394,11 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
while (cptr1 > cptr1_start) { while (cptr1 > cptr1_start) {
if (cptr == s->cbuf) if (cptr == s->cbuf)
goto no_match; goto no_match;
GET_PREV_CHAR(c1, cptr1, cptr1_start); GET_PREV_CHAR(c1, cptr1, cptr1_start, cbuf_type);
GET_PREV_CHAR(c2, cptr, s->cbuf); GET_PREV_CHAR(c2, cptr, s->cbuf, cbuf_type);
if (s->ignore_case) { if (s->ignore_case) {
c1 = lre_canonicalize(c1, s->is_utf16); c1 = lre_canonicalize(c1, s->is_unicode);
c2 = lre_canonicalize(c2, s->is_utf16); c2 = lre_canonicalize(c2, s->is_unicode);
} }
if (c1 != c2) if (c1 != c2)
goto no_match; goto no_match;
@ -2376,9 +2415,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
pc += 2; pc += 2;
if (cptr >= cbuf_end) if (cptr >= cbuf_end)
goto no_match; goto no_match;
GET_CHAR(c, cptr, cbuf_end); GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) { if (s->ignore_case) {
c = lre_canonicalize(c, s->is_utf16); c = lre_canonicalize(c, s->is_unicode);
} }
idx_min = 0; idx_min = 0;
low = get_u16(pc + 0 * 4); low = get_u16(pc + 0 * 4);
@ -2416,9 +2455,9 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
pc += 2; pc += 2;
if (cptr >= cbuf_end) if (cptr >= cbuf_end)
goto no_match; goto no_match;
GET_CHAR(c, cptr, cbuf_end); GET_CHAR(c, cptr, cbuf_end, cbuf_type);
if (s->ignore_case) { if (s->ignore_case) {
c = lre_canonicalize(c, s->is_utf16); c = lre_canonicalize(c, s->is_unicode);
} }
idx_min = 0; idx_min = 0;
low = get_u32(pc + 0 * 8); low = get_u32(pc + 0 * 8);
@ -2448,7 +2487,7 @@ static intptr_t lre_exec_backtrack(REExecContext *s, uint8_t **capture,
/* go to the previous char */ /* go to the previous char */
if (cptr == s->cbuf) if (cptr == s->cbuf)
goto no_match; goto no_match;
PREV_CHAR(cptr, s->cbuf); PREV_CHAR(cptr, s->cbuf, cbuf_type);
break; break;
case REOP_simple_greedy_quant: case REOP_simple_greedy_quant:
{ {
@ -2507,16 +2546,16 @@ int lre_exec(uint8_t **capture,
int re_flags, i, alloca_size, ret; int re_flags, i, alloca_size, ret;
StackInt *stack_buf; StackInt *stack_buf;
re_flags = bc_buf[RE_HEADER_FLAGS]; re_flags = lre_get_flags(bc_buf);
s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0; s->multi_line = (re_flags & LRE_FLAG_MULTILINE) != 0;
s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0; s->ignore_case = (re_flags & LRE_FLAG_IGNORECASE) != 0;
s->is_utf16 = (re_flags & LRE_FLAG_UTF16) != 0; s->is_unicode = (re_flags & LRE_FLAG_UNICODE) != 0;
s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT]; s->capture_count = bc_buf[RE_HEADER_CAPTURE_COUNT];
s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE]; s->stack_size_max = bc_buf[RE_HEADER_STACK_SIZE];
s->cbuf = cbuf; s->cbuf = cbuf;
s->cbuf_end = cbuf + (clen << cbuf_type); s->cbuf_end = cbuf + (clen << cbuf_type);
s->cbuf_type = cbuf_type; s->cbuf_type = cbuf_type;
if (s->cbuf_type == 1 && s->is_utf16) if (s->cbuf_type == 1 && s->is_unicode)
s->cbuf_type = 2; s->cbuf_type = 2;
s->opaque = opaque; s->opaque = opaque;
@ -2544,7 +2583,7 @@ int lre_get_capture_count(const uint8_t *bc_buf)
int lre_get_flags(const uint8_t *bc_buf) int lre_get_flags(const uint8_t *bc_buf)
{ {
return bc_buf[RE_HEADER_FLAGS]; return get_u16(bc_buf + RE_HEADER_FLAGS);
} }
/* Return NULL if no group names. Otherwise, return a pointer to /* Return NULL if no group names. Otherwise, return a pointer to
@ -2554,14 +2593,14 @@ const char *lre_get_groupnames(const uint8_t *bc_buf)
uint32_t re_bytecode_len; uint32_t re_bytecode_len;
if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0) if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)
return NULL; return NULL;
re_bytecode_len = get_u32(bc_buf + 3); re_bytecode_len = get_u32(bc_buf + RE_HEADER_BYTECODE_LEN);
return (const char *)(bc_buf + 7 + re_bytecode_len); return (const char *)(bc_buf + RE_HEADER_LEN + re_bytecode_len);
} }
void lre_byte_swap(uint8_t *buf, size_t len, BOOL is_byte_swapped) void lre_byte_swap(uint8_t *buf, size_t len, BOOL is_byte_swapped)
{ {
uint8_t *p, *pe; uint8_t *p, *pe;
uint32_t n, r; uint32_t n, r, nw;
p = buf; p = buf;
if (len < RE_HEADER_LEN) if (len < RE_HEADER_LEN)
@ -2573,8 +2612,10 @@ void lre_byte_swap(uint8_t *buf, size_t len, BOOL is_byte_swapped)
// <capture group name 1> // <capture group name 1>
// <capture group name 2> // <capture group name 2>
// etc. // etc.
n = get_u32(&p[3]); // bytecode size inplace_bswap16(&p[RE_HEADER_FLAGS]);
inplace_bswap32(&p[3]);
n = get_u32(&p[RE_HEADER_BYTECODE_LEN]);
inplace_bswap32(&p[RE_HEADER_BYTECODE_LEN]);
if (is_byte_swapped) if (is_byte_swapped)
n = bswap32(n); n = bswap32(n);
if (n > len - RE_HEADER_LEN) if (n > len - RE_HEADER_LEN)
@ -2594,16 +2635,23 @@ void lre_byte_swap(uint8_t *buf, size_t len, BOOL is_byte_swapped)
case REOP_save_reset: // has two 8 bit arguments case REOP_save_reset: // has two 8 bit arguments
break; break;
case REOP_range32: // variable length case REOP_range32: // variable length
for (r = 3 + 4 * get_u16(&p[1]); n < r; n += 4) nw = get_u16(&p[1]); // number of pairs of uint32_t
if (is_byte_swapped)
n = bswap16(n);
for (r = 3 + 8 * nw; n < r; n += 4)
inplace_bswap32(&p[n]); inplace_bswap32(&p[n]);
goto doswap16; goto doswap16;
case REOP_range: // variable length case REOP_range: // variable length
for (r = 3 + 2 * get_u16(&p[1]); n < r; n += 2) nw = get_u16(&p[1]); // number of pairs of uint16_t
if (is_byte_swapped)
n = bswap16(n);
for (r = 3 + 4 * nw; n < r; n += 2)
inplace_bswap16(&p[n]); inplace_bswap16(&p[n]);
goto doswap16; goto doswap16;
default: default:
doswap16: doswap16:
inplace_bswap16(&p[1]); inplace_bswap16(&p[1]);
break;
} }
break; break;
case 5: case 5:

View file

@ -34,11 +34,11 @@
#define LRE_FLAG_IGNORECASE (1 << 1) #define LRE_FLAG_IGNORECASE (1 << 1)
#define LRE_FLAG_MULTILINE (1 << 2) #define LRE_FLAG_MULTILINE (1 << 2)
#define LRE_FLAG_DOTALL (1 << 3) #define LRE_FLAG_DOTALL (1 << 3)
#define LRE_FLAG_UTF16 (1 << 4) #define LRE_FLAG_UNICODE (1 << 4)
#define LRE_FLAG_STICKY (1 << 5) #define LRE_FLAG_STICKY (1 << 5)
#define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */ #define LRE_FLAG_INDICES (1 << 6) /* Unused by libregexp, just recorded. */
#define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */ #define LRE_FLAG_NAMED_GROUPS (1 << 7) /* named groups are present in the regexp */
#define LRE_FLAG_UNICODE_SETS (1 << 8)
uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
const char *buf, size_t buf_len, int re_flags, const char *buf, size_t buf_len, int re_flags,
@ -53,7 +53,7 @@ int lre_exec(uint8_t **capture,
int lre_parse_escape(const uint8_t **pp, int allow_utf16); int lre_parse_escape(const uint8_t **pp, int allow_utf16);
LRE_BOOL lre_is_space(int c); LRE_BOOL lre_is_space(int c);
void lre_byte_swap(uint8_t *buf, size_t len, BOOL is_byte_swapped); void lre_byte_swap(uint8_t *buf, size_t len, LRE_BOOL is_byte_swapped);
/* must be provided by the user */ /* must be provided by the user */
LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size); LRE_BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size);

View file

@ -947,8 +947,8 @@ int unicode_script(CharRange *cr,
int script_idx; int script_idx;
const uint8_t *p, *p_end; const uint8_t *p, *p_end;
uint32_t c, c1, b, n, v, v_len, i, type; uint32_t c, c1, b, n, v, v_len, i, type;
CharRange cr1_s, *cr1; CharRange cr1_s = { 0 }, *cr1 = NULL;
CharRange cr2_s, *cr2 = &cr2_s; CharRange cr2_s = { 0 }, *cr2 = &cr2_s;
BOOL is_common; BOOL is_common;
script_idx = unicode_find_name(unicode_script_name_table, script_name); script_idx = unicode_find_name(unicode_script_name_table, script_name);

View file

@ -24,6 +24,7 @@
#ifndef LIBUNICODE_H #ifndef LIBUNICODE_H
#define LIBUNICODE_H #define LIBUNICODE_H
#include <stddef.h>
#include <inttypes.h> #include <inttypes.h>
#define LRE_BOOL int /* for documentation purposes */ #define LRE_BOOL int /* for documentation purposes */

3
list.h
View file

@ -36,8 +36,7 @@ struct list_head {
#define LIST_HEAD_INIT(el) { &(el), &(el) } #define LIST_HEAD_INIT(el) { &(el), &(el) }
/* return the pointer of type 'type *' containing 'el' as field 'member' */ /* return the pointer of type 'type *' containing 'el' as field 'member' */
#define list_entry(el, type, member) \ #define list_entry(el, type, member) container_of(el, type, member)
((type *)((uint8_t *)(el) - offsetof(type, member)))
static inline void init_list_head(struct list_head *head) static inline void init_list_head(struct list_head *head)
{ {

138
qjs.c
View file

@ -41,6 +41,8 @@
extern const uint8_t qjsc_repl[]; extern const uint8_t qjsc_repl[];
extern const uint32_t qjsc_repl_size; extern const uint32_t qjsc_repl_size;
static JSCFunctionListEntry argv0;
static int eval_buf(JSContext *ctx, const void *buf, int buf_len, static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
const char *filename, int eval_flags) const char *filename, int eval_flags)
{ {
@ -56,6 +58,7 @@ static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
js_module_set_import_meta(ctx, val, TRUE, TRUE); js_module_set_import_meta(ctx, val, TRUE, TRUE);
val = JS_EvalFunction(ctx, val); val = JS_EvalFunction(ctx, val);
} }
val = js_std_await(ctx, val);
} else { } else {
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
} }
@ -94,6 +97,51 @@ static int eval_file(JSContext *ctx, const char *filename, int module)
return ret; return ret;
} }
static int64_t parse_limit(const char *arg) {
char *p;
unsigned long unit = 1024; /* default to traditional KB */
double d = strtod(arg, &p);
if (p == arg) {
fprintf(stderr, "Invalid limit: %s\n", arg);
return -1;
}
if (*p) {
switch (*p++) {
case 'b': case 'B': unit = 1UL << 0; break;
case 'k': case 'K': unit = 1UL << 10; break; /* IEC kibibytes */
case 'm': case 'M': unit = 1UL << 20; break; /* IEC mebibytes */
case 'g': case 'G': unit = 1UL << 30; break; /* IEC gigibytes */
default:
fprintf(stderr, "Invalid limit: %s, unrecognized suffix, only k,m,g are allowed\n", arg);
return -1;
}
if (*p) {
fprintf(stderr, "Invalid limit: %s, only one suffix allowed\n", arg);
return -1;
}
}
return (int64_t)(d * unit);
}
static JSValue js_gc(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv)
{
JS_RunGC(JS_GetRuntime(ctx));
return JS_UNDEFINED;
}
static const JSCFunctionListEntry navigator_obj[] = {
JS_PROP_STRING_DEF("userAgent", "quickjs-ng", JS_PROP_ENUMERABLE),
};
static const JSCFunctionListEntry global_obj[] = {
JS_CFUNC_DEF("gc", 0, js_gc),
JS_OBJECT_DEF("navigator", navigator_obj, countof(navigator_obj), JS_PROP_C_W_E),
};
/* also used to initialize the worker context */ /* also used to initialize the worker context */
static JSContext *JS_NewCustomContext(JSRuntime *rt) static JSContext *JS_NewCustomContext(JSRuntime *rt)
{ {
@ -104,6 +152,12 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt)
/* system modules */ /* system modules */
js_init_module_std(ctx, "std"); js_init_module_std(ctx, "std");
js_init_module_os(ctx, "os"); js_init_module_os(ctx, "os");
JSValue global = JS_GetGlobalObject(ctx);
JS_SetPropertyFunctionList(ctx, global, global_obj, countof(global_obj));
JS_SetPropertyFunctionList(ctx, global, &argv0, 1);
JS_FreeValue(ctx, global);
return ctx; return ctx;
} }
@ -175,7 +229,8 @@ static void *js_trace_malloc(JSMallocState *s, size_t size)
/* Do not allocate zero bytes: behavior is platform dependent */ /* Do not allocate zero bytes: behavior is platform dependent */
assert(size != 0); assert(size != 0);
if (unlikely(s->malloc_size + size > s->malloc_limit)) /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
if (unlikely(s->malloc_size + size > s->malloc_limit - 1))
return NULL; return NULL;
ptr = malloc(size); ptr = malloc(size);
js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr); js_trace_malloc_printf(s, "A %zd -> %p\n", size, ptr);
@ -214,7 +269,8 @@ static void *js_trace_realloc(JSMallocState *s, void *ptr, size_t size)
free(ptr); free(ptr);
return NULL; return NULL;
} }
if (s->malloc_size + size - old_size > s->malloc_limit) /* When malloc_limit is 0 (unlimited), malloc_limit - 1 will be SIZE_MAX. */
if (s->malloc_size + size - old_size > s->malloc_limit - 1)
return NULL; return NULL;
js_trace_malloc_printf(s, "R %zd %p", size, ptr); js_trace_malloc_printf(s, "R %zd %p", size, ptr);
@ -249,8 +305,8 @@ void help(void)
" --std make 'std' and 'os' available to the loaded script\n" " --std make 'std' and 'os' available to the loaded script\n"
"-T --trace trace memory allocation\n" "-T --trace trace memory allocation\n"
"-d --dump dump the memory usage stats\n" "-d --dump dump the memory usage stats\n"
" --memory-limit n limit the memory usage to 'n' bytes\n" " --memory-limit n limit the memory usage to 'n' Kbytes\n"
" --stack-size n limit the stack size to 'n' bytes\n" " --stack-size n limit the stack size to 'n' Kbytes\n"
" --unhandled-rejection dump unhandled promise rejections\n" " --unhandled-rejection dump unhandled promise rejections\n"
"-q --quit just instantiate the interpreter and quit\n", JS_GetVersion()); "-q --quit just instantiate the interpreter and quit\n", JS_GetVersion());
exit(1); exit(1);
@ -265,15 +321,19 @@ int main(int argc, char **argv)
char *expr = NULL; char *expr = NULL;
int interactive = 0; int interactive = 0;
int dump_memory = 0; int dump_memory = 0;
int dump_flags = 0;
int trace_memory = 0; int trace_memory = 0;
int empty_run = 0; int empty_run = 0;
int module = -1; int module = -1;
int load_std = 0; int load_std = 0;
int dump_unhandled_promise_rejection = 0; int dump_unhandled_promise_rejection = 0;
size_t memory_limit = 0;
char *include_list[32]; char *include_list[32];
int i, include_count = 0; int i, include_count = 0;
size_t stack_size = 0; int64_t memory_limit = -1;
int64_t stack_size = -1;
argv0 = (JSCFunctionListEntry)JS_PROP_STRING_DEF("argv0", argv[0],
JS_PROP_C_W_E);
/* cannot use getopt because we want to pass the command line to /* cannot use getopt because we want to pass the command line to
the script */ the script */
@ -281,12 +341,16 @@ int main(int argc, char **argv)
while (optind < argc && *argv[optind] == '-') { while (optind < argc && *argv[optind] == '-') {
char *arg = argv[optind] + 1; char *arg = argv[optind] + 1;
const char *longopt = ""; const char *longopt = "";
char *opt_arg = NULL;
/* a single - is not an option, it also stops argument scanning */ /* a single - is not an option, it also stops argument scanning */
if (!*arg) if (!*arg)
break; break;
optind++; optind++;
if (*arg == '-') { if (*arg == '-') {
longopt = arg + 1; longopt = arg + 1;
opt_arg = strchr(longopt, '=');
if (opt_arg)
*opt_arg++ = '\0';
arg += strlen(arg); arg += strlen(arg);
/* -- stops argument scanning */ /* -- stops argument scanning */
if (!*longopt) if (!*longopt)
@ -294,23 +358,25 @@ int main(int argc, char **argv)
} }
for (; *arg || *longopt; longopt = "") { for (; *arg || *longopt; longopt = "") {
char opt = *arg; char opt = *arg;
if (opt) if (opt) {
arg++; arg++;
if (!opt_arg && *arg)
opt_arg = arg;
}
if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) { if (opt == 'h' || opt == '?' || !strcmp(longopt, "help")) {
help(); help();
continue; continue;
} }
if (opt == 'e' || !strcmp(longopt, "eval")) { if (opt == 'e' || !strcmp(longopt, "eval")) {
if (*arg) { if (!opt_arg) {
expr = arg; if (optind >= argc) {
break; fprintf(stderr, "qjs: missing expression for -e\n");
exit(2);
}
opt_arg = argv[optind++];
} }
if (optind < argc) { expr = opt_arg;
expr = argv[optind++]; break;
break;
}
fprintf(stderr, "qjs: missing expression for -e\n");
exit(2);
} }
if (opt == 'I' || !strcmp(longopt, "include")) { if (opt == 'I' || !strcmp(longopt, "include")) {
if (optind >= argc) { if (optind >= argc) {
@ -340,6 +406,10 @@ int main(int argc, char **argv)
dump_memory++; dump_memory++;
continue; continue;
} }
if (opt == 'D' || !strcmp(longopt, "dump-flags")) {
dump_flags = opt_arg ? strtol(opt_arg, NULL, 16) : 0;
break;
}
if (opt == 'T' || !strcmp(longopt, "trace")) { if (opt == 'T' || !strcmp(longopt, "trace")) {
trace_memory++; trace_memory++;
continue; continue;
@ -357,20 +427,26 @@ int main(int argc, char **argv)
continue; continue;
} }
if (!strcmp(longopt, "memory-limit")) { if (!strcmp(longopt, "memory-limit")) {
if (optind >= argc) { if (!opt_arg) {
fprintf(stderr, "expecting memory limit"); if (optind >= argc) {
exit(1); fprintf(stderr, "expecting memory limit");
exit(1);
}
opt_arg = argv[optind++];
} }
memory_limit = (size_t)strtod(argv[optind++], NULL); memory_limit = parse_limit(opt_arg);
continue; break;
} }
if (!strcmp(longopt, "stack-size")) { if (!strcmp(longopt, "stack-size")) {
if (optind >= argc) { if (!opt_arg) {
fprintf(stderr, "expecting stack size"); if (optind >= argc) {
exit(1); fprintf(stderr, "expecting stack size");
exit(1);
}
opt_arg = argv[optind++];
} }
stack_size = (size_t)strtod(argv[optind++], NULL); stack_size = parse_limit(opt_arg);
continue; break;
} }
if (opt) { if (opt) {
fprintf(stderr, "qjs: unknown option '-%c'\n", opt); fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
@ -391,10 +467,12 @@ int main(int argc, char **argv)
fprintf(stderr, "qjs: cannot allocate JS runtime\n"); fprintf(stderr, "qjs: cannot allocate JS runtime\n");
exit(2); exit(2);
} }
if (memory_limit != 0) if (memory_limit >= 0)
JS_SetMemoryLimit(rt, memory_limit); JS_SetMemoryLimit(rt, (size_t)memory_limit);
if (stack_size != 0) if (stack_size >= 0)
JS_SetMaxStackSize(rt, stack_size); JS_SetMaxStackSize(rt, (size_t)stack_size);
if (dump_flags != 0)
JS_SetDumpFlags(rt, dump_flags);
js_std_set_worker_new_context_func(JS_NewCustomContext); js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt); js_std_init_handlers(rt);
ctx = JS_NewCustomContext(rt); ctx = JS_NewCustomContext(rt);

20
qjsc.c
View file

@ -56,7 +56,7 @@ static namelist_t cmodule_list;
static namelist_t init_module_list; static namelist_t init_module_list;
static FILE *outfile; static FILE *outfile;
static const char *c_ident_prefix = "qjsc_"; static const char *c_ident_prefix = "qjsc_";
static int strip;
void namelist_add(namelist_t *lp, const char *name, const char *short_name, void namelist_add(namelist_t *lp, const char *name, const char *short_name,
int flags) int flags)
@ -150,13 +150,20 @@ static void dump_hex(FILE *f, const uint8_t *buf, size_t len)
} }
static void output_object_code(JSContext *ctx, static void output_object_code(JSContext *ctx,
FILE *fo, JSValueConst obj, const char *c_name, FILE *fo, JSValue obj, const char *c_name,
BOOL load_only) BOOL load_only)
{ {
uint8_t *out_buf; uint8_t *out_buf;
size_t out_buf_len; size_t out_buf_len;
int flags = JS_WRITE_OBJ_BYTECODE;
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, JS_WRITE_OBJ_BYTECODE); if (strip) {
flags |= JS_WRITE_OBJ_STRIP_SOURCE;
if (strip > 1)
flags |= JS_WRITE_OBJ_STRIP_DEBUG;
}
out_buf = JS_WriteObject(ctx, &out_buf_len, obj, flags);
if (!out_buf) { if (!out_buf) {
js_std_dump_error(ctx); js_std_dump_error(ctx);
exit(1); exit(1);
@ -305,6 +312,7 @@ static const char main_c_template1[] =
static const char main_c_template2[] = static const char main_c_template2[] =
" js_std_loop(ctx);\n" " js_std_loop(ctx);\n"
" JS_FreeContext(ctx);\n" " JS_FreeContext(ctx);\n"
" js_std_free_handlers(rt);\n"
" JS_FreeRuntime(rt);\n" " JS_FreeRuntime(rt);\n"
" return 0;\n" " return 0;\n"
"}\n"; "}\n";
@ -353,6 +361,7 @@ int main(int argc, char **argv)
cname = NULL; cname = NULL;
module = -1; module = -1;
verbose = 0; verbose = 0;
strip = 0;
stack_size = 0; stack_size = 0;
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list)); memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
@ -361,7 +370,7 @@ int main(int argc, char **argv)
namelist_add(&cmodule_list, "os", "os", 0); namelist_add(&cmodule_list, "os", "os", 0);
for(;;) { for(;;) {
c = getopt(argc, argv, "ho:N:mxevM:p:S:D:"); c = getopt(argc, argv, "ho:N:mxesvM:p:S:D:");
if (c == -1) if (c == -1)
break; break;
switch(c) { switch(c) {
@ -398,6 +407,9 @@ int main(int argc, char **argv)
case 'D': case 'D':
namelist_add(&dynamic_module_list, optarg, NULL, 0); namelist_add(&dynamic_module_list, optarg, NULL, 0);
break; break;
case 's':
strip++;
break;
case 'v': case 'v':
verbose++; verbose++;
break; break;

View file

@ -79,8 +79,6 @@ DEF(await, "await")
DEF(empty_string, "") DEF(empty_string, "")
/* identifiers */ /* identifiers */
DEF(length, "length") DEF(length, "length")
DEF(fileName, "fileName")
DEF(lineNumber, "lineNumber")
DEF(message, "message") DEF(message, "message")
DEF(cause, "cause") DEF(cause, "cause")
DEF(errors, "errors") DEF(errors, "errors")
@ -172,11 +170,9 @@ DEF(status, "status")
DEF(reason, "reason") DEF(reason, "reason")
DEF(globalThis, "globalThis") DEF(globalThis, "globalThis")
DEF(bigint, "bigint") DEF(bigint, "bigint")
#ifdef CONFIG_ATOMICS
DEF(not_equal, "not-equal") DEF(not_equal, "not-equal")
DEF(timed_out, "timed-out") DEF(timed_out, "timed-out")
DEF(ok, "ok") DEF(ok, "ok")
#endif
DEF(toJSON, "toJSON") DEF(toJSON, "toJSON")
/* class names */ /* class names */
DEF(Object, "Object") DEF(Object, "Object")
@ -238,6 +234,7 @@ DEF(SyntaxError, "SyntaxError")
DEF(TypeError, "TypeError") DEF(TypeError, "TypeError")
DEF(URIError, "URIError") DEF(URIError, "URIError")
DEF(InternalError, "InternalError") DEF(InternalError, "InternalError")
DEF(CallSite, "CallSite")
/* private symbols */ /* private symbols */
DEF(Private_brand, "<brand>") DEF(Private_brand, "<brand>")
/* symbols */ /* symbols */

File diff suppressed because it is too large Load diff

View file

@ -37,18 +37,19 @@ JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name); JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
void js_std_add_helpers(JSContext *ctx, int argc, char **argv); void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
void js_std_loop(JSContext *ctx); void js_std_loop(JSContext *ctx);
JSValue js_std_await(JSContext *ctx, JSValue obj);
void js_std_init_handlers(JSRuntime *rt); void js_std_init_handlers(JSRuntime *rt);
void js_std_free_handlers(JSRuntime *rt); void js_std_free_handlers(JSRuntime *rt);
void js_std_dump_error(JSContext *ctx); void js_std_dump_error(JSContext *ctx);
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename); uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, int js_module_set_import_meta(JSContext *ctx, JSValue func_val,
JS_BOOL use_realpath, JS_BOOL is_main); JS_BOOL use_realpath, JS_BOOL is_main);
JSModuleDef *js_module_loader(JSContext *ctx, JSModuleDef *js_module_loader(JSContext *ctx,
const char *module_name, void *opaque); const char *module_name, void *opaque);
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len, void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
int flags); int flags);
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, void js_std_promise_rejection_tracker(JSContext *ctx, JSValue promise,
JSValueConst reason, JSValue reason,
JS_BOOL is_handled, void *opaque); JS_BOOL is_handled, void *opaque);
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt)); void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));

View file

@ -44,6 +44,7 @@ FMT(loc)
FMT(arg) FMT(arg)
FMT(var_ref) FMT(var_ref)
FMT(u32) FMT(u32)
FMT(u32x2)
FMT(i32) FMT(i32)
FMT(const) FMT(const)
FMT(label) FMT(label)
@ -135,9 +136,12 @@ DEF( put_ref_value, 1, 3, 0, none)
DEF( define_var, 6, 0, 0, atom_u8) DEF( define_var, 6, 0, 0, atom_u8)
DEF(check_define_var, 6, 0, 0, atom_u8) DEF(check_define_var, 6, 0, 0, atom_u8)
DEF( define_func, 6, 1, 0, atom_u8) DEF( define_func, 6, 1, 0, atom_u8)
// order matters, see IC counterparts
DEF( get_field, 5, 1, 1, atom) DEF( get_field, 5, 1, 1, atom)
DEF( get_field2, 5, 1, 2, atom) DEF( get_field2, 5, 1, 2, atom)
DEF( put_field, 5, 2, 0, atom) DEF( put_field, 5, 2, 0, atom)
DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */ DEF( get_private_field, 1, 2, 1, none) /* obj prop -> value */
DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */ DEF( put_private_field, 1, 3, 0, none) /* obj value prop -> */
DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */ DEF(define_private_field, 1, 3, 1, none) /* obj prop value -> obj */
@ -182,6 +186,7 @@ DEF( goto, 5, 0, 0, label) /* must come after if_true */
DEF( catch, 5, 0, 1, label) DEF( catch, 5, 0, 1, label)
DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */ DEF( gosub, 5, 0, 0, label) /* used to execute the finally block */
DEF( ret, 1, 1, 0, none) /* used to return from the finally block */ DEF( ret, 1, 1, 0, none) /* used to return from the finally block */
DEF( nip_catch, 1, 2, 1, none) /* catch ... a -> a */
DEF( to_object, 1, 1, 1, none) DEF( to_object, 1, 1, 1, none)
//DEF( to_string, 1, 1, 1, none) //DEF( to_string, 1, 1, 1, none)
@ -208,7 +213,6 @@ DEF( for_of_next, 2, 3, 5, u8)
DEF(iterator_check_object, 1, 1, 1, none) DEF(iterator_check_object, 1, 1, 1, none)
DEF(iterator_get_value_done, 1, 1, 2, none) DEF(iterator_get_value_done, 1, 1, 2, none)
DEF( iterator_close, 1, 3, 0, none) DEF( iterator_close, 1, 3, 0, none)
DEF(iterator_close_return, 1, 4, 4, none)
DEF( iterator_next, 1, 4, 4, none) DEF( iterator_next, 1, 4, 4, none)
DEF( iterator_call, 2, 4, 5, u8) DEF( iterator_call, 2, 4, 5, u8)
DEF( initial_yield, 1, 0, 0, none) DEF( initial_yield, 1, 0, 0, none)
@ -277,11 +281,11 @@ def( scope_get_ref, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase
def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */ def(scope_put_var_init, 7, 0, 2, atom_u16) /* emitted in phase 1, removed in phase 2 */
def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */ def(scope_get_private_field, 7, 1, 1, atom_u16) /* obj -> value, emitted in phase 1, removed in phase 2 */
def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */ def(scope_get_private_field2, 7, 1, 2, atom_u16) /* obj -> obj value, emitted in phase 1, removed in phase 2 */
def(scope_put_private_field, 7, 1, 1, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */ def(scope_put_private_field, 7, 2, 0, atom_u16) /* obj value ->, emitted in phase 1, removed in phase 2 */
def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */ def( set_class_name, 5, 1, 1, u32) /* emitted in phase 1, removed in phase 2 */
def( line_num, 5, 0, 0, u32) /* emitted in phase 1, removed in phase 3 */ def( source_loc, 9, 0, 0, u32x2) /* emitted in phase 1, removed in phase 3 */
DEF( push_minus1, 1, 0, 1, none_int) DEF( push_minus1, 1, 0, 1, none_int)
DEF( push_0, 1, 0, 1, none_int) DEF( push_0, 1, 0, 1, none_int)
@ -357,6 +361,7 @@ DEF( is_null, 1, 1, 1, none)
DEF(typeof_is_undefined, 1, 1, 1, none) DEF(typeof_is_undefined, 1, 1, 1, none)
DEF( typeof_is_function, 1, 1, 1, none) DEF( typeof_is_function, 1, 1, 1, none)
// order matters, see non-IC counterparts
DEF( get_field_ic, 5, 1, 1, none) DEF( get_field_ic, 5, 1, 1, none)
DEF( get_field2_ic, 5, 1, 2, none) DEF( get_field2_ic, 5, 1, 2, none)
DEF( put_field_ic, 5, 2, 0, none) DEF( put_field_ic, 5, 2, 0, none)

9844
quickjs.c

File diff suppressed because it is too large Load diff

438
quickjs.h
View file

@ -29,18 +29,18 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include <math.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define js_unlikely(x) __builtin_expect(!!(x), 0)
#define js_force_inline inline __attribute__((always_inline)) #define js_force_inline inline __attribute__((always_inline))
#define __js_printf_like(f, a) __attribute__((format(printf, f, a))) #define __js_printf_like(f, a) __attribute__((format(printf, f, a)))
#define JS_EXTERN __attribute__((visibility("default"))) #define JS_EXTERN __attribute__((visibility("default")))
#else #else
#define js_unlikely(x) (x)
#define js_force_inline inline #define js_force_inline inline
#define __js_printf_like(a, b) #define __js_printf_like(a, b)
#define JS_EXTERN /* nothing */ #define JS_EXTERN /* nothing */
@ -55,6 +55,12 @@ typedef struct JSClass JSClass;
typedef uint32_t JSClassID; typedef uint32_t JSClassID;
typedef uint32_t JSAtom; typedef uint32_t JSAtom;
/* Unless documented otherwise, C string pointers (`char *` or `const char *`)
are assumed to verify these constraints:
- unless a length is passed separately, the string has a null terminator
- string contents is either pure ASCII or is UTF-8 encoded.
*/
#if INTPTR_MAX < INT64_MAX #if INTPTR_MAX < INT64_MAX
/* Use NAN boxing for 32bit builds. */ /* Use NAN boxing for 32bit builds. */
#define JS_NAN_BOXING #define JS_NAN_BOXING
@ -86,47 +92,12 @@ typedef struct JSRefCountHeader {
} JSRefCountHeader; } JSRefCountHeader;
#define JS_FLOAT64_NAN NAN #define JS_FLOAT64_NAN NAN
#define JSValueConst JSValue /* For backwards compatibility. */
#ifdef CONFIG_CHECK_JSVALUE #if defined(JS_NAN_BOXING)
/* JSValue consistency : it is not possible to run the code in this
mode, but it is useful to detect simple reference counting
errors. It would be interesting to modify a static C analyzer to
handle specific annotations (clang has such annotations but only
for objective C) */
typedef struct __JSValue *JSValue;
typedef const struct __JSValue *JSValueConst;
#define JS_VALUE_GET_TAG(v) (int)((uintptr_t)(v) & 0xf)
/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)
#define JS_VALUE_GET_INT(v) (int)((intptr_t)(v) >> 4)
#define JS_VALUE_GET_BOOL(v) JS_VALUE_GET_INT(v)
#define JS_VALUE_GET_FLOAT64(v) (double)JS_VALUE_GET_INT(v)
#define JS_VALUE_GET_PTR(v) (void *)((intptr_t)(v) & ~0xf)
#define JS_MKVAL(tag, val) (JSValue)(intptr_t)(((val) << 4) | (tag))
#define JS_MKPTR(tag, p) (JSValue)((intptr_t)(p) | (tag))
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
#define JS_NAN JS_MKVAL(JS_TAG_FLOAT64, 1)
static inline JSValue __JS_NewFloat64(double d)
{
return JS_MKVAL(JS_TAG_FLOAT64, (int)d);
}
static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
{
return 0;
}
#elif defined(JS_NAN_BOXING)
typedef uint64_t JSValue; typedef uint64_t JSValue;
#define JSValueConst JSValue
#define JS_VALUE_GET_TAG(v) (int)((v) >> 32) #define JS_VALUE_GET_TAG(v) (int)((v) >> 32)
#define JS_VALUE_GET_INT(v) (int)(v) #define JS_VALUE_GET_INT(v) (int)(v)
#define JS_VALUE_GET_BOOL(v) (int)(v) #define JS_VALUE_GET_BOOL(v) (int)(v)
@ -159,7 +130,7 @@ static inline JSValue __JS_NewFloat64(double d)
JSValue v; JSValue v;
u.d = d; u.d = d;
/* normalize NaN */ /* normalize NaN */
if (js_unlikely((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)) if ((u.u64 & 0x7fffffffffffffff) > 0x7ff0000000000000)
v = JS_NAN; v = JS_NAN;
else else
v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32); v = u.u64 - ((uint64_t)JS_FLOAT64_TAG_ADDEND << 32);
@ -199,8 +170,6 @@ typedef struct JSValue {
int64_t tag; int64_t tag;
} JSValue; } JSValue;
#define JSValueConst JSValue
#define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag) #define JS_VALUE_GET_TAG(v) ((int32_t)(v).tag)
/* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */ /* same as JS_VALUE_GET_TAG, but return JS_TAG_FLOAT64 with NaN boxing */
#define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v) #define JS_VALUE_GET_NORM_TAG(v) JS_VALUE_GET_TAG(v)
@ -214,7 +183,7 @@ typedef struct JSValue {
#define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64) #define JS_TAG_IS_FLOAT64(tag) ((unsigned)(tag) == JS_TAG_FLOAT64)
#define JS_NAN (JSValue){ .u.float64 = JS_FLOAT64_NAN, JS_TAG_FLOAT64 } #define JS_NAN (JSValue){ (JSValueUnion){ .float64 = JS_FLOAT64_NAN }, JS_TAG_FLOAT64 }
static inline JSValue __JS_NewFloat64(double d) static inline JSValue __JS_NewFloat64(double d)
{ {
@ -242,7 +211,6 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2))) #define JS_VALUE_IS_BOTH_FLOAT(v1, v2) (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v1)) && JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(v2)))
#define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v)) #define JS_VALUE_GET_OBJ(v) ((JSObject *)JS_VALUE_GET_PTR(v))
#define JS_VALUE_GET_STRING(v) ((JSString *)JS_VALUE_GET_PTR(v))
#define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST) #define JS_VALUE_HAS_REF_COUNT(v) ((unsigned)JS_VALUE_GET_TAG(v) >= (unsigned)JS_TAG_FIRST)
/* special values */ /* special values */
@ -283,8 +251,14 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#define JS_PROP_NO_ADD (1 << 16) /* internal use */ #define JS_PROP_NO_ADD (1 << 16) /* internal use */
#define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */ #define JS_PROP_NO_EXOTIC (1 << 17) /* internal use */
#define JS_PROP_DEFINE_PROPERTY (1 << 18) /* internal use */
#define JS_PROP_REFLECT_DEFINE_PROPERTY (1 << 19) /* internal use */
#if defined(__wasi__)
#define JS_DEFAULT_STACK_SIZE 0
#else
#define JS_DEFAULT_STACK_SIZE (256 * 1024) #define JS_DEFAULT_STACK_SIZE (256 * 1024)
#endif
/* JS_Eval() flags */ /* JS_Eval() flags */
#define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */
@ -301,10 +275,13 @@ static inline JS_BOOL JS_VALUE_IS_NAN(JSValue v)
#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) #define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5)
/* don't include the stack frames before this eval in the Error() backtraces */ /* don't include the stack frames before this eval in the Error() backtraces */
#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) #define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6)
/* allow top-level await in normal script. JS_Eval() returns a
promise. Only allowed with JS_EVAL_TYPE_GLOBAL */
#define JS_EVAL_FLAG_ASYNC (1 << 7)
typedef JSValue JSCFunction(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv); typedef JSValue JSCFunction(JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); typedef JSValue JSCFunctionMagic(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic);
typedef JSValue JSCFunctionData(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic, JSValue *func_data); typedef JSValue JSCFunctionData(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic, JSValue *func_data);
typedef struct JSMallocState { typedef struct JSMallocState {
size_t malloc_count; size_t malloc_count;
@ -325,7 +302,10 @@ typedef struct JSGCObjectHeader JSGCObjectHeader;
JS_EXTERN JSRuntime *JS_NewRuntime(void); JS_EXTERN JSRuntime *JS_NewRuntime(void);
/* info lifetime must exceed that of rt */ /* info lifetime must exceed that of rt */
JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info); JS_EXTERN void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
/* use 0 to disable memory limit */
JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit); JS_EXTERN void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
JS_EXTERN void JS_SetDumpFlags(JSRuntime *rt, uint64_t flags);
JS_EXTERN size_t JS_GetGCThreshold(JSRuntime *rt);
JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold); JS_EXTERN void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
/* use 0 to disable maximum stack size check */ /* use 0 to disable maximum stack size check */
JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size); JS_EXTERN void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
@ -337,9 +317,9 @@ JS_EXTERN void JS_FreeRuntime(JSRuntime *rt);
JS_EXTERN void *JS_GetRuntimeOpaque(JSRuntime *rt); JS_EXTERN void *JS_GetRuntimeOpaque(JSRuntime *rt);
JS_EXTERN void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque); JS_EXTERN void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque);
typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp); typedef void JS_MarkFunc(JSRuntime *rt, JSGCObjectHeader *gp);
JS_EXTERN void JS_MarkValue(JSRuntime *rt, JSValueConst val, JS_MarkFunc *mark_func); JS_EXTERN void JS_MarkValue(JSRuntime *rt, JSValue val, JS_MarkFunc *mark_func);
JS_EXTERN void JS_RunGC(JSRuntime *rt); JS_EXTERN void JS_RunGC(JSRuntime *rt);
JS_EXTERN JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj); JS_EXTERN JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValue obj);
JS_EXTERN JSContext *JS_NewContext(JSRuntime *rt); JS_EXTERN JSContext *JS_NewContext(JSRuntime *rt);
JS_EXTERN void JS_FreeContext(JSContext *s); JS_EXTERN void JS_FreeContext(JSContext *s);
@ -367,9 +347,16 @@ JS_EXTERN void JS_AddIntrinsicBigInt(JSContext *ctx);
JS_EXTERN void JS_AddIntrinsicWeakRef(JSContext *ctx); JS_EXTERN void JS_AddIntrinsicWeakRef(JSContext *ctx);
JS_EXTERN void JS_AddPerformance(JSContext *ctx); JS_EXTERN void JS_AddPerformance(JSContext *ctx);
/* for equality comparisons and sameness */
JS_EXTERN int JS_IsEqual(JSContext *ctx, JSValue op1, JSValue op2);
JS_EXTERN JS_BOOL JS_IsStrictEqual(JSContext *ctx, JSValue op1, JSValue op2);
JS_EXTERN JS_BOOL JS_IsSameValue(JSContext *ctx, JSValue op1, JSValue op2);
/* Similar to same-value equality, but +0 and -0 are considered equal. */
JS_EXTERN JS_BOOL JS_IsSameValueZero(JSContext *ctx, JSValue op1, JSValue op2);
/* Only used for running 262 tests. TODO(saghul) add build time flag. */ /* Only used for running 262 tests. TODO(saghul) add build time flag. */
JS_EXTERN JSValue js_string_codePointRange(JSContext *ctx, JSValueConst this_val, JS_EXTERN JSValue js_string_codePointRange(JSContext *ctx, JSValue this_val,
int argc, JSValueConst *argv); int argc, JSValue *argv);
JS_EXTERN void *js_malloc_rt(JSRuntime *rt, size_t size); JS_EXTERN void *js_malloc_rt(JSRuntime *rt, size_t size);
JS_EXTERN void js_free_rt(JSRuntime *rt, void *ptr); JS_EXTERN void js_free_rt(JSRuntime *rt, void *ptr);
@ -417,7 +404,7 @@ JS_EXTERN void JS_FreeAtomRT(JSRuntime *rt, JSAtom v);
JS_EXTERN JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom); JS_EXTERN JSValue JS_AtomToValue(JSContext *ctx, JSAtom atom);
JS_EXTERN JSValue JS_AtomToString(JSContext *ctx, JSAtom atom); JS_EXTERN JSValue JS_AtomToString(JSContext *ctx, JSAtom atom);
JS_EXTERN const char *JS_AtomToCString(JSContext *ctx, JSAtom atom); JS_EXTERN const char *JS_AtomToCString(JSContext *ctx, JSAtom atom);
JS_EXTERN JSAtom JS_ValueToAtom(JSContext *ctx, JSValueConst val); JS_EXTERN JSAtom JS_ValueToAtom(JSContext *ctx, JSValue val);
/* object class support */ /* object class support */
@ -438,41 +425,41 @@ typedef struct JSClassExoticMethods {
FALSE if the property does not exists, TRUE if it exists. If 1 is FALSE if the property does not exists, TRUE if it exists. If 1 is
returned, the property descriptor 'desc' is filled if != NULL. */ returned, the property descriptor 'desc' is filled if != NULL. */
int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc, int (*get_own_property)(JSContext *ctx, JSPropertyDescriptor *desc,
JSValueConst obj, JSAtom prop); JSValue obj, JSAtom prop);
/* '*ptab' should hold the '*plen' property keys. Return 0 if OK, /* '*ptab' should hold the '*plen' property keys. Return 0 if OK,
-1 if exception. The 'is_enumerable' field is ignored. -1 if exception. The 'is_enumerable' field is ignored.
*/ */
int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab, int (*get_own_property_names)(JSContext *ctx, JSPropertyEnum **ptab,
uint32_t *plen, uint32_t *plen,
JSValueConst obj); JSValue obj);
/* return < 0 if exception, or TRUE/FALSE */ /* return < 0 if exception, or TRUE/FALSE */
int (*delete_property)(JSContext *ctx, JSValueConst obj, JSAtom prop); int (*delete_property)(JSContext *ctx, JSValue obj, JSAtom prop);
/* return < 0 if exception or TRUE/FALSE */ /* return < 0 if exception or TRUE/FALSE */
int (*define_own_property)(JSContext *ctx, JSValueConst this_obj, int (*define_own_property)(JSContext *ctx, JSValue this_obj,
JSAtom prop, JSValueConst val, JSAtom prop, JSValue val,
JSValueConst getter, JSValueConst setter, JSValue getter, JSValue setter,
int flags); int flags);
/* The following methods can be emulated with the previous ones, /* The following methods can be emulated with the previous ones,
so they are usually not needed */ so they are usually not needed */
/* return < 0 if exception or TRUE/FALSE */ /* return < 0 if exception or TRUE/FALSE */
int (*has_property)(JSContext *ctx, JSValueConst obj, JSAtom atom); int (*has_property)(JSContext *ctx, JSValue obj, JSAtom atom);
JSValue (*get_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, JSValue (*get_property)(JSContext *ctx, JSValue obj, JSAtom atom,
JSValueConst receiver); JSValue receiver);
/* return < 0 if exception or TRUE/FALSE */ /* return < 0 if exception or TRUE/FALSE */
int (*set_property)(JSContext *ctx, JSValueConst obj, JSAtom atom, int (*set_property)(JSContext *ctx, JSValue obj, JSAtom atom,
JSValueConst value, JSValueConst receiver, int flags); JSValue value, JSValue receiver, int flags);
} JSClassExoticMethods; } JSClassExoticMethods;
typedef void JSClassFinalizer(JSRuntime *rt, JSValue val); typedef void JSClassFinalizer(JSRuntime *rt, JSValue val);
typedef void JSClassGCMark(JSRuntime *rt, JSValueConst val, typedef void JSClassGCMark(JSRuntime *rt, JSValue val,
JS_MarkFunc *mark_func); JS_MarkFunc *mark_func);
#define JS_CALL_FLAG_CONSTRUCTOR (1 << 0) #define JS_CALL_FLAG_CONSTRUCTOR (1 << 0)
typedef JSValue JSClassCall(JSContext *ctx, JSValueConst func_obj, typedef JSValue JSClassCall(JSContext *ctx, JSValue func_obj,
JSValueConst this_val, int argc, JSValueConst *argv, JSValue this_val, int argc, JSValue *argv,
int flags); int flags);
typedef struct JSClassDef { typedef struct JSClassDef {
const char *class_name; const char *class_name; /* pure ASCII only! */
JSClassFinalizer *finalizer; JSClassFinalizer *finalizer;
JSClassGCMark *gc_mark; JSClassGCMark *gc_mark;
/* if call != NULL, the object is a function. If (flags & /* if call != NULL, the object is a function. If (flags &
@ -486,7 +473,10 @@ typedef struct JSClassDef {
JSClassExoticMethods *exotic; JSClassExoticMethods *exotic;
} JSClassDef; } JSClassDef;
#define JS_INVALID_CLASS_ID 0
JS_EXTERN JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id); JS_EXTERN JSClassID JS_NewClassID(JSRuntime *rt, JSClassID *pclass_id);
/* Returns the class ID if `v` is an object, otherwise returns JS_INVALID_CLASS_ID. */
JS_EXTERN JSClassID JS_GetClassID(JSValue v);
JS_EXTERN int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def); JS_EXTERN int JS_NewClass(JSRuntime *rt, JSClassID class_id, const JSClassDef *class_def);
JS_EXTERN int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); JS_EXTERN int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id);
@ -502,6 +492,11 @@ static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
return JS_MKVAL(JS_TAG_INT, val); return JS_MKVAL(JS_TAG_INT, val);
} }
static js_force_inline JSValue JS_NewFloat64(JSContext *ctx, double val)
{
return __JS_NewFloat64(val);
}
static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val) static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
{ {
return JS_MKVAL(JS_TAG_CATCH_OFFSET, val); return JS_MKVAL(JS_TAG_CATCH_OFFSET, val);
@ -510,10 +505,10 @@ static js_force_inline JSValue JS_NewCatchOffset(JSContext *ctx, int32_t val)
static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val) static js_force_inline JSValue JS_NewInt64(JSContext *ctx, int64_t val)
{ {
JSValue v; JSValue v;
if (val == (int32_t)val) { if (val >= INT32_MIN && val <= INT32_MAX) {
v = JS_NewInt32(ctx, val); v = JS_NewInt32(ctx, (int32_t)val);
} else { } else {
v = __JS_NewFloat64(val); v = JS_NewFloat64(ctx, (double)val);
} }
return v; return v;
} }
@ -522,74 +517,75 @@ static js_force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
{ {
JSValue v; JSValue v;
if (val <= 0x7fffffff) { if (val <= 0x7fffffff) {
v = JS_NewInt32(ctx, val); v = JS_NewInt32(ctx, (int32_t)val);
} else { } else {
v = __JS_NewFloat64(val); v = JS_NewFloat64(ctx, (double)val);
} }
return v; return v;
} }
JS_EXTERN JSValue JS_NewFloat64(JSContext *ctx, double d); JS_EXTERN JSValue JS_NewNumber(JSContext *ctx, double d);
JS_EXTERN JSValue JS_NewBigInt64(JSContext *ctx, int64_t v); JS_EXTERN JSValue JS_NewBigInt64(JSContext *ctx, int64_t v);
JS_EXTERN JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v); JS_EXTERN JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v);
static inline JS_BOOL JS_IsNumber(JSValueConst v) static inline JS_BOOL JS_IsNumber(JSValue v)
{ {
int tag = JS_VALUE_GET_TAG(v); int tag = JS_VALUE_GET_TAG(v);
return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag); return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
} }
static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v) static inline JS_BOOL JS_IsBigInt(JSContext *ctx, JSValue v)
{ {
int tag = JS_VALUE_GET_TAG(v); int tag = JS_VALUE_GET_TAG(v);
return tag == JS_TAG_BIG_INT; return tag == JS_TAG_BIG_INT;
} }
static inline JS_BOOL JS_IsBool(JSValueConst v) static inline JS_BOOL JS_IsBool(JSValue v)
{ {
return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL; return JS_VALUE_GET_TAG(v) == JS_TAG_BOOL;
} }
static inline JS_BOOL JS_IsNull(JSValueConst v) static inline JS_BOOL JS_IsNull(JSValue v)
{ {
return JS_VALUE_GET_TAG(v) == JS_TAG_NULL; return JS_VALUE_GET_TAG(v) == JS_TAG_NULL;
} }
static inline JS_BOOL JS_IsUndefined(JSValueConst v) static inline JS_BOOL JS_IsUndefined(JSValue v)
{ {
return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED; return JS_VALUE_GET_TAG(v) == JS_TAG_UNDEFINED;
} }
static inline JS_BOOL JS_IsException(JSValueConst v) static inline JS_BOOL JS_IsException(JSValue v)
{ {
return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION); return JS_VALUE_GET_TAG(v) == JS_TAG_EXCEPTION;
} }
static inline JS_BOOL JS_IsUninitialized(JSValueConst v) static inline JS_BOOL JS_IsUninitialized(JSValue v)
{ {
return js_unlikely(JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED); return JS_VALUE_GET_TAG(v) == JS_TAG_UNINITIALIZED;
} }
static inline JS_BOOL JS_IsString(JSValueConst v) static inline JS_BOOL JS_IsString(JSValue v)
{ {
return JS_VALUE_GET_TAG(v) == JS_TAG_STRING; return JS_VALUE_GET_TAG(v) == JS_TAG_STRING;
} }
static inline JS_BOOL JS_IsSymbol(JSValueConst v) static inline JS_BOOL JS_IsSymbol(JSValue v)
{ {
return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL; return JS_VALUE_GET_TAG(v) == JS_TAG_SYMBOL;
} }
static inline JS_BOOL JS_IsObject(JSValueConst v) static inline JS_BOOL JS_IsObject(JSValue v)
{ {
return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT; return JS_VALUE_GET_TAG(v) == JS_TAG_OBJECT;
} }
JS_EXTERN JSValue JS_Throw(JSContext *ctx, JSValue obj); JS_EXTERN JSValue JS_Throw(JSContext *ctx, JSValue obj);
JS_EXTERN JSValue JS_GetException(JSContext *ctx); JS_EXTERN JSValue JS_GetException(JSContext *ctx);
JS_EXTERN JS_BOOL JS_IsError(JSContext *ctx, JSValueConst val); JS_EXTERN JS_BOOL JS_IsError(JSContext *ctx, JSValue val);
JS_EXTERN void JS_ResetUncatchableError(JSContext *ctx); JS_EXTERN void JS_ResetUncatchableError(JSContext *ctx);
JS_EXTERN JSValue JS_NewError(JSContext *ctx); JS_EXTERN JSValue JS_NewError(JSContext *ctx);
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowPlainError(JSContext *ctx, const char *fmt, ...);
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...); JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowSyntaxError(JSContext *ctx, const char *fmt, ...);
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...); JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowTypeError(JSContext *ctx, const char *fmt, ...);
JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...); JS_EXTERN JSValue __js_printf_like(2, 3) JS_ThrowReferenceError(JSContext *ctx, const char *fmt, ...);
@ -618,101 +614,94 @@ static inline void JS_FreeValueRT(JSRuntime *rt, JSValue v)
} }
} }
static inline JSValue JS_DupValue(JSContext *ctx, JSValueConst v) static inline JSValue JS_DupValue(JSContext *ctx, JSValue v)
{ {
if (JS_VALUE_HAS_REF_COUNT(v)) { if (JS_VALUE_HAS_REF_COUNT(v)) {
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
p->ref_count++; p->ref_count++;
} }
return (JSValue)v; return v;
} }
static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValueConst v) static inline JSValue JS_DupValueRT(JSRuntime *rt, JSValue v)
{ {
if (JS_VALUE_HAS_REF_COUNT(v)) { if (JS_VALUE_HAS_REF_COUNT(v)) {
JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v); JSRefCountHeader *p = (JSRefCountHeader *)JS_VALUE_GET_PTR(v);
p->ref_count++; p->ref_count++;
} }
return (JSValue)v; return v;
} }
JS_EXTERN int JS_ToBool(JSContext *ctx, JSValueConst val); /* return -1 for JS_EXCEPTION */ JS_EXTERN int JS_ToBool(JSContext *ctx, JSValue val); /* return -1 for JS_EXCEPTION */
JS_EXTERN int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValueConst val); JS_EXTERN int JS_ToInt32(JSContext *ctx, int32_t *pres, JSValue val);
static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValueConst val) static inline int JS_ToUint32(JSContext *ctx, uint32_t *pres, JSValue val)
{ {
return JS_ToInt32(ctx, (int32_t*)pres, val); return JS_ToInt32(ctx, (int32_t*)pres, val);
} }
JS_EXTERN int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val); JS_EXTERN int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValue val);
JS_EXTERN int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val); JS_EXTERN int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValue val);
JS_EXTERN int JS_ToFloat64(JSContext *ctx, double *pres, JSValueConst val); JS_EXTERN int JS_ToFloat64(JSContext *ctx, double *pres, JSValue val);
/* return an exception if 'val' is a Number */ /* return an exception if 'val' is a Number */
JS_EXTERN int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val); JS_EXTERN int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValue val);
JS_EXTERN int JS_ToBigUint64(JSContext *ctx, uint64_t *pres, JSValue val);
/* same as JS_ToInt64() but allow BigInt */ /* same as JS_ToInt64() but allow BigInt */
JS_EXTERN int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val); JS_EXTERN int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValue val);
JS_EXTERN JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1); JS_EXTERN JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1);
JS_EXTERN JSValue JS_NewString(JSContext *ctx, const char *str); static inline JSValue JS_NewString(JSContext *ctx, const char *str) {
return JS_NewStringLen(ctx, str, strlen(str));
}
JS_EXTERN JSValue JS_NewAtomString(JSContext *ctx, const char *str); JS_EXTERN JSValue JS_NewAtomString(JSContext *ctx, const char *str);
JS_EXTERN JSValue JS_ToString(JSContext *ctx, JSValueConst val); JS_EXTERN JSValue JS_ToString(JSContext *ctx, JSValue val);
JS_EXTERN JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val); JS_EXTERN JSValue JS_ToPropertyKey(JSContext *ctx, JSValue val);
JS_EXTERN const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValueConst val1, JS_BOOL cesu8); JS_EXTERN const char *JS_ToCStringLen2(JSContext *ctx, size_t *plen, JSValue val1, JS_BOOL cesu8);
static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValueConst val1) static inline const char *JS_ToCStringLen(JSContext *ctx, size_t *plen, JSValue val1)
{ {
return JS_ToCStringLen2(ctx, plen, val1, 0); return JS_ToCStringLen2(ctx, plen, val1, 0);
} }
static inline const char *JS_ToCString(JSContext *ctx, JSValueConst val1) static inline const char *JS_ToCString(JSContext *ctx, JSValue val1)
{ {
return JS_ToCStringLen2(ctx, NULL, val1, 0); return JS_ToCStringLen2(ctx, NULL, val1, 0);
} }
JS_EXTERN void JS_FreeCString(JSContext *ctx, const char *ptr); JS_EXTERN void JS_FreeCString(JSContext *ctx, const char *ptr);
JS_EXTERN JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValueConst proto, JSClassID class_id); JS_EXTERN JSValue JS_NewObjectProtoClass(JSContext *ctx, JSValue proto, JSClassID class_id);
JS_EXTERN JSValue JS_NewObjectClass(JSContext *ctx, int class_id); JS_EXTERN JSValue JS_NewObjectClass(JSContext *ctx, int class_id);
JS_EXTERN JSValue JS_NewObjectProto(JSContext *ctx, JSValueConst proto); JS_EXTERN JSValue JS_NewObjectProto(JSContext *ctx, JSValue proto);
JS_EXTERN JSValue JS_NewObject(JSContext *ctx); JS_EXTERN JSValue JS_NewObject(JSContext *ctx);
JS_EXTERN JS_BOOL JS_IsFunction(JSContext* ctx, JSValueConst val); JS_EXTERN JS_BOOL JS_IsFunction(JSContext* ctx, JSValue val);
JS_EXTERN JS_BOOL JS_IsConstructor(JSContext* ctx, JSValueConst val); JS_EXTERN JS_BOOL JS_IsConstructor(JSContext* ctx, JSValue val);
JS_EXTERN JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValueConst func_obj, JS_BOOL val); JS_EXTERN JS_BOOL JS_SetConstructorBit(JSContext *ctx, JSValue func_obj, JS_BOOL val);
JS_EXTERN JSValue JS_NewArray(JSContext *ctx); JS_EXTERN JSValue JS_NewArray(JSContext *ctx);
JS_EXTERN int JS_IsArray(JSContext *ctx, JSValueConst val); JS_EXTERN int JS_IsArray(JSContext *ctx, JSValue val);
JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms); JS_EXTERN JSValue JS_NewDate(JSContext *ctx, double epoch_ms);
JS_EXTERN JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, JS_EXTERN JSValue JS_GetProperty(JSContext *ctx, JSValue this_obj, JSAtom prop);
JSAtom prop, JSValueConst receiver, JS_EXTERN JSValue JS_GetPropertyUint32(JSContext *ctx, JSValue this_obj,
JS_BOOL throw_ref_error);
static js_force_inline JSValue JS_GetProperty(JSContext *ctx, JSValueConst this_obj,
JSAtom prop)
{
return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, 0);
}
JS_EXTERN JSValue JS_GetPropertyStr(JSContext *ctx, JSValueConst this_obj,
const char *prop);
JS_EXTERN JSValue JS_GetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
uint32_t idx); uint32_t idx);
JS_EXTERN JSValue JS_GetPropertyInt64(JSContext *ctx, JSValue this_obj,
int64_t idx);
JS_EXTERN JSValue JS_GetPropertyStr(JSContext *ctx, JSValue this_obj,
const char *prop);
int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_SetProperty(JSContext *ctx, JSValue this_obj,
JSAtom prop, JSValue val, JSAtom prop, JSValue val);
int flags); JS_EXTERN int JS_SetPropertyUint32(JSContext *ctx, JSValue this_obj,
static inline int JS_SetProperty(JSContext *ctx, JSValueConst this_obj,
JSAtom prop, JSValue val)
{
return JS_SetPropertyInternal(ctx, this_obj, prop, val, JS_PROP_THROW);
}
JS_EXTERN int JS_SetPropertyUint32(JSContext *ctx, JSValueConst this_obj,
uint32_t idx, JSValue val); uint32_t idx, JSValue val);
JS_EXTERN int JS_SetPropertyInt64(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_SetPropertyInt64(JSContext *ctx, JSValue this_obj,
int64_t idx, JSValue val); int64_t idx, JSValue val);
JS_EXTERN int JS_SetPropertyStr(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_SetPropertyStr(JSContext *ctx, JSValue this_obj,
const char *prop, JSValue val); const char *prop, JSValue val);
JS_EXTERN int JS_HasProperty(JSContext *ctx, JSValueConst this_obj, JSAtom prop); JS_EXTERN int JS_HasProperty(JSContext *ctx, JSValue this_obj, JSAtom prop);
JS_EXTERN int JS_IsExtensible(JSContext *ctx, JSValueConst obj); JS_EXTERN int JS_IsExtensible(JSContext *ctx, JSValue obj);
JS_EXTERN int JS_PreventExtensions(JSContext *ctx, JSValueConst obj); JS_EXTERN int JS_PreventExtensions(JSContext *ctx, JSValue obj);
JS_EXTERN int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags); JS_EXTERN int JS_DeleteProperty(JSContext *ctx, JSValue obj, JSAtom prop, int flags);
JS_EXTERN int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val); JS_EXTERN int JS_SetPrototype(JSContext *ctx, JSValue obj, JSValue proto_val);
JS_EXTERN JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val); JS_EXTERN JSValue JS_GetPrototype(JSContext *ctx, JSValue val);
JS_EXTERN int JS_GetLength(JSContext *ctx, JSValue obj, int64_t *pres);
#define JS_GPN_STRING_MASK (1 << 0) #define JS_GPN_STRING_MASK (1 << 0)
#define JS_GPN_SYMBOL_MASK (1 << 1) #define JS_GPN_SYMBOL_MASK (1 << 1)
@ -723,67 +712,71 @@ JS_EXTERN JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
#define JS_GPN_SET_ENUM (1 << 5) #define JS_GPN_SET_ENUM (1 << 5)
JS_EXTERN int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab, JS_EXTERN int JS_GetOwnPropertyNames(JSContext *ctx, JSPropertyEnum **ptab,
uint32_t *plen, JSValueConst obj, int flags); uint32_t *plen, JSValue obj, int flags);
JS_EXTERN int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc, JS_EXTERN int JS_GetOwnProperty(JSContext *ctx, JSPropertyDescriptor *desc,
JSValueConst obj, JSAtom prop); JSValue obj, JSAtom prop);
JS_EXTERN void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab,
uint32_t len);
JS_EXTERN JSValue JS_Call(JSContext *ctx, JSValueConst func_obj, JSValueConst this_obj, JS_EXTERN JSValue JS_Call(JSContext *ctx, JSValue func_obj, JSValue this_obj,
int argc, JSValueConst *argv); int argc, JSValue *argv);
JS_EXTERN JSValue JS_Invoke(JSContext *ctx, JSValueConst this_val, JSAtom atom, JS_EXTERN JSValue JS_Invoke(JSContext *ctx, JSValue this_val, JSAtom atom,
int argc, JSValueConst *argv); int argc, JSValue *argv);
JS_EXTERN JSValue JS_CallConstructor(JSContext *ctx, JSValueConst func_obj, JS_EXTERN JSValue JS_CallConstructor(JSContext *ctx, JSValue func_obj,
int argc, JSValueConst *argv); int argc, JSValue *argv);
JS_EXTERN JSValue JS_CallConstructor2(JSContext *ctx, JSValueConst func_obj, JS_EXTERN JSValue JS_CallConstructor2(JSContext *ctx, JSValue func_obj,
JSValueConst new_target, JSValue new_target,
int argc, JSValueConst *argv); int argc, JSValue *argv);
JS_EXTERN JS_BOOL JS_DetectModule(const char *input, size_t input_len); JS_EXTERN JS_BOOL JS_DetectModule(const char *input, size_t input_len);
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */
JS_EXTERN JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len, JS_EXTERN JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
const char *filename, int eval_flags); const char *filename, int eval_flags);
/* same as JS_Eval() but with an explicit 'this_obj' parameter */ /* same as JS_Eval() but with an explicit 'this_obj' parameter */
JS_EXTERN JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj, JS_EXTERN JSValue JS_EvalThis(JSContext *ctx, JSValue this_obj,
const char *input, size_t input_len, const char *input, size_t input_len,
const char *filename, int eval_flags); const char *filename, int eval_flags);
JS_EXTERN JSValue JS_GetGlobalObject(JSContext *ctx); JS_EXTERN JSValue JS_GetGlobalObject(JSContext *ctx);
JS_EXTERN int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj); JS_EXTERN int JS_IsInstanceOf(JSContext *ctx, JSValue val, JSValue obj);
JS_EXTERN int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_DefineProperty(JSContext *ctx, JSValue this_obj,
JSAtom prop, JSValueConst val, JSAtom prop, JSValue val,
JSValueConst getter, JSValueConst setter, int flags); JSValue getter, JSValue setter, int flags);
JS_EXTERN int JS_DefinePropertyValue(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_DefinePropertyValue(JSContext *ctx, JSValue this_obj,
JSAtom prop, JSValue val, int flags); JSAtom prop, JSValue val, int flags);
JS_EXTERN int JS_DefinePropertyValueUint32(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_DefinePropertyValueUint32(JSContext *ctx, JSValue this_obj,
uint32_t idx, JSValue val, int flags); uint32_t idx, JSValue val, int flags);
JS_EXTERN int JS_DefinePropertyValueStr(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_DefinePropertyValueStr(JSContext *ctx, JSValue this_obj,
const char *prop, JSValue val, int flags); const char *prop, JSValue val, int flags);
JS_EXTERN int JS_DefinePropertyGetSet(JSContext *ctx, JSValueConst this_obj, JS_EXTERN int JS_DefinePropertyGetSet(JSContext *ctx, JSValue this_obj,
JSAtom prop, JSValue getter, JSValue setter, JSAtom prop, JSValue getter, JSValue setter,
int flags); int flags);
JS_EXTERN void JS_SetOpaque(JSValue obj, void *opaque); JS_EXTERN void JS_SetOpaque(JSValue obj, void *opaque);
JS_EXTERN void *JS_GetOpaque(JSValueConst obj, JSClassID class_id); JS_EXTERN void *JS_GetOpaque(JSValue obj, JSClassID class_id);
JS_EXTERN void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); JS_EXTERN void *JS_GetOpaque2(JSContext *ctx, JSValue obj, JSClassID class_id);
JS_EXTERN void *JS_GetAnyOpaque(JSValueConst obj, JSClassID *class_id); JS_EXTERN void *JS_GetAnyOpaque(JSValue obj, JSClassID *class_id);
/* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */ /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
JS_EXTERN JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, JS_EXTERN JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
const char *filename); const char *filename);
JS_EXTERN JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj, JS_EXTERN JSValue JS_JSONStringify(JSContext *ctx, JSValue obj,
JSValueConst replacer, JSValueConst space0); JSValue replacer, JSValue space0);
typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr); typedef void JSFreeArrayBufferDataFunc(JSRuntime *rt, void *opaque, void *ptr);
JS_EXTERN JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len, JS_EXTERN JSValue JS_NewArrayBuffer(JSContext *ctx, uint8_t *buf, size_t len,
JSFreeArrayBufferDataFunc *free_func, void *opaque, JSFreeArrayBufferDataFunc *free_func, void *opaque,
JS_BOOL is_shared); JS_BOOL is_shared);
JS_EXTERN JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len); JS_EXTERN JSValue JS_NewArrayBufferCopy(JSContext *ctx, const uint8_t *buf, size_t len);
JS_EXTERN void JS_DetachArrayBuffer(JSContext *ctx, JSValueConst obj); JS_EXTERN void JS_DetachArrayBuffer(JSContext *ctx, JSValue obj);
JS_EXTERN uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst obj); JS_EXTERN uint8_t *JS_GetArrayBuffer(JSContext *ctx, size_t *psize, JSValue obj);
JS_EXTERN uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValueConst obj); JS_EXTERN JS_BOOL JS_IsArrayBuffer(JSValue obj);
JS_EXTERN JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, JS_EXTERN uint8_t *JS_GetUint8Array(JSContext *ctx, size_t *psize, JSValue obj);
JS_EXTERN JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValue obj,
size_t *pbyte_offset, size_t *pbyte_offset,
size_t *pbyte_length, size_t *pbyte_length,
size_t *pbytes_per_element); size_t *pbytes_per_element);
JS_EXTERN JSValue JS_NewUint8Array(JSContext *ctx, uint8_t *buf, size_t len, JS_EXTERN JSValue JS_NewUint8Array(JSContext *ctx, uint8_t *buf, size_t len,
JSFreeArrayBufferDataFunc *free_func, void *opaque, JSFreeArrayBufferDataFunc *free_func, void *opaque,
JS_BOOL is_shared); JS_BOOL is_shared);
JS_EXTERN JS_BOOL JS_IsUint8Array(JSValue obj);
JS_EXTERN JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len); JS_EXTERN JSValue JS_NewUint8ArrayCopy(JSContext *ctx, const uint8_t *buf, size_t len);
typedef struct { typedef struct {
void *(*sab_alloc)(void *opaque, size_t size); void *(*sab_alloc)(void *opaque, size_t size);
@ -793,11 +786,21 @@ typedef struct {
} JSSharedArrayBufferFunctions; } JSSharedArrayBufferFunctions;
JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf); JS_EXTERN void JS_SetSharedArrayBufferFunctions(JSRuntime *rt, const JSSharedArrayBufferFunctions *sf);
typedef enum JSPromiseStateEnum {
JS_PROMISE_PENDING,
JS_PROMISE_FULFILLED,
JS_PROMISE_REJECTED,
} JSPromiseStateEnum;
JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs); JS_EXTERN JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
JS_EXTERN JSValue JS_NewSymbol(JSContext *ctx, const char *description, JS_BOOL is_global);
/* is_handled = TRUE means that the rejection is handled */ /* is_handled = TRUE means that the rejection is handled */
typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValueConst promise, typedef void JSHostPromiseRejectionTracker(JSContext *ctx, JSValue promise,
JSValueConst reason, JSValue reason,
JS_BOOL is_handled, void *opaque); JS_BOOL is_handled, void *opaque);
JS_EXTERN void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque); JS_EXTERN void JS_SetHostPromiseRejectionTracker(JSRuntime *rt, JSHostPromiseRejectionTracker *cb, void *opaque);
@ -807,7 +810,7 @@ JS_EXTERN void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, voi
/* if can_block is TRUE, Atomics.wait() can be used */ /* if can_block is TRUE, Atomics.wait() can be used */
JS_EXTERN void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); JS_EXTERN void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);
/* set the [IsHTMLDDA] internal slot */ /* set the [IsHTMLDDA] internal slot */
JS_EXTERN void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj); JS_EXTERN void JS_SetIsHTMLDDA(JSContext *ctx, JSValue obj);
typedef struct JSModuleDef JSModuleDef; typedef struct JSModuleDef JSModuleDef;
@ -827,11 +830,12 @@ JS_EXTERN void JS_SetModuleLoaderFunc(JSRuntime *rt,
/* return the import.meta object of a module */ /* return the import.meta object of a module */
JS_EXTERN JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m); JS_EXTERN JSValue JS_GetImportMeta(JSContext *ctx, JSModuleDef *m);
JS_EXTERN JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m); JS_EXTERN JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m);
JSValue JS_GetModuleNamespace(JSContext *ctx, JSModuleDef *m);
/* JS Job support */ /* JS Job support */
typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValueConst *argv); typedef JSValue JSJobFunc(JSContext *ctx, int argc, JSValue *argv);
JS_EXTERN int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValueConst *argv); JS_EXTERN int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func, int argc, JSValue *argv);
JS_EXTERN JS_BOOL JS_IsJobPending(JSRuntime *rt); JS_EXTERN JS_BOOL JS_IsJobPending(JSRuntime *rt);
JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx); JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
@ -840,15 +844,15 @@ JS_EXTERN int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */ #define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */ #define JS_WRITE_OBJ_BSWAP (0) /* byte swapped output (obsolete, handled transparently) */
#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ #define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to #define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to encode arbitrary object graph */
encode arbitrary object #define JS_WRITE_OBJ_STRIP_SOURCE (1 << 4) /* do not write source code information */
graph */ #define JS_WRITE_OBJ_STRIP_DEBUG (1 << 5) /* do not write debug information */
JS_EXTERN uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, int flags); JS_EXTERN uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValue obj, int flags);
JS_EXTERN uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj, JS_EXTERN uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValue obj,
int flags, uint8_t ***psab_tab, size_t *psab_tab_len); int flags, uint8_t ***psab_tab, size_t *psab_tab_len);
#define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */ #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */
#define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */ #define JS_READ_OBJ_ROM_DATA (0) /* avoid duplicating 'buf' data (obsolete, broken by ICs) */
#define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */ #define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
JS_EXTERN JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags); JS_EXTERN JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags);
@ -857,13 +861,13 @@ JS_EXTERN JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_l
JS_EXTERN JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj); JS_EXTERN JSValue JS_EvalFunction(JSContext *ctx, JSValue fun_obj);
/* load the dependencies of the module 'obj'. Useful when JS_ReadObject() /* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
returns a module. */ returns a module. */
JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValueConst obj); JS_EXTERN int JS_ResolveModule(JSContext *ctx, JSValue obj);
/* only exported for os.Worker() */ /* only exported for os.Worker() */
JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels); JS_EXTERN JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
/* only exported for os.Worker() */ /* only exported for os.Worker() */
JS_EXTERN JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, JS_EXTERN JSValue JS_LoadModule(JSContext *ctx, const char *basename,
const char *filename); const char *filename);
/* C function definition */ /* C function definition */
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
@ -884,18 +888,18 @@ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
typedef union JSCFunctionType { typedef union JSCFunctionType {
JSCFunction *generic; JSCFunction *generic;
JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); JSValue (*generic_magic)(JSContext *ctx, JSValue this_val, int argc, JSValue *argv, int magic);
JSCFunction *constructor; JSCFunction *constructor;
JSValue (*constructor_magic)(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv, int magic); JSValue (*constructor_magic)(JSContext *ctx, JSValue new_target, int argc, JSValue *argv, int magic);
JSCFunction *constructor_or_func; JSCFunction *constructor_or_func;
double (*f_f)(double); double (*f_f)(double);
double (*f_f_f)(double, double); double (*f_f_f)(double, double);
JSValue (*getter)(JSContext *ctx, JSValueConst this_val); JSValue (*getter)(JSContext *ctx, JSValue this_val);
JSValue (*setter)(JSContext *ctx, JSValueConst this_val, JSValueConst val); JSValue (*setter)(JSContext *ctx, JSValue this_val, JSValue val);
JSValue (*getter_magic)(JSContext *ctx, JSValueConst this_val, int magic); JSValue (*getter_magic)(JSContext *ctx, JSValue this_val, int magic);
JSValue (*setter_magic)(JSContext *ctx, JSValueConst this_val, JSValueConst val, int magic); JSValue (*setter_magic)(JSContext *ctx, JSValue this_val, JSValue val, int magic);
JSValue (*iterator_next)(JSContext *ctx, JSValueConst this_val, JSValue (*iterator_next)(JSContext *ctx, JSValue this_val,
int argc, JSValueConst *argv, int *pdone, int magic); int argc, JSValue *argv, int *pdone, int magic);
} JSCFunctionType; } JSCFunctionType;
JS_EXTERN JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, JS_EXTERN JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
@ -903,7 +907,7 @@ JS_EXTERN JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
int length, JSCFunctionEnum cproto, int magic); int length, JSCFunctionEnum cproto, int magic);
JS_EXTERN JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, JS_EXTERN JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func,
int length, int magic, int data_len, int length, int magic, int data_len,
JSValueConst *data); JSValue *data);
static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name,
int length) int length)
@ -919,13 +923,13 @@ static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *fun
JSCFunctionType ft = { .generic_magic = func }; JSCFunctionType ft = { .generic_magic = func };
return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic); return JS_NewCFunction2(ctx, ft.generic, name, length, cproto, magic);
} }
JS_EXTERN void JS_SetConstructor(JSContext *ctx, JSValueConst func_obj, JS_EXTERN void JS_SetConstructor(JSContext *ctx, JSValue func_obj,
JSValueConst proto); JSValue proto);
/* C property definition */ /* C property definition */
typedef struct JSCFunctionListEntry { typedef struct JSCFunctionListEntry {
const char *name; const char *name; /* pure ASCII or UTF-8 encoded */
uint8_t prop_flags; uint8_t prop_flags;
uint8_t def_type; uint8_t def_type;
int16_t magic; int16_t magic;
@ -947,7 +951,7 @@ typedef struct JSCFunctionListEntry {
const struct JSCFunctionListEntry *tab; const struct JSCFunctionListEntry *tab;
int len; int len;
} prop_list; } prop_list;
const char *str; const char *str; /* pure ASCII or UTF-8 encoded */
int32_t i32; int32_t i32;
int64_t i64; int64_t i64;
double f64; double f64;
@ -966,23 +970,23 @@ typedef struct JSCFunctionListEntry {
#define JS_DEF_ALIAS 9 #define JS_DEF_ALIAS 9
/* Note: c++ does not like nested designators */ /* Note: c++ does not like nested designators */
#define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } #define JS_CFUNC_DEF(name, length, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
#define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } } #define JS_CFUNC_DEF2(name, length, func1, prop_flags) { name, prop_flags, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } } #define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }
#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } } #define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, 0, { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }
#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } } #define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_CFUNC, magic, { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }
#define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, .u = { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } } #define JS_CGETSET_DEF(name, fgetter, fsetter) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET, 0, { .getset = { .get = { .getter = fgetter }, .set = { .setter = fsetter } } } }
#define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, .u = { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } } #define JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) { name, JS_PROP_CONFIGURABLE, JS_DEF_CGETSET_MAGIC, magic, { .getset = { .get = { .getter_magic = fgetter }, .set = { .setter_magic = fsetter } } } }
#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } } #define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, { .str = cstr } }
#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } } #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, { .i32 = val } }
#define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, .u = { .i64 = val } } #define JS_PROP_INT64_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT64, 0, { .i64 = val } }
#define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, .u = { .f64 = val } } #define JS_PROP_DOUBLE_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_DOUBLE, 0, { .f64 = val } }
#define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, .u = { .i32 = 0 } } #define JS_PROP_UNDEFINED_DEF(name, prop_flags) { name, prop_flags, JS_DEF_PROP_UNDEFINED, 0, { .i32 = 0 } }
#define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, .u = { .prop_list = { tab, len } } } #define JS_OBJECT_DEF(name, tab, len, prop_flags) { name, prop_flags, JS_DEF_OBJECT, 0, { .prop_list = { tab, len } } }
#define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, -1 } } } #define JS_ALIAS_DEF(name, from) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, -1 } } }
#define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, .u = { .alias = { from, base } } } #define JS_ALIAS_BASE_DEF(name, from, base) { name, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, JS_DEF_ALIAS, 0, { .alias = { from, base } } }
JS_EXTERN void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj, JS_EXTERN void JS_SetPropertyFunctionList(JSContext *ctx, JSValue obj,
const JSCFunctionListEntry *tab, const JSCFunctionListEntry *tab,
int len); int len);
@ -1002,28 +1006,16 @@ JS_EXTERN int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *exp
JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m, JS_EXTERN int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
const JSCFunctionListEntry *tab, int len); const JSCFunctionListEntry *tab, int len);
/* Promise */
typedef enum JSPromiseStateEnum {
JS_PROMISE_PENDING,
JS_PROMISE_FULFILLED,
JS_PROMISE_REJECTED,
} JSPromiseStateEnum;
JS_EXTERN JSPromiseStateEnum JS_PromiseState(JSContext *ctx, JSValue promise);
JS_EXTERN JSValue JS_PromiseResult(JSContext *ctx, JSValue promise);
/* Version */ /* Version */
#define QJS_VERSION_MAJOR 0 #define QJS_VERSION_MAJOR 0
#define QJS_VERSION_MINOR 3 #define QJS_VERSION_MINOR 6
#define QJS_VERSION_PATCH 0 #define QJS_VERSION_PATCH 0
#define QJS_VERSION_SUFFIX "dev" #define QJS_VERSION_SUFFIX "dev"
JS_EXTERN const char* JS_GetVersion(void); JS_EXTERN const char* JS_GetVersion(void);
#undef JS_EXTERN #undef JS_EXTERN
#undef js_unlikely
#undef js_force_inline #undef js_force_inline
#undef __js_printf_like #undef __js_printf_like

953
repl.js

File diff suppressed because it is too large Load diff

View file

@ -371,8 +371,8 @@ static void enumerate_tests(const char *path)
namelist_cmp_indirect); namelist_cmp_indirect);
} }
static JSValue js_print(JSContext *ctx, JSValueConst this_val, static JSValue js_print(JSContext *ctx, JSValue this_val,
int argc, JSValueConst *argv) int argc, JSValue *argv)
{ {
int i; int i;
const char *str; const char *str;
@ -508,7 +508,7 @@ static void *agent_start(void *arg)
NULL, NULL, TRUE); NULL, NULL, TRUE);
args[1] = JS_NewInt32(ctx, agent->broadcast_val); args[1] = JS_NewInt32(ctx, agent->broadcast_val);
ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED, ret_val = JS_Call(ctx, agent->broadcast_func, JS_UNDEFINED,
2, (JSValueConst *)args); 2, args);
JS_FreeValue(ctx, args[0]); JS_FreeValue(ctx, args[0]);
JS_FreeValue(ctx, args[1]); JS_FreeValue(ctx, args[1]);
if (JS_IsException(ret_val)) if (JS_IsException(ret_val))
@ -594,7 +594,7 @@ static BOOL is_broadcast_pending(void)
static JSValue js_agent_broadcast(JSContext *ctx, JSValue this_val, static JSValue js_agent_broadcast(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv) int argc, JSValue *argv)
{ {
JSValueConst sab = argv[0]; JSValue sab = argv[0];
struct list_head *el; struct list_head *el;
Test262Agent *agent; Test262Agent *agent;
uint8_t *buf; uint8_t *buf;
@ -820,6 +820,19 @@ static JSModuleDef *js_module_loader_test(JSContext *ctx,
uint8_t *buf; uint8_t *buf;
JSModuleDef *m; JSModuleDef *m;
JSValue func_val; JSValue func_val;
char *filename, *slash, path[1024];
// interpret import("bar.js") from path/to/foo.js as
// import("path/to/bar.js") but leave import("./bar.js") untouched
filename = opaque;
if (!strchr(module_name, '/')) {
slash = strrchr(filename, '/');
if (slash) {
snprintf(path, sizeof(path), "%.*s/%s",
(int) (slash - filename), filename, module_name);
module_name = path;
}
}
buf = js_load_file(ctx, &buf_len, module_name); buf = js_load_file(ctx, &buf_len, module_name);
if (!buf) { if (!buf) {
@ -1185,7 +1198,7 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
{ {
JSValue res_val, exception_val; JSValue res_val, exception_val;
int ret, error_line, pos, pos_line; int ret, error_line, pos, pos_line;
BOOL is_error, has_error_line; BOOL is_error, has_error_line, ret_promise;
const char *error_name; const char *error_name;
pos = skip_comments(buf, 1, &pos_line); pos = skip_comments(buf, 1, &pos_line);
@ -1194,12 +1207,19 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
exception_val = JS_UNDEFINED; exception_val = JS_UNDEFINED;
error_name = NULL; error_name = NULL;
/* a module evaluation returns a promise */
ret_promise = ((eval_flags & JS_EVAL_TYPE_MODULE) != 0);
async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */ async_done = 0; /* counter of "Test262:AsyncTestComplete" messages */
res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags); res_val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
if (is_async && !JS_IsException(res_val)) { if ((is_async || ret_promise) && !JS_IsException(res_val)) {
JS_FreeValue(ctx, res_val); JSValue promise = JS_UNDEFINED;
if (ret_promise) {
promise = res_val;
} else {
JS_FreeValue(ctx, res_val);
}
for(;;) { for(;;) {
JSContext *ctx1; JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
@ -1207,37 +1227,26 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
res_val = JS_EXCEPTION; res_val = JS_EXCEPTION;
break; break;
} else if (ret == 0) { } else if (ret == 0) {
/* test if the test called $DONE() once */ if (is_async) {
if (async_done != 1) { /* test if the test called $DONE() once */
res_val = JS_ThrowTypeError(ctx, "$DONE() not called"); if (async_done != 1) {
res_val = JS_ThrowTypeError(ctx, "$DONE() not called");
} else {
res_val = JS_UNDEFINED;
}
} else { } else {
res_val = JS_UNDEFINED; /* check that the returned promise is fulfilled */
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
if (state == JS_PROMISE_FULFILLED)
res_val = JS_UNDEFINED;
else if (state == JS_PROMISE_REJECTED)
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
else
res_val = JS_ThrowTypeError(ctx, "promise is pending");
} }
break; break;
} }
} }
} else if ((eval_flags & JS_EVAL_TYPE_MODULE) &&
!JS_IsUndefined(res_val) &&
!JS_IsException(res_val)) {
JSValue promise = res_val;
for(;;) {
JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
if (ret < 0) {
res_val = JS_EXCEPTION;
break;
}
if (ret == 0) {
JSPromiseStateEnum s = JS_PromiseState(ctx, promise);
if (s == JS_PROMISE_FULFILLED)
res_val = JS_UNDEFINED;
else if (s == JS_PROMISE_REJECTED)
res_val = JS_Throw(ctx, JS_PromiseResult(ctx, promise));
else
res_val = JS_EXCEPTION;
break;
}
}
JS_FreeValue(ctx, promise); JS_FreeValue(ctx, promise);
} }
@ -1286,11 +1295,15 @@ static int eval_buf(JSContext *ctx, const char *buf, size_t buf_len,
const char *msg; const char *msg;
msg = JS_ToCString(ctx, exception_val); msg = JS_ToCString(ctx, exception_val);
error_class = strdup_len(msg, strcspn(msg, ":")); if (msg == NULL) {
if (!str_equal(error_class, error_type))
ret = -1; ret = -1;
free(error_class); } else {
JS_FreeCString(ctx, msg); error_class = strdup_len(msg, strcspn(msg, ":"));
if (!str_equal(error_class, error_type))
ret = -1;
free(error_class);
JS_FreeCString(ctx, msg);
}
} }
} else { } else {
ret = -1; ret = -1;
@ -1490,7 +1503,9 @@ void update_stats(JSRuntime *rt, const char *filename) {
JS_ComputeMemoryUsage(rt, &stats); JS_ComputeMemoryUsage(rt, &stats);
if (stats_count++ == 0) { if (stats_count++ == 0) {
stats_avg = stats_all = stats_min = stats_max = stats; stats_avg = stats_all = stats_min = stats_max = stats;
free(stats_min_filename);
stats_min_filename = strdup(filename); stats_min_filename = strdup(filename);
free(stats_max_filename);
stats_max_filename = strdup(filename); stats_max_filename = strdup(filename);
} else { } else {
if (stats_max.malloc_size < stats.malloc_size) { if (stats_max.malloc_size < stats.malloc_size) {
@ -1555,7 +1570,7 @@ int run_test_buf(const char *filename, char *harness, namelist_t *ip,
JS_SetCanBlock(rt, can_block); JS_SetCanBlock(rt, can_block);
/* loader for ES6 modules */ /* loader for ES6 modules */
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL); JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *) filename);
add_helpers(ctx); add_helpers(ctx);
@ -1851,7 +1866,7 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
JS_SetCanBlock(rt, can_block); JS_SetCanBlock(rt, can_block);
/* loader for ES6 modules */ /* loader for ES6 modules */
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, NULL); JS_SetModuleLoaderFunc(rt, NULL, js_module_loader_test, (void *) filename);
add_helpers(ctx); add_helpers(ctx);
@ -1868,17 +1883,32 @@ int run_test262_harness_test(const char *filename, BOOL is_module)
js_std_dump_error(ctx); js_std_dump_error(ctx);
ret_code = 1; ret_code = 1;
} else { } else {
JS_FreeValue(ctx, res_val); JSValue promise = JS_UNDEFINED;
if (is_module) {
promise = res_val;
} else {
JS_FreeValue(ctx, res_val);
}
for(;;) { for(;;) {
JSContext *ctx1; JSContext *ctx1;
ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1); ret = JS_ExecutePendingJob(JS_GetRuntime(ctx), &ctx1);
if (ret < 0) { if (ret < 0) {
js_std_dump_error(ctx1); js_std_dump_error(ctx1);
ret_code = 1; ret_code = 1;
} else if (ret == 0) { } else if (ret == 0) {
break; break;
} }
} }
/* dump the error if the module returned an error. */
if (is_module) {
JSPromiseStateEnum state = JS_PromiseState(ctx, promise);
if (state == JS_PROMISE_REJECTED) {
JS_Throw(ctx, JS_PromiseResult(ctx, promise));
js_std_dump_error(ctx);
ret_code = 1;
}
}
JS_FreeValue(ctx, promise);
} }
free(buf); free(buf);
#ifdef CONFIG_AGENT #ifdef CONFIG_AGENT
@ -2165,7 +2195,12 @@ int main(int argc, char **argv)
free(harness_dir); free(harness_dir);
free(harness_features); free(harness_features);
free(harness_exclude); free(harness_exclude);
free(harness_skip_features);
free(error_file); free(error_file);
free(error_filename);
free(report_filename);
free(stats_min_filename);
free(stats_max_filename);
/* Signal that the error file is out of date. */ /* Signal that the error file is out of date. */
return new_errors || changed_errors || fixed_errors; return new_errors || changed_errors || fixed_errors;

132
test262-fast.conf Normal file
View file

@ -0,0 +1,132 @@
[exclude]
# list excluded tests and directories here for faster operation
# lengthy constructed regexp (>500 ms)
test262/test/annexB/built-ins/RegExp/RegExp-leading-escape-BMP.js
test262/test/annexB/built-ins/RegExp/RegExp-trailing-escape-BMP.js
# slow notifications (> 600 ms)
test262/test/built-ins/Atomics/notify/notify-in-order-one-time.js
test262/test/built-ins/Atomics/notify/notify-in-order.js
test262/test/built-ins/Atomics/wait/bigint/waiterlist-order-of-operations-is-fifo.js
test262/test/built-ins/Atomics/wait/waiterlist-order-of-operations-is-fifo.js
# lengthy constructed regexp (>200 ms)
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-digit-class-escape-plus-quantifier-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-whitespace-class-escape-plus-quantifier-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-flags-u.js
test262/test/built-ins/RegExp/CharacterClassEscapes/character-class-non-word-class-escape-plus-quantifier-flags-u.js
test262/test/built-ins/RegExp/character-class-escape-non-whitespace.js
# 417 lengty tests with huge constructed regexp (>200 ms)
test262/test/built-ins/RegExp/property-escapes/generated/
# lengthy constructed URLS (>200 ms)
test262/test/built-ins/decodeURI/S15.1.3.1_A1.2_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.2_T2.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.10_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.11_T2.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T1.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T2.js
test262/test/built-ins/decodeURI/S15.1.3.1_A1.12_T3.js
test262/test/built-ins/decodeURI/S15.1.3.1_A2.5_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.2_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.2_T2.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.10_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.11_T2.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T2.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A1.12_T3.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.5_T1.js
# lengthy comment tests
test262/test/language/comments/S7.4_A5.js
test262/test/language/comments/S7.4_A6.js
# lengthy unicode level tests
test262/test/language/identifiers/start-unicode-5.2.0-class-escaped.js
test262/test/language/identifiers/start-unicode-5.2.0-class.js
test262/test/language/identifiers/start-unicode-8.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-8.0.0-class.js
test262/test/language/identifiers/start-unicode-9.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-9.0.0-class.js
test262/test/language/identifiers/start-unicode-10.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-10.0.0-class.js
test262/test/language/identifiers/start-unicode-13.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-13.0.0-class.js
test262/test/language/identifiers/start-unicode-15.0.0-class-escaped.js
test262/test/language/identifiers/start-unicode-15.0.0-class.js
# Atomics tests with 2 second delays
test262/test/built-ins/Atomics/notify/bigint/notify-all-on-loc.js
test262/test/built-ins/Atomics/notify/negative-count.js
test262/test/built-ins/Atomics/notify/notify-all-on-loc.js
test262/test/built-ins/Atomics/notify/notify-all.js
test262/test/built-ins/Atomics/notify/notify-nan.js
test262/test/built-ins/Atomics/notify/notify-one.js
test262/test/built-ins/Atomics/notify/notify-two.js
test262/test/built-ins/Atomics/notify/notify-zero.js
# Atomics tests with 400 millisecond delays
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-no-operation.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-add.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-and.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-compareExchange.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-exchange.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-or.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-store.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-sub.js
test262/test/built-ins/Atomics/wait/bigint/no-spurious-wakeup-on-xor.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-no-operation.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-add.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-and.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-compareExchange.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-exchange.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-or.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-store.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-sub.js
test262/test/built-ins/Atomics/wait/no-spurious-wakeup-on-xor.js
# Atomics tests with 200 millisecond delays
test262/test/built-ins/Atomics/notify/count-defaults-to-infinity-missing.js
test262/test/built-ins/Atomics/notify/count-defaults-to-infinity-undefined.js
test262/test/built-ins/Atomics/notify/notify-renotify-noop.js
test262/test/built-ins/Atomics/notify/undefined-index-defaults-to-zero.js
test262/test/built-ins/Atomics/wait/bigint/false-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/bigint/nan-for-timeout.js
test262/test/built-ins/Atomics/wait/bigint/negative-timeout-agent.js
test262/test/built-ins/Atomics/wait/bigint/value-not-equal.js
test262/test/built-ins/Atomics/wait/bigint/was-woken-before-timeout.js
test262/test/built-ins/Atomics/wait/false-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/nan-for-timeout.js
test262/test/built-ins/Atomics/wait/negative-timeout-agent.js
test262/test/built-ins/Atomics/wait/null-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/object-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/poisoned-object-for-timeout-throws-agent.js
test262/test/built-ins/Atomics/wait/symbol-for-index-throws-agent.js
test262/test/built-ins/Atomics/wait/symbol-for-timeout-throws-agent.js
test262/test/built-ins/Atomics/wait/symbol-for-value-throws-agent.js
test262/test/built-ins/Atomics/wait/true-for-timeout-agent.js
test262/test/built-ins/Atomics/wait/undefined-for-timeout.js
test262/test/built-ins/Atomics/wait/undefined-index-defaults-to-zero.js
test262/test/built-ins/Atomics/wait/value-not-equal.js
test262/test/built-ins/Atomics/wait/wait-index-value-not-equal.js
test262/test/built-ins/Atomics/wait/was-woken-before-timeout.js
# lengthy regexp literal construction (>500 ms)
test262/test/language/literals/regexp/S7.8.5_A1.1_T2.js
test262/test/language/literals/regexp/S7.8.5_A1.4_T2.js
test262/test/language/literals/regexp/S7.8.5_A2.1_T2.js
test262/test/language/literals/regexp/S7.8.5_A2.4_T2.js
# lengthy built-ins tests (100-200 ms)
test262/test/built-ins/Function/prototype/toString/built-in-function-object.js
test262/test/built-ins/decodeURI/S15.1.3.1_A2.4_T1.js
test262/test/built-ins/decodeURIComponent/S15.1.3.2_A2.4_T1.js
test262/test/built-ins/encodeURI/S15.1.3.3_A2.3_T1.js
test262/test/built-ins/encodeURIComponent/S15.1.3.4_A2.3_T1.js
test262/test/language/expressions/dynamic-import/await-import-evaluation.js

View file

@ -69,7 +69,7 @@ arraybuffer-transfer
arrow-function arrow-function
async-functions async-functions
async-iteration async-iteration
Atomics=skip # disabled because of Windows <-> pthreads Atomics
Atomics.waitAsync=skip Atomics.waitAsync=skip
BigInt BigInt
caller caller
@ -157,7 +157,7 @@ regexp-lookbehind
regexp-match-indices regexp-match-indices
regexp-named-groups regexp-named-groups
regexp-unicode-property-escapes regexp-unicode-property-escapes
regexp-v-flag=skip regexp-v-flag
resizable-arraybuffer=skip resizable-arraybuffer=skip
rest-parameters rest-parameters
Set Set
@ -223,5 +223,147 @@ test262/test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
#test262/test/built-ins/RegExp/CharacterClassEscapes/ #test262/test/built-ins/RegExp/CharacterClassEscapes/
#test262/test/built-ins/RegExp/property-escapes/ #test262/test/built-ins/RegExp/property-escapes/
# in progress regexp-v-flag support, see https://github.com/quickjs-ng/quickjs/issues/228
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Basic_Emoji.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/Emoji_Keycap_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Flag_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Modifier_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_Tag_Sequence.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence-negative-CharacterClass.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence-negative-P.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence-negative-u.js
test262/test/built-ins/RegExp/property-escapes/generated/strings/RGI_Emoji_ZWJ_Sequence.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-escape-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-class-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-property-escape-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/character-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/property-of-strings-escape-union-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-13.1.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-14.0.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-15.0.js
test262/test/built-ins/RegExp/unicodeSets/generated/rgi-emoji-15.1.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-difference-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-intersection-string-literal.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character-class-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character-class.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character-property-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-character.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-property-of-strings-escape.js
test262/test/built-ins/RegExp/unicodeSets/generated/string-literal-union-string-literal.js
[tests] [tests]
# list test files or use config.testdir # list test files or use config.testdir

View file

@ -1,163 +1,12 @@
test262/test/annexB/language/eval-code/direct/script-decl-lex-collision-in-sloppy-mode.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all test262/test/annexB/language/eval-code/direct/script-decl-lex-collision-in-sloppy-mode.js:13: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/built-ins/AsyncGeneratorPrototype/return/return-suspendedYield-broken-promise-try-catch.js:39: TypeError: $DONE() not called
test262/test/built-ins/AsyncGeneratorPrototype/return/return-suspendedYield-broken-promise-try-catch.js:39: strict mode: TypeError: $DONE() not called
test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier
test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: strict mode: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier test262/test/built-ins/RegExp/lookahead-quantifier-match-groups.js:27: strict mode: Test262Error: Expected [a, abc] and [a, undefined] to have the same contents. ? quantifier
test262/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-no-throw.js:30: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-no-throw.js:30: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js:30: TypeError: ArrayBuffer is detached (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/sort/sort-tonumber.js:30: strict mode: TypeError: ArrayBuffer is detached (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toReversed/ignores-species.js:26: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toReversed/ignores-species.js:26: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toReversed/immutable.js:14: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toReversed/immutable.js:14: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toReversed/length-property-ignored.js:21: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toReversed/length-property-ignored.js:21: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toReversed/metadata/length.js:30: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toReversed/metadata/length.js:30: strict mode: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toReversed/metadata/name.js:28: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toReversed/metadata/name.js:28: strict mode: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toReversed/metadata/property-descriptor.js:18: Test262Error: typeof Expected SameValue(«undefined», «function») to be true
test262/test/built-ins/TypedArray/prototype/toReversed/metadata/property-descriptor.js:18: strict mode: Test262Error: typeof Expected SameValue(«undefined», «function») to be true
test262/test/built-ins/TypedArray/prototype/toReversed/not-a-constructor.js:25: Test262Error: isConstructor invoked with a non-function value
test262/test/built-ins/TypedArray/prototype/toReversed/not-a-constructor.js:25: strict mode: Test262Error: isConstructor invoked with a non-function value
test262/test/built-ins/TypedArray/prototype/toSorted/ignores-species.js:26: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toSorted/ignores-species.js:26: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toSorted/immutable.js:14: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toSorted/immutable.js:14: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toSorted/length-property-ignored.js:21: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toSorted/length-property-ignored.js:21: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/toSorted/metadata/length.js:30: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toSorted/metadata/length.js:30: strict mode: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toSorted/metadata/name.js:28: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toSorted/metadata/name.js:28: strict mode: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/toSorted/metadata/property-descriptor.js:18: Test262Error: typeof Expected SameValue(«undefined», «function») to be true
test262/test/built-ins/TypedArray/prototype/toSorted/metadata/property-descriptor.js:18: strict mode: Test262Error: typeof Expected SameValue(«undefined», «function») to be true
test262/test/built-ins/TypedArray/prototype/toSorted/not-a-constructor.js:25: Test262Error: isConstructor invoked with a non-function value
test262/test/built-ins/TypedArray/prototype/toSorted/not-a-constructor.js:25: strict mode: Test262Error: isConstructor invoked with a non-function value
test262/test/built-ins/TypedArray/prototype/with/BigInt/early-type-coercion-bigint.js:29: TypeError: not a function (Testing with BigInt64Array.)
test262/test/built-ins/TypedArray/prototype/with/BigInt/early-type-coercion-bigint.js:29: strict mode: TypeError: not a function (Testing with BigInt64Array.)
test262/test/built-ins/TypedArray/prototype/with/early-type-coercion.js:29: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/early-type-coercion.js:29: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/ignores-species.js:26: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/ignores-species.js:26: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/immutable.js:14: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/immutable.js:14: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-bigger-or-eq-than-length.js:22: Test262Error: Expected a RangeError but got a TypeError (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-bigger-or-eq-than-length.js:22: strict mode: Test262Error: Expected a RangeError but got a TypeError (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-casted-to-number.js:24: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-casted-to-number.js:24: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-negative.js:24: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-negative.js:24: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-smaller-than-minus-length.js:22: Test262Error: Expected a RangeError but got a TypeError (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/index-smaller-than-minus-length.js:22: strict mode: Test262Error: Expected a RangeError but got a TypeError (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/length-property-ignored.js:21: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/length-property-ignored.js:21: strict mode: TypeError: not a function (Testing with Float64Array.)
test262/test/built-ins/TypedArray/prototype/with/metadata/length.js:30: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/with/metadata/length.js:30: strict mode: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/with/metadata/name.js:28: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/with/metadata/name.js:28: strict mode: TypeError: cannot convert to object
test262/test/built-ins/TypedArray/prototype/with/metadata/property-descriptor.js:18: Test262Error: typeof Expected SameValue(«undefined», «function») to be true
test262/test/built-ins/TypedArray/prototype/with/metadata/property-descriptor.js:18: strict mode: Test262Error: typeof Expected SameValue(«undefined», «function») to be true
test262/test/built-ins/TypedArray/prototype/with/not-a-constructor.js:25: Test262Error: isConstructor invoked with a non-function value
test262/test/built-ins/TypedArray/prototype/with/not-a-constructor.js:25: strict mode: Test262Error: isConstructor invoked with a non-function value
test262/test/built-ins/TypedArrayConstructors/ctors/no-species.js:16: Test262Error: unreachable
test262/test/built-ins/TypedArrayConstructors/ctors/no-species.js:16: strict mode: Test262Error: unreachable
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/tonumber-value-detached-buffer.js:40: Test262Error: Reflect.defineProperty(ta, 0, {value: {valueOf() {$DETACHBUFFER(ta.buffer); return 42n;}}}) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/tonumber-value-detached-buffer.js:40: strict mode: Test262Error: Reflect.defineProperty(ta, 0, {value: {valueOf() {$DETACHBUFFER(ta.buffer); return 42n;}}}) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/tonumber-value-detached-buffer.js:42: Test262Error: Reflect.defineProperty(ta, 0, {value: {valueOf() {$DETACHBUFFER(ta.buffer); return 42;}}} ) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/tonumber-value-detached-buffer.js:42: strict mode: Test262Error: Reflect.defineProperty(ta, 0, {value: {valueOf() {$DETACHBUFFER(ta.buffer); return 42;}}} ) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: strict mode: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: strict mode: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: strict mode: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: strict mode: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: strict mode: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: unexpected error type: Test262: This statement should not be evaluated. test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: strict mode: unexpected error type: Test262: This statement should not be evaluated. test262/test/language/expressions/arrow-function/static-init-await-reference.js:12: strict mode: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/assignment/target-member-computed-reference-null.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/assignment/target-member-computed-reference-undefined.js:32: strict mode: Test262Error: Expected a DummyError but got a TypeError
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-add.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «3») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-add.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «3») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-bitand.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «0») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-bitand.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «0») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-bitor.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «15») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-bitor.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «15») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-bitxor.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «257») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-bitxor.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «257») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-div.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «0.5») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-div.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «0.5») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-exp.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1000») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-exp.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1000») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-lshift.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «96») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-lshift.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «96») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-mod.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-mod.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-mult.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «6») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-mult.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «6») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-rshift.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «3») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-rshift.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «3») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-srshift.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «3») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-srshift.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «3») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-sub.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1») to be true
test262/test/language/expressions/compound-assignment/left-hand-side-private-reference-accessor-property-sub.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1») to be true
test262/test/language/expressions/delete/super-property-null-base.js:26: Test262Error: Expected a ReferenceError but got a TypeError
test262/test/language/expressions/delete/super-property-null-base.js:26: strict mode: Test262Error: Expected a ReferenceError but got a TypeError
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
test262/test/language/expressions/function/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier test262/test/language/expressions/function/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier
test262/test/language/expressions/function/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier test262/test/language/expressions/function/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier
test262/test/language/expressions/generators/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier test262/test/language/expressions/generators/static-init-await-binding.js:16: SyntaxError: 'await' is a reserved identifier
test262/test/language/expressions/generators/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier test262/test/language/expressions/generators/static-init-await-binding.js:16: strict mode: SyntaxError: 'await' is a reserved identifier
test262/test/language/expressions/logical-assignment/left-hand-side-private-reference-accessor-property-and.js:60: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «false») to be true
test262/test/language/expressions/logical-assignment/left-hand-side-private-reference-accessor-property-and.js:60: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «false») to be true
test262/test/language/expressions/logical-assignment/left-hand-side-private-reference-accessor-property-nullish.js:59: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1») to be true
test262/test/language/expressions/logical-assignment/left-hand-side-private-reference-accessor-property-nullish.js:59: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «1») to be true
test262/test/language/expressions/logical-assignment/left-hand-side-private-reference-accessor-property-or.js:60: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «true») to be true
test262/test/language/expressions/logical-assignment/left-hand-side-private-reference-accessor-property-or.js:60: strict mode: Test262Error: The expression should evaluate to the result Expected SameValue(«undefined», «true») to be true
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:16: strict mode: TypeError: cannot read property '_b' of undefined
test262/test/language/global-code/script-decl-lex-var-declared-via-eval-sloppy.js:13: Test262Error: variable Expected a SyntaxError to be thrown but no exception was thrown at all test262/test/language/global-code/script-decl-lex-var-declared-via-eval-sloppy.js:13: Test262Error: variable Expected a SyntaxError to be thrown but no exception was thrown at all
test262/test/language/statements/async-generator/yield-star-promise-not-unwrapped.js:25: TypeError: $DONE() not called
test262/test/language/statements/async-generator/yield-star-promise-not-unwrapped.js:25: strict mode: TypeError: $DONE() not called
test262/test/language/statements/async-generator/yield-star-return-then-getter-ticks.js:131: TypeError: $DONE() not called
test262/test/language/statements/async-generator/yield-star-return-then-getter-ticks.js:131: strict mode: TypeError: $DONE() not called
test262/test/language/statements/class/elements/private-method-double-initialisation-get-and-set.js:33: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-get-and-set.js:33: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-get.js:32: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-get.js:32: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-set.js:32: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation-set.js:32: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation.js:32: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/elements/private-method-double-initialisation.js:32: strict mode: Test262Error: Expected a TypeError to be thrown but no exception was thrown at all
test262/test/language/statements/class/private-non-static-getter-static-setter-early-error.js:13: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/class/private-non-static-getter-static-setter-early-error.js:13: strict mode: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/class/private-non-static-setter-static-getter-early-error.js:13: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/class/private-non-static-setter-static-getter-early-error.js:13: strict mode: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/class/private-static-getter-non-static-setter-early-error.js:13: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/class/private-static-getter-non-static-setter-early-error.js:13: strict mode: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/class/private-static-setter-non-static-getter-early-error.js:13: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/class/private-static-setter-non-static-getter-early-error.js:13: strict mode: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated.
test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated.

View file

@ -24,8 +24,8 @@
#include "../quickjs-libc.h" #include "../quickjs-libc.h"
#include "../cutils.h" #include "../cutils.h"
static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val, static JSValue js_bjson_read(JSContext *ctx, JSValue this_val,
int argc, JSValueConst *argv) int argc, JSValue *argv)
{ {
uint8_t *buf; uint8_t *buf;
uint64_t pos, len; uint64_t pos, len;
@ -49,8 +49,8 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val,
return obj; return obj;
} }
static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val, static JSValue js_bjson_write(JSContext *ctx, JSValue this_val,
int argc, JSValueConst *argv) int argc, JSValue *argv)
{ {
size_t len; size_t len;
uint8_t *buf; uint8_t *buf;

14
tests/function_source.js Normal file
View file

@ -0,0 +1,14 @@
"use strict"
const expect = "function f() { return 42 }"
function f() { return 42 }
{
const actual = f.toString()
if (actual !== expect) throw Error(actual)
}
{
const f = eval(expect + "f")
const actual = f.toString()
if (actual !== expect) throw Error(actual)
}

View file

@ -876,9 +876,23 @@ function int_to_string(n)
var s, r, j; var s, r, j;
r = 0; r = 0;
for(j = 0; j < n; j++) { for(j = 0; j < n; j++) {
s = (j + 1).toString(); s = (j % 10) + '';
s = (j % 100) + '';
s = (j) + '';
} }
return n; return n * 3;
}
function int_toString(n)
{
var s, r, j;
r = 0;
for(j = 0; j < n; j++) {
s = (j % 10).toString();
s = (j % 100).toString();
s = (j).toString();
}
return n * 3;
} }
function float_to_string(n) function float_to_string(n)
@ -886,9 +900,59 @@ function float_to_string(n)
var s, r, j; var s, r, j;
r = 0; r = 0;
for(j = 0; j < n; j++) { for(j = 0; j < n; j++) {
s = (j + 0.1).toString(); s = (j % 10 + 0.1) + '';
s = (j + 0.1) + '';
s = (j * 12345678 + 0.1) + '';
} }
return n; return n * 3;
}
function float_toString(n)
{
var s, r, j;
r = 0;
for(j = 0; j < n; j++) {
s = (j % 10 + 0.1).toString();
s = (j + 0.1).toString();
s = (j * 12345678 + 0.1).toString();
}
return n * 3;
}
function float_toFixed(n)
{
var s, r, j;
r = 0;
for(j = 0; j < n; j++) {
s = (j % 10 + 0.1).toFixed(j % 16);
s = (j + 0.1).toFixed(j % 16);
s = (j * 12345678 + 0.1).toFixed(j % 16);
}
return n * 3;
}
function float_toPrecision(n)
{
var s, r, j;
r = 0;
for(j = 0; j < n; j++) {
s = (j % 10 + 0.1).toPrecision(j % 16 + 1);
s = (j + 0.1).toPrecision(j % 16 + 1);
s = (j * 12345678 + 0.1).toPrecision(j % 16 + 1);
}
return n * 3;
}
function float_toExponential(n)
{
var s, r, j;
r = 0;
for(j = 0; j < n; j++) {
s = (j % 10 + 0.1).toExponential(j % 16);
s = (j + 0.1).toExponential(j % 16);
s = (j * 12345678 + 0.1).toExponential(j % 16);
}
return n * 3;
} }
function string_to_int(n) function string_to_int(n)
@ -983,12 +1047,17 @@ function main(argc, argv, g)
//string_build4, //string_build4,
sort_bench, sort_bench,
int_to_string, int_to_string,
int_toString,
float_to_string, float_to_string,
float_toString,
float_toFixed,
float_toPrecision,
float_toExponential,
string_to_int, string_to_int,
string_to_float, string_to_float,
]; ];
var tests = []; var tests = [];
var i, j, n, f, name; var i, j, n, f, name, found;
if (typeof BigInt == "function") { if (typeof BigInt == "function") {
/* BigInt test */ /* BigInt test */
@ -1015,14 +1084,14 @@ function main(argc, argv, g)
sort_bench.array_size = +argv[i++]; sort_bench.array_size = +argv[i++];
continue; continue;
} }
for (j = 0; j < test_list.length; j++) { for (j = 0, found = false; j < test_list.length; j++) {
f = test_list[j]; f = test_list[j];
if (name === f.name) { if (f.name.startsWith(name)) {
tests.push(f); tests.push(f);
break; found = true;
} }
} }
if (j == test_list.length) { if (!found) {
console.log("unknown benchmark: " + name); console.log("unknown benchmark: " + name);
return 1; return 1;
} }
@ -1050,6 +1119,9 @@ function main(argc, argv, g)
save_result("microbench-new.txt", log_data); save_result("microbench-new.txt", log_data);
} }
if (!scriptArgs) if (typeof scriptArgs === "undefined") {
scriptArgs = []; scriptArgs = [];
if (typeof process.argv === "object")
scriptArgs = process.argv.slice(1);
}
main(scriptArgs.length, scriptArgs, this); main(scriptArgs.length, scriptArgs, this);

View file

@ -85,7 +85,7 @@ function toStr(a)
case "undefined": case "undefined":
return "undefined"; return "undefined";
case "string": case "string":
return a.__quote(); return JSON.stringify(a);
case "number": case "number":
if (a == 0 && 1 / a < 0) if (a == 0 && 1 / a < 0)
return "-0"; return "-0";

View file

@ -1,18 +1,105 @@
import * as os from "os"; import * as os from "os";
// Keep this at the top; it tests source positions.
function test_exception_source_pos()
{
var e;
try {
throw new Error(""); // line 9, column 19
} catch(_e) {
e = _e;
}
assert(e.stack.includes("test_builtin.js:9:19"));
}
// Keep this at the top; it tests source positions.
function test_function_source_pos() // line 18, column 1
{
function inner() {} // line 20, column 5
var f = eval("function f() {} f");
assert(`${test_function_source_pos.lineNumber}:${test_function_source_pos.columnNumber}`, "18:1");
assert(`${inner.lineNumber}:${inner.columnNumber}`, "20:5");
assert(`${f.lineNumber}:${f.columnNumber}`, "1:1");
}
// Keep this at the top; it tests source positions.
function test_exception_prepare_stack()
{
var e;
Error.prepareStackTrace = (_, frames) => {
// Just return the array to check.
return frames;
};
try {
throw new Error(""); // line 38, column 19
} catch(_e) {
e = _e;
}
assert(e.stack.length === 2);
const f = e.stack[0];
assert(f.getFunctionName() === 'test_exception_prepare_stack');
assert(f.getFileName() === 'tests/test_builtin.js');
assert(f.getLineNumber() === 38);
assert(f.getColumnNumber() === 19);
assert(!f.isNative());
Error.prepareStackTrace = undefined;
}
// Keep this at the top; it tests source positions.
function test_exception_stack_size_limit()
{
var e;
Error.stackTraceLimit = 1;
Error.prepareStackTrace = (_, frames) => {
// Just return the array to check.
return frames;
};
try {
throw new Error(""); // line 66, column 19
} catch(_e) {
e = _e;
}
assert(e.stack.length === 1);
const f = e.stack[0];
assert(f.getFunctionName() === 'test_exception_stack_size_limit');
assert(f.getFileName() === 'tests/test_builtin.js');
assert(f.getLineNumber() === 66);
assert(f.getColumnNumber() === 19);
assert(!f.isNative());
Error.stackTraceLimit = 10;
Error.prepareStackTrace = undefined;
}
function assert(actual, expected, message) { function assert(actual, expected, message) {
if (arguments.length == 1) if (arguments.length == 1)
expected = true; expected = true;
if (actual === expected) if (typeof actual === typeof expected) {
return; if (actual === expected) {
if (actual !== 0 || (1 / actual) === (1 / expected))
if (actual !== null && expected !== null return;
&& typeof actual == 'object' && typeof expected == 'object' }
&& actual.toString() === expected.toString()) if (typeof actual === 'number') {
return; if (isNaN(actual) && isNaN(expected))
return true;
}
if (typeof actual === 'object') {
if (actual !== null && expected !== null
&& actual.constructor === expected.constructor
&& actual.toString() === expected.toString())
return;
}
}
throw Error("assertion failed: got |" + actual + "|" + throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" + ", expected |" + expected + "|" +
(message ? " (" + message + ")" : "")); (message ? " (" + message + ")" : ""));
@ -133,6 +220,8 @@ function test()
assert(Object.isExtensible(a), false, "extensible"); assert(Object.isExtensible(a), false, "extensible");
assert(typeof a.y, "undefined", "extensible"); assert(typeof a.y, "undefined", "extensible");
assert(err, true, "extensible"); assert(err, true, "extensible");
assert_throws(TypeError, () => Object.setPrototypeOf(Object.prototype, {}));
} }
function test_enum() function test_enum()
@ -345,17 +434,17 @@ function test_number()
assert(Number.isNaN(Number("-"))); assert(Number.isNaN(Number("-")));
assert(Number.isNaN(Number("\x00a"))); assert(Number.isNaN(Number("\x00a")));
// TODO: Fix rounding errors on Windows/Cygwin. assert((1-2**-53).toString(12), "0.bbbbbbbbbbbbbba");
if (['win32', 'cygwin'].includes(os.platform)) { assert((1000000000000000128).toString(), "1000000000000000100");
return; assert((1000000000000000128).toFixed(0), "1000000000000000128");
}
assert((25).toExponential(0), "3e+1"); assert((25).toExponential(0), "3e+1");
assert((-25).toExponential(0), "-3e+1"); assert((-25).toExponential(0), "-3e+1");
assert((2.5).toPrecision(1), "3"); assert((2.5).toPrecision(1), "3");
assert((-2.5).toPrecision(1), "-3"); assert((-2.5).toPrecision(1), "-3");
assert((1.125).toFixed(2), "1.13"); assert((1.125).toFixed(2), "1.13");
assert((-1.125).toFixed(2), "-1.13"); assert((-1.125).toFixed(2), "-1.13");
assert((0.5).toFixed(0), "1");
assert((-0.5).toFixed(0), "-1");
} }
function test_eval2() function test_eval2()
@ -372,6 +461,20 @@ function test_eval2()
f1(g); f1(g);
f2(g); f2(g);
assert(g_call_count, 2); assert(g_call_count, 2);
var e;
try {
new class extends Object {
constructor() {
(() => {
for (const _ in this);
eval("");
})();
}
};
} catch (_e) {
e = _e;
}
assert(e?.message, "this is not initialized");
} }
function test_eval() function test_eval()
@ -413,7 +516,7 @@ function test_eval()
function test_typed_array() function test_typed_array()
{ {
var buffer, a, i, str; var buffer, a, i, str, b;
a = new Uint8Array(4); a = new Uint8Array(4);
assert(a.length, 4); assert(a.length, 4);
@ -466,6 +569,17 @@ function test_typed_array()
assert(a.toString(), "1,2,3,4"); assert(a.toString(), "1,2,3,4");
a.set([10, 11], 2); a.set([10, 11], 2);
assert(a.toString(), "1,2,10,11"); assert(a.toString(), "1,2,10,11");
a = new Uint8Array(buffer, 0, 4);
a.constructor = {
[Symbol.species]: function (len) {
return new Uint8Array(buffer, 1, len);
},
};
b = a.slice();
assert(a.buffer, b.buffer);
assert(a.toString(), "0,0,0,255");
assert(b.toString(), "0,0,255,255");
} }
function test_json() function test_json()
@ -495,26 +609,113 @@ function test_json()
function test_date() function test_date()
{ {
var d = new Date(1506098258091), a, s; // Date Time String format is YYYY-MM-DDTHH:mm:ss.sssZ
// accepted date formats are: YYYY, YYYY-MM and YYYY-MM-DD
// accepted time formats are: THH:mm, THH:mm:ss, THH:mm:ss.sss
// expanded years are represented with 6 digits prefixed by + or -
// -000000 is invalid.
// A string containing out-of-bounds or nonconforming elements
// is not a valid instance of this format.
// Hence the fractional part after . should have 3 digits and how
// a different number of digits is handled is implementation defined.
assert(Date.parse(""), NaN);
assert(Date.parse("2000"), 946684800000);
assert(Date.parse("2000-01"), 946684800000);
assert(Date.parse("2000-01-01"), 946684800000);
//assert(Date.parse("2000-01-01T"), NaN);
//assert(Date.parse("2000-01-01T00Z"), NaN);
assert(Date.parse("2000-01-01T00:00Z"), 946684800000);
assert(Date.parse("2000-01-01T00:00:00Z"), 946684800000);
assert(Date.parse("2000-01-01T00:00:00.1Z"), 946684800100);
assert(Date.parse("2000-01-01T00:00:00.10Z"), 946684800100);
assert(Date.parse("2000-01-01T00:00:00.100Z"), 946684800100);
assert(Date.parse("2000-01-01T00:00:00.1000Z"), 946684800100);
assert(Date.parse("2000-01-01T00:00:00+00:00"), 946684800000);
//assert(Date.parse("2000-01-01T00:00:00+00:30"), 946686600000);
var d = new Date("2000T00:00"); // Jan 1st 2000, 0:00:00 local time
assert(typeof d === 'object' && d.toString() != 'Invalid Date');
assert((new Date('Jan 1 2000')).toISOString(),
d.toISOString());
assert((new Date('Jan 1 2000 00:00')).toISOString(),
d.toISOString());
assert((new Date('Jan 1 2000 00:00:00')).toISOString(),
d.toISOString());
assert((new Date('Jan 1 2000 00:00:00 GMT+0100')).toISOString(),
'1999-12-31T23:00:00.000Z');
assert((new Date('Jan 1 2000 00:00:00 GMT+0200')).toISOString(),
'1999-12-31T22:00:00.000Z');
assert((new Date('Sat Jan 1 2000')).toISOString(),
d.toISOString());
assert((new Date('Sat Jan 1 2000 00:00')).toISOString(),
d.toISOString());
assert((new Date('Sat Jan 1 2000 00:00:00')).toISOString(),
d.toISOString());
assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0100')).toISOString(),
'1999-12-31T23:00:00.000Z');
assert((new Date('Sat Jan 1 2000 00:00:00 GMT+0200')).toISOString(),
'1999-12-31T22:00:00.000Z');
var d = new Date(1506098258091);
assert(d.toISOString(), "2017-09-22T16:37:38.091Z"); assert(d.toISOString(), "2017-09-22T16:37:38.091Z");
d.setUTCHours(18, 10, 11); d.setUTCHours(18, 10, 11);
assert(d.toISOString(), "2017-09-22T18:10:11.091Z"); assert(d.toISOString(), "2017-09-22T18:10:11.091Z");
a = Date.parse(d.toISOString()); var a = Date.parse(d.toISOString());
assert((new Date(a)).toISOString(), d.toISOString()); assert((new Date(a)).toISOString(), d.toISOString());
s = new Date("2020-01-01T01:01:01.1Z").toISOString();
assert(s == "2020-01-01T01:01:01.100Z"); assert((new Date("2020-01-01T01:01:01.123Z")).toISOString(),
s = new Date("2020-01-01T01:01:01.12Z").toISOString(); "2020-01-01T01:01:01.123Z");
assert(s == "2020-01-01T01:01:01.120Z"); /* implementation defined behavior */
s = new Date("2020-01-01T01:01:01.123Z").toISOString(); assert((new Date("2020-01-01T01:01:01.1Z")).toISOString(),
assert(s == "2020-01-01T01:01:01.123Z"); "2020-01-01T01:01:01.100Z");
s = new Date("2020-01-01T01:01:01.1234Z").toISOString(); assert((new Date("2020-01-01T01:01:01.12Z")).toISOString(),
assert(s == "2020-01-01T01:01:01.123Z"); "2020-01-01T01:01:01.120Z");
s = new Date("2020-01-01T01:01:01.12345Z").toISOString(); assert((new Date("2020-01-01T01:01:01.1234Z")).toISOString(),
assert(s == "2020-01-01T01:01:01.123Z"); "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.1235Z").toISOString(); assert((new Date("2020-01-01T01:01:01.12345Z")).toISOString(),
assert(s == "2020-01-01T01:01:01.124Z"); "2020-01-01T01:01:01.123Z");
s = new Date("2020-01-01T01:01:01.9999Z").toISOString(); assert((new Date("2020-01-01T01:01:01.1235Z")).toISOString(),
assert(s == "2020-01-01T01:01:02.000Z"); "2020-01-01T01:01:01.123Z");
assert((new Date("2020-01-01T01:01:01.9999Z")).toISOString(),
"2020-01-01T01:01:01.999Z");
assert(Date.UTC(2017), 1483228800000);
assert(Date.UTC(2017, 9), 1506816000000);
assert(Date.UTC(2017, 9, 22), 1508630400000);
assert(Date.UTC(2017, 9, 22, 18), 1508695200000);
assert(Date.UTC(2017, 9, 22, 18, 10), 1508695800000);
assert(Date.UTC(2017, 9, 22, 18, 10, 11), 1508695811000);
assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91), 1508695811091);
assert(Date.UTC(NaN), NaN);
assert(Date.UTC(2017, NaN), NaN);
assert(Date.UTC(2017, 9, NaN), NaN);
assert(Date.UTC(2017, 9, 22, NaN), NaN);
assert(Date.UTC(2017, 9, 22, 18, NaN), NaN);
assert(Date.UTC(2017, 9, 22, 18, 10, NaN), NaN);
assert(Date.UTC(2017, 9, 22, 18, 10, 11, NaN), NaN);
assert(Date.UTC(2017, 9, 22, 18, 10, 11, 91, NaN), 1508695811091);
// TODO: Fix rounding errors on Windows/Cygwin.
if (!['win32', 'cygwin'].includes(os.platform)) {
// from test262/test/built-ins/Date/UTC/fp-evaluation-order.js
assert(Date.UTC(1970, 0, 1, 80063993375, 29, 1, -288230376151711740), 29312,
'order of operations / precision in MakeTime');
assert(Date.UTC(1970, 0, 213503982336, 0, 0, 0, -18446744073709552000), 34447360,
'precision in MakeDate');
}
//assert(Date.UTC(2017 - 1e9, 9 + 12e9), 1506816000000); // node fails this
assert(Date.UTC(2017, 9, 22 - 1e10, 18 + 24e10), 1508695200000);
assert(Date.UTC(2017, 9, 22, 18 - 1e10, 10 + 60e10), 1508695800000);
assert(Date.UTC(2017, 9, 22, 18, 10 - 1e10, 11 + 60e10), 1508695811000);
assert(Date.UTC(2017, 9, 22, 18, 10, 11 - 1e12, 91 + 1000e12), 1508695811091);
assert(new Date("2024 Apr 7 1:00 AM").toLocaleString(), "04/07/2024, 01:00:00 AM");
assert(new Date("2024 Apr 7 2:00 AM").toLocaleString(), "04/07/2024, 02:00:00 AM");
assert(new Date("2024 Apr 7 11:00 AM").toLocaleString(), "04/07/2024, 11:00:00 AM");
assert(new Date("2024 Apr 7 12:00 AM").toLocaleString(), "04/07/2024, 12:00:00 AM");
assert(new Date("2024 Apr 7 1:00 PM").toLocaleString(), "04/07/2024, 01:00:00 PM");
assert(new Date("2024 Apr 7 2:00 PM").toLocaleString(), "04/07/2024, 02:00:00 PM");
assert(new Date("2024 Apr 7 11:00 PM").toLocaleString(), "04/07/2024, 11:00:00 PM");
assert(new Date("2024 Apr 7 12:00 PM").toLocaleString(), "04/07/2024, 12:00:00 PM");
} }
function test_regexp() function test_regexp()
@ -553,6 +754,20 @@ function test_regexp()
assert(/{1a}/.toString(), "/{1a}/"); assert(/{1a}/.toString(), "/{1a}/");
a = /a{1+/.exec("a{11"); a = /a{1+/.exec("a{11");
assert(a, ["a{11"] ); assert(a, ["a{11"] );
eval("/[a-]/"); // accepted with no flag
eval("/[a-]/u"); // accepted with 'u' flag
let ex;
try {
eval("/[a-]/v"); // rejected with 'v' flag
} catch (_ex) {
ex = _ex;
}
assert(ex?.message, "invalid class range");
eval("/[\\-]/");
eval("/[\\-]/u");
} }
function test_symbol() function test_symbol()
@ -591,6 +806,16 @@ function test_map()
{ {
var a, i, n, tab, o, v; var a, i, n, tab, o, v;
n = 1000; n = 1000;
a = new Map();
for (var i = 0; i < n; i++) {
a.set(i, i);
}
a.set(-2147483648, 1);
assert(a.get(-2147483648), 1);
assert(a.get(-2147483647 - 1), 1);
assert(a.get(-2147483647.5 - 0.5), 1);
a = new Map(); a = new Map();
tab = []; tab = [];
for(i = 0; i < n; i++) { for(i = 0; i < n; i++) {
@ -685,6 +910,18 @@ function test_generator()
assert(ret, "ret_val"); assert(ret, "ret_val");
return 3; return 3;
} }
function *f3() {
var ret;
/* test stack consistency with nip_n to handle yield return +
* finally clause */
try {
ret = 2 + (yield 1);
} catch(e) {
} finally {
ret++;
}
return ret;
}
var g, v; var g, v;
g = f(); g = f();
v = g.next(); v = g.next();
@ -705,6 +942,28 @@ function test_generator()
assert(v.value === 3 && v.done === true); assert(v.value === 3 && v.done === true);
v = g.next(); v = g.next();
assert(v.value === undefined && v.done === true); assert(v.value === undefined && v.done === true);
g = f3();
v = g.next();
assert(v.value === 1 && v.done === false);
v = g.next(3);
assert(v.value === 6 && v.done === true);
}
function test_proxy_iter()
{
const p = new Proxy({}, {
getOwnPropertyDescriptor() {
return {configurable: true, enumerable: true, value: 42};
},
ownKeys() {
return ["x", "y"];
},
});
const a = [];
for (const x in p) a.push(x);
assert(a[0], "x");
assert(a[1], "y");
} }
/* CVE-2023-31922 */ /* CVE-2023-31922 */
@ -717,15 +976,63 @@ function test_proxy_is_array()
/* Without ASAN */ /* Without ASAN */
assert(Array.isArray(r)); assert(Array.isArray(r));
} catch(e) { } catch(e) {
/* With ASAN expect InternalError "stack overflow" to be raised */ /* With ASAN expect RangeError "Maximum call stack size exceeded" to be raised */
if (e instanceof InternalError) { if (e instanceof RangeError) {
assert(e.message, "stack overflow", "Stack overflow error was not raised") assert(e.message, "Maximum call stack size exceeded", "Stack overflow error was not raised")
} else { } else {
throw e; throw e;
} }
} }
} }
function test_cur_pc()
{
var a = [];
Object.defineProperty(a, '1', {
get: function() { throw Error("a[1]_get"); },
set: function(x) { throw Error("a[1]_set"); }
});
assert_throws(Error, function() { return a[1]; });
assert_throws(Error, function() { a[1] = 1; });
assert_throws(Error, function() { return [...a]; });
assert_throws(Error, function() { return ({...b} = a); });
var o = {};
Object.defineProperty(o, 'x', {
get: function() { throw Error("o.x_get"); },
set: function(x) { throw Error("o.x_set"); }
});
o.valueOf = function() { throw Error("o.valueOf"); };
assert_throws(Error, function() { return +o; });
assert_throws(Error, function() { return -o; });
assert_throws(Error, function() { return o+1; });
assert_throws(Error, function() { return o-1; });
assert_throws(Error, function() { return o*1; });
assert_throws(Error, function() { return o/1; });
assert_throws(Error, function() { return o%1; });
assert_throws(Error, function() { return o**1; });
assert_throws(Error, function() { return o<<1; });
assert_throws(Error, function() { return o>>1; });
assert_throws(Error, function() { return o>>>1; });
assert_throws(Error, function() { return o&1; });
assert_throws(Error, function() { return o|1; });
assert_throws(Error, function() { return o^1; });
assert_throws(Error, function() { return o<1; });
assert_throws(Error, function() { return o==1; });
assert_throws(Error, function() { return o++; });
assert_throws(Error, function() { return o--; });
assert_throws(Error, function() { return ++o; });
assert_throws(Error, function() { return --o; });
assert_throws(Error, function() { return ~o; });
Object.defineProperty(globalThis, 'xxx', {
get: function() { throw Error("xxx_get"); },
set: function(x) { throw Error("xxx_set"); }
});
assert_throws(Error, function() { return xxx; });
assert_throws(Error, function() { xxx = 1; });
}
test(); test();
test_function(); test_function();
test_enum(); test_enum();
@ -743,4 +1050,10 @@ test_map();
test_weak_map(); test_weak_map();
test_weak_set(); test_weak_set();
test_generator(); test_generator();
test_proxy_iter();
test_proxy_is_array(); test_proxy_is_array();
test_exception_source_pos();
test_function_source_pos();
test_exception_prepare_stack();
test_exception_stack_size_limit();
test_cur_pc();

1746
tests/test_conv.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -5,29 +5,41 @@ function assert(actual, expected, message) {
if (actual === expected) if (actual === expected)
return; return;
if (typeof actual == 'number' && isNaN(actual)
&& typeof expected == 'number' && isNaN(expected))
return;
if (actual !== null && expected !== null if (actual !== null && expected !== null
&& typeof actual == 'object' && typeof expected == 'object' && typeof actual == 'object' && typeof expected == 'object'
&& actual.toString() === expected.toString()) && actual.toString() === expected.toString())
return; return;
var msg = message ? " (" + message + ")" : "";
throw Error("assertion failed: got |" + actual + "|" + throw Error("assertion failed: got |" + actual + "|" +
", expected |" + expected + "|" + ", expected |" + expected + "|" + msg);
(message ? " (" + message + ")" : ""));
} }
function assert_throws(expected_error, func) function assert_throws(expected_error, func, message)
{ {
var err = false; var err = false;
var msg = message ? " (" + message + ")" : "";
try { try {
func(); switch (typeof func) {
case 'string':
eval(func);
break;
case 'function':
func();
break;
}
} catch(e) { } catch(e) {
err = true; err = true;
if (!(e instanceof expected_error)) { if (!(e instanceof expected_error)) {
throw Error("unexpected exception type"); throw Error(`expected ${expected_error.name}, got ${e.name}${msg}`);
} }
} }
if (!err) { if (!err) {
throw Error("expected exception"); throw Error(`expected ${expected_error.name}${msg}`);
} }
} }
@ -120,6 +132,7 @@ function test_cvt()
assert((Infinity >>> 0) === 0); assert((Infinity >>> 0) === 0);
assert(((-Infinity) >>> 0) === 0); assert(((-Infinity) >>> 0) === 0);
assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4)); assert(((4294967296 * 3 - 4) >>> 0) === (4294967296 - 4));
assert((19686109595169230000).toString() === "19686109595169230000");
} }
function test_eq() function test_eq()
@ -334,6 +347,13 @@ function test_class()
assert(S.x === 42); assert(S.x === 42);
assert(S.y === 42); assert(S.y === 42);
assert(S.z === 42); assert(S.z === 42);
class P {
get = () => "123";
static() { return 42; }
}
assert(new P().get() === "123");
assert(new P().static() === 42);
}; };
function test_template() function test_template()
@ -361,8 +381,9 @@ function test_template_skip()
function test_object_literal() function test_object_literal()
{ {
var x = 0, get = 1, set = 2; async = 3; var x = 0, get = 1, set = 2; async = 3;
a = { get: 2, set: 3, async: 4 }; a = { get: 2, set: 3, async: 4, get a(){ return this.get} };
assert(JSON.stringify(a), '{"get":2,"set":3,"async":4}'); assert(JSON.stringify(a), '{"get":2,"set":3,"async":4,"a":2}');
assert(a.a === 2);
a = { x, get, set, async }; a = { x, get, set, async };
assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}'); assert(JSON.stringify(a), '{"x":0,"get":1,"set":2,"async":3}');
@ -420,7 +441,9 @@ function test_argument_scope()
var c = "global"; var c = "global";
f = function(a = eval("var arguments")) {}; f = function(a = eval("var arguments")) {};
assert_throws(SyntaxError, f); // for some reason v8 does not throw an exception here
if (typeof require === 'undefined')
assert_throws(SyntaxError, f);
f = function(a = eval("1"), b = arguments[0]) { return b; }; f = function(a = eval("1"), b = arguments[0]) { return b; };
assert(f(12), 12); assert(f(12), 12);
@ -535,6 +558,107 @@ function test_function_expr_name()
assert_throws(TypeError, f); assert_throws(TypeError, f);
} }
function test_expr(expr, err) {
if (err)
assert_throws(err, expr, `for ${expr}`);
else
assert(1, eval(expr), `for ${expr}`);
}
function test_name(name, err)
{
test_expr(`(function() { return typeof ${name} ? 1 : 1; })()`);
test_expr(`(function() { var ${name}; ${name} = 1; return ${name}; })()`);
test_expr(`(function() { let ${name}; ${name} = 1; return ${name}; })()`, name == 'let' ? SyntaxError : undefined);
test_expr(`(function() { const ${name} = 1; return ${name}; })()`, name == 'let' ? SyntaxError : undefined);
test_expr(`(function(${name}) { ${name} = 1; return ${name}; })()`);
test_expr(`(function({${name}}) { ${name} = 1; return ${name}; })({})`);
test_expr(`(function ${name}() { return ${name} ? 1 : 0; })()`);
test_expr(`"use strict"; (function() { return typeof ${name} ? 1 : 1; })()`, err);
test_expr(`"use strict"; (function() { if (0) ${name} = 1; return 1; })()`, err);
test_expr(`"use strict"; (function() { var x; if (0) x = ${name}; return 1; })()`, err);
test_expr(`"use strict"; (function() { var ${name}; return 1; })()`, err);
test_expr(`"use strict"; (function() { let ${name}; return 1; })()`, err);
test_expr(`"use strict"; (function() { const ${name} = 1; return 1; })()`, err);
test_expr(`"use strict"; (function() { var ${name}; ${name} = 1; return 1; })()`, err);
test_expr(`"use strict"; (function() { var ${name}; ${name} = 1; return ${name}; })()`, err);
test_expr(`"use strict"; (function(${name}) { return 1; })()`, err);
test_expr(`"use strict"; (function({${name}}) { return 1; })({})`, err);
test_expr(`"use strict"; (function ${name}() { return 1; })()`, err);
test_expr(`(function() { "use strict"; return typeof ${name} ? 1 : 1; })()`, err);
test_expr(`(function() { "use strict"; if (0) ${name} = 1; return 1; })()`, err);
test_expr(`(function() { "use strict"; var x; if (0) x = ${name}; return 1; })()`, err);
test_expr(`(function() { "use strict"; var ${name}; return 1; })()`, err);
test_expr(`(function() { "use strict"; let ${name}; return 1; })()`, err);
test_expr(`(function() { "use strict"; const ${name} = 1; return 1; })()`, err);
test_expr(`(function() { "use strict"; var ${name}; ${name} = 1; return 1; })()`, err);
test_expr(`(function() { "use strict"; var ${name}; ${name} = 1; return ${name}; })()`, err);
test_expr(`(function(${name}) { "use strict"; return 1; })()`, err);
test_expr(`(function({${name}}) { "use strict"; return 1; })({})`, SyntaxError);
test_expr(`(function ${name}() { "use strict"; return 1; })()`, err);
}
function test_reserved_names()
{
test_name('await');
test_name('yield', SyntaxError);
test_name('implements', SyntaxError);
test_name('interface', SyntaxError);
test_name('let', SyntaxError);
test_name('package', SyntaxError);
test_name('private', SyntaxError);
test_name('protected', SyntaxError);
test_name('public', SyntaxError);
test_name('static', SyntaxError);
}
function test_number_literals()
{
assert(0.1.a, undefined);
assert(0x1.a, undefined);
assert(0b1.a, undefined);
assert(01.a, undefined);
assert(0o1.a, undefined);
test_expr('0.a', SyntaxError);
assert(parseInt("0_1"), 0);
assert(parseInt("1_0"), 1);
assert(parseInt("0_1", 8), 0);
assert(parseInt("1_0", 8), 1);
assert(parseFloat("0_1"), 0);
assert(parseFloat("1_0"), 1);
assert(1_0, 10);
assert(parseInt("Infinity"), NaN);
assert(parseFloat("Infinity"), Infinity);
assert(parseFloat("Infinity1"), Infinity);
assert(parseFloat("Infinity_"), Infinity);
assert(parseFloat("Infinity."), Infinity);
test_expr('0_0', SyntaxError);
test_expr('00_0', SyntaxError);
test_expr('01_0', SyntaxError);
test_expr('08_0', SyntaxError);
test_expr('09_0', SyntaxError);
}
function test_syntax()
{
assert_throws(SyntaxError, "do");
assert_throws(SyntaxError, "do;");
assert_throws(SyntaxError, "do{}");
assert_throws(SyntaxError, "if");
assert_throws(SyntaxError, "if\n");
assert_throws(SyntaxError, "if 1");
assert_throws(SyntaxError, "if \0");
assert_throws(SyntaxError, "if ;");
assert_throws(SyntaxError, "if 'abc'");
assert_throws(SyntaxError, "if `abc`");
assert_throws(SyntaxError, "if /abc/");
assert_throws(SyntaxError, "if abc");
assert_throws(SyntaxError, "if abc\u0064");
assert_throws(SyntaxError, "if abc\\u0064");
assert_throws(SyntaxError, "if \u0123");
assert_throws(SyntaxError, "if \\u0123");
}
test_op1(); test_op1();
test_cvt(); test_cvt();
test_eq(); test_eq();
@ -554,3 +678,6 @@ test_spread();
test_function_length(); test_function_length();
test_argument_scope(); test_argument_scope();
test_function_expr_name(); test_function_expr_name();
test_reserved_names();
test_number_literals();
test_syntax();

View file

@ -2,6 +2,7 @@ import * as std from "std";
import * as os from "os"; import * as os from "os";
const isWin = os.platform === 'win32'; const isWin = os.platform === 'win32';
const isCygwin = os.platform === 'cygwin';
function assert(actual, expected, message) { function assert(actual, expected, message) {
if (arguments.length == 1) if (arguments.length == 1)
@ -243,13 +244,26 @@ function test_os_exec()
pid = os.exec(["cat"], { block: false } ); pid = os.exec(["cat"], { block: false } );
assert(pid >= 0); assert(pid >= 0);
os.kill(pid, os.SIGQUIT); os.kill(pid, os.SIGTERM);
[ret, status] = os.waitpid(pid, 0); [ret, status] = os.waitpid(pid, 0);
assert(ret, pid); assert(ret, pid);
assert(status & 0x7f, os.SIGQUIT); // Flaky on cygwin for unclear reasons, see
// https://github.com/quickjs-ng/quickjs/issues/184
if (!isCygwin) {
assert(status & 0x7f, os.SIGTERM);
}
} }
function test_timer() function test_interval()
{
var t = os.setInterval(f, 1);
function f() {
if (++f.count === 3) os.clearInterval(t);
}
f.count = 0;
}
function test_timeout()
{ {
var th, i; var th, i;
@ -261,6 +275,18 @@ function test_timer()
os.clearTimeout(th[i]); os.clearTimeout(th[i]);
} }
function test_timeout_order()
{
var s = "";
os.setTimeout(a, 1);
os.setTimeout(b, 2);
os.setTimeout(d, 5);
function a() { s += "a"; os.setTimeout(c, 0); }
function b() { s += "b"; }
function c() { s += "c"; }
function d() { assert(s === "abc"); } // not "acb"
}
test_printf(); test_printf();
test_file1(); test_file1();
test_file2(); test_file2();
@ -268,4 +294,6 @@ test_getline();
test_popen(); test_popen();
test_os(); test_os();
!isWin && test_os_exec(); !isWin && test_os_exec();
test_timer(); test_interval();
test_timeout();
test_timeout_order();

View file

@ -217,7 +217,7 @@ static const char *unicode_prop_short_name[] = {
#undef DEF #undef DEF
}; };
#undef UNICODE_SPROP_LIST #undef UNICODE_PROP_LIST
typedef struct { typedef struct {
/* case conv */ /* case conv */

25
v8-tweak.js Normal file
View file

@ -0,0 +1,25 @@
;(function() {
"use strict"
const print = globalThis.print
globalThis.print = function() {} // print nothing, v8 tests are chatty
let count = 0 // rate limit to avoid excessive logs
globalThis.failWithMessage = function(message) {
if (count > 99) return
if (++count > 99) return print("<output elided>")
print(String(message).slice(0, 300))
}
globalThis.formatFailureText = function(expectedText, found, name_opt) {
var message = "Fail" + "ure"
if (name_opt) {
// Fix this when we ditch the old test runner.
message += " (" + name_opt + ")"
}
var foundText = prettyPrinted(found)
if (expectedText.length <= 60 && foundText.length <= 60) {
message += ": expected <" + expectedText + "> found <" + foundText + ">"
} else {
message += ":\nexpected:\n" + expectedText + "\nfound:\n" + foundText
}
return message
}
})()

109
v8.js Normal file
View file

@ -0,0 +1,109 @@
import * as std from "std"
import * as os from "os"
argv0 = realpath(argv0)
const tweak = realpath("v8-tweak.js")
const dir = "test262/implementation-contributed/v8/mjsunit"
const exclude = [
"arguments-indirect.js", // implementation-defined
"array-concat.js", // slow
"array-isarray.js", // unstable output due to stack overflow
"array-join.js", // unstable output due to stack overflow
"ascii-regexp-subject.js", // slow
"asm-directive.js", // v8 specific
"disallow-codegen-from-strings.js", // --disallow-code-generation-from-strings
"cyclic-array-to-string.js", // unstable output due to stack overflow
"error-tostring.js", // unstable output due to stack overflow
"invalid-lhs.js", // v8 expects ReferenceError but ECMA says SyntaxError
"regexp.js", // invalid, legitimate early SyntaxError
"regexp-capture-3.js", // slow
"regexp-cache-replace.js", // deprecated RegExp.$1 etc.
"regexp-indexof.js", // deprecated RegExp.lastMatch etc.
"regexp-static.js", // deprecated RegExp static properties.
"regexp-modifiers-autogenerated-i18n.js", // invalid group
"regexp-modifiers-autogenerated.js", // invalid group
"regexp-modifiers-dotall.js", // invalid group
"regexp-modifiers-i18n.js", // invalid group
"regexp-modifiers.js", // invalid group
"regexp-override-symbol-match-all.js", // missing g flag
"serialize-embedded-error.js", // parseInt() = 0;
"string-replace.js", // unstable output
"string-match.js", // deprecated RegExp.$1 etc.
"string-slices-regexp.js", // deprecated RegExp.$1 etc.
"omit-default-ctors-array-iterator.js",
"mjsunit.js",
"mjsunit-assertion-error.js",
"mjsunit-assert-equals.js",
"mjsunit_suppressions.js",
"verify-assert-false.js", // self check
"verify-check-false.js", // self check
"clone-ic-regression-crbug-1466315.js", // spurious output
]
let files = scriptArgs.slice(1) // run only these tests
if (files.length === 0) files = os.readdir(dir)[0].sort()
for (const file of files) {
if (!file.endsWith(".js")) continue
if (exclude.includes(file)) continue
const source = std.loadFile(dir + "/" + file)
if (/^(im|ex)port/m.test(source)) continue // TODO support modules
if (source.includes('Realm.create')) continue // TODO support Realm object
if (source.includes('// MODULE')) continue // TODO support modules
if (source.includes('// Files:')) continue // TODO support includes
// the default --stack-size is necessary to keep output of stack overflowing
// tests stable; it will be overridden by a Flags comment
let flags = { '--stack-size': 2048 }, flagstr = ""
// parse command line flags
for (let s of source.matchAll(/\/\/ Flags:(.+)/g)) {
for (let m of s[1].matchAll(/\s*([\S]+)/g)) {
const v = m[1].match(/([\S]+)=([\S]+)/)
if (v) {
flags[v[1]] = v[2]
flagstr += ` ${v[1]}=${v[2]}`
} else {
flags[m[1]] = true
flagstr += ` ${m[1]}`
}
}
}
// exclude tests that use V8 intrinsics like %OptimizeFunctionOnNextCall
if (flags["--allow-natives-syntax"]) continue
if (flags["--allow-natives-for-differential-fuzzing"]) continue
if (flags["--dump-counters"]) continue
if (flags["--expose-cputracemark"]) continue
if (flags["--harmony-rab-gsab"]) continue
if (flags["--harmony-class-fields"]) continue
if (flags["--enable-experimental-regexp-engine"]) continue
if (flags["--experimental-stack-trace-frames"]) continue
if (flags["--js-float16array"]) continue
if (flags["--expose-cputracemark-as"]) continue
// exclude tests that use V8 extensions
if (flags["--expose-externalize-string"]) continue
// parse environment variables
let env = {}, envstr = ""
for (let s of source.matchAll(/environment variables:(.+)/ig)) {
for (let m of s[1].matchAll(/\s*([\S]+)=([\S]+)/g)) {
env[m[1]] = m[2]
envstr += ` ${m[1]}=${m[2]}`
}
}
//print(`=== ${file}${envstr}${flagstr}`)
print(`=== ${file}${envstr}`)
const args = [argv0,
"--stack-size", `${flags["--stack-size"]}`,
"-I", "mjsunit.js",
"-I", tweak,
file]
const opts = {block:true, cwd:dir, env:env, usePath:false}
os.exec(args, opts)
}
function realpath(path) {
return os.realpath(path)[0]
}

10
v8.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/sh
set -e
: ${QJS:=build/qjs}
if [ "x" = "x$1" ] ; then
"$QJS" v8.js $* 2>&1 | tee v8.txt$$
diff -uw v8.txt v8.txt$$ || exit 1
rm v8.txt$$
else
"$QJS" v8.js $* 2>&1
fi

971
v8.txt Normal file
View file

@ -0,0 +1,971 @@
=== accessors-no-prototype.js
=== accessors-on-global-object.js
=== api-call-after-bypassed-exception.js
=== apply-arguments-gc-safepoint.js
=== argument-assigned.js
=== argument-named-arguments.js
=== arguments-apply.js
=== arguments-call-apply.js
=== arguments-enum.js
=== arguments-escape.js
=== arguments-lazy.js
=== arguments-load-across-eval.js
=== arguments-read-and-assignment.js
=== array-elements-from-array-prototype-chain.js
=== array-elements-from-array-prototype.js
=== array-elements-from-object-prototype.js
=== array-foreach.js
=== array-from-large-set.js
=== array-functions-prototype-misc.js
=== array-functions-prototype.js
=== array-indexing.js
=== array-iteration.js
=== array-join-element-tostring-prototype-side-effects.js
=== array-join-nesting.js
=== array-join-nonarray-length-getter-side-effects.js
=== array-lastindexof.js
=== array-length-number-conversion.js
=== array-length.js
=== array-prototype-every.js
=== array-prototype-filter.js
=== array-prototype-find.js
=== array-prototype-findindex.js
=== array-prototype-foreach.js
=== array-prototype-includes.js
=== array-prototype-indexof.js
=== array-prototype-lastindexof.js
=== array-prototype-map.js
=== array-prototype-pop.js
=== array-prototype-reduce.js
=== array-prototype-slice.js
=== array-prototype-some.js
=== array-push-non-smi-value.js
=== array-push10.js
=== array-push11.js
=== array-push13.js
=== array-push14.js
=== array-push2.js
=== array-reverse.js
=== array-shift.js
=== array-splice.js
=== array-tolocalestring.js
Failure: expected <"1,"> found <"1,[object Object]">
Failure: expected <"1,"> found <"1,[object Object]">
Failure (Error message): expected <"7 is not a function"> found <"not a function">
=== array-tostring.js
=== array-unshift.js
=== arrow-with.js
=== async-stack-traces-prepare-stacktrace-1.js
=== async-stack-traces-prepare-stacktrace-2.js
Failure:
expected:
undefined
found:
async function two(x) {
"use strict";
try {
x = await x;
throw new Error();
} catch (e) {
return e.stack;
}
}
=== async-stack-traces-prepare-stacktrace-3.js
=== async-stack-traces-prepare-stacktrace-4.js
=== big-array-literal.js
=== big-object-literal.js
=== binary-op-newspace.js
=== binary-operation-overwrite.js
=== bit-not.js
=== bitops-info.js
=== bitwise-operations-bools.js
=== bitwise-operations-undefined.js
=== body-not-visible.js
=== bool-concat.js
=== boolean.js
=== break.js
=== call-non-function-call.js
=== call-non-function.js
=== call-stub.js
=== call.js
=== char-escape.js
=== class-of-builtins.js
=== closure.js
=== code-comments.js
=== codegen-coverage.js
=== compare-character.js
=== compare-nan.js
=== compare-table-eq.js
=== compare-table-gt.js
=== compare-table-gteq.js
=== compare-table-lt.js
=== compare-table-lteq.js
=== compare-table-ne.js
=== compare-table-seq.js
=== compare-table-sne.js
=== console.js
TypeError: not a function
at <eval> (console.js:5:1)
=== constant-folding.js
=== context-variable-assignments.js
=== copy-on-write-assert.js
=== cyrillic.js
Failure (7): expected <true> found <false>
Failure (8): expected <true> found <false>
Failure (9): expected <true> found <false>
Failure (10): expected <true> found <false>
Failure (11): expected <true> found <false>
Failure (12): expected <true> found <false>
Failure (7): expected <true> found <false>
Failure (8): expected <true> found <false>
Failure (9): expected <true> found <false>
Failure (10): expected <true> found <false>
Failure (11): expected <true> found <false>
Failure (12): expected <true> found <false>
Failure (16): expected <true> found <false>
Failure (19): expected <true> found <false>
Failure (20): expected <true> found <false>
Failure (21): expected <true> found <false>
Failure (25): expected <true> found <false>
Failure (26): expected <true> found <false>
Failure (27): expected <true> found <false>
Failure (44[]): expected <true> found <false>
Failure (45[]): expected <true> found <false>
Failure (46[]): expected <true> found <false>
Failure (54[]): expected <true> found <false>
Failure (55[]): expected <true> found <false>
Failure (56[]): expected <true> found <false>
=== date-parse.js
=== declare-locally.js
=== deep-recursion.js
=== define-property-gc.js
=== delay-syntax-error.js
=== delete-global-properties.js
=== delete-in-eval.js
=== delete-in-with.js
=== delete-non-configurable.js
=== delete-vars-from-eval.js
=== delete.js
=== deserialize-reference.js
=== do-not-strip-fc.js
=== dont-enum-array-holes.js
=== dont-reinit-global-var.js
=== double-equals.js
=== dtoa.js
=== duplicate-parameters.js
=== eagerly-parsed-lazily-compiled-functions.js
=== elements-transition-and-store.js
=== empirical_max_arraybuffer.js
=== enumeration-order.js
=== error-accessors.js
=== error-constructors.js
=== error-tostring-omit.js
Failure: expected <true> found <false>
=== escape.js
=== eval-enclosing-function-name.js
Failure: expected <"number"> found <"undefined">
Failure: expected <"number"> found <"function">
=== eval-origin.js
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
=== eval-stack-trace.js
Failure: expected <"eval"> found <"<eval>">
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
TypeError: not a function
[object CallSite],[object CallSite],[object CallSite],[object CallSite]
=== eval-typeof-non-existing.js
=== eval.js
=== external-backing-store-gc.js
=== extra-arguments.js
TypeError: cannot read property 'length' of undefined
at g (extra-arguments.js:35:23)
at f (extra-arguments.js:29:10)
at apply (native)
at <eval> (extra-arguments.js:51:40)
=== extra-commas.js
=== for-in-delete.js
=== for-in-null-or-undefined.js
=== for-in-special-cases.js
=== for-in.js
=== for-of-in-catch-duplicate-decl.js
=== for.js
=== fun-as-prototype.js
=== fun-name.js
=== function-arguments-null.js
Failure: expected <true> found <false>
=== function-bind-name.js
=== function-call.js
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <true> found <false>
<output elided>
=== function-caller.js
Failure: expected <function f(match) {
g(match);
}> found <undefined>
Failure: expected <function h() {
f(h);
}> found <undefined>
Failure: expected <function f(match) {
g(match);
}> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <function f(match) {
g(match);
}> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <function f(match) {
g(match);
}> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
=== function-length-accessor.js
=== function-name-eval-shadowed.js
Failure: expected <200> found <function f() { eval("var f = 100"); f = 200; return f }>
=== function-names.js
=== function-property.js
=== function-prototype.js
=== function-var.js
=== function-without-prototype.js
=== function.js
Failure: expected <"undefined"> found <"function">
Failure: expected <42> found <function anonymous(
) {
return anonymous;
}>
=== fuzz-accessors.js
=== get-own-property-descriptor-non-objects.js
=== get-own-property-descriptor.js
=== get-prototype-of.js
=== getter-in-prototype.js
=== getter-in-value-prototype.js
=== global-accessors.js
=== global-arrow-delete-this.js
=== global-deleted-property-ic.js
=== global-hash.js
=== global-ic.js
=== global-load-from-eval-in-with.js
=== global-load-from-eval.js
=== global-load-from-nested-eval.js
=== global-properties.js
=== global-vars-eval.js
=== global-vars-with.js
=== handle-count-ast.js
=== handle-count-runtime-literals.js
=== has-own-property-evaluation-order.js
=== has-own-property.js
=== hex-parsing.js
=== holy-double-no-arg-array.js
=== html-comments.js
=== html-string-funcs.js
=== icu-date-lord-howe.js TZ=Australia/Lord_Howe LC_ALL=en
Failure:
expected:
"Mon Jan 01 1990 11:00:00 GMT+1100 (Lord Howe Daylight Time)"
found:
"Mon Jan 01 1990 11:00:00 GMT+1100"
Failure:
expected:
"Fri Jun 01 1990 10:30:00 GMT+1030 (Lord Howe Standard Time)"
found:
"Fri Jun 01 1990 10:30:00 GMT+1030"
=== icu-date-to-string.js TZ=Europe/Madrid LC_ALL=de
Failure:
expected:
"Sun Dec 31 1989 00:00:00 GMT+0100 (Mitteleuropäische Normalzeit)"
found:
"Sun Dec 31 1989 00:00:00 GMT+0100"
Failure:
expected:
"Sat Jun 30 1990 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit)"
found:
"Sat Jun 30 1990 00:00:00 GMT+0200"
=== if-in-undefined.js
=== in.js
=== indexed-accessors.js
=== indexed-value-properties.js
=== instanceof-2.js
=== instanceof.js
=== int32-ops.js
=== integer-to-string.js
=== intl-numberformat-formattoparts.js
=== intl-pluralrules-select.js
=== invalid-source-element.js
=== json-errors.js
Failure:
expected:
"Unexpected token \n in JSON at position 3"
found:
"Bad control character in string literal in JSON at position 3 (line 1 column 4)"
Failure:
expected:
"Unexpected token \n in JSON at position 3"
found:
"Bad control character in string literal in JSON at position 3 (line 1 column 4)"
=== json-parser-recursive.js
=== json-replacer-number-wrapper-tostring.js
=== json-replacer-order.js
=== json-stringify-holder.js
=== json-stringify-recursive.js
Did not throw exception
Did not throw exception
=== json-stringify-stack.js
=== json.js
=== keyed-array-call.js
=== keyed-call-generic.js
=== keyed-call-ic.js
=== keyed-ic.js
=== keyed-storage-extend.js
=== keywords-and-reserved_words.js
=== large-object-allocation.js
=== lazy-inner-functions.js
=== lazy-load.js
=== leakcheck.js
=== length.js
=== linecontinuation.js
=== load-callback-from-value-classic.js
=== local-load-from-eval.js
=== logical.js
=== math-exp-precision.js
=== math-sqrt.js
=== md5.js
=== megamorphic-callbacks.js
=== mod.js
=== mul-exhaustive-part1.js
=== mul-exhaustive-part10.js
=== mul-exhaustive-part2.js
=== mul-exhaustive-part3.js
=== mul-exhaustive-part4.js
=== mul-exhaustive-part5.js
=== mul-exhaustive-part6.js
=== mul-exhaustive-part7.js
=== mul-exhaustive-part8.js
=== mul-exhaustive-part9.js
=== multiline.js
=== multiple-return.js
=== negate-zero.js
=== negate.js
=== new-function.js
Failure: expected <true> found <false>
=== new.js
=== newline-in-string.js
=== no-branch-elimination.js
=== no-octal-constants-above-256.js
=== no-semicolon.js
=== non-ascii-replace.js
=== not.js
=== nul-characters.js
=== number-is.js
=== number-limits.js
=== number-literal.js
=== number-string-index-call.js
=== number-tostring-add.js
=== number-tostring-big-integer.js
=== number-tostring-func.js
=== number-tostring-small.js
=== number-tostring.js
=== numops-fuzz-part1.js
=== numops-fuzz-part2.js
=== numops-fuzz-part3.js
=== numops-fuzz-part4.js
=== obj-construct.js
=== object-create.js
=== object-define-properties.js
Failure: expected <undefined> found <1>
=== object-freeze-global.js
=== object-get-own-property-names.js
=== object-is.js
=== object-literal-conversions.js
=== object-literal-gc.js
=== object-literal-modified-object-prototype.js
=== object-literal-multiple-fields.js
=== object-literal-multiple-proto-fields.js
=== object-seal-global.js
=== object-toprimitive.js
=== override-read-only-property.js
=== parallel-compile-tasks.js
=== parse-int-float.js
=== parse-surrogates.js
=== preparse-toplevel-strict-eval.js
=== primitive-keyed-access.js
Failure: expected <100> found <200>
Did not throw exception
=== print.js
Failure (printErr should be defined): expected <"function"> found <"undefined">
=== property-load-across-eval.js
=== property-name-eval-arguments.js
=== property-object-key.js
=== proto-accessor.js
=== proto-elements-add-during-foreach.js
=== proto.js
=== prototype.js
=== random-bit-correlations.js
=== readonly-accessor.js
=== receiver-in-with-calls.js
=== regexp-UC16.js
=== regexp-call-as-function.js
=== regexp-capture.js
Failure: expected <["",undefined,""]> found <["","undefined",""]>
Failure: expected <["",undefined,""]> found <["","undefined",""]>
Failure: expected <["bbaa","a","","a"]> found <["abba","bba","b","a"]>
=== regexp-captures.js
=== regexp-compile.js
=== regexp-global.js
SyntaxError: too many captures
at RegExp (native)
at <eval> (regexp-global.js:169:36)
=== regexp-lastIndex.js
=== regexp-lookahead.js
=== regexp-loop-capture.js
Failure: expected <["abc",undefined,undefined,"c"]> found <["abc","a","b","c"]>
Failure: expected <["ab",undefined]> found <["ab","a"]>
=== regexp-multiline.js
Failure: expected <true> found <false>
Failure: expected <true> found <false>
=== regexp-override-exec.js
=== regexp-override-symbol-match.js
=== regexp-override-symbol-replace.js
=== regexp-override-symbol-search.js
=== regexp-override-symbol-split.js
=== regexp-regexpexec.js
=== regexp-results-cache.js
=== regexp-sort.js
=== regexp-stack-overflow.js
=== regexp-standalones.js
=== regexp-string-methods.js
=== regress-regexp-functional-replace-slow.js
=== result-table-max.js
=== result-table-min.js
=== scanner.js
=== scope-calls-eval.js
=== search-string-multiple.js
=== serialize-after-execute.js
=== serialize-ic.js
=== shifts.js
=== short-circuit-boolean.js
=== simple-constructor.js
=== skipping-inner-functions-bailout.js
=== skipping-inner-functions.js
=== smi-negative-zero.js
=== smi-ops-inlined.js
=== smi-ops.js
=== sparse-array.js
=== splice-proxy.js
=== spread-large-array.js
=== spread-large-map.js
=== spread-large-set.js
=== spread-large-string.js
=== stack-traces-2.js
=== stack-traces-custom-lazy.js
Failure:
expected:
"bar"
found:
" at <anonymous> (stack-traces-custom-lazy.js:47:46)\n at testPrepareStackTrace (stack-traces-custom-lazy.js:31:5)\n at <eval> (stack-traces-custom-lazy.js:47:60)\n"
Failure:
expected:
"bar"
found:
" at f (stack-traces-custom-lazy.js:48:38)\n at f (stack-traces-custom-lazy.js:48:38)\n at f (stack-traces-custom-lazy.js:48:38)\n at f (stack-traces-custom-lazy.js:48:38)\n at f (stack-traces-custom-lazy.js:48:38)\n at f (stack-traces-custom-lazy.js
=== stack-traces-custom.js
TypeError: not a function
at <eval> (stack-traces-custom.js:20:21)
=== stack-traces-overflow.js
Failure: expected <true> found <false>
Failure: expected <true> found <false>
Failure: expected <undefined> found <"">
=== stack-traces.js
Failure (testArrayNative doesn't contain expected[0] stack = at <anonymous> (stack-traces.js:48:31)
at map (native)
at testArrayNative (stack-traces.js:48:37)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:267:47)
): expected <true> found <false>
Failure (testMethodNameInference doesn't contain expected[0] stack = at <anonymous> (stack-traces.js:30:37)
at testMethodNameInference (stack-traces.js:31:8)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:269:63)
): expected <true> found <false>
Failure (testImplicitConversion doesn't contain expected[0] stack = at <anonymous> (stack-traces.js:53:42)
at testImplicitConversion (stack-traces.js:54:19)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:270:61)
): expected <true> found <false>
Failure (testEval doesn't contain expected[0] stack = at Doo (<input>:1:17)
at <eval> (<input>:1:26)
at testEval (stack-traces.js:58:3)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:271:33)
): expected <true> found <false>
Failure (testNestedEval doesn't contain expected[0] stack = at <eval> (<input>:1:1)
at Inner (<input>:1:19)
at Outer (<input>:1:58)
at <eval> (<input>:1:70)
at testNestedEval (stack-traces.js:63:3)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:272:45)
):
Failure (testEvalWithSourceURL doesn't contain expected[0] stack = at Doo (<input>:1:17)
at <eval> (<input>:1:26)
at testEvalWithSourceURL (stack-traces.js:67:3)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:274:34)
): expected <true> found <false>
Failure (testNestedEvalWithSourceURL doesn't contain expected[0] stack = at <eval> (<input>:1:1)
at Inner (<input>:1:19)
at Outer (<input>:1:36)
at <eval> (<input>:1:48)
at testNestedEvalWithSourceURL (stack-traces.js:73:3)
at testTrace (stack-traces.js:162:5)
at <eval> (
Failure (testNestedEvalWithSourceURL doesn't contain expected[1] stack = at <eval> (<input>:1:1)
at Inner (<input>:1:19)
at Outer (<input>:1:36)
at <eval> (<input>:1:48)
at testNestedEvalWithSourceURL (stack-traces.js:73:3)
at testTrace (stack-traces.js:162:5)
at <eval> (
Failure (testValue doesn't contain expected[0] stack = at <anonymous> (stack-traces.js:77:47)
at testValue (stack-traces.js:78:3)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:278:35)
): expected <true> found <false>
Failure (testConstructor doesn't contain expected[0] stack = at Plonk (stack-traces.js:82:22)
at testConstructor (stack-traces.js:83:7)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:279:47)
): expected <true> found <false>
Failure (testRenamedMethod doesn't contain expected[0] stack = at a$b$c$d (stack-traces.js:87:31)
at testRenamedMethod (stack-traces.js:90:8)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:280:51)
): expected <true> found <false>
Failure (testAnonymousMethod doesn't contain expected[0] stack = at <anonymous> (stack-traces.js:94:18)
at call (native)
at testAnonymousMethod (stack-traces.js:94:38)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:281:55)
): expected <true> found <false>
Failure (testFunctionName doesn't contain expected[2] stack = at foo_0 (stack-traces.js:101:9)
at foo_1 (stack-traces.js:103:27)
at <anonymous> (stack-traces.js:103:27)
at boo_3 (stack-traces.js:103:27)
at <anonymous> (stack-traces.js:103:27)
at testFunctionName (stack-traces
Failure (testFunctionName doesn't contain expected[4] stack = at foo_0 (stack-traces.js:101:9)
at foo_1 (stack-traces.js:103:27)
at <anonymous> (stack-traces.js:103:27)
at boo_3 (stack-traces.js:103:27)
at <anonymous> (stack-traces.js:103:27)
at testFunctionName (stack-traces
Failure (testDefaultCustomError doesn't contain expected[0] stack = at CustomError (stack-traces.js:130:33)
at testDefaultCustomError (stack-traces.js:138:36)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:287:5)
): expected <true> found <false>
Failure (testDefaultCustomError doesn't contain expected[1] stack = at CustomError (stack-traces.js:130:33)
at testDefaultCustomError (stack-traces.js:138:36)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:287:5)
): expected <true> found <false>
Failure (testStrippedCustomError doesn't contain expected[0] stack = at CustomError (stack-traces.js:130:33)
at testStrippedCustomError (stack-traces.js:142:36)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:289:25)
): expected <true> found <false>
Failure (testClassNames doesn't contain expected[0] stack = at MyObj (stack-traces.js:145:22)
at <anonymous> (stack-traces.js:150:14)
at testClassNames (stack-traces.js:154:8)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:291:49)
): expected <true> found <false>
Failure (testClassNames doesn't contain expected[1] stack = at MyObj (stack-traces.js:145:22)
at <anonymous> (stack-traces.js:150:14)
at testClassNames (stack-traces.js:154:8)
at testTrace (stack-traces.js:162:5)
at <eval> (stack-traces.js:291:49)
): expected <true> found <false>
Failure (UnintendedCallerCensorship didn't contain new ReferenceError): expected <true> found <false>
Failure: expected <"abc"> found <undefined>
Failure: expected <"abc"> found <" at <eval> (stack-traces.js:371:13)\n">
Failure: expected <undefined> found <" at <eval> (stack-traces.js:375:13)\n">
TypeError: not a function
at <eval> (stack-traces.js:381:1)
=== str-to-num.js
Failure: expected <7.922816251426436e+28> found <7.922816251426434e+28>
=== stress-array-push.js
=== strict-equals.js
=== strict-mode-eval.js
=== strict-mode.js
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Did not throw exception
Failure: expected <null> found <undefined>
Failure: expected <undefined> found <function non_strict() {
return return_my_caller();
}>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
Failure: expected <null> found <undefined>
TypeError: cannot read property 'value' of undefined
at <anonymous> (strict-mode.js:1213:58)
at recurse (strict-mode.js:1207:14)
at non_strict (strict-mode.js:1214:5)
at strict (strict-mode.js:1199:15)
at <anonymous> (strict-mode.js:1218:43)
at recurse (strict-mode.js:1207:14)
at test (strict-mode.js:1218:54)
at TestNonStrictFunctionCallerDescriptorPill (strict-mode.js:1222:22)
at <eval> (strict-mode.js:1224:1)
=== string-add.js
=== string-charat.js
=== string-compare-alignment.js
=== string-concat.js
=== string-equal.js
=== string-flatten.js
=== string-indexof-2.js
=== string-lastindexof.js
=== string-localecompare.js
=== string-normalize.js
=== string-oom-concat.js
=== string-pad.js
=== string-replace-gc.js
=== string-replace-one-char.js
=== string-search.js
=== string-split-cache.js
=== string-trim.js
=== string-wrapper.js
=== substr.js
=== test-builtins-setup.js
=== this-dynamic-lookup.js
=== this-in-callbacks.js
=== this-property-assignment.js
=== this.js
=== throw-and-catch-function.js
=== throw-exception-for-null-access.js
=== to-precision.js
=== to_number_order.js
=== tobool.js
=== toint32.js
=== top-level-assignments.js
=== touint32.js
=== transcendentals.js
=== try-catch-default-destructuring.js
=== try-catch-extension-object.js
=== try-catch-scopes.js
=== try-finally-continue.js
=== try-finally-nested.js
=== try.js
=== typeof.js
=== tzoffset-seoul-noi18n.js TZ=Asia/Seoul
=== tzoffset-seoul.js TZ=Asia/Seoul
=== tzoffset-transition-apia.js TZ=Pacific/Apia
Failure: expected <Date(1316872800000)> found <Date(1316876400000)>
Failure: expected <Date(1316874600000)> found <Date(1316878200000)>
Failure: expected <Date(1325275200000)> found <Date(1325188800000)>
Failure: expected <Date(1325277000000)> found <Date(1325190600000)>
Failure: expected <Date(1325278800000)> found <Date(1325192400000)>
Failure: expected <Date(1325280600000)> found <Date(1325194200000)>
Failure: expected <Date(1325282400000)> found <Date(1325196000000)>
Failure: expected <Date(1325284200000)> found <Date(1325197800000)>
Failure: expected <Date(1325286000000)> found <Date(1325199600000)>
Failure: expected <Date(1325287800000)> found <Date(1325201400000)>
Failure: expected <Date(1325289600000)> found <Date(1325203200000)>
Failure: expected <Date(1325291400000)> found <Date(1325205000000)>
Failure: expected <Date(1325293200000)> found <Date(1325206800000)>
Failure: expected <Date(1325295000000)> found <Date(1325208600000)>
Failure: expected <Date(1325296800000)> found <Date(1325210400000)>
Failure: expected <Date(1325298600000)> found <Date(1325212200000)>
Failure: expected <Date(1325300400000)> found <Date(1325214000000)>
Failure: expected <Date(1325302200000)> found <Date(1325215800000)>
Failure: expected <Date(1325304000000)> found <Date(1325217600000)>
Failure: expected <Date(1325305800000)> found <Date(1325219400000)>
Failure: expected <Date(1325307600000)> found <Date(1325221200000)>
Failure: expected <Date(1325309400000)> found <Date(1325223000000)>
Failure: expected <Date(1325311200000)> found <Date(1325224800000)>
Failure: expected <Date(1325313000000)> found <Date(1325226600000)>
Failure: expected <Date(1325314800000)> found <Date(1325228400000)>
Failure: expected <Date(1325316600000)> found <Date(1325230200000)>
Failure: expected <Date(1325318400000)> found <Date(1325232000000)>
Failure: expected <Date(1325320200000)> found <Date(1325233800000)>
Failure: expected <Date(1325322000000)> found <Date(1325235600000)>
Failure: expected <Date(1325323800000)> found <Date(1325237400000)>
Failure: expected <Date(1333198800000)> found <Date(1333202400000)>
Failure: expected <Date(1333200600000)> found <Date(1333204200000)>
Failure: expected <Date(1333202340000)> found <Date(1333205940000)>
=== tzoffset-transition-lord-howe.js TZ=Australia/Lord_Howe
Failure: expected <Date(1491056940000)> found <Date(1491058740000)>
Failure: expected <Date(1491057000000)> found <Date(1491058800000)>
Failure: expected <Date(1491057900000)> found <Date(1491059700000)>
Failure: expected <Date(1491058740000)> found <Date(1491060540000)>
Failure: expected <Date(1506785340000)> found <Date(1506783540000)>
Failure: expected <Date(1506785400000)> found <Date(1506783600000)>
Failure: expected <Date(1506786300000)> found <Date(1506784500000)>
Failure: expected <-660> found <-630>
=== tzoffset-transition-moscow.js TZ=Europe/Moscow
Failure: expected <Date(1269730740000)> found <Date(1269727140000)>
Failure: expected <Date(1269730800000)> found <Date(1269727200000)>
Failure: expected <Date(1269732600000)> found <Date(1269729000000)>
Failure: expected <-240> found <-180>
Failure: expected <Date(1288475940000)> found <Date(1288479540000)>
Failure: expected <Date(1288476000000)> found <Date(1288479600000)>
Failure: expected <Date(1288477800000)> found <Date(1288481400000)>
Failure: expected <Date(1288479540000)> found <Date(1288483140000)>
Failure: expected <Date(1301180340000)> found <Date(1301176740000)>
Failure: expected <Date(1301180400000)> found <Date(1301176800000)>
Failure: expected <Date(1301182200000)> found <Date(1301178600000)>
Failure: expected <-240> found <-180>
Failure: expected <Date(1414270740000)> found <Date(1414274340000)>
Failure: expected <Date(1414270800000)> found <Date(1414274400000)>
Failure: expected <Date(1414272600000)> found <Date(1414276200000)>
Failure: expected <Date(1414274340000)> found <Date(1414277940000)>
=== tzoffset-transition-new-york-noi18n.js TZ=America/New_York
Failure: expected <Date(1489302000000)> found <Date(1489305600000)>
Failure: expected <Date(1489303800000)> found <Date(1489307400000)>
Failure: expected <Date(1509865200000)> found <Date(1509861600000)>
Failure: expected <Date(1509868800000)> found <Date(1509865200000)>
=== tzoffset-transition-new-york.js TZ=America/New_York
Failure: expected <Date(1489302000000)> found <Date(1489305600000)>
Failure: expected <Date(1489303800000)> found <Date(1489307400000)>
Failure: expected <Date(1509865200000)> found <Date(1509861600000)>
Failure: expected <Date(1509868800000)> found <Date(1509865200000)>
=== ubsan-fuzzerbugs.js
=== undeletable-functions.js
=== unicode-case-overoptimization.js
Failure (181): expected <true> found <false>
Failure (224): expected <true> found <false>
Failure (225): expected <true> found <false>
Failure (226): expected <true> found <false>
Failure (227): expected <true> found <false>
Failure (228): expected <true> found <false>
Failure (229): expected <true> found <false>
Failure (230): expected <true> found <false>
Failure (231): expected <true> found <false>
Failure (232): expected <true> found <false>
Failure (233): expected <true> found <false>
Failure (234): expected <true> found <false>
Failure (235): expected <true> found <false>
Failure (236): expected <true> found <false>
Failure (237): expected <true> found <false>
Failure (238): expected <true> found <false>
Failure (239): expected <true> found <false>
Failure (240): expected <true> found <false>
Failure (241): expected <true> found <false>
Failure (242): expected <true> found <false>
Failure (243): expected <true> found <false>
Failure (244): expected <true> found <false>
Failure (245): expected <true> found <false>
Failure (246): expected <true> found <false>
Failure (248): expected <true> found <false>
Failure (249): expected <true> found <false>
Failure (250): expected <true> found <false>
Failure (251): expected <true> found <false>
Failure (252): expected <true> found <false>
Failure (253): expected <true> found <false>
Failure (254): expected <true> found <false>
Failure (255): expected <true> found <false>
Failure (257): expected <true> found <false>
Failure (259): expected <true> found <false>
Failure (261): expected <true> found <false>
Failure (263): expected <true> found <false>
Failure (265): expected <true> found <false>
Failure (267): expected <true> found <false>
Failure (269): expected <true> found <false>
Failure (271): expected <true> found <false>
Failure (273): expected <true> found <false>
Failure (275): expected <true> found <false>
Failure (277): expected <true> found <false>
Failure (279): expected <true> found <false>
Failure (281): expected <true> found <false>
Failure (283): expected <true> found <false>
Failure (285): expected <true> found <false>
Failure (287): expected <true> found <false>
Failure (289): expected <true> found <false>
Failure (291): expected <true> found <false>
Failure (293): expected <true> found <false>
Failure (295): expected <true> found <false>
Failure (297): expected <true> found <false>
Failure (299): expected <true> found <false>
Failure (301): expected <true> found <false>
Failure (303): expected <true> found <false>
Failure (307): expected <true> found <false>
Failure (309): expected <true> found <false>
Failure (311): expected <true> found <false>
Failure (314): expected <true> found <false>
Failure (316): expected <true> found <false>
Failure (318): expected <true> found <false>
Failure (320): expected <true> found <false>
Failure (322): expected <true> found <false>
Failure (324): expected <true> found <false>
Failure (326): expected <true> found <false>
Failure (328): expected <true> found <false>
Failure (331): expected <true> found <false>
Failure (333): expected <true> found <false>
Failure (335): expected <true> found <false>
Failure (337): expected <true> found <false>
Failure (339): expected <true> found <false>
Failure (341): expected <true> found <false>
Failure (343): expected <true> found <false>
Failure (345): expected <true> found <false>
Failure (347): expected <true> found <false>
Failure (349): expected <true> found <false>
Failure (351): expected <true> found <false>
Failure (353): expected <true> found <false>
Failure (355): expected <true> found <false>
Failure (357): expected <true> found <false>
Failure (359): expected <true> found <false>
Failure (361): expected <true> found <false>
Failure (363): expected <true> found <false>
Failure (365): expected <true> found <false>
Failure (367): expected <true> found <false>
Failure (369): expected <true> found <false>
Failure (371): expected <true> found <false>
Failure (373): expected <true> found <false>
Failure (375): expected <true> found <false>
Failure (378): expected <true> found <false>
Failure (380): expected <true> found <false>
Failure (382): expected <true> found <false>
Failure (384): expected <true> found <false>
Failure (387): expected <true> found <false>
Failure (389): expected <true> found <false>
Failure (392): expected <true> found <false>
Failure (396): expected <true> found <false>
Failure (402): expected <true> found <false>
<output elided>
=== unicode-string-to-number.js
=== unicode-test.js
=== unicodelctest-no-optimization.js
=== unicodelctest.js
=== unused-context-in-with.js
=== unusual-constructor.js
=== uri.js
=== value-callic-prototype-change.js
=== value-of.js
=== value-wrapper.js
=== var.js
=== whitespaces.js
=== with-function-expression.js
=== with-leave.js
=== with-parameter-access.js
=== with-prototype.js
=== with-readonly.js
=== with-value.js