Browse Source

Separate `JsString` into its own crate (#3837)

utility-crate
Haled Odat 6 months ago committed by GitHub
parent
commit
ced222fdba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      ABOUT.md
  2. 16
      Cargo.lock
  3. 1
      Cargo.toml
  4. 2
      cli/ABOUT.md
  5. 2
      core/ast/ABOUT.md
  6. 2
      core/engine/ABOUT.md
  7. 5
      core/engine/Cargo.toml
  8. 2
      core/engine/src/builtins/array/mod.rs
  9. 2
      core/engine/src/builtins/array_buffer/mod.rs
  10. 2
      core/engine/src/builtins/array_buffer/shared.rs
  11. 2
      core/engine/src/builtins/async_function/mod.rs
  12. 2
      core/engine/src/builtins/async_generator/mod.rs
  13. 2
      core/engine/src/builtins/async_generator_function/mod.rs
  14. 2
      core/engine/src/builtins/atomics/mod.rs
  15. 2
      core/engine/src/builtins/bigint/mod.rs
  16. 2
      core/engine/src/builtins/boolean/mod.rs
  17. 2
      core/engine/src/builtins/builder.rs
  18. 2
      core/engine/src/builtins/dataview/mod.rs
  19. 2
      core/engine/src/builtins/date/mod.rs
  20. 2
      core/engine/src/builtins/error/aggregate.rs
  21. 2
      core/engine/src/builtins/error/eval.rs
  22. 2
      core/engine/src/builtins/error/mod.rs
  23. 2
      core/engine/src/builtins/error/range.rs
  24. 2
      core/engine/src/builtins/error/reference.rs
  25. 2
      core/engine/src/builtins/error/syntax.rs
  26. 2
      core/engine/src/builtins/error/type.rs
  27. 2
      core/engine/src/builtins/error/uri.rs
  28. 4
      core/engine/src/builtins/escape/mod.rs
  29. 2
      core/engine/src/builtins/eval/mod.rs
  30. 2
      core/engine/src/builtins/function/mod.rs
  31. 2
      core/engine/src/builtins/generator/mod.rs
  32. 2
      core/engine/src/builtins/generator_function/mod.rs
  33. 2
      core/engine/src/builtins/intl/collator/mod.rs
  34. 2
      core/engine/src/builtins/intl/date_time_format.rs
  35. 2
      core/engine/src/builtins/intl/list_format/mod.rs
  36. 2
      core/engine/src/builtins/intl/locale/mod.rs
  37. 2
      core/engine/src/builtins/intl/mod.rs
  38. 2
      core/engine/src/builtins/intl/number_format/mod.rs
  39. 2
      core/engine/src/builtins/intl/plural_rules/mod.rs
  40. 2
      core/engine/src/builtins/intl/segmenter/mod.rs
  41. 2
      core/engine/src/builtins/json/mod.rs
  42. 2
      core/engine/src/builtins/map/mod.rs
  43. 4
      core/engine/src/builtins/math/mod.rs
  44. 2
      core/engine/src/builtins/number/globals.rs
  45. 2
      core/engine/src/builtins/number/mod.rs
  46. 2
      core/engine/src/builtins/object/mod.rs
  47. 2
      core/engine/src/builtins/promise/mod.rs
  48. 2
      core/engine/src/builtins/proxy/mod.rs
  49. 2
      core/engine/src/builtins/reflect/mod.rs
  50. 2
      core/engine/src/builtins/regexp/mod.rs
  51. 2
      core/engine/src/builtins/set/mod.rs
  52. 19
      core/engine/src/builtins/string/mod.rs
  53. 2
      core/engine/src/builtins/symbol/mod.rs
  54. 2
      core/engine/src/builtins/temporal/calendar/mod.rs
  55. 2
      core/engine/src/builtins/temporal/duration/mod.rs
  56. 2
      core/engine/src/builtins/temporal/instant/mod.rs
  57. 2
      core/engine/src/builtins/temporal/mod.rs
  58. 2
      core/engine/src/builtins/temporal/now.rs
  59. 2
      core/engine/src/builtins/temporal/plain_date/mod.rs
  60. 2
      core/engine/src/builtins/temporal/plain_date_time/mod.rs
  61. 2
      core/engine/src/builtins/temporal/plain_month_day/mod.rs
  62. 2
      core/engine/src/builtins/temporal/plain_time/mod.rs
  63. 2
      core/engine/src/builtins/temporal/plain_year_month/mod.rs
  64. 2
      core/engine/src/builtins/temporal/time_zone/mod.rs
  65. 2
      core/engine/src/builtins/temporal/zoned_date_time/mod.rs
  66. 2
      core/engine/src/builtins/typed_array/builtin.rs
  67. 2
      core/engine/src/builtins/typed_array/mod.rs
  68. 2
      core/engine/src/builtins/uri/mod.rs
  69. 2
      core/engine/src/builtins/weak/weak_ref.rs
  70. 2
      core/engine/src/builtins/weak_map/mod.rs
  71. 2
      core/engine/src/builtins/weak_set/mod.rs
  72. 2
      core/engine/src/object/mod.rs
  73. 2
      core/engine/src/object/operations.rs
  74. 211
      core/engine/src/string.rs
  75. 950
      core/engine/src/string/common.rs
  76. 2
      core/engine/src/symbol.rs
  77. 1
      core/engine/src/tagged.rs
  78. 2
      core/engine/src/vm/opcode/push/array.rs
  79. 2
      core/gc/ABOUT.md
  80. 3
      core/gc/Cargo.toml
  81. 12
      core/gc/src/trace.rs
  82. 2
      core/icu_provider/ABOUT.md
  83. 2
      core/interner/ABOUT.md
  84. 2
      core/interop/ABOUT.md
  85. 2
      core/macros/ABOUT.md
  86. 2
      core/parser/ABOUT.md
  87. 2
      core/profiler/ABOUT.md
  88. 2
      core/runtime/ABOUT.md
  89. 34
      core/string/ABOUT.md
  90. 28
      core/string/Cargo.toml
  91. 951
      core/string/src/common.rs
  92. 4
      core/string/src/iter.rs
  93. 369
      core/string/src/lib.rs
  94. 17
      core/string/src/str.rs
  95. 109
      core/string/src/tagged.rs
  96. 166
      core/string/src/tests.rs

2
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

16
Cargo.lock generated

@ -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"

1
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"

2
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

2
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

2
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

5
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"

2
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,

2
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,
};

2
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,
};

2
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,
};

2
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},

2
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,

2
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,
};

2
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,

2
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;

2
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,
};

2
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,

2
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,

2
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;

2
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;

2
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};

2
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;

2
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;

2
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;

2
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;

2
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;

4
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};

2
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,
};

2
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},

2
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},

2
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,

2
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,
};

2
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,
};

2
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,
};

2
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;

2
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,
};

2
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,

2
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,
};

2
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,
};

2
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},

2
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,
};

4
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;

2
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,
};

2
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,
};

2
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,

2
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,

2
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,
};

2
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,
};

2
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,

2
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,
};

19
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;

2
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,

2
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};

2
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};

2
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,
};

2
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,
};

2
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,
};

2
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};

2
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};

2
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};

2
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};

2
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};

2
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};

2
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};

2
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,
};

2
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,

2
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,
};

2
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,
};

2
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,
};

2
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,
};

2
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,
};

2
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,
};

211
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 <code>[&\[u16\]][slice]</code>:
///
/// ```
/// # 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<T: Hash>(value: &T) -> u64 {
BuildHasherDefault::<FxHasher>::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());
}
}

950
core/engine/src/string/common.rs

@ -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<JsString> {
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<JsStr<'static>> {
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<JsStr<'static>, usize> = {
let mut constants = FxHashMap::with_capacity_and_hasher(
RAW_STATICS.len(),
BuildHasherDefault::<FxHasher>::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!("$"),
];

2
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};

1
core/engine/src/tagged.rs

@ -39,6 +39,7 @@ impl<T> Clone for Tagged<T> {
impl<T> Copy for Tagged<T> {}
#[allow(dead_code)]
impl<T> Tagged<T> {
/// Creates a new, tagged `Tagged` pointer from an integer.
///

2
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,
};

2
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

3
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 }

12
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 {}
}

2
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

2
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

2
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

2
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

2
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

2
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

2
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

34
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

28
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

951
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<JsString> {
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<JsStr<'static>> {
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<JsStr<'static>, usize> = {
let mut constants = FxHashMap::with_capacity_and_hasher(
RAW_STATICS.len(),
BuildHasherDefault::<FxHasher>::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()),
];

4
core/engine/src/string/iter.rs → 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<Self::Item> {
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<Self::Item> {
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(),

369
core/engine/src/string/mod.rs → 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 <code>[&\[u16\]][slice]</code>:
///
/// ```
/// # 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<char> {
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::<RawJsString>();
///
/// 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<RawJsString>,
@ -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<String, std::string::FromUtf16Error> {
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<String, u16>`], returning surrogates as
/// errors.
#[inline]
pub fn to_std_string_with_surrogates(&self) -> impl Iterator<Item = Result<String, u16>> + '_ {
struct WideStringDecoderIterator<I: Iterator> {
codepoints: Peekable<I>,
@ -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<F>(&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<Item = CodePoint> + 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<usize> {
// 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<U16>`].
#[inline]
#[must_use]
pub fn to_vec(&self) -> Vec<u16> {
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<I::Value>
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<usize> {
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<JsStr<'_>> 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<JsStr<'_>> for JsString {
}
impl From<&[JsString]> for JsString {
#[inline]
fn from(value: &[JsString]) -> Self {
Self::concat_array(
&value
@ -972,36 +985,42 @@ impl From<String> for JsString {
}
impl<const N: usize> From<&[u16; N]> for JsString {
#[inline]
fn from(s: &[u16; N]) -> Self {
Self::from(&s[..])
}
}
impl Hash for JsString {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
impl PartialOrd for JsStr<'_> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
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<JsString> for [u16] {
#[inline]
fn eq(&self, other: &JsString) -> bool {
if self.len() != other.len() {
return false;
@ -1016,24 +1035,28 @@ impl PartialEq<JsString> for [u16] {
}
impl<const N: usize> PartialEq<JsString> 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<const N: usize> PartialEq<[u16; N]> for JsString {
#[inline]
fn eq(&self, other: &[u16; N]) -> bool {
*self == other[..]
}
}
impl PartialEq<str> 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<str> for JsString {
}
impl PartialEq<JsString> for str {
#[inline]
fn eq(&self, other: &JsString) -> bool {
other == self
}
}
impl PartialEq<JsStr<'_>> for JsString {
#[inline]
fn eq(&self, other: &JsStr<'_>) -> bool {
self.as_str() == *other
}
}
impl PartialEq<JsString> for JsStr<'_> {
#[inline]
fn eq(&self, other: &JsString) -> bool {
other == self
}
}
impl PartialOrd for JsString {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
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<Self, Self::Err> {
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<usize> {
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<T: Hash>(value: &T) -> u64 {
BuildHasherDefault::<FxHasher>::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());
}
}

17
core/engine/src/string/str.rs → 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<U16>`].
#[inline]
#[must_use]
pub fn to_vec(&self) -> Vec<u16> {
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<H: Hasher>(&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<JsStr<'a>> for [u16] {
#[inline]
fn eq(&self, other: &JsStr<'a>) -> bool {
if self.len() != other.len() {
return false;

109
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<Tagged>`].
///
/// # Provenance
///
/// This struct stores a [`NonNull<T>`] 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<T>(NonNull<T>);
impl<T> Clone for Tagged<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Tagged<T> {}
impl<T> Tagged<T> {
/// 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::<T>() >= 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::<T>() >= 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<T>) -> Self {
debug_assert!(std::mem::align_of::<T>() >= 2);
Self(ptr)
}
/// Unwraps the `Tagged` pointer.
pub(crate) fn unwrap(self) -> UnwrappedTagged<T> {
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<T> {
Ptr(NonNull<T>),
Tag(usize),
}

166
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<T: Hash>(value: &T) -> u64 {
BuildHasherDefault::<FxHasher>::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());
}
Loading…
Cancel
Save