From ced222fdbabacc695f8f081c5b009afc9be6b8d0 Mon Sep 17 00:00:00 2001 From: Haled Odat <8566042+HalidOdat@users.noreply.github.com> Date: Sun, 12 May 2024 21:48:06 +0200 Subject: [PATCH] Separate `JsString` into its own crate (#3837) --- ABOUT.md | 2 + Cargo.lock | 16 +- Cargo.toml | 1 + cli/ABOUT.md | 2 + core/ast/ABOUT.md | 2 + core/engine/ABOUT.md | 2 + core/engine/Cargo.toml | 5 +- core/engine/src/builtins/array/mod.rs | 2 +- core/engine/src/builtins/array_buffer/mod.rs | 2 +- .../src/builtins/array_buffer/shared.rs | 2 +- .../engine/src/builtins/async_function/mod.rs | 2 +- .../src/builtins/async_generator/mod.rs | 2 +- .../builtins/async_generator_function/mod.rs | 2 +- core/engine/src/builtins/atomics/mod.rs | 2 +- core/engine/src/builtins/bigint/mod.rs | 2 +- core/engine/src/builtins/boolean/mod.rs | 2 +- core/engine/src/builtins/builder.rs | 2 +- core/engine/src/builtins/dataview/mod.rs | 2 +- core/engine/src/builtins/date/mod.rs | 2 +- core/engine/src/builtins/error/aggregate.rs | 2 +- core/engine/src/builtins/error/eval.rs | 2 +- core/engine/src/builtins/error/mod.rs | 2 +- core/engine/src/builtins/error/range.rs | 2 +- core/engine/src/builtins/error/reference.rs | 2 +- core/engine/src/builtins/error/syntax.rs | 2 +- core/engine/src/builtins/error/type.rs | 2 +- core/engine/src/builtins/error/uri.rs | 2 +- core/engine/src/builtins/escape/mod.rs | 4 +- core/engine/src/builtins/eval/mod.rs | 2 +- core/engine/src/builtins/function/mod.rs | 2 +- core/engine/src/builtins/generator/mod.rs | 2 +- .../src/builtins/generator_function/mod.rs | 2 +- core/engine/src/builtins/intl/collator/mod.rs | 2 +- .../src/builtins/intl/date_time_format.rs | 2 +- .../src/builtins/intl/list_format/mod.rs | 2 +- core/engine/src/builtins/intl/locale/mod.rs | 2 +- core/engine/src/builtins/intl/mod.rs | 2 +- .../src/builtins/intl/number_format/mod.rs | 2 +- .../src/builtins/intl/plural_rules/mod.rs | 2 +- .../engine/src/builtins/intl/segmenter/mod.rs | 2 +- core/engine/src/builtins/json/mod.rs | 2 +- core/engine/src/builtins/map/mod.rs | 2 +- core/engine/src/builtins/math/mod.rs | 4 +- core/engine/src/builtins/number/globals.rs | 2 +- core/engine/src/builtins/number/mod.rs | 2 +- core/engine/src/builtins/object/mod.rs | 2 +- core/engine/src/builtins/promise/mod.rs | 2 +- core/engine/src/builtins/proxy/mod.rs | 2 +- core/engine/src/builtins/reflect/mod.rs | 2 +- core/engine/src/builtins/regexp/mod.rs | 2 +- core/engine/src/builtins/set/mod.rs | 2 +- core/engine/src/builtins/string/mod.rs | 19 +- core/engine/src/builtins/symbol/mod.rs | 2 +- .../src/builtins/temporal/calendar/mod.rs | 2 +- .../src/builtins/temporal/duration/mod.rs | 2 +- .../src/builtins/temporal/instant/mod.rs | 2 +- core/engine/src/builtins/temporal/mod.rs | 2 +- core/engine/src/builtins/temporal/now.rs | 2 +- .../src/builtins/temporal/plain_date/mod.rs | 2 +- .../builtins/temporal/plain_date_time/mod.rs | 2 +- .../builtins/temporal/plain_month_day/mod.rs | 2 +- .../src/builtins/temporal/plain_time/mod.rs | 2 +- .../builtins/temporal/plain_year_month/mod.rs | 2 +- .../src/builtins/temporal/time_zone/mod.rs | 2 +- .../builtins/temporal/zoned_date_time/mod.rs | 2 +- .../src/builtins/typed_array/builtin.rs | 2 +- core/engine/src/builtins/typed_array/mod.rs | 2 +- core/engine/src/builtins/uri/mod.rs | 2 +- core/engine/src/builtins/weak/weak_ref.rs | 2 +- core/engine/src/builtins/weak_map/mod.rs | 2 +- core/engine/src/builtins/weak_set/mod.rs | 2 +- core/engine/src/object/mod.rs | 2 +- core/engine/src/object/operations.rs | 2 +- core/engine/src/string.rs | 211 ++++ core/engine/src/string/common.rs | 950 ----------------- core/engine/src/symbol.rs | 2 +- core/engine/src/tagged.rs | 1 + core/engine/src/vm/opcode/push/array.rs | 2 +- core/gc/ABOUT.md | 2 + core/gc/Cargo.toml | 3 + core/gc/src/trace.rs | 12 + core/icu_provider/ABOUT.md | 2 + core/interner/ABOUT.md | 2 + core/interop/ABOUT.md | 2 + core/macros/ABOUT.md | 2 + core/parser/ABOUT.md | 2 + core/profiler/ABOUT.md | 2 + core/runtime/ABOUT.md | 2 + core/string/ABOUT.md | 34 + core/string/Cargo.toml | 28 + core/string/src/common.rs | 951 ++++++++++++++++++ .../{engine/src/string => string/src}/iter.rs | 4 + .../src/string/mod.rs => string/src/lib.rs} | 369 ++----- core/{engine/src/string => string/src}/str.rs | 17 +- core/string/src/tagged.rs | 109 ++ core/string/src/tests.rs | 166 +++ 96 files changed, 1750 insertions(+), 1308 deletions(-) create mode 100644 core/engine/src/string.rs delete mode 100644 core/engine/src/string/common.rs create mode 100644 core/string/ABOUT.md create mode 100644 core/string/Cargo.toml create mode 100644 core/string/src/common.rs rename core/{engine/src/string => string/src}/iter.rs (97%) rename core/{engine/src/string/mod.rs => string/src/lib.rs} (82%) rename core/{engine/src/string => string/src}/str.rs (96%) create mode 100644 core/string/src/tagged.rs create mode 100644 core/string/src/tests.rs diff --git a/ABOUT.md b/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/ABOUT.md +++ b/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/Cargo.lock b/Cargo.lock index 3889476774..2a012fc602 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,6 +395,7 @@ dependencies = [ "boa_macros", "boa_parser", "boa_profiler", + "boa_string", "bytemuck", "cfg-if", "criterion", @@ -427,7 +428,6 @@ dependencies = [ "num-traits", "num_enum", "once_cell", - "paste", "pollster", "portable-atomic", "rand", @@ -437,7 +437,6 @@ dependencies = [ "serde", "serde_json", "sptr", - "static_assertions", "sys-locale", "tap", "temporal_rs", @@ -475,6 +474,7 @@ version = "0.18.0" dependencies = [ "boa_macros", "boa_profiler", + "boa_string", "hashbrown 0.14.5", "icu_locid", "thin-vec", @@ -571,6 +571,18 @@ dependencies = [ "textwrap", ] +[[package]] +name = "boa_string" +version = "0.18.0" +dependencies = [ + "boa_macros", + "fast-float", + "paste", + "rustc-hash", + "sptr", + "static_assertions", +] + [[package]] name = "boa_tester" version = "0.18.0" diff --git a/Cargo.toml b/Cargo.toml index 75650ecd0b..ac1c3bf75d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ boa_macros = { version = "~0.18.0", path = "core/macros" } boa_parser = { version = "~0.18.0", path = "core/parser" } boa_profiler = { version = "~0.18.0", path = "core/profiler" } boa_runtime = { version = "~0.18.0", path = "core/runtime" } +boa_string = { version = "~0.18.0", path = "core/string" } # Shared deps arbitrary = "1" diff --git a/cli/ABOUT.md b/cli/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/cli/ABOUT.md +++ b/cli/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/ast/ABOUT.md b/core/ast/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/ast/ABOUT.md +++ b/core/ast/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/engine/ABOUT.md b/core/engine/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/engine/ABOUT.md +++ b/core/engine/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 40883df1bd..73502507c1 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -69,11 +69,12 @@ js = ["dep:web-time"] [dependencies] boa_interner.workspace = true -boa_gc = { workspace = true, features = ["thin-vec"] } +boa_gc = { workspace = true, features = ["thin-vec", "boa_string"] } boa_profiler.workspace = true boa_macros.workspace = true boa_ast.workspace = true boa_parser.workspace = true +boa_string.workspace = true serde = { workspace = true, features = ["derive", "rc"] } serde_json.workspace = true rand = "0.8.5" @@ -89,7 +90,6 @@ fast-float.workspace = true once_cell = { workspace = true, features = ["std"] } tap = "1.0.1" sptr = "0.3.2" -static_assertions.workspace = true thiserror = "1.0.59" dashmap = "5.5.3" num_enum = "0.7.2" @@ -97,7 +97,6 @@ pollster.workspace = true thin-vec.workspace = true itertools = { version = "0.12.1", default-features = false } icu_normalizer = { workspace = true, features = ["compiled_data"] } -paste = "1.0" portable-atomic = "1.6.0" bytemuck = { version = "1.15.0", features = ["derive"] } arrayvec = "0.7.4" diff --git a/core/engine/src/builtins/array/mod.rs b/core/engine/src/builtins/array/mod.rs index aa96247040..31472c605f 100644 --- a/core/engine/src/builtins/array/mod.rs +++ b/core/engine/src/builtins/array/mod.rs @@ -32,7 +32,7 @@ use crate::{ }, property::{Attribute, PropertyDescriptor, PropertyKey, PropertyNameKind}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::{IntegerOrInfinity, JsValue}, Context, JsArgs, JsResult, JsString, diff --git a/core/engine/src/builtins/array_buffer/mod.rs b/core/engine/src/builtins/array_buffer/mod.rs index 1145c26f82..d5ea40ab55 100644 --- a/core/engine/src/builtins/array_buffer/mod.rs +++ b/core/engine/src/builtins/array_buffer/mod.rs @@ -29,7 +29,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject, Object}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsData, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/array_buffer/shared.rs b/core/engine/src/builtins/array_buffer/shared.rs index 790a15eda0..10c1092ee7 100644 --- a/core/engine/src/builtins/array_buffer/shared.rs +++ b/core/engine/src/builtins/array_buffer/shared.rs @@ -18,7 +18,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/builtins/async_function/mod.rs b/core/engine/src/builtins/async_function/mod.rs index 865510b4ea..f8db6134e9 100644 --- a/core/engine/src/builtins/async_function/mod.rs +++ b/core/engine/src/builtins/async_function/mod.rs @@ -12,7 +12,7 @@ use crate::{ context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/async_generator/mod.rs b/core/engine/src/builtins/async_generator/mod.rs index 976dab93cf..6fa423ddbd 100644 --- a/core/engine/src/builtins/async_generator/mod.rs +++ b/core/engine/src/builtins/async_generator/mod.rs @@ -19,7 +19,7 @@ use crate::{ object::{FunctionObjectBuilder, JsObject, CONSTRUCTOR}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, vm::{CompletionRecord, GeneratorResumeKind}, diff --git a/core/engine/src/builtins/async_generator_function/mod.rs b/core/engine/src/builtins/async_generator_function/mod.rs index 975bb842cd..c0ca21b09e 100644 --- a/core/engine/src/builtins/async_generator_function/mod.rs +++ b/core/engine/src/builtins/async_generator_function/mod.rs @@ -11,7 +11,7 @@ use crate::{ object::{JsObject, PROTOTYPE}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, Context, JsResult, JsString, diff --git a/core/engine/src/builtins/atomics/mod.rs b/core/engine/src/builtins/atomics/mod.rs index db74e6fbca..2d4ff957ae 100644 --- a/core/engine/src/builtins/atomics/mod.rs +++ b/core/engine/src/builtins/atomics/mod.rs @@ -16,7 +16,7 @@ use std::sync::atomic::Ordering; use crate::{ builtins::BuiltInObject, context::intrinsics::Intrinsics, js_string, object::JsObject, - property::Attribute, realm::Realm, string::common::StaticJsStrings, symbol::JsSymbol, + property::Attribute, realm::Realm, string::StaticJsStrings, symbol::JsSymbol, sys::time::Duration, value::IntegerOrInfinity, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/bigint/mod.rs b/core/engine/src/builtins/bigint/mod.rs index 3dc75356b1..947183afa5 100644 --- a/core/engine/src/builtins/bigint/mod.rs +++ b/core/engine/src/builtins/bigint/mod.rs @@ -20,7 +20,7 @@ use crate::{ object::JsObject, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::{IntegerOrInfinity, PreferredType}, Context, JsArgs, JsBigInt, JsResult, JsString, JsValue, diff --git a/core/engine/src/builtins/boolean/mod.rs b/core/engine/src/builtins/boolean/mod.rs index 3ae156b44b..b33525a023 100644 --- a/core/engine/src/builtins/boolean/mod.rs +++ b/core/engine/src/builtins/boolean/mod.rs @@ -19,7 +19,7 @@ use crate::{ js_string, object::{internal_methods::get_prototype_from_constructor, JsObject}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsResult, JsString, JsValue, }; use boa_profiler::Profiler; diff --git a/core/engine/src/builtins/builder.rs b/core/engine/src/builtins/builder.rs index c87b9ab729..610a910db3 100644 --- a/core/engine/src/builtins/builder.rs +++ b/core/engine/src/builtins/builder.rs @@ -9,7 +9,7 @@ use crate::{ }, property::{Attribute, PropertyDescriptor, PropertyKey}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, JsObject, JsString, JsValue, NativeFunction, }; diff --git a/core/engine/src/builtins/dataview/mod.rs b/core/engine/src/builtins/dataview/mod.rs index 7274cc1fd9..dd8dfef309 100644 --- a/core/engine/src/builtins/dataview/mod.rs +++ b/core/engine/src/builtins/dataview/mod.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsData, JsResult, JsString, diff --git a/core/engine/src/builtins/date/mod.rs b/core/engine/src/builtins/date/mod.rs index 49be23c5f8..17304c6e5e 100644 --- a/core/engine/src/builtins/date/mod.rs +++ b/core/engine/src/builtins/date/mod.rs @@ -27,7 +27,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::{JsValue, PreferredType}, Context, JsArgs, JsData, JsError, JsResult, JsString, diff --git a/core/engine/src/builtins/error/aggregate.rs b/core/engine/src/builtins/error/aggregate.rs index bc4b9c3292..6a8042df31 100644 --- a/core/engine/src/builtins/error/aggregate.rs +++ b/core/engine/src/builtins/error/aggregate.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::{Attribute, PropertyDescriptorBuilder}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; use boa_macros::js_str; diff --git a/core/engine/src/builtins/error/eval.rs b/core/engine/src/builtins/error/eval.rs index 266fd82053..88f6d21f0d 100644 --- a/core/engine/src/builtins/error/eval.rs +++ b/core/engine/src/builtins/error/eval.rs @@ -18,7 +18,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; use boa_macros::js_str; diff --git a/core/engine/src/builtins/error/mod.rs b/core/engine/src/builtins/error/mod.rs index ed005d0e38..39911f7115 100644 --- a/core/engine/src/builtins/error/mod.rs +++ b/core/engine/src/builtins/error/mod.rs @@ -18,7 +18,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/builtins/error/range.rs b/core/engine/src/builtins/error/range.rs index cc192396c3..15cf63d64f 100644 --- a/core/engine/src/builtins/error/range.rs +++ b/core/engine/src/builtins/error/range.rs @@ -16,7 +16,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; use boa_macros::js_str; diff --git a/core/engine/src/builtins/error/reference.rs b/core/engine/src/builtins/error/reference.rs index eb8a115862..f56f6b403a 100644 --- a/core/engine/src/builtins/error/reference.rs +++ b/core/engine/src/builtins/error/reference.rs @@ -16,7 +16,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; use boa_macros::js_str; diff --git a/core/engine/src/builtins/error/syntax.rs b/core/engine/src/builtins/error/syntax.rs index 9074856694..70333aaa10 100644 --- a/core/engine/src/builtins/error/syntax.rs +++ b/core/engine/src/builtins/error/syntax.rs @@ -18,7 +18,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; use boa_macros::js_str; diff --git a/core/engine/src/builtins/error/type.rs b/core/engine/src/builtins/error/type.rs index 3b3223d0fb..364afba24d 100644 --- a/core/engine/src/builtins/error/type.rs +++ b/core/engine/src/builtins/error/type.rs @@ -24,7 +24,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, NativeFunction, }; use boa_macros::js_str; diff --git a/core/engine/src/builtins/error/uri.rs b/core/engine/src/builtins/error/uri.rs index fcf7b1d208..36e6f275bc 100644 --- a/core/engine/src/builtins/error/uri.rs +++ b/core/engine/src/builtins/error/uri.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; use boa_macros::js_str; diff --git a/core/engine/src/builtins/escape/mod.rs b/core/engine/src/builtins/escape/mod.rs index e3fcf1cb2b..dc11cd0ae3 100644 --- a/core/engine/src/builtins/escape/mod.rs +++ b/core/engine/src/builtins/escape/mod.rs @@ -11,8 +11,8 @@ //! [spec]: https://tc39.es/ecma262/#sec-additional-properties-of-the-global-object use crate::{ - context::intrinsics::Intrinsics, js_string, realm::Realm, string::common::StaticJsStrings, - Context, JsArgs, JsObject, JsResult, JsString, JsValue, + context::intrinsics::Intrinsics, js_string, realm::Realm, string::StaticJsStrings, Context, + JsArgs, JsObject, JsResult, JsString, JsValue, }; use super::{BuiltInBuilder, BuiltInObject, IntrinsicObject}; diff --git a/core/engine/src/builtins/eval/mod.rs b/core/engine/src/builtins/eval/mod.rs index 2026208ab7..8982c716c0 100644 --- a/core/engine/src/builtins/eval/mod.rs +++ b/core/engine/src/builtins/eval/mod.rs @@ -20,7 +20,7 @@ use crate::{ js_string, object::JsObject, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, vm::{CallFrame, CallFrameFlags, Opcode}, Context, JsArgs, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/function/mod.rs b/core/engine/src/builtins/function/mod.rs index 653a402ec7..1bf76b5e82 100644 --- a/core/engine/src/builtins/function/mod.rs +++ b/core/engine/src/builtins/function/mod.rs @@ -30,7 +30,7 @@ use crate::{ }, property::{Attribute, PropertyDescriptor, PropertyKey}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::IntegerOrInfinity, vm::{ActiveRunnable, CallFrame, CallFrameFlags, CodeBlock}, diff --git a/core/engine/src/builtins/generator/mod.rs b/core/engine/src/builtins/generator/mod.rs index 3a9d56aa5b..da8e38d181 100644 --- a/core/engine/src/builtins/generator/mod.rs +++ b/core/engine/src/builtins/generator/mod.rs @@ -17,7 +17,7 @@ use crate::{ object::{JsObject, CONSTRUCTOR}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, vm::{CallFrame, CallFrameFlags, CompletionRecord, GeneratorResumeKind}, diff --git a/core/engine/src/builtins/generator_function/mod.rs b/core/engine/src/builtins/generator_function/mod.rs index 300600d1ec..c4687f1b05 100644 --- a/core/engine/src/builtins/generator_function/mod.rs +++ b/core/engine/src/builtins/generator_function/mod.rs @@ -16,7 +16,7 @@ use crate::{ object::PROTOTYPE, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, Context, JsResult, JsString, diff --git a/core/engine/src/builtins/intl/collator/mod.rs b/core/engine/src/builtins/intl/collator/mod.rs index a99aec57a6..edbb931436 100644 --- a/core/engine/src/builtins/intl/collator/mod.rs +++ b/core/engine/src/builtins/intl/collator/mod.rs @@ -29,7 +29,7 @@ use crate::{ }, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsData, JsNativeError, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/intl/date_time_format.rs b/core/engine/src/builtins/intl/date_time_format.rs index 0dff2fe4dd..f6dca66bfc 100644 --- a/core/engine/src/builtins/intl/date_time_format.rs +++ b/core/engine/src/builtins/intl/date_time_format.rs @@ -17,7 +17,7 @@ use crate::{ js_string, object::{internal_methods::get_prototype_from_constructor, JsObject}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsData, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/intl/list_format/mod.rs b/core/engine/src/builtins/intl/list_format/mod.rs index c76889ffae..6bc069570e 100644 --- a/core/engine/src/builtins/intl/list_format/mod.rs +++ b/core/engine/src/builtins/intl/list_format/mod.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsData, JsNativeError, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/intl/locale/mod.rs b/core/engine/src/builtins/intl/locale/mod.rs index a70ab770f6..9c1afe0bd2 100644 --- a/core/engine/src/builtins/intl/locale/mod.rs +++ b/core/engine/src/builtins/intl/locale/mod.rs @@ -1,4 +1,4 @@ -use crate::{builtins::options::get_option, realm::Realm, string::common::StaticJsStrings}; +use crate::{builtins::options::get_option, realm::Realm, string::StaticJsStrings}; use boa_macros::js_str; use boa_profiler::Profiler; use icu_collator::CaseFirst; diff --git a/core/engine/src/builtins/intl/mod.rs b/core/engine/src/builtins/intl/mod.rs index 149babe56b..5f033a7568 100644 --- a/core/engine/src/builtins/intl/mod.rs +++ b/core/engine/src/builtins/intl/mod.rs @@ -20,7 +20,7 @@ use crate::{ object::JsObject, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsData, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/intl/number_format/mod.rs b/core/engine/src/builtins/intl/number_format/mod.rs index 3b63fca375..a94d8e56cc 100644 --- a/core/engine/src/builtins/intl/number_format/mod.rs +++ b/core/engine/src/builtins/intl/number_format/mod.rs @@ -32,7 +32,7 @@ use crate::{ }, property::{Attribute, PropertyDescriptor}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, value::PreferredType, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, NativeFunction, diff --git a/core/engine/src/builtins/intl/plural_rules/mod.rs b/core/engine/src/builtins/intl/plural_rules/mod.rs index d0dad83b30..917e85c191 100644 --- a/core/engine/src/builtins/intl/plural_rules/mod.rs +++ b/core/engine/src/builtins/intl/plural_rules/mod.rs @@ -21,7 +21,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, ObjectInitializer}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsStr, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/builtins/intl/segmenter/mod.rs b/core/engine/src/builtins/intl/segmenter/mod.rs index 517e359b68..7353acfef5 100644 --- a/core/engine/src/builtins/intl/segmenter/mod.rs +++ b/core/engine/src/builtins/intl/segmenter/mod.rs @@ -18,7 +18,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject, ObjectInitializer}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsResult, JsStr, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/builtins/json/mod.rs b/core/engine/src/builtins/json/mod.rs index af6a4513ba..52e8debde2 100644 --- a/core/engine/src/builtins/json/mod.rs +++ b/core/engine/src/builtins/json/mod.rs @@ -27,7 +27,7 @@ use crate::{ object::{internal_methods::InternalMethodContext, JsObject}, property::{Attribute, PropertyNameKind}, realm::Realm, - string::{common::StaticJsStrings, CodePoint}, + string::{CodePoint, StaticJsStrings}, symbol::JsSymbol, value::IntegerOrInfinity, vm::{CallFrame, CallFrameFlags}, diff --git a/core/engine/src/builtins/map/mod.rs b/core/engine/src/builtins/map/mod.rs index c5c4edee46..ef8eaad1e5 100644 --- a/core/engine/src/builtins/map/mod.rs +++ b/core/engine/src/builtins/map/mod.rs @@ -18,7 +18,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::{Attribute, PropertyNameKind}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/math/mod.rs b/core/engine/src/builtins/math/mod.rs index 13d5748c07..424aed1e2d 100644 --- a/core/engine/src/builtins/math/mod.rs +++ b/core/engine/src/builtins/math/mod.rs @@ -13,8 +13,8 @@ use crate::{ builtins::BuiltInObject, context::intrinsics::Intrinsics, js_string, object::JsObject, - property::Attribute, realm::Realm, string::common::StaticJsStrings, symbol::JsSymbol, Context, - JsArgs, JsResult, JsString, JsValue, + property::Attribute, realm::Realm, string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, + JsResult, JsString, JsValue, }; use boa_profiler::Profiler; diff --git a/core/engine/src/builtins/number/globals.rs b/core/engine/src/builtins/number/globals.rs index 1900fa850c..9564d4de92 100644 --- a/core/engine/src/builtins/number/globals.rs +++ b/core/engine/src/builtins/number/globals.rs @@ -3,7 +3,7 @@ use crate::{ context::intrinsics::Intrinsics, object::JsObject, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsResult, JsStr, JsString, JsValue, }; diff --git a/core/engine/src/builtins/number/mod.rs b/core/engine/src/builtins/number/mod.rs index 025c25acf6..7334591278 100644 --- a/core/engine/src/builtins/number/mod.rs +++ b/core/engine/src/builtins/number/mod.rs @@ -21,7 +21,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, value::{AbstractRelation, IntegerOrInfinity, JsValue}, Context, JsArgs, JsResult, JsString, }; diff --git a/core/engine/src/builtins/object/mod.rs b/core/engine/src/builtins/object/mod.rs index a0fe635191..92d2abe835 100644 --- a/core/engine/src/builtins/object/mod.rs +++ b/core/engine/src/builtins/object/mod.rs @@ -28,7 +28,7 @@ use crate::{ }, property::{Attribute, PropertyDescriptor, PropertyKey, PropertyNameKind}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsData, JsResult, JsString, diff --git a/core/engine/src/builtins/promise/mod.rs b/core/engine/src/builtins/promise/mod.rs index b3fc4d103f..0578ad98eb 100644 --- a/core/engine/src/builtins/promise/mod.rs +++ b/core/engine/src/builtins/promise/mod.rs @@ -17,7 +17,7 @@ use crate::{ }, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsError, JsResult, JsString, diff --git a/core/engine/src/builtins/proxy/mod.rs b/core/engine/src/builtins/proxy/mod.rs index ea0d032910..ff6327c63c 100644 --- a/core/engine/src/builtins/proxy/mod.rs +++ b/core/engine/src/builtins/proxy/mod.rs @@ -26,7 +26,7 @@ use crate::{ }, property::{PropertyDescriptor, PropertyKey}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, value::Type, Context, JsArgs, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/reflect/mod.rs b/core/engine/src/builtins/reflect/mod.rs index f4d405adf7..841a24d4b3 100644 --- a/core/engine/src/builtins/reflect/mod.rs +++ b/core/engine/src/builtins/reflect/mod.rs @@ -19,7 +19,7 @@ use crate::{ object::{internal_methods::InternalMethodContext, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/regexp/mod.rs b/core/engine/src/builtins/regexp/mod.rs index 34be1ef965..beb782af1a 100644 --- a/core/engine/src/builtins/regexp/mod.rs +++ b/core/engine/src/builtins/regexp/mod.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject, CONSTRUCTOR}, property::Attribute, realm::Realm, - string::{common::StaticJsStrings, CodePoint, JsStrVariant}, + string::{CodePoint, JsStrVariant, StaticJsStrings}, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsData, JsResult, JsString, diff --git a/core/engine/src/builtins/set/mod.rs b/core/engine/src/builtins/set/mod.rs index a82f8c973f..2927a9e846 100644 --- a/core/engine/src/builtins/set/mod.rs +++ b/core/engine/src/builtins/set/mod.rs @@ -26,7 +26,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::{Attribute, PropertyNameKind}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/string/mod.rs b/core/engine/src/builtins/string/mod.rs index a49f08a186..f0a3d8ce34 100644 --- a/core/engine/src/builtins/string/mod.rs +++ b/core/engine/src/builtins/string/mod.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::{Attribute, PropertyDescriptor}, realm::Realm, - string::{common::StaticJsStrings, CodePoint}, + string::{CodePoint, StaticJsStrings}, symbol::JsSymbol, value::IntegerOrInfinity, Context, JsArgs, JsResult, JsString, JsValue, @@ -73,23 +73,6 @@ pub(crate) const fn is_trimmable_whitespace(c: char) -> bool { ) } -/// Helper function to check if a `u8` latin1 character is trimmable. -pub(crate) const fn is_trimmable_whitespace_latin1(c: u8) -> bool { - // The rust implementation of `trim` does not regard the same characters whitespace as ecma standard does - // - // Rust uses \p{White_Space} by default, which also includes: - // `\u{0085}' (next line) - // And does not include: - // '\u{FEFF}' (zero width non-breaking space) - // Explicit whitespace: https://tc39.es/ecma262/#sec-white-space - matches!( - c, - 0x09 | 0x0B | 0x0C | 0x20 | 0xA0 | - // Line terminators: https://tc39.es/ecma262/#sec-line-terminators - 0x0A | 0x0D - ) -} - /// JavaScript `String` implementation. #[derive(Debug, Clone, Copy)] pub(crate) struct String; diff --git a/core/engine/src/builtins/symbol/mod.rs b/core/engine/src/builtins/symbol/mod.rs index dd50afb104..ca18aee702 100644 --- a/core/engine/src/builtins/symbol/mod.rs +++ b/core/engine/src/builtins/symbol/mod.rs @@ -28,7 +28,7 @@ use crate::{ object::JsObject, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::JsValue, Context, JsArgs, JsResult, JsString, diff --git a/core/engine/src/builtins/temporal/calendar/mod.rs b/core/engine/src/builtins/temporal/calendar/mod.rs index 2da4335a92..489e8f0163 100644 --- a/core/engine/src/builtins/temporal/calendar/mod.rs +++ b/core/engine/src/builtins/temporal/calendar/mod.rs @@ -18,7 +18,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{custom_trace, Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index 8e242ae44a..f22ef7599c 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -10,7 +10,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/instant/mod.rs b/core/engine/src/builtins/temporal/instant/mod.rs index 48335b5db3..d4c927e4ca 100644 --- a/core/engine/src/builtins/temporal/instant/mod.rs +++ b/core/engine/src/builtins/temporal/instant/mod.rs @@ -14,7 +14,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsBigInt, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index adb2688780..d8aa749aaa 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -33,7 +33,7 @@ use crate::{ js_string, property::{Attribute, PropertyKey}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, value::Type, Context, JsBigInt, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/builtins/temporal/now.rs b/core/engine/src/builtins/temporal/now.rs index 4e13a3424d..0578244144 100644 --- a/core/engine/src/builtins/temporal/now.rs +++ b/core/engine/src/builtins/temporal/now.rs @@ -9,7 +9,7 @@ use crate::{ js_string, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, sys::time::SystemTime, Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/builtins/temporal/plain_date/mod.rs b/core/engine/src/builtins/temporal/plain_date/mod.rs index aac77d7e01..558d8121a6 100644 --- a/core/engine/src/builtins/temporal/plain_date/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date/mod.rs @@ -13,7 +13,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/plain_date_time/mod.rs b/core/engine/src/builtins/temporal/plain_date_time/mod.rs index 462b1caf33..55e4d81562 100644 --- a/core/engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date_time/mod.rs @@ -11,7 +11,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/plain_month_day/mod.rs b/core/engine/src/builtins/temporal/plain_month_day/mod.rs index 3cdc17652b..62e483ab2b 100644 --- a/core/engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/core/engine/src/builtins/temporal/plain_month_day/mod.rs @@ -6,7 +6,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/plain_time/mod.rs b/core/engine/src/builtins/temporal/plain_time/mod.rs index 846b23cc63..adba3b53ed 100644 --- a/core/engine/src/builtins/temporal/plain_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_time/mod.rs @@ -10,7 +10,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/plain_year_month/mod.rs b/core/engine/src/builtins/temporal/plain_year_month/mod.rs index c651534b5d..4b06c7ae46 100644 --- a/core/engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/core/engine/src/builtins/temporal/plain_year_month/mod.rs @@ -7,7 +7,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/time_zone/mod.rs b/core/engine/src/builtins/temporal/time_zone/mod.rs index 826cf94bb5..a1e35e93e6 100644 --- a/core/engine/src/builtins/temporal/time_zone/mod.rs +++ b/core/engine/src/builtins/temporal/time_zone/mod.rs @@ -11,7 +11,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, CONSTRUCTOR}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{custom_trace, Finalize, Trace}; diff --git a/core/engine/src/builtins/temporal/zoned_date_time/mod.rs b/core/engine/src/builtins/temporal/zoned_date_time/mod.rs index d95f7de02f..3c0e8691d5 100644 --- a/core/engine/src/builtins/temporal/zoned_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/zoned_date_time/mod.rs @@ -4,7 +4,7 @@ use crate::{ context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsBigInt, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{custom_trace, Finalize, Trace}; diff --git a/core/engine/src/builtins/typed_array/builtin.rs b/core/engine/src/builtins/typed_array/builtin.rs index 9119edd361..faa4961e6e 100644 --- a/core/engine/src/builtins/typed_array/builtin.rs +++ b/core/engine/src/builtins/typed_array/builtin.rs @@ -24,7 +24,7 @@ use crate::{ object::internal_methods::get_prototype_from_constructor, property::{Attribute, PropertyNameKind}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, value::IntegerOrInfinity, Context, JsArgs, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/builtins/typed_array/mod.rs b/core/engine/src/builtins/typed_array/mod.rs index 15f63e0fe3..8bbdf820a6 100644 --- a/core/engine/src/builtins/typed_array/mod.rs +++ b/core/engine/src/builtins/typed_array/mod.rs @@ -23,7 +23,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, value::{JsValue, Numeric}, Context, JsArgs, JsResult, JsString, diff --git a/core/engine/src/builtins/uri/mod.rs b/core/engine/src/builtins/uri/mod.rs index 3389a36f6d..0e7fb3d476 100644 --- a/core/engine/src/builtins/uri/mod.rs +++ b/core/engine/src/builtins/uri/mod.rs @@ -25,7 +25,7 @@ use crate::{ js_string, object::{JsFunction, JsObject}, realm::Realm, - string::{common::StaticJsStrings, CodePoint}, + string::{CodePoint, StaticJsStrings}, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/weak/weak_ref.rs b/core/engine/src/builtins/weak/weak_ref.rs index 8442e6ac1b..a19ec15a7c 100644 --- a/core/engine/src/builtins/weak/weak_ref.rs +++ b/core/engine/src/builtins/weak/weak_ref.rs @@ -8,7 +8,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, ErasedVTableObject, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/weak_map/mod.rs b/core/engine/src/builtins/weak_map/mod.rs index 01cd63c0a9..57e2bd588e 100644 --- a/core/engine/src/builtins/weak_map/mod.rs +++ b/core/engine/src/builtins/weak_map/mod.rs @@ -17,7 +17,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, ErasedVTableObject, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/builtins/weak_set/mod.rs b/core/engine/src/builtins/weak_set/mod.rs index d90a825772..493051b873 100644 --- a/core/engine/src/builtins/weak_set/mod.rs +++ b/core/engine/src/builtins/weak_set/mod.rs @@ -14,7 +14,7 @@ use crate::{ object::{internal_methods::get_prototype_from_constructor, ErasedVTableObject, JsObject}, property::Attribute, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, symbol::JsSymbol, Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; diff --git a/core/engine/src/object/mod.rs b/core/engine/src/object/mod.rs index ffffaa5579..b6696e6e66 100644 --- a/core/engine/src/object/mod.rs +++ b/core/engine/src/object/mod.rs @@ -23,7 +23,7 @@ use crate::{ native_function::{NativeFunction, NativeFunctionObject}, property::{Attribute, PropertyDescriptor, PropertyKey}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, Context, JsStr, JsString, JsSymbol, JsValue, }; diff --git a/core/engine/src/object/operations.rs b/core/engine/src/object/operations.rs index 6cee0140e1..0301d6c10b 100644 --- a/core/engine/src/object/operations.rs +++ b/core/engine/src/object/operations.rs @@ -9,7 +9,7 @@ use crate::{ object::{JsObject, PrivateElement, PrivateName, CONSTRUCTOR, PROTOTYPE}, property::{PropertyDescriptor, PropertyDescriptorBuilder, PropertyKey, PropertyNameKind}, realm::Realm, - string::common::StaticJsStrings, + string::StaticJsStrings, value::Type, Context, JsResult, JsSymbol, JsValue, }; diff --git a/core/engine/src/string.rs b/core/engine/src/string.rs new file mode 100644 index 0000000000..cfddb9328c --- /dev/null +++ b/core/engine/src/string.rs @@ -0,0 +1,211 @@ +//! This module contains the [`js_string`][crate::js_string] macro and the +//! [`js_str`][crate::js_str] macro. +//! +//! The [`js_string`][crate::js_string] macro is used when you need to create a new [`JsString`], +//! and the [`js_str`][crate::js_str] macro is used for const conversions of string literals to [`JsStr`]. + +#[doc(inline)] +pub use boa_string::*; + +/// Utility macro to create a [`JsString`]. +/// +/// # Examples +/// +/// You can call the macro without arguments to create an empty `JsString`: +/// +/// ``` +/// use boa_engine::js_string; +/// +/// let empty_str = js_string!(); +/// assert!(empty_str.is_empty()); +/// ``` +/// +/// +/// You can create a `JsString` from a string literal, which completely skips the runtime +/// conversion from [`&str`] to [&\[u16\]][slice]: +/// +/// ``` +/// # use boa_engine::js_string; +/// let hw = js_string!("Hello, world!"); +/// assert_eq!(&hw, "Hello, world!"); +/// ``` +/// +/// Any `&[u16]` slice is a valid `JsString`, including unpaired surrogates: +/// +/// ``` +/// # use boa_engine::js_string; +/// let array = js_string!(&[0xD8AFu16, 0x00A0, 0xD8FF, 0x00F0]); +/// ``` +/// +/// You can also pass it any number of `&[u16]` as arguments to create a new `JsString` with +/// the concatenation of every slice: +/// +/// ``` +/// # use boa_engine::{js_string, js_str, JsStr}; +/// const NAME: JsStr<'_> = js_str!("human! "); +/// let greeting = js_string!("Hello, "); +/// let msg = js_string!(&greeting, NAME, js_str!("Nice to meet you!")); +/// +/// assert_eq!(&msg, "Hello, human! Nice to meet you!"); +/// ``` +#[macro_export] +#[allow(clippy::module_name_repetitions)] +macro_rules! js_string { + () => { + $crate::string::JsString::default() + }; + ($s:literal) => { + $crate::string::JsString::from($crate::js_str!($s)) + }; + ($s:expr) => { + $crate::string::JsString::from($s) + }; + ( $x:expr, $y:expr ) => { + $crate::string::JsString::concat($crate::string::JsStr::from($x), $crate::string::JsStr::from($y)) + }; + ( $( $s:expr ),+ ) => { + $crate::string::JsString::concat_array(&[ $( $crate::string::JsStr::from($s) ),+ ]) + }; +} + +#[allow(clippy::redundant_clone)] +#[cfg(test)] +mod tests { + use std::hash::{BuildHasher, BuildHasherDefault, Hash}; + + use crate::{string::StaticJsStrings, JsStr}; + + use super::JsString; + use boa_macros::{js_str, utf16}; + use rustc_hash::FxHasher; + + fn hash_value(value: &T) -> u64 { + BuildHasherDefault::::default().hash_one(value) + } + + #[test] + fn empty() { + let s = js_string!(); + assert_eq!(&s, utf16!("")); + } + + #[test] + fn refcount() { + let x = js_string!("Hello world"); + assert_eq!(x.refcount(), Some(1)); + + { + let y = x.clone(); + assert_eq!(x.refcount(), Some(2)); + assert_eq!(y.refcount(), Some(2)); + + { + let z = y.clone(); + assert_eq!(x.refcount(), Some(3)); + assert_eq!(y.refcount(), Some(3)); + assert_eq!(z.refcount(), Some(3)); + } + + assert_eq!(x.refcount(), Some(2)); + assert_eq!(y.refcount(), Some(2)); + } + + assert_eq!(x.refcount(), Some(1)); + } + + #[test] + fn static_refcount() { + let x = js_string!(); + assert_eq!(x.refcount(), None); + + { + let y = x.clone(); + assert_eq!(x.refcount(), None); + assert_eq!(y.refcount(), None); + }; + + assert_eq!(x.refcount(), None); + } + + #[test] + fn as_str() { + const HELLO: &[u16] = utf16!("Hello"); + let x = js_string!(HELLO); + + assert_eq!(&x, HELLO); + } + + #[test] + fn hash() { + const HELLOWORLD: JsStr<'_> = js_str!("Hello World!"); + let x = js_string!(HELLOWORLD); + + assert_eq!(x.as_str(), HELLOWORLD); + + assert!(HELLOWORLD.is_latin1()); + assert!(x.as_str().is_latin1()); + + let s_hash = hash_value(&HELLOWORLD); + let x_hash = hash_value(&x); + + assert_eq!(s_hash, x_hash); + } + + #[test] + fn concat() { + const Y: &[u16] = utf16!(", "); + const W: &[u16] = utf16!("!"); + + let x = js_string!("hello"); + let z = js_string!("world"); + + let xy = js_string!(&x, &JsString::from(Y)); + assert_eq!(&xy, utf16!("hello, ")); + assert_eq!(xy.refcount(), Some(1)); + + let xyz = js_string!(&xy, &z); + assert_eq!(&xyz, utf16!("hello, world")); + assert_eq!(xyz.refcount(), Some(1)); + + let xyzw = js_string!(&xyz, &JsString::from(W)); + assert_eq!(&xyzw, utf16!("hello, world!")); + assert_eq!(xyzw.refcount(), Some(1)); + } + + #[test] + fn trim_start_non_ascii_to_ascii() { + let s = "\u{2029}abc"; + let x = js_string!(s); + + let y = js_string!(x.trim_start()); + + assert_eq!(&y, s.trim_start()); + } + + #[test] + fn conversion_to_known_static_js_string() { + const JS_STR_U8: &JsStr<'_> = &js_str!("length"); + const JS_STR_U16: &JsStr<'_> = &JsStr::utf16(utf16!("length")); + + assert!(JS_STR_U8.is_latin1()); + assert!(!JS_STR_U16.is_latin1()); + + assert_eq!(JS_STR_U8, JS_STR_U8); + assert_eq!(JS_STR_U16, JS_STR_U16); + + assert_eq!(JS_STR_U8, JS_STR_U16); + assert_eq!(JS_STR_U16, JS_STR_U8); + + assert_eq!(hash_value(JS_STR_U8), hash_value(JS_STR_U16)); + + let string = StaticJsStrings::get_string(JS_STR_U8); + + assert!(string.is_some()); + assert!(string.unwrap().as_str().is_latin1()); + + let string = StaticJsStrings::get_string(JS_STR_U16); + + assert!(string.is_some()); + assert!(string.unwrap().as_str().is_latin1()); + } +} diff --git a/core/engine/src/string/common.rs b/core/engine/src/string/common.rs deleted file mode 100644 index ba7785d7f6..0000000000 --- a/core/engine/src/string/common.rs +++ /dev/null @@ -1,950 +0,0 @@ -//! List of commonly used strings in Javascript code. - -use crate::{tagged::Tagged, JsStr}; - -use super::JsString; -use boa_macros::js_str; -use paste::paste; -use rustc_hash::{FxHashMap, FxHasher}; -use std::hash::BuildHasherDefault; - -macro_rules! well_known_statics { - ( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => { - $( - paste!{ - #[doc = "Gets the static `JsString` for `\"" $string "\"`."] - pub const $name: JsString = JsString { - ptr: Tagged::from_tag( - Self::find_index($string), - ), - }; - } - )+ - }; -} - -/// List of commonly used strings in Javascript code. -/// -/// Any strings defined here are used as a static [`JsString`] instead of allocating on the heap. -#[derive(Debug, Clone, Copy)] -pub struct StaticJsStrings; - -impl StaticJsStrings { - // useful to search at compile time a certain string in the array - const fn find_index(candidate: &str) -> usize { - const fn const_eq(lhs: &[u8], rhs: &[u8]) -> bool { - if lhs.len() != rhs.len() { - return false; - } - - let mut i = 0; - while i < lhs.len() { - if lhs[i] != rhs[i] { - return false; - } - i += 1; - } - true - } - - let len = RAW_STATICS.len(); - let mut i = 0; - while i < len { - let Some(s) = RAW_STATICS[i].as_latin1() else { - // All static strings are latin1 encoded - unreachable!() - }; - if const_eq(s, candidate.as_bytes()) { - return i; - } - i += 1; - } - - panic!("couldn't find the required string on the common string array"); - } - - /// Gets the `JsString` corresponding to `string`, or `None` if the string - /// doesn't exist inside the static array. - pub(crate) fn get_string(string: &JsStr<'_>) -> Option { - if string.len() > MAX_STATIC_LENGTH { - return None; - } - - let index = RAW_STATICS_CACHE.with(|map| map.get(string).copied())?; - - Some(JsString { - ptr: Tagged::from_tag(index), - }) - } - - /// Gets the `&[u16]` slice corresponding to the provided index, or `None` if the index - /// provided exceeds the size of the static array. - pub(crate) fn get(index: usize) -> Option> { - RAW_STATICS.get(index).copied() - } - - // Some consts are only used on certain features, which triggers the unused lint. - well_known_statics! { - (EMPTY_STRING, ""), - (LENGTH, "length"), - // Symbols - (SYMBOL_ASYNC_ITERATOR, "Symbol.asyncIterator"), - (SYMBOL_HAS_INSTANCE, "Symbol.hasInstance"), - (SYMBOL_IS_CONCAT_SPREADABLE, "Symbol.isConcatSpreadable"), - (SYMBOL_ITERATOR, "Symbol.iterator"), - (SYMBOL_MATCH, "Symbol.match"), - (SYMBOL_MATCH_ALL, "Symbol.matchAll"), - (SYMBOL_REPLACE, "Symbol.replace"), - (SYMBOL_SEARCH, "Symbol.search"), - (SYMBOL_SPECIES, "Symbol.species"), - (SYMBOL_SPLIT, "Symbol.split"), - (SYMBOL_TO_PRIMITIVE, "Symbol.toPrimitive"), - (SYMBOL_TO_STRING_TAG, "Symbol.toStringTag"), - (SYMBOL_UNSCOPABLES, "Symbol.unscopables"), - (FN_SYMBOL_ASYNC_ITERATOR, "[Symbol.asyncIterator]"), - (FN_SYMBOL_HAS_INSTANCE, "[Symbol.hasInstance]"), - (FN_SYMBOL_IS_CONCAT_SPREADABLE, "[Symbol.isConcatSpreadable]"), - (FN_SYMBOL_ITERATOR, "[Symbol.iterator]"), - (FN_SYMBOL_MATCH, "[Symbol.match]"), - (FN_SYMBOL_MATCH_ALL, "[Symbol.matchAll]"), - (FN_SYMBOL_REPLACE, "[Symbol.replace]"), - (FN_SYMBOL_SEARCH, "[Symbol.search]"), - (FN_SYMBOL_SPECIES, "[Symbol.species]"), - (FN_SYMBOL_SPLIT, "[Symbol.split]"), - (FN_SYMBOL_TO_PRIMITIVE, "[Symbol.toPrimitive]"), - (FN_SYMBOL_TO_STRING_TAG, "[Symbol.toStringTag]"), - (FN_SYMBOL_UNSCOPABLES, "[Symbol.unscopables]"), - // Builtins - (ARRAY, "Array"), - (ARRAY_BUFFER, "ArrayBuffer"), - (SHARED_ARRAY_BUFFER, "SharedArrayBuffer"), - (ASYNC_FUNCTION, "AsyncFunction"), - (ASYNC_GENERATOR, "AsyncGenerator"), - (ASYNC_GENERATOR_FUNCTION, "AsyncGeneratorFunction"), - (ATOMICS, "Atomics"), - (BIG_INT, "BigInt"), - (BOOLEAN, "Boolean"), - (DATA_VIEW, "DataView"), - (DATE, "Date"), - (ERROR, "Error"), - (AGGREGATE_ERROR, "AggregateError"), - (EVAL_ERROR, "EvalError"), - (RANGE_ERROR, "RangeError"), - (REFERENCE_ERROR, "ReferenceError"), - (SYNTAX_ERROR, "SyntaxError"), - (TYPE_ERROR, "TypeError"), - (URI_ERROR, "URIError"), - (ESCAPE, "escape"), - (UNESCAPE, "unescape"), - (EVAL, "eval"), - (FUNCTION, "Function"), - (GENERATOR, "Generator"), - (GENERATOR_FUNCTION, "GeneratorFunction"), - (INTL, "Intl"), - (COLLATOR, "Collator"), - (LIST_FORMAT, "ListFormat"), - (LOCALE, "Locale"), - (PLURAL_RULES, "PluralRules"), - (SEGMENTER, "Segmenter"), - (DATE_TIME_FORMAT, "DateTimeFormat"), - (JSON, "JSON"), - (MAP, "Map"), - (MATH, "Math"), - (NUMBER, "Number"), - (NUMBER_FORMAT, "NumberFormat"), - (IS_FINITE, "isFinite"), - (IS_NAN, "isNaN"), - (PARSE_INT, "parseInt"), - (PARSE_FLOAT, "parseFloat"), - (OBJECT, "Object"), - (PROMISE, "Promise"), - (PROXY, "Proxy"), - (REFLECT, "Reflect"), - (REG_EXP, "RegExp"), - (SET, "Set"), - (STRING, "String"), - (SYMBOL, "Symbol"), - (TYPED_ARRAY, "TypedArray"), - (INT8_ARRAY, "Int8Array"), - (UINT8_ARRAY, "Uint8Array"), - (UINT8_CLAMPED_ARRAY, "Uint8ClampedArray"), - (INT16_ARRAY, "Int16Array"), - (UINT16_ARRAY, "Uint16Array"), - (INT32_ARRAY, "Int32Array"), - (UINT32_ARRAY, "Uint32Array"), - (BIG_INT64_ARRAY, "BigInt64Array"), - (BIG_UINT64_ARRAY, "BigUint64Array"), - (FLOAT32_ARRAY, "Float32Array"), - (FLOAT64_ARRAY, "Float64Array"), - (ENCODE_URI, "encodeURI"), - (ENCODE_URI_COMPONENT, "encodeURIComponent"), - (DECODE_URI, "decodeURI"), - (DECODE_URI_COMPONENT, "decodeURIComponent"), - (WEAK_REF, "WeakRef"), - (WEAK_MAP, "WeakMap"), - (WEAK_SET, "WeakSet"), - (TEMPORAL, "Temporal"), - (NOW, "Temporal.Now"), - (INSTANT, "Temporal.Instant"), - (DURATION, "Temporal.Duration"), - (PLAIN_DATE, "Temporal.PlainDate"), - (PLAIN_DATETIME, "Temporal.PlainDateTime"), - (PLAIN_TIME, "Temporal.PlainTime"), - (PLAIN_YM, "Temporal.PlainYearMonth"), - (PLAIN_MD, "Temporal.PlainMonthDay"), - (CALENDAR, "Temporal.Calendar"), - (TIMEZONE, "Temporal.TimeZone"), - (ZONED_DT, "Temporal.ZonedDateTime"), - } -} - -const MAX_STATIC_LENGTH: usize = { - let mut max = 0; - let mut i = 0; - while i < RAW_STATICS.len() { - // TOOD: Because `get_index` is not const, we are accessing doc hidden stuff, that may change. - let len = RAW_STATICS[i].len(); - if len > max { - max = len; - } - i += 1; - } - max -}; - -thread_local! { - /// Map from a string inside [`RAW_STATICS`] to its corresponding static index on `RAW_STATICS`. - static RAW_STATICS_CACHE: FxHashMap, usize> = { - let mut constants = FxHashMap::with_capacity_and_hasher( - RAW_STATICS.len(), - BuildHasherDefault::::default(), - ); - - for (idx, &s) in RAW_STATICS.iter().enumerate() { - constants.insert(s, idx); - } - - constants - }; -} - -/// Array of raw static strings that aren't reference counted. -const RAW_STATICS: &[JsStr<'_>] = &[ - js_str!(""), - // Well known symbols - js_str!("Symbol.asyncIterator"), - js_str!("[Symbol.asyncIterator]"), - js_str!("Symbol.hasInstance"), - js_str!("[Symbol.hasInstance]"), - js_str!("Symbol.isConcatSpreadable"), - js_str!("[Symbol.isConcatSpreadable]"), - js_str!("Symbol.iterator"), - js_str!("[Symbol.iterator]"), - js_str!("Symbol.match"), - js_str!("[Symbol.match]"), - js_str!("Symbol.matchAll"), - js_str!("[Symbol.matchAll]"), - js_str!("Symbol.replace"), - js_str!("[Symbol.replace]"), - js_str!("Symbol.search"), - js_str!("[Symbol.search]"), - js_str!("Symbol.species"), - js_str!("[Symbol.species]"), - js_str!("Symbol.split"), - js_str!("[Symbol.split]"), - js_str!("Symbol.toPrimitive"), - js_str!("[Symbol.toPrimitive]"), - js_str!("Symbol.toStringTag"), - js_str!("[Symbol.toStringTag]"), - js_str!("Symbol.unscopables"), - js_str!("[Symbol.unscopables]"), - js_str!("get [Symbol.species]"), - js_str!("get [Symbol.toStringTag]"), - // Well known builtins - js_str!("Array"), - js_str!("ArrayBuffer"), - js_str!("SharedArrayBuffer"), - js_str!("AsyncFunction"), - js_str!("AsyncGenerator"), - js_str!("AsyncGeneratorFunction"), - js_str!("Atomics"), - js_str!("BigInt"), - js_str!("Boolean"), - js_str!("DataView"), - js_str!("Date"), - js_str!("Error"), - js_str!("AggregateError"), - js_str!("EvalError"), - js_str!("RangeError"), - js_str!("ReferenceError"), - js_str!("SyntaxError"), - js_str!("TypeError"), - js_str!("URIError"), - js_str!("escape"), - js_str!("unescape"), - js_str!("eval"), - js_str!("Function"), - js_str!("Generator"), - js_str!("GeneratorFunction"), - js_str!("Intl"), - js_str!("Collator"), - js_str!("ListFormat"), - js_str!("Locale"), - js_str!("PluralRules"), - js_str!("Segmenter"), - js_str!("DateTimeFormat"), - js_str!("JSON"), - js_str!("Map"), - js_str!("Math"), - js_str!("Number"), - js_str!("NumberFormat"), - js_str!("isFinite"), - js_str!("isNaN"), - js_str!("parseInt"), - js_str!("parseFloat"), - js_str!("Object"), - js_str!("Promise"), - js_str!("Proxy"), - js_str!("Reflect"), - js_str!("RegExp"), - js_str!("Set"), - js_str!("String"), - js_str!("Symbol"), - js_str!("TypedArray"), - js_str!("Int8Array"), - js_str!("Uint8Array"), - js_str!("Uint8ClampedArray"), - js_str!("Int16Array"), - js_str!("Uint16Array"), - js_str!("Int32Array"), - js_str!("Uint32Array"), - js_str!("BigInt64Array"), - js_str!("BigUint64Array"), - js_str!("Float32Array"), - js_str!("Float64Array"), - js_str!("encodeURI"), - js_str!("encodeURIComponent"), - js_str!("decodeURI"), - js_str!("decodeURIComponent"), - js_str!("WeakRef"), - js_str!("WeakMap"), - js_str!("WeakSet"), - js_str!("Temporal"), - js_str!("Temporal.Now"), - js_str!("Temporal.Instant"), - js_str!("Temporal.Duration"), - js_str!("Temporal.Calendar"), - js_str!("Temporal.PlainDate"), - js_str!("Temporal.PlainDateTime"), - js_str!("Temporal.PlainMonthDay"), - js_str!("Temporal.PlainYearMonth"), - js_str!("Temporal.PlainTime"), - js_str!("Temporal.TimeZone"), - js_str!("Temporal.ZonedDateTime"), - // Misc - js_str!(","), - js_str!(":"), - // Generic use - js_str!("name"), - js_str!("length"), - js_str!("arguments"), - js_str!("prototype"), - js_str!("constructor"), - js_str!("return"), - js_str!("throw"), - js_str!("global"), - js_str!("globalThis"), - // typeof - js_str!("null"), - js_str!("undefined"), - js_str!("number"), - js_str!("string"), - js_str!("symbol"), - js_str!("bigint"), - js_str!("object"), - js_str!("function"), - // Property descriptor - js_str!("value"), - js_str!("get"), - js_str!("set"), - js_str!("writable"), - js_str!("enumerable"), - js_str!("configurable"), - // Object object - js_str!("assign"), - js_str!("create"), - js_str!("toString"), - js_str!("valueOf"), - js_str!("is"), - js_str!("seal"), - js_str!("isSealed"), - js_str!("freeze"), - js_str!("isFrozen"), - js_str!("isExtensible"), - js_str!("hasOwnProperty"), - js_str!("isPrototypeOf"), - js_str!("setPrototypeOf"), - js_str!("getPrototypeOf"), - js_str!("defineProperty"), - js_str!("defineProperties"), - js_str!("deleteProperty"), - js_str!("construct"), - js_str!("hasOwn"), - js_str!("ownKeys"), - js_str!("keys"), - js_str!("values"), - js_str!("entries"), - js_str!("fromEntries"), - js_str!("propertyIsEnumerable"), - js_str!("preventExtensions"), - js_str!("getOwnPropertyDescriptor"), - js_str!("getOwnPropertyDescriptors"), - js_str!("getOwnPropertyNames"), - js_str!("getOwnPropertySymbols"), - js_str!("__defineGetter__"), - js_str!("__defineSetter__"), - js_str!("__lookupGetter__"), - js_str!("__lookupSetter__"), - js_str!("__proto__"), - js_str!("get __proto__"), - js_str!("set __proto__"), - // Function object - js_str!("apply"), - js_str!("bind"), - js_str!("call"), - js_str!("caller"), - // Arguments object - js_str!("callee"), - // Array object - js_str!("at"), - js_str!("from"), - js_str!("isArray"), - js_str!("of"), - js_str!("copyWithin"), - js_str!("every"), - js_str!("fill"), - js_str!("filter"), - js_str!("find"), - js_str!("findIndex"), - js_str!("findLast"), - js_str!("findLastIndex"), - js_str!("flat"), - js_str!("flatMap"), - js_str!("forEach"), - js_str!("includes"), - js_str!("indexOf"), - js_str!("join"), - js_str!("map"), - js_str!("next"), - js_str!("reduce"), - js_str!("reduceRight"), - js_str!("reverse"), - js_str!("shift"), - js_str!("slice"), - js_str!("splice"), - js_str!("some"), - js_str!("sort"), - js_str!("unshift"), - js_str!("push"), - js_str!("pop"), - js_str!("groupBy"), - js_str!("toReversed"), - js_str!("toSorted"), - js_str!("toSpliced"), - js_str!("with"), - // String object - js_str!("charAt"), - js_str!("charCodeAt"), - js_str!("codePointAt"), - js_str!("concat"), - js_str!("endsWith"), - js_str!("fromCharCode"), - js_str!("fromCodePoint"), - js_str!("lastIndexOf"), - js_str!("match"), - js_str!("matchAll"), - js_str!("normalize"), - js_str!("padEnd"), - js_str!("padStart"), - js_str!("raw"), - js_str!("repeat"), - js_str!("replace"), - js_str!("replaceAll"), - js_str!("search"), - js_str!("split"), - js_str!("startsWith"), - js_str!("substr"), - js_str!("substring"), - js_str!("toLocaleString"), - js_str!("toLowerCase"), - js_str!("toUpperCase"), - js_str!("trim"), - js_str!("trimEnd"), - js_str!("trimStart"), - js_str!("isWellFormed"), - js_str!("localeCompare"), - js_str!("toWellFormed"), - js_str!("toLocaleLowerCase"), - js_str!("toLocaleUpperCase"), - js_str!("trimLeft"), - js_str!("trimRight"), - js_str!("anchor"), - js_str!("big"), - js_str!("blink"), - js_str!("bold"), - js_str!("fixed"), - js_str!("fontcolor"), - js_str!("fontsize"), - js_str!("italics"), - js_str!("link"), - js_str!("small"), - js_str!("strike"), - js_str!("sub"), - js_str!("sup"), - // Number object - js_str!("Infinity"), - js_str!("NaN"), - js_str!("EPSILON"), - js_str!("MAX_SAFE_INTEGER"), - js_str!("MIN_SAFE_INTEGER"), - js_str!("MAX_VALUE"), - js_str!("MIN_VALUE"), - js_str!("NEGATIVE_INFINITY"), - js_str!("POSITIVE_INFINITY"), - js_str!("isSafeInteger"), - js_str!("isInteger"), - js_str!("toExponential"), - js_str!("toFixed"), - js_str!("toPrecision"), - // BigInt object - js_str!("asIntN"), - js_str!("asUintN"), - // RegExp object - js_str!("exec"), - js_str!("test"), - js_str!("compile"), - js_str!("flags"), - js_str!("index"), - js_str!("lastIndex"), - js_str!("hasIndices"), - js_str!("ignoreCase"), - js_str!("multiline"), - js_str!("dotAll"), - js_str!("unicode"), - js_str!("sticky"), - js_str!("source"), - js_str!("get hasIndices"), - js_str!("get global"), - js_str!("get ignoreCase"), - js_str!("get multiline"), - js_str!("get dotAll"), - js_str!("get unicode"), - js_str!("get sticky"), - js_str!("get flags"), - js_str!("get source"), - // Symbol object - js_str!("for"), - js_str!("keyFor"), - js_str!("description"), - js_str!("asyncIterator"), - js_str!("hasInstance"), - js_str!("species"), - js_str!("unscopables"), - js_str!("iterator"), - js_str!("toStringTag"), - js_str!("toPrimitive"), - js_str!("isConcatSpreadable"), - js_str!("get description"), - // Map object - js_str!("clear"), - js_str!("delete"), - js_str!("has"), - js_str!("size"), - // Set object - js_str!("add"), - // Reflect object - // Proxy object - js_str!("revocable"), - // Error objects - js_str!("message"), - // Date object - js_str!("toJSON"), - js_str!("getDate"), - js_str!("getDay"), - js_str!("getFullYear"), - js_str!("getHours"), - js_str!("getMilliseconds"), - js_str!("getMinutes"), - js_str!("getMonth"), - js_str!("getSeconds"), - js_str!("getTime"), - js_str!("getYear"), - js_str!("getUTCDate"), - js_str!("getUTCDay"), - js_str!("getUTCFullYear"), - js_str!("getUTCHours"), - js_str!("getUTCMinutes"), - js_str!("getUTCMonth"), - js_str!("getUTCSeconds"), - js_str!("setDate"), - js_str!("setFullYear"), - js_str!("setHours"), - js_str!("setMilliseconds"), - js_str!("setMinutes"), - js_str!("setMonth"), - js_str!("setSeconds"), - js_str!("setYear"), - js_str!("setTime"), - js_str!("setUTCDate"), - js_str!("setUTCFullYear"), - js_str!("setUTCHours"), - js_str!("setUTCMinutes"), - js_str!("setUTCMonth"), - js_str!("setUTCSeconds"), - js_str!("toDateString"), - js_str!("toGMTString"), - js_str!("toISOString"), - js_str!("toTimeString"), - js_str!("toUTCString"), - js_str!("now"), - js_str!("UTC"), - js_str!("getTimezoneOffset"), - js_str!("getUTCMilliseconds"), - js_str!("setUTCMilliseconds"), - js_str!("toLocaleDateString"), - js_str!("toLocaleTimeString"), - // JSON object - js_str!("parse"), - js_str!("stringify"), - // Promise object - js_str!("promise"), - js_str!("resolve"), - js_str!("reject"), - js_str!("all"), - js_str!("allSettled"), - js_str!("any"), - js_str!("race"), - js_str!("then"), - js_str!("catch"), - js_str!("finally"), - js_str!("withResolvers"), - // Iterator object - js_str!("Array Iterator"), - js_str!("Set Iterator"), - js_str!("String Iterator"), - js_str!("Map Iterator"), - js_str!("For In Iterator"), - js_str!("RegExp String Iterator"), - // Iterator result object - js_str!("done"), - // Math object - js_str!("LN10"), - js_str!("LN2"), - js_str!("LOG10E"), - js_str!("LOG2E"), - js_str!("PI"), - js_str!("SQRT1_2"), - js_str!("SQRT2"), - js_str!("abs"), - js_str!("acos"), - js_str!("acosh"), - js_str!("asin"), - js_str!("asinh"), - js_str!("atan"), - js_str!("atanh"), - js_str!("atan2"), - js_str!("cbrt"), - js_str!("ceil"), - js_str!("clz32"), - js_str!("cos"), - js_str!("cosh"), - js_str!("exp"), - js_str!("expm1"), - js_str!("floor"), - js_str!("fround"), - js_str!("hypot"), - js_str!("imul"), - js_str!("log"), - js_str!("log1p"), - js_str!("log10"), - js_str!("log2"), - js_str!("max"), - js_str!("min"), - js_str!("pow"), - js_str!("random"), - js_str!("round"), - js_str!("sign"), - js_str!("sin"), - js_str!("sinh"), - js_str!("sqrt"), - js_str!("tan"), - js_str!("tanh"), - js_str!("trunc"), - // TypedArray object - js_str!("BYTES_PER_ELEMENT"), - js_str!("buffer"), - js_str!("byteLength"), - js_str!("byteOffset"), - js_str!("isView"), - js_str!("subarray"), - js_str!("get byteLength"), - js_str!("get buffer"), - js_str!("get byteOffset"), - js_str!("get size"), - js_str!("get length"), - // DataView object - js_str!("getBigInt64"), - js_str!("getBigUint64"), - js_str!("getFloat32"), - js_str!("getFloat64"), - js_str!("getInt8"), - js_str!("getInt16"), - js_str!("getInt32"), - js_str!("getUint8"), - js_str!("getUint16"), - js_str!("getUint32"), - js_str!("setBigInt64"), - js_str!("setBigUint64"), - js_str!("setFloat32"), - js_str!("setFloat64"), - js_str!("setInt8"), - js_str!("setInt16"), - js_str!("setInt32"), - js_str!("setUint8"), - js_str!("setUint16"), - js_str!("setUint32"), - // WeakRef object - js_str!("deref"), - // Atomic object - js_str!("and"), - js_str!("compareExchange"), - js_str!("exchange"), - js_str!("isLockFree"), - js_str!("load"), - js_str!("or"), - js_str!("store"), - js_str!("wait"), - js_str!("notify"), - js_str!("xor"), - // Intl object - js_str!("getCanonicalLocales"), - js_str!("get compare"), - js_str!("supportedLocalesOf"), - js_str!("Intl.Collator"), - js_str!("compare"), - js_str!("resolvedOptions"), - js_str!("Intl.ListFormat"), - js_str!("format"), - js_str!("formatToParts"), - js_str!("get baseName"), - js_str!("get calendar"), - js_str!("get caseFirst"), - js_str!("get collation"), - js_str!("get hourCycle"), - js_str!("get numeric"), - js_str!("get numberingSystem"), - js_str!("get language"), - js_str!("get script"), - js_str!("get region"), - js_str!("Intl.Locale"), - js_str!("maximize"), - js_str!("minimize"), - js_str!("baseName"), - js_str!("calendar"), - js_str!("caseFirst"), - js_str!("collation"), - js_str!("hourCycle"), - js_str!("numeric"), - js_str!("numberingSystem"), - js_str!("language"), - js_str!("script"), - js_str!("region"), - js_str!("Intl.Segmenter"), - js_str!("segment"), - js_str!("containing"), - js_str!("Segmenter String Iterator"), - js_str!("Intl.PluralRules"), - js_str!("select"), - // Temporal object - js_str!("get Id"), - js_str!("getOffsetNanosecondsFor"), - js_str!("getOffsetStringFor"), - js_str!("getPlainDateTimeFor"), - js_str!("getInstantFor"), - js_str!("getPossibleInstantFor"), - js_str!("getNextTransition"), - js_str!("getPreviousTransition"), - js_str!("id"), - js_str!("Now"), - js_str!("Calendar"), - js_str!("Duration"), - js_str!("Instant"), - js_str!("PlainDate"), - js_str!("PlainDateTime"), - js_str!("PlainMonthDay"), - js_str!("PlainTime"), - js_str!("PlainYearMonth"), - js_str!("TimeZone"), - js_str!("ZonedDateTime"), - js_str!("timeZoneId"), - js_str!("instant"), - js_str!("plainDateTime"), - js_str!("plainDateTimeISO"), - js_str!("zonedDateTime"), - js_str!("zonedDateTimeISO"), - js_str!("plainDate"), - js_str!("plainDateISO"), - js_str!("get epochSeconds"), - js_str!("get epochMilliseconds"), - js_str!("get epochMicroseconds"), - js_str!("get epochNanoseconds"), - js_str!("epochSeconds"), - js_str!("epochMilliseconds"), - js_str!("epochMicroseconds"), - js_str!("epochNanoseconds"), - js_str!("subtract"), - js_str!("until"), - js_str!("since"), - js_str!("equals"), - js_str!("toZonedDateTime"), - js_str!("toZonedDateTimeISO"), - js_str!("get Years"), - js_str!("get Months"), - js_str!("get Weeks"), - js_str!("get Days"), - js_str!("get Hours"), - js_str!("get Minutes"), - js_str!("get Seconds"), - js_str!("get Milliseconds"), - js_str!("get Microseconds"), - js_str!("get Nanoseconds"), - js_str!("get Sign"), - js_str!("get blank"), - js_str!("years"), - js_str!("months"), - js_str!("weeks"), - js_str!("days"), - js_str!("hours"), - js_str!("minutes"), - js_str!("seconds"), - js_str!("milliseconds"), - js_str!("microseconds"), - js_str!("nanoseconds"), - js_str!("blank"), - js_str!("negated"), - js_str!("total"), - js_str!("get calendarId"), - js_str!("get year"), - js_str!("get month"), - js_str!("get monthCode"), - js_str!("get day"), - js_str!("get dayOfWeek"), - js_str!("get dayOfYear"), - js_str!("get weekOfYear"), - js_str!("get yearOfWeek"), - js_str!("get daysInWeek"), - js_str!("get daysInMonth"), - js_str!("get daysInYear"), - js_str!("get monthsInYear"), - js_str!("get inLeapYear"), - js_str!("calendarId"), - js_str!("year"), - js_str!("month"), - js_str!("monthCode"), - js_str!("day"), - js_str!("dayOfWeek"), - js_str!("dayOfYear"), - js_str!("weekOfYear"), - js_str!("yearOfWeek"), - js_str!("daysInWeek"), - js_str!("daysInMonth"), - js_str!("daysInYear"), - js_str!("monthsInYear"), - js_str!("inLeapYear"), - js_str!("toPlainYearMonth"), - js_str!("toPlainMonthDay"), - js_str!("getISOFields"), - js_str!("getCalendar"), - js_str!("withCalendar"), - js_str!("dateFromFields"), - js_str!("yearMonthFromFields"), - js_str!("monthDayFromFields"), - js_str!("dateAdd"), - js_str!("dateUntil"), - js_str!("era"), - js_str!("eraYear"), - js_str!("fields"), - js_str!("mergeFields"), - // Console object - js_str!("console"), - js_str!("assert"), - js_str!("debug"), - js_str!("error"), - js_str!("info"), - js_str!("trace"), - js_str!("warn"), - js_str!("exception"), - js_str!("count"), - js_str!("countReset"), - js_str!("group"), - js_str!("groupCollapsed"), - js_str!("groupEnd"), - js_str!("time"), - js_str!("timeLog"), - js_str!("timeEnd"), - js_str!("dir"), - js_str!("dirxml"), - // Minified name - js_str!("a"), - js_str!("c"), - js_str!("d"), - js_str!("e"), - js_str!("f"), - js_str!("g"), - js_str!("h"), - js_str!("i"), - js_str!("j"), - js_str!("k"), - js_str!("l"), - js_str!("m"), - js_str!("n"), - js_str!("o"), - js_str!("p"), - js_str!("q"), - js_str!("r"), - js_str!("s"), - js_str!("t"), - js_str!("u"), - js_str!("v"), - js_str!("w"), - js_str!("x"), - js_str!("y"), - js_str!("z"), - js_str!("A"), - js_str!("C"), - js_str!("D"), - js_str!("E"), - js_str!("F"), - js_str!("G"), - js_str!("H"), - js_str!("I"), - js_str!("J"), - js_str!("K"), - js_str!("L"), - js_str!("M"), - js_str!("N"), - js_str!("O"), - js_str!("P"), - js_str!("Q"), - js_str!("R"), - js_str!("S"), - js_str!("T"), - js_str!("U"), - js_str!("V"), - js_str!("W"), - js_str!("X"), - js_str!("Y"), - js_str!("Z"), - js_str!("_"), - js_str!("$"), -]; diff --git a/core/engine/src/symbol.rs b/core/engine/src/symbol.rs index 11b04dd9e6..a25cf08855 100644 --- a/core/engine/src/symbol.rs +++ b/core/engine/src/symbol.rs @@ -23,7 +23,7 @@ use crate::{ js_string, - string::{common::StaticJsStrings, JsString}, + string::{JsString, StaticJsStrings}, tagged::{Tagged, UnwrappedTagged}, }; use boa_gc::{Finalize, Trace}; diff --git a/core/engine/src/tagged.rs b/core/engine/src/tagged.rs index 83ec17c24b..3415b38ed8 100644 --- a/core/engine/src/tagged.rs +++ b/core/engine/src/tagged.rs @@ -39,6 +39,7 @@ impl Clone for Tagged { impl Copy for Tagged {} +#[allow(dead_code)] impl Tagged { /// Creates a new, tagged `Tagged` pointer from an integer. /// diff --git a/core/engine/src/vm/opcode/push/array.rs b/core/engine/src/vm/opcode/push/array.rs index 9135f4109b..480e979ecf 100644 --- a/core/engine/src/vm/opcode/push/array.rs +++ b/core/engine/src/vm/opcode/push/array.rs @@ -1,6 +1,6 @@ use crate::{ builtins::Array, - string::common::StaticJsStrings, + string::StaticJsStrings, vm::{opcode::Operation, CompletionType}, Context, JsResult, JsValue, }; diff --git a/core/gc/ABOUT.md b/core/gc/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/gc/ABOUT.md +++ b/core/gc/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/gc/Cargo.toml b/core/gc/Cargo.toml index b21b61c44c..af223d0767 100644 --- a/core/gc/Cargo.toml +++ b/core/gc/Cargo.toml @@ -15,12 +15,15 @@ rust-version.workspace = true thin-vec = ["dep:thin-vec"] # Enable default implementations of trace and finalize for some `ICU4X` types icu = ["dep:icu_locid"] +# Enable default implementations of trace and finalize for the `boa_string` crate +boa_string = ["dep:boa_string"] [dependencies] boa_profiler.workspace = true boa_macros.workspace = true hashbrown = { workspace = true, features = ["ahash", "raw"] } +boa_string = { workspace = true, optional = true } thin-vec = { workspace = true, optional = true } icu_locid = { workspace = true, optional = true } diff --git a/core/gc/src/trace.rs b/core/gc/src/trace.rs index b28d976e8d..41ac9d9144 100644 --- a/core/gc/src/trace.rs +++ b/core/gc/src/trace.rs @@ -521,3 +521,15 @@ mod icu { empty_trace!(); } } + +#[cfg(feature = "boa_string")] +mod boa_string_trace { + use crate::{Finalize, Trace}; + + // SAFETY: `boa_string::JsString` doesn't have any traceable data. + unsafe impl Trace for boa_string::JsString { + empty_trace!(); + } + + impl Finalize for boa_string::JsString {} +} diff --git a/core/icu_provider/ABOUT.md b/core/icu_provider/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/icu_provider/ABOUT.md +++ b/core/icu_provider/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/interner/ABOUT.md b/core/interner/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/interner/ABOUT.md +++ b/core/interner/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/interop/ABOUT.md b/core/interop/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/interop/ABOUT.md +++ b/core/interop/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/macros/ABOUT.md b/core/macros/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/macros/ABOUT.md +++ b/core/macros/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/parser/ABOUT.md b/core/parser/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/parser/ABOUT.md +++ b/core/parser/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/profiler/ABOUT.md b/core/profiler/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/profiler/ABOUT.md +++ b/core/profiler/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/runtime/ABOUT.md b/core/runtime/ABOUT.md index c1de9c5a19..c8c37206ac 100644 --- a/core/runtime/ABOUT.md +++ b/core/runtime/ABOUT.md @@ -18,6 +18,7 @@ Try out the most recent release with Boa's live demo - [**`boa_profiler`**][profiler] - Boa's code profiler. - [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. - [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. [boa-conformance]: https://boajs.dev/conformance [boa-web]: https://boajs.dev/ @@ -30,3 +31,4 @@ Try out the most recent release with Boa's live demo [profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html [icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html [runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/string/ABOUT.md b/core/string/ABOUT.md new file mode 100644 index 0000000000..c8c37206ac --- /dev/null +++ b/core/string/ABOUT.md @@ -0,0 +1,34 @@ +# About Boa + +Boa is an open-source, experimental ECMAScript Engine written in Rust for +lexing, parsing and executing ECMAScript/JavaScript. Currently, Boa supports some +of the [language][boa-conformance]. More information can be viewed at [Boa's +website][boa-web]. + +Try out the most recent release with Boa's live demo +[playground][boa-playground]. + +## Boa Crates + +- [**`boa_ast`**][ast] - Boa's ECMAScript Abstract Syntax Tree. +- [**`boa_engine`**][engine] - Boa's implementation of ECMAScript builtin objects and execution. +- [**`boa_gc`**][gc] - Boa's garbage collector. +- [**`boa_interner`**][interner] - Boa's string interner. +- [**`boa_parser`**][parser] - Boa's lexer and parser. +- [**`boa_profiler`**][profiler] - Boa's code profiler. +- [**`boa_icu_provider`**][icu] - Boa's ICU4X data provider. +- [**`boa_runtime`**][runtime] - Boa's WebAPI features. +- [**`boa_string`**][string] - Boa's ECMAScript string implementation. + +[boa-conformance]: https://boajs.dev/conformance +[boa-web]: https://boajs.dev/ +[boa-playground]: https://boajs.dev/playground +[ast]: https://docs.rs/boa_ast/latest/boa_ast/index.html +[engine]: https://docs.rs/boa_engine/latest/boa_engine/index.html +[gc]: https://docs.rs/boa_gc/latest/boa_gc/index.html +[interner]: https://docs.rs/boa_interner/latest/boa_interner/index.html +[parser]: https://docs.rs/boa_parser/latest/boa_parser/index.html +[profiler]: https://docs.rs/boa_profiler/latest/boa_profiler/index.html +[icu]: https://docs.rs/boa_icu_provider/latest/boa_icu_provider/index.html +[runtime]: https://docs.rs/boa_runtime/latest/boa_runtime/index.html +[string]: https://docs.rs/boa_string/latest/boa_string/index.html diff --git a/core/string/Cargo.toml b/core/string/Cargo.toml new file mode 100644 index 0000000000..2a36d739c0 --- /dev/null +++ b/core/string/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "boa_string" +keywords = ["javascript", "js", "string"] +categories = ["parser-implementations", "compilers"] +readme = "../../README.md" +description.workspace = true +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[dependencies] +rustc-hash = { workspace = true, features = ["std"] } +sptr = "0.3.2" +static_assertions.workspace = true +paste = "1.0" +fast-float.workspace = true + +[dev-dependencies] +boa_macros.workspace = true + +[lints] +workspace = true + +[package.metadata.docs.rs] +all-features = true diff --git a/core/string/src/common.rs b/core/string/src/common.rs new file mode 100644 index 0000000000..8b420f7c68 --- /dev/null +++ b/core/string/src/common.rs @@ -0,0 +1,951 @@ +//! List of commonly used strings in Javascript code. + +use crate::{tagged::Tagged, JsStr}; + +use super::JsString; +use paste::paste; +use rustc_hash::{FxHashMap, FxHasher}; +use std::hash::BuildHasherDefault; + +macro_rules! well_known_statics { + ( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => { + $( + paste!{ + #[doc = "Gets the static `JsString` for `\"" $string "\"`."] + pub const $name: JsString = JsString { + ptr: Tagged::from_tag( + Self::find_index($string), + ), + }; + } + )+ + }; +} + +/// List of commonly used strings in Javascript code. +/// +/// Any strings defined here are used as a static [`JsString`] instead of allocating on the heap. +#[derive(Debug, Clone, Copy)] +pub struct StaticJsStrings; + +impl StaticJsStrings { + // useful to search at compile time a certain string in the array + const fn find_index(candidate: &str) -> usize { + const fn const_eq(lhs: &[u8], rhs: &[u8]) -> bool { + if lhs.len() != rhs.len() { + return false; + } + + let mut i = 0; + while i < lhs.len() { + if lhs[i] != rhs[i] { + return false; + } + i += 1; + } + true + } + + let len = RAW_STATICS.len(); + let mut i = 0; + while i < len { + let Some(s) = RAW_STATICS[i].as_latin1() else { + // All static strings are latin1 encoded + unreachable!() + }; + if const_eq(s, candidate.as_bytes()) { + return i; + } + i += 1; + } + + panic!("couldn't find the required string on the common string array"); + } + + /// Gets the `JsString` corresponding to `string`, or `None` if the string + /// doesn't exist inside the static array. + #[inline] + #[must_use] + pub fn get_string(string: &JsStr<'_>) -> Option { + if string.len() > MAX_STATIC_LENGTH { + return None; + } + + let index = RAW_STATICS_CACHE.with(|map| map.get(string).copied())?; + + Some(JsString { + ptr: Tagged::from_tag(index), + }) + } + + /// Gets the `&[u16]` slice corresponding to the provided index, or `None` if the index + /// provided exceeds the size of the static array. + pub(crate) fn get(index: usize) -> Option> { + RAW_STATICS.get(index).copied() + } + + // Some consts are only used on certain features, which triggers the unused lint. + well_known_statics! { + (EMPTY_STRING, ""), + (LENGTH, "length"), + // Symbols + (SYMBOL_ASYNC_ITERATOR, "Symbol.asyncIterator"), + (SYMBOL_HAS_INSTANCE, "Symbol.hasInstance"), + (SYMBOL_IS_CONCAT_SPREADABLE, "Symbol.isConcatSpreadable"), + (SYMBOL_ITERATOR, "Symbol.iterator"), + (SYMBOL_MATCH, "Symbol.match"), + (SYMBOL_MATCH_ALL, "Symbol.matchAll"), + (SYMBOL_REPLACE, "Symbol.replace"), + (SYMBOL_SEARCH, "Symbol.search"), + (SYMBOL_SPECIES, "Symbol.species"), + (SYMBOL_SPLIT, "Symbol.split"), + (SYMBOL_TO_PRIMITIVE, "Symbol.toPrimitive"), + (SYMBOL_TO_STRING_TAG, "Symbol.toStringTag"), + (SYMBOL_UNSCOPABLES, "Symbol.unscopables"), + (FN_SYMBOL_ASYNC_ITERATOR, "[Symbol.asyncIterator]"), + (FN_SYMBOL_HAS_INSTANCE, "[Symbol.hasInstance]"), + (FN_SYMBOL_IS_CONCAT_SPREADABLE, "[Symbol.isConcatSpreadable]"), + (FN_SYMBOL_ITERATOR, "[Symbol.iterator]"), + (FN_SYMBOL_MATCH, "[Symbol.match]"), + (FN_SYMBOL_MATCH_ALL, "[Symbol.matchAll]"), + (FN_SYMBOL_REPLACE, "[Symbol.replace]"), + (FN_SYMBOL_SEARCH, "[Symbol.search]"), + (FN_SYMBOL_SPECIES, "[Symbol.species]"), + (FN_SYMBOL_SPLIT, "[Symbol.split]"), + (FN_SYMBOL_TO_PRIMITIVE, "[Symbol.toPrimitive]"), + (FN_SYMBOL_TO_STRING_TAG, "[Symbol.toStringTag]"), + (FN_SYMBOL_UNSCOPABLES, "[Symbol.unscopables]"), + // Builtins + (ARRAY, "Array"), + (ARRAY_BUFFER, "ArrayBuffer"), + (SHARED_ARRAY_BUFFER, "SharedArrayBuffer"), + (ASYNC_FUNCTION, "AsyncFunction"), + (ASYNC_GENERATOR, "AsyncGenerator"), + (ASYNC_GENERATOR_FUNCTION, "AsyncGeneratorFunction"), + (ATOMICS, "Atomics"), + (BIG_INT, "BigInt"), + (BOOLEAN, "Boolean"), + (DATA_VIEW, "DataView"), + (DATE, "Date"), + (ERROR, "Error"), + (AGGREGATE_ERROR, "AggregateError"), + (EVAL_ERROR, "EvalError"), + (RANGE_ERROR, "RangeError"), + (REFERENCE_ERROR, "ReferenceError"), + (SYNTAX_ERROR, "SyntaxError"), + (TYPE_ERROR, "TypeError"), + (URI_ERROR, "URIError"), + (ESCAPE, "escape"), + (UNESCAPE, "unescape"), + (EVAL, "eval"), + (FUNCTION, "Function"), + (GENERATOR, "Generator"), + (GENERATOR_FUNCTION, "GeneratorFunction"), + (INTL, "Intl"), + (COLLATOR, "Collator"), + (LIST_FORMAT, "ListFormat"), + (LOCALE, "Locale"), + (PLURAL_RULES, "PluralRules"), + (SEGMENTER, "Segmenter"), + (DATE_TIME_FORMAT, "DateTimeFormat"), + (JSON, "JSON"), + (MAP, "Map"), + (MATH, "Math"), + (NUMBER, "Number"), + (NUMBER_FORMAT, "NumberFormat"), + (IS_FINITE, "isFinite"), + (IS_NAN, "isNaN"), + (PARSE_INT, "parseInt"), + (PARSE_FLOAT, "parseFloat"), + (OBJECT, "Object"), + (PROMISE, "Promise"), + (PROXY, "Proxy"), + (REFLECT, "Reflect"), + (REG_EXP, "RegExp"), + (SET, "Set"), + (STRING, "String"), + (SYMBOL, "Symbol"), + (TYPED_ARRAY, "TypedArray"), + (INT8_ARRAY, "Int8Array"), + (UINT8_ARRAY, "Uint8Array"), + (UINT8_CLAMPED_ARRAY, "Uint8ClampedArray"), + (INT16_ARRAY, "Int16Array"), + (UINT16_ARRAY, "Uint16Array"), + (INT32_ARRAY, "Int32Array"), + (UINT32_ARRAY, "Uint32Array"), + (BIG_INT64_ARRAY, "BigInt64Array"), + (BIG_UINT64_ARRAY, "BigUint64Array"), + (FLOAT32_ARRAY, "Float32Array"), + (FLOAT64_ARRAY, "Float64Array"), + (ENCODE_URI, "encodeURI"), + (ENCODE_URI_COMPONENT, "encodeURIComponent"), + (DECODE_URI, "decodeURI"), + (DECODE_URI_COMPONENT, "decodeURIComponent"), + (WEAK_REF, "WeakRef"), + (WEAK_MAP, "WeakMap"), + (WEAK_SET, "WeakSet"), + (TEMPORAL, "Temporal"), + (NOW, "Temporal.Now"), + (INSTANT, "Temporal.Instant"), + (DURATION, "Temporal.Duration"), + (PLAIN_DATE, "Temporal.PlainDate"), + (PLAIN_DATETIME, "Temporal.PlainDateTime"), + (PLAIN_TIME, "Temporal.PlainTime"), + (PLAIN_YM, "Temporal.PlainYearMonth"), + (PLAIN_MD, "Temporal.PlainMonthDay"), + (CALENDAR, "Temporal.Calendar"), + (TIMEZONE, "Temporal.TimeZone"), + (ZONED_DT, "Temporal.ZonedDateTime"), + } +} + +const MAX_STATIC_LENGTH: usize = { + let mut max = 0; + let mut i = 0; + while i < RAW_STATICS.len() { + // TOOD: Because `get_index` is not const, we are accessing doc hidden stuff, that may change. + let len = RAW_STATICS[i].len(); + if len > max { + max = len; + } + i += 1; + } + max +}; + +thread_local! { + /// Map from a string inside [`RAW_STATICS`] to its corresponding static index on `RAW_STATICS`. + static RAW_STATICS_CACHE: FxHashMap, usize> = { + let mut constants = FxHashMap::with_capacity_and_hasher( + RAW_STATICS.len(), + BuildHasherDefault::::default(), + ); + + for (idx, &s) in RAW_STATICS.iter().enumerate() { + constants.insert(s, idx); + } + + constants + }; +} + +/// Array of raw static strings that aren't reference counted. +const RAW_STATICS: &[JsStr<'_>] = &[ + JsStr::latin1("".as_bytes()), + // Well known symbols + JsStr::latin1("Symbol.asyncIterator".as_bytes()), + JsStr::latin1("[Symbol.asyncIterator]".as_bytes()), + JsStr::latin1("Symbol.hasInstance".as_bytes()), + JsStr::latin1("[Symbol.hasInstance]".as_bytes()), + JsStr::latin1("Symbol.isConcatSpreadable".as_bytes()), + JsStr::latin1("[Symbol.isConcatSpreadable]".as_bytes()), + JsStr::latin1("Symbol.iterator".as_bytes()), + JsStr::latin1("[Symbol.iterator]".as_bytes()), + JsStr::latin1("Symbol.match".as_bytes()), + JsStr::latin1("[Symbol.match]".as_bytes()), + JsStr::latin1("Symbol.matchAll".as_bytes()), + JsStr::latin1("[Symbol.matchAll]".as_bytes()), + JsStr::latin1("Symbol.replace".as_bytes()), + JsStr::latin1("[Symbol.replace]".as_bytes()), + JsStr::latin1("Symbol.search".as_bytes()), + JsStr::latin1("[Symbol.search]".as_bytes()), + JsStr::latin1("Symbol.species".as_bytes()), + JsStr::latin1("[Symbol.species]".as_bytes()), + JsStr::latin1("Symbol.split".as_bytes()), + JsStr::latin1("[Symbol.split]".as_bytes()), + JsStr::latin1("Symbol.toPrimitive".as_bytes()), + JsStr::latin1("[Symbol.toPrimitive]".as_bytes()), + JsStr::latin1("Symbol.toStringTag".as_bytes()), + JsStr::latin1("[Symbol.toStringTag]".as_bytes()), + JsStr::latin1("Symbol.unscopables".as_bytes()), + JsStr::latin1("[Symbol.unscopables]".as_bytes()), + JsStr::latin1("get [Symbol.species]".as_bytes()), + JsStr::latin1("get [Symbol.toStringTag]".as_bytes()), + // Well known builtins + JsStr::latin1("Array".as_bytes()), + JsStr::latin1("ArrayBuffer".as_bytes()), + JsStr::latin1("SharedArrayBuffer".as_bytes()), + JsStr::latin1("AsyncFunction".as_bytes()), + JsStr::latin1("AsyncGenerator".as_bytes()), + JsStr::latin1("AsyncGeneratorFunction".as_bytes()), + JsStr::latin1("Atomics".as_bytes()), + JsStr::latin1("BigInt".as_bytes()), + JsStr::latin1("Boolean".as_bytes()), + JsStr::latin1("DataView".as_bytes()), + JsStr::latin1("Date".as_bytes()), + JsStr::latin1("Error".as_bytes()), + JsStr::latin1("AggregateError".as_bytes()), + JsStr::latin1("EvalError".as_bytes()), + JsStr::latin1("RangeError".as_bytes()), + JsStr::latin1("ReferenceError".as_bytes()), + JsStr::latin1("SyntaxError".as_bytes()), + JsStr::latin1("TypeError".as_bytes()), + JsStr::latin1("URIError".as_bytes()), + JsStr::latin1("escape".as_bytes()), + JsStr::latin1("unescape".as_bytes()), + JsStr::latin1("eval".as_bytes()), + JsStr::latin1("Function".as_bytes()), + JsStr::latin1("Generator".as_bytes()), + JsStr::latin1("GeneratorFunction".as_bytes()), + JsStr::latin1("Intl".as_bytes()), + JsStr::latin1("Collator".as_bytes()), + JsStr::latin1("ListFormat".as_bytes()), + JsStr::latin1("Locale".as_bytes()), + JsStr::latin1("PluralRules".as_bytes()), + JsStr::latin1("Segmenter".as_bytes()), + JsStr::latin1("DateTimeFormat".as_bytes()), + JsStr::latin1("JSON".as_bytes()), + JsStr::latin1("Map".as_bytes()), + JsStr::latin1("Math".as_bytes()), + JsStr::latin1("Number".as_bytes()), + JsStr::latin1("NumberFormat".as_bytes()), + JsStr::latin1("isFinite".as_bytes()), + JsStr::latin1("isNaN".as_bytes()), + JsStr::latin1("parseInt".as_bytes()), + JsStr::latin1("parseFloat".as_bytes()), + JsStr::latin1("Object".as_bytes()), + JsStr::latin1("Promise".as_bytes()), + JsStr::latin1("Proxy".as_bytes()), + JsStr::latin1("Reflect".as_bytes()), + JsStr::latin1("RegExp".as_bytes()), + JsStr::latin1("Set".as_bytes()), + JsStr::latin1("String".as_bytes()), + JsStr::latin1("Symbol".as_bytes()), + JsStr::latin1("TypedArray".as_bytes()), + JsStr::latin1("Int8Array".as_bytes()), + JsStr::latin1("Uint8Array".as_bytes()), + JsStr::latin1("Uint8ClampedArray".as_bytes()), + JsStr::latin1("Int16Array".as_bytes()), + JsStr::latin1("Uint16Array".as_bytes()), + JsStr::latin1("Int32Array".as_bytes()), + JsStr::latin1("Uint32Array".as_bytes()), + JsStr::latin1("BigInt64Array".as_bytes()), + JsStr::latin1("BigUint64Array".as_bytes()), + JsStr::latin1("Float32Array".as_bytes()), + JsStr::latin1("Float64Array".as_bytes()), + JsStr::latin1("encodeURI".as_bytes()), + JsStr::latin1("encodeURIComponent".as_bytes()), + JsStr::latin1("decodeURI".as_bytes()), + JsStr::latin1("decodeURIComponent".as_bytes()), + JsStr::latin1("WeakRef".as_bytes()), + JsStr::latin1("WeakMap".as_bytes()), + JsStr::latin1("WeakSet".as_bytes()), + JsStr::latin1("Temporal".as_bytes()), + JsStr::latin1("Temporal.Now".as_bytes()), + JsStr::latin1("Temporal.Instant".as_bytes()), + JsStr::latin1("Temporal.Duration".as_bytes()), + JsStr::latin1("Temporal.Calendar".as_bytes()), + JsStr::latin1("Temporal.PlainDate".as_bytes()), + JsStr::latin1("Temporal.PlainDateTime".as_bytes()), + JsStr::latin1("Temporal.PlainMonthDay".as_bytes()), + JsStr::latin1("Temporal.PlainYearMonth".as_bytes()), + JsStr::latin1("Temporal.PlainTime".as_bytes()), + JsStr::latin1("Temporal.TimeZone".as_bytes()), + JsStr::latin1("Temporal.ZonedDateTime".as_bytes()), + // Misc + JsStr::latin1(",".as_bytes()), + JsStr::latin1(":".as_bytes()), + // Generic use + JsStr::latin1("name".as_bytes()), + JsStr::latin1("length".as_bytes()), + JsStr::latin1("arguments".as_bytes()), + JsStr::latin1("prototype".as_bytes()), + JsStr::latin1("constructor".as_bytes()), + JsStr::latin1("return".as_bytes()), + JsStr::latin1("throw".as_bytes()), + JsStr::latin1("global".as_bytes()), + JsStr::latin1("globalThis".as_bytes()), + // typeof + JsStr::latin1("null".as_bytes()), + JsStr::latin1("undefined".as_bytes()), + JsStr::latin1("number".as_bytes()), + JsStr::latin1("string".as_bytes()), + JsStr::latin1("symbol".as_bytes()), + JsStr::latin1("bigint".as_bytes()), + JsStr::latin1("object".as_bytes()), + JsStr::latin1("function".as_bytes()), + // Property descriptor + JsStr::latin1("value".as_bytes()), + JsStr::latin1("get".as_bytes()), + JsStr::latin1("set".as_bytes()), + JsStr::latin1("writable".as_bytes()), + JsStr::latin1("enumerable".as_bytes()), + JsStr::latin1("configurable".as_bytes()), + // Object object + JsStr::latin1("assign".as_bytes()), + JsStr::latin1("create".as_bytes()), + JsStr::latin1("toString".as_bytes()), + JsStr::latin1("valueOf".as_bytes()), + JsStr::latin1("is".as_bytes()), + JsStr::latin1("seal".as_bytes()), + JsStr::latin1("isSealed".as_bytes()), + JsStr::latin1("freeze".as_bytes()), + JsStr::latin1("isFrozen".as_bytes()), + JsStr::latin1("isExtensible".as_bytes()), + JsStr::latin1("hasOwnProperty".as_bytes()), + JsStr::latin1("isPrototypeOf".as_bytes()), + JsStr::latin1("setPrototypeOf".as_bytes()), + JsStr::latin1("getPrototypeOf".as_bytes()), + JsStr::latin1("defineProperty".as_bytes()), + JsStr::latin1("defineProperties".as_bytes()), + JsStr::latin1("deleteProperty".as_bytes()), + JsStr::latin1("construct".as_bytes()), + JsStr::latin1("hasOwn".as_bytes()), + JsStr::latin1("ownKeys".as_bytes()), + JsStr::latin1("keys".as_bytes()), + JsStr::latin1("values".as_bytes()), + JsStr::latin1("entries".as_bytes()), + JsStr::latin1("fromEntries".as_bytes()), + JsStr::latin1("propertyIsEnumerable".as_bytes()), + JsStr::latin1("preventExtensions".as_bytes()), + JsStr::latin1("getOwnPropertyDescriptor".as_bytes()), + JsStr::latin1("getOwnPropertyDescriptors".as_bytes()), + JsStr::latin1("getOwnPropertyNames".as_bytes()), + JsStr::latin1("getOwnPropertySymbols".as_bytes()), + JsStr::latin1("__defineGetter__".as_bytes()), + JsStr::latin1("__defineSetter__".as_bytes()), + JsStr::latin1("__lookupGetter__".as_bytes()), + JsStr::latin1("__lookupSetter__".as_bytes()), + JsStr::latin1("__proto__".as_bytes()), + JsStr::latin1("get __proto__".as_bytes()), + JsStr::latin1("set __proto__".as_bytes()), + // Function object + JsStr::latin1("apply".as_bytes()), + JsStr::latin1("bind".as_bytes()), + JsStr::latin1("call".as_bytes()), + JsStr::latin1("caller".as_bytes()), + // Arguments object + JsStr::latin1("callee".as_bytes()), + // Array object + JsStr::latin1("at".as_bytes()), + JsStr::latin1("from".as_bytes()), + JsStr::latin1("isArray".as_bytes()), + JsStr::latin1("of".as_bytes()), + JsStr::latin1("copyWithin".as_bytes()), + JsStr::latin1("every".as_bytes()), + JsStr::latin1("fill".as_bytes()), + JsStr::latin1("filter".as_bytes()), + JsStr::latin1("find".as_bytes()), + JsStr::latin1("findIndex".as_bytes()), + JsStr::latin1("findLast".as_bytes()), + JsStr::latin1("findLastIndex".as_bytes()), + JsStr::latin1("flat".as_bytes()), + JsStr::latin1("flatMap".as_bytes()), + JsStr::latin1("forEach".as_bytes()), + JsStr::latin1("includes".as_bytes()), + JsStr::latin1("indexOf".as_bytes()), + JsStr::latin1("join".as_bytes()), + JsStr::latin1("map".as_bytes()), + JsStr::latin1("next".as_bytes()), + JsStr::latin1("reduce".as_bytes()), + JsStr::latin1("reduceRight".as_bytes()), + JsStr::latin1("reverse".as_bytes()), + JsStr::latin1("shift".as_bytes()), + JsStr::latin1("slice".as_bytes()), + JsStr::latin1("splice".as_bytes()), + JsStr::latin1("some".as_bytes()), + JsStr::latin1("sort".as_bytes()), + JsStr::latin1("unshift".as_bytes()), + JsStr::latin1("push".as_bytes()), + JsStr::latin1("pop".as_bytes()), + JsStr::latin1("groupBy".as_bytes()), + JsStr::latin1("toReversed".as_bytes()), + JsStr::latin1("toSorted".as_bytes()), + JsStr::latin1("toSpliced".as_bytes()), + JsStr::latin1("with".as_bytes()), + // String object + JsStr::latin1("charAt".as_bytes()), + JsStr::latin1("charCodeAt".as_bytes()), + JsStr::latin1("codePointAt".as_bytes()), + JsStr::latin1("concat".as_bytes()), + JsStr::latin1("endsWith".as_bytes()), + JsStr::latin1("fromCharCode".as_bytes()), + JsStr::latin1("fromCodePoint".as_bytes()), + JsStr::latin1("lastIndexOf".as_bytes()), + JsStr::latin1("match".as_bytes()), + JsStr::latin1("matchAll".as_bytes()), + JsStr::latin1("normalize".as_bytes()), + JsStr::latin1("padEnd".as_bytes()), + JsStr::latin1("padStart".as_bytes()), + JsStr::latin1("raw".as_bytes()), + JsStr::latin1("repeat".as_bytes()), + JsStr::latin1("replace".as_bytes()), + JsStr::latin1("replaceAll".as_bytes()), + JsStr::latin1("search".as_bytes()), + JsStr::latin1("split".as_bytes()), + JsStr::latin1("startsWith".as_bytes()), + JsStr::latin1("substr".as_bytes()), + JsStr::latin1("substring".as_bytes()), + JsStr::latin1("toLocaleString".as_bytes()), + JsStr::latin1("toLowerCase".as_bytes()), + JsStr::latin1("toUpperCase".as_bytes()), + JsStr::latin1("trim".as_bytes()), + JsStr::latin1("trimEnd".as_bytes()), + JsStr::latin1("trimStart".as_bytes()), + JsStr::latin1("isWellFormed".as_bytes()), + JsStr::latin1("localeCompare".as_bytes()), + JsStr::latin1("toWellFormed".as_bytes()), + JsStr::latin1("toLocaleLowerCase".as_bytes()), + JsStr::latin1("toLocaleUpperCase".as_bytes()), + JsStr::latin1("trimLeft".as_bytes()), + JsStr::latin1("trimRight".as_bytes()), + JsStr::latin1("anchor".as_bytes()), + JsStr::latin1("big".as_bytes()), + JsStr::latin1("blink".as_bytes()), + JsStr::latin1("bold".as_bytes()), + JsStr::latin1("fixed".as_bytes()), + JsStr::latin1("fontcolor".as_bytes()), + JsStr::latin1("fontsize".as_bytes()), + JsStr::latin1("italics".as_bytes()), + JsStr::latin1("link".as_bytes()), + JsStr::latin1("small".as_bytes()), + JsStr::latin1("strike".as_bytes()), + JsStr::latin1("sub".as_bytes()), + JsStr::latin1("sup".as_bytes()), + // Number object + JsStr::latin1("Infinity".as_bytes()), + JsStr::latin1("NaN".as_bytes()), + JsStr::latin1("EPSILON".as_bytes()), + JsStr::latin1("MAX_SAFE_INTEGER".as_bytes()), + JsStr::latin1("MIN_SAFE_INTEGER".as_bytes()), + JsStr::latin1("MAX_VALUE".as_bytes()), + JsStr::latin1("MIN_VALUE".as_bytes()), + JsStr::latin1("NEGATIVE_INFINITY".as_bytes()), + JsStr::latin1("POSITIVE_INFINITY".as_bytes()), + JsStr::latin1("isSafeInteger".as_bytes()), + JsStr::latin1("isInteger".as_bytes()), + JsStr::latin1("toExponential".as_bytes()), + JsStr::latin1("toFixed".as_bytes()), + JsStr::latin1("toPrecision".as_bytes()), + // BigInt object + JsStr::latin1("asIntN".as_bytes()), + JsStr::latin1("asUintN".as_bytes()), + // RegExp object + JsStr::latin1("exec".as_bytes()), + JsStr::latin1("test".as_bytes()), + JsStr::latin1("compile".as_bytes()), + JsStr::latin1("flags".as_bytes()), + JsStr::latin1("index".as_bytes()), + JsStr::latin1("lastIndex".as_bytes()), + JsStr::latin1("hasIndices".as_bytes()), + JsStr::latin1("ignoreCase".as_bytes()), + JsStr::latin1("multiline".as_bytes()), + JsStr::latin1("dotAll".as_bytes()), + JsStr::latin1("unicode".as_bytes()), + JsStr::latin1("sticky".as_bytes()), + JsStr::latin1("source".as_bytes()), + JsStr::latin1("get hasIndices".as_bytes()), + JsStr::latin1("get global".as_bytes()), + JsStr::latin1("get ignoreCase".as_bytes()), + JsStr::latin1("get multiline".as_bytes()), + JsStr::latin1("get dotAll".as_bytes()), + JsStr::latin1("get unicode".as_bytes()), + JsStr::latin1("get sticky".as_bytes()), + JsStr::latin1("get flags".as_bytes()), + JsStr::latin1("get source".as_bytes()), + // Symbol object + JsStr::latin1("for".as_bytes()), + JsStr::latin1("keyFor".as_bytes()), + JsStr::latin1("description".as_bytes()), + JsStr::latin1("asyncIterator".as_bytes()), + JsStr::latin1("hasInstance".as_bytes()), + JsStr::latin1("species".as_bytes()), + JsStr::latin1("unscopables".as_bytes()), + JsStr::latin1("iterator".as_bytes()), + JsStr::latin1("toStringTag".as_bytes()), + JsStr::latin1("toPrimitive".as_bytes()), + JsStr::latin1("isConcatSpreadable".as_bytes()), + JsStr::latin1("get description".as_bytes()), + // Map object + JsStr::latin1("clear".as_bytes()), + JsStr::latin1("delete".as_bytes()), + JsStr::latin1("has".as_bytes()), + JsStr::latin1("size".as_bytes()), + // Set object + JsStr::latin1("add".as_bytes()), + // Reflect object + // Proxy object + JsStr::latin1("revocable".as_bytes()), + // Error objects + JsStr::latin1("message".as_bytes()), + // Date object + JsStr::latin1("toJSON".as_bytes()), + JsStr::latin1("getDate".as_bytes()), + JsStr::latin1("getDay".as_bytes()), + JsStr::latin1("getFullYear".as_bytes()), + JsStr::latin1("getHours".as_bytes()), + JsStr::latin1("getMilliseconds".as_bytes()), + JsStr::latin1("getMinutes".as_bytes()), + JsStr::latin1("getMonth".as_bytes()), + JsStr::latin1("getSeconds".as_bytes()), + JsStr::latin1("getTime".as_bytes()), + JsStr::latin1("getYear".as_bytes()), + JsStr::latin1("getUTCDate".as_bytes()), + JsStr::latin1("getUTCDay".as_bytes()), + JsStr::latin1("getUTCFullYear".as_bytes()), + JsStr::latin1("getUTCHours".as_bytes()), + JsStr::latin1("getUTCMinutes".as_bytes()), + JsStr::latin1("getUTCMonth".as_bytes()), + JsStr::latin1("getUTCSeconds".as_bytes()), + JsStr::latin1("setDate".as_bytes()), + JsStr::latin1("setFullYear".as_bytes()), + JsStr::latin1("setHours".as_bytes()), + JsStr::latin1("setMilliseconds".as_bytes()), + JsStr::latin1("setMinutes".as_bytes()), + JsStr::latin1("setMonth".as_bytes()), + JsStr::latin1("setSeconds".as_bytes()), + JsStr::latin1("setYear".as_bytes()), + JsStr::latin1("setTime".as_bytes()), + JsStr::latin1("setUTCDate".as_bytes()), + JsStr::latin1("setUTCFullYear".as_bytes()), + JsStr::latin1("setUTCHours".as_bytes()), + JsStr::latin1("setUTCMinutes".as_bytes()), + JsStr::latin1("setUTCMonth".as_bytes()), + JsStr::latin1("setUTCSeconds".as_bytes()), + JsStr::latin1("toDateString".as_bytes()), + JsStr::latin1("toGMTString".as_bytes()), + JsStr::latin1("toISOString".as_bytes()), + JsStr::latin1("toTimeString".as_bytes()), + JsStr::latin1("toUTCString".as_bytes()), + JsStr::latin1("now".as_bytes()), + JsStr::latin1("UTC".as_bytes()), + JsStr::latin1("getTimezoneOffset".as_bytes()), + JsStr::latin1("getUTCMilliseconds".as_bytes()), + JsStr::latin1("setUTCMilliseconds".as_bytes()), + JsStr::latin1("toLocaleDateString".as_bytes()), + JsStr::latin1("toLocaleTimeString".as_bytes()), + // JSON object + JsStr::latin1("parse".as_bytes()), + JsStr::latin1("stringify".as_bytes()), + // Promise object + JsStr::latin1("promise".as_bytes()), + JsStr::latin1("resolve".as_bytes()), + JsStr::latin1("reject".as_bytes()), + JsStr::latin1("all".as_bytes()), + JsStr::latin1("allSettled".as_bytes()), + JsStr::latin1("any".as_bytes()), + JsStr::latin1("race".as_bytes()), + JsStr::latin1("then".as_bytes()), + JsStr::latin1("catch".as_bytes()), + JsStr::latin1("finally".as_bytes()), + JsStr::latin1("withResolvers".as_bytes()), + // Iterator object + JsStr::latin1("Array Iterator".as_bytes()), + JsStr::latin1("Set Iterator".as_bytes()), + JsStr::latin1("String Iterator".as_bytes()), + JsStr::latin1("Map Iterator".as_bytes()), + JsStr::latin1("For In Iterator".as_bytes()), + JsStr::latin1("RegExp String Iterator".as_bytes()), + // Iterator result object + JsStr::latin1("done".as_bytes()), + // Math object + JsStr::latin1("LN10".as_bytes()), + JsStr::latin1("LN2".as_bytes()), + JsStr::latin1("LOG10E".as_bytes()), + JsStr::latin1("LOG2E".as_bytes()), + JsStr::latin1("PI".as_bytes()), + JsStr::latin1("SQRT1_2".as_bytes()), + JsStr::latin1("SQRT2".as_bytes()), + JsStr::latin1("abs".as_bytes()), + JsStr::latin1("acos".as_bytes()), + JsStr::latin1("acosh".as_bytes()), + JsStr::latin1("asin".as_bytes()), + JsStr::latin1("asinh".as_bytes()), + JsStr::latin1("atan".as_bytes()), + JsStr::latin1("atanh".as_bytes()), + JsStr::latin1("atan2".as_bytes()), + JsStr::latin1("cbrt".as_bytes()), + JsStr::latin1("ceil".as_bytes()), + JsStr::latin1("clz32".as_bytes()), + JsStr::latin1("cos".as_bytes()), + JsStr::latin1("cosh".as_bytes()), + JsStr::latin1("exp".as_bytes()), + JsStr::latin1("expm1".as_bytes()), + JsStr::latin1("floor".as_bytes()), + JsStr::latin1("fround".as_bytes()), + JsStr::latin1("hypot".as_bytes()), + JsStr::latin1("imul".as_bytes()), + JsStr::latin1("log".as_bytes()), + JsStr::latin1("log1p".as_bytes()), + JsStr::latin1("log10".as_bytes()), + JsStr::latin1("log2".as_bytes()), + JsStr::latin1("max".as_bytes()), + JsStr::latin1("min".as_bytes()), + JsStr::latin1("pow".as_bytes()), + JsStr::latin1("random".as_bytes()), + JsStr::latin1("round".as_bytes()), + JsStr::latin1("sign".as_bytes()), + JsStr::latin1("sin".as_bytes()), + JsStr::latin1("sinh".as_bytes()), + JsStr::latin1("sqrt".as_bytes()), + JsStr::latin1("tan".as_bytes()), + JsStr::latin1("tanh".as_bytes()), + JsStr::latin1("trunc".as_bytes()), + // TypedArray object + JsStr::latin1("BYTES_PER_ELEMENT".as_bytes()), + JsStr::latin1("buffer".as_bytes()), + JsStr::latin1("byteLength".as_bytes()), + JsStr::latin1("byteOffset".as_bytes()), + JsStr::latin1("isView".as_bytes()), + JsStr::latin1("subarray".as_bytes()), + JsStr::latin1("get byteLength".as_bytes()), + JsStr::latin1("get buffer".as_bytes()), + JsStr::latin1("get byteOffset".as_bytes()), + JsStr::latin1("get size".as_bytes()), + JsStr::latin1("get length".as_bytes()), + // DataView object + JsStr::latin1("getBigInt64".as_bytes()), + JsStr::latin1("getBigUint64".as_bytes()), + JsStr::latin1("getFloat32".as_bytes()), + JsStr::latin1("getFloat64".as_bytes()), + JsStr::latin1("getInt8".as_bytes()), + JsStr::latin1("getInt16".as_bytes()), + JsStr::latin1("getInt32".as_bytes()), + JsStr::latin1("getUint8".as_bytes()), + JsStr::latin1("getUint16".as_bytes()), + JsStr::latin1("getUint32".as_bytes()), + JsStr::latin1("setBigInt64".as_bytes()), + JsStr::latin1("setBigUint64".as_bytes()), + JsStr::latin1("setFloat32".as_bytes()), + JsStr::latin1("setFloat64".as_bytes()), + JsStr::latin1("setInt8".as_bytes()), + JsStr::latin1("setInt16".as_bytes()), + JsStr::latin1("setInt32".as_bytes()), + JsStr::latin1("setUint8".as_bytes()), + JsStr::latin1("setUint16".as_bytes()), + JsStr::latin1("setUint32".as_bytes()), + // WeakRef object + JsStr::latin1("deref".as_bytes()), + // Atomic object + JsStr::latin1("and".as_bytes()), + JsStr::latin1("compareExchange".as_bytes()), + JsStr::latin1("exchange".as_bytes()), + JsStr::latin1("isLockFree".as_bytes()), + JsStr::latin1("load".as_bytes()), + JsStr::latin1("or".as_bytes()), + JsStr::latin1("store".as_bytes()), + JsStr::latin1("wait".as_bytes()), + JsStr::latin1("notify".as_bytes()), + JsStr::latin1("xor".as_bytes()), + // Intl object + JsStr::latin1("getCanonicalLocales".as_bytes()), + JsStr::latin1("get compare".as_bytes()), + JsStr::latin1("supportedLocalesOf".as_bytes()), + JsStr::latin1("Intl.Collator".as_bytes()), + JsStr::latin1("compare".as_bytes()), + JsStr::latin1("resolvedOptions".as_bytes()), + JsStr::latin1("Intl.ListFormat".as_bytes()), + JsStr::latin1("format".as_bytes()), + JsStr::latin1("formatToParts".as_bytes()), + JsStr::latin1("get baseName".as_bytes()), + JsStr::latin1("get calendar".as_bytes()), + JsStr::latin1("get caseFirst".as_bytes()), + JsStr::latin1("get collation".as_bytes()), + JsStr::latin1("get hourCycle".as_bytes()), + JsStr::latin1("get numeric".as_bytes()), + JsStr::latin1("get numberingSystem".as_bytes()), + JsStr::latin1("get language".as_bytes()), + JsStr::latin1("get script".as_bytes()), + JsStr::latin1("get region".as_bytes()), + JsStr::latin1("Intl.Locale".as_bytes()), + JsStr::latin1("maximize".as_bytes()), + JsStr::latin1("minimize".as_bytes()), + JsStr::latin1("baseName".as_bytes()), + JsStr::latin1("calendar".as_bytes()), + JsStr::latin1("caseFirst".as_bytes()), + JsStr::latin1("collation".as_bytes()), + JsStr::latin1("hourCycle".as_bytes()), + JsStr::latin1("numeric".as_bytes()), + JsStr::latin1("numberingSystem".as_bytes()), + JsStr::latin1("language".as_bytes()), + JsStr::latin1("script".as_bytes()), + JsStr::latin1("region".as_bytes()), + JsStr::latin1("Intl.Segmenter".as_bytes()), + JsStr::latin1("segment".as_bytes()), + JsStr::latin1("containing".as_bytes()), + JsStr::latin1("Segmenter String Iterator".as_bytes()), + JsStr::latin1("Intl.PluralRules".as_bytes()), + JsStr::latin1("select".as_bytes()), + // Temporal object + JsStr::latin1("get Id".as_bytes()), + JsStr::latin1("getOffsetNanosecondsFor".as_bytes()), + JsStr::latin1("getOffsetStringFor".as_bytes()), + JsStr::latin1("getPlainDateTimeFor".as_bytes()), + JsStr::latin1("getInstantFor".as_bytes()), + JsStr::latin1("getPossibleInstantFor".as_bytes()), + JsStr::latin1("getNextTransition".as_bytes()), + JsStr::latin1("getPreviousTransition".as_bytes()), + JsStr::latin1("id".as_bytes()), + JsStr::latin1("Now".as_bytes()), + JsStr::latin1("Calendar".as_bytes()), + JsStr::latin1("Duration".as_bytes()), + JsStr::latin1("Instant".as_bytes()), + JsStr::latin1("PlainDate".as_bytes()), + JsStr::latin1("PlainDateTime".as_bytes()), + JsStr::latin1("PlainMonthDay".as_bytes()), + JsStr::latin1("PlainTime".as_bytes()), + JsStr::latin1("PlainYearMonth".as_bytes()), + JsStr::latin1("TimeZone".as_bytes()), + JsStr::latin1("ZonedDateTime".as_bytes()), + JsStr::latin1("timeZoneId".as_bytes()), + JsStr::latin1("instant".as_bytes()), + JsStr::latin1("plainDateTime".as_bytes()), + JsStr::latin1("plainDateTimeISO".as_bytes()), + JsStr::latin1("zonedDateTime".as_bytes()), + JsStr::latin1("zonedDateTimeISO".as_bytes()), + JsStr::latin1("plainDate".as_bytes()), + JsStr::latin1("plainDateISO".as_bytes()), + JsStr::latin1("get epochSeconds".as_bytes()), + JsStr::latin1("get epochMilliseconds".as_bytes()), + JsStr::latin1("get epochMicroseconds".as_bytes()), + JsStr::latin1("get epochNanoseconds".as_bytes()), + JsStr::latin1("epochSeconds".as_bytes()), + JsStr::latin1("epochMilliseconds".as_bytes()), + JsStr::latin1("epochMicroseconds".as_bytes()), + JsStr::latin1("epochNanoseconds".as_bytes()), + JsStr::latin1("subtract".as_bytes()), + JsStr::latin1("until".as_bytes()), + JsStr::latin1("since".as_bytes()), + JsStr::latin1("equals".as_bytes()), + JsStr::latin1("toZonedDateTime".as_bytes()), + JsStr::latin1("toZonedDateTimeISO".as_bytes()), + JsStr::latin1("get Years".as_bytes()), + JsStr::latin1("get Months".as_bytes()), + JsStr::latin1("get Weeks".as_bytes()), + JsStr::latin1("get Days".as_bytes()), + JsStr::latin1("get Hours".as_bytes()), + JsStr::latin1("get Minutes".as_bytes()), + JsStr::latin1("get Seconds".as_bytes()), + JsStr::latin1("get Milliseconds".as_bytes()), + JsStr::latin1("get Microseconds".as_bytes()), + JsStr::latin1("get Nanoseconds".as_bytes()), + JsStr::latin1("get Sign".as_bytes()), + JsStr::latin1("get blank".as_bytes()), + JsStr::latin1("years".as_bytes()), + JsStr::latin1("months".as_bytes()), + JsStr::latin1("weeks".as_bytes()), + JsStr::latin1("days".as_bytes()), + JsStr::latin1("hours".as_bytes()), + JsStr::latin1("minutes".as_bytes()), + JsStr::latin1("seconds".as_bytes()), + JsStr::latin1("milliseconds".as_bytes()), + JsStr::latin1("microseconds".as_bytes()), + JsStr::latin1("nanoseconds".as_bytes()), + JsStr::latin1("blank".as_bytes()), + JsStr::latin1("negated".as_bytes()), + JsStr::latin1("total".as_bytes()), + JsStr::latin1("get calendarId".as_bytes()), + JsStr::latin1("get year".as_bytes()), + JsStr::latin1("get month".as_bytes()), + JsStr::latin1("get monthCode".as_bytes()), + JsStr::latin1("get day".as_bytes()), + JsStr::latin1("get dayOfWeek".as_bytes()), + JsStr::latin1("get dayOfYear".as_bytes()), + JsStr::latin1("get weekOfYear".as_bytes()), + JsStr::latin1("get yearOfWeek".as_bytes()), + JsStr::latin1("get daysInWeek".as_bytes()), + JsStr::latin1("get daysInMonth".as_bytes()), + JsStr::latin1("get daysInYear".as_bytes()), + JsStr::latin1("get monthsInYear".as_bytes()), + JsStr::latin1("get inLeapYear".as_bytes()), + JsStr::latin1("calendarId".as_bytes()), + JsStr::latin1("year".as_bytes()), + JsStr::latin1("month".as_bytes()), + JsStr::latin1("monthCode".as_bytes()), + JsStr::latin1("day".as_bytes()), + JsStr::latin1("dayOfWeek".as_bytes()), + JsStr::latin1("dayOfYear".as_bytes()), + JsStr::latin1("weekOfYear".as_bytes()), + JsStr::latin1("yearOfWeek".as_bytes()), + JsStr::latin1("daysInWeek".as_bytes()), + JsStr::latin1("daysInMonth".as_bytes()), + JsStr::latin1("daysInYear".as_bytes()), + JsStr::latin1("monthsInYear".as_bytes()), + JsStr::latin1("inLeapYear".as_bytes()), + JsStr::latin1("toPlainYearMonth".as_bytes()), + JsStr::latin1("toPlainMonthDay".as_bytes()), + JsStr::latin1("getISOFields".as_bytes()), + JsStr::latin1("getCalendar".as_bytes()), + JsStr::latin1("withCalendar".as_bytes()), + JsStr::latin1("dateFromFields".as_bytes()), + JsStr::latin1("yearMonthFromFields".as_bytes()), + JsStr::latin1("monthDayFromFields".as_bytes()), + JsStr::latin1("dateAdd".as_bytes()), + JsStr::latin1("dateUntil".as_bytes()), + JsStr::latin1("era".as_bytes()), + JsStr::latin1("eraYear".as_bytes()), + JsStr::latin1("fields".as_bytes()), + JsStr::latin1("mergeFields".as_bytes()), + // Console object + JsStr::latin1("console".as_bytes()), + JsStr::latin1("assert".as_bytes()), + JsStr::latin1("debug".as_bytes()), + JsStr::latin1("error".as_bytes()), + JsStr::latin1("info".as_bytes()), + JsStr::latin1("trace".as_bytes()), + JsStr::latin1("warn".as_bytes()), + JsStr::latin1("exception".as_bytes()), + JsStr::latin1("count".as_bytes()), + JsStr::latin1("countReset".as_bytes()), + JsStr::latin1("group".as_bytes()), + JsStr::latin1("groupCollapsed".as_bytes()), + JsStr::latin1("groupEnd".as_bytes()), + JsStr::latin1("time".as_bytes()), + JsStr::latin1("timeLog".as_bytes()), + JsStr::latin1("timeEnd".as_bytes()), + JsStr::latin1("dir".as_bytes()), + JsStr::latin1("dirxml".as_bytes()), + // Minified name + JsStr::latin1("a".as_bytes()), + JsStr::latin1("c".as_bytes()), + JsStr::latin1("d".as_bytes()), + JsStr::latin1("e".as_bytes()), + JsStr::latin1("f".as_bytes()), + JsStr::latin1("g".as_bytes()), + JsStr::latin1("h".as_bytes()), + JsStr::latin1("i".as_bytes()), + JsStr::latin1("j".as_bytes()), + JsStr::latin1("k".as_bytes()), + JsStr::latin1("l".as_bytes()), + JsStr::latin1("m".as_bytes()), + JsStr::latin1("n".as_bytes()), + JsStr::latin1("o".as_bytes()), + JsStr::latin1("p".as_bytes()), + JsStr::latin1("q".as_bytes()), + JsStr::latin1("r".as_bytes()), + JsStr::latin1("s".as_bytes()), + JsStr::latin1("t".as_bytes()), + JsStr::latin1("u".as_bytes()), + JsStr::latin1("v".as_bytes()), + JsStr::latin1("w".as_bytes()), + JsStr::latin1("x".as_bytes()), + JsStr::latin1("y".as_bytes()), + JsStr::latin1("z".as_bytes()), + JsStr::latin1("A".as_bytes()), + JsStr::latin1("C".as_bytes()), + JsStr::latin1("D".as_bytes()), + JsStr::latin1("E".as_bytes()), + JsStr::latin1("F".as_bytes()), + JsStr::latin1("G".as_bytes()), + JsStr::latin1("H".as_bytes()), + JsStr::latin1("I".as_bytes()), + JsStr::latin1("J".as_bytes()), + JsStr::latin1("K".as_bytes()), + JsStr::latin1("L".as_bytes()), + JsStr::latin1("M".as_bytes()), + JsStr::latin1("N".as_bytes()), + JsStr::latin1("O".as_bytes()), + JsStr::latin1("P".as_bytes()), + JsStr::latin1("Q".as_bytes()), + JsStr::latin1("R".as_bytes()), + JsStr::latin1("S".as_bytes()), + JsStr::latin1("T".as_bytes()), + JsStr::latin1("U".as_bytes()), + JsStr::latin1("V".as_bytes()), + JsStr::latin1("W".as_bytes()), + JsStr::latin1("X".as_bytes()), + JsStr::latin1("Y".as_bytes()), + JsStr::latin1("Z".as_bytes()), + JsStr::latin1("_".as_bytes()), + JsStr::latin1("$".as_bytes()), +]; diff --git a/core/engine/src/string/iter.rs b/core/string/src/iter.rs similarity index 97% rename from core/engine/src/string/iter.rs rename to core/string/src/iter.rs index 03dedcb6b8..ead0e8c94c 100644 --- a/core/engine/src/string/iter.rs +++ b/core/string/src/iter.rs @@ -29,6 +29,7 @@ impl<'a> Iter<'a> { impl Iterator for Iter<'_> { type Item = u16; + #[inline] fn next(&mut self) -> Option { match &mut self.inner { IterInner::U8(iter) => iter.map(u16::from).next(), @@ -40,6 +41,7 @@ impl Iterator for Iter<'_> { impl FusedIterator for Iter<'_> {} impl ExactSizeIterator for Iter<'_> { + #[inline] fn len(&self) -> usize { match &self.inner { IterInner::U8(v) => v.len(), @@ -75,6 +77,7 @@ impl<'a> Windows<'a> { impl<'a> Iterator for Windows<'a> { type Item = JsStr<'a>; + #[inline] fn next(&mut self) -> Option { match &mut self.inner { WindowsInner::U8(iter) => iter.next().map(JsStr::latin1), @@ -86,6 +89,7 @@ impl<'a> Iterator for Windows<'a> { impl FusedIterator for Windows<'_> {} impl ExactSizeIterator for Windows<'_> { + #[inline] fn len(&self) -> usize { match &self.inner { WindowsInner::U8(v) => v.len(), diff --git a/core/engine/src/string/mod.rs b/core/string/src/lib.rs similarity index 82% rename from core/engine/src/string/mod.rs rename to core/string/src/lib.rs index 16f2172731..2daae7d5c6 100644 --- a/core/engine/src/string/mod.rs +++ b/core/string/src/lib.rs @@ -1,10 +1,4 @@ //! A Latin1 or UTF-16 encoded, reference counted, immutable string. -//! -//! This module contains the [`JsString`] type, the [`js_string`][crate::js_string] macro and the -//! [`js_str`][crate::js_str] macro. -//! -//! The [`js_string`][crate::js_string] macro is used when you need to create a new [`JsString`], -//! and the [`js_str`][crate::js_str] macro is used for const conversions of string literals to [`JsStr`]. // Required per unsafe code standards to ensure every unsafe usage is properly documented. // - `unsafe_op_in_unsafe_fn` will be warn-by-default in edition 2024: @@ -20,22 +14,24 @@ // Right now this allows us to use the stable polyfill from the `sptr` crate, which uses // the same names from the unstable functions of the `std::ptr` module. #![allow(unstable_name_collisions)] +#![allow(clippy::module_name_repetitions)] -pub mod common; +mod common; mod iter; mod str; +mod tagged; -use self::{common::StaticJsStrings, iter::Windows, str::JsSliceIndex}; +#[cfg(test)] +mod tests; + +use self::{iter::Windows, str::JsSliceIndex}; +use crate::tagged::{Tagged, UnwrappedTagged}; #[doc(inline)] -pub use crate::string::{ +pub use crate::{ + common::StaticJsStrings, iter::Iter, str::{JsStr, JsStrVariant}, }; -use crate::{ - builtins::string::is_trimmable_whitespace, - tagged::{Tagged, UnwrappedTagged}, -}; -use boa_gc::{Finalize, Trace}; use std::{ alloc::{alloc, dealloc, Layout}, cell::Cell, @@ -51,65 +47,41 @@ fn alloc_overflow() -> ! { panic!("detected overflow during string allocation") } -/// Utility macro to create a [`JsString`]. -/// -/// # Examples -/// -/// You can call the macro without arguments to create an empty `JsString`: -/// -/// ``` -/// use boa_engine::js_string; -/// -/// let empty_str = js_string!(); -/// assert!(empty_str.is_empty()); -/// ``` -/// -/// -/// You can create a `JsString` from a string literal, which completely skips the runtime -/// conversion from [`&str`] to [&\[u16\]][slice]: -/// -/// ``` -/// # use boa_engine::js_string; -/// let hw = js_string!("Hello, world!"); -/// assert_eq!(&hw, "Hello, world!"); -/// ``` -/// -/// Any `&[u16]` slice is a valid `JsString`, including unpaired surrogates: -/// -/// ``` -/// # use boa_engine::js_string; -/// let array = js_string!(&[0xD8AFu16, 0x00A0, 0xD8FF, 0x00F0]); -/// ``` -/// -/// You can also pass it any number of `&[u16]` as arguments to create a new `JsString` with -/// the concatenation of every slice: -/// -/// ``` -/// # use boa_engine::{js_string, js_str, JsStr}; -/// const NAME: JsStr<'_> = js_str!("human! "); -/// let greeting = js_string!("Hello, "); -/// let msg = js_string!(&greeting, NAME, js_str!("Nice to meet you!")); -/// -/// assert_eq!(&msg, "Hello, human! Nice to meet you!"); -/// ``` -#[macro_export] -#[allow(clippy::module_name_repetitions)] -macro_rules! js_string { - () => { - $crate::string::JsString::default() - }; - ($s:literal) => { - $crate::string::JsString::from($crate::js_str!($s)) - }; - ($s:expr) => { - $crate::string::JsString::from($s) - }; - ( $x:expr, $y:expr ) => { - $crate::string::JsString::concat($crate::string::JsStr::from($x), $crate::string::JsStr::from($y)) - }; - ( $( $s:expr ),+ ) => { - $crate::string::JsString::concat_array(&[ $( $crate::string::JsStr::from($s) ),+ ]) - }; +/// Helper function to check if a `char` is trimmable. +pub(crate) const fn is_trimmable_whitespace(c: char) -> bool { + // The rust implementation of `trim` does not regard the same characters whitespace as ecma standard does + // + // Rust uses \p{White_Space} by default, which also includes: + // `\u{0085}' (next line) + // And does not include: + // '\u{FEFF}' (zero width non-breaking space) + // Explicit whitespace: https://tc39.es/ecma262/#sec-white-space + matches!( + c, + '\u{0009}' | '\u{000B}' | '\u{000C}' | '\u{0020}' | '\u{00A0}' | '\u{FEFF}' | + // Unicode Space_Separator category + '\u{1680}' | '\u{2000}' + ..='\u{200A}' | '\u{202F}' | '\u{205F}' | '\u{3000}' | + // Line terminators: https://tc39.es/ecma262/#sec-line-terminators + '\u{000A}' | '\u{000D}' | '\u{2028}' | '\u{2029}' + ) +} + +/// Helper function to check if a `u8` latin1 character is trimmable. +pub(crate) const fn is_trimmable_whitespace_latin1(c: u8) -> bool { + // The rust implementation of `trim` does not regard the same characters whitespace as ecma standard does + // + // Rust uses \p{White_Space} by default, which also includes: + // `\u{0085}' (next line) + // And does not include: + // '\u{FEFF}' (zero width non-breaking space) + // Explicit whitespace: https://tc39.es/ecma262/#sec-white-space + matches!( + c, + 0x09 | 0x0B | 0x0C | 0x20 | 0xA0 | + // Line terminators: https://tc39.es/ecma262/#sec-line-terminators + 0x0A | 0x0D + ) } /// Represents a Unicode codepoint within a [`JsString`], which could be a valid @@ -127,6 +99,7 @@ pub enum CodePoint { impl CodePoint { /// Get the number of UTF-16 code units needed to encode this code point. + #[inline] #[must_use] pub const fn code_unit_count(self) -> usize { match self { @@ -136,6 +109,7 @@ impl CodePoint { } /// Convert the code point to its [`u32`] representation. + #[inline] #[must_use] pub fn as_u32(self) -> u32 { match self { @@ -146,6 +120,7 @@ impl CodePoint { /// If the code point represents a valid 'Unicode scalar value', returns its [`char`] /// representation, otherwise returns [`None`] on unpaired surrogates. + #[inline] #[must_use] pub const fn as_char(self) -> Option { match self { @@ -161,6 +136,8 @@ impl CodePoint { /// /// Panics if the buffer is not large enough. A buffer of length 2 is large enough to encode any /// code point. + #[inline] + #[must_use] pub fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] { match self { Self::Unicode(c) => c.encode_utf16(dst), @@ -218,9 +195,6 @@ const DATA_OFFSET: usize = std::mem::size_of::(); /// /// We define some commonly used string constants in an interner. For these strings, we don't allocate /// memory on the heap to reduce the overhead of memory allocation and reference counting. -#[derive(Trace, Finalize)] -// Safety: `JsString` does not contain any objects which needs to be traced, so this is safe. -#[boa_gc(unsafe_empty_trace)] #[allow(clippy::module_name_repetitions)] pub struct JsString { ptr: Tagged, @@ -230,6 +204,7 @@ pub struct JsString { static_assertions::assert_eq_size!(JsString, *const ()); impl<'a> From<&'a JsString> for JsStr<'a> { + #[inline] fn from(value: &'a JsString) -> Self { value.as_str() } @@ -237,8 +212,9 @@ impl<'a> From<&'a JsString> for JsStr<'a> { impl<'a> IntoIterator for &'a JsString { type IntoIter = Iter<'a>; - type Item = u16; + + #[inline] fn into_iter(self) -> Self::IntoIter { self.iter() } @@ -260,6 +236,7 @@ impl JsString { } /// Obtains the underlying [`&[u16]`][slice] slice of a [`JsString`] + #[inline] #[must_use] pub fn as_str(&self) -> JsStr<'_> { match self.ptr.unwrap() { @@ -298,6 +275,7 @@ impl JsString { } /// Creates a new [`JsString`] from the concatenation of `x` and `y`. + #[inline] #[must_use] pub fn concat(x: JsStr<'_>, y: JsStr<'_>) -> Self { Self::concat_array(&[x, y]) @@ -305,6 +283,7 @@ impl JsString { /// Creates a new [`JsString`] from the concatenation of every element of /// `strings`. + #[inline] #[must_use] pub fn concat_array(strings: &[JsStr<'_>]) -> Self { let mut latin1_encoding = true; @@ -373,6 +352,7 @@ impl JsString { /// Decodes a [`JsString`] into a [`String`], replacing invalid data with its escaped representation /// in 4 digit hexadecimal. + #[inline] #[must_use] pub fn to_std_string_escaped(&self) -> String { self.to_string_escaped() @@ -383,6 +363,7 @@ impl JsString { /// # Errors /// /// [`FromUtf16Error`][std::string::FromUtf16Error] if it contains any invalid data. + #[inline] pub fn to_std_string(&self) -> Result { match self.as_str().variant() { JsStrVariant::Latin1(v) => Ok(v.iter().copied().map(char::from).collect()), @@ -392,6 +373,7 @@ impl JsString { /// Decodes a [`JsString`] into an iterator of [`Result`], returning surrogates as /// errors. + #[inline] pub fn to_std_string_with_surrogates(&self) -> impl Iterator> + '_ { struct WideStringDecoderIterator { codepoints: Peekable, @@ -443,6 +425,7 @@ impl JsString { } /// Maps the valid segments of an UTF16 string and leaves the unpaired surrogates unchanged. + #[inline] #[must_use] pub fn map_valid_segments(&self, mut f: F) -> Self where @@ -457,10 +440,11 @@ impl JsString { } } - js_string!(&text[..]) + Self::from(&text[..]) } /// Gets an iterator of all the Unicode codepoints of a [`JsString`]. + #[inline] pub fn code_points(&self) -> impl Iterator + Clone + '_ { char::decode_utf16(self.iter()).map(|res| match res { Ok(c) => CodePoint::Unicode(c), @@ -477,6 +461,7 @@ impl JsString { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-stringindexof + #[inline] #[must_use] pub fn index_of(&self, search_value: JsStr<'_>, from_index: usize) -> Option { // 1. Assert: Type(string) is String. @@ -522,6 +507,7 @@ impl JsString { /// # Panics /// /// If `position` is smaller than size of string. + #[inline] #[must_use] pub fn code_point_at(&self, position: usize) -> CodePoint { // 1. Let size be the length of string. @@ -569,6 +555,8 @@ impl JsString { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-stringtonumber + #[inline] + #[must_use] pub fn to_number(&self) -> f64 { // 1. Let text be ! StringToCodePoints(str). // 2. Let literal be ParseText(text, StringNumericLiteral). @@ -781,12 +769,14 @@ impl JsString { } /// Convert the [`JsString`] into a [`Vec`]. + #[inline] #[must_use] pub fn to_vec(&self) -> Vec { self.as_str().to_vec() } /// Check if the [`JsString`] contains a byte. + #[inline] #[must_use] pub fn contains(&self, element: u8) -> bool { match self.as_str().variant() { @@ -796,30 +786,35 @@ impl JsString { } /// Trim whitespace from the start and end of the [`JsString`]. + #[inline] #[must_use] pub fn trim(&self) -> JsStr<'_> { self.as_str().trim() } /// Trim whitespace from the start of the [`JsString`]. + #[inline] #[must_use] pub fn trim_start(&self) -> JsStr<'_> { self.as_str().trim_start() } /// Trim whitespace from the end of the [`JsString`]. + #[inline] #[must_use] pub fn trim_end(&self) -> JsStr<'_> { self.as_str().trim_end() } /// Check if the [`JsString`] is static. + #[inline] #[must_use] pub fn is_static(&self) -> bool { self.ptr.is_tagged() } /// Get the element a the given index, [`None`] otherwise. + #[inline] #[must_use] pub fn get<'a, I>(&'a self, index: I) -> Option where @@ -833,6 +828,7 @@ impl JsString { /// # Panics /// /// If the index is out of bounds. + #[inline] #[must_use] pub fn get_expect<'a, I>(&'a self, index: I) -> I::Value where @@ -840,6 +836,20 @@ impl JsString { { self.get(index).expect("Index out of bounds") } + + /// Gets the number of `JsString`s which point to this allocation. + #[inline] + #[must_use] + pub fn refcount(&self) -> Option { + match self.ptr.unwrap() { + UnwrappedTagged::Ptr(inner) => { + // SAFETY: The reference count of `JsString` guarantees that `inner` is always valid. + let inner = unsafe { inner.as_ref() }; + Some(inner.refcount.get()) + } + UnwrappedTagged::Tag(_inner) => None, + } + } } impl Clone for JsString { @@ -866,6 +876,7 @@ impl Default for JsString { } impl Drop for JsString { + #[inline] fn drop(&mut self) { if let UnwrappedTagged::Ptr(raw) = self.ptr.unwrap() { // See https://doc.rust-lang.org/src/alloc/sync.rs.html#1672 for details. @@ -947,6 +958,7 @@ impl From<&str> for JsString { } impl From> for JsString { + #[inline] fn from(value: JsStr<'_>) -> Self { StaticJsStrings::get_string(&value) .unwrap_or_else(|| JsString::from_slice_skip_interning(value)) @@ -954,6 +966,7 @@ impl From> for JsString { } impl From<&[JsString]> for JsString { + #[inline] fn from(value: &[JsString]) -> Self { Self::concat_array( &value @@ -972,36 +985,42 @@ impl From for JsString { } impl From<&[u16; N]> for JsString { + #[inline] fn from(s: &[u16; N]) -> Self { Self::from(&s[..]) } } impl Hash for JsString { + #[inline] fn hash(&self, state: &mut H) { self.as_str().hash(state); } } impl PartialOrd for JsStr<'_> { + #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl Ord for JsString { + #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_str().cmp(&other.as_str()) } } impl PartialEq for JsString { + #[inline] fn eq(&self, other: &Self) -> bool { self.as_str() == other.as_str() } } impl PartialEq for [u16] { + #[inline] fn eq(&self, other: &JsString) -> bool { if self.len() != other.len() { return false; @@ -1016,24 +1035,28 @@ impl PartialEq for [u16] { } impl PartialEq for [u16; N] { + #[inline] fn eq(&self, other: &JsString) -> bool { self[..] == *other } } impl PartialEq<[u16]> for JsString { + #[inline] fn eq(&self, other: &[u16]) -> bool { other == self } } impl PartialEq<[u16; N]> for JsString { + #[inline] fn eq(&self, other: &[u16; N]) -> bool { *self == other[..] } } impl PartialEq for JsString { + #[inline] fn eq(&self, other: &str) -> bool { let utf16 = self.code_points(); let mut utf8 = other.chars(); @@ -1052,24 +1075,28 @@ impl PartialEq for JsString { } impl PartialEq for str { + #[inline] fn eq(&self, other: &JsString) -> bool { other == self } } impl PartialEq> for JsString { + #[inline] fn eq(&self, other: &JsStr<'_>) -> bool { self.as_str() == *other } } impl PartialEq for JsStr<'_> { + #[inline] fn eq(&self, other: &JsString) -> bool { other == self } } impl PartialOrd for JsString { + #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } @@ -1078,6 +1105,7 @@ impl PartialOrd for JsString { impl FromStr for JsString { type Err = Infallible; + #[inline] fn from_str(s: &str) -> Result { Ok(Self::from(s)) } @@ -1091,6 +1119,7 @@ pub(crate) trait ToStringEscaped { } impl ToStringEscaped for [u16] { + #[inline] fn to_string_escaped(&self) -> String { char::decode_utf16(self.iter().copied()) .map(|r| match r { @@ -1100,187 +1129,3 @@ impl ToStringEscaped for [u16] { .collect() } } - -#[allow(clippy::redundant_clone)] -#[cfg(test)] -mod tests { - use std::hash::{BuildHasher, BuildHasherDefault, Hash}; - - use crate::{string::common::StaticJsStrings, tagged::UnwrappedTagged, JsStr}; - - use super::JsString; - use boa_macros::{js_str, utf16}; - use rustc_hash::FxHasher; - - impl JsString { - /// Gets the number of `JsString`s which point to this allocation. - fn refcount(&self) -> Option { - match self.ptr.unwrap() { - UnwrappedTagged::Ptr(inner) => { - // SAFETY: The reference count of `JsString` guarantees that `inner` is always valid. - let inner = unsafe { inner.as_ref() }; - Some(inner.refcount.get()) - } - UnwrappedTagged::Tag(_inner) => None, - } - } - } - - fn hash_value(value: &T) -> u64 { - BuildHasherDefault::::default().hash_one(value) - } - - #[test] - fn empty() { - let s = js_string!(); - assert_eq!(&s, utf16!("")); - } - - #[test] - fn refcount() { - let x = js_string!("Hello world"); - assert_eq!(x.refcount(), Some(1)); - - { - let y = x.clone(); - assert_eq!(x.refcount(), Some(2)); - assert_eq!(y.refcount(), Some(2)); - - { - let z = y.clone(); - assert_eq!(x.refcount(), Some(3)); - assert_eq!(y.refcount(), Some(3)); - assert_eq!(z.refcount(), Some(3)); - } - - assert_eq!(x.refcount(), Some(2)); - assert_eq!(y.refcount(), Some(2)); - } - - assert_eq!(x.refcount(), Some(1)); - } - - #[test] - fn static_refcount() { - let x = js_string!(); - assert_eq!(x.refcount(), None); - - { - let y = x.clone(); - assert_eq!(x.refcount(), None); - assert_eq!(y.refcount(), None); - }; - - assert_eq!(x.refcount(), None); - } - - #[test] - fn ptr_eq() { - let x = js_string!("Hello"); - let y = x.clone(); - - assert!(!x.ptr.is_tagged()); - - assert_eq!(x.ptr.addr(), y.ptr.addr()); - - let z = js_string!("Hello"); - assert_ne!(x.ptr.addr(), z.ptr.addr()); - assert_ne!(y.ptr.addr(), z.ptr.addr()); - } - - #[test] - fn static_ptr_eq() { - let x = js_string!(); - let y = x.clone(); - - assert!(x.ptr.is_tagged()); - - assert_eq!(x.ptr.addr(), y.ptr.addr()); - - let z = js_string!(); - assert_eq!(x.ptr.addr(), z.ptr.addr()); - assert_eq!(y.ptr.addr(), z.ptr.addr()); - } - - #[test] - fn as_str() { - const HELLO: &[u16] = utf16!("Hello"); - let x = js_string!(HELLO); - - assert_eq!(&x, HELLO); - } - - #[test] - fn hash() { - const HELLOWORLD: JsStr<'_> = js_str!("Hello World!"); - let x = js_string!(HELLOWORLD); - - assert_eq!(x.as_str(), HELLOWORLD); - - assert!(HELLOWORLD.is_latin1()); - assert!(x.as_str().is_latin1()); - - let s_hash = hash_value(&HELLOWORLD); - let x_hash = hash_value(&x); - - assert_eq!(s_hash, x_hash); - } - - #[test] - fn concat() { - const Y: &[u16] = utf16!(", "); - const W: &[u16] = utf16!("!"); - - let x = js_string!("hello"); - let z = js_string!("world"); - - let xy = js_string!(&x, &JsString::from(Y)); - assert_eq!(&xy, utf16!("hello, ")); - assert_eq!(xy.refcount(), Some(1)); - - let xyz = js_string!(&xy, &z); - assert_eq!(&xyz, utf16!("hello, world")); - assert_eq!(xyz.refcount(), Some(1)); - - let xyzw = js_string!(&xyz, &JsString::from(W)); - assert_eq!(&xyzw, utf16!("hello, world!")); - assert_eq!(xyzw.refcount(), Some(1)); - } - - #[test] - fn trim_start_non_ascii_to_ascii() { - let s = "\u{2029}abc"; - let x = js_string!(s); - - let y = js_string!(x.trim_start()); - - assert_eq!(&y, s.trim_start()); - } - - #[test] - fn conversion_to_known_static_js_string() { - const JS_STR_U8: &JsStr<'_> = &js_str!("length"); - const JS_STR_U16: &JsStr<'_> = &JsStr::utf16(utf16!("length")); - - assert!(JS_STR_U8.is_latin1()); - assert!(!JS_STR_U16.is_latin1()); - - assert_eq!(JS_STR_U8, JS_STR_U8); - assert_eq!(JS_STR_U16, JS_STR_U16); - - assert_eq!(JS_STR_U8, JS_STR_U16); - assert_eq!(JS_STR_U16, JS_STR_U8); - - assert_eq!(hash_value(JS_STR_U8), hash_value(JS_STR_U16)); - - let string = StaticJsStrings::get_string(JS_STR_U8); - - assert!(string.is_some()); - assert!(string.unwrap().as_str().is_latin1()); - - let string = StaticJsStrings::get_string(JS_STR_U16); - - assert!(string.is_some()); - assert!(string.unwrap().as_str().is_latin1()); - } -} diff --git a/core/engine/src/string/str.rs b/core/string/src/str.rs similarity index 96% rename from core/engine/src/string/str.rs rename to core/string/src/str.rs index 6ce3c4cabd..ef31ac7a27 100644 --- a/core/engine/src/string/str.rs +++ b/core/string/src/str.rs @@ -1,7 +1,4 @@ -use crate::{ - builtins::string::{is_trimmable_whitespace, is_trimmable_whitespace_latin1}, - string::Iter, -}; +use crate::{is_trimmable_whitespace, is_trimmable_whitespace_latin1, Iter}; use std::{ hash::{Hash, Hasher}, slice::SliceIndex, @@ -195,6 +192,8 @@ impl<'a> JsStr<'a> { } /// Convert the [`JsStr`] into a [`Vec`]. + #[inline] + #[must_use] pub fn to_vec(&self) -> Vec { match self.variant() { JsStrVariant::Latin1(v) => v.iter().copied().map(u16::from).collect(), @@ -203,13 +202,19 @@ impl<'a> JsStr<'a> { } /// Returns true if needle is a prefix of the [`JsStr`]. + #[inline] #[must_use] + // We check the size, so this should never panic. + #[allow(clippy::missing_panics_doc)] pub fn starts_with(&self, needle: JsStr<'_>) -> bool { let n = needle.len(); self.len() >= n && needle == self.get(..n).expect("already checked size") } /// Returns `true` if `needle` is a suffix of the [`JsStr`]. + #[inline] #[must_use] + // We check the size, so this should never panic. + #[allow(clippy::missing_panics_doc)] pub fn ends_with(&self, needle: JsStr<'_>) -> bool { let (m, n) = (self.len(), needle.len()); m >= n && needle == self.get(m - n..).expect("already checked size") @@ -217,6 +222,7 @@ impl<'a> JsStr<'a> { } impl Hash for JsStr<'_> { + #[inline] fn hash(&self, state: &mut H) { // NOTE: The hash function has been inlined to ensure that a hash of latin1 and U16 // encoded strings remains the same if they have the same characters @@ -238,6 +244,7 @@ impl Hash for JsStr<'_> { } impl Ord for JsStr<'_> { + #[inline] fn cmp(&self, other: &Self) -> std::cmp::Ordering { match (self.variant(), other.variant()) { (JsStrVariant::Latin1(x), JsStrVariant::Latin1(y)) => x.cmp(y), @@ -250,6 +257,7 @@ impl Ord for JsStr<'_> { impl Eq for JsStr<'_> {} impl PartialEq for JsStr<'_> { + #[inline] fn eq(&self, other: &Self) -> bool { match (self.variant(), other.variant()) { (JsStrVariant::Latin1(lhs), JsStrVariant::Latin1(rhs)) => return lhs == rhs, @@ -269,6 +277,7 @@ impl PartialEq for JsStr<'_> { } impl<'a> PartialEq> for [u16] { + #[inline] fn eq(&self, other: &JsStr<'a>) -> bool { if self.len() != other.len() { return false; diff --git a/core/string/src/tagged.rs b/core/string/src/tagged.rs new file mode 100644 index 0000000000..83ec17c24b --- /dev/null +++ b/core/string/src/tagged.rs @@ -0,0 +1,109 @@ +// Remove when/if https://github.com/rust-lang/rust/issues/95228 stabilizes. +// Right now this allows us to use the stable polyfill from the `sptr` crate, which uses +// the same names from the unstable functions of the `std::ptr` module. +#![allow(unstable_name_collisions)] + +use sptr::Strict; +use std::ptr::NonNull; + +/// A pointer that can be tagged with an `usize`. +/// +/// Only pointers with a minimum alignment of 2-bytes are valid, and the tag must have its most +/// significant bit (MSB) unset. In other words, the tag must fit inside `usize::BITS - 1` bits. +/// +/// # Representation +/// +/// If the least significant bit (LSB) of the internal [`NonNull`] is set (1), then the pointer +/// address represents a tag where the remaining bits store the tag. Otherwise, the whole pointer +/// represents the pointer itself. +/// +/// It uses [`NonNull`], which guarantees that [`Tagged`] can use the "null pointer optimization" +/// to optimize the size of [`Option`]. +/// +/// # Provenance +/// +/// This struct stores a [`NonNull`] instead of a [`NonZeroUsize`][std::num::NonZeroUsize] +/// in order to preserve the provenance of our valid heap pointers. +/// On the other hand, all index values are just casted to invalid pointers, because we don't need to +/// preserve the provenance of [`usize`] indices. +/// +/// [tagged_wp]: https://en.wikipedia.org/wiki/Tagged_pointer +#[derive(Debug)] +pub(crate) struct Tagged(NonNull); + +impl Clone for Tagged { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Tagged {} + +impl Tagged { + /// Creates a new, tagged `Tagged` pointer from an integer. + /// + /// # Requirements + /// + /// - `T` must have an alignment of at least 2. + /// - `tag` must fit inside `usize::BITS - 1` bits + pub(crate) const fn from_tag(tag: usize) -> Self { + debug_assert!(std::mem::align_of::() >= 2); + let addr = (tag << 1) | 1; + // SAFETY: `addr` is never zero, since we always set its LSB to 1 + unsafe { Self(NonNull::new_unchecked(sptr::invalid_mut(addr))) } + } + + /// Creates a new `Tagged` pointer from a raw pointer. + /// + /// # Requirements + /// + /// - `T` must have an alignment of at least 2. + /// + /// # Safety + /// + /// - `T` must be non null. + pub(crate) const unsafe fn from_ptr(ptr: *mut T) -> Self { + debug_assert!(std::mem::align_of::() >= 2); + // SAFETY: the caller must ensure the invariants hold. + unsafe { Self(NonNull::new_unchecked(ptr)) } + } + + /// Creates a new `Tagged` pointer from a `NonNull` pointer. + /// + /// # Requirements + /// + /// - `T` must have an alignment of at least 2. + pub(crate) const fn from_non_null(ptr: NonNull) -> Self { + debug_assert!(std::mem::align_of::() >= 2); + Self(ptr) + } + + /// Unwraps the `Tagged` pointer. + pub(crate) fn unwrap(self) -> UnwrappedTagged { + let addr = self.0.as_ptr().addr(); + if addr & 1 == 0 { + UnwrappedTagged::Ptr(self.0) + } else { + UnwrappedTagged::Tag(addr >> 1) + } + } + + /// Gets the address of the inner pointer. + #[allow(unused)] + pub(crate) fn addr(self) -> usize { + self.0.as_ptr().addr() + } + + /// Returns `true` if `self ` is a tagged pointer. + #[allow(unused)] + pub(crate) fn is_tagged(self) -> bool { + self.0.as_ptr().addr() & 1 > 0 + } +} + +/// The unwrapped value of a [`Tagged`] pointer. +#[derive(Debug, Clone, Copy)] +pub(crate) enum UnwrappedTagged { + Ptr(NonNull), + Tag(usize), +} diff --git a/core/string/src/tests.rs b/core/string/src/tests.rs new file mode 100644 index 0000000000..2022994b48 --- /dev/null +++ b/core/string/src/tests.rs @@ -0,0 +1,166 @@ +#![allow(clippy::redundant_clone)] + +use std::hash::{BuildHasher, BuildHasherDefault, Hash}; + +use crate::{JsStr, JsString, StaticJsStrings}; + +use boa_macros::utf16; +use rustc_hash::FxHasher; + +fn hash_value(value: &T) -> u64 { + BuildHasherDefault::::default().hash_one(value) +} + +#[test] +fn empty() { + let s = StaticJsStrings::EMPTY_STRING; + assert_eq!(&s, utf16!("")); +} + +#[test] +fn refcount() { + let x = JsString::from("Hello world"); + assert_eq!(x.refcount(), Some(1)); + + { + let y = x.clone(); + assert_eq!(x.refcount(), Some(2)); + assert_eq!(y.refcount(), Some(2)); + + { + let z = y.clone(); + assert_eq!(x.refcount(), Some(3)); + assert_eq!(y.refcount(), Some(3)); + assert_eq!(z.refcount(), Some(3)); + } + + assert_eq!(x.refcount(), Some(2)); + assert_eq!(y.refcount(), Some(2)); + } + + assert_eq!(x.refcount(), Some(1)); +} + +#[test] +fn static_refcount() { + let x = StaticJsStrings::EMPTY_STRING; + assert_eq!(x.refcount(), None); + + { + let y = x.clone(); + assert_eq!(x.refcount(), None); + assert_eq!(y.refcount(), None); + }; + + assert_eq!(x.refcount(), None); +} + +#[test] +fn ptr_eq() { + let x = JsString::from("Hello"); + let y = x.clone(); + + assert!(!x.ptr.is_tagged()); + + assert_eq!(x.ptr.addr(), y.ptr.addr()); + + let z = JsString::from("Hello"); + assert_ne!(x.ptr.addr(), z.ptr.addr()); + assert_ne!(y.ptr.addr(), z.ptr.addr()); +} + +#[test] +fn static_ptr_eq() { + let x = StaticJsStrings::EMPTY_STRING; + let y = x.clone(); + + assert!(x.ptr.is_tagged()); + + assert_eq!(x.ptr.addr(), y.ptr.addr()); + + let z = StaticJsStrings::EMPTY_STRING; + assert_eq!(x.ptr.addr(), z.ptr.addr()); + assert_eq!(y.ptr.addr(), z.ptr.addr()); +} + +#[test] +fn as_str() { + const HELLO: &[u16] = utf16!("Hello"); + let x = JsString::from(HELLO); + + assert_eq!(&x, HELLO); +} + +#[test] +fn hash() { + const HELLOWORLD: JsStr<'_> = JsStr::latin1("Hello World!".as_bytes()); + let x = JsString::from(HELLOWORLD); + + assert_eq!(x.as_str(), HELLOWORLD); + + assert!(HELLOWORLD.is_latin1()); + assert!(x.as_str().is_latin1()); + + let s_hash = hash_value(&HELLOWORLD); + let x_hash = hash_value(&x); + + assert_eq!(s_hash, x_hash); +} + +#[test] +fn concat() { + const Y: &[u16] = utf16!(", "); + const W: &[u16] = utf16!("!"); + + let x = JsString::from("hello"); + let z = JsString::from("world"); + + let xy = JsString::concat(x.as_str(), JsString::from(Y).as_str()); + assert_eq!(&xy, utf16!("hello, ")); + assert_eq!(xy.refcount(), Some(1)); + + let xyz = JsString::concat(xy.as_str(), z.as_str()); + assert_eq!(&xyz, utf16!("hello, world")); + assert_eq!(xyz.refcount(), Some(1)); + + let xyzw = JsString::concat(xyz.as_str(), JsString::from(W).as_str()); + assert_eq!(&xyzw, utf16!("hello, world!")); + assert_eq!(xyzw.refcount(), Some(1)); +} + +#[test] +fn trim_start_non_ascii_to_ascii() { + let s = "\u{2029}abc"; + let x = JsString::from(s); + + let y = JsString::from(x.trim_start()); + + assert_eq!(&y, s.trim_start()); +} + +#[test] +fn conversion_to_known_static_js_string() { + const JS_STR_U8: &JsStr<'_> = &JsStr::latin1("length".as_bytes()); + const JS_STR_U16: &JsStr<'_> = &JsStr::utf16(utf16!("length")); + + assert!(JS_STR_U8.is_latin1()); + assert!(!JS_STR_U16.is_latin1()); + + assert_eq!(JS_STR_U8, JS_STR_U8); + assert_eq!(JS_STR_U16, JS_STR_U16); + + assert_eq!(JS_STR_U8, JS_STR_U16); + assert_eq!(JS_STR_U16, JS_STR_U8); + + assert_eq!(hash_value(JS_STR_U8), hash_value(JS_STR_U16)); + + let string = StaticJsStrings::get_string(JS_STR_U8); + + assert!(string.is_some()); + assert!(string.unwrap().as_str().is_latin1()); + + let string = StaticJsStrings::get_string(JS_STR_U16); + + assert!(string.is_some()); + assert!(string.unwrap().as_str().is_latin1()); +}