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
- 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
* 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)
- `-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
* 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.)
- 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
* 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`
- 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
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
- 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
* 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()`
- 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
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.
* 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
* 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)
* 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
* 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)`
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
* 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
* 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**
* 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()`
- 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
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>
* 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>
`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
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.
`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.
`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.
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
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.
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.
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.
The default 256 kb stack is too small to run some of the test262 tests
when ASAN is enabled.
Double it to 512 kb and ensure threads created by quickjs have big
enough stacks.
Change JS_WriteObject() and JS_WriteObject2() to write little-endian
data and update JS_ReadObject() to byte-swap data when running on a
big-endian system.
Obsoletes the JS_WRITE_OBJ_BSWAP flag, it is now a no-op.
Fixes: https://github.com/quickjs-ng/quickjs/issues/125
Spec compliance bug: "await" is illegal inside initializer blocks
_except_ when used as an identifier in a function expression, like so:
class C {
static {
var f = function await() {}
}
}
It is somewhat complicated to make the parser understand the distinction
and such code is probably rare or non-existent so I decided to leave
well enough alone for now.
Observed in generated code for static initializers. We could in theory
track and correct it in js_parse_class() but doing it as a peephole
optimization is both easier and more general.
A poisoned .constructor property is observable and the resulting
exception should be delivered to the catch handler, not silently
dropped, otherwise the generator hangs.