From 9d7153cdf357481979a14f5b2ad352247c6da289 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:59:17 +0200 Subject: [PATCH 01/72] Bump the rust-dependencies group with 4 updates (#4013) Bumps the rust-dependencies group with 4 updates: [once_cell](https://github.com/matklad/once_cell), [regex](https://github.com/rust-lang/regex), [syn](https://github.com/dtolnay/syn) and [portable-atomic](https://github.com/taiki-e/portable-atomic). Updates `once_cell` from 1.19.0 to 1.20.1 - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.19.0...v1.20.1) Updates `regex` from 1.10.6 to 1.11.0 - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.10.6...1.11.0) Updates `syn` from 2.0.77 to 2.0.79 - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.77...2.0.79) Updates `portable-atomic` from 1.8.0 to 1.9.0 - [Release notes](https://github.com/taiki-e/portable-atomic/releases) - [Changelog](https://github.com/taiki-e/portable-atomic/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/portable-atomic/compare/v1.8.0...v1.9.0) --- updated-dependencies: - dependency-name: once_cell dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: portable-atomic dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 8 ++++---- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb210c9032c..9460027662c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -921,9 +921,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" +checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" [[package]] name = "crossbeam-channel" @@ -2359,9 +2359,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" dependencies = [ "critical-section", "portable-atomic", @@ -2605,9 +2605,9 @@ checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" [[package]] name = "portable-atomic" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d30538d42559de6b034bc76fd6dd4c38961b1ee5c6c56e3808c50128fdbc22ce" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "postcard" @@ -2726,14 +2726,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -2748,13 +2748,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2765,9 +2765,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "regress" @@ -3184,9 +3184,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index f5651d63b55..96ddfadbf3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,10 +57,10 @@ indoc = "2.0.5" jemallocator = "0.5.4" num-bigint = "0.4.6" num-traits = "0.2.19" -once_cell = { version = "1.19.0", default-features = false } +once_cell = { version = "1.20.1", default-features = false } phf = { version = "0.11.2", default-features = false } pollster = "0.3.0" -regex = "1.10.6" +regex = "1.11.0" regress = { version = "0.10.1", features = ["utf16"] } rustc-hash = { version = "2.0.0", default-features = false } serde_json = "1.0.128" @@ -90,7 +90,7 @@ isahc = "1.7.2" rustyline = { version = "14.0.0", default-features = false } dhat = "0.3.3" quote = "1.0.37" -syn = { version = "2.0.77", default-features = false } +syn = { version = "2.0.79", default-features = false } proc-macro2 = "1.0" synstructure = "0.13" measureme = "11.0.1" @@ -104,7 +104,7 @@ thiserror = "1.0.64" dashmap = "5.5.3" num_enum = "0.7.3" itertools = { version = "0.13.0", default-features = false } -portable-atomic = "1.8.0" +portable-atomic = "1.9.0" bytemuck = { version = "1.18.0", default-features = false } arrayvec = "0.7.6" intrusive-collections = "0.9.7" From fcd4422b2875abf95914d13e361d9d806cc2388e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 19:44:15 +0200 Subject: [PATCH 02/72] Bump the rust-dependencies group with 4 updates (#4015) Bumps the rust-dependencies group with 4 updates: [clap](https://github.com/clap-rs/clap), [indexmap](https://github.com/indexmap-rs/indexmap), [once_cell](https://github.com/matklad/once_cell) and [futures-util](https://github.com/rust-lang/futures-rs). Updates `clap` from 4.5.18 to 4.5.19 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.18...clap_complete-v4.5.19) Updates `indexmap` from 2.5.0 to 2.6.0 - [Changelog](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.5.0...2.6.0) Updates `once_cell` from 1.20.1 to 1.20.2 - [Changelog](https://github.com/matklad/once_cell/blob/master/CHANGELOG.md) - [Commits](https://github.com/matklad/once_cell/compare/v1.20.1...v1.20.2) Updates `futures-util` from 0.3.30 to 0.3.31 - [Release notes](https://github.com/rust-lang/futures-rs/releases) - [Changelog](https://github.com/rust-lang/futures-rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/futures-rs/compare/0.3.30...0.3.31) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: indexmap dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: once_cell dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: futures-util dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 50 ++++++++++++++++++++++++++++---------------------- Cargo.toml | 8 ++++---- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9460027662c..68500d8c19e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -364,7 +364,7 @@ dependencies = [ "fixed_decimal", "float-cmp", "futures-lite 2.3.0", - "hashbrown", + "hashbrown 0.14.5", "icu_calendar", "icu_casemap", "icu_collator", @@ -435,7 +435,7 @@ dependencies = [ "boa_macros", "boa_profiler", "boa_string", - "hashbrown", + "hashbrown 0.14.5", "icu_locid", "thin-vec", ] @@ -467,7 +467,7 @@ dependencies = [ "arbitrary", "boa_gc", "boa_macros", - "hashbrown", + "hashbrown 0.14.5", "indexmap", "once_cell", "phf", @@ -738,9 +738,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -748,9 +748,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -1025,7 +1025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core", @@ -1294,9 +1294,9 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" @@ -1334,9 +1334,9 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -1345,15 +1345,15 @@ dependencies = [ [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-macro", @@ -1426,6 +1426,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "heck" version = "0.5.0" @@ -1933,12 +1939,12 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.0", ] [[package]] @@ -2359,9 +2365,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.1" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" dependencies = [ "critical-section", "portable-atomic", @@ -2775,7 +2781,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1541daf4e4ed43a0922b7969bdc2170178bcacc5dabf7e39bc508a9fa3953a7a" dependencies = [ - "hashbrown", + "hashbrown 0.14.5", "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 96ddfadbf3c..008d2eb3a22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,16 +48,16 @@ boa_string = { version = "~0.19.0", path = "core/string" } # Shared deps arbitrary = "1" bitflags = "2.5.0" -clap = "4.5.18" +clap = "4.5.19" colored = "2.1.0" fast-float = "0.2.0" hashbrown = { version = "0.14.5", default-features = false } -indexmap = { version = "2.5.0", default-features = false } +indexmap = { version = "2.6.0", default-features = false } indoc = "2.0.5" jemallocator = "0.5.4" num-bigint = "0.4.6" num-traits = "0.2.19" -once_cell = { version = "1.20.1", default-features = false } +once_cell = { version = "1.20.2", default-features = false } phf = { version = "0.11.2", default-features = false } pollster = "0.3.0" regex = "1.11.0" @@ -85,7 +85,7 @@ getrandom = { version = "0.2.15", default-features = false } console_error_panic_hook = "0.1.7" wasm-bindgen-test = "0.3.43" smol = "2.0.2" -futures-util = "0.3.30" +futures-util = "0.3.31" isahc = "1.7.2" rustyline = { version = "14.0.0", default-features = false } dhat = "0.3.3" From c9d1b5d805d7ae633ba05ba7bd460eaea3cd244a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:44:28 +0000 Subject: [PATCH 03/72] Bump rustsec/audit-check from 1.4.1 to 2.0.0 (#4012) Bumps [rustsec/audit-check](https://github.com/rustsec/audit-check) from 1.4.1 to 2.0.0. - [Release notes](https://github.com/rustsec/audit-check/releases) - [Changelog](https://github.com/rustsec/audit-check/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustsec/audit-check/compare/v1.4.1...v2.0.0) --- updated-dependencies: - dependency-name: rustsec/audit-check dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/security_audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/security_audit.yml b/.github/workflows/security_audit.yml index fd4fb530ff7..45a49316998 100644 --- a/.github/workflows/security_audit.yml +++ b/.github/workflows/security_audit.yml @@ -9,6 +9,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - uses: rustsec/audit-check@v1.4.1 + - uses: rustsec/audit-check@v2.0.0 with: token: ${{ secrets.GITHUB_TOKEN }} From 67f4884d9bbf7905923559229003c24d1cd95501 Mon Sep 17 00:00:00 2001 From: Nikita-str <42584606+Nikita-str@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:45:09 +0300 Subject: [PATCH 04/72] `JsValue::to_json` fix integer property keys (#4011) * #3923: `to_json` fix integer properties key * some refactoring --- .../src/value/conversions/serde_json.rs | 50 ++++++++++++------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/core/engine/src/value/conversions/serde_json.rs b/core/engine/src/value/conversions/serde_json.rs index 104d928e7c9..95bbd5e884f 100644 --- a/core/engine/src/value/conversions/serde_json.rs +++ b/core/engine/src/value/conversions/serde_json.rs @@ -124,22 +124,33 @@ impl JsValue { .with_message("cannot convert bigint to JSON") .into()), Self::Object(obj) => { + let value_by_prop_key = |property_key, context: &mut Context| { + obj.borrow() + .properties() + .get(&property_key) + .and_then(|x| x.value().map(|val| val.to_json(context))) + .unwrap_or(Ok(Value::Null)) + }; + if obj.is_array() { let len = obj.length_of_array_like(context)?; let mut arr = Vec::with_capacity(len as usize); - let obj = obj.borrow(); - for k in 0..len as u32 { - let val = obj.properties().get(&k.into()).map_or(Self::Null, |desc| { - desc.value().cloned().unwrap_or(Self::Null) - }); - arr.push(val.to_json(context)?); + let val = value_by_prop_key(k.into(), context)?; + arr.push(val); } Ok(Value::Array(arr)) } else { let mut map = Map::new(); + + for index in obj.borrow().properties().index_property_keys() { + let key = index.to_string(); + let value = value_by_prop_key(index.into(), context)?; + map.insert(key, value); + } + for property_key in obj.borrow().properties().shape.keys() { let key = match &property_key { PropertyKey::String(string) => string.to_std_string_escaped(), @@ -150,17 +161,7 @@ impl JsValue { .into()) } }; - - let value = match obj - .borrow() - .properties() - .get(&property_key) - .and_then(|x| x.value().cloned()) - { - Some(val) => val.to_json(context)?, - None => Value::Null, - }; - + let value = value_by_prop_key(property_key, context)?; map.insert(key, value); } @@ -181,7 +182,7 @@ mod tests { use serde_json::json; use crate::object::JsArray; - use crate::JsValue; + use crate::{js_string, JsValue}; use crate::{run_test_actions, TestAction}; #[test] @@ -200,7 +201,10 @@ mod tests { -45, {}, true - ] + ], + "7.3": "random text", + "100": 1000, + "24": 42 } "#}; @@ -217,6 +221,14 @@ mod tests { assert_eq!(obj.get(js_str!("age"), ctx).unwrap(), 43_i32.into()); assert_eq!(obj.get(js_str!("minor"), ctx).unwrap(), false.into()); assert_eq!(obj.get(js_str!("adult"), ctx).unwrap(), true.into()); + + assert_eq!( + obj.get(js_str!("7.3"), ctx).unwrap(), + js_string!("random text").into() + ); + assert_eq!(obj.get(js_str!("100"), ctx).unwrap(), 1000.into()); + assert_eq!(obj.get(js_str!("24"), ctx).unwrap(), 42.into()); + { let extra = obj.get(js_str!("extra"), ctx).unwrap(); let extra = extra.as_object().unwrap(); From 94d08fe4e68791ceca3c4b7d94ccc5f3588feeb3 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Wed, 9 Oct 2024 10:54:23 -0700 Subject: [PATCH 05/72] Add a URL class to boa_runtime (#4004) * Add a URL class (with caveats) Some methods are NOT currently supported (some don' make sense outside of a browser context). They are still implemented but will throw a JavaScript Error. Supported methods should follow the specification perfectly. * Adding tests and using url::quirks for simpler getters/setters * clippies * Address comments --- Cargo.lock | 1 + cli/src/main.rs | 11 +- core/runtime/Cargo.toml | 5 + core/runtime/src/console/mod.rs | 4 +- core/runtime/src/lib.rs | 53 +++++++ core/runtime/src/url.rs | 236 ++++++++++++++++++++++++++++++++ core/runtime/src/url/tests.rs | 113 +++++++++++++++ core/string/src/lib.rs | 13 ++ 8 files changed, 426 insertions(+), 10 deletions(-) create mode 100644 core/runtime/src/url.rs create mode 100644 core/runtime/src/url/tests.rs diff --git a/Cargo.lock b/Cargo.lock index 68500d8c19e..12f26aaccd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -540,6 +540,7 @@ dependencies = [ "indoc", "rustc-hash 2.0.0", "textwrap", + "url", ] [[package]] diff --git a/cli/src/main.rs b/cli/src/main.rs index d43335df528..899b73f3139 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -14,15 +14,12 @@ use boa_engine::{ builtins::promise::PromiseState, context::ContextBuilder, job::{FutureJob, JobQueue, NativeJob}, - js_string, module::{Module, SimpleModuleLoader}, optimizer::OptimizerOptions, - property::Attribute, script::Script, vm::flowgraph::{Direction, Graph}, Context, JsError, JsNativeError, JsResult, Source, }; -use boa_runtime::Console; use clap::{Parser, ValueEnum, ValueHint}; use colored::Colorize; use debug::init_boa_debug_object; @@ -442,12 +439,10 @@ fn main() -> Result<(), io::Error> { Ok(()) } -/// Adds the CLI runtime to the context. +/// Adds the CLI runtime to the context with default options. fn add_runtime(context: &mut Context) { - let console = Console::init(context); - context - .register_global_property(js_string!(Console::NAME), console, Attribute::all()) - .expect("the console object shouldn't exist"); + boa_runtime::register(context, boa_runtime::RegisterOptions::new()) + .expect("should not fail while registering the runtime"); } #[derive(Default)] diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 62a0a4907f6..95c743b9841 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -15,6 +15,7 @@ boa_engine.workspace = true boa_gc.workspace = true boa_interop.workspace = true rustc-hash = { workspace = true, features = ["std"] } +url = { version = "2.5.2", optional = true } [dev-dependencies] indoc.workspace = true @@ -25,3 +26,7 @@ workspace = true [package.metadata.docs.rs] all-features = true + +[features] +default = ["all"] +all = ["url"] diff --git a/core/runtime/src/console/mod.rs b/core/runtime/src/console/mod.rs index bc2efa8bc86..c9fde6b79d2 100644 --- a/core/runtime/src/console/mod.rs +++ b/core/runtime/src/console/mod.rs @@ -58,8 +58,8 @@ pub trait Logger: Trace + Sized { /// Implements the [`Logger`] trait and output errors to stderr and all /// the others to stdout. Will add indentation based on the number of /// groups. -#[derive(Trace, Finalize)] -struct DefaultLogger; +#[derive(Debug, Trace, Finalize)] +pub struct DefaultLogger; impl Logger for DefaultLogger { #[inline] diff --git a/core/runtime/src/lib.rs b/core/runtime/src/lib.rs index 38dea056c27..f5f501dc138 100644 --- a/core/runtime/src/lib.rs +++ b/core/runtime/src/lib.rs @@ -61,8 +61,60 @@ mod text; #[doc(inline)] pub use text::{TextDecoder, TextEncoder}; +pub mod url; + +/// Options used when registering all built-in objects and functions of the `WebAPI` runtime. +#[derive(Debug)] +pub struct RegisterOptions { + console_logger: L, +} + +impl Default for RegisterOptions { + fn default() -> Self { + Self { + console_logger: console::DefaultLogger, + } + } +} + +impl RegisterOptions { + /// Create a new `RegisterOptions` with the default options. + #[must_use] + pub fn new() -> Self { + Self::default() + } +} + +impl RegisterOptions { + /// Set the logger for the console object. + pub fn with_console_logger(self, logger: L2) -> RegisterOptions { + RegisterOptions:: { + console_logger: logger, + } + } +} + +/// Register all the built-in objects and functions of the `WebAPI` runtime. +/// +/// # Errors +/// This will error is any of the built-in objects or functions cannot be registered. +pub fn register( + ctx: &mut boa_engine::Context, + options: RegisterOptions, +) -> boa_engine::JsResult<()> { + Console::register_with_logger(ctx, options.console_logger)?; + TextDecoder::register(ctx)?; + TextEncoder::register(ctx)?; + + #[cfg(feature = "url")] + url::Url::register(ctx)?; + + Ok(()) +} + #[cfg(test)] pub(crate) mod test { + use crate::{register, RegisterOptions}; use boa_engine::{builtins, Context, JsResult, JsValue, Source}; use std::borrow::Cow; @@ -126,6 +178,7 @@ pub(crate) mod test { #[track_caller] pub(crate) fn run_test_actions(actions: impl IntoIterator) { let context = &mut Context::default(); + register(context, RegisterOptions::default()).expect("failed to register WebAPI objects"); run_test_actions_with(actions, context); } diff --git a/core/runtime/src/url.rs b/core/runtime/src/url.rs new file mode 100644 index 00000000000..f634ef96f88 --- /dev/null +++ b/core/runtime/src/url.rs @@ -0,0 +1,236 @@ +//! Boa's implementation of JavaScript's `URL` Web API class. +//! +//! The `URL` class can be instantiated from any global object. +//! This relies on the `url` feature. +//! +//! More information: +//! - [MDN documentation][mdn] +//! - [WHATWG `URL` specification][spec] +//! +//! [spec]: https://url.spec.whatwg.org/ +//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/URL +#![cfg(feature = "url")] + +#[cfg(test)] +mod tests; + +use boa_engine::value::Convert; +use boa_engine::{ + js_error, js_string, Context, Finalize, JsData, JsResult, JsString, JsValue, Trace, +}; +use boa_interop::{js_class, IntoJsFunctionCopied, JsClass}; +use std::fmt::Display; + +/// The `URL` class represents a (properly parsed) Uniform Resource Locator. +#[derive(Debug, Clone, JsData, Trace, Finalize)] +#[boa_gc(unsafe_no_drop)] +pub struct Url(#[unsafe_ignore_trace] url::Url); + +impl Url { + /// Register the `URL` class into the realm. + /// + /// # Errors + /// This will error if the context or realm cannot register the class. + pub fn register(context: &mut Context) -> JsResult<()> { + context.register_global_class::()?; + Ok(()) + } + + /// Create a new `URL` object. Meant to be called from the JavaScript constructor. + /// + /// # Errors + /// Any errors that might occur during URL parsing. + fn js_new(Convert(ref url): Convert, base: &Option>) -> JsResult { + if let Some(Convert(base)) = base { + let base_url = url::Url::parse(base) + .map_err(|e| js_error!(TypeError: "Failed to parse base URL: {}", e))?; + if base_url.cannot_be_a_base() { + return Err(js_error!(TypeError: "Base URL {} cannot be a base", base)); + } + + let url = base_url + .join(url) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + Ok(Self(url)) + } else { + let url = url::Url::parse(url) + .map_err(|e| js_error!(TypeError: "Failed to parse URL: {}", e))?; + Ok(Self(url)) + } + } +} + +impl Display for Url { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +impl From for Url { + fn from(url: url::Url) -> Self { + Self(url) + } +} + +impl From for url::Url { + fn from(url: Url) -> url::Url { + url.0 + } +} + +js_class! { + class Url as "URL" { + property hash { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::hash(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + url::quirks::set_hash(&mut this.borrow_mut().0, &value.0); + } + } + + property hostname { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::hostname(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + let _ = url::quirks::set_hostname(&mut this.borrow_mut().0, &value.0); + } + } + + property host { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::host(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + let _ = url::quirks::set_host(&mut this.borrow_mut().0, &value.0); + } + } + + property href { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::href(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) -> JsResult<()> { + url::quirks::set_href(&mut this.borrow_mut().0, &value.0) + .map_err(|e| js_error!(TypeError: "Failed to set href: {}", e)) + } + } + + property origin { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::origin(&this.borrow().0)) + } + } + + property password { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::password(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + let _ = url::quirks::set_password(&mut this.borrow_mut().0, &value.0); + } + } + + property pathname { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::pathname(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + let () = url::quirks::set_pathname(&mut this.borrow_mut().0, &value.0); + } + } + + property port { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::port(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + let _ = url::quirks::set_port(&mut this.borrow_mut().0, &value.0.to_std_string_lossy()); + } + } + + property protocol { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::protocol(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + let _ = url::quirks::set_protocol(&mut this.borrow_mut().0, &value.0); + } + } + + property search { + fn get(this: JsClass) -> JsString { + JsString::from(url::quirks::search(&this.borrow().0)) + } + + fn set(this: JsClass, value: Convert) { + url::quirks::set_search(&mut this.borrow_mut().0, &value.0); + } + } + + property search_params as "searchParams" { + fn get() -> JsResult<()> { + Err(js_error!(Error: "URL.searchParams is not implemented")) + } + } + + property username { + fn get(this: JsClass) -> JsString { + JsString::from(this.borrow().0.username()) + } + + fn set(this: JsClass, value: Convert) { + let _ = this.borrow_mut().0.set_username(&value.0); + } + } + + constructor(url: Convert, base: Option>) { + Self::js_new(url, &base) + } + + init(class: &mut ClassBuilder) -> JsResult<()> { + let create_object_url = (|| -> JsResult<()> { + Err(js_error!(Error: "URL.createObjectURL is not implemented")) + }) + .into_js_function_copied(class.context()); + let can_parse = (|url: Convert, base: Option>| { + Url::js_new(url, &base).is_ok() + }) + .into_js_function_copied(class.context()); + let parse = (|url: Convert, base: Option>, context: &mut Context| { + Url::js_new(url, &base) + .map_or(Ok(JsValue::null()), |u| Url::from_data(u, context).map(JsValue::from)) + }) + .into_js_function_copied(class.context()); + let revoke_object_url = (|| -> JsResult<()> { + Err(js_error!(Error: "URL.revokeObjectURL is not implemented")) + }) + .into_js_function_copied(class.context()); + + class + .static_method(js_string!("createObjectURL"), 1, create_object_url) + .static_method(js_string!("canParse"), 2, can_parse) + .static_method(js_string!("parse"), 2, parse) + .static_method(js_string!("revokeObjectUrl"), 1, revoke_object_url); + + Ok(()) + } + + fn to_string as "toString"(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + + fn to_json as "toJSON"(this: JsClass) -> JsString { + JsString::from(format!("{}", this.borrow().0)) + } + } +} diff --git a/core/runtime/src/url/tests.rs b/core/runtime/src/url/tests.rs new file mode 100644 index 00000000000..685efc6df1b --- /dev/null +++ b/core/runtime/src/url/tests.rs @@ -0,0 +1,113 @@ +use crate::test::{run_test_actions, TestAction}; + +const TEST_HARNESS: &str = r#" +function assert(condition, message) { + if (!condition) { + if (!message) { + message = "Assertion failed"; + } + throw new Error(message); + } +} + +function assert_eq(a, b, message) { + if (a !== b) { + throw new Error(`${message} (${JSON.stringify(a)} !== ${JSON.stringify(b)})`); + } +} +"#; + +#[test] +fn url_basic() { + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + url = new URL("https://example.com:8080/path/to/resource?query#fragment"); + assert(url instanceof URL); + assert_eq(url.href, "https://example.com:8080/path/to/resource?query#fragment"); + assert_eq(url.protocol, "https:"); + assert_eq(url.host, "example.com:8080"); + assert_eq(url.hostname, "example.com"); + assert_eq(url.port, "8080"); + assert_eq(url.pathname, "/path/to/resource"); + assert_eq(url.search, "?query"); + assert_eq(url.hash, "#fragment"); + "##, + ), + ]); +} + +#[test] +fn url_base() { + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + url = new URL("https://example.com:8080/path/to/resource?query#fragment", "http://example.org/"); + assert_eq(url.href, "https://example.com:8080/path/to/resource?query#fragment"); + assert_eq(url.protocol, "https:"); + assert_eq(url.host, "example.com:8080"); + assert_eq(url.hostname, "example.com"); + assert_eq(url.port, "8080"); + assert_eq(url.pathname, "/path/to/resource"); + assert_eq(url.search, "?query"); + assert_eq(url.hash, "#fragment"); + "##, + ), + TestAction::run( + r##" + url = new URL("/path/to/resource?query#fragment", "http://example.org/"); + assert_eq(url.href, "http://example.org/path/to/resource?query#fragment"); + assert_eq(url.protocol, "http:"); + assert_eq(url.host, "example.org"); + assert_eq(url.hostname, "example.org"); + assert_eq(url.port, ""); + assert_eq(url.pathname, "/path/to/resource"); + assert_eq(url.search, "?query"); + assert_eq(url.hash, "#fragment"); + "##, + ), + ]); +} + +#[test] +fn url_setters() { + // These were double checked against Firefox. + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + url = new URL("https://example.com:8080/path/to/resource?query#fragment"); + url.protocol = "http:"; + url.host = "example.org:80"; // Since protocol is http, port is removed. + url.pathname = "/new/path"; + url.search = "?new-query"; + url.hash = "#new-fragment"; + assert_eq(url.href, "http://example.org/new/path?new-query#new-fragment"); + assert_eq(url.protocol, "http:"); + assert_eq(url.host, "example.org"); + assert_eq(url.hostname, "example.org"); + assert_eq(url.port, ""); + assert_eq(url.pathname, "/new/path"); + assert_eq(url.search, "?new-query"); + assert_eq(url.hash, "#new-fragment"); + "##, + ), + ]); +} + +#[test] +fn url_static_methods() { + run_test_actions([ + TestAction::run(TEST_HARNESS), + TestAction::run( + r##" + assert(URL.canParse("http://example.org/new/path?new-query#new-fragment")); + assert(!URL.canParse("http//:example.org/new/path?new-query#new-fragment")); + assert(!URL.canParse("http://example.org/new/path?new-query#new-fragment", "http:")); + assert(URL.canParse("/new/path?new-query#new-fragment", "http://example.org/")); + "##, + ), + ]); +} diff --git a/core/string/src/lib.rs b/core/string/src/lib.rs index ecacaa1d56a..26922832aea 100644 --- a/core/string/src/lib.rs +++ b/core/string/src/lib.rs @@ -454,6 +454,19 @@ impl JsString { self.to_string_escaped() } + /// Decodes a [`JsString`] into a [`String`], replacing invalid data with the + /// replacement character U+FFFD. + #[inline] + #[must_use] + pub fn to_std_string_lossy(&self) -> String { + self.code_points() + .map(|cp| match cp { + CodePoint::Unicode(c) => c, + CodePoint::UnpairedSurrogate(_) => '\u{FFFD}', + }) + .collect() + } + /// Decodes a [`JsString`] into a [`String`], returning /// /// # Errors From e22a703dfd7591ccfd143e1e7ade4c2d2ba55b55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:52:36 -0500 Subject: [PATCH 06/72] Bump the rust-dependencies group across 1 directory with 8 updates (#4021) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump the rust-dependencies group across 1 directory with 8 updates Bumps the rust-dependencies group with 8 updates in the / directory: | Package | From | To | | --- | --- | --- | | [clap](https://github.com/clap-rs/clap) | `4.5.19` | `4.5.20` | | [serde_json](https://github.com/serde-rs/json) | `1.0.128` | `1.0.132` | | [trybuild](https://github.com/dtolnay/trybuild) | `1.0.99` | `1.0.101` | | [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) | `0.2.93` | `0.2.95` | | [wasm-bindgen-test](https://github.com/rustwasm/wasm-bindgen) | `0.3.43` | `0.3.45` | | [syn](https://github.com/dtolnay/syn) | `2.0.79` | `2.0.82` | | [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.86` | `1.0.88` | | [bytemuck](https://github.com/Lokathor/bytemuck) | `1.18.0` | `1.19.0` | Updates `clap` from 4.5.19 to 4.5.20 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.19...clap_complete-v4.5.20) Updates `serde_json` from 1.0.128 to 1.0.132 - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/1.0.128...1.0.132) Updates `trybuild` from 1.0.99 to 1.0.101 - [Release notes](https://github.com/dtolnay/trybuild/releases) - [Commits](https://github.com/dtolnay/trybuild/compare/1.0.99...1.0.101) Updates `wasm-bindgen` from 0.2.93 to 0.2.95 - [Release notes](https://github.com/rustwasm/wasm-bindgen/releases) - [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustwasm/wasm-bindgen/compare/0.2.93...0.2.95) Updates `wasm-bindgen-test` from 0.3.43 to 0.3.45 - [Release notes](https://github.com/rustwasm/wasm-bindgen/releases) - [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustwasm/wasm-bindgen/commits) Updates `syn` from 2.0.79 to 2.0.82 - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.79...2.0.82) Updates `proc-macro2` from 1.0.86 to 1.0.88 - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.86...1.0.88) Updates `bytemuck` from 1.18.0 to 1.19.0 - [Changelog](https://github.com/Lokathor/bytemuck/blob/main/changelog.md) - [Commits](https://github.com/Lokathor/bytemuck/compare/v1.18.0...v1.19.0) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: trybuild dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: wasm-bindgen dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: wasm-bindgen-test dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: bytemuck dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] * Fix wasm dependencies --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: José Julián Espina --- Cargo.lock | 71 ++++++++++++++++++--------------- Cargo.toml | 16 ++++---- core/parser/src/lexer/number.rs | 17 ++++---- ffi/wasm/Cargo.toml | 2 +- ffi/wasm/tests/web.rs | 10 ++++- 5 files changed, 64 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12f26aaccd0..815a6a504bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,9 +608,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" +checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" dependencies = [ "bytemuck_derive", ] @@ -739,9 +739,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -749,9 +749,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -2077,9 +2077,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -2650,9 +2650,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -2993,9 +2993,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -3191,9 +3191,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.79" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -3226,6 +3226,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-triple" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" + [[package]] name = "temporal_rs" version = "0.0.3" @@ -3526,14 +3532,15 @@ dependencies = [ [[package]] name = "trybuild" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" +checksum = "8dcd332a5496c026f1e14b7f3d2b7bd98e509660c04239c58b0ba38a12daded4" dependencies = [ "glob", "serde", "serde_derive", "serde_json", + "target-triple", "termcolor", "toml 0.8.19", ] @@ -3688,9 +3695,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -3699,9 +3706,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", @@ -3714,9 +3721,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -3726,9 +3733,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3736,9 +3743,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", @@ -3749,15 +3756,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-bindgen-test" -version = "0.3.43" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" +checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" dependencies = [ "console_error_panic_hook", "js-sys", @@ -3770,9 +3777,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.43" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" +checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 008d2eb3a22..e7f522906ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ exclude = [ [workspace.package] edition = "2021" version = "0.19.0" -rust-version = "1.80.0" +rust-version = "1.82.0" authors = ["boa-dev"] repository = "https://github.com/boa-dev/boa" license = "Unlicense OR MIT" @@ -48,7 +48,7 @@ boa_string = { version = "~0.19.0", path = "core/string" } # Shared deps arbitrary = "1" bitflags = "2.5.0" -clap = "4.5.19" +clap = "4.5.20" colored = "2.1.0" fast-float = "0.2.0" hashbrown = { version = "0.14.5", default-features = false } @@ -63,7 +63,7 @@ pollster = "0.3.0" regex = "1.11.0" regress = { version = "0.10.1", features = ["utf16"] } rustc-hash = { version = "2.0.0", default-features = false } -serde_json = "1.0.128" +serde_json = "1.0.132" serde = "1.0.210" static_assertions = "1.1.0" textwrap = "0.16.0" @@ -73,24 +73,24 @@ tinystr = "0.7.5" log = "0.4.22" simple_logger = "5.0.0" cargo_metadata = "0.18.1" -trybuild = "1.0.99" +trybuild = "1.0.101" rayon = "1.10.0" toml = "0.8.19" color-eyre = "0.6.3" comfy-table = "7.1.1" serde_repr = "0.1.19" bus = "2.4.1" -wasm-bindgen = { version = "0.2.93", default-features = false } +wasm-bindgen = { version = "0.2.95", default-features = false } getrandom = { version = "0.2.15", default-features = false } console_error_panic_hook = "0.1.7" -wasm-bindgen-test = "0.3.43" +wasm-bindgen-test = "0.3.45" smol = "2.0.2" futures-util = "0.3.31" isahc = "1.7.2" rustyline = { version = "14.0.0", default-features = false } dhat = "0.3.3" quote = "1.0.37" -syn = { version = "2.0.79", default-features = false } +syn = { version = "2.0.82", default-features = false } proc-macro2 = "1.0" synstructure = "0.13" measureme = "11.0.1" @@ -105,7 +105,7 @@ dashmap = "5.5.3" num_enum = "0.7.3" itertools = { version = "0.13.0", default-features = false } portable-atomic = "1.9.0" -bytemuck = { version = "1.18.0", default-features = false } +bytemuck = { version = "1.19.0", default-features = false } arrayvec = "0.7.6" intrusive-collections = "0.9.7" cfg-if = "1.0.0" diff --git a/core/parser/src/lexer/number.rs b/core/parser/src/lexer/number.rs index 9fa7475ec5f..c944eb878b8 100644 --- a/core/parser/src/lexer/number.rs +++ b/core/parser/src/lexer/number.rs @@ -367,18 +367,15 @@ impl Tokenizer for NumberLiteral { // The non-digit character at this point must be an 'e' or 'E' to indicate an Exponent Part. // Another '.' or 'n' is not allowed. - match cursor.peek_char()? { - Some(0x0065 /*e */ | 0x0045 /* E */) => { - // Consume the ExponentIndicator. - cursor.next_char()?.expect("e or E token vanished"); + if let Some(0x0065 /*e */ | 0x0045 /* E */) = cursor.peek_char()? { + // Consume the ExponentIndicator. + cursor.next_char()?.expect("e or E token vanished"); - buf.push(b'E'); + buf.push(b'E'); - take_signed_integer(&mut buf, cursor, kind)?; - } - Some(_) | None => { - // Finished lexing. - } + take_signed_integer(&mut buf, cursor, kind)?; + } else { + // Finished lexing. } } } diff --git a/ffi/wasm/Cargo.toml b/ffi/wasm/Cargo.toml index ec2c2c23a05..d8f65750574 100644 --- a/ffi/wasm/Cargo.toml +++ b/ffi/wasm/Cargo.toml @@ -17,7 +17,7 @@ wasm-bindgen = { workspace = true, default-features = false } getrandom = { workspace = true, features = ["js"] } console_error_panic_hook.workspace = true -[dev-dependencies] +[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies] wasm-bindgen-test.workspace = true [features] diff --git a/ffi/wasm/tests/web.rs b/ffi/wasm/tests/web.rs index b04bfb90e4b..d3ea23b9f4d 100644 --- a/ffi/wasm/tests/web.rs +++ b/ffi/wasm/tests/web.rs @@ -1,4 +1,12 @@ -#![allow(unused_crate_dependencies)] +#![expect( + unused_crate_dependencies, + reason = "https://github.com/rust-lang/rust/issues/95513" +)] +#![cfg(all( + any(target_arch = "wasm32", target_arch = "wasm64"), + target_os = "unknown" +))] + use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); From acd1a8d9ab05b33062b8094816fb23ca70a54704 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Fri, 25 Oct 2024 07:52:56 -0700 Subject: [PATCH 07/72] Add a display_lossy() to write a JsString lossily (#4023) * Add a display_lossy() to write a JsString lossily * cargo fmt --- core/string/src/display.rs | 48 ++++++++++++++++++++++++++++++++++++++ core/string/src/lib.rs | 12 ++++++++-- core/string/src/str.rs | 8 +++++++ 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/core/string/src/display.rs b/core/string/src/display.rs index 9124af24e14..6873e406f72 100644 --- a/core/string/src/display.rs +++ b/core/string/src/display.rs @@ -34,6 +34,27 @@ impl<'a> From> for JsStrDisplayEscaped<'a> { } } +/// Display implementation for [`crate::JsString`] that escapes unicode characters. +#[derive(Debug)] +pub struct JsStrDisplayLossy<'a> { + inner: JsStr<'a>, +} + +impl fmt::Display for JsStrDisplayLossy<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // No need to optimize latin1. + self.inner + .code_points_lossy() + .try_for_each(|c| f.write_char(c)) + } +} + +impl<'a> From> for JsStrDisplayLossy<'a> { + fn from(inner: JsStr<'a>) -> Self { + Self { inner } + } +} + #[test] fn latin1() { // 0xE9 is `é` in ISO-8859-1 (see https://www.ascii-code.com/ISO-8859-1). @@ -41,4 +62,31 @@ fn latin1() { let rust_str = format!("{}", JsStrDisplayEscaped { inner: s }); assert_eq!(rust_str, "Hello é world!"); + + let rust_str = format!("{}", JsStrDisplayLossy { inner: s }); + assert_eq!(rust_str, "Hello é world!"); +} + +#[test] +fn emoji() { + // 0x1F600 is `😀` (see https://www.fileformat.info/info/unicode/char/1f600/index.htm). + let s = JsStr::utf16(&[0xD83D, 0xDE00]); + + let rust_str = format!("{}", JsStrDisplayEscaped { inner: s }); + assert_eq!(rust_str, "😀"); + + let rust_str = format!("{}", JsStrDisplayLossy { inner: s }); + assert_eq!(rust_str, "😀"); +} + +#[test] +fn unpaired_surrogates() { + // 0xD800 is an unpaired surrogate (see https://www.fileformat.info/info/unicode/char/d800/index.htm). + let s = JsStr::utf16(&[0xD800]); + + let rust_str = format!("{}", JsStrDisplayEscaped { inner: s }); + assert_eq!(rust_str, "\\uD800"); + + let rust_str = format!("{}", JsStrDisplayLossy { inner: s }); + assert_eq!(rust_str, "�"); } diff --git a/core/string/src/lib.rs b/core/string/src/lib.rs index 26922832aea..c4171c7f3df 100644 --- a/core/string/src/lib.rs +++ b/core/string/src/lib.rs @@ -26,7 +26,7 @@ mod tagged; mod tests; use self::{iter::Windows, str::JsSliceIndex}; -use crate::display::JsStrDisplayEscaped; +use crate::display::{JsStrDisplayEscaped, JsStrDisplayLossy}; use crate::tagged::{Tagged, UnwrappedTagged}; #[doc(inline)] pub use crate::{ @@ -960,7 +960,7 @@ impl JsString { } } - /// Gets a displayable escaped string. This may be faster and has less + /// Gets a displayable escaped string. This may be faster and has fewer /// allocations than `format!("{}", str.to_string_escaped())` when /// displaying. #[inline] @@ -968,6 +968,14 @@ impl JsString { pub fn display_escaped(&self) -> JsStrDisplayEscaped<'_> { JsStrDisplayEscaped::from(self.as_str()) } + + /// Gets a displayable lossy string. This may be faster and has fewer + /// allocations than `format!("{}", str.to_string_lossy())` when displaying. + #[inline] + #[must_use] + pub fn display_lossy(&self) -> JsStrDisplayLossy<'_> { + JsStrDisplayLossy::from(self.as_str()) + } } impl Clone for JsString { diff --git a/core/string/src/str.rs b/core/string/src/str.rs index ffbee00034c..c0c49f44f27 100644 --- a/core/string/src/str.rs +++ b/core/string/src/str.rs @@ -235,6 +235,14 @@ impl<'a> JsStr<'a> { m >= n && needle == self.get(m - n..).expect("already checked size") } + /// Gets an iterator of all the Unicode codepoints of a [`JsStr`], replacing + /// unpaired surrogates with the replacement character. This is faster than + /// using [`Self::code_points`]. + #[inline] + pub(crate) fn code_points_lossy(self) -> impl Iterator + 'a { + char::decode_utf16(self.iter()).map(|res| res.unwrap_or('\u{FFFD}')) + } + /// Gets an iterator of all the Unicode codepoints of a [`JsStr`]. /// This is not optimized for Latin1 strings. #[inline] From 905e4c6f90d66c116ee62259a6d6bc0ab39bc39e Mon Sep 17 00:00:00 2001 From: Nikita-str <42584606+Nikita-str@users.noreply.github.com> Date: Sat, 26 Oct 2024 18:48:49 +0300 Subject: [PATCH 08/72] `TryIntoJs` trait and derive macro for it (#3999) * #3874: `TryIntoJs` impl for primitive types * #3874: `#[derive(TryIntoJs)]` is it ok to use `create_data_property_or_throw`? in other words, am I create an object correctly? * #3874: some (but not enough) tests * #3874: fix `TryintoJs` derive bug in multi attr case * #3874: `TryIntoJs` derive macro example * fix paths in derive macro * make lint happy --- core/engine/src/value/conversions/mod.rs | 1 + .../src/value/conversions/try_into_js.rs | 289 ++++++++++++++++++ core/engine/src/value/mod.rs | 5 +- core/macros/src/lib.rs | 107 +++++++ examples/src/bin/try_into_js_derive.rs | 96 ++++++ 5 files changed, 496 insertions(+), 2 deletions(-) create mode 100644 core/engine/src/value/conversions/try_into_js.rs create mode 100644 examples/src/bin/try_into_js_derive.rs diff --git a/core/engine/src/value/conversions/mod.rs b/core/engine/src/value/conversions/mod.rs index b247db10f93..3fa3841212e 100644 --- a/core/engine/src/value/conversions/mod.rs +++ b/core/engine/src/value/conversions/mod.rs @@ -7,6 +7,7 @@ use super::{JsBigInt, JsObject, JsString, JsSymbol, JsValue, Profiler}; mod either; mod serde_json; pub(super) mod try_from_js; +pub(super) mod try_into_js; pub(super) mod convert; diff --git a/core/engine/src/value/conversions/try_into_js.rs b/core/engine/src/value/conversions/try_into_js.rs new file mode 100644 index 00000000000..ce24903c5dc --- /dev/null +++ b/core/engine/src/value/conversions/try_into_js.rs @@ -0,0 +1,289 @@ +use crate::{Context, JsNativeError, JsResult, JsValue}; +use boa_string::JsString; + +/// This trait adds a conversions from a Rust Type into [`JsValue`]. +pub trait TryIntoJs: Sized { + /// This function tries to convert a `Self` into [`JsValue`]. + fn try_into_js(&self, context: &mut Context) -> JsResult; +} + +impl TryIntoJs for bool { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + JsResult::Ok(JsValue::Boolean(*self)) + } +} + +impl TryIntoJs for &str { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + JsResult::Ok(JsValue::String(JsString::from(*self))) + } +} +impl TryIntoJs for String { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + JsResult::Ok(JsValue::String(JsString::from(self.as_str()))) + } +} + +macro_rules! impl_try_into_js_by_from { + ($t:ty) => { + impl TryIntoJs for $t { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + JsResult::Ok(JsValue::from(self.clone())) + } + } + }; + [$($ts:ty),+] => { + $(impl_try_into_js_by_from!($ts);)+ + } +} +impl_try_into_js_by_from![i8, u8, i16, u16, i32, u32, f32, f64]; +impl_try_into_js_by_from![ + JsValue, + JsString, + crate::JsBigInt, + crate::JsObject, + crate::JsSymbol, + crate::object::JsArray, + crate::object::JsArrayBuffer, + crate::object::JsDataView, + crate::object::JsDate, + crate::object::JsFunction, + crate::object::JsGenerator, + crate::object::JsMapIterator, + crate::object::JsMap, + crate::object::JsSetIterator, + crate::object::JsSet, + crate::object::JsSharedArrayBuffer, + crate::object::JsInt8Array, + crate::object::JsInt16Array, + crate::object::JsInt32Array, + crate::object::JsUint8Array, + crate::object::JsUint16Array, + crate::object::JsUint32Array, + crate::object::JsFloat32Array, + crate::object::JsFloat64Array +]; + +const MAX_SAFE_INTEGER_I64: i64 = (1 << 53) - 1; +const MIN_SAFE_INTEGER_I64: i64 = -MAX_SAFE_INTEGER_I64; + +fn err_outside_safe_range() -> crate::JsError { + JsNativeError::typ() + .with_message("cannot convert value into JsValue: the value is outside the safe range") + .into() +} +fn convert_safe_i64(value: i64) -> JsValue { + i32::try_from(value).map_or(JsValue::Rational(value as f64), JsValue::Integer) +} + +impl TryIntoJs for i64 { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + let value = *self; + #[allow(clippy::manual_range_contains)] + if value < MIN_SAFE_INTEGER_I64 || MAX_SAFE_INTEGER_I64 < value { + JsResult::Err(err_outside_safe_range()) + } else { + JsResult::Ok(convert_safe_i64(value)) + } + } +} +impl TryIntoJs for u64 { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + let value = *self; + if (MAX_SAFE_INTEGER_I64 as u64) < value { + JsResult::Err(err_outside_safe_range()) + } else { + JsResult::Ok(convert_safe_i64(value as i64)) + } + } +} +impl TryIntoJs for i128 { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + let value = *self; + if value < i128::from(MIN_SAFE_INTEGER_I64) || i128::from(MAX_SAFE_INTEGER_I64) < value { + JsResult::Err(err_outside_safe_range()) + } else { + JsResult::Ok(convert_safe_i64(value as i64)) + } + } +} +impl TryIntoJs for u128 { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + let value = *self; + if (MAX_SAFE_INTEGER_I64 as u128) < value { + JsResult::Err(err_outside_safe_range()) + } else { + JsResult::Ok(convert_safe_i64(value as i64)) + } + } +} + +impl TryIntoJs for Option +where + T: TryIntoJs, +{ + fn try_into_js(&self, context: &mut Context) -> JsResult { + match self { + Some(x) => x.try_into_js(context), + None => JsResult::Ok(JsValue::Null), + } + } +} + +impl TryIntoJs for Vec +where + T: TryIntoJs, +{ + fn try_into_js(&self, context: &mut Context) -> JsResult { + let arr = crate::object::JsArray::new(context); + for value in self { + let value = value.try_into_js(context)?; + arr.push(value, context)?; + } + JsResult::Ok(arr.into()) + } +} + +macro_rules! impl_try_into_js_for_tuples { + ($($names:ident : $ts:ident),+) => { + impl<$($ts: TryIntoJs,)+> TryIntoJs for ($($ts,)+) { + fn try_into_js(&self, context: &mut Context) -> JsResult { + let ($($names,)+) = self; + let arr = crate::object::JsArray::new(context); + $(arr.push($names.try_into_js(context)?, context)?;)+ + JsResult::Ok(arr.into()) + } + } + }; +} + +impl_try_into_js_for_tuples!(a: A); +impl_try_into_js_for_tuples!(a: A, b: B); +impl_try_into_js_for_tuples!(a: A, b: B, c: C); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J); +impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K); + +impl TryIntoJs for () { + fn try_into_js(&self, _context: &mut Context) -> JsResult { + JsResult::Ok(JsValue::Null) + } +} + +impl TryIntoJs for std::collections::HashSet +where + T: TryIntoJs, +{ + fn try_into_js(&self, context: &mut Context) -> JsResult { + let set = crate::object::JsSet::new(context); + for value in self { + let value = value.try_into_js(context)?; + set.add(value, context)?; + } + JsResult::Ok(set.into()) + } +} + +impl TryIntoJs for std::collections::HashMap +where + K: TryIntoJs, + V: TryIntoJs, +{ + fn try_into_js(&self, context: &mut Context) -> JsResult { + let map = crate::object::JsMap::new(context); + for (key, value) in self { + let key = key.try_into_js(context)?; + let value = value.try_into_js(context)?; + map.set(key, value, context)?; + } + JsResult::Ok(map.into()) + } +} + +#[cfg(test)] +mod try_into_js_tests { + use crate::value::{TryFromJs, TryIntoJs}; + use crate::{Context, JsResult}; + + #[test] + fn big_int_err() { + fn assert(int: &T, context: &mut Context) { + let expect_err = int.try_into_js(context); + assert!(expect_err.is_err()); + } + + let mut context = Context::default(); + let context = &mut context; + + let int = (1 << 55) + 17i64; + assert(&int, context); + + let int = (1 << 55) + 17u64; + assert(&int, context); + + let int = (1 << 55) + 17u128; + assert(&int, context); + + let int = (1 << 55) + 17i128; + assert(&int, context); + } + + #[test] + fn int_tuple() -> JsResult<()> { + let mut context = Context::default(); + let context = &mut context; + + let tuple_initial = ( + -42i8, + 42u8, + 1764i16, + 7641u16, + -((1 << 27) + 13), + (1 << 27) + 72u32, + (1 << 49) + 1793i64, + (1 << 49) + 1793u64, + -((1 << 49) + 7193i128), + (1 << 49) + 9173u128, + ); + + // it will rewrite without reading, so it's just for auto type resolving. + #[allow(unused_assignments)] + let mut tuple_after_transform = tuple_initial; + + let js_value = tuple_initial.try_into_js(context)?; + tuple_after_transform = TryFromJs::try_from_js(&js_value, context)?; + + assert_eq!(tuple_initial, tuple_after_transform); + Ok(()) + } + + #[test] + fn string() -> JsResult<()> { + let mut context = Context::default(); + let context = &mut context; + + let s_init = "String".to_string(); + let js_value = s_init.try_into_js(context)?; + let s: String = TryFromJs::try_from_js(&js_value, context)?; + assert_eq!(s_init, s); + Ok(()) + } + + #[test] + fn vec() -> JsResult<()> { + let mut context = Context::default(); + let context = &mut context; + + let vec_init = vec![(-4i64, 2u64), (15, 15), (32, 23)]; + let js_value = vec_init.try_into_js(context)?; + println!("JsValue: {}", js_value.display()); + let vec: Vec<(i64, u64)> = TryFromJs::try_from_js(&js_value, context)?; + assert_eq!(vec_init, vec); + Ok(()) + } +} diff --git a/core/engine/src/value/mod.rs b/core/engine/src/value/mod.rs index 34e8e273778..f98c12607cf 100644 --- a/core/engine/src/value/mod.rs +++ b/core/engine/src/value/mod.rs @@ -17,6 +17,7 @@ use once_cell::sync::Lazy; use boa_gc::{custom_trace, Finalize, Trace}; #[doc(inline)] pub use boa_macros::TryFromJs; +pub use boa_macros::TryIntoJs; use boa_profiler::Profiler; #[doc(inline)] pub use conversions::convert::Convert; @@ -24,8 +25,8 @@ pub use conversions::convert::Convert; pub(crate) use self::conversions::IntoOrUndefined; #[doc(inline)] pub use self::{ - conversions::try_from_js::TryFromJs, display::ValueDisplay, integer::IntegerOrInfinity, - operations::*, r#type::Type, + conversions::try_from_js::TryFromJs, conversions::try_into_js::TryIntoJs, + display::ValueDisplay, integer::IntegerOrInfinity, operations::*, r#type::Type, }; use crate::builtins::RegExp; use crate::object::{JsFunction, JsPromise, JsRegExp}; diff --git a/core/macros/src/lib.rs b/core/macros/src/lib.rs index 0807d9a0a86..a5bb12afefd 100644 --- a/core/macros/src/lib.rs +++ b/core/macros/src/lib.rs @@ -497,3 +497,110 @@ fn to_compile_errors(errors: Vec) -> proc_macro2::TokenStream { let compile_errors = errors.iter().map(syn::Error::to_compile_error); quote!(#(#compile_errors)*) } + +/// Derives the `TryIntoJs` trait, with the `#[boa()]` attribute. +/// +/// # Panics +/// +/// It will panic if the user tries to derive the `TryIntoJs` trait in an `enum` or a tuple struct. +#[proc_macro_derive(TryIntoJs, attributes(boa))] +pub fn derive_try_into_js(input: TokenStream) -> TokenStream { + // Parse the input tokens into a syntax tree + let input = parse_macro_input!(input as DeriveInput); + + let Data::Struct(data) = input.data else { + panic!("you can only derive TryFromJs for structs"); + }; + // TODO: Enums ? + + let Fields::Named(fields) = data.fields else { + panic!("you can only derive TryFromJs for named-field structs") + }; + + let props = generate_obj_properties(fields) + .map_err(|err| vec![err]) + .unwrap_or_else(to_compile_errors); + + let type_name = input.ident; + + // Build the output, possibly using quasi-quotation + let expanded = quote! { + impl ::boa_engine::value::TryIntoJs for #type_name { + fn try_into_js(&self, context: &mut boa_engine::Context) -> boa_engine::JsResult { + let obj = boa_engine::JsObject::default(); + #props + boa_engine::JsResult::Ok(obj.into()) + } + } + }; + + // Hand the output tokens back to the compiler + expanded.into() +} + +/// Generates property creation for object. +fn generate_obj_properties(fields: FieldsNamed) -> Result { + use syn::spanned::Spanned; + + let mut prop_ctors = Vec::with_capacity(fields.named.len()); + + for field in fields.named { + let span = field.span(); + let name = field.ident.ok_or_else(|| { + syn::Error::new( + span, + "you can only derive `TryIntoJs` for named-field structs", + ) + })?; + + let mut into_js_with = None; + let mut prop_key = format!("{name}"); + let mut skip = false; + + for attr in field + .attrs + .into_iter() + .filter(|attr| attr.path().is_ident("boa")) + { + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("into_js_with") { + let value = meta.value()?; + into_js_with = Some(value.parse::()?); + Ok(()) + } else if meta.path.is_ident("rename") { + let value = meta.value()?; + prop_key = value.parse::()?.value(); + Ok(()) + } else if meta.path.is_ident("skip") & meta.input.is_empty() { + skip = true; + Ok(()) + } else { + Err(meta.error( + "invalid syntax in the `#[boa()]` attribute. \ + Note that this attribute only accepts the following syntax: \ + \n* `#[boa(into_js_with = \"fully::qualified::path\")]`\ + \n* `#[boa(rename = \"jsPropertyName\")]` \ + \n* `#[boa(skip)]` \ + ", + )) + } + })?; + } + + if skip { + continue; + } + + let value = if let Some(into_js_with) = into_js_with { + let into_js_with = Ident::new(&into_js_with.value(), into_js_with.span()); + quote! { #into_js_with(&self.#name, context)? } + } else { + quote! { boa_engine::value::TryIntoJs::try_into_js(&self.#name, context)? } + }; + prop_ctors.push(quote! { + obj.create_data_property_or_throw(boa_engine::js_str!(#prop_key), #value, context)?; + }); + } + + Ok(quote! { #(#prop_ctors)* }) +} diff --git a/examples/src/bin/try_into_js_derive.rs b/examples/src/bin/try_into_js_derive.rs new file mode 100644 index 00000000000..55de96e87a3 --- /dev/null +++ b/examples/src/bin/try_into_js_derive.rs @@ -0,0 +1,96 @@ +use boa_engine::{ + js_string, + value::{TryFromJs, TryIntoJs}, + Context, JsResult, JsValue, Source, +}; + +#[derive(TryIntoJs)] +struct Test { + x: i32, + #[boa(rename = "y")] + y_point: i32, + #[allow(unused)] + #[boa(skip)] + tuple: (i32, u8, String), + #[boa(rename = "isReadable")] + #[boa(into_js_with = "readable_into_js")] + is_readable: i8, +} + +#[derive(TryFromJs, Debug, PartialEq, Eq)] +struct ResultVerifier { + x: i32, + y: i32, + #[boa(rename = "isReadable")] + is_readable: bool, +} + +fn main() -> JsResult<()> { + let js_code = r#" + function pointShift(pointA, pointB) { + if (pointA.isReadable === true && pointB.isReadable === true) { + return { + x: pointA.x + pointB.x, + y: pointA.y + pointB.y, + isReadable: true, + } + } + return undefined + } + "#; + + let mut context = Context::default(); + let context = &mut context; + + context.eval(Source::from_bytes(js_code))?; + + let point_shift = context + .global_object() + .get(js_string!("pointShift"), context)?; + let point_shift = point_shift.as_callable().unwrap(); + + let a = Test { + x: 10, + y_point: 20, + tuple: (30, 40, "no matter".into()), + is_readable: 1, + }; + let b = Test { + x: 2, + y_point: 1, + tuple: (30, 40, "no matter".into()), + is_readable: 2, + }; + let c = Test { + x: 2, + y_point: 1, + tuple: (30, 40, "no matter".into()), + is_readable: 0, + }; + + let result = point_shift.call( + &JsValue::Undefined, + &[a.try_into_js(context)?, b.try_into_js(context)?], + context, + )?; + let verifier = ResultVerifier::try_from_js(&result, context)?; + let expect = ResultVerifier { + x: 10 + 2, + y: 20 + 1, + is_readable: true, + }; + assert_eq!(verifier, expect); + + let result = point_shift.call( + &JsValue::Undefined, + &[a.try_into_js(context)?, c.try_into_js(context)?], + context, + )?; + assert!(result.is_undefined()); + + Ok(()) +} + +fn readable_into_js(value: &i8, _context: &mut Context) -> JsResult { + Ok(JsValue::Boolean(*value != 0)) +} From 23e8ba29be18e6a6a04e2a52f5e55e5568f223e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 20:09:44 -0500 Subject: [PATCH 09/72] Bump the rust-dependencies group with 5 updates (#4025) Bumps the rust-dependencies group with 5 updates: | Package | From | To | | --- | --- | --- | | [regex](https://github.com/rust-lang/regex) | `1.11.0` | `1.11.1` | | [serde](https://github.com/serde-rs/serde) | `1.0.210` | `1.0.213` | | [syn](https://github.com/dtolnay/syn) | `2.0.82` | `2.0.85` | | [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.88` | `1.0.89` | | [thiserror](https://github.com/dtolnay/thiserror) | `1.0.64` | `1.0.65` | Updates `regex` from 1.11.0 to 1.11.1 - [Release notes](https://github.com/rust-lang/regex/releases) - [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/regex/compare/1.11.0...1.11.1) Updates `serde` from 1.0.210 to 1.0.213 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.210...v1.0.213) Updates `syn` from 2.0.82 to 2.0.85 - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.82...2.0.85) Updates `proc-macro2` from 1.0.88 to 1.0.89 - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.88...1.0.89) Updates `thiserror` from 1.0.64 to 1.0.65 - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.64...1.0.65) --- updated-dependencies: - dependency-name: regex dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 28 ++++++++++++++-------------- Cargo.toml | 8 ++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 815a6a504bc..8a66269eaa1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2650,9 +2650,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -2733,9 +2733,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -2963,9 +2963,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" dependencies = [ "serde_derive", ] @@ -2982,9 +2982,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" dependencies = [ "proc-macro2", "quote", @@ -3191,9 +3191,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.82" +version = "2.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" dependencies = [ "proc-macro2", "quote", @@ -3307,18 +3307,18 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index e7f522906ce..0a425012947 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,11 +60,11 @@ num-traits = "0.2.19" once_cell = { version = "1.20.2", default-features = false } phf = { version = "0.11.2", default-features = false } pollster = "0.3.0" -regex = "1.11.0" +regex = "1.11.1" regress = { version = "0.10.1", features = ["utf16"] } rustc-hash = { version = "2.0.0", default-features = false } serde_json = "1.0.132" -serde = "1.0.210" +serde = "1.0.213" static_assertions = "1.1.0" textwrap = "0.16.0" thin-vec = "0.2.13" @@ -90,7 +90,7 @@ isahc = "1.7.2" rustyline = { version = "14.0.0", default-features = false } dhat = "0.3.3" quote = "1.0.37" -syn = { version = "2.0.82", default-features = false } +syn = { version = "2.0.85", default-features = false } proc-macro2 = "1.0" synstructure = "0.13" measureme = "11.0.1" @@ -100,7 +100,7 @@ rand = "0.8.5" num-integer = "0.1.46" ryu-js = "1.0.1" tap = "1.0.1" -thiserror = "1.0.64" +thiserror = "1.0.65" dashmap = "5.5.3" num_enum = "0.7.3" itertools = { version = "0.13.0", default-features = false } From d3dbb4ad02d395457843317a7dc67e0dd0195178 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Sat, 2 Nov 2024 08:49:22 -0700 Subject: [PATCH 10/72] console.debug() should use a debug Logger method (#4019) --- core/runtime/src/console/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/runtime/src/console/mod.rs b/core/runtime/src/console/mod.rs index c9fde6b79d2..d63bb1613a0 100644 --- a/core/runtime/src/console/mod.rs +++ b/core/runtime/src/console/mod.rs @@ -28,6 +28,14 @@ use std::{cell::RefCell, collections::hash_map::Entry, io::Write, rc::Rc, time:: /// A trait that can be used to forward console logs to an implementation. pub trait Logger: Trace + Sized { + /// Log a debug message (`console.debug`). By default, passes the message to `log`. + /// + /// # Errors + /// Returning an error will throw an exception in JavaScript. + fn debug(&self, msg: String, state: &ConsoleState, context: &mut Context) -> JsResult<()> { + self.log(msg, state, context) + } + /// Log a log message (`console.log`). /// /// # Errors @@ -473,7 +481,7 @@ impl Console { logger: &impl Logger, context: &mut Context, ) -> JsResult { - logger.log(formatter(args, context)?, &console.state, context)?; + logger.debug(formatter(args, context)?, &console.state, context)?; Ok(JsValue::undefined()) } From d8ec97c85f0b9e805b99e08cd45d4c4c95510c56 Mon Sep 17 00:00:00 2001 From: Jason Williams <936006+jasonwilliams@users.noreply.github.com> Date: Sat, 2 Nov 2024 16:29:08 +0000 Subject: [PATCH 11/72] use with_capacity to reduce re-allocations fixes #3896 (#3961) * use with_capacity to reduce allocations * Update to use const generics over runtime param * add comment above with_capacity * - move OWN_PROPS - add profiling marks in more places * use const in trait instead --- core/engine/src/builtins/array/mod.rs | 3 +++ core/engine/src/builtins/array_buffer/mod.rs | 2 ++ .../src/builtins/array_buffer/shared.rs | 2 ++ .../engine/src/builtins/async_function/mod.rs | 2 ++ .../builtins/async_generator_function/mod.rs | 2 ++ core/engine/src/builtins/bigint/mod.rs | 2 ++ core/engine/src/builtins/boolean/mod.rs | 2 ++ core/engine/src/builtins/builder.rs | 12 +++++++---- core/engine/src/builtins/dataview/mod.rs | 2 ++ core/engine/src/builtins/date/mod.rs | 2 ++ core/engine/src/builtins/error/aggregate.rs | 2 ++ core/engine/src/builtins/error/eval.rs | 2 ++ core/engine/src/builtins/error/mod.rs | 2 ++ core/engine/src/builtins/error/range.rs | 2 ++ core/engine/src/builtins/error/reference.rs | 2 ++ core/engine/src/builtins/error/syntax.rs | 2 ++ core/engine/src/builtins/error/type.rs | 2 ++ core/engine/src/builtins/error/uri.rs | 2 ++ core/engine/src/builtins/function/mod.rs | 2 ++ .../src/builtins/generator_function/mod.rs | 2 ++ core/engine/src/builtins/intl/collator/mod.rs | 2 ++ .../src/builtins/intl/date_time_format.rs | 2 ++ .../src/builtins/intl/list_format/mod.rs | 2 ++ core/engine/src/builtins/intl/locale/mod.rs | 2 ++ .../src/builtins/intl/number_format/mod.rs | 2 ++ .../src/builtins/intl/plural_rules/mod.rs | 2 ++ .../engine/src/builtins/intl/segmenter/mod.rs | 2 ++ core/engine/src/builtins/map/mod.rs | 2 ++ core/engine/src/builtins/mod.rs | 7 +++++++ core/engine/src/builtins/number/mod.rs | 2 ++ core/engine/src/builtins/object/mod.rs | 2 ++ core/engine/src/builtins/promise/mod.rs | 2 ++ core/engine/src/builtins/proxy/mod.rs | 2 ++ core/engine/src/builtins/regexp/mod.rs | 2 ++ core/engine/src/builtins/set/mod.rs | 2 ++ core/engine/src/builtins/string/mod.rs | 2 ++ core/engine/src/builtins/symbol/mod.rs | 2 ++ .../src/builtins/temporal/duration/mod.rs | 2 ++ .../src/builtins/temporal/instant/mod.rs | 2 ++ .../src/builtins/temporal/plain_date/mod.rs | 2 ++ .../builtins/temporal/plain_date_time/mod.rs | 2 ++ .../builtins/temporal/plain_month_day/mod.rs | 2 ++ .../src/builtins/temporal/plain_time/mod.rs | 2 ++ .../builtins/temporal/plain_year_month/mod.rs | 2 ++ .../builtins/temporal/zoned_date_time/mod.rs | 2 ++ .../src/builtins/typed_array/builtin.rs | 2 ++ core/engine/src/builtins/typed_array/mod.rs | 2 ++ core/engine/src/builtins/weak/weak_ref.rs | 2 ++ core/engine/src/builtins/weak_map/mod.rs | 2 ++ core/engine/src/builtins/weak_set/mod.rs | 2 ++ core/engine/src/context/icu.rs | 3 +++ core/engine/src/context/mod.rs | 1 + core/engine/src/module/loader.rs | 2 ++ .../engine/src/object/shape/property_table.rs | 21 +++++++++++++++---- .../src/object/shape/shared_shape/mod.rs | 3 ++- core/engine/src/vm/mod.rs | 1 + 56 files changed, 138 insertions(+), 9 deletions(-) diff --git a/core/engine/src/builtins/array/mod.rs b/core/engine/src/builtins/array/mod.rs index 947f76d0ca9..4eda932d08e 100644 --- a/core/engine/src/builtins/array/mod.rs +++ b/core/engine/src/builtins/array/mod.rs @@ -190,6 +190,9 @@ impl BuiltInObject for Array { } impl BuiltInConstructor for Array { + const P: usize = 41; + const SP: usize = 5; + const LENGTH: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = diff --git a/core/engine/src/builtins/array_buffer/mod.rs b/core/engine/src/builtins/array_buffer/mod.rs index d5ea40ab554..7c2e3197022 100644 --- a/core/engine/src/builtins/array_buffer/mod.rs +++ b/core/engine/src/builtins/array_buffer/mod.rs @@ -374,6 +374,8 @@ impl BuiltInObject for ArrayBuffer { } impl BuiltInConstructor for ArrayBuffer { + const P: usize = 9; + const SP: usize = 2; const LENGTH: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = diff --git a/core/engine/src/builtins/array_buffer/shared.rs b/core/engine/src/builtins/array_buffer/shared.rs index a9be40ce3d8..d19eec5ed55 100644 --- a/core/engine/src/builtins/array_buffer/shared.rs +++ b/core/engine/src/builtins/array_buffer/shared.rs @@ -155,6 +155,8 @@ impl BuiltInObject for SharedArrayBuffer { impl BuiltInConstructor for SharedArrayBuffer { const LENGTH: usize = 1; + const P: usize = 6; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::shared_array_buffer; diff --git a/core/engine/src/builtins/async_function/mod.rs b/core/engine/src/builtins/async_function/mod.rs index f8db6134e9a..2ff782af849 100644 --- a/core/engine/src/builtins/async_function/mod.rs +++ b/core/engine/src/builtins/async_function/mod.rs @@ -52,6 +52,8 @@ impl BuiltInObject for AsyncFunction { impl BuiltInConstructor for AsyncFunction { const LENGTH: usize = 1; + const P: usize = 1; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::async_function; diff --git a/core/engine/src/builtins/async_generator_function/mod.rs b/core/engine/src/builtins/async_generator_function/mod.rs index c0ca21b09ec..01bb0539de5 100644 --- a/core/engine/src/builtins/async_generator_function/mod.rs +++ b/core/engine/src/builtins/async_generator_function/mod.rs @@ -57,6 +57,8 @@ impl BuiltInObject for AsyncGeneratorFunction { impl BuiltInConstructor for AsyncGeneratorFunction { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::async_generator_function; diff --git a/core/engine/src/builtins/bigint/mod.rs b/core/engine/src/builtins/bigint/mod.rs index 947183afa54..65caaa84cfd 100644 --- a/core/engine/src/builtins/bigint/mod.rs +++ b/core/engine/src/builtins/bigint/mod.rs @@ -65,6 +65,8 @@ impl BuiltInObject for BigInt { impl BuiltInConstructor for BigInt { const LENGTH: usize = 1; + const P: usize = 3; + const SP: usize = 2; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::bigint; diff --git a/core/engine/src/builtins/boolean/mod.rs b/core/engine/src/builtins/boolean/mod.rs index b33525a0238..bd0766a918b 100644 --- a/core/engine/src/builtins/boolean/mod.rs +++ b/core/engine/src/builtins/boolean/mod.rs @@ -51,6 +51,8 @@ impl BuiltInObject for Boolean { impl BuiltInConstructor for Boolean { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::boolean; diff --git a/core/engine/src/builtins/builder.rs b/core/engine/src/builtins/builder.rs index 459a5104d9a..5411a1888df 100644 --- a/core/engine/src/builtins/builder.rs +++ b/core/engine/src/builtins/builder.rs @@ -135,6 +135,9 @@ impl ApplyToObject for OrdinaryObject { fn apply_to(self, _: &JsObject) {} } +// The number of properties that are always present in a standard constructor. See build method +const OWN_PROPS: usize = 3; + /// Builder for creating built-in objects, like `Array`. /// /// The marker `ObjectType` restricts the methods that can be called depending on the @@ -528,6 +531,7 @@ impl<'ctx> BuiltInBuilder<'ctx, OrdinaryObject> { } impl<'ctx> BuiltInBuilder<'ctx, Callable> { + /// Create a new builder for a constructor function setting the properties ahead of time for optimizations (less reallocations) pub(crate) fn from_standard_constructor( realm: &'ctx Realm, ) -> BuiltInConstructorWithPrototype<'ctx> { @@ -537,11 +541,11 @@ impl<'ctx> BuiltInBuilder<'ctx, Callable> { function: SC::constructor, name: js_string!(SC::NAME), length: SC::LENGTH, - object_property_table: PropertyTableInner::default(), - object_storage: Vec::default(), + object_property_table: PropertyTableInner::with_capacity(SC::SP + OWN_PROPS), + object_storage: Vec::with_capacity(SC::SP + OWN_PROPS), object: constructor.constructor(), - prototype_property_table: PropertyTableInner::default(), - prototype_storage: Vec::default(), + prototype_property_table: PropertyTableInner::with_capacity(SC::P), + prototype_storage: Vec::with_capacity(SC::P), prototype: constructor.prototype(), __proto__: Some(realm.intrinsics().constructors().function().prototype()), inherits: Some(realm.intrinsics().constructors().object().prototype()), diff --git a/core/engine/src/builtins/dataview/mod.rs b/core/engine/src/builtins/dataview/mod.rs index a8a4eaf283a..1c36146715f 100644 --- a/core/engine/src/builtins/dataview/mod.rs +++ b/core/engine/src/builtins/dataview/mod.rs @@ -167,6 +167,8 @@ impl BuiltInObject for DataView { impl BuiltInConstructor for DataView { const LENGTH: usize = 1; + const P: usize = 24; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::data_view; diff --git a/core/engine/src/builtins/date/mod.rs b/core/engine/src/builtins/date/mod.rs index 13f5b5c5772..9e255893e23 100644 --- a/core/engine/src/builtins/date/mod.rs +++ b/core/engine/src/builtins/date/mod.rs @@ -185,6 +185,8 @@ impl BuiltInObject for Date { impl BuiltInConstructor for Date { const LENGTH: usize = 7; + const P: usize = 47; + const SP: usize = 3; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::date; diff --git a/core/engine/src/builtins/error/aggregate.rs b/core/engine/src/builtins/error/aggregate.rs index 3dacfbcaab7..ddde1683c1b 100644 --- a/core/engine/src/builtins/error/aggregate.rs +++ b/core/engine/src/builtins/error/aggregate.rs @@ -52,6 +52,8 @@ impl BuiltInObject for AggregateError { impl BuiltInConstructor for AggregateError { const LENGTH: usize = 2; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::aggregate_error; diff --git a/core/engine/src/builtins/error/eval.rs b/core/engine/src/builtins/error/eval.rs index 88f6d21f0d1..360638cc7f7 100644 --- a/core/engine/src/builtins/error/eval.rs +++ b/core/engine/src/builtins/error/eval.rs @@ -54,6 +54,8 @@ impl BuiltInObject for EvalError { impl BuiltInConstructor for EvalError { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::eval_error; diff --git a/core/engine/src/builtins/error/mod.rs b/core/engine/src/builtins/error/mod.rs index 343080137bd..2e22e17904c 100644 --- a/core/engine/src/builtins/error/mod.rs +++ b/core/engine/src/builtins/error/mod.rs @@ -154,6 +154,8 @@ impl BuiltInObject for Error { impl BuiltInConstructor for Error { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::error; diff --git a/core/engine/src/builtins/error/range.rs b/core/engine/src/builtins/error/range.rs index 15cf63d64f4..37278ae8267 100644 --- a/core/engine/src/builtins/error/range.rs +++ b/core/engine/src/builtins/error/range.rs @@ -52,6 +52,8 @@ impl BuiltInObject for RangeError { impl BuiltInConstructor for RangeError { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::range_error; diff --git a/core/engine/src/builtins/error/reference.rs b/core/engine/src/builtins/error/reference.rs index f56f6b403a7..a16c77c3db6 100644 --- a/core/engine/src/builtins/error/reference.rs +++ b/core/engine/src/builtins/error/reference.rs @@ -51,6 +51,8 @@ impl BuiltInObject for ReferenceError { impl BuiltInConstructor for ReferenceError { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::reference_error; diff --git a/core/engine/src/builtins/error/syntax.rs b/core/engine/src/builtins/error/syntax.rs index 70333aaa10f..9ac489dc713 100644 --- a/core/engine/src/builtins/error/syntax.rs +++ b/core/engine/src/builtins/error/syntax.rs @@ -54,6 +54,8 @@ impl BuiltInObject for SyntaxError { impl BuiltInConstructor for SyntaxError { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::syntax_error; diff --git a/core/engine/src/builtins/error/type.rs b/core/engine/src/builtins/error/type.rs index 364afba24dc..c0e8397ca26 100644 --- a/core/engine/src/builtins/error/type.rs +++ b/core/engine/src/builtins/error/type.rs @@ -60,6 +60,8 @@ impl BuiltInObject for TypeError { impl BuiltInConstructor for TypeError { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::type_error; diff --git a/core/engine/src/builtins/error/uri.rs b/core/engine/src/builtins/error/uri.rs index 36e6f275bc8..113ccebea21 100644 --- a/core/engine/src/builtins/error/uri.rs +++ b/core/engine/src/builtins/error/uri.rs @@ -53,6 +53,8 @@ impl BuiltInObject for UriError { impl BuiltInConstructor for UriError { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::uri_error; diff --git a/core/engine/src/builtins/function/mod.rs b/core/engine/src/builtins/function/mod.rs index 8c4967e5644..0ff46d988aa 100644 --- a/core/engine/src/builtins/function/mod.rs +++ b/core/engine/src/builtins/function/mod.rs @@ -356,6 +356,8 @@ impl BuiltInObject for BuiltInFunctionObject { impl BuiltInConstructor for BuiltInFunctionObject { const LENGTH: usize = 1; + const P: usize = 7; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::function; diff --git a/core/engine/src/builtins/generator_function/mod.rs b/core/engine/src/builtins/generator_function/mod.rs index c4687f1b051..017b23c7bf7 100644 --- a/core/engine/src/builtins/generator_function/mod.rs +++ b/core/engine/src/builtins/generator_function/mod.rs @@ -62,6 +62,8 @@ impl BuiltInObject for GeneratorFunction { impl BuiltInConstructor for GeneratorFunction { const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::generator_function; diff --git a/core/engine/src/builtins/intl/collator/mod.rs b/core/engine/src/builtins/intl/collator/mod.rs index ea700d78b95..24520950ef7 100644 --- a/core/engine/src/builtins/intl/collator/mod.rs +++ b/core/engine/src/builtins/intl/collator/mod.rs @@ -188,6 +188,8 @@ impl BuiltInObject for Collator { impl BuiltInConstructor for Collator { const LENGTH: usize = 0; + const P: usize = 3; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::collator; diff --git a/core/engine/src/builtins/intl/date_time_format.rs b/core/engine/src/builtins/intl/date_time_format.rs index f6dca66bfc7..69cd896d8c4 100644 --- a/core/engine/src/builtins/intl/date_time_format.rs +++ b/core/engine/src/builtins/intl/date_time_format.rs @@ -82,6 +82,8 @@ impl BuiltInObject for DateTimeFormat { impl BuiltInConstructor for DateTimeFormat { const LENGTH: usize = 0; + const P: usize = 0; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::date_time_format; diff --git a/core/engine/src/builtins/intl/list_format/mod.rs b/core/engine/src/builtins/intl/list_format/mod.rs index 9da43f072d2..2cf3133b160 100644 --- a/core/engine/src/builtins/intl/list_format/mod.rs +++ b/core/engine/src/builtins/intl/list_format/mod.rs @@ -83,6 +83,8 @@ impl BuiltInObject for ListFormat { impl BuiltInConstructor for ListFormat { const LENGTH: usize = 0; + const P: usize = 4; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::list_format; diff --git a/core/engine/src/builtins/intl/locale/mod.rs b/core/engine/src/builtins/intl/locale/mod.rs index b285eaab13f..cbcaa67481d 100644 --- a/core/engine/src/builtins/intl/locale/mod.rs +++ b/core/engine/src/builtins/intl/locale/mod.rs @@ -157,6 +157,8 @@ impl BuiltInObject for Locale { impl BuiltInConstructor for Locale { const LENGTH: usize = 1; + const P: usize = 14; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::locale; diff --git a/core/engine/src/builtins/intl/number_format/mod.rs b/core/engine/src/builtins/intl/number_format/mod.rs index 979c7b4ce44..395355d2796 100644 --- a/core/engine/src/builtins/intl/number_format/mod.rs +++ b/core/engine/src/builtins/intl/number_format/mod.rs @@ -173,6 +173,8 @@ impl BuiltInObject for NumberFormat { impl BuiltInConstructor for NumberFormat { const LENGTH: usize = 0; + const P: usize = 3; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::number_format; diff --git a/core/engine/src/builtins/intl/plural_rules/mod.rs b/core/engine/src/builtins/intl/plural_rules/mod.rs index 03589c19581..4689feff4d2 100644 --- a/core/engine/src/builtins/intl/plural_rules/mod.rs +++ b/core/engine/src/builtins/intl/plural_rules/mod.rs @@ -83,6 +83,8 @@ impl BuiltInObject for PluralRules { impl BuiltInConstructor for PluralRules { const LENGTH: usize = 0; + const P: usize = 4; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::plural_rules; diff --git a/core/engine/src/builtins/intl/segmenter/mod.rs b/core/engine/src/builtins/intl/segmenter/mod.rs index e506073df21..2eeb7afbd35 100644 --- a/core/engine/src/builtins/intl/segmenter/mod.rs +++ b/core/engine/src/builtins/intl/segmenter/mod.rs @@ -119,6 +119,8 @@ impl BuiltInObject for Segmenter { impl BuiltInConstructor for Segmenter { const LENGTH: usize = 0; + const P: usize = 3; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::segmenter; diff --git a/core/engine/src/builtins/map/mod.rs b/core/engine/src/builtins/map/mod.rs index 40223620e8f..1d075d5120e 100644 --- a/core/engine/src/builtins/map/mod.rs +++ b/core/engine/src/builtins/map/mod.rs @@ -108,6 +108,8 @@ impl BuiltInObject for Map { impl BuiltInConstructor for Map { const LENGTH: usize = 0; + const P: usize = 11; + const SP: usize = 2; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::map; diff --git a/core/engine/src/builtins/mod.rs b/core/engine/src/builtins/mod.rs index b9a738f059e..3fbe2473a8a 100644 --- a/core/engine/src/builtins/mod.rs +++ b/core/engine/src/builtins/mod.rs @@ -37,6 +37,7 @@ pub mod weak_set; mod builder; use boa_macros::js_str; +use boa_profiler::Profiler; use builder::BuiltInBuilder; #[cfg(feature = "annex-b")] @@ -157,6 +158,10 @@ pub(crate) trait BuiltInObject: IntrinsicObject { /// /// [built-in object]: https://tc39.es/ecma262/#sec-built-in-object pub(crate) trait BuiltInConstructor: BuiltInObject { + /// Const Generic `P` is the minimum storage capacity for the prototype's Property table. + const P: usize; + /// Const Generic `SP` is the minimum storage capacity for the object's Static Property table. + const SP: usize; /// The amount of arguments this function object takes. const LENGTH: usize; @@ -304,6 +309,8 @@ impl Realm { /// /// [spec]: https://tc39.es/ecma262/#sec-setdefaultglobalbindings pub(crate) fn set_default_global_bindings(context: &mut Context) -> JsResult<()> { + let _timer = + Profiler::global().start_event("Builtins::set_default_global_bindings", "Builtins"); let global_object = context.global_object(); global_object.define_property_or_throw( diff --git a/core/engine/src/builtins/number/mod.rs b/core/engine/src/builtins/number/mod.rs index 73345912782..1a6dc39aac0 100644 --- a/core/engine/src/builtins/number/mod.rs +++ b/core/engine/src/builtins/number/mod.rs @@ -108,6 +108,8 @@ impl BuiltInObject for Number { impl BuiltInConstructor for Number { const LENGTH: usize = 1; + const P: usize = 6; + const SP: usize = 14; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::number; diff --git a/core/engine/src/builtins/object/mod.rs b/core/engine/src/builtins/object/mod.rs index d90a5bd06aa..1f34fd49103 100644 --- a/core/engine/src/builtins/object/mod.rs +++ b/core/engine/src/builtins/object/mod.rs @@ -150,6 +150,8 @@ impl BuiltInObject for OrdinaryObject { impl BuiltInConstructor for OrdinaryObject { const LENGTH: usize = 1; + const P: usize = 11; + const SP: usize = 23; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::object; diff --git a/core/engine/src/builtins/promise/mod.rs b/core/engine/src/builtins/promise/mod.rs index f9e0fe4e084..223fe40b2c3 100644 --- a/core/engine/src/builtins/promise/mod.rs +++ b/core/engine/src/builtins/promise/mod.rs @@ -381,6 +381,8 @@ impl BuiltInObject for Promise { impl BuiltInConstructor for Promise { const LENGTH: usize = 1; + const P: usize = 4; + const SP: usize = 9; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::promise; diff --git a/core/engine/src/builtins/proxy/mod.rs b/core/engine/src/builtins/proxy/mod.rs index 880838fdc94..f92daa30f16 100644 --- a/core/engine/src/builtins/proxy/mod.rs +++ b/core/engine/src/builtins/proxy/mod.rs @@ -106,6 +106,8 @@ impl BuiltInObject for Proxy { impl BuiltInConstructor for Proxy { const LENGTH: usize = 2; + const P: usize = 0; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::proxy; diff --git a/core/engine/src/builtins/regexp/mod.rs b/core/engine/src/builtins/regexp/mod.rs index beb782af1ac..73c0f57ef2c 100644 --- a/core/engine/src/builtins/regexp/mod.rs +++ b/core/engine/src/builtins/regexp/mod.rs @@ -177,6 +177,8 @@ impl BuiltInObject for RegExp { impl BuiltInConstructor for RegExp { const LENGTH: usize = 2; + const P: usize = 19; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::regexp; diff --git a/core/engine/src/builtins/set/mod.rs b/core/engine/src/builtins/set/mod.rs index c29fca4f4e3..a78984b187a 100644 --- a/core/engine/src/builtins/set/mod.rs +++ b/core/engine/src/builtins/set/mod.rs @@ -109,6 +109,8 @@ impl BuiltInObject for Set { impl BuiltInConstructor for Set { const LENGTH: usize = 0; + const P: usize = 11; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::set; diff --git a/core/engine/src/builtins/string/mod.rs b/core/engine/src/builtins/string/mod.rs index 7656c3a0cb1..22bab2cb550 100644 --- a/core/engine/src/builtins/string/mod.rs +++ b/core/engine/src/builtins/string/mod.rs @@ -198,6 +198,8 @@ impl BuiltInObject for String { impl BuiltInConstructor for String { const LENGTH: usize = 1; + const P: usize = 36; + const SP: usize = 3; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::string; diff --git a/core/engine/src/builtins/symbol/mod.rs b/core/engine/src/builtins/symbol/mod.rs index ca18aee702a..c0d915a873f 100644 --- a/core/engine/src/builtins/symbol/mod.rs +++ b/core/engine/src/builtins/symbol/mod.rs @@ -186,6 +186,8 @@ impl BuiltInObject for Symbol { impl BuiltInConstructor for Symbol { const LENGTH: usize = 0; + const P: usize = 5; + const SP: usize = 15; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::symbol; diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index 822e2c6c521..b302de2c733 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -201,6 +201,8 @@ impl IntrinsicObject for Duration { impl BuiltInConstructor for Duration { const LENGTH: usize = 0; + const P: usize = 22; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::duration; diff --git a/core/engine/src/builtins/temporal/instant/mod.rs b/core/engine/src/builtins/temporal/instant/mod.rs index f244e1f86c5..771e0011d9b 100644 --- a/core/engine/src/builtins/temporal/instant/mod.rs +++ b/core/engine/src/builtins/temporal/instant/mod.rs @@ -127,6 +127,8 @@ impl IntrinsicObject for Instant { impl BuiltInConstructor for Instant { const LENGTH: usize = 1; + const P: usize = 13; + const SP: usize = 4; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::instant; diff --git a/core/engine/src/builtins/temporal/plain_date/mod.rs b/core/engine/src/builtins/temporal/plain_date/mod.rs index 77f05f5b0d6..345493d974c 100644 --- a/core/engine/src/builtins/temporal/plain_date/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date/mod.rs @@ -241,6 +241,8 @@ impl IntrinsicObject for PlainDate { impl BuiltInConstructor for PlainDate { const LENGTH: usize = 3; + const P: usize = 26; + const SP: usize = 2; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::plain_date; diff --git a/core/engine/src/builtins/temporal/plain_date_time/mod.rs b/core/engine/src/builtins/temporal/plain_date_time/mod.rs index a2a582754d2..e296e570eef 100644 --- a/core/engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date_time/mod.rs @@ -298,6 +298,8 @@ impl IntrinsicObject for PlainDateTime { impl BuiltInConstructor for PlainDateTime { const LENGTH: usize = 3; + const P: usize = 29; + const SP: usize = 2; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::plain_date_time; diff --git a/core/engine/src/builtins/temporal/plain_month_day/mod.rs b/core/engine/src/builtins/temporal/plain_month_day/mod.rs index 37ad9f8ae61..bb49efdb285 100644 --- a/core/engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/core/engine/src/builtins/temporal/plain_month_day/mod.rs @@ -185,6 +185,8 @@ impl IntrinsicObject for PlainMonthDay { impl BuiltInConstructor for PlainMonthDay { const LENGTH: usize = 2; + const P: usize = 5; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::plain_month_day; diff --git a/core/engine/src/builtins/temporal/plain_time/mod.rs b/core/engine/src/builtins/temporal/plain_time/mod.rs index 18b13725390..c99461be486 100644 --- a/core/engine/src/builtins/temporal/plain_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_time/mod.rs @@ -129,6 +129,8 @@ impl IntrinsicObject for PlainTime { impl BuiltInConstructor for PlainTime { const LENGTH: usize = 0; + const P: usize = 15; + const SP: usize = 2; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::plain_time; diff --git a/core/engine/src/builtins/temporal/plain_year_month/mod.rs b/core/engine/src/builtins/temporal/plain_year_month/mod.rs index 74c90bd9c1a..0cea51490cb 100644 --- a/core/engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/core/engine/src/builtins/temporal/plain_year_month/mod.rs @@ -167,6 +167,8 @@ impl IntrinsicObject for PlainYearMonth { impl BuiltInConstructor for PlainYearMonth { const LENGTH: usize = 2; + const P: usize = 16; + const SP: usize = 1; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::plain_year_month; diff --git a/core/engine/src/builtins/temporal/zoned_date_time/mod.rs b/core/engine/src/builtins/temporal/zoned_date_time/mod.rs index ee76c047e0e..5f8e5e16780 100644 --- a/core/engine/src/builtins/temporal/zoned_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/zoned_date_time/mod.rs @@ -42,6 +42,8 @@ impl IntrinsicObject for ZonedDateTime { impl BuiltInConstructor for ZonedDateTime { const LENGTH: usize = 2; + const P: usize = 1; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::zoned_date_time; diff --git a/core/engine/src/builtins/typed_array/builtin.rs b/core/engine/src/builtins/typed_array/builtin.rs index cde663cd6eb..f4d34b2bd21 100644 --- a/core/engine/src/builtins/typed_array/builtin.rs +++ b/core/engine/src/builtins/typed_array/builtin.rs @@ -165,6 +165,8 @@ impl BuiltInObject for BuiltinTypedArray { impl BuiltInConstructor for BuiltinTypedArray { const LENGTH: usize = 0; + const P: usize = 37; + const SP: usize = 3; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::typed_array; diff --git a/core/engine/src/builtins/typed_array/mod.rs b/core/engine/src/builtins/typed_array/mod.rs index 168464d25e7..41f6e93d824 100644 --- a/core/engine/src/builtins/typed_array/mod.rs +++ b/core/engine/src/builtins/typed_array/mod.rs @@ -94,6 +94,8 @@ impl BuiltInObject for T { impl BuiltInConstructor for T { const LENGTH: usize = 3; + const P: usize = 1; + const SP: usize = 2; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = ::ERASED.standard_constructor(); diff --git a/core/engine/src/builtins/weak/weak_ref.rs b/core/engine/src/builtins/weak/weak_ref.rs index a19ec15a7cc..26cc460676b 100644 --- a/core/engine/src/builtins/weak/weak_ref.rs +++ b/core/engine/src/builtins/weak/weak_ref.rs @@ -53,6 +53,8 @@ impl BuiltInObject for WeakRef { impl BuiltInConstructor for WeakRef { /// The amount of arguments the `WeakRef` constructor takes. const LENGTH: usize = 1; + const P: usize = 2; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::weak_ref; diff --git a/core/engine/src/builtins/weak_map/mod.rs b/core/engine/src/builtins/weak_map/mod.rs index dced501b8b2..c326a56383b 100644 --- a/core/engine/src/builtins/weak_map/mod.rs +++ b/core/engine/src/builtins/weak_map/mod.rs @@ -60,6 +60,8 @@ impl BuiltInObject for WeakMap { impl BuiltInConstructor for WeakMap { /// The amount of arguments the `WeakMap` constructor takes. const LENGTH: usize = 0; + const P: usize = 5; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::weak_map; diff --git a/core/engine/src/builtins/weak_set/mod.rs b/core/engine/src/builtins/weak_set/mod.rs index 4d19526bf0c..b9922677160 100644 --- a/core/engine/src/builtins/weak_set/mod.rs +++ b/core/engine/src/builtins/weak_set/mod.rs @@ -58,6 +58,8 @@ impl BuiltInObject for WeakSet { impl BuiltInConstructor for WeakSet { /// The amount of arguments the `WeakSet` constructor takes. const LENGTH: usize = 0; + const P: usize = 4; + const SP: usize = 0; const STANDARD_CONSTRUCTOR: fn(&StandardConstructors) -> &StandardConstructor = StandardConstructors::weak_set; diff --git a/core/engine/src/context/icu.rs b/core/engine/src/context/icu.rs index 57a7b909f85..3c05b101a41 100644 --- a/core/engine/src/context/icu.rs +++ b/core/engine/src/context/icu.rs @@ -1,5 +1,6 @@ use std::{cell::OnceCell, fmt::Debug}; +use boa_profiler::Profiler; use icu_casemap::CaseMapper; use icu_locid_transform::{LocaleCanonicalizer, LocaleExpander, LocaleTransformError}; use icu_normalizer::{ComposingNormalizer, DecomposingNormalizer, NormalizerError}; @@ -89,6 +90,7 @@ impl IntlProvider { pub(crate) fn try_new_with_buffer_provider( provider: (impl BufferProvider + 'static), ) -> IntlProvider { + let _timer = Profiler::global().start_event("ICU::try_new_with_buffer_provider", "ICU"); Self { locale_canonicalizer: OnceCell::new(), locale_expander: OnceCell::new(), @@ -106,6 +108,7 @@ impl IntlProvider { pub(crate) fn try_new_with_any_provider( provider: (impl AnyProvider + 'static), ) -> IntlProvider { + let _timer = Profiler::global().start_event("ICU::try_new_with_any_provider", "ICU"); Self { locale_canonicalizer: OnceCell::new(), locale_expander: OnceCell::new(), diff --git a/core/engine/src/context/mod.rs b/core/engine/src/context/mod.rs index dd27ebf8f63..4ab70c3ac29 100644 --- a/core/engine/src/context/mod.rs +++ b/core/engine/src/context/mod.rs @@ -1052,6 +1052,7 @@ impl ContextBuilder { // TODO: try to use a custom error here, since most of the `JsError` APIs // require having a `Context` in the first place. pub fn build(self) -> JsResult { + let _timer = Profiler::global().start_event("Ctx::build", "context"); if self.can_block { if CANNOT_BLOCK_COUNTER.get() > 0 { return Err(JsNativeError::typ() diff --git a/core/engine/src/module/loader.rs b/core/engine/src/module/loader.rs index 8a90fab679e..a4dd22ddbc5 100644 --- a/core/engine/src/module/loader.rs +++ b/core/engine/src/module/loader.rs @@ -1,5 +1,6 @@ use std::path::{Component, Path, PathBuf}; +use boa_profiler::Profiler; use rustc_hash::FxHashMap; use boa_gc::GcRefCell; @@ -251,6 +252,7 @@ pub struct SimpleModuleLoader { impl SimpleModuleLoader { /// Creates a new `SimpleModuleLoader` from a root module path. pub fn new>(root: P) -> JsResult { + let _timer = Profiler::global().start_event("Loader::new", "Loader"); if cfg!(target_family = "wasm") { return Err(JsNativeError::typ() .with_message("cannot resolve a relative path in WASM targets") diff --git a/core/engine/src/object/shape/property_table.rs b/core/engine/src/object/shape/property_table.rs index cb2d7513042..9aaa8f72dd1 100644 --- a/core/engine/src/object/shape/property_table.rs +++ b/core/engine/src/object/shape/property_table.rs @@ -1,11 +1,9 @@ -use std::{cell::RefCell, rc::Rc}; - -use rustc_hash::FxHashMap; - use crate::{ object::shape::slot::{Slot, SlotAttributes}, property::PropertyKey, }; +use rustc_hash::{FxBuildHasher, FxHashMap}; +use std::{cell::RefCell, rc::Rc}; /// The internal representation of [`PropertyTable`]. #[derive(Default, Debug, Clone)] @@ -15,6 +13,14 @@ pub(crate) struct PropertyTableInner { } impl PropertyTableInner { + /// Returns a new table with a given minimum capacity. + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self { + map: FxHashMap::with_capacity_and_hasher(capacity, FxBuildHasher), + keys: Vec::with_capacity(capacity), + } + } + /// Returns all the keys, in insertion order. pub(crate) fn keys(&self) -> Vec { self.keys_cloned_n(self.keys.len() as u32) @@ -74,6 +80,13 @@ pub(crate) struct PropertyTable { } impl PropertyTable { + /// Creates a new `PropertyTable` with the specified capacity. + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self { + inner: Rc::new(RefCell::new(PropertyTableInner::with_capacity(capacity))), + } + } + /// Returns the inner representation of a [`PropertyTable`]. pub(super) fn inner(&self) -> &RefCell { &self.inner diff --git a/core/engine/src/object/shape/shared_shape/mod.rs b/core/engine/src/object/shape/shared_shape/mod.rs index b27b5f62005..3189603df15 100644 --- a/core/engine/src/object/shape/shared_shape/mod.rs +++ b/core/engine/src/object/shape/shared_shape/mod.rs @@ -186,7 +186,8 @@ impl SharedShape { forward_transitions: ForwardTransition::default(), prototype: None, property_count: 0, - property_table: PropertyTable::default(), + // Most of the time the root shape initiates with between 1-4 properties. + property_table: PropertyTable::with_capacity(4), previous: None, flags: ShapeFlags::default(), transition_count: 0, diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index 4e17a001210..ea4f019cd11 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -110,6 +110,7 @@ unsafe impl Trace for ActiveRunnable { impl Vm { /// Creates a new virtual machine. pub(crate) fn new(realm: Realm) -> Self { + let _timer = Profiler::global().start_event("VM::new", "VM"); Self { frames: Vec::with_capacity(16), frame: CallFrame::new( From b60b1039e3ebb3ec771de014d88ca630fd06a3b8 Mon Sep 17 00:00:00 2001 From: Nikita-str <42584606+Nikita-str@users.noreply.github.com> Date: Sun, 3 Nov 2024 17:01:14 +0300 Subject: [PATCH 12/72] `TryFromJs` from `JsMap` for `HashMap` & `BtreeMap` (#3998) * `TryFromJs` from `JsMap` for `HashMap` & `BtreeMap` * fix `clippy` warn * use `IteratorResult` instead of `as_object` * `JsMap` impl `rust_for_each` * fix: initial `JsMap` can be changed in `for_each` * better naming --- core/engine/src/builtins/map/mod.rs | 47 +++++++++++++++++++ core/engine/src/object/builtins/jsmap.rs | 10 ++++ .../src/value/conversions/try_from_js.rs | 23 +++++++++ .../conversions/try_from_js/collections.rs | 29 ++++++++++++ 4 files changed, 109 insertions(+) diff --git a/core/engine/src/builtins/map/mod.rs b/core/engine/src/builtins/map/mod.rs index 1d075d5120e..953cc977980 100644 --- a/core/engine/src/builtins/map/mod.rs +++ b/core/engine/src/builtins/map/mod.rs @@ -503,6 +503,53 @@ impl Map { } } + /// Call `f` for each `(key, value)` in the `Map`. + /// + /// Can not be used in [`Self::for_each`] because in that case will be + /// incorrect order for next steps of the algo: + /// ```txt + /// 2. Perform ? RequireInternalSlot(M, [[MapData]]). + /// 3. If IsCallable(callbackfn) is false, throw a TypeError exception. + /// ``` + pub(crate) fn for_each_native(this: &JsValue, mut f: F) -> JsResult<()> + where + F: FnMut(JsValue, JsValue) -> JsResult<()>, + { + // See `Self::for_each` for comments on the algo. + + let map = this + .as_object() + .filter(|obj| obj.is::>()) + .ok_or_else(|| JsNativeError::typ().with_message("`this` is not a Map"))?; + + let _lock = map + .downcast_mut::>() + .expect("checked that `this` was a map") + .lock(map.clone()); + + let mut index = 0; + loop { + let (k, v) = { + let map = map + .downcast_ref::>() + .expect("checked that `this` was a map"); + + if index < map.full_len() { + if let Some((k, v)) = map.get_index(index) { + (k.clone(), v.clone()) + } else { + continue; + } + } else { + return Ok(()); + } + }; + + f(k, v)?; + index += 1; + } + } + /// `Map.prototype.values()` /// /// Returns a new Iterator object that contains the values for each element in the Map object in insertion order. diff --git a/core/engine/src/object/builtins/jsmap.rs b/core/engine/src/object/builtins/jsmap.rs index 7027bbaa46a..af63ef90db5 100644 --- a/core/engine/src/object/builtins/jsmap.rs +++ b/core/engine/src/object/builtins/jsmap.rs @@ -402,6 +402,16 @@ impl JsMap { ) } + /// Executes the provided callback function for each key-value pair within the [`JsMap`]. + #[inline] + pub fn for_each_native(&self, f: F) -> JsResult<()> + where + F: FnMut(JsValue, JsValue) -> JsResult<()>, + { + let this = self.inner.clone().into(); + Map::for_each_native(&this, f) + } + /// Returns a new [`JsMapIterator`] object that yields the `value` for each element within the [`JsMap`] in insertion order. #[inline] pub fn values(&self, context: &mut Context) -> JsResult { diff --git a/core/engine/src/value/conversions/try_from_js.rs b/core/engine/src/value/conversions/try_from_js.rs index ebe7c980fa1..42068c6c9ab 100644 --- a/core/engine/src/value/conversions/try_from_js.rs +++ b/core/engine/src/value/conversions/try_from_js.rs @@ -565,3 +565,26 @@ fn value_into_map() { }), ]); } + +#[test] +fn js_map_into_rust_map() -> JsResult<()> { + use boa_engine::Source; + use std::collections::{BTreeMap, HashMap}; + + let js_code = "new Map([['a', 1], ['b', 3], ['aboba', 42024]])"; + let mut context = Context::default(); + + let js_value = context.eval(Source::from_bytes(js_code))?; + + let hash_map = HashMap::::try_from_js(&js_value, &mut context)?; + let btree_map = BTreeMap::::try_from_js(&js_value, &mut context)?; + + let expect = [("a".into(), 1), ("aboba".into(), 42024), ("b".into(), 3)]; + + let expected_hash_map: HashMap = expect.iter().cloned().collect(); + assert_eq!(expected_hash_map, hash_map); + + let expected_btree_map: BTreeMap = expect.iter().cloned().collect(); + assert_eq!(expected_btree_map, btree_map); + Ok(()) +} diff --git a/core/engine/src/value/conversions/try_from_js/collections.rs b/core/engine/src/value/conversions/try_from_js/collections.rs index 37d649e9630..4934de30352 100644 --- a/core/engine/src/value/conversions/try_from_js/collections.rs +++ b/core/engine/src/value/conversions/try_from_js/collections.rs @@ -3,6 +3,7 @@ use std::collections::{BTreeMap, HashMap}; use std::hash::Hash; +use crate::object::JsMap; use crate::value::TryFromJs; use crate::{Context, JsNativeError, JsResult, JsValue}; @@ -18,6 +19,20 @@ where .into()); }; + // JsMap case + if let Ok(js_map) = JsMap::from_object(object.clone()) { + let mut map = Self::default(); + js_map.for_each_native(|key, value| { + map.insert( + K::try_from_js(&key, context)?, + V::try_from_js(&value, context)?, + ); + Ok(()) + })?; + return Ok(map); + } + + // key-valued JsObject case: let keys = object.__own_property_keys__(context)?; keys.into_iter() @@ -47,6 +62,20 @@ where .into()); }; + // JsMap case + if let Ok(js_map) = JsMap::from_object(object.clone()) { + let mut map = Self::default(); + js_map.for_each_native(|key, value| { + map.insert( + K::try_from_js(&key, context)?, + V::try_from_js(&value, context)?, + ); + Ok(()) + })?; + return Ok(map); + } + + // key-valued JsObject case: let keys = object.__own_property_keys__(context)?; keys.into_iter() From 265dca3a117401d6d1e7ebf5fa4fa7b052f72d28 Mon Sep 17 00:00:00 2001 From: Jason Williams <936006+jasonwilliams@users.noreply.github.com> Date: Sun, 3 Nov 2024 21:43:51 +0000 Subject: [PATCH 13/72] add nightly build (#4026) * add nightly build * add line on the end --- .github/workflows/nightly_build.yml | 47 +++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/workflows/nightly_build.yml diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml new file mode 100644 index 00000000000..30d6fc5832f --- /dev/null +++ b/.github/workflows/nightly_build.yml @@ -0,0 +1,47 @@ +name: Nightly Build + +# Schedule this workflow to run at midnight every day +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + + - name: Install Dependencies + run: | + cargo fetch + + - name: Build Project + run: | + cargo build --release + + - name: Set File Name + id: vars + run: | + DATE=$(date +'%Y%m%d') + COMMIT_HASH=$(git rev-parse --short HEAD) + echo "FILE_NAME=boa-nightly-linux-${DATE}-${COMMIT_HASH}" >> $GITHUB_ENV + + - name: Rename Binary + run: mv target/release/boa target/release/$FILE_NAME + + - name: Upload binaries to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: target/release/$FILE_NAME + asset_name: ${{ env.FILE_NAME }} + tag: nightly + overwrite: true From 4983471ff6131205bd955c1b13ed08aca1de4c12 Mon Sep 17 00:00:00 2001 From: CrazyboyQCD <53971641+CrazyboyQCD@users.noreply.github.com> Date: Mon, 4 Nov 2024 09:37:27 +0800 Subject: [PATCH 14/72] Some optimizations on `Error` (#4020) * chore: mark `JsNativeError`'s constructors const * chore: add associated constants * chore: replace const method calls in `js_error` with corresponding constants * fix: use correct method * perf: change error's `message` type to `Cow<'static str>` * chore: fix lint --- core/engine/src/builtins/temporal/error.rs | 8 +- core/engine/src/error.rs | 133 +++++++++++++-------- core/gc/src/trace.rs | 2 +- 3 files changed, 87 insertions(+), 56 deletions(-) diff --git a/core/engine/src/builtins/temporal/error.rs b/core/engine/src/builtins/temporal/error.rs index 5755434b4ef..4b7f3e73092 100644 --- a/core/engine/src/builtins/temporal/error.rs +++ b/core/engine/src/builtins/temporal/error.rs @@ -5,10 +5,10 @@ use crate::{JsError, JsNativeError}; impl From for JsNativeError { fn from(value: TemporalError) -> Self { match value.kind() { - ErrorKind::Range => JsNativeError::range().with_message(value.message()), - ErrorKind::Type => JsNativeError::typ().with_message(value.message()), - ErrorKind::Generic => JsNativeError::error().with_message(value.message()), - ErrorKind::Syntax => JsNativeError::syntax().with_message(value.message()), + ErrorKind::Range => JsNativeError::range().with_message(value.message().to_owned()), + ErrorKind::Type => JsNativeError::typ().with_message(value.message().to_owned()), + ErrorKind::Generic => JsNativeError::error().with_message(value.message().to_owned()), + ErrorKind::Syntax => JsNativeError::syntax().with_message(value.message().to_owned()), ErrorKind::Assert => JsNativeError::error().with_message("internal engine error"), } } diff --git a/core/engine/src/error.rs b/core/engine/src/error.rs index 2dafbadbb42..577fa70a478 100644 --- a/core/engine/src/error.rs +++ b/core/engine/src/error.rs @@ -10,7 +10,7 @@ use crate::{ }; use boa_gc::{custom_trace, Finalize, Trace}; use boa_macros::js_str; -use std::{error, fmt}; +use std::{borrow::Cow, error, fmt}; use thiserror::Error; /// Create an error object from a value or string literal. Optionally the @@ -59,80 +59,80 @@ use thiserror::Error; macro_rules! js_error { (Error: $value: literal) => { $crate::JsError::from_native( - $crate::JsNativeError::error().with_message($value) + $crate::JsNativeError::ERROR.with_message($value) ) }; (Error: $value: literal $(, $args: expr)* $(,)?) => { $crate::JsError::from_native( - $crate::JsNativeError::error() + $crate::JsNativeError::ERROR .with_message(format!($value $(, $args)*)) ) }; (TypeError: $value: literal) => { $crate::JsError::from_native( - $crate::JsNativeError::typ().with_message($value) + $crate::JsNativeError::TYP.with_message($value) ) }; (TypeError: $value: literal $(, $args: expr)* $(,)?) => { $crate::JsError::from_native( - $crate::JsNativeError::typ() + $crate::JsNativeError::TYP .with_message(format!($value $(, $args)*)) ) }; (SyntaxError: $value: literal) => { $crate::JsError::from_native( - $crate::JsNativeError::syntax().with_message($value) + $crate::JsNativeError::SYNTAX.with_message($value) ) }; (SyntaxError: $value: literal $(, $args: expr)* $(,)?) => { $crate::JsError::from_native( - $crate::JsNativeError::syntax().with_message(format!($value $(, $args)*)) + $crate::JsNativeError::SYNTAX.with_message(format!($value $(, $args)*)) ) }; (RangeError: $value: literal) => { $crate::JsError::from_native( - $crate::JsNativeError::range().with_message($value) + $crate::JsNativeError::RANGE.with_message($value) ) }; (RangeError: $value: literal $(, $args: expr)* $(,)?) => { $crate::JsError::from_native( - $crate::JsNativeError::range().with_message(format!($value $(, $args)*)) + $crate::JsNativeError::RANGE.with_message(format!($value $(, $args)*)) ) }; (EvalError: $value: literal) => { $crate::JsError::from_native( - $crate::JsNativeError::eval().with_message($value) + $crate::JsNativeError::EVAL.with_message($value) ) }; (EvalError: $value: literal $(, $args: expr)* $(,)?) => { $crate::JsError::from_native( - $crate::JsNativeError::eval().with_message(format!($value $(, $args)*)) + $crate::JsNativeError::EVAL.with_message(format!($value $(, $args)*)) ) }; (ReferenceError: $value: literal) => { $crate::JsError::from_native( - $crate::JsNativeError::reference().with_message($value) + $crate::JsNativeError::REFERENCE.with_message($value) ) }; (ReferenceError: $value: literal $(, $args: expr)* $(,)?) => { $crate::JsError::from_native( - $crate::JsNativeError::reference().with_message(format!($value $(, $args)*)) + $crate::JsNativeError::REFERENCE.with_message(format!($value $(, $args)*)) ) }; (URIError: $value: literal) => { $crate::JsError::from_native( - $crate::JsNativeError::uri().with_message($value) + $crate::JsNativeError::URI.with_message($value) ) }; (URIError: $value: literal $(, $args: expr)* $(,)?) => { $crate::JsError::from_native( - $crate::JsNativeError::uri().with_message(format!($value $(, $args)*)) + $crate::JsNativeError::URI.with_message(format!($value $(, $args)*)) ) }; @@ -407,14 +407,15 @@ impl JsError { let message = if let Some(msg) = try_get_property(js_string!("message"), "message", context)? { - msg.as_string() - .map(JsString::to_std_string) - .transpose() - .map_err(|_| TryNativeError::InvalidMessageEncoding)? - .ok_or(TryNativeError::InvalidPropertyType("message"))? - .into() + Cow::Owned( + msg.as_string() + .map(JsString::to_std_string) + .transpose() + .map_err(|_| TryNativeError::InvalidMessageEncoding)? + .ok_or(TryNativeError::InvalidPropertyType("message"))?, + ) } else { - Box::default() + Cow::Borrowed("") }; let cause = try_get_property(js_string!("cause"), "cause", context)?; @@ -559,7 +560,7 @@ impl JsError { pub fn into_erased(self, context: &mut Context) -> JsErasedError { let Ok(native) = self.try_native(context) else { return JsErasedError { - inner: ErasedRepr::Opaque(self.to_string().into_boxed_str()), + inner: ErasedRepr::Opaque(Cow::Owned(self.to_string())), }; }; @@ -671,7 +672,7 @@ impl fmt::Display for JsError { pub struct JsNativeError { /// The kind of native error (e.g. `TypeError`, `SyntaxError`, etc.) pub kind: JsNativeErrorKind, - message: Box, + message: Cow<'static, str>, #[source] cause: Option>, realm: Option, @@ -710,8 +711,34 @@ impl fmt::Debug for JsNativeError { } impl JsNativeError { + /// Default `AggregateError` kind `JsNativeError`. + pub const AGGREGATE: Self = Self::aggregate(Vec::new()); + /// Default `Error` kind `JsNativeError`. + pub const ERROR: Self = Self::error(); + /// Default `EvalError` kind `JsNativeError`. + pub const EVAL: Self = Self::eval(); + /// Default `RangeError` kind `JsNativeError`. + pub const RANGE: Self = Self::range(); + /// Default `ReferenceError` kind `JsNativeError`. + pub const REFERENCE: Self = Self::reference(); + /// Default `SyntaxError` kind `JsNativeError`. + pub const SYNTAX: Self = Self::syntax(); + /// Default `error` kind `JsNativeError`. + pub const TYP: Self = Self::typ(); + /// Default `UriError` kind `JsNativeError`. + pub const URI: Self = Self::uri(); + #[cfg(feature = "fuzz")] + /// Default `NoInstructionsRemain` kind `JsNativeError`. + pub const NO_INSTRUCTIONS_REMAIN: Self = Self::no_instructions_remain(); + /// Default `error` kind `JsNativeError`. + pub const RUNTIME_LIMIT: Self = Self::runtime_limit(); + /// Creates a new `JsNativeError` from its `kind`, `message` and (optionally) its `cause`. - fn new(kind: JsNativeErrorKind, message: Box, cause: Option>) -> Self { + const fn new( + kind: JsNativeErrorKind, + message: Cow<'static, str>, + cause: Option>, + ) -> Self { Self { kind, message, @@ -740,8 +767,12 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn aggregate(errors: Vec) -> Self { - Self::new(JsNativeErrorKind::Aggregate(errors), Box::default(), None) + pub const fn aggregate(errors: Vec) -> Self { + Self::new( + JsNativeErrorKind::Aggregate(errors), + Cow::Borrowed(""), + None, + ) } /// Check if it's a [`JsNativeErrorKind::Aggregate`]. @@ -763,8 +794,8 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn error() -> Self { - Self::new(JsNativeErrorKind::Error, Box::default(), None) + pub const fn error() -> Self { + Self::new(JsNativeErrorKind::Error, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::Error`]. @@ -786,8 +817,8 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn eval() -> Self { - Self::new(JsNativeErrorKind::Eval, Box::default(), None) + pub const fn eval() -> Self { + Self::new(JsNativeErrorKind::Eval, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::Eval`]. @@ -809,8 +840,8 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn range() -> Self { - Self::new(JsNativeErrorKind::Range, Box::default(), None) + pub const fn range() -> Self { + Self::new(JsNativeErrorKind::Range, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::Range`]. @@ -832,8 +863,8 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn reference() -> Self { - Self::new(JsNativeErrorKind::Reference, Box::default(), None) + pub const fn reference() -> Self { + Self::new(JsNativeErrorKind::Reference, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::Reference`]. @@ -855,8 +886,8 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn syntax() -> Self { - Self::new(JsNativeErrorKind::Syntax, Box::default(), None) + pub const fn syntax() -> Self { + Self::new(JsNativeErrorKind::Syntax, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::Syntax`]. @@ -878,8 +909,8 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn typ() -> Self { - Self::new(JsNativeErrorKind::Type, Box::default(), None) + pub const fn typ() -> Self { + Self::new(JsNativeErrorKind::Type, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::Type`]. @@ -901,8 +932,8 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub fn uri() -> Self { - Self::new(JsNativeErrorKind::Uri, Box::default(), None) + pub const fn uri() -> Self { + Self::new(JsNativeErrorKind::Uri, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::Uri`]. @@ -916,10 +947,10 @@ impl JsNativeError { /// is only used in a fuzzing context. #[cfg(feature = "fuzz")] #[must_use] - pub fn no_instructions_remain() -> Self { + pub const fn no_instructions_remain() -> Self { Self::new( JsNativeErrorKind::NoInstructionsRemain, - Box::default(), + Cow::Borrowed(""), None, ) } @@ -935,8 +966,8 @@ impl JsNativeError { /// Creates a new `JsNativeError` that indicates that the context exceeded the runtime limits. #[must_use] #[inline] - pub fn runtime_limit() -> Self { - Self::new(JsNativeErrorKind::RuntimeLimit, Box::default(), None) + pub const fn runtime_limit() -> Self { + Self::new(JsNativeErrorKind::RuntimeLimit, Cow::Borrowed(""), None) } /// Check if it's a [`JsNativeErrorKind::RuntimeLimit`]. @@ -960,7 +991,7 @@ impl JsNativeError { #[inline] pub fn with_message(mut self, message: S) -> Self where - S: Into>, + S: Into>, { self.message = message.into(); self @@ -1004,7 +1035,7 @@ impl JsNativeError { /// ``` #[must_use] #[inline] - pub const fn message(&self) -> &str { + pub fn message(&self) -> &str { &self.message } @@ -1099,7 +1130,7 @@ impl JsNativeError { o.create_non_enumerable_data_property_or_throw( js_str!("message"), - js_string!(&**message), + js_string!(message.as_ref()), context, ); @@ -1340,7 +1371,7 @@ pub struct JsErasedError { #[derive(Debug, Clone, Trace, Finalize, PartialEq, Eq)] enum ErasedRepr { Native(JsErasedNativeError), - Opaque(Box), + Opaque(Cow<'static, str>), } impl fmt::Display for JsErasedError { @@ -1365,7 +1396,7 @@ impl JsErasedError { /// Gets the inner [`str`] if the error is an opaque error, /// or `None` otherwise. #[must_use] - pub const fn as_opaque(&self) -> Option<&str> { + pub fn as_opaque(&self) -> Option<&str> { match self.inner { ErasedRepr::Native(_) => None, ErasedRepr::Opaque(ref v) => Some(v), @@ -1388,7 +1419,7 @@ impl JsErasedError { pub struct JsErasedNativeError { /// The kind of native error (e.g. `TypeError`, `SyntaxError`, etc.) pub kind: JsErasedNativeErrorKind, - message: Box, + message: Cow<'static, str>, #[source] cause: Option>, } diff --git a/core/gc/src/trace.rs b/core/gc/src/trace.rs index beb684fcd4a..12a456dd4c9 100644 --- a/core/gc/src/trace.rs +++ b/core/gc/src/trace.rs @@ -179,7 +179,7 @@ simple_empty_finalize_trace![ char, TypeId, String, - Box, + str, Rc, Path, PathBuf, From 24e24815031fdcda65e82bf18f5e47594e9e3263 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:52:44 -0600 Subject: [PATCH 15/72] Bump the rust-dependencies group with 5 updates (#4027) Bumps the rust-dependencies group with 5 updates: | Package | From | To | | --- | --- | --- | | [serde](https://github.com/serde-rs/serde) | `1.0.213` | `1.0.214` | | [syn](https://github.com/dtolnay/syn) | `2.0.85` | `2.0.87` | | [thiserror](https://github.com/dtolnay/thiserror) | `1.0.65` | `1.0.67` | | [sys-locale](https://github.com/1Password/sys-locale) | `0.3.1` | `0.3.2` | | [futures-lite](https://github.com/smol-rs/futures-lite) | `2.3.0` | `2.4.0` | Updates `serde` from 1.0.213 to 1.0.214 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.213...v1.0.214) Updates `syn` from 2.0.85 to 2.0.87 - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.85...2.0.87) Updates `thiserror` from 1.0.65 to 1.0.67 - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.65...1.0.67) Updates `sys-locale` from 0.3.1 to 0.3.2 - [Release notes](https://github.com/1Password/sys-locale/releases) - [Changelog](https://github.com/1Password/sys-locale/blob/main/CHANGELOG.md) - [Commits](https://github.com/1Password/sys-locale/compare/v0.3.1...v0.3.2) Updates `futures-lite` from 2.3.0 to 2.4.0 - [Release notes](https://github.com/smol-rs/futures-lite/releases) - [Changelog](https://github.com/smol-rs/futures-lite/blob/master/CHANGELOG.md) - [Commits](https://github.com/smol-rs/futures-lite/compare/v2.3.0...v2.4.0) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: sys-locale dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: futures-lite dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 44 ++++++++++++++++++++++---------------------- Cargo.toml | 10 +++++----- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a66269eaa1..cafaa431014 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,7 +146,7 @@ dependencies = [ "async-task", "concurrent-queue", "fastrand 2.1.0", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "slab", ] @@ -158,7 +158,7 @@ checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.4.0", ] [[package]] @@ -171,7 +171,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "parking", "polling 3.7.2", "rustix", @@ -199,7 +199,7 @@ checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ "async-io", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.4.0", ] [[package]] @@ -216,7 +216,7 @@ dependencies = [ "blocking", "cfg-if", "event-listener 5.3.1", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "rustix", "tracing", "windows-sys 0.52.0", @@ -303,7 +303,7 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "piper", ] @@ -363,7 +363,7 @@ dependencies = [ "fast-float", "fixed_decimal", "float-cmp", - "futures-lite 2.3.0", + "futures-lite 2.4.0", "hashbrown 0.14.5", "icu_calendar", "icu_casemap", @@ -1322,9 +1322,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" dependencies = [ "fastrand 2.1.0", "futures-core", @@ -2963,9 +2963,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] @@ -2982,9 +2982,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", @@ -3121,7 +3121,7 @@ dependencies = [ "async-net", "async-process", "blocking", - "futures-lite 2.3.0", + "futures-lite 2.4.0", ] [[package]] @@ -3191,9 +3191,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.85" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -3213,9 +3213,9 @@ dependencies = [ [[package]] name = "sys-locale" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801cf239ecd6ccd71f03d270d67dd53d13e90aab208bf4b8fe4ad957ea949b0" +checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4" dependencies = [ "libc", ] @@ -3307,18 +3307,18 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.65" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +checksum = "3b3c6efbfc763e64eb85c11c25320f0737cb7364c4b6336db90aa9ebe27a0bbd" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.65" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 0a425012947..73d0cffb030 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -64,7 +64,7 @@ regex = "1.11.1" regress = { version = "0.10.1", features = ["utf16"] } rustc-hash = { version = "2.0.0", default-features = false } serde_json = "1.0.132" -serde = "1.0.213" +serde = "1.0.214" static_assertions = "1.1.0" textwrap = "0.16.0" thin-vec = "0.2.13" @@ -90,7 +90,7 @@ isahc = "1.7.2" rustyline = { version = "14.0.0", default-features = false } dhat = "0.3.3" quote = "1.0.37" -syn = { version = "2.0.85", default-features = false } +syn = { version = "2.0.87", default-features = false } proc-macro2 = "1.0" synstructure = "0.13" measureme = "11.0.1" @@ -100,7 +100,7 @@ rand = "0.8.5" num-integer = "0.1.46" ryu-js = "1.0.1" tap = "1.0.1" -thiserror = "1.0.65" +thiserror = "1.0.67" dashmap = "5.5.3" num_enum = "0.7.3" itertools = { version = "0.13.0", default-features = false } @@ -110,12 +110,12 @@ arrayvec = "0.7.6" intrusive-collections = "0.9.7" cfg-if = "1.0.0" either = "1.13.0" -sys-locale = "0.3.1" +sys-locale = "0.3.2" temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "1e7901d07a83211e62373ab94284a7d1ada4c913" } web-time = "1.1.0" criterion = "0.5.1" float-cmp = "0.9.0" -futures-lite = "2.3.0" +futures-lite = "2.4.0" test-case = "3.3.1" winapi = { version = "0.3.9", default-features = false } From e37dc418ec764e3a33f0856232d2e7796f10eaef Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 4 Nov 2024 10:41:31 -0800 Subject: [PATCH 16/72] Option::None should try into Undefined, not Null (#4029) This PR also include removal of useless path JsResult:: for Ok and Err, which are preluded already. --- .../src/value/conversions/try_into_js.rs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/core/engine/src/value/conversions/try_into_js.rs b/core/engine/src/value/conversions/try_into_js.rs index ce24903c5dc..f497db05e7b 100644 --- a/core/engine/src/value/conversions/try_into_js.rs +++ b/core/engine/src/value/conversions/try_into_js.rs @@ -9,18 +9,18 @@ pub trait TryIntoJs: Sized { impl TryIntoJs for bool { fn try_into_js(&self, _context: &mut Context) -> JsResult { - JsResult::Ok(JsValue::Boolean(*self)) + Ok(JsValue::Boolean(*self)) } } impl TryIntoJs for &str { fn try_into_js(&self, _context: &mut Context) -> JsResult { - JsResult::Ok(JsValue::String(JsString::from(*self))) + Ok(JsValue::String(JsString::from(*self))) } } impl TryIntoJs for String { fn try_into_js(&self, _context: &mut Context) -> JsResult { - JsResult::Ok(JsValue::String(JsString::from(self.as_str()))) + Ok(JsValue::String(JsString::from(self.as_str()))) } } @@ -28,7 +28,7 @@ macro_rules! impl_try_into_js_by_from { ($t:ty) => { impl TryIntoJs for $t { fn try_into_js(&self, _context: &mut Context) -> JsResult { - JsResult::Ok(JsValue::from(self.clone())) + Ok(JsValue::from(self.clone())) } } }; @@ -81,9 +81,9 @@ impl TryIntoJs for i64 { let value = *self; #[allow(clippy::manual_range_contains)] if value < MIN_SAFE_INTEGER_I64 || MAX_SAFE_INTEGER_I64 < value { - JsResult::Err(err_outside_safe_range()) + Err(err_outside_safe_range()) } else { - JsResult::Ok(convert_safe_i64(value)) + Ok(convert_safe_i64(value)) } } } @@ -91,9 +91,9 @@ impl TryIntoJs for u64 { fn try_into_js(&self, _context: &mut Context) -> JsResult { let value = *self; if (MAX_SAFE_INTEGER_I64 as u64) < value { - JsResult::Err(err_outside_safe_range()) + Err(err_outside_safe_range()) } else { - JsResult::Ok(convert_safe_i64(value as i64)) + Ok(convert_safe_i64(value as i64)) } } } @@ -101,9 +101,9 @@ impl TryIntoJs for i128 { fn try_into_js(&self, _context: &mut Context) -> JsResult { let value = *self; if value < i128::from(MIN_SAFE_INTEGER_I64) || i128::from(MAX_SAFE_INTEGER_I64) < value { - JsResult::Err(err_outside_safe_range()) + Err(err_outside_safe_range()) } else { - JsResult::Ok(convert_safe_i64(value as i64)) + Ok(convert_safe_i64(value as i64)) } } } @@ -111,9 +111,9 @@ impl TryIntoJs for u128 { fn try_into_js(&self, _context: &mut Context) -> JsResult { let value = *self; if (MAX_SAFE_INTEGER_I64 as u128) < value { - JsResult::Err(err_outside_safe_range()) + Err(err_outside_safe_range()) } else { - JsResult::Ok(convert_safe_i64(value as i64)) + Ok(convert_safe_i64(value as i64)) } } } @@ -125,7 +125,7 @@ where fn try_into_js(&self, context: &mut Context) -> JsResult { match self { Some(x) => x.try_into_js(context), - None => JsResult::Ok(JsValue::Null), + None => Ok(JsValue::Undefined), } } } @@ -140,7 +140,7 @@ where let value = value.try_into_js(context)?; arr.push(value, context)?; } - JsResult::Ok(arr.into()) + Ok(arr.into()) } } @@ -151,7 +151,7 @@ macro_rules! impl_try_into_js_for_tuples { let ($($names,)+) = self; let arr = crate::object::JsArray::new(context); $(arr.push($names.try_into_js(context)?, context)?;)+ - JsResult::Ok(arr.into()) + Ok(arr.into()) } } }; @@ -171,7 +171,7 @@ impl_try_into_js_for_tuples!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: impl TryIntoJs for () { fn try_into_js(&self, _context: &mut Context) -> JsResult { - JsResult::Ok(JsValue::Null) + Ok(JsValue::Null) } } @@ -185,7 +185,7 @@ where let value = value.try_into_js(context)?; set.add(value, context)?; } - JsResult::Ok(set.into()) + Ok(set.into()) } } @@ -201,7 +201,7 @@ where let value = value.try_into_js(context)?; map.set(key, value, context)?; } - JsResult::Ok(map.into()) + Ok(map.into()) } } From 93192765afb31f64505fac6d02a4e9049007f941 Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:32:26 -0600 Subject: [PATCH 17/72] Patch the indentation on nightly_build.yml (#4028) --- .github/workflows/nightly_build.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index 30d6fc5832f..0c19abd9645 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -9,14 +9,12 @@ on: jobs: build: runs-on: ubuntu-latest - steps: - name: Check out the repository uses: actions/checkout@v4 - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: + uses: dtolnay/rust-toolchain@stable + with: toolchain: stable - name: Install Dependencies @@ -28,14 +26,14 @@ jobs: cargo build --release - name: Set File Name - id: vars - run: | - DATE=$(date +'%Y%m%d') - COMMIT_HASH=$(git rev-parse --short HEAD) - echo "FILE_NAME=boa-nightly-linux-${DATE}-${COMMIT_HASH}" >> $GITHUB_ENV + id: vars + run: | + DATE=$(date +'%Y%m%d') + COMMIT_HASH=$(git rev-parse --short HEAD) + echo "FILE_NAME=boa-nightly-linux-${DATE}-${COMMIT_HASH}" >> $GITHUB_ENV - name: Rename Binary - run: mv target/release/boa target/release/$FILE_NAME + run: mv target/release/boa target/release/$FILE_NAME - name: Upload binaries to release uses: svenstaro/upload-release-action@v2 From 5ea44d8c4015330d57c2e7c00007d2102db28350 Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:16:07 -0600 Subject: [PATCH 18/72] Wrap the mv command in quotations and add echo for testing (#4032) --- .github/workflows/nightly_build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index 0c19abd9645..e0a3c8ed77d 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -32,8 +32,10 @@ jobs: COMMIT_HASH=$(git rev-parse --short HEAD) echo "FILE_NAME=boa-nightly-linux-${DATE}-${COMMIT_HASH}" >> $GITHUB_ENV - - name: Rename Binary - run: mv target/release/boa target/release/$FILE_NAME + - name: Rename binary to file name + run: | + echo "Renaming binary to $FILE_NAME" + mv target/release/boa "target/release/$FILE_NAME" - name: Upload binaries to release uses: svenstaro/upload-release-action@v2 From f30514b0854af6970fc6eab45886eec1b9ded28b Mon Sep 17 00:00:00 2001 From: CrazyboyQCD <53971641+CrazyboyQCD@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:05:54 +0800 Subject: [PATCH 19/72] Some string optimizations (#4030) * chore: replace `js_str` with `js_string` * chore: replace `boolean`'s `to_string` with literal * chore: remove unnecessary `to_string` * chore: fix lint and format * chore: add feature gate to import `js_str` * chore: change `get_typed_fn`'s name to `JsString` * chore: replace js_str with js_string(cli) * chore: replace js_str with js_string(`try_into_js`) * chore: replace js_str with js_string(`Console`) * chore: fix lint * perf: use more efficient `LazyLock` on `RAW_STATICS_CACHE` * chore: move `js_str` together with other imports --- cli/src/debug/function.rs | 9 +- cli/src/debug/limits.rs | 20 ++-- cli/src/debug/mod.rs | 20 ++-- cli/src/debug/optimizer.rs | 6 +- .../src/builtins/array/array_iterator.rs | 3 +- core/engine/src/builtins/array/mod.rs | 39 ++++--- .../src/builtins/async_generator/mod.rs | 4 +- core/engine/src/builtins/atomics/mod.rs | 7 +- core/engine/src/builtins/boolean/mod.rs | 6 +- core/engine/src/builtins/builder.rs | 12 +- core/engine/src/builtins/error/aggregate.rs | 9 +- core/engine/src/builtins/error/eval.rs | 7 +- core/engine/src/builtins/error/mod.rs | 8 +- core/engine/src/builtins/error/range.rs | 7 +- core/engine/src/builtins/error/reference.rs | 7 +- core/engine/src/builtins/error/syntax.rs | 7 +- core/engine/src/builtins/error/type.rs | 9 +- core/engine/src/builtins/error/uri.rs | 7 +- core/engine/src/builtins/function/mod.rs | 6 +- core/engine/src/builtins/intl/collator/mod.rs | 48 ++++---- .../src/builtins/intl/date_time_format.rs | 39 ++++--- .../src/builtins/intl/list_format/mod.rs | 30 ++--- core/engine/src/builtins/intl/locale/mod.rs | 19 ++-- core/engine/src/builtins/intl/locale/utils.rs | 3 +- .../src/builtins/intl/number_format/mod.rs | 14 +-- .../builtins/intl/number_format/options.rs | 30 ++--- core/engine/src/builtins/intl/options.rs | 4 +- .../src/builtins/intl/plural_rules/mod.rs | 60 +++++----- .../engine/src/builtins/intl/segmenter/mod.rs | 18 +-- .../iterable/async_from_sync_iterator.rs | 11 +- core/engine/src/builtins/iterable/mod.rs | 10 +- core/engine/src/builtins/json/mod.rs | 8 +- core/engine/src/builtins/map/mod.rs | 3 +- core/engine/src/builtins/mod.rs | 10 +- core/engine/src/builtins/number/mod.rs | 11 +- core/engine/src/builtins/object/mod.rs | 18 +-- core/engine/src/builtins/options.rs | 4 +- core/engine/src/builtins/promise/mod.rs | 36 +++--- core/engine/src/builtins/proxy/mod.rs | 31 +++--- core/engine/src/builtins/regexp/mod.rs | 104 ++++++++++-------- .../builtins/regexp/regexp_string_iterator.rs | 5 +- core/engine/src/builtins/set/mod.rs | 3 +- core/engine/src/builtins/string/mod.rs | 13 ++- .../src/builtins/temporal/calendar/mod.rs | 4 +- .../src/builtins/temporal/duration/mod.rs | 35 +++--- .../src/builtins/temporal/instant/mod.rs | 17 ++- core/engine/src/builtins/temporal/mod.rs | 9 +- core/engine/src/builtins/temporal/options.rs | 16 +-- .../src/builtins/temporal/plain_date/mod.rs | 41 ++++--- .../builtins/temporal/plain_date_time/mod.rs | 70 ++++++------ .../builtins/temporal/plain_month_day/mod.rs | 14 +-- .../src/builtins/temporal/plain_time/mod.rs | 45 ++++---- .../builtins/temporal/plain_year_month/mod.rs | 21 ++-- .../src/builtins/typed_array/builtin.rs | 4 +- core/engine/src/builtins/typed_array/mod.rs | 5 +- core/engine/src/builtins/weak_map/mod.rs | 3 +- core/engine/src/builtins/weak_set/mod.rs | 3 +- core/engine/src/class.rs | 8 +- core/engine/src/context/intrinsics.rs | 19 ++-- core/engine/src/context/mod.rs | 16 +-- core/engine/src/error.rs | 21 ++-- core/engine/src/module/mod.rs | 6 +- core/engine/src/object/builtins/jsdate.rs | 4 +- core/engine/src/object/builtins/jsmap.rs | 64 +++++------ core/engine/src/object/builtins/jspromise.rs | 12 +- core/engine/src/object/builtins/jsproxy.rs | 28 ++--- core/engine/src/object/jsobject.rs | 17 ++- core/engine/src/object/mod.rs | 9 +- .../src/value/conversions/try_into_js.rs | 3 +- core/engine/src/value/display.rs | 8 +- core/engine/src/value/mod.rs | 32 +++--- core/engine/src/value/tests.rs | 1 + core/engine/src/vm/mod.rs | 3 +- core/engine/src/vm/opcode/await/mod.rs | 6 +- core/engine/src/vm/opcode/generator/mod.rs | 6 +- core/engine/src/vm/opcode/iteration/for_in.rs | 4 +- .../src/vm/opcode/iteration/iterator.rs | 7 +- .../src/vm/opcode/push/class/private.rs | 2 +- core/engine/src/vm/opcode/templates/mod.rs | 4 +- core/engine/tests/gcd.rs | 4 +- core/interop/tests/fibonacci.rs | 4 +- core/interop/tests/gcd_callback.rs | 4 +- core/macros/src/lib.rs | 2 +- core/runtime/src/console/mod.rs | 6 +- core/runtime/src/console/tests.rs | 2 +- core/string/src/common.rs | 27 ++--- examples/src/bin/loadfile.rs | 4 +- 87 files changed, 679 insertions(+), 666 deletions(-) diff --git a/cli/src/debug/function.rs b/cli/src/debug/function.rs index 71326c1294c..8337ba708b7 100644 --- a/cli/src/debug/function.rs +++ b/cli/src/debug/function.rs @@ -1,6 +1,6 @@ use boa_engine::{ builtins::function::OrdinaryFunction, - js_str, js_string, + js_string, object::ObjectInitializer, vm::flowgraph::{Direction, Graph}, Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction, @@ -68,9 +68,10 @@ fn flowgraph(_this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResu let mut direction = Direction::LeftToRight; if let Some(arguments) = args.get(1) { if let Some(arguments) = arguments.as_object() { - format = flowgraph_parse_format_option(&arguments.get(js_str!("format"), context)?)?; - direction = - flowgraph_parse_direction_option(&arguments.get(js_str!("direction"), context)?)?; + format = flowgraph_parse_format_option(&arguments.get(js_string!("format"), context)?)?; + direction = flowgraph_parse_direction_option( + &arguments.get(js_string!("direction"), context)?, + )?; } else if value.is_string() { format = flowgraph_parse_format_option(value)?; } else { diff --git a/cli/src/debug/limits.rs b/cli/src/debug/limits.rs index e2be688c745..b73e7a45fa5 100644 --- a/cli/src/debug/limits.rs +++ b/cli/src/debug/limits.rs @@ -1,5 +1,5 @@ use boa_engine::{ - js_str, + js_string, object::{FunctionObjectBuilder, ObjectInitializer}, property::Attribute, Context, JsArgs, JsNativeError, JsObject, JsResult, JsValue, NativeFunction, @@ -51,51 +51,51 @@ fn set_recursion(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResu pub(super) fn create_object(context: &mut Context) -> JsObject { let get_loop = FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_loop)) - .name(js_str!("get loop")) + .name(js_string!("get loop")) .length(0) .build(); let set_loop = FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_loop)) - .name(js_str!("set loop")) + .name(js_string!("set loop")) .length(1) .build(); let get_stack = FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_stack)) - .name(js_str!("get stack")) + .name(js_string!("get stack")) .length(0) .build(); let set_stack = FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_stack)) - .name(js_str!("set stack")) + .name(js_string!("set stack")) .length(1) .build(); let get_recursion = FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(get_recursion)) - .name(js_str!("get recursion")) + .name(js_string!("get recursion")) .length(0) .build(); let set_recursion = FunctionObjectBuilder::new(context.realm(), NativeFunction::from_fn_ptr(set_recursion)) - .name(js_str!("set recursion")) + .name(js_string!("set recursion")) .length(1) .build(); ObjectInitializer::new(context) .accessor( - js_str!("loop"), + js_string!("loop"), Some(get_loop), Some(set_loop), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, ) .accessor( - js_str!("stack"), + js_string!("stack"), Some(get_stack), Some(set_stack), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, ) .accessor( - js_str!("recursion"), + js_string!("recursion"), Some(get_recursion), Some(set_recursion), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, diff --git a/cli/src/debug/mod.rs b/cli/src/debug/mod.rs index a093f76a40a..03b4f99d1d2 100644 --- a/cli/src/debug/mod.rs +++ b/cli/src/debug/mod.rs @@ -1,7 +1,7 @@ // Allow lint so it, doesn't warn about `JsResult<>` unneeded return on functions. #![allow(clippy::unnecessary_wraps)] -use boa_engine::{js_str, object::ObjectInitializer, property::Attribute, Context, JsObject}; +use boa_engine::{js_string, object::ObjectInitializer, property::Attribute, Context, JsObject}; mod function; mod gc; @@ -24,42 +24,42 @@ fn create_boa_object(context: &mut Context) -> JsObject { ObjectInitializer::new(context) .property( - js_str!("function"), + js_string!("function"), function_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - js_str!("object"), + js_string!("object"), object_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - js_str!("shape"), + js_string!("shape"), shape_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - js_str!("optimizer"), + js_string!("optimizer"), optimizer_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - js_str!("gc"), + js_string!("gc"), gc_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - js_str!("realm"), + js_string!("realm"), realm_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - js_str!("limits"), + js_string!("limits"), limits_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) .property( - js_str!("string"), + js_string!("string"), string_module, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) @@ -71,7 +71,7 @@ pub(crate) fn init_boa_debug_object(context: &mut Context) { let boa_object = create_boa_object(context); context .register_global_property( - js_str!("$boa"), + js_string!("$boa"), boa_object, Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ) diff --git a/cli/src/debug/optimizer.rs b/cli/src/debug/optimizer.rs index fdb93e17ec9..92793e93ba0 100644 --- a/cli/src/debug/optimizer.rs +++ b/cli/src/debug/optimizer.rs @@ -1,5 +1,5 @@ use boa_engine::{ - js_str, + js_string, object::{FunctionObjectBuilder, ObjectInitializer}, optimizer::OptimizerOptions, property::Attribute, @@ -64,13 +64,13 @@ pub(super) fn create_object(context: &mut Context) -> JsObject { .build(); ObjectInitializer::new(context) .accessor( - js_str!("constantFolding"), + js_string!("constantFolding"), Some(get_constant_folding), Some(set_constant_folding), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, ) .accessor( - js_str!("statistics"), + js_string!("statistics"), Some(get_statistics), Some(set_statistics), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::NON_ENUMERABLE, diff --git a/core/engine/src/builtins/array/array_iterator.rs b/core/engine/src/builtins/array/array_iterator.rs index 70393e93406..d323a7ad60a 100644 --- a/core/engine/src/builtins/array/array_iterator.rs +++ b/core/engine/src/builtins/array/array_iterator.rs @@ -20,7 +20,6 @@ use crate::{ Context, JsData, JsResult, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; /// The Array Iterator object represents an iteration over an array. It implements the iterator protocol. @@ -53,7 +52,7 @@ impl IntrinsicObject for ArrayIterator { .static_method(Self::next, js_string!("next"), 0) .static_property( JsSymbol::to_string_tag(), - js_str!("Array Iterator"), + js_string!("Array Iterator"), Attribute::CONFIGURABLE, ) .build(); diff --git a/core/engine/src/builtins/array/mod.rs b/core/engine/src/builtins/array/mod.rs index 4eda932d08e..f392efbe74f 100644 --- a/core/engine/src/builtins/array/mod.rs +++ b/core/engine/src/builtins/array/mod.rs @@ -10,7 +10,6 @@ //! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use thin_vec::ThinVec; @@ -2169,12 +2168,12 @@ impl Array { #[cfg(feature = "intl")] { // TODO: this should eventually return a locale-sensitive separator. - js_str!(", ") + js_string!(", ") } #[cfg(not(feature = "intl"))] { - js_str!(", ") + js_string!(", ") } }; @@ -2197,7 +2196,7 @@ impl Array { if !next.is_null_or_undefined() { // i. Let S be ? ToString(? Invoke(nextElement, "toLocaleString", « locales, options »)). let s = next - .invoke(js_str!("toLocaleString"), args, context)? + .invoke(js_string!("toLocaleString"), args, context)? .to_string(context)?; // ii. Set R to the string-concatenation of R and S. @@ -3258,37 +3257,37 @@ impl Array { { let mut obj = unscopable_list.borrow_mut(); // 2. Perform ! CreateDataPropertyOrThrow(unscopableList, "at", true). - obj.insert(js_str!("at"), true_prop.clone()); + obj.insert(js_string!("at"), true_prop.clone()); // 3. Perform ! CreateDataPropertyOrThrow(unscopableList, "copyWithin", true). - obj.insert(js_str!("copyWithin"), true_prop.clone()); + obj.insert(js_string!("copyWithin"), true_prop.clone()); // 4. Perform ! CreateDataPropertyOrThrow(unscopableList, "entries", true). - obj.insert(js_str!("entries"), true_prop.clone()); + obj.insert(js_string!("entries"), true_prop.clone()); // 5. Perform ! CreateDataPropertyOrThrow(unscopableList, "fill", true). - obj.insert(js_str!("fill"), true_prop.clone()); + obj.insert(js_string!("fill"), true_prop.clone()); // 6. Perform ! CreateDataPropertyOrThrow(unscopableList, "find", true). - obj.insert(js_str!("find"), true_prop.clone()); + obj.insert(js_string!("find"), true_prop.clone()); // 7. Perform ! CreateDataPropertyOrThrow(unscopableList, "findIndex", true). - obj.insert(js_str!("findIndex"), true_prop.clone()); + obj.insert(js_string!("findIndex"), true_prop.clone()); // 8. Perform ! CreateDataPropertyOrThrow(unscopableList, "findLast", true). - obj.insert(js_str!("findLast"), true_prop.clone()); + obj.insert(js_string!("findLast"), true_prop.clone()); // 9. Perform ! CreateDataPropertyOrThrow(unscopableList, "findLastIndex", true). - obj.insert(js_str!("findLastIndex"), true_prop.clone()); + obj.insert(js_string!("findLastIndex"), true_prop.clone()); // 10. Perform ! CreateDataPropertyOrThrow(unscopableList, "flat", true). - obj.insert(js_str!("flat"), true_prop.clone()); + obj.insert(js_string!("flat"), true_prop.clone()); // 11. Perform ! CreateDataPropertyOrThrow(unscopableList, "flatMap", true). - obj.insert(js_str!("flatMap"), true_prop.clone()); + obj.insert(js_string!("flatMap"), true_prop.clone()); // 12. Perform ! CreateDataPropertyOrThrow(unscopableList, "includes", true). - obj.insert(js_str!("includes"), true_prop.clone()); + obj.insert(js_string!("includes"), true_prop.clone()); // 13. Perform ! CreateDataPropertyOrThrow(unscopableList, "keys", true). - obj.insert(js_str!("keys"), true_prop.clone()); + obj.insert(js_string!("keys"), true_prop.clone()); // 14. Perform ! CreateDataPropertyOrThrow(unscopableList, "toReversed", true). - obj.insert(js_str!("toReversed"), true_prop.clone()); + obj.insert(js_string!("toReversed"), true_prop.clone()); // 15. Perform ! CreateDataPropertyOrThrow(unscopableList, "toSorted", true). - obj.insert(js_str!("toSorted"), true_prop.clone()); + obj.insert(js_string!("toSorted"), true_prop.clone()); // 16. Perform ! CreateDataPropertyOrThrow(unscopableList, "toSpliced", true). - obj.insert(js_str!("toSpliced"), true_prop.clone()); + obj.insert(js_string!("toSpliced"), true_prop.clone()); // 17. Perform ! CreateDataPropertyOrThrow(unscopableList, "values", true). - obj.insert(js_str!("values"), true_prop); + obj.insert(js_string!("values"), true_prop); } // 13. Return unscopableList. diff --git a/core/engine/src/builtins/async_generator/mod.rs b/core/engine/src/builtins/async_generator/mod.rs index 23b6966fc0a..6ec1f0872b5 100644 --- a/core/engine/src/builtins/async_generator/mod.rs +++ b/core/engine/src/builtins/async_generator/mod.rs @@ -561,7 +561,7 @@ impl AsyncGenerator { generator.clone(), ), ) - .name(js_string!("")) + .name(js_string!()) .length(1) .build(); @@ -592,7 +592,7 @@ impl AsyncGenerator { generator.clone(), ), ) - .name(js_string!("")) + .name(js_string!()) .length(1) .build(); diff --git a/core/engine/src/builtins/atomics/mod.rs b/core/engine/src/builtins/atomics/mod.rs index 95ac36996ac..98c98cf5804 100644 --- a/core/engine/src/builtins/atomics/mod.rs +++ b/core/engine/src/builtins/atomics/mod.rs @@ -21,7 +21,6 @@ use crate::{ JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{ @@ -468,9 +467,9 @@ impl Atomics { }; Ok(match result { - futex::AtomicsWaitResult::NotEqual => js_str!("not-equal"), - futex::AtomicsWaitResult::TimedOut => js_str!("timed-out"), - futex::AtomicsWaitResult::Ok => js_str!("ok"), + futex::AtomicsWaitResult::NotEqual => js_string!("not-equal"), + futex::AtomicsWaitResult::TimedOut => js_string!("timed-out"), + futex::AtomicsWaitResult::Ok => js_string!("ok"), } .into()) } diff --git a/core/engine/src/builtins/boolean/mod.rs b/core/engine/src/builtins/boolean/mod.rs index bd0766a918b..117703a2b27 100644 --- a/core/engine/src/builtins/boolean/mod.rs +++ b/core/engine/src/builtins/boolean/mod.rs @@ -112,7 +112,11 @@ impl Boolean { #[allow(clippy::wrong_self_convention)] pub(crate) fn to_string(this: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult { let boolean = Self::this_boolean_value(this)?; - Ok(JsValue::new(js_string!(boolean.to_string()))) + Ok(JsValue::new(if boolean { + js_string!("true") + } else { + js_string!("false") + })) } /// The `valueOf()` method returns the primitive value of a `Boolean` object. diff --git a/core/engine/src/builtins/builder.rs b/core/engine/src/builtins/builder.rs index 5411a1888df..4533190da65 100644 --- a/core/engine/src/builtins/builder.rs +++ b/core/engine/src/builtins/builder.rs @@ -1,5 +1,3 @@ -use boa_macros::js_str; - use crate::{ js_string, native_function::{NativeFunctionObject, NativeFunctionPointer}, @@ -119,7 +117,7 @@ impl ApplyToObject for Callable { .configurable(true), ); object.insert( - js_str!("name"), + js_string!("name"), PropertyDescriptor::builder() .value(self.name) .writable(false) @@ -368,8 +366,8 @@ impl BuiltInConstructorWithPrototype<'_> { let length = self.length; let name = self.name.clone(); let prototype = self.prototype.clone(); - self = self.static_property(js_str!("length"), length, Attribute::CONFIGURABLE); - self = self.static_property(js_str!("name"), name, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("length"), length, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("name"), name, Attribute::CONFIGURABLE); self = self.static_property(PROTOTYPE, prototype, Attribute::empty()); let attributes = self.attributes; @@ -416,8 +414,8 @@ impl BuiltInConstructorWithPrototype<'_> { pub(crate) fn build_without_prototype(mut self) { let length = self.length; let name = self.name.clone(); - self = self.static_property(js_str!("length"), length, Attribute::CONFIGURABLE); - self = self.static_property(js_str!("name"), name, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("length"), length, Attribute::CONFIGURABLE); + self = self.static_property(js_string!("name"), name, Attribute::CONFIGURABLE); let mut object = self.object.borrow_mut(); let function = object diff --git a/core/engine/src/builtins/error/aggregate.rs b/core/engine/src/builtins/error/aggregate.rs index ddde1683c1b..892bba7f4d0 100644 --- a/core/engine/src/builtins/error/aggregate.rs +++ b/core/engine/src/builtins/error/aggregate.rs @@ -20,7 +20,6 @@ use crate::{ string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{Error, ErrorObject}; @@ -36,8 +35,8 @@ impl IntrinsicObject for AggregateError { BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(js_str!("name"), Self::NAME, attribute) - .property(js_str!("message"), js_string!(), attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -102,7 +101,7 @@ impl BuiltInConstructor for AggregateError { let msg = message.to_string(context)?; // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). - o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); + o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context); } // 4. Perform ? InstallErrorCause(O, options). @@ -122,7 +121,7 @@ impl BuiltInConstructor for AggregateError { // [[Value]]: CreateArrayFromList(errorsList) // }). o.define_property_or_throw( - js_str!("errors"), + js_string!("errors"), PropertyDescriptorBuilder::new() .configurable(true) .enumerable(false) diff --git a/core/engine/src/builtins/error/eval.rs b/core/engine/src/builtins/error/eval.rs index 360638cc7f7..df2715bf7fe 100644 --- a/core/engine/src/builtins/error/eval.rs +++ b/core/engine/src/builtins/error/eval.rs @@ -21,7 +21,6 @@ use crate::{ string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{Error, ErrorObject}; @@ -38,8 +37,8 @@ impl IntrinsicObject for EvalError { BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(js_str!("name"), Self::NAME, attribute) - .property(js_str!("message"), js_string!(), attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -97,7 +96,7 @@ impl BuiltInConstructor for EvalError { let msg = message.to_string(context)?; // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). - o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); + o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context); } // 4. Perform ? InstallErrorCause(O, options). diff --git a/core/engine/src/builtins/error/mod.rs b/core/engine/src/builtins/error/mod.rs index 2e22e17904c..7eb85b9c646 100644 --- a/core/engine/src/builtins/error/mod.rs +++ b/core/engine/src/builtins/error/mod.rs @@ -214,9 +214,9 @@ impl Error { // 1. If Type(options) is Object and ? HasProperty(options, "cause") is true, then // 1.a. Let cause be ? Get(options, "cause"). if let Some(options) = options.as_object() { - if let Some(cause) = options.try_get(js_str!("cause"), context)? { + if let Some(cause) = options.try_get(js_string!("cause"), context)? { // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause). - o.create_non_enumerable_data_property_or_throw(js_str!("cause"), cause, context); + o.create_non_enumerable_data_property_or_throw(js_string!("cause"), cause, context); } } @@ -247,7 +247,7 @@ impl Error { .ok_or_else(|| JsNativeError::typ().with_message("'this' is not an Object"))?; // 3. Let name be ? Get(O, "name"). - let name = o.get(js_str!("name"), context)?; + let name = o.get(js_string!("name"), context)?; // 4. If name is undefined, set name to "Error"; otherwise set name to ? ToString(name). let name = if name.is_undefined() { @@ -257,7 +257,7 @@ impl Error { }; // 5. Let msg be ? Get(O, "message"). - let msg = o.get(js_str!("message"), context)?; + let msg = o.get(js_string!("message"), context)?; // 6. If msg is undefined, set msg to the empty String; otherwise set msg to ? ToString(msg). let msg = if msg.is_undefined() { diff --git a/core/engine/src/builtins/error/range.rs b/core/engine/src/builtins/error/range.rs index 37278ae8267..59f6ab4eae7 100644 --- a/core/engine/src/builtins/error/range.rs +++ b/core/engine/src/builtins/error/range.rs @@ -19,7 +19,6 @@ use crate::{ string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{Error, ErrorObject}; @@ -36,8 +35,8 @@ impl IntrinsicObject for RangeError { BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(js_str!("name"), Self::NAME, attribute) - .property(js_str!("message"), js_string!(), attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -95,7 +94,7 @@ impl BuiltInConstructor for RangeError { let msg = message.to_string(context)?; // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). - o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); + o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context); } // 4. Perform ? InstallErrorCause(O, options). diff --git a/core/engine/src/builtins/error/reference.rs b/core/engine/src/builtins/error/reference.rs index a16c77c3db6..b10e1ef761c 100644 --- a/core/engine/src/builtins/error/reference.rs +++ b/core/engine/src/builtins/error/reference.rs @@ -19,7 +19,6 @@ use crate::{ string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{Error, ErrorObject}; @@ -35,8 +34,8 @@ impl IntrinsicObject for ReferenceError { BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(js_str!("name"), Self::NAME, attribute) - .property(js_str!("message"), js_string!(), attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -97,7 +96,7 @@ impl BuiltInConstructor for ReferenceError { let msg = message.to_string(context)?; // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). - o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); + o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context); } // 4. Perform ? InstallErrorCause(O, options). diff --git a/core/engine/src/builtins/error/syntax.rs b/core/engine/src/builtins/error/syntax.rs index 9ac489dc713..fddc1e558e5 100644 --- a/core/engine/src/builtins/error/syntax.rs +++ b/core/engine/src/builtins/error/syntax.rs @@ -21,7 +21,6 @@ use crate::{ string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{Error, ErrorObject}; @@ -38,8 +37,8 @@ impl IntrinsicObject for SyntaxError { BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(js_str!("name"), Self::NAME, attribute) - .property(js_str!("message"), js_string!(), attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -100,7 +99,7 @@ impl BuiltInConstructor for SyntaxError { let msg = message.to_string(context)?; // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). - o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); + o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context); } // 4. Perform ? InstallErrorCause(O, options). diff --git a/core/engine/src/builtins/error/type.rs b/core/engine/src/builtins/error/type.rs index c0e8397ca26..1e7fbd3befa 100644 --- a/core/engine/src/builtins/error/type.rs +++ b/core/engine/src/builtins/error/type.rs @@ -27,7 +27,6 @@ use crate::{ string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, NativeFunction, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{Error, ErrorObject}; @@ -44,8 +43,8 @@ impl IntrinsicObject for TypeError { BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(js_str!("name"), Self::NAME, attribute) - .property(js_str!("message"), js_string!(), attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -103,7 +102,7 @@ impl BuiltInConstructor for TypeError { let msg = message.to_string(context)?; // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). - o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); + o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context); } // 4. Perform ? InstallErrorCause(O, options). @@ -122,7 +121,7 @@ impl IntrinsicObject for ThrowTypeError { let obj = BuiltInBuilder::with_intrinsic::(realm) .prototype(realm.intrinsics().constructors().function().prototype()) .static_property(StaticJsStrings::LENGTH, 0, Attribute::empty()) - .static_property(js_str!("name"), js_string!(), Attribute::empty()) + .static_property(js_string!("name"), js_string!(), Attribute::empty()) .build(); let mut obj = obj.borrow_mut(); diff --git a/core/engine/src/builtins/error/uri.rs b/core/engine/src/builtins/error/uri.rs index 113ccebea21..6f1eaed5a2b 100644 --- a/core/engine/src/builtins/error/uri.rs +++ b/core/engine/src/builtins/error/uri.rs @@ -20,7 +20,6 @@ use crate::{ string::StaticJsStrings, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use super::{Error, ErrorObject}; @@ -37,8 +36,8 @@ impl IntrinsicObject for UriError { BuiltInBuilder::from_standard_constructor::(realm) .prototype(realm.intrinsics().constructors().error().constructor()) .inherits(Some(realm.intrinsics().constructors().error().prototype())) - .property(js_str!("name"), Self::NAME, attribute) - .property(js_str!("message"), js_string!(), attribute) + .property(js_string!("name"), Self::NAME, attribute) + .property(js_string!("message"), js_string!(), attribute) .build(); } @@ -96,7 +95,7 @@ impl BuiltInConstructor for UriError { let msg = message.to_string(context)?; // b. Perform CreateNonEnumerableDataPropertyOrThrow(O, "message", msg). - o.create_non_enumerable_data_property_or_throw(js_str!("message"), msg, context); + o.create_non_enumerable_data_property_or_throw(js_string!("message"), msg, context); } // 4. Perform ? InstallErrorCause(O, options). diff --git a/core/engine/src/builtins/function/mod.rs b/core/engine/src/builtins/function/mod.rs index 0ff46d988aa..bd662fe4d7c 100644 --- a/core/engine/src/builtins/function/mod.rs +++ b/core/engine/src/builtins/function/mod.rs @@ -776,7 +776,7 @@ impl BuiltInFunctionObject { .expect("defining the `length` property for a new object should not fail"); // 8. Let targetName be ? Get(Target, "name"). - let target_name = target.get(js_str!("name"), context)?; + let target_name = target.get(js_string!("name"), context)?; // 9. If Type(targetName) is not String, set targetName to the empty String. let target_name = target_name @@ -849,7 +849,7 @@ impl BuiltInFunctionObject { let name = { // Is there a case here where if there is no name field on a value // name should default to None? Do all functions have names set? - let value = object.get(js_str!("name"), &mut *context)?; + let value = object.get(js_string!("name"), &mut *context)?; if value.is_null_or_undefined() { js_string!() } else { @@ -943,7 +943,7 @@ pub(crate) fn set_function_name( // [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }). function .define_property_or_throw( - js_str!("name"), + js_string!("name"), PropertyDescriptor::builder() .value(name) .writable(false) diff --git a/core/engine/src/builtins/intl/collator/mod.rs b/core/engine/src/builtins/intl/collator/mod.rs index 24520950ef7..a18afb1b431 100644 --- a/core/engine/src/builtins/intl/collator/mod.rs +++ b/core/engine/src/builtins/intl/collator/mod.rs @@ -1,5 +1,4 @@ use boa_gc::{custom_trace, Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use icu_collator::{ provider::CollationMetadataV1Marker, AlternateHandling, CaseFirst, MaxVariable, Numeric, @@ -243,28 +242,29 @@ impl BuiltInConstructor for Collator { // a. Let localeData be %Collator%.[[SortLocaleData]]. // 6. Else, // a. Let localeData be %Collator%.[[SearchLocaleData]]. - let usage = get_option(&options, js_str!("usage"), context)?.unwrap_or_default(); + let usage = get_option(&options, js_string!("usage"), context)?.unwrap_or_default(); // 7. Let opt be a new Record. // 8. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 9. Set opt.[[localeMatcher]] to matcher. - let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); + let matcher = + get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 10. Let collation be ? GetOption(options, "collation", string, empty, undefined). // 11. If collation is not undefined, then // a. If collation does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. // 12. Set opt.[[co]] to collation. - let collation = get_option(&options, js_str!("collation"), context)?; + let collation = get_option(&options, js_string!("collation"), context)?; // 13. Let numeric be ? GetOption(options, "numeric", boolean, empty, undefined). // 14. If numeric is not undefined, then // a. Let numeric be ! ToString(numeric). // 15. Set opt.[[kn]] to numeric. - let numeric = get_option(&options, js_str!("numeric"), context)?; + let numeric = get_option(&options, js_string!("numeric"), context)?; // 16. Let caseFirst be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined). // 17. Set opt.[[kf]] to caseFirst. - let case_first = get_option(&options, js_str!("caseFirst"), context)?; + let case_first = get_option(&options, js_string!("caseFirst"), context)?; let mut intl_options = IntlOptions { matcher, @@ -316,7 +316,7 @@ impl BuiltInConstructor for Collator { // 26. Let sensitivity be ? GetOption(options, "sensitivity", string, « "base", "accent", "case", "variant" », undefined). // 28. Set collator.[[Sensitivity]] to sensitivity. - let sensitivity = get_option(&options, js_str!("sensitivity"), context)? + let sensitivity = get_option(&options, js_string!("sensitivity"), context)? // 27. If sensitivity is undefined, then // a. If usage is "sort", then // i. Let sensitivity be "variant". @@ -329,7 +329,7 @@ impl BuiltInConstructor for Collator { // 29. Let ignorePunctuation be ? GetOption(options, "ignorePunctuation", boolean, empty, false). // 30. Set collator.[[IgnorePunctuation]] to ignorePunctuation. let ignore_punctuation: bool = - get_option(&options, js_str!("ignorePunctuation"), context)?.unwrap_or_default(); + get_option(&options, js_string!("ignorePunctuation"), context)?.unwrap_or_default(); let (strength, case_level) = sensitivity.map(Sensitivity::to_collator_options).unzip(); @@ -523,58 +523,58 @@ impl Collator { // 5. Return options. options .create_data_property_or_throw( - js_str!("locale"), + js_string!("locale"), js_string!(collator.locale.to_string()), context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - js_str!("usage"), + js_string!("usage"), match collator.usage { - Usage::Search => js_str!("search"), - Usage::Sort => js_str!("sort"), + Usage::Search => js_string!("search"), + Usage::Sort => js_string!("sort"), }, context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - js_str!("sensitivity"), + js_string!("sensitivity"), match collator.sensitivity { - Sensitivity::Base => js_str!("base"), - Sensitivity::Accent => js_str!("accent"), - Sensitivity::Case => js_str!("case"), - Sensitivity::Variant => js_str!("variant"), + Sensitivity::Base => js_string!("base"), + Sensitivity::Accent => js_string!("accent"), + Sensitivity::Case => js_string!("case"), + Sensitivity::Variant => js_string!("variant"), }, context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - js_str!("ignorePunctuation"), + js_string!("ignorePunctuation"), collator.ignore_punctuation, context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - js_str!("collation"), + js_string!("collation"), js_string!(collator.collation.to_string()), context, ) .expect("operation must not fail per the spec"); options - .create_data_property_or_throw(js_str!("numeric"), collator.numeric, context) + .create_data_property_or_throw(js_string!("numeric"), collator.numeric, context) .expect("operation must not fail per the spec"); if let Some(kf) = collator.case_first { options .create_data_property_or_throw( - js_str!("caseFirst"), + js_string!("caseFirst"), match kf { - CaseFirst::Off => js_str!("false"), - CaseFirst::LowerFirst => js_str!("lower"), - CaseFirst::UpperFirst => js_str!("upper"), + CaseFirst::Off => js_string!("false"), + CaseFirst::LowerFirst => js_string!("lower"), + CaseFirst::UpperFirst => js_string!("upper"), _ => unreachable!(), }, context, diff --git a/core/engine/src/builtins/intl/date_time_format.rs b/core/engine/src/builtins/intl/date_time_format.rs index 69cd896d8c4..426b34ff7d0 100644 --- a/core/engine/src/builtins/intl/date_time_format.rs +++ b/core/engine/src/builtins/intl/date_time_format.rs @@ -22,7 +22,6 @@ use crate::{ }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use icu_datetime::options::preferences::HourCycle; @@ -142,8 +141,8 @@ impl BuiltInConstructor for DateTimeFormat { hour: js_string!("numeric"), minute: js_string!("numeric"), second: js_string!("numeric"), - fractional_second_digits: js_string!(""), - time_zone_name: js_string!(""), + fractional_second_digits: js_string!(), + time_zone_name: js_string!(), hour_cycle: js_string!("h24"), pattern: js_string!("{hour}:{minute}"), bound_format: js_string!("undefined"), @@ -208,10 +207,10 @@ pub(crate) fn to_date_time_options( if [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(required) { // a. For each property name prop of « "weekday", "year", "month", "day" », do for property in [ - js_str!("weekday"), - js_str!("year"), - js_str!("month"), - js_str!("day"), + js_string!("weekday"), + js_string!("year"), + js_string!("month"), + js_string!("day"), ] { // i. Let value be ? Get(options, prop). let value = options.get(property, context)?; @@ -228,11 +227,11 @@ pub(crate) fn to_date_time_options( // a. For each property name prop of « "dayPeriod", "hour", "minute", "second", // "fractionalSecondDigits" », do for property in [ - js_str!("dayPeriod"), - js_str!("hour"), - js_str!("minute"), - js_str!("second"), - js_str!("fractionalSecondDigits"), + js_string!("dayPeriod"), + js_string!("hour"), + js_string!("minute"), + js_string!("second"), + js_string!("fractionalSecondDigits"), ] { // i. Let value be ? Get(options, prop). let value = options.get(property, context)?; @@ -245,10 +244,10 @@ pub(crate) fn to_date_time_options( } // 6. Let dateStyle be ? Get(options, "dateStyle"). - let date_style = options.get(js_str!("dateStyle"), context)?; + let date_style = options.get(js_string!("dateStyle"), context)?; // 7. Let timeStyle be ? Get(options, "timeStyle"). - let time_style = options.get(js_str!("timeStyle"), context)?; + let time_style = options.get(js_string!("timeStyle"), context)?; // 8. If dateStyle is not undefined or timeStyle is not undefined, let needDefaults be false. if !date_style.is_undefined() || !time_style.is_undefined() { @@ -274,18 +273,22 @@ pub(crate) fn to_date_time_options( // 11. If needDefaults is true and defaults is either "date" or "all", then if need_defaults && [DateTimeReqs::Date, DateTimeReqs::AnyAll].contains(defaults) { // a. For each property name prop of « "year", "month", "day" », do - for property in [js_str!("year"), js_str!("month"), js_str!("day")] { + for property in [js_string!("year"), js_string!("month"), js_string!("day")] { // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). - options.create_data_property_or_throw(property, js_str!("numeric"), context)?; + options.create_data_property_or_throw(property, js_string!("numeric"), context)?; } } // 12. If needDefaults is true and defaults is either "time" or "all", then if need_defaults && [DateTimeReqs::Time, DateTimeReqs::AnyAll].contains(defaults) { // a. For each property name prop of « "hour", "minute", "second" », do - for property in [js_str!("hour"), js_str!("minute"), js_str!("second")] { + for property in [ + js_string!("hour"), + js_string!("minute"), + js_string!("second"), + ] { // i. Perform ? CreateDataPropertyOrThrow(options, prop, "numeric"). - options.create_data_property_or_throw(property, js_str!("numeric"), context)?; + options.create_data_property_or_throw(property, js_string!("numeric"), context)?; } } diff --git a/core/engine/src/builtins/intl/list_format/mod.rs b/core/engine/src/builtins/intl/list_format/mod.rs index 2cf3133b160..34fd8d7fae0 100644 --- a/core/engine/src/builtins/intl/list_format/mod.rs +++ b/core/engine/src/builtins/intl/list_format/mod.rs @@ -1,7 +1,6 @@ use std::fmt::Write; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use icu_list::{provider::AndListV1Marker, ListFormatter, ListLength}; use icu_locid::Locale; @@ -121,7 +120,8 @@ impl BuiltInConstructor for ListFormat { // 5. Let opt be a new Record. // 6. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). - let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); + let matcher = + get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 7. Set opt.[[localeMatcher]] to matcher. // 8. Let localeData be %ListFormat%.[[LocaleData]]. @@ -138,11 +138,11 @@ impl BuiltInConstructor for ListFormat { // 11. Let type be ? GetOption(options, "type", string, « "conjunction", "disjunction", "unit" », "conjunction"). // 12. Set listFormat.[[Type]] to type. - let typ = get_option(&options, js_str!("type"), context)?.unwrap_or_default(); + let typ = get_option(&options, js_string!("type"), context)?.unwrap_or_default(); // 13. Let style be ? GetOption(options, "style", string, « "long", "short", "narrow" », "long"). // 14. Set listFormat.[[Style]] to style. - let style = get_option(&options, js_str!("style"), context)?.unwrap_or(ListLength::Wide); + let style = get_option(&options, js_string!("style"), context)?.unwrap_or(ListLength::Wide); // 15. Let dataLocale be r.[[dataLocale]]. // 16. Let dataLocaleData be localeData.[[]]. @@ -390,11 +390,11 @@ impl ListFormat { .create(OrdinaryObject, vec![]); // b. Perform ! CreateDataPropertyOrThrow(O, "type", part.[[Type]]). - o.create_data_property_or_throw(js_str!("type"), js_string!(part.typ()), context) + o.create_data_property_or_throw(js_string!("type"), js_string!(part.typ()), context) .expect("operation must not fail per the spec"); // c. Perform ! CreateDataPropertyOrThrow(O, "value", part.[[Value]]). - o.create_data_property_or_throw(js_str!("value"), js_string!(part.value()), context) + o.create_data_property_or_throw(js_string!("value"), js_string!(part.value()), context) .expect("operation must not fail per the spec"); // d. Perform ! CreateDataPropertyOrThrow(result, ! ToString(n), O). @@ -445,29 +445,29 @@ impl ListFormat { // d. Perform ! CreateDataPropertyOrThrow(options, p, v). options .create_data_property_or_throw( - js_str!("locale"), + js_string!("locale"), js_string!(lf.locale.to_string()), context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - js_str!("type"), + js_string!("type"), match lf.typ { - ListFormatType::Conjunction => js_str!("conjunction"), - ListFormatType::Disjunction => js_str!("disjunction"), - ListFormatType::Unit => js_str!("unit"), + ListFormatType::Conjunction => js_string!("conjunction"), + ListFormatType::Disjunction => js_string!("disjunction"), + ListFormatType::Unit => js_string!("unit"), }, context, ) .expect("operation must not fail per the spec"); options .create_data_property_or_throw( - js_str!("style"), + js_string!("style"), match lf.style { - ListLength::Wide => js_str!("long"), - ListLength::Short => js_str!("short"), - ListLength::Narrow => js_str!("narrow"), + ListLength::Wide => js_string!("long"), + ListLength::Short => js_string!("short"), + ListLength::Narrow => js_string!("narrow"), _ => unreachable!(), }, context, diff --git a/core/engine/src/builtins/intl/locale/mod.rs b/core/engine/src/builtins/intl/locale/mod.rs index cbcaa67481d..39e3cb9d3e8 100644 --- a/core/engine/src/builtins/intl/locale/mod.rs +++ b/core/engine/src/builtins/intl/locale/mod.rs @@ -1,5 +1,4 @@ use crate::{builtins::options::get_option, realm::Realm, string::StaticJsStrings}; -use boa_macros::js_str; use boa_profiler::Profiler; use icu_collator::CaseFirst; use icu_datetime::options::preferences::HourCycle; @@ -235,17 +234,17 @@ impl BuiltInConstructor for Locale { // 4. Let language be ? GetOption(options, "language", string, empty, undefined). // 5. If language is not undefined, then // a. If language does not match the unicode_language_subtag production, throw a RangeError exception. - let language = get_option(options, js_str!("language"), context)?; + let language = get_option(options, js_string!("language"), context)?; // 6. Let script be ? GetOption(options, "script", string, empty, undefined). // 7. If script is not undefined, then // a. If script does not match the unicode_script_subtag production, throw a RangeError exception. - let script = get_option(options, js_str!("script"), context)?; + let script = get_option(options, js_string!("script"), context)?; // 8. Let region be ? GetOption(options, "region", string, empty, undefined). // 9. If region is not undefined, then // a. If region does not match the unicode_region_subtag production, throw a RangeError exception. - let region = get_option(options, js_str!("region"), context)?; + let region = get_option(options, js_string!("region"), context)?; // 10. Set tag to ! CanonicalizeUnicodeLocaleId(tag). context @@ -293,17 +292,17 @@ impl BuiltInConstructor for Locale { // 14. If calendar is not undefined, then // 15. Set opt.[[ca]] to calendar. // a. If calendar does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - let ca = get_option(options, js_str!("calendar"), context)?; + let ca = get_option(options, js_string!("calendar"), context)?; // 16. Let collation be ? GetOption(options, "collation", string, empty, undefined). // 17. If collation is not undefined, then // 18. Set opt.[[co]] to collation. // a. If collation does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - let co = get_option(options, js_str!("collation"), context)?; + let co = get_option(options, js_string!("collation"), context)?; // 19. Let hc be ? GetOption(options, "hourCycle", string, « "h11", "h12", "h23", "h24" », undefined). // 20. Set opt.[[hc]] to hc. - let hc = get_option(options, js_str!("hourCycle"), context)?.map(|hc| match hc { + let hc = get_option(options, js_string!("hourCycle"), context)?.map(|hc| match hc { HourCycle::H24 => value!("h24"), HourCycle::H23 => value!("h23"), HourCycle::H12 => value!("h12"), @@ -312,7 +311,7 @@ impl BuiltInConstructor for Locale { // 21. Let kf be ? GetOption(options, "caseFirst", string, « "upper", "lower", "false" », undefined). // 22. Set opt.[[kf]] to kf. - let kf = get_option(options, js_str!("caseFirst"), context)?.map(|kf| match kf { + let kf = get_option(options, js_string!("caseFirst"), context)?.map(|kf| match kf { CaseFirst::UpperFirst => value!("upper"), CaseFirst::LowerFirst => value!("lower"), CaseFirst::Off => value!("false"), @@ -322,7 +321,7 @@ impl BuiltInConstructor for Locale { // 23. Let kn be ? GetOption(options, "numeric", boolean, empty, undefined). // 24. If kn is not undefined, set kn to ! ToString(kn). // 25. Set opt.[[kn]] to kn. - let kn = get_option(options, js_str!("numeric"), context)?.map(|b| { + let kn = get_option(options, js_string!("numeric"), context)?.map(|b| { if b { value!("true") } else { @@ -334,7 +333,7 @@ impl BuiltInConstructor for Locale { // 27. If numberingSystem is not undefined, then // 28. Set opt.[[nu]] to numberingSystem. // a. If numberingSystem does not match the Unicode Locale Identifier type nonterminal, throw a RangeError exception. - let nu = get_option(options, js_str!("numberingSystem"), context)?; + let nu = get_option(options, js_string!("numberingSystem"), context)?; // 29. Let r be ! ApplyUnicodeExtensionToTag(tag, opt, relevantExtensionKeys). // 30. Set locale.[[Locale]] to r.[[locale]]. diff --git a/core/engine/src/builtins/intl/locale/utils.rs b/core/engine/src/builtins/intl/locale/utils.rs index d21cd644105..300c3441d5c 100644 --- a/core/engine/src/builtins/intl/locale/utils.rs +++ b/core/engine/src/builtins/intl/locale/utils.rs @@ -13,7 +13,6 @@ use crate::{ Context, JsNativeError, JsResult, JsValue, }; -use boa_macros::js_str; use icu_locid::{ extensions::unicode::{Key, Value}, subtags::Variants, @@ -420,7 +419,7 @@ where let options = coerce_options_to_object(options, context)?; // 2. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). - let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); + let matcher = get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 3. Let subset be a new empty List. let mut subset = Vec::with_capacity(requested_locales.len()); diff --git a/core/engine/src/builtins/intl/number_format/mod.rs b/core/engine/src/builtins/intl/number_format/mod.rs index 395355d2796..12c77c0a3c2 100644 --- a/core/engine/src/builtins/intl/number_format/mod.rs +++ b/core/engine/src/builtins/intl/number_format/mod.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use fixed_decimal::{FixedDecimal, FloatPrecision, SignDisplay}; use icu_decimal::{ @@ -227,13 +226,14 @@ impl BuiltInConstructor for NumberFormat { // 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 5. Set opt.[[localeMatcher]] to matcher. - let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); + let matcher = + get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 6. Let numberingSystem be ? GetOption(options, "numberingSystem", string, empty, undefined). // 7. If numberingSystem is not undefined, then // a. If numberingSystem cannot be matched by the type Unicode locale nonterminal, throw a RangeError exception. // 8. Set opt.[[nu]] to numberingSystem. - let numbering_system = get_option(&options, js_str!("numberingSystem"), context)?; + let numbering_system = get_option(&options, js_string!("numberingSystem"), context)?; let mut intl_options = IntlOptions { matcher, @@ -283,7 +283,7 @@ impl BuiltInConstructor for NumberFormat { // 18. Let notation be ? GetOption(options, "notation", string, « "standard", "scientific", "engineering", "compact" », "standard"). // 19. Set numberFormat.[[Notation]] to notation. - let notation = get_option(&options, js_str!("notation"), context)?.unwrap_or_default(); + let notation = get_option(&options, js_string!("notation"), context)?.unwrap_or_default(); // 20. Perform ? SetNumberFormatDigitOptions(numberFormat, options, mnfdDefault, mxfdDefault, notation). let digit_options = DigitFormatOptions::from_options( @@ -296,7 +296,7 @@ impl BuiltInConstructor for NumberFormat { // 21. Let compactDisplay be ? GetOption(options, "compactDisplay", string, « "short", "long" », "short"). let compact_display = - get_option(&options, js_str!("compactDisplay"), context)?.unwrap_or_default(); + get_option(&options, js_string!("compactDisplay"), context)?.unwrap_or_default(); // 22. Let defaultUseGrouping be "auto". let mut default_use_grouping = GroupingStrategy::Auto; @@ -331,7 +331,7 @@ impl BuiltInConstructor for NumberFormat { // // 1. Let value be ? Get(options, property). - let value = options.get(js_str!("useGrouping"), context)?; + let value = options.get(js_string!("useGrouping"), context)?; // 2. If value is undefined, return fallback. if value.is_undefined() { @@ -369,7 +369,7 @@ impl BuiltInConstructor for NumberFormat { // 29. Let signDisplay be ? GetOption(options, "signDisplay", string, « "auto", "never", "always", "exceptZero", "negative" », "auto"). // 30. Set numberFormat.[[SignDisplay]] to signDisplay. let sign_display = - get_option(&options, js_str!("signDisplay"), context)?.unwrap_or(SignDisplay::Auto); + get_option(&options, js_string!("signDisplay"), context)?.unwrap_or(SignDisplay::Auto); let mut options = FixedDecimalFormatterOptions::default(); options.grouping_strategy = use_grouping; diff --git a/core/engine/src/builtins/intl/number_format/options.rs b/core/engine/src/builtins/intl/number_format/options.rs index ccf33a328f7..ab58762a38f 100644 --- a/core/engine/src/builtins/intl/number_format/options.rs +++ b/core/engine/src/builtins/intl/number_format/options.rs @@ -392,12 +392,12 @@ impl UnitFormatOptions { pub(crate) fn from_options(options: &JsObject, context: &mut Context) -> JsResult { // 1. Let style be ? GetOption(options, "style", string, « "decimal", "percent", "currency", "unit" », "decimal"). // 2. Set intlObj.[[Style]] to style. - let style: Style = get_option(options, js_str!("style"), context)?.unwrap_or_default(); + let style: Style = get_option(options, js_string!("style"), context)?.unwrap_or_default(); // 3. Let currency be ? GetOption(options, "currency", string, empty, undefined). // 5. Else, // a. If IsWellFormedCurrencyCode(currency) is false, throw a RangeError exception. - let currency = get_option(options, js_str!("currency"), context)?; + let currency = get_option(options, js_string!("currency"), context)?; // 4. If currency is undefined, then if currency.is_none() { @@ -413,16 +413,16 @@ impl UnitFormatOptions { // 6. Let currencyDisplay be ? GetOption(options, "currencyDisplay", string, « "code", "symbol", "narrowSymbol", "name" », "symbol"). let currency_display = - get_option(options, js_str!("currencyDisplay"), context)?.unwrap_or_default(); + get_option(options, js_string!("currencyDisplay"), context)?.unwrap_or_default(); // 7. Let currencySign be ? GetOption(options, "currencySign", string, « "standard", "accounting" », "standard"). let currency_sign = - get_option(options, js_str!("currencySign"), context)?.unwrap_or_default(); + get_option(options, js_string!("currencySign"), context)?.unwrap_or_default(); // 8. Let unit be ? GetOption(options, "unit", string, empty, undefined). // 10. Else, // a. If IsWellFormedUnitIdentifier(unit) is false, throw a RangeError exception. - let unit = get_option(options, js_str!("unit"), context)?; + let unit = get_option(options, js_string!("unit"), context)?; // 9. If unit is undefined, then if unit.is_none() { // a. If style is "unit", throw a TypeError exception. @@ -437,7 +437,7 @@ impl UnitFormatOptions { // 11. Let unitDisplay be ? GetOption(options, "unitDisplay", string, « "short", "narrow", "long" », "short"). let unit_display = - get_option(options, js_str!("unitDisplay"), context)?.unwrap_or_default(); + get_option(options, js_string!("unitDisplay"), context)?.unwrap_or_default(); // 14. Return unused. Ok(match style { @@ -492,25 +492,25 @@ impl DigitFormatOptions { ) -> JsResult { // 1. Let mnid be ? GetNumberOption(options, "minimumIntegerDigits,", 1, 21, 1). let minimum_integer_digits = - get_number_option(options, js_str!("minimumIntegerDigits"), 1, 21, context)? + get_number_option(options, js_string!("minimumIntegerDigits"), 1, 21, context)? .unwrap_or(1); // 2. Let mnfd be ? Get(options, "minimumFractionDigits"). - let min_float_digits = options.get(js_str!("minimumFractionDigits"), context)?; + let min_float_digits = options.get(js_string!("minimumFractionDigits"), context)?; // 3. Let mxfd be ? Get(options, "maximumFractionDigits"). - let max_float_digits = options.get(js_str!("maximumFractionDigits"), context)?; + let max_float_digits = options.get(js_string!("maximumFractionDigits"), context)?; // 4. Let mnsd be ? Get(options, "minimumSignificantDigits"). - let min_sig_digits = options.get(js_str!("minimumSignificantDigits"), context)?; + let min_sig_digits = options.get(js_string!("minimumSignificantDigits"), context)?; // 5. Let mxsd be ? Get(options, "maximumSignificantDigits"). - let max_sig_digits = options.get(js_str!("maximumSignificantDigits"), context)?; + let max_sig_digits = options.get(js_string!("maximumSignificantDigits"), context)?; // 7. Let roundingPriority be ? GetOption(options, "roundingPriority", string, « "auto", "morePrecision", "lessPrecision" », "auto"). let mut rounding_priority = - get_option(options, js_str!("roundingPriority"), context)?.unwrap_or_default(); + get_option(options, js_string!("roundingPriority"), context)?.unwrap_or_default(); // 8. Let roundingIncrement be ? GetNumberOption(options, "roundingIncrement", 1, 5000, 1). // 9. If roundingIncrement is not in « 1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000 », throw a RangeError exception. let rounding_increment = - get_number_option(options, js_str!("roundingIncrement"), 1, 5000, context)? + get_number_option(options, js_string!("roundingIncrement"), 1, 5000, context)? .unwrap_or(1); let rounding_increment = @@ -520,11 +520,11 @@ impl DigitFormatOptions { // 10. Let roundingMode be ? GetOption(options, "roundingMode", string, « "ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor", "halfExpand", "halfTrunc", "halfEven" », "halfExpand"). let rounding_mode = - get_option(options, js_str!("roundingMode"), context)?.unwrap_or_default(); + get_option(options, js_string!("roundingMode"), context)?.unwrap_or_default(); // 11. Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", string, « "auto", "stripIfInteger" », "auto"). let trailing_zero_display = - get_option(options, js_str!("trailingZeroDisplay"), context)?.unwrap_or_default(); + get_option(options, js_string!("trailingZeroDisplay"), context)?.unwrap_or_default(); // 12. NOTE: All fields required by SetNumberFormatDigitOptions have now been read from options. The remainder of this AO interprets the options and may throw exceptions. diff --git a/core/engine/src/builtins/intl/options.rs b/core/engine/src/builtins/intl/options.rs index da0803126c2..9a6b67845f0 100644 --- a/core/engine/src/builtins/intl/options.rs +++ b/core/engine/src/builtins/intl/options.rs @@ -5,7 +5,7 @@ use num_traits::FromPrimitive; use crate::{ builtins::{options::ParsableOptionType, OrdinaryObject}, object::JsObject, - Context, JsNativeError, JsResult, JsStr, JsValue, + Context, JsNativeError, JsResult, JsString, JsValue, }; /// `IntlOptions` aggregates the `locale_matcher` selector and any other object @@ -60,7 +60,7 @@ impl ParsableOptionType for LocaleMatcher {} /// [spec]: https://tc39.es/ecma402/#sec-getnumberoption pub(super) fn get_number_option( options: &JsObject, - property: JsStr<'_>, + property: JsString, minimum: T, maximum: T, context: &mut Context, diff --git a/core/engine/src/builtins/intl/plural_rules/mod.rs b/core/engine/src/builtins/intl/plural_rules/mod.rs index 4689feff4d2..05d98243a66 100644 --- a/core/engine/src/builtins/intl/plural_rules/mod.rs +++ b/core/engine/src/builtins/intl/plural_rules/mod.rs @@ -1,7 +1,6 @@ mod options; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use fixed_decimal::FixedDecimal; use icu_locid::Locale; @@ -25,7 +24,7 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsStr, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use super::{ @@ -126,12 +125,13 @@ impl BuiltInConstructor for PluralRules { // 3. Let opt be a new Record. // 4. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). // 5. Set opt.[[localeMatcher]] to matcher. - let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); + let matcher = + get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 6. Let t be ? GetOption(options, "type", string, « "cardinal", "ordinal" », "cardinal"). // 7. Set pluralRules.[[Type]] to t. let rule_type = - get_option(&options, js_str!("type"), context)?.unwrap_or(PluralRuleType::Cardinal); + get_option(&options, js_string!("type"), context)?.unwrap_or(PluralRuleType::Cardinal); // 8. Perform ? SetNumberFormatDigitOptions(pluralRules, options, +0𝔽, 3𝔽, "standard"). let format_options = @@ -330,21 +330,21 @@ impl PluralRules { let mut options = ObjectInitializer::new(context); options .property( - js_str!("locale"), + js_string!("locale"), js_string!(plural_rules.locale.to_string()), Attribute::all(), ) .property( - js_str!("type"), + js_string!("type"), match plural_rules.rule_type { - PluralRuleType::Cardinal => js_str!("cardinal"), - PluralRuleType::Ordinal => js_str!("ordinal"), - _ => js_str!("unknown"), + PluralRuleType::Cardinal => js_string!("cardinal"), + PluralRuleType::Ordinal => js_string!("ordinal"), + _ => js_string!("unknown"), }, Attribute::all(), ) .property( - js_str!("minimumIntegerDigits"), + js_string!("minimumIntegerDigits"), plural_rules.format_options.minimum_integer_digits, Attribute::all(), ); @@ -353,8 +353,16 @@ impl PluralRules { plural_rules.format_options.rounding_type.fraction_digits() { options - .property(js_str!("minimumFractionDigits"), minimum, Attribute::all()) - .property(js_str!("maximumFractionDigits"), maximum, Attribute::all()); + .property( + js_string!("minimumFractionDigits"), + minimum, + Attribute::all(), + ) + .property( + js_string!("maximumFractionDigits"), + maximum, + Attribute::all(), + ); } if let Some(Extrema { minimum, maximum }) = plural_rules @@ -364,12 +372,12 @@ impl PluralRules { { options .property( - js_str!("minimumSignificantDigits"), + js_string!("minimumSignificantDigits"), minimum, Attribute::all(), ) .property( - js_str!("maximumSignificantDigits"), + js_string!("maximumSignificantDigits"), maximum, Attribute::all(), ); @@ -377,17 +385,17 @@ impl PluralRules { options .property( - js_str!("roundingMode"), + js_string!("roundingMode"), js_string!(plural_rules.format_options.rounding_mode.to_js_string()), Attribute::all(), ) .property( - js_str!("roundingIncrement"), + js_string!("roundingIncrement"), plural_rules.format_options.rounding_increment.to_u16(), Attribute::all(), ) .property( - js_str!("trailingZeroDisplay"), + js_string!("trailingZeroDisplay"), plural_rules .format_options .trailing_zero_display @@ -408,7 +416,7 @@ impl PluralRules { // 6. Perform ! CreateDataProperty(options, "pluralCategories", CreateArrayFromList(pluralCategories)). options.property( - js_str!("pluralCategories"), + js_string!("pluralCategories"), plural_categories, Attribute::all(), ); @@ -420,7 +428,7 @@ impl PluralRules { // 9. Else, // a. Perform ! CreateDataPropertyOrThrow(options, "roundingPriority", "auto"). options.property( - js_str!("roundingPriority"), + js_string!("roundingPriority"), js_string!(plural_rules.format_options.rounding_priority.to_js_string()), Attribute::all(), ); @@ -472,13 +480,13 @@ fn resolve_plural(plural_rules: &PluralRules, n: f64) -> ResolvedPlural { } } -fn plural_category_to_js_string(category: PluralCategory) -> JsStr<'static> { +fn plural_category_to_js_string(category: PluralCategory) -> JsString { match category { - PluralCategory::Zero => js_str!("zero"), - PluralCategory::One => js_str!("one"), - PluralCategory::Two => js_str!("two"), - PluralCategory::Few => js_str!("few"), - PluralCategory::Many => js_str!("many"), - PluralCategory::Other => js_str!("other"), + PluralCategory::Zero => js_string!("zero"), + PluralCategory::One => js_string!("one"), + PluralCategory::Two => js_string!("two"), + PluralCategory::Few => js_string!("few"), + PluralCategory::Many => js_string!("many"), + PluralCategory::Other => js_string!("other"), } } diff --git a/core/engine/src/builtins/intl/segmenter/mod.rs b/core/engine/src/builtins/intl/segmenter/mod.rs index 2eeb7afbd35..839d0b66113 100644 --- a/core/engine/src/builtins/intl/segmenter/mod.rs +++ b/core/engine/src/builtins/intl/segmenter/mod.rs @@ -1,7 +1,6 @@ use std::ops::Range; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use icu_collator::provider::CollationDiacriticsV1Marker; use icu_locid::Locale; @@ -147,7 +146,8 @@ impl BuiltInConstructor for Segmenter { // 6. Let opt be a new Record. // 7. Let matcher be ? GetOption(options, "localeMatcher", string, « "lookup", "best fit" », "best fit"). - let matcher = get_option(&options, js_str!("localeMatcher"), context)?.unwrap_or_default(); + let matcher = + get_option(&options, js_string!("localeMatcher"), context)?.unwrap_or_default(); // 8. Set opt.[[localeMatcher]] to matcher. // 9. Let localeData be %Segmenter%.[[LocaleData]]. @@ -164,7 +164,7 @@ impl BuiltInConstructor for Segmenter { // 12. Let granularity be ? GetOption(options, "granularity", string, « "grapheme", "word", "sentence" », "grapheme"). let granularity = - get_option(&options, js_str!("granularity"), context)?.unwrap_or_default(); + get_option(&options, js_string!("granularity"), context)?.unwrap_or_default(); // 13. Set segmenter.[[SegmenterGranularity]] to granularity. let native = match (granularity, context.intl_provider().erased_provider()) { @@ -269,12 +269,12 @@ impl Segmenter { // d. Perform ! CreateDataPropertyOrThrow(options, p, v). let options = ObjectInitializer::new(context) .property( - js_str!("locale"), + js_string!("locale"), js_string!(segmenter.locale.to_string()), Attribute::all(), ) .property( - js_str!("granularity"), + js_string!("granularity"), js_string!(segmenter.native.granularity().to_string()), Attribute::all(), ) @@ -336,18 +336,18 @@ fn create_segment_data_object( object // 7. Perform ! CreateDataPropertyOrThrow(result, "segment", segment). - .property(js_str!("segment"), segment, Attribute::all()) + .property(js_string!("segment"), segment, Attribute::all()) // 8. Perform ! CreateDataPropertyOrThrow(result, "index", 𝔽(startIndex)). - .property(js_str!("index"), start, Attribute::all()) + .property(js_string!("index"), start, Attribute::all()) // 9. Perform ! CreateDataPropertyOrThrow(result, "input", string). - .property(js_str!("input"), string, Attribute::all()); + .property(js_string!("input"), string, Attribute::all()); // 10. Let granularity be segmenter.[[SegmenterGranularity]]. // 11. If granularity is "word", then if let Some(is_word_like) = is_word_like { // a. Let isWordLike be a Boolean value indicating whether the segment in string is "word-like" according to locale segmenter.[[Locale]]. // b. Perform ! CreateDataPropertyOrThrow(result, "isWordLike", isWordLike). - object.property(js_str!("isWordLike"), is_word_like, Attribute::all()); + object.property(js_string!("isWordLike"), is_word_like, Attribute::all()); } // 12. Return result. diff --git a/core/engine/src/builtins/iterable/async_from_sync_iterator.rs b/core/engine/src/builtins/iterable/async_from_sync_iterator.rs index 032cc298e5b..00c51940f9e 100644 --- a/core/engine/src/builtins/iterable/async_from_sync_iterator.rs +++ b/core/engine/src/builtins/iterable/async_from_sync_iterator.rs @@ -12,7 +12,6 @@ use crate::{ Context, JsArgs, JsData, JsError, JsNativeError, JsResult, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; /// `%AsyncFromSyncIteratorPrototype%` object. @@ -80,7 +79,7 @@ impl AsyncFromSyncIterator { // 3. Let nextMethod be ! Get(asyncIterator, "next"). let next_method = async_iterator - .get(js_str!("next"), context) + .get(js_string!("next"), context) .expect("async from sync iterator prototype must have next method"); // 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: asyncIterator, [[NextMethod]]: nextMethod, [[Done]]: false }. @@ -158,7 +157,7 @@ impl AsyncFromSyncIterator { .expect("cannot fail with promise constructor"); // 6. Let return be Completion(GetMethod(syncIterator, "return")). - let r#return = sync_iterator.get_method(js_str!("return"), context); + let r#return = sync_iterator.get_method(js_string!("return"), context); // 7. IfAbruptRejectPromise(return, promiseCapability). let r#return = if_abrupt_reject_promise!(r#return, promise_capability, context); @@ -235,7 +234,7 @@ impl AsyncFromSyncIterator { .expect("cannot fail with promise constructor"); // 6. Let throw be Completion(GetMethod(syncIterator, "throw")). - let throw = sync_iterator.get_method(js_str!("throw"), context); + let throw = sync_iterator.get_method(js_string!("throw"), context); // 7. IfAbruptRejectPromise(throw, promiseCapability). let throw = if_abrupt_reject_promise!(throw, promise_capability, context); @@ -360,7 +359,7 @@ impl AsyncFromSyncIterator { )) }), ) - .name(js_str!("")) + .name(js_string!()) .length(1) .build(); @@ -393,7 +392,7 @@ impl AsyncFromSyncIterator { sync_iterator_record, ), ) - .name(js_str!("")) + .name(js_string!()) .length(1) .build(), ) diff --git a/core/engine/src/builtins/iterable/mod.rs b/core/engine/src/builtins/iterable/mod.rs index ca3303ba590..b2de198516f 100644 --- a/core/engine/src/builtins/iterable/mod.rs +++ b/core/engine/src/builtins/iterable/mod.rs @@ -4,13 +4,13 @@ use crate::{ builtins::{BuiltInBuilder, IntrinsicObject}, context::intrinsics::Intrinsics, error::JsNativeError, + js_string, object::JsObject, realm::Realm, symbol::JsSymbol, Context, JsResult, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; mod async_from_sync_iterator; @@ -243,7 +243,7 @@ impl JsValue { JsNativeError::typ().with_message("returned iterator is not an object") })?; // 3. Let nextMethod be ? Get(iterator, "next"). - let next_method = iterator_obj.get(js_str!("next"), context)?; + let next_method = iterator_obj.get(js_string!("next"), context)?; // 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }. // 5. Return iteratorRecord. Ok(IteratorRecord::new(iterator_obj.clone(), next_method)) @@ -341,7 +341,7 @@ impl IteratorResult { #[inline] pub fn complete(&self, context: &mut Context) -> JsResult { // 1. Return ToBoolean(? Get(iterResult, "done")). - Ok(self.object.get(js_str!("done"), context)?.to_boolean()) + Ok(self.object.get(js_string!("done"), context)?.to_boolean()) } /// `IteratorValue ( iterResult )` @@ -357,7 +357,7 @@ impl IteratorResult { #[inline] pub fn value(&self, context: &mut Context) -> JsResult { // 1. Return ? Get(iterResult, "value"). - self.object.get(js_str!("value"), context) + self.object.get(js_string!("value"), context) } } @@ -588,7 +588,7 @@ impl IteratorRecord { let iterator = &self.iterator; // 3. Let innerResult be Completion(GetMethod(iterator, "return")). - let inner_result = iterator.get_method(js_str!("return"), context); + let inner_result = iterator.get_method(js_string!("return"), context); // 4. If innerResult.[[Type]] is normal, then let inner_result = match inner_result { diff --git a/core/engine/src/builtins/json/mod.rs b/core/engine/src/builtins/json/mod.rs index ce4af91bad2..8dd04fcf85b 100644 --- a/core/engine/src/builtins/json/mod.rs +++ b/core/engine/src/builtins/json/mod.rs @@ -16,7 +16,7 @@ use std::{borrow::Cow, iter::once}; use boa_ast::scope::Scope; -use boa_macros::{js_str, utf16}; +use boa_macros::utf16; use itertools::Itertools; use crate::{ @@ -154,7 +154,7 @@ impl Json { // b. Let rootName be the empty String. // c. Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered). - root.create_data_property_or_throw(js_str!(""), unfiltered, context) + root.create_data_property_or_throw(js_string!(), unfiltered, context) .expect("CreateDataPropertyOrThrow should never throw here"); // d. Return ? InternalizeJSONProperty(root, rootName, reviver). @@ -386,7 +386,7 @@ impl Json { // 10. Perform ! CreateDataPropertyOrThrow(wrapper, the empty String, value). wrapper - .create_data_property_or_throw(js_str!(""), args.get_or_undefined(0).clone(), context) + .create_data_property_or_throw(js_string!(), args.get_or_undefined(0).clone(), context) .expect("CreateDataPropertyOrThrow should never fail here"); // 11. Let state be the Record { [[ReplacerFunction]]: ReplacerFunction, [[Stack]]: stack, [[Indent]]: indent, [[Gap]]: gap, [[PropertyList]]: PropertyList }. @@ -424,7 +424,7 @@ impl Json { // 2. If Type(value) is Object or BigInt, then if value.is_object() || value.is_bigint() { // a. Let toJSON be ? GetV(value, "toJSON"). - let to_json = value.get_v(js_str!("toJSON"), context)?; + let to_json = value.get_v(js_string!("toJSON"), context)?; // b. If IsCallable(toJSON) is true, then if let Some(obj) = to_json.as_object() { diff --git a/core/engine/src/builtins/map/mod.rs b/core/engine/src/builtins/map/mod.rs index 953cc977980..bdd39e52c76 100644 --- a/core/engine/src/builtins/map/mod.rs +++ b/core/engine/src/builtins/map/mod.rs @@ -22,7 +22,6 @@ use crate::{ symbol::JsSymbol, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use num_traits::Zero; @@ -155,7 +154,7 @@ impl BuiltInConstructor for Map { // 5. Let adder be ? Get(map, "set"). // 6. If IsCallable(adder) is false, throw a TypeError exception. let adder = map - .get(js_str!("set"), context)? + .get(js_string!("set"), context)? .as_function() .ok_or_else(|| { JsNativeError::typ() diff --git a/core/engine/src/builtins/mod.rs b/core/engine/src/builtins/mod.rs index 3fbe2473a8a..be52220e254 100644 --- a/core/engine/src/builtins/mod.rs +++ b/core/engine/src/builtins/mod.rs @@ -36,7 +36,6 @@ pub mod weak_set; mod builder; -use boa_macros::js_str; use boa_profiler::Profiler; use builder::BuiltInBuilder; @@ -107,6 +106,7 @@ use crate::{ weak_set::WeakSet, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, + js_string, object::JsObject, property::{Attribute, PropertyDescriptor}, realm::Realm, @@ -314,7 +314,7 @@ pub(crate) fn set_default_global_bindings(context: &mut Context) -> JsResult<()> let global_object = context.global_object(); global_object.define_property_or_throw( - js_str!("globalThis"), + js_string!("globalThis"), PropertyDescriptor::builder() .value(context.realm().global_this().clone()) .writable(true) @@ -327,17 +327,17 @@ pub(crate) fn set_default_global_bindings(context: &mut Context) -> JsResult<()> .enumerable(false) .configurable(false); global_object.define_property_or_throw( - js_str!("Infinity"), + js_string!("Infinity"), restricted.clone().value(f64::INFINITY), context, )?; global_object.define_property_or_throw( - js_str!("NaN"), + js_string!("NaN"), restricted.clone().value(f64::NAN), context, )?; global_object.define_property_or_throw( - js_str!("undefined"), + js_string!("undefined"), restricted.value(JsValue::undefined()), context, )?; diff --git a/core/engine/src/builtins/number/mod.rs b/core/engine/src/builtins/number/mod.rs index 1a6dc39aac0..d1b09d4ecfe 100644 --- a/core/engine/src/builtins/number/mod.rs +++ b/core/engine/src/builtins/number/mod.rs @@ -25,7 +25,6 @@ use crate::{ value::{AbstractRelation, IntegerOrInfinity, JsValue}, Context, JsArgs, JsResult, JsString, }; -use boa_macros::js_str; use boa_profiler::Profiler; use num_traits::float::FloatCore; @@ -648,7 +647,7 @@ impl Number { #[allow(clippy::wrong_self_convention)] pub(crate) fn to_js_string(x: f64) -> JsString { let mut buffer = ryu_js::Buffer::new(); - js_string!(buffer.format(x).to_string()) + js_string!(buffer.format(x)) } /// `Number.prototype.toString( [radix] )` @@ -693,13 +692,13 @@ impl Number { } if x == -0. { - return Ok(JsValue::new(js_str!("0"))); + return Ok(JsValue::new(js_string!("0"))); } else if x.is_nan() { - return Ok(JsValue::new(js_str!("NaN"))); + return Ok(JsValue::new(js_string!("NaN"))); } else if x.is_infinite() && x.is_sign_positive() { - return Ok(JsValue::new(js_str!("Infinity"))); + return Ok(JsValue::new(js_string!("Infinity"))); } else if x.is_infinite() && x.is_sign_negative() { - return Ok(JsValue::new(js_str!("-Infinity"))); + return Ok(JsValue::new(js_string!("-Infinity"))); } // This is a Optimization from the v8 source code to print values that can fit in a single character diff --git a/core/engine/src/builtins/object/mod.rs b/core/engine/src/builtins/object/mod.rs index 1f34fd49103..30a022875b7 100644 --- a/core/engine/src/builtins/object/mod.rs +++ b/core/engine/src/builtins/object/mod.rs @@ -575,42 +575,42 @@ impl OrdinaryObject { // 4. If Desc has a [[Value]] field, then if let Some(value) = desc.value() { // a. Perform ! CreateDataPropertyOrThrow(obj, "value", Desc.[[Value]]). - obj.create_data_property_or_throw(js_str!("value"), value.clone(), context) + obj.create_data_property_or_throw(js_string!("value"), value.clone(), context) .expect("CreateDataPropertyOrThrow cannot fail here"); } // 5. If Desc has a [[Writable]] field, then if let Some(writable) = desc.writable() { // a. Perform ! CreateDataPropertyOrThrow(obj, "writable", Desc.[[Writable]]). - obj.create_data_property_or_throw(js_str!("writable"), writable, context) + obj.create_data_property_or_throw(js_string!("writable"), writable, context) .expect("CreateDataPropertyOrThrow cannot fail here"); } // 6. If Desc has a [[Get]] field, then if let Some(get) = desc.get() { // a. Perform ! CreateDataPropertyOrThrow(obj, "get", Desc.[[Get]]). - obj.create_data_property_or_throw(js_str!("get"), get.clone(), context) + obj.create_data_property_or_throw(js_string!("get"), get.clone(), context) .expect("CreateDataPropertyOrThrow cannot fail here"); } // 7. If Desc has a [[Set]] field, then if let Some(set) = desc.set() { // a. Perform ! CreateDataPropertyOrThrow(obj, "set", Desc.[[Set]]). - obj.create_data_property_or_throw(js_str!("set"), set.clone(), context) + obj.create_data_property_or_throw(js_string!("set"), set.clone(), context) .expect("CreateDataPropertyOrThrow cannot fail here"); } // 8. If Desc has an [[Enumerable]] field, then if let Some(enumerable) = desc.enumerable() { // a. Perform ! CreateDataPropertyOrThrow(obj, "enumerable", Desc.[[Enumerable]]). - obj.create_data_property_or_throw(js_str!("enumerable"), enumerable, context) + obj.create_data_property_or_throw(js_string!("enumerable"), enumerable, context) .expect("CreateDataPropertyOrThrow cannot fail here"); } // 9. If Desc has a [[Configurable]] field, then if let Some(configurable) = desc.configurable() { // a. Perform ! CreateDataPropertyOrThrow(obj, "configurable", Desc.[[Configurable]]). - obj.create_data_property_or_throw(js_str!("configurable"), configurable, context) + obj.create_data_property_or_throw(js_string!("configurable"), configurable, context) .expect("CreateDataPropertyOrThrow cannot fail here"); } @@ -826,11 +826,11 @@ impl OrdinaryObject { pub fn to_string(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult { // 1. If the this value is undefined, return "[object Undefined]". if this.is_undefined() { - return Ok(js_str!("[object Undefined]").into()); + return Ok(js_string!("[object Undefined]").into()); } // 2. If the this value is null, return "[object Null]". if this.is_null() { - return Ok(js_str!("[object Null]").into()); + return Ok(js_string!("[object Null]").into()); } // 3. Let O be ! ToObject(this value). let o = this.to_object(context).expect("toObject cannot fail here"); @@ -898,7 +898,7 @@ impl OrdinaryObject { ) -> JsResult { // 1. Let O be the this value. // 2. Return ? Invoke(O, "toString"). - this.invoke(js_str!("toString"), &[], context) + this.invoke(js_string!("toString"), &[], context) } /// `Object.prototype.hasOwnProperty( property )` diff --git a/core/engine/src/builtins/options.rs b/core/engine/src/builtins/options.rs index 4c939c91649..db5c84b4ec9 100644 --- a/core/engine/src/builtins/options.rs +++ b/core/engine/src/builtins/options.rs @@ -2,7 +2,7 @@ use std::{fmt, str::FromStr}; -use crate::{object::JsObject, string::JsStr, Context, JsNativeError, JsResult, JsString, JsValue}; +use crate::{object::JsObject, Context, JsNativeError, JsResult, JsString, JsValue}; /// A type used as an option parameter for [`get_option`]. pub(crate) trait OptionType: Sized { @@ -50,7 +50,7 @@ where /// [spec]: https://tc39.es/ecma402/#sec-getoption pub(crate) fn get_option( options: &JsObject, - property: JsStr<'_>, + property: JsString, context: &mut Context, ) -> JsResult> { // 1. Let value be ? Get(options, property). diff --git a/core/engine/src/builtins/promise/mod.rs b/core/engine/src/builtins/promise/mod.rs index 223fe40b2c3..d97be26b683 100644 --- a/core/engine/src/builtins/promise/mod.rs +++ b/core/engine/src/builtins/promise/mod.rs @@ -26,7 +26,7 @@ use crate::{ Context, JsArgs, JsError, JsResult, JsString, }; use boa_gc::{custom_trace, Finalize, Gc, GcRefCell, Trace}; -use boa_macros::{js_str, JsData}; +use boa_macros::JsData; use boa_profiler::Profiler; use std::{cell::Cell, rc::Rc}; use tap::{Conv, Pipe}; @@ -739,7 +739,7 @@ impl Promise { // n. Perform ? Invoke(nextPromise, "then", « onFulfilled, resultCapability.[[Reject]] »). next_promise.invoke( - js_str!("then"), + js_string!("then"), &[ on_fulfilled.into(), result_capability.functions.reject.clone().into(), @@ -915,15 +915,15 @@ impl Promise { // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "fulfilled"). obj.create_data_property_or_throw( - js_str!("status"), - js_str!("fulfilled"), + js_string!("status"), + js_string!("fulfilled"), context, ) .expect("cannot fail per spec"); // 11. Perform ! CreateDataPropertyOrThrow(obj, "value", x). obj.create_data_property_or_throw( - js_str!("value"), + js_string!("value"), args.get_or_undefined(0).clone(), context, ) @@ -1005,15 +1005,15 @@ impl Promise { // 10. Perform ! CreateDataPropertyOrThrow(obj, "status", "rejected"). obj.create_data_property_or_throw( - js_str!("status"), - js_str!("rejected"), + js_string!("status"), + js_string!("rejected"), context, ) .expect("cannot fail per spec"); // 11. Perform ! CreateDataPropertyOrThrow(obj, "reason", x). obj.create_data_property_or_throw( - js_str!("reason"), + js_string!("reason"), args.get_or_undefined(0).clone(), context, ) @@ -1065,7 +1065,7 @@ impl Promise { // w. Perform ? Invoke(nextPromise, "then", « onFulfilled, onRejected »). next_promise.invoke( - js_str!("then"), + js_string!("then"), &[on_fulfilled.into(), on_rejected.into()], context, )?; @@ -1286,7 +1286,7 @@ impl Promise { // n. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], onRejected »). next_promise.invoke( - js_str!("then"), + js_string!("then"), &[ result_capability.functions.resolve.clone().into(), on_rejected.into(), @@ -1417,7 +1417,7 @@ impl Promise { let next_promise = promise_resolve.call(&constructor, &[next], context)?; // d. Perform ? Invoke(nextPromise, "then", « resultCapability.[[Resolve]], resultCapability.[[Reject]] »). next_promise.invoke( - js_str!("then"), + js_string!("then"), &[ result_capability.functions.resolve.clone().into(), result_capability.functions.reject.clone().into(), @@ -1576,7 +1576,7 @@ impl Promise { let promise = this; // 2. Return ? Invoke(promise, "then", « undefined, onRejected »). promise.invoke( - js_str!("then"), + js_string!("then"), &[JsValue::undefined(), on_rejected.clone()], context, ) @@ -1622,7 +1622,7 @@ impl Promise { // a. Let thenFinally be onFinally. // b. Let catchFinally be onFinally. // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). - let then = promise.get(js_str!("then"), context)?; + let then = promise.get(js_string!("then"), context)?; return then.call(this, &[on_finally.clone(), on_finally.clone()], context); }; @@ -1630,7 +1630,7 @@ impl Promise { Self::then_catch_finally_closures(c, on_finally, context); // 7. Return ? Invoke(promise, "then", « thenFinally, catchFinally »). - let then = promise.get(js_str!("then"), context)?; + let then = promise.get(js_string!("then"), context)?; then.call(this, &[then_finally.into(), catch_finally.into()], context) } @@ -1685,7 +1685,7 @@ impl Promise { let value_thunk = return_value.length(0).name("").build(); // v. Return ? Invoke(promise, "then", « valueThunk »). - promise.invoke(js_str!("then"), &[value_thunk.into()], context) + promise.invoke(js_string!("then"), &[value_thunk.into()], context) }, FinallyCaptures { on_finally: on_finally.clone(), @@ -1736,7 +1736,7 @@ impl Promise { let thrower = throw_reason.length(0).name("").build(); // v. Return ? Invoke(promise, "then", « thrower »). - promise.invoke(js_str!("then"), &[thrower.into()], context) + promise.invoke(js_string!("then"), &[thrower.into()], context) }, FinallyCaptures { on_finally, c }, ), @@ -1941,7 +1941,7 @@ impl Promise { context: &mut Context, ) -> JsResult { // 1. Let promiseResolve be ? Get(promiseConstructor, "resolve"). - let promise_resolve = promise_constructor.get(js_str!("resolve"), context)?; + let promise_resolve = promise_constructor.get(js_string!("resolve"), context)?; // 2. If IsCallable(promiseResolve) is false, throw a TypeError exception. promise_resolve.as_callable().cloned().ok_or_else(|| { @@ -2139,7 +2139,7 @@ impl Promise { }; // 9. Let then be Completion(Get(resolution, "then")). - let then_action = match then.get(js_str!("then"), context) { + let then_action = match then.get(js_string!("then"), context) { // 10. If then is an abrupt completion, then Err(e) => { // a. Perform RejectPromise(promise, then.[[Value]]). diff --git a/core/engine/src/builtins/proxy/mod.rs b/core/engine/src/builtins/proxy/mod.rs index f92daa30f16..f99ed9bc07a 100644 --- a/core/engine/src/builtins/proxy/mod.rs +++ b/core/engine/src/builtins/proxy/mod.rs @@ -31,7 +31,6 @@ use crate::{ Context, JsArgs, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, GcRefCell, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use rustc_hash::FxHashSet; @@ -237,12 +236,12 @@ impl Proxy { // 6. Perform ! CreateDataPropertyOrThrow(result, "proxy", p). result - .create_data_property_or_throw(js_str!("proxy"), p, context) + .create_data_property_or_throw(js_string!("proxy"), p, context) .expect("CreateDataPropertyOrThrow cannot fail here"); // 7. Perform ! CreateDataPropertyOrThrow(result, "revoke", revoker). result - .create_data_property_or_throw(js_str!("revoke"), revoker, context) + .create_data_property_or_throw(js_string!("revoke"), revoker, context) .expect("CreateDataPropertyOrThrow cannot fail here"); // 8. Return result. @@ -270,7 +269,7 @@ pub(crate) fn proxy_exotic_get_prototype_of( .try_data()?; // 5. Let trap be ? GetMethod(handler, "getPrototypeOf"). - let Some(trap) = handler.get_method(js_str!("getPrototypeOf"), context)? else { + let Some(trap) = handler.get_method(js_string!("getPrototypeOf"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[GetPrototypeOf]](). return target.__get_prototype_of__(context); @@ -331,7 +330,7 @@ pub(crate) fn proxy_exotic_set_prototype_of( .try_data()?; // 5. Let trap be ? GetMethod(handler, "setPrototypeOf"). - let Some(trap) = handler.get_method(js_str!("setPrototypeOf"), context)? else { + let Some(trap) = handler.get_method(js_string!("setPrototypeOf"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[SetPrototypeOf]](V). return target.__set_prototype_of__(val, context); @@ -390,7 +389,7 @@ pub(crate) fn proxy_exotic_is_extensible(obj: &JsObject, context: &mut Context) .try_data()?; // 5. Let trap be ? GetMethod(handler, "isExtensible"). - let Some(trap) = handler.get_method(js_str!("isExtensible"), context)? else { + let Some(trap) = handler.get_method(js_string!("isExtensible"), context)? else { // 6. If trap is undefined, then // a. Return ? IsExtensible(target). return target.is_extensible(context); @@ -435,7 +434,7 @@ pub(crate) fn proxy_exotic_prevent_extensions( .try_data()?; // 5. Let trap be ? GetMethod(handler, "preventExtensions"). - let Some(trap) = handler.get_method(js_str!("preventExtensions"), context)? else { + let Some(trap) = handler.get_method(js_string!("preventExtensions"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[PreventExtensions]](). return target.__prevent_extensions__(context); @@ -482,7 +481,7 @@ pub(crate) fn proxy_exotic_get_own_property( .try_data()?; // 5. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor"). - let Some(trap) = handler.get_method(js_str!("getOwnPropertyDescriptor"), context)? else { + let Some(trap) = handler.get_method(js_string!("getOwnPropertyDescriptor"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[GetOwnProperty]](P). return target.__get_own_property__(key, context); @@ -607,7 +606,7 @@ pub(crate) fn proxy_exotic_define_own_property( .try_data()?; // 5. Let trap be ? GetMethod(handler, "defineProperty"). - let Some(trap) = handler.get_method(js_str!("defineProperty"), context)? else { + let Some(trap) = handler.get_method(js_string!("defineProperty"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[DefineOwnProperty]](P, Desc). return target.__define_own_property__(key, desc, context); @@ -719,7 +718,7 @@ pub(crate) fn proxy_exotic_has_property( .try_data()?; // 5. Let trap be ? GetMethod(handler, "has"). - let Some(trap) = handler.get_method(js_str!("has"), context)? else { + let Some(trap) = handler.get_method(js_string!("has"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[HasProperty]](P). return target.has_property(key.clone(), context); @@ -811,7 +810,7 @@ pub(crate) fn proxy_exotic_get( .try_data()?; // 5. Let trap be ? GetMethod(handler, "get"). - let Some(trap) = handler.get_method(js_str!("get"), context)? else { + let Some(trap) = handler.get_method(js_string!("get"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[Get]](P, Receiver). return target.__get__(key, receiver, context); @@ -881,7 +880,7 @@ pub(crate) fn proxy_exotic_set( .try_data()?; // 5. Let trap be ? GetMethod(handler, "set"). - let Some(trap) = handler.get_method(js_str!("set"), context)? else { + let Some(trap) = handler.get_method(js_string!("set"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[Set]](P, V, Receiver). return target.__set__(key, value, receiver, context); @@ -961,7 +960,7 @@ pub(crate) fn proxy_exotic_delete( .try_data()?; // 5. Let trap be ? GetMethod(handler, "deleteProperty"). - let Some(trap) = handler.get_method(js_str!("deleteProperty"), context)? else { + let Some(trap) = handler.get_method(js_string!("deleteProperty"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[Delete]](P). return target.__delete__(key, context); @@ -1026,7 +1025,7 @@ pub(crate) fn proxy_exotic_own_property_keys( .try_data()?; // 5. Let trap be ? GetMethod(handler, "ownKeys"). - let Some(trap) = handler.get_method(js_str!("ownKeys"), context)? else { + let Some(trap) = handler.get_method(js_string!("ownKeys"), context)? else { // 6. If trap is undefined, then // a. Return ? target.[[OwnPropertyKeys]](). return target.__own_property_keys__(context); @@ -1160,7 +1159,7 @@ fn proxy_exotic_call( .try_data()?; // 5. Let trap be ? GetMethod(handler, "apply"). - let Some(trap) = handler.get_method(js_str!("apply"), context)? else { + let Some(trap) = handler.get_method(js_string!("apply"), context)? else { // 6. If trap is undefined, then // a. Return ? Call(target, thisArgument, argumentsList). return Ok(target.__call__(argument_count)); @@ -1208,7 +1207,7 @@ fn proxy_exotic_construct( assert!(target.is_constructor()); // 6. Let trap be ? GetMethod(handler, "construct"). - let Some(trap) = handler.get_method(js_str!("construct"), context)? else { + let Some(trap) = handler.get_method(js_string!("construct"), context)? else { // 7. If trap is undefined, then // a. Return ? Construct(target, argumentsList, newTarget). return Ok(target.__construct__(argument_count)); diff --git a/core/engine/src/builtins/regexp/mod.rs b/core/engine/src/builtins/regexp/mod.rs index 73c0f57ef2c..9fb6a1f7c29 100644 --- a/core/engine/src/builtins/regexp/mod.rs +++ b/core/engine/src/builtins/regexp/mod.rs @@ -241,12 +241,12 @@ impl BuiltInConstructor for RegExp { (p, f) } else if let Some(pattern) = pattern_is_regexp { // a. Let P be ? Get(pattern, "source"). - let p = pattern.get(js_str!("source"), context)?; + let p = pattern.get(js_string!("source"), context)?; // b. If flags is undefined, then let f = if flags.is_undefined() { // i. Let F be ? Get(pattern, "flags"). - pattern.get(js_str!("flags"), context)? + pattern.get(js_string!("flags"), context)? // c. Else, } else { // i. Let F be flags. @@ -643,49 +643,49 @@ impl RegExp { // 4. Let hasIndices be ToBoolean(? Get(R, "hasIndices")). // 5. If hasIndices is true, append the code unit 0x0064 (LATIN SMALL LETTER D) to codeUnits. - if object.get(js_str!("hasIndices"), context)?.to_boolean() { + if object.get(js_string!("hasIndices"), context)?.to_boolean() { code_units.push('d'); } // 6. Let global be ToBoolean(? Get(R, "global")). // 7. If global is true, append the code unit 0x0067 (LATIN SMALL LETTER G) to codeUnits. - if object.get(js_str!("global"), context)?.to_boolean() { + if object.get(js_string!("global"), context)?.to_boolean() { code_units.push('g'); } // 8. Let ignoreCase be ToBoolean(? Get(R, "ignoreCase")). // 9. If ignoreCase is true, append the code unit 0x0069 (LATIN SMALL LETTER I) to codeUnits. - if object.get(js_str!("ignoreCase"), context)?.to_boolean() { + if object.get(js_string!("ignoreCase"), context)?.to_boolean() { code_units.push('i'); } // 10. Let multiline be ToBoolean(? Get(R, "multiline")). // 11. If multiline is true, append the code unit 0x006D (LATIN SMALL LETTER M) to codeUnits. - if object.get(js_str!("multiline"), context)?.to_boolean() { + if object.get(js_string!("multiline"), context)?.to_boolean() { code_units.push('m'); } // 12. Let dotAll be ToBoolean(? Get(R, "dotAll")). // 13. If dotAll is true, append the code unit 0x0073 (LATIN SMALL LETTER S) to codeUnits. - if object.get(js_str!("dotAll"), context)?.to_boolean() { + if object.get(js_string!("dotAll"), context)?.to_boolean() { code_units.push('s'); } // 14. Let unicode be ToBoolean(? Get(R, "unicode")). // 15. If unicode is true, append the code unit 0x0075 (LATIN SMALL LETTER U) to codeUnits. - if object.get(js_str!("unicode"), context)?.to_boolean() { + if object.get(js_string!("unicode"), context)?.to_boolean() { code_units.push('u'); } // 16. Let unicodeSets be ToBoolean(? Get(R, "unicodeSets")). // 17. If unicodeSets is true, append the code unit 0x0076 (LATIN SMALL LETTER V) to codeUnits. - if object.get(js_str!("unicodeSets"), context)?.to_boolean() { + if object.get(js_string!("unicodeSets"), context)?.to_boolean() { code_units.push('v'); } // 18. Let sticky be ToBoolean(? Get(R, "sticky")). // 19. If sticky is true, append the code unit 0x0079 (LATIN SMALL LETTER Y) to codeUnits. - if object.get(js_str!("sticky"), context)?.to_boolean() { + if object.get(js_string!("sticky"), context)?.to_boolean() { code_units.push('y'); } @@ -727,7 +727,7 @@ impl RegExp { this, &JsValue::new(context.intrinsics().constructors().regexp().prototype()), ) { - Ok(JsValue::new(js_str!("(?:)"))) + Ok(JsValue::new(js_string!("(?:)"))) } else { Err(JsNativeError::typ() .with_message("RegExp.prototype.source method called on incompatible value") @@ -755,7 +755,7 @@ impl RegExp { /// [spec]: https://tc39.es/ecma262/#sec-escaperegexppattern fn escape_pattern(src: &JsString, _flags: &JsString) -> JsValue { if src.is_empty() { - js_str!("(?:)").into() + js_string!("(?:)").into() } else { let mut s = Vec::with_capacity(src.len()); let mut buf = [0; 2]; @@ -866,7 +866,7 @@ impl RegExp { // 2. Assert: Type(S) is String. // 3. Let exec be ? Get(R, "exec"). - let exec = this.get(js_str!("exec"), context)?; + let exec = this.get(js_string!("exec"), context)?; // 4. If IsCallable(exec) is true, then if let Some(exec) = exec.as_callable() { @@ -919,7 +919,7 @@ impl RegExp { // 2. Let lastIndex be ℝ(? ToLength(? Get(R, "lastIndex"))). let mut last_index = this - .get(js_str!("lastIndex"), context)? + .get(js_string!("lastIndex"), context)? .to_length(context)?; // 3. Let flags be R.[[OriginalFlags]]. @@ -957,7 +957,7 @@ impl RegExp { // i. If global is true or sticky is true, then if global || sticky { // 1. Perform ? Set(R, "lastIndex", +0𝔽, true). - this.set(js_str!("lastIndex"), 0, true, context)?; + this.set(js_string!("lastIndex"), 0, true, context)?; } // ii. Return null. @@ -990,7 +990,7 @@ impl RegExp { // 13.a.i. If global is true or sticky is true, then if global || sticky { // 1. Perform ? Set(R, "lastIndex", +0𝔽, true). - this.set(js_str!("lastIndex"), 0, true, context)?; + this.set(js_string!("lastIndex"), 0, true, context)?; } // MOVE: ii. Set lastIndex to AdvanceStringIndex(S, lastIndex, fullUnicode). @@ -1009,7 +1009,7 @@ impl RegExp { // NOTE: regress currently doesn't support the sticky flag so we have to emulate it. if sticky && match_value.start() != last_index as usize { // 1. Perform ? Set(R, "lastIndex", +0𝔽, true). - this.set(js_str!("lastIndex"), 0, true, context)?; + this.set(js_string!("lastIndex"), 0, true, context)?; // 2. Return null. return Ok(None); @@ -1027,7 +1027,7 @@ impl RegExp { // 16. If global is true or sticky is true, then if global || sticky { // a. Perform ? Set(R, "lastIndex", 𝔽(e), true). - this.set(js_str!("lastIndex"), e, true, context)?; + this.set(js_string!("lastIndex"), e, true, context)?; } // 17. Let n be the number of elements in r's captures List. @@ -1041,11 +1041,11 @@ impl RegExp { let a = Array::array_create(n + 1, None, context)?; // 22. Perform ! CreateDataPropertyOrThrow(A, "index", 𝔽(lastIndex)). - a.create_data_property_or_throw(js_str!("index"), last_index, context) + a.create_data_property_or_throw(js_string!("index"), last_index, context) .expect("this CreateDataPropertyOrThrow call must not fail"); // 23. Perform ! CreateDataPropertyOrThrow(A, "input", S). - a.create_data_property_or_throw(js_str!("input"), input.clone(), context) + a.create_data_property_or_throw(js_string!("input"), input.clone(), context) .expect("this CreateDataPropertyOrThrow call must not fail"); // 24. Let match be the Match Record { [[StartIndex]]: lastIndex, [[EndIndex]]: e }. @@ -1141,11 +1141,11 @@ impl RegExp { // 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups ) // 8. Perform ! CreateDataPropertyOrThrow(A, "groups", groups). indices - .create_data_property_or_throw(js_str!("groups"), group_names, context) + .create_data_property_or_throw(js_string!("groups"), group_names, context) .expect("this CreateDataPropertyOrThrow call must not fail"); // 32. Perform ! CreateDataPropertyOrThrow(A, "groups", groups). - a.create_data_property_or_throw(js_str!("groups"), groups, context) + a.create_data_property_or_throw(js_string!("groups"), groups, context) .expect("this CreateDataPropertyOrThrow call must not fail"); // 27. For each integer i such that i ≥ 1 and i ≤ n, in ascending order, do @@ -1186,7 +1186,7 @@ impl RegExp { // a. Let indicesArray be MakeMatchIndicesIndexPairArray(S, indices, groupNames, hasGroups). // b. Perform ! CreateDataPropertyOrThrow(A, "indices", indicesArray). if has_indices { - a.create_data_property_or_throw(js_str!("indices"), indices, context) + a.create_data_property_or_throw(js_string!("indices"), indices, context) .expect("this CreateDataPropertyOrThrow call must not fail"); } @@ -1221,7 +1221,7 @@ impl RegExp { let arg_str = args.get_or_undefined(0).to_string(context)?; // 4. Let flags be ? ToString(? Get(rx, "flags")). - let flags = rx.get(js_str!("flags"), context)?.to_string(context)?; + let flags = rx.get(js_string!("flags"), context)?.to_string(context)?; // 5. If flags does not contain "g", then if !flags.contains(b'g') { @@ -1236,7 +1236,7 @@ impl RegExp { let full_unicode = flags.contains(b'u') || flags.contains(b'v'); // b. Perform ? Set(rx, "lastIndex", +0𝔽, true). - rx.set(js_str!("lastIndex"), 0, true, context)?; + rx.set(js_string!("lastIndex"), 0, true, context)?; // c. Let A be ! ArrayCreate(0). let a = Array::array_create(0, None, context).expect("this ArrayCreate call must not fail"); @@ -1262,14 +1262,16 @@ impl RegExp { // 3. If matchStr is the empty String, then if match_str.is_empty() { // a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))). - let this_index = rx.get(js_str!("lastIndex"), context)?.to_length(context)?; + let this_index = rx + .get(js_string!("lastIndex"), context)? + .to_length(context)?; // b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode). let next_index = advance_string_index(&arg_str, this_index, full_unicode); // c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true). rx.set( - js_str!("lastIndex"), + js_string!("lastIndex"), JsValue::new(next_index), true, context, @@ -1313,10 +1315,14 @@ impl RegExp { })?; // 3. Let pattern be ? ToString(? Get(R, "source")). - let pattern = regexp.get(js_str!("source"), context)?.to_string(context)?; + let pattern = regexp + .get(js_string!("source"), context)? + .to_string(context)?; // 4. Let flags be ? ToString(? Get(R, "flags")). - let flags = regexp.get(js_str!("flags"), context)?.to_string(context)?; + let flags = regexp + .get(js_string!("flags"), context)? + .to_string(context)?; // 5. Let result be the string-concatenation of "/", pattern, "/", and flags. // 6. Return result. @@ -1352,18 +1358,20 @@ impl RegExp { let c = regexp.species_constructor(StandardConstructors::regexp, context)?; // 5. Let flags be ? ToString(? Get(R, "flags")). - let flags = regexp.get(js_str!("flags"), context)?.to_string(context)?; + let flags = regexp + .get(js_string!("flags"), context)? + .to_string(context)?; // 6. Let matcher be ? Construct(C, « R, flags »). let matcher = c.construct(&[this.clone(), flags.clone().into()], Some(&c), context)?; // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). let last_index = regexp - .get(js_str!("lastIndex"), context)? + .get(js_string!("lastIndex"), context)? .to_length(context)?; // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). - matcher.set(js_str!("lastIndex"), last_index, true, context)?; + matcher.set(js_string!("lastIndex"), last_index, true, context)?; // 9. If flags contains "g", let global be true. // 10. Else, let global be false. @@ -1434,7 +1442,7 @@ impl RegExp { }; // 7. Let flags be ? ToString(? Get(rx, "flags")). - let flags = rx.get(js_str!("flags"), context)?.to_string(context)?; + let flags = rx.get(js_string!("flags"), context)?.to_string(context)?; // 8. If flags contains "g", let global be true. Otherwise, let global be false. let global = flags.contains(b'g'); @@ -1445,7 +1453,7 @@ impl RegExp { let full_unicode = flags.contains(b'u'); // b. Perform ? Set(rx, "lastIndex", +0𝔽, true). - rx.set(js_str!("lastIndex"), 0, true, context)?; + rx.set(js_string!("lastIndex"), 0, true, context)?; full_unicode } else { @@ -1487,14 +1495,16 @@ impl RegExp { // 2. If matchStr is the empty String, then if match_str.is_empty() { // a. Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))). - let this_index = rx.get(js_str!("lastIndex"), context)?.to_length(context)?; + let this_index = rx + .get(js_string!("lastIndex"), context)? + .to_length(context)?; // b. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode). let next_index = advance_string_index(&s, this_index, full_unicode); // c. Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true). rx.set( - js_str!("lastIndex"), + js_string!("lastIndex"), JsValue::new(next_index), true, context, @@ -1527,7 +1537,7 @@ impl RegExp { // e. Let position be ? ToIntegerOrInfinity(? Get(result, "index")). let position = result - .get(js_str!("index"), context)? + .get(js_string!("index"), context)? .to_integer_or_infinity(context)?; // f. Set position to the result of clamping position between 0 and lengthS. @@ -1559,7 +1569,7 @@ impl RegExp { } // j. Let namedCaptures be ? Get(result, "groups"). - let mut named_captures = result.get(js_str!("groups"), context)?; + let mut named_captures = result.get(js_string!("groups"), context)?; let replacement = match replace_value { // k. If functionalReplace is true, then @@ -1659,31 +1669,31 @@ impl RegExp { let arg_str = args.get_or_undefined(0).to_string(context)?; // 4. Let previousLastIndex be ? Get(rx, "lastIndex"). - let previous_last_index = rx.get(js_str!("lastIndex"), context)?; + let previous_last_index = rx.get(js_string!("lastIndex"), context)?; // 5. If SameValue(previousLastIndex, +0𝔽) is false, then if !JsValue::same_value(&previous_last_index, &JsValue::new(0)) { // a. Perform ? Set(rx, "lastIndex", +0𝔽, true). - rx.set(js_str!("lastIndex"), 0, true, context)?; + rx.set(js_string!("lastIndex"), 0, true, context)?; } // 6. Let result be ? RegExpExec(rx, S). let result = Self::abstract_exec(rx, arg_str, context)?; // 7. Let currentLastIndex be ? Get(rx, "lastIndex"). - let current_last_index = rx.get(js_str!("lastIndex"), context)?; + let current_last_index = rx.get(js_string!("lastIndex"), context)?; // 8. If SameValue(currentLastIndex, previousLastIndex) is false, then if !JsValue::same_value(¤t_last_index, &previous_last_index) { // a. Perform ? Set(rx, "lastIndex", previousLastIndex, true). - rx.set(js_str!("lastIndex"), previous_last_index, true, context)?; + rx.set(js_string!("lastIndex"), previous_last_index, true, context)?; } // 9. If result is null, return -1𝔽. // 10. Return ? Get(result, "index"). result.map_or_else( || Ok(JsValue::new(-1)), - |result| result.get(js_str!("index"), context), + |result| result.get(js_string!("index"), context), ) } @@ -1716,7 +1726,7 @@ impl RegExp { let constructor = rx.species_constructor(StandardConstructors::regexp, context)?; // 5. Let flags be ? ToString(? Get(rx, "flags")). - let flags = rx.get(js_str!("flags"), context)?.to_string(context)?; + let flags = rx.get(js_string!("flags"), context)?.to_string(context)?; // 6. If flags contains "u", let unicodeMatching be true. // 7. Else, let unicodeMatching be false. @@ -1785,7 +1795,7 @@ impl RegExp { // 19. Repeat, while q < size, while q < size { // a. Perform ? Set(splitter, "lastIndex", 𝔽(q), true). - splitter.set(js_str!("lastIndex"), JsValue::new(q), true, context)?; + splitter.set(js_string!("lastIndex"), JsValue::new(q), true, context)?; // b. Let z be ? RegExpExec(splitter, S). let result = Self::abstract_exec(&splitter, arg_str.clone(), context)?; @@ -1795,7 +1805,7 @@ impl RegExp { if let Some(result) = result { // i. Let e be ℝ(? ToLength(? Get(splitter, "lastIndex"))). let mut e = splitter - .get(js_str!("lastIndex"), context)? + .get(js_string!("lastIndex"), context)? .to_length(context)?; // ii. Set e to min(e, size). @@ -1919,7 +1929,7 @@ impl RegExp { .expect("already checked that the object was a RegExp") = regexp; } - this.set(js_str!("lastIndex"), 0, true, context)?; + this.set(js_string!("lastIndex"), 0, true, context)?; Ok(this.into()) } diff --git a/core/engine/src/builtins/regexp/regexp_string_iterator.rs b/core/engine/src/builtins/regexp/regexp_string_iterator.rs index 2cb8620a8a5..356e4e5e6da 100644 --- a/core/engine/src/builtins/regexp/regexp_string_iterator.rs +++ b/core/engine/src/builtins/regexp/regexp_string_iterator.rs @@ -22,7 +22,6 @@ use crate::{ Context, JsData, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use regexp::{advance_string_index, RegExp}; @@ -160,7 +159,7 @@ impl RegExpStringIterator { // 1. Let thisIndex be ℝ(? ToLength(? Get(R, "lastIndex"))). let this_index = iterator .matcher - .get(js_str!("lastIndex"), context)? + .get(js_string!("lastIndex"), context)? .to_length(context)?; // 2. Let nextIndex be ! AdvanceStringIndex(S, thisIndex, fullUnicode). @@ -170,7 +169,7 @@ impl RegExpStringIterator { // 3. Perform ? Set(R, "lastIndex", 𝔽(nextIndex), true). iterator .matcher - .set(js_str!("lastIndex"), next_index, true, context)?; + .set(js_string!("lastIndex"), next_index, true, context)?; } // vi. Perform ? Yield(match). diff --git a/core/engine/src/builtins/set/mod.rs b/core/engine/src/builtins/set/mod.rs index a78984b187a..1b7d463ea50 100644 --- a/core/engine/src/builtins/set/mod.rs +++ b/core/engine/src/builtins/set/mod.rs @@ -30,7 +30,6 @@ use crate::{ symbol::JsSymbol, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use num_traits::Zero; @@ -146,7 +145,7 @@ impl BuiltInConstructor for Set { } // 5. Let adder be ? Get(set, "add"). - let adder = set.get(js_str!("add"), context)?; + let adder = set.get(js_string!("add"), context)?; // 6. If IsCallable(adder) is false, throw a TypeError exception. let adder = adder.as_callable().ok_or_else(|| { diff --git a/core/engine/src/builtins/string/mod.rs b/core/engine/src/builtins/string/mod.rs index 22bab2cb550..baa4b24d771 100644 --- a/core/engine/src/builtins/string/mod.rs +++ b/core/engine/src/builtins/string/mod.rs @@ -22,7 +22,8 @@ use crate::{ value::IntegerOrInfinity, Context, JsArgs, JsResult, JsString, JsValue, }; -use boa_macros::{js_str, utf16}; +use boa_macros::utf16; + use boa_profiler::Profiler; use icu_normalizer::{ComposingNormalizer, DecomposingNormalizer}; use std::cmp::{max, min}; @@ -33,7 +34,7 @@ mod string_iterator; pub(crate) use string_iterator::StringIterator; #[cfg(feature = "annex-b")] -pub use crate::JsStr; +pub use crate::{js_str, JsStr}; /// The set of normalizers required for the `String.prototype.normalize` function. #[derive(Debug)] @@ -387,7 +388,7 @@ impl String { let cooked = args.get_or_undefined(0).to_object(context)?; // 3. Let raw be ? ToObject(? Get(cooked, "raw")). - let raw = cooked.get(js_str!("raw"), context)?.to_object(context)?; + let raw = cooked.get(js_string!("raw"), context)?.to_object(context)?; // 4. Let literalSegments be ? LengthOfArrayLike(raw). let literal_segments = raw.length_of_array_like(context)?; @@ -1129,7 +1130,7 @@ impl String { // b. If isRegExp is true, then if let Some(obj) = RegExp::is_reg_exp(search_value, context)? { // i. Let flags be ? Get(searchValue, "flags"). - let flags = obj.get(js_str!("flags"), context)?; + let flags = obj.get(js_string!("flags"), context)?; // ii. Perform ? RequireObjectCoercible(flags). flags.require_object_coercible()?; @@ -2074,7 +2075,7 @@ impl String { // b. If isRegExp is true, then if let Some(regexp) = RegExp::is_reg_exp(regexp, context)? { // i. Let flags be ? Get(regexp, "flags"). - let flags = regexp.get(js_str!("flags"), context)?; + let flags = regexp.get(js_string!("flags"), context)?; // ii. Perform ? RequireObjectCoercible(flags). flags.require_object_coercible()?; @@ -2100,7 +2101,7 @@ impl String { let s = o.to_string(context)?; // 4. Let rx be ? RegExpCreate(regexp, "g"). - let rx = RegExp::create(regexp, &JsValue::new(js_str!("g")), context)?; + let rx = RegExp::create(regexp, &JsValue::new(js_string!("g")), context)?; // 5. Return ? Invoke(rx, @@matchAll, « S »). rx.invoke(JsSymbol::match_all(), &[JsValue::new(s)], context) diff --git a/core/engine/src/builtins/temporal/calendar/mod.rs b/core/engine/src/builtins/temporal/calendar/mod.rs index 11b5a4a049b..665daee341f 100644 --- a/core/engine/src/builtins/temporal/calendar/mod.rs +++ b/core/engine/src/builtins/temporal/calendar/mod.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use super::extract_from_temporal_type; -use crate::{js_str, Context, JsNativeError, JsObject, JsResult, JsValue}; +use crate::{js_string, Context, JsNativeError, JsObject, JsResult, JsValue}; use temporal_rs::components::calendar::Calendar; // -- `Calendar` Abstract Operations -- @@ -32,7 +32,7 @@ pub(crate) fn get_temporal_calendar_slot_value_with_default( } // 2. Let calendarLike be ? Get(item, "calendar"). - let calendar_like = item.get(js_str!("calendar"), context)?; + let calendar_like = item.get(js_string!("calendar"), context)?; // 3. Return ? ToTemporalCalendarSlotValue(calendarLike, "iso8601"). to_temporal_calendar_slot_value(&calendar_like) diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index b302de2c733..30f053f00ea 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -14,7 +14,6 @@ use crate::{ Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use temporal_rs::{ components::{duration::PartialDuration, Duration as InnerDuration}, @@ -659,7 +658,7 @@ impl Duration { let new_round_to = JsObject::with_null_proto(); // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). new_round_to.create_data_property_or_throw( - js_str!("smallestUnit"), + js_string!("smallestUnit"), param_string, context, )?; @@ -681,7 +680,7 @@ impl Duration { // 9. Let largestUnit be ? GetTemporalUnit(roundTo, "largestUnit", datetime, undefined, « "auto" »). options.largest_unit = get_temporal_unit( &round_to, - js_str!("largestUnit"), + js_string!("largestUnit"), TemporalUnitGroup::DateTime, Some([TemporalUnit::Auto].into()), context, @@ -695,16 +694,16 @@ impl Duration { // 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). options.increment = - get_option::(&round_to, js_str!("roundingIncrement"), context)?; + get_option::(&round_to, js_string!("roundingIncrement"), context)?; // 14. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). options.rounding_mode = - get_option::(&round_to, js_str!("roundingMode"), context)?; + get_option::(&round_to, js_string!("roundingMode"), context)?; // 15. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", datetime, undefined). options.smallest_unit = get_temporal_unit( &round_to, - js_str!("smallestUnit"), + js_string!("smallestUnit"), TemporalUnitGroup::DateTime, None, context, @@ -754,7 +753,7 @@ impl Duration { let total_of = JsObject::with_null_proto(); // c. Perform ! CreateDataPropertyOrThrow(totalOf, "unit", paramString). total_of.create_data_property_or_throw( - js_str!("unit"), + js_string!("unit"), param_string.clone(), context, )?; @@ -777,7 +776,7 @@ impl Duration { // 10. Let unit be ? GetTemporalUnit(totalOf, "unit", datetime, required). let _unit = get_temporal_unit( &total_of, - js_str!("unit"), + js_string!("unit"), TemporalUnitGroup::DateTime, None, context, @@ -935,7 +934,7 @@ pub(crate) fn to_temporal_partial_duration( // 3. NOTE: The following steps read properties and perform independent validation in alphabetical order. // 4. Let days be ? Get(temporalDurationLike, "days"). - let days = unknown_object.get(js_str!("days"), context)?; + let days = unknown_object.get(js_string!("days"), context)?; if !days.is_undefined() { // 5. If days is not undefined, set result.[[Days]] to ? ToIntegerIfIntegral(days). let _ = result @@ -944,7 +943,7 @@ pub(crate) fn to_temporal_partial_duration( } // 6. Let hours be ? Get(temporalDurationLike, "hours"). - let hours = unknown_object.get(js_str!("hours"), context)?; + let hours = unknown_object.get(js_string!("hours"), context)?; // 7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours). if !hours.is_undefined() { let _ = result @@ -953,7 +952,7 @@ pub(crate) fn to_temporal_partial_duration( } // 8. Let microseconds be ? Get(temporalDurationLike, "microseconds"). - let microseconds = unknown_object.get(js_str!("microseconds"), context)?; + let microseconds = unknown_object.get(js_string!("microseconds"), context)?; // 9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds). if !microseconds.is_undefined() { let _ = result @@ -965,7 +964,7 @@ pub(crate) fn to_temporal_partial_duration( } // 10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds"). - let milliseconds = unknown_object.get(js_str!("milliseconds"), context)?; + let milliseconds = unknown_object.get(js_string!("milliseconds"), context)?; // 11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds). if !milliseconds.is_undefined() { let _ = result @@ -977,7 +976,7 @@ pub(crate) fn to_temporal_partial_duration( } // 12. Let minutes be ? Get(temporalDurationLike, "minutes"). - let minutes = unknown_object.get(js_str!("minutes"), context)?; + let minutes = unknown_object.get(js_string!("minutes"), context)?; // 13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes). if !minutes.is_undefined() { let _ = result @@ -986,7 +985,7 @@ pub(crate) fn to_temporal_partial_duration( } // 14. Let months be ? Get(temporalDurationLike, "months"). - let months = unknown_object.get(js_str!("months"), context)?; + let months = unknown_object.get(js_string!("months"), context)?; // 15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months). if !months.is_undefined() { let _ = result @@ -995,7 +994,7 @@ pub(crate) fn to_temporal_partial_duration( } // 16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds"). - let nanoseconds = unknown_object.get(js_str!("nanoseconds"), context)?; + let nanoseconds = unknown_object.get(js_string!("nanoseconds"), context)?; // 17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds). if !nanoseconds.is_undefined() { let _ = result @@ -1007,7 +1006,7 @@ pub(crate) fn to_temporal_partial_duration( } // 18. Let seconds be ? Get(temporalDurationLike, "seconds"). - let seconds = unknown_object.get(js_str!("seconds"), context)?; + let seconds = unknown_object.get(js_string!("seconds"), context)?; // 19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds). if !seconds.is_undefined() { let _ = result @@ -1016,7 +1015,7 @@ pub(crate) fn to_temporal_partial_duration( } // 20. Let weeks be ? Get(temporalDurationLike, "weeks"). - let weeks = unknown_object.get(js_str!("weeks"), context)?; + let weeks = unknown_object.get(js_string!("weeks"), context)?; // 21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks). if !weeks.is_undefined() { let _ = result @@ -1025,7 +1024,7 @@ pub(crate) fn to_temporal_partial_duration( } // 22. Let years be ? Get(temporalDurationLike, "years"). - let years = unknown_object.get(js_str!("years"), context)?; + let years = unknown_object.get(js_string!("years"), context)?; // 23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years). if !years.is_undefined() { let _ = result diff --git a/core/engine/src/builtins/temporal/instant/mod.rs b/core/engine/src/builtins/temporal/instant/mod.rs index 771e0011d9b..a5746555325 100644 --- a/core/engine/src/builtins/temporal/instant/mod.rs +++ b/core/engine/src/builtins/temporal/instant/mod.rs @@ -21,7 +21,6 @@ use crate::{ JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use num_traits::ToPrimitive; use temporal_rs::{ @@ -70,25 +69,25 @@ impl IntrinsicObject for Instant { Attribute::CONFIGURABLE, ) .accessor( - js_str!("epochSeconds"), + js_string!("epochSeconds"), Some(get_seconds), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("epochMilliseconds"), + js_string!("epochMilliseconds"), Some(get_millis), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("epochMicroseconds"), + js_string!("epochMicroseconds"), Some(get_micros), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("epochNanoseconds"), + js_string!("epochNanoseconds"), Some(get_nanos), None, Attribute::CONFIGURABLE, @@ -429,7 +428,7 @@ impl Instant { let new_round_to = JsObject::with_null_proto(); // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). new_round_to.create_data_property_or_throw( - js_str!("smallestUnit"), + js_string!("smallestUnit"), param_string, context, )?; @@ -447,16 +446,16 @@ impl Instant { let mut options = RoundingOptions::default(); // 7. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). options.increment = - get_option::(&round_to, js_str!("roundingIncrement"), context)?; + get_option::(&round_to, js_string!("roundingIncrement"), context)?; // 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). options.rounding_mode = - get_option::(&round_to, js_str!("roundingMode"), context)?; + get_option::(&round_to, js_string!("roundingMode"), context)?; // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit"), time, required). let smallest_unit = get_temporal_unit( &round_to, - js_str!("smallestUnit"), + js_string!("smallestUnit"), TemporalUnitGroup::Time, None, context, diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index 9f4fd983aa0..bd4128b3a3b 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -30,13 +30,12 @@ use crate::{ builtins::{iterable::IteratorRecord, BuiltInBuilder, BuiltInObject, IntrinsicObject}, context::intrinsics::Intrinsics, js_string, - property::{Attribute, PropertyKey}, + property::Attribute, realm::Realm, string::StaticJsStrings, value::Type, Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; -use boa_macros::js_str; use boa_profiler::Profiler; use temporal_rs::{ components::{Date as TemporalDate, ZonedDateTime as TemporalZonedDateTime}, @@ -246,7 +245,7 @@ pub(crate) fn to_relative_temporal_object( options: &JsObject, context: &mut Context, ) -> RelativeTemporalObjectResult { - let relative_to = options.get(PropertyKey::from(js_str!("relativeTo")), context)?; + let relative_to = options.get(js_string!("relativeTo"), context)?; let plain_date = match relative_to { JsValue::String(relative_to_str) => JsValue::from(relative_to_str), JsValue::Object(relative_to_obj) => JsValue::from(relative_to_obj), @@ -297,13 +296,13 @@ pub(crate) fn is_partial_temporal_object<'value>( } // 3. Let calendarProperty be ? Get(value, "calendar"). - let calendar_property = obj.get(js_str!("calendar"), context)?; + let calendar_property = obj.get(js_string!("calendar"), context)?; // 4. If calendarProperty is not undefined, return false. if !calendar_property.is_undefined() { return Ok(None); } // 5. Let timeZoneProperty be ? Get(value, "timeZone"). - let time_zone_property = obj.get(js_str!("timeZone"), context)?; + let time_zone_property = obj.get(js_string!("timeZone"), context)?; // 6. If timeZoneProperty is not undefined, return false. if !time_zone_property.is_undefined() { return Ok(None); diff --git a/core/engine/src/builtins/temporal/options.rs b/core/engine/src/builtins/temporal/options.rs index 06b83e2087c..0d369ff776e 100644 --- a/core/engine/src/builtins/temporal/options.rs +++ b/core/engine/src/builtins/temporal/options.rs @@ -10,10 +10,8 @@ use crate::{ builtins::options::{get_option, OptionType, ParsableOptionType}, - string::JsStr, - Context, JsNativeError, JsObject, JsResult, JsValue, + js_string, Context, JsNativeError, JsObject, JsResult, JsString, JsValue, }; -use boa_macros::js_str; use temporal_rs::options::{ ArithmeticOverflow, CalendarName, DifferenceSettings, DurationOverflow, InstantDisambiguation, OffsetDisambiguation, RoundingIncrement, TemporalRoundingMode, TemporalUnit, @@ -25,7 +23,7 @@ use temporal_rs::options::{ #[inline] pub(crate) fn get_temporal_unit( options: &JsObject, - key: JsStr<'_>, + key: JsString, unit_group: TemporalUnitGroup, extra_values: Option>, context: &mut Context, @@ -53,12 +51,14 @@ pub(crate) fn get_difference_settings( context: &mut Context, ) -> JsResult { let mut settings = DifferenceSettings::default(); - settings.largest_unit = get_option::(options, js_str!("largestUnit"), context)?; + settings.largest_unit = + get_option::(options, js_string!("largestUnit"), context)?; settings.increment = - get_option::(options, js_str!("roundingIncrement"), context)?; + get_option::(options, js_string!("roundingIncrement"), context)?; settings.rounding_mode = - get_option::(options, js_str!("roundingMode"), context)?; - settings.smallest_unit = get_option::(options, js_str!("smallestUnit"), context)?; + get_option::(options, js_string!("roundingMode"), context)?; + settings.smallest_unit = + get_option::(options, js_string!("smallestUnit"), context)?; Ok(settings) } diff --git a/core/engine/src/builtins/temporal/plain_date/mod.rs b/core/engine/src/builtins/temporal/plain_date/mod.rs index 345493d974c..f85cb56036f 100644 --- a/core/engine/src/builtins/temporal/plain_date/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date/mod.rs @@ -20,7 +20,6 @@ use crate::{ JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use temporal_rs::{ components::{ @@ -504,7 +503,7 @@ impl PlainDate { if let Some(date) = item.as_object().and_then(JsObject::downcast_ref::) { let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?; - let _ = get_option::(&options, js_str!("overflow"), context)?; + let _ = get_option::(&options, js_string!("overflow"), context)?; return create_temporal_date(date.inner.clone(), None, context).map(Into::into); } @@ -555,20 +554,28 @@ impl PlainDate { // 4. Perform ! CreateDataPropertyOrThrow(fields, "calendar", temporalDate.[[Calendar]]). fields.create_data_property_or_throw( - js_str!("calendar"), + js_string!("calendar"), JsString::from(date.inner.calendar().identifier()), context, )?; // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoDay", 𝔽(temporalDate.[[ISODay]])). - fields.create_data_property_or_throw(js_str!("isoDay"), date.inner.iso_day(), context)?; + fields.create_data_property_or_throw( + js_string!("isoDay"), + date.inner.iso_day(), + context, + )?; // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMonth", 𝔽(temporalDate.[[ISOMonth]])). fields.create_data_property_or_throw( - js_str!("isoMonth"), + js_string!("isoMonth"), date.inner.iso_month(), context, )?; // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoYear", 𝔽(temporalDate.[[ISOYear]])). - fields.create_data_property_or_throw(js_str!("isoYear"), date.inner.iso_year(), context)?; + fields.create_data_property_or_throw( + js_string!("isoYear"), + date.inner.iso_year(), + context, + )?; // 8. Return fields. Ok(fields.into()) } @@ -589,7 +596,7 @@ impl PlainDate { // 4. Set options to ? GetOptionsObject(options). let options = get_options_object(args.get_or_undefined(1))?; - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; // 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 6. Return ? AddDate(calendarRec, temporalDate, duration, options). @@ -611,7 +618,7 @@ impl PlainDate { // 4. Set options to ? GetOptionsObject(options). let options = get_options_object(args.get_or_undefined(1))?; - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; // 5. Let negatedDuration be CreateNegatedTemporalDuration(duration). // 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). @@ -648,7 +655,7 @@ impl PlainDate { // 7. Let partialDate be ? PrepareTemporalFields(temporalDateLike, fieldsResult.[[FieldNames]], partial). // 8. Let fields be ? CalendarMergeFields(calendarRec, fieldsResult.[[Fields]], partialDate). // 9. Set fields to ? PrepareTemporalFields(fields, fieldsResult.[[FieldNames]], «»). - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; let partial = to_partial_date_record(partial_object, context)?; // 10. Return ? CalendarDateFromFields(calendarRec, fields, resolvedOptions). @@ -833,7 +840,7 @@ pub(crate) fn to_temporal_date( // c. If item has an [[InitializedTemporalDateTime]] internal slot, then } else if let Some(date_time) = object.downcast_ref::() { // i. Perform ? ToTemporalOverflow(options). - let _o = get_option(&options_obj, js_str!("overflow"), context)? + let _o = get_option(&options_obj, js_string!("overflow"), context)? .unwrap_or(ArithmeticOverflow::Constrain); let date = InnerDate::from(date_time.inner().clone()); @@ -845,7 +852,7 @@ pub(crate) fn to_temporal_date( // d. Let calendar be ? GetTemporalCalendarSlotValueWithISODefault(item). let calendar = get_temporal_calendar_slot_value_with_default(object, context)?; let overflow = - get_option::(&options_obj, js_str!("overflow"), context)? + get_option::(&options_obj, js_string!("overflow"), context)? .unwrap_or(ArithmeticOverflow::Constrain); // e. Let fieldNames be ? CalendarFields(calendar, « "day", "month", "monthCode", "year" »). @@ -896,15 +903,15 @@ pub(crate) fn to_partial_date_record( context: &mut Context, ) -> JsResult { let day = partial_object - .get(js_str!("day"), context)? + .get(js_string!("day"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let month = partial_object - .get(js_str!("month"), context)? + .get(js_string!("month"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let month_code = partial_object - .get(js_str!("monthCode"), context)? + .get(js_string!("monthCode"), context)? .map(|v| { let JsValue::String(month_code) = v.to_primitive(context, crate::value::PreferredType::String)? @@ -917,15 +924,15 @@ pub(crate) fn to_partial_date_record( }) .transpose()?; let year = partial_object - .get(js_str!("year"), context)? + .get(js_string!("year"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let era_year = partial_object - .get(js_str!("eraYear"), context)? + .get(js_string!("eraYear"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let era = partial_object - .get(js_str!("era"), context)? + .get(js_string!("era"), context)? .map(|v| { let JsValue::String(era) = v.to_primitive(context, crate::value::PreferredType::String)? diff --git a/core/engine/src/builtins/temporal/plain_date_time/mod.rs b/core/engine/src/builtins/temporal/plain_date_time/mod.rs index e296e570eef..b8f965d6c78 100644 --- a/core/engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date_time/mod.rs @@ -16,7 +16,6 @@ use crate::{ Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; #[cfg(test)] @@ -163,116 +162,121 @@ impl IntrinsicObject for PlainDateTime { Attribute::CONFIGURABLE, ) .accessor( - js_str!("calendarId"), + js_string!("calendarId"), Some(get_calendar_id), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("year"), + js_string!("year"), Some(get_year), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("month"), + js_string!("month"), Some(get_month), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("monthCode"), + js_string!("monthCode"), Some(get_month_code), None, Attribute::CONFIGURABLE, ) - .accessor(js_str!("day"), Some(get_day), None, Attribute::CONFIGURABLE) .accessor( - js_str!("hour"), + js_string!("day"), + Some(get_day), + None, + Attribute::CONFIGURABLE, + ) + .accessor( + js_string!("hour"), Some(get_hour), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("minute"), + js_string!("minute"), Some(get_minute), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("second"), + js_string!("second"), Some(get_second), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("millisecond"), + js_string!("millisecond"), Some(get_millisecond), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("microsecond"), + js_string!("microsecond"), Some(get_microsecond), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("nanosecond"), + js_string!("nanosecond"), Some(get_nanosecond), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("dayOfWeek"), + js_string!("dayOfWeek"), Some(get_day_of_week), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("dayOfYear"), + js_string!("dayOfYear"), Some(get_day_of_year), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("weekOfYear"), + js_string!("weekOfYear"), Some(get_week_of_year), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("yearOfWeek"), + js_string!("yearOfWeek"), Some(get_year_of_week), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("daysInWeek"), + js_string!("daysInWeek"), Some(get_days_in_week), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("daysInMonth"), + js_string!("daysInMonth"), Some(get_days_in_month), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("daysInYear"), + js_string!("daysInYear"), Some(get_days_in_year), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("monthsInYear"), + js_string!("monthsInYear"), Some(get_months_in_year), None, Attribute::CONFIGURABLE, ) .accessor( - js_str!("inLeapYear"), + js_string!("inLeapYear"), Some(get_in_leap_year), None, Attribute::CONFIGURABLE, @@ -650,7 +654,7 @@ impl PlainDateTime { let dt = if let Some(pdt) = item.as_object().and_then(JsObject::downcast_ref::) { // a. Perform ? GetTemporalOverflowOption(options). let options = get_options_object(args.get_or_undefined(1))?; - let _ = get_option::(&options, js_str!("overflow"), context)?; + let _ = get_option::(&options, js_string!("overflow"), context)?; // b. Return ! CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], // item.[[ISODay]], item.[[ISOHour]], item.[[ISOMinute]], item.[[ISOSecond]], // item.[[ISOMillisecond]], item.[[ISOMicrosecond]], item.[[ISONanosecond]], @@ -706,7 +710,7 @@ impl PlainDateTime { let partial_dt = PartialDateTime { date, time }; - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; create_temporal_datetime(dt.inner.with(partial_dt, overflow)?, None, context) .map(Into::into) @@ -760,7 +764,7 @@ impl PlainDateTime { // 4. Set options to ? GetOptionsObject(options). let options = get_options_object(args.get_or_undefined(1))?; - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; // 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 6. Return ? AddDate(calendarRec, temporalDate, duration, options). @@ -783,7 +787,7 @@ impl PlainDateTime { // 4. Set options to ? GetOptionsObject(options). let options = get_options_object(args.get_or_undefined(1))?; - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; // 5. Let negatedDuration be CreateNegatedTemporalDuration(duration). // 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). @@ -851,7 +855,7 @@ impl PlainDateTime { let new_round_to = JsObject::with_null_proto(); // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). new_round_to.create_data_property_or_throw( - js_str!("smallestUnit"), + js_string!("smallestUnit"), param_string, context, )?; @@ -870,16 +874,16 @@ impl PlainDateTime { let mut options = RoundingOptions::default(); options.increment = - get_option::(&round_to, js_str!("roundingIncrement"), context)?; + get_option::(&round_to, js_string!("roundingIncrement"), context)?; // 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). options.rounding_mode = - get_option::(&round_to, js_str!("roundingMode"), context)?; + get_option::(&round_to, js_string!("roundingMode"), context)?; // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", TIME, REQUIRED, undefined). options.smallest_unit = get_temporal_unit( &round_to, - js_str!("smallestUnit"), + js_string!("smallestUnit"), TemporalUnitGroup::Time, None, context, @@ -983,7 +987,7 @@ pub(crate) fn to_temporal_datetime( // b. If item has an [[InitializedTemporalZonedDateTime]] internal slot, then } else if let Some(_zdt) = object.downcast_ref::() { // i. Perform ? GetTemporalOverflowOption(resolvedOptions). - let _ = get_option::(&options, js_str!("overflow"), context)?; + let _ = get_option::(&options, js_string!("overflow"), context)?; // ii. Let instant be ! CreateTemporalInstant(item.[[Nanoseconds]]). // iii. Let timeZoneRec be ? CreateTimeZoneMethodsRecord(item.[[TimeZone]], « get-offset-nanoseconds-for »). // iv. Return ? GetPlainDateTimeFor(timeZoneRec, instant, item.[[Calendar]]). @@ -993,7 +997,7 @@ pub(crate) fn to_temporal_datetime( // c. If item has an [[InitializedTemporalDate]] internal slot, then } else if let Some(date) = object.downcast_ref::() { // i. Perform ? GetTemporalOverflowOption(resolvedOptions). - let _ = get_option::(&options, js_str!("overflow"), context)?; + let _ = get_option::(&options, js_string!("overflow"), context)?; // ii. Return ? CreateTemporalDateTime(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], 0, 0, 0, 0, 0, 0, item.[[Calendar]]). return Ok(InnerDateTime::new( date.inner.iso_year(), @@ -1029,7 +1033,7 @@ pub(crate) fn to_temporal_datetime( .into()); } // g. Let result be ? InterpretTemporalDateTimeFields(calendarRec, fields, resolvedOptions). - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; let date = calendar.date_from_fields( &mut TemporalFields::from(partial_date), overflow.unwrap_or(ArithmeticOverflow::Constrain), @@ -1075,7 +1079,7 @@ pub(crate) fn to_temporal_datetime( // h. Set calendar to CanonicalizeUValue("ca", calendar). let date = string.to_std_string_escaped().parse::()?; // i. Perform ? GetTemporalOverflowOption(resolvedOptions). - let _ = get_option::(&options, js_str!("overflow"), context)?; + let _ = get_option::(&options, js_string!("overflow"), context)?; // 5. Return ? CreateTemporalDateTime(result.[[Year]], result.[[Month]], result.[[Day]], // result.[[Hour]], result.[[Minute]], result.[[Second]], result.[[Millisecond]], // result.[[Microsecond]], result.[[Nanosecond]], calendar). diff --git a/core/engine/src/builtins/temporal/plain_month_day/mod.rs b/core/engine/src/builtins/temporal/plain_month_day/mod.rs index bb49efdb285..8eace7d6d90 100644 --- a/core/engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/core/engine/src/builtins/temporal/plain_month_day/mod.rs @@ -16,7 +16,6 @@ use crate::{ Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use temporal_rs::{ @@ -112,8 +111,9 @@ impl PlainMonthDay { let options = get_options_object(args.get_or_undefined(0))?; // 4. Let showCalendar be ? ToShowCalendarOption(options). // Get calendarName from the options object - let show_calendar = get_option::(&options, js_str!("calendarName"), context)? - .unwrap_or(CalendarName::Auto); + let show_calendar = + get_option::(&options, js_string!("calendarName"), context)? + .unwrap_or(CalendarName::Auto); Ok(month_day_to_string(inner, show_calendar)) } @@ -286,11 +286,11 @@ fn to_temporal_month_day( options: &JsObject, context: &mut Context, ) -> JsResult { - let overflow = get_option::(options, js_str!("overflow"), context)? + let overflow = get_option::(options, js_string!("overflow"), context)? .unwrap_or(ArithmeticOverflow::Constrain); // get the calendar property (string) from the item object - let calender_id = item.get_v(js_str!("calendar"), context)?; + let calender_id = item.get_v(js_string!("calendar"), context)?; let calendar = to_temporal_calendar_slot_value(&calender_id)?; let inner = if let Some(item_obj) = item @@ -302,11 +302,11 @@ fn to_temporal_month_day( InnerMonthDay::from_str(item_string.to_std_string_escaped().as_str())? } else if item.is_object() { InnerMonthDay::new( - item.get_v(js_str!("month"), context) + item.get_v(js_string!("month"), context) .expect("Month not found") .to_i32(context) .expect("Cannot convert month to i32"), - item.get_v(js_str!("day"), context) + item.get_v(js_string!("day"), context) .expect("Day not found") .to_i32(context) .expect("Cannot convert day to i32"), diff --git a/core/engine/src/builtins/temporal/plain_time/mod.rs b/core/engine/src/builtins/temporal/plain_time/mod.rs index c99461be486..52d34cbbbb7 100644 --- a/core/engine/src/builtins/temporal/plain_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_time/mod.rs @@ -14,7 +14,6 @@ use crate::{ Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use temporal_rs::{ components::{PartialTime, Time}, @@ -304,7 +303,7 @@ impl PlainTime { // 2. Let overflow be ? GetTemporalOverflowOption(options). let overflow = get_option::( &get_options_object(args.get_or_undefined(1))?, - js_str!("overflow"), + js_string!("overflow"), context, )?; // 3. If item is an Object and item has an [[InitializedTemporalTime]] internal slot, then @@ -398,7 +397,7 @@ impl PlainTime { }; let options = get_options_object(args.get_or_undefined(1))?; - let overflow = get_option::(&options, js_str!("overflow"), context)?; + let overflow = get_option::(&options, js_string!("overflow"), context)?; let partial = to_partial_time_record(partial_object, context)?; create_temporal_time(time.inner.with(partial, overflow)?, None, context).map(Into::into) @@ -468,7 +467,7 @@ impl PlainTime { let new_round_to = JsObject::with_null_proto(); // c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString). new_round_to.create_data_property_or_throw( - js_str!("smallestUnit"), + js_string!("smallestUnit"), param_string, context, )?; @@ -484,16 +483,16 @@ impl PlainTime { // 6. NOTE: The following steps read options and perform independent validation in alphabetical order (ToTemporalRoundingIncrement reads "roundingIncrement" and ToTemporalRoundingMode reads "roundingMode"). // 7. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). let rounding_increment = - get_option::(&round_to, js_str!("roundingIncrement"), context)?; + get_option::(&round_to, js_string!("roundingIncrement"), context)?; // 8. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). let rounding_mode = - get_option::(&round_to, js_str!("roundingMode"), context)?; + get_option::(&round_to, js_string!("roundingMode"), context)?; // 9. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", time, required). let smallest_unit = get_temporal_unit( &round_to, - js_str!("smallestUnit"), + js_string!("smallestUnit"), TemporalUnitGroup::Time, None, context, @@ -550,29 +549,37 @@ impl PlainTime { let fields = JsObject::with_object_proto(context.intrinsics()); // 4. Perform ! CreateDataPropertyOrThrow(fields, "isoHour", 𝔽(temporalTime.[[ISOHour]])). - fields.create_data_property_or_throw(js_str!("isoHour"), time.inner.hour(), context)?; + fields.create_data_property_or_throw(js_string!("isoHour"), time.inner.hour(), context)?; // 5. Perform ! CreateDataPropertyOrThrow(fields, "isoMicrosecond", 𝔽(temporalTime.[[ISOMicrosecond]])). fields.create_data_property_or_throw( - js_str!("isoMicrosecond"), + js_string!("isoMicrosecond"), time.inner.microsecond(), context, )?; // 6. Perform ! CreateDataPropertyOrThrow(fields, "isoMillisecond", 𝔽(temporalTime.[[ISOMillisecond]])). fields.create_data_property_or_throw( - js_str!("isoMillisecond"), + js_string!("isoMillisecond"), time.inner.millisecond(), context, )?; // 7. Perform ! CreateDataPropertyOrThrow(fields, "isoMinute", 𝔽(temporalTime.[[ISOMinute]])). - fields.create_data_property_or_throw(js_str!("isoMinute"), time.inner.minute(), context)?; + fields.create_data_property_or_throw( + js_string!("isoMinute"), + time.inner.minute(), + context, + )?; // 8. Perform ! CreateDataPropertyOrThrow(fields, "isoNanosecond", 𝔽(temporalTime.[[ISONanosecond]])). fields.create_data_property_or_throw( - js_str!("isoNanosecond"), + js_string!("isoNanosecond"), time.inner.nanosecond(), context, )?; // 9. Perform ! CreateDataPropertyOrThrow(fields, "isoSecond", 𝔽(temporalTime.[[ISOSecond]])). - fields.create_data_property_or_throw(js_str!("isoSecond"), time.inner.second(), context)?; + fields.create_data_property_or_throw( + js_string!("isoSecond"), + time.inner.second(), + context, + )?; // 10. Return fields. Ok(fields.into()) @@ -696,32 +703,32 @@ pub(crate) fn to_partial_time_record( context: &mut Context, ) -> JsResult { let hour = partial_object - .get(js_str!("hour"), context)? + .get(js_string!("hour"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let minute = partial_object - .get(js_str!("minute"), context)? + .get(js_string!("minute"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let second = partial_object - .get(js_str!("second"), context)? + .get(js_string!("second"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let millisecond = partial_object - .get(js_str!("millisecond"), context)? + .get(js_string!("millisecond"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let microsecond = partial_object - .get(js_str!("microsecond"), context)? + .get(js_string!("microsecond"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; let nanosecond = partial_object - .get(js_str!("nanosecond"), context)? + .get(js_string!("nanosecond"), context)? .map(|v| super::to_integer_if_integral(v, context)) .transpose()?; diff --git a/core/engine/src/builtins/temporal/plain_year_month/mod.rs b/core/engine/src/builtins/temporal/plain_year_month/mod.rs index 0cea51490cb..aaf55ac6064 100644 --- a/core/engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/core/engine/src/builtins/temporal/plain_year_month/mod.rs @@ -16,7 +16,6 @@ use crate::{ Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use temporal_rs::{ @@ -226,26 +225,27 @@ impl PlainYearMonth { { // Perform ? [GetTemporalOverflowOption](https://tc39.es/proposal-temporal/#sec-temporal-gettemporaloverflowoption)(options). let options = get_options_object(args.get_or_undefined(1))?; - let _ = get_option::(&options, js_str!("overflow"), context)?; + let _ = + get_option::(&options, js_string!("overflow"), context)?; data.inner.clone() } else { let options = get_options_object(args.get_or_undefined(1))?; - let overflow = get_option(&options, js_str!("overflow"), context)? + let overflow = get_option(&options, js_string!("overflow"), context)? .unwrap_or(ArithmeticOverflow::Constrain); // a. Let calendar be ? ToTemporalCalendar(item). let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(1))?; InnerYearMonth::new( super::to_integer_with_truncation( - &item.get_v(js_str!("year"), context)?, + &item.get_v(js_string!("year"), context)?, context, )?, super::to_integer_with_truncation( - &item.get_v(js_str!("month"), context)?, + &item.get_v(js_string!("month"), context)?, context, )?, super::to_integer_with_truncation( - &item.get_v(js_str!("day"), context)?, + &item.get_v(js_string!("day"), context)?, context, ) .ok(), @@ -414,8 +414,9 @@ impl PlainYearMonth { let options = get_options_object(args.get_or_undefined(0))?; // 4. Let showCalendar be ? ToShowCalendarOption(options). // Get calendarName from the options object - let show_calendar = get_option::(&options, js_str!("calendarName"), context)? - .unwrap_or(CalendarName::Auto); + let show_calendar = + get_option::(&options, js_string!("calendarName"), context)? + .unwrap_or(CalendarName::Auto); Ok(year_month_to_string(inner, show_calendar)) } @@ -484,8 +485,8 @@ fn add_or_subtract_duration( .into()); }; - let overflow = - get_option(options, js_str!("overflow"), context)?.unwrap_or(ArithmeticOverflow::Constrain); + let overflow = get_option(options, js_string!("overflow"), context)? + .unwrap_or(ArithmeticOverflow::Constrain); let year_month = this .as_object() diff --git a/core/engine/src/builtins/typed_array/builtin.rs b/core/engine/src/builtins/typed_array/builtin.rs index f4d34b2bd21..51512ee7bc7 100644 --- a/core/engine/src/builtins/typed_array/builtin.rs +++ b/core/engine/src/builtins/typed_array/builtin.rs @@ -3,7 +3,7 @@ use std::{ sync::atomic::Ordering, }; -use boa_macros::{js_str, utf16}; +use boa_macros::utf16; use num_traits::Zero; use super::{ @@ -2484,7 +2484,7 @@ impl BuiltinTypedArray { if is_fixed_len || !next_element.is_undefined() { let s = next_element .invoke( - js_str!("toLocaleString"), + js_string!("toLocaleString"), &[ args.get_or_undefined(0).clone(), args.get_or_undefined(1).clone(), diff --git a/core/engine/src/builtins/typed_array/mod.rs b/core/engine/src/builtins/typed_array/mod.rs index 41f6e93d824..f834dbff38e 100644 --- a/core/engine/src/builtins/typed_array/mod.rs +++ b/core/engine/src/builtins/typed_array/mod.rs @@ -26,7 +26,6 @@ use crate::{ Context, JsArgs, JsResult, JsString, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; mod builtin; @@ -72,12 +71,12 @@ impl IntrinsicObject for T { Attribute::CONFIGURABLE, ) .property( - js_str!("BYTES_PER_ELEMENT"), + js_string!("BYTES_PER_ELEMENT"), size_of::(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT, ) .static_property( - js_str!("BYTES_PER_ELEMENT"), + js_string!("BYTES_PER_ELEMENT"), size_of::(), Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::PERMANENT, ) diff --git a/core/engine/src/builtins/weak_map/mod.rs b/core/engine/src/builtins/weak_map/mod.rs index c326a56383b..6a9ede76df8 100644 --- a/core/engine/src/builtins/weak_map/mod.rs +++ b/core/engine/src/builtins/weak_map/mod.rs @@ -22,7 +22,6 @@ use crate::{ Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; type NativeWeakMap = boa_gc::WeakMap; @@ -105,7 +104,7 @@ impl BuiltInConstructor for WeakMap { // 5. Let adder be ? Get(map, "set"). // 6. If IsCallable(adder) is false, throw a TypeError exception. let adder = map - .get(js_str!("set"), context)? + .get(js_string!("set"), context)? .as_function() .ok_or_else(|| JsNativeError::typ().with_message("WeakMap: 'add' is not a function"))?; diff --git a/core/engine/src/builtins/weak_set/mod.rs b/core/engine/src/builtins/weak_set/mod.rs index b9922677160..68363f12003 100644 --- a/core/engine/src/builtins/weak_set/mod.rs +++ b/core/engine/src/builtins/weak_set/mod.rs @@ -19,7 +19,6 @@ use crate::{ Context, JsArgs, JsNativeError, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use boa_profiler::Profiler; use super::iterable::IteratorHint; @@ -101,7 +100,7 @@ impl BuiltInConstructor for WeakSet { } // 5. Let adder be ? Get(set, "add"). - let adder = weak_set.get(js_str!("add"), context)?; + let adder = weak_set.get(js_string!("add"), context)?; // 6. If IsCallable(adder) is false, throw a TypeError exception. let adder = adder diff --git a/core/engine/src/class.rs b/core/engine/src/class.rs index 609f74ced3e..d176aaf6c4d 100644 --- a/core/engine/src/class.rs +++ b/core/engine/src/class.rs @@ -56,7 +56,7 @@ //! let age = args.get_or_undefined(1).to_number(context)?; //! //! // Roughly equivalent to `this.age = Number(age)`. -//! instance.set(js_str!("age"), age, true, context)?; +//! instance.set(js_string!("age"), age, true, context)?; //! //! Ok(()) //! } @@ -70,9 +70,9 @@ //! if let Some(object) = this.as_object() { //! if let Some(animal) = object.downcast_ref::() { //! return Ok(match &*animal { -//! Self::Cat => js_str!("meow"), -//! Self::Dog => js_str!("woof"), -//! Self::Other => js_str!(r"¯\_(ツ)_/¯"), +//! Self::Cat => js_string!("meow"), +//! Self::Dog => js_string!("woof"), +//! Self::Other => js_string!(r"¯\_(ツ)_/¯"), //! }.into()); //! } //! } diff --git a/core/engine/src/context/intrinsics.rs b/core/engine/src/context/intrinsics.rs index a0d8519a7f7..b1056f71bb1 100644 --- a/core/engine/src/context/intrinsics.rs +++ b/core/engine/src/context/intrinsics.rs @@ -1,7 +1,6 @@ //! Data structures that contain intrinsic objects and constructors. use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use crate::{ builtins::{iterable::IteratorPrototypes, uri::UriFunctions, Array, OrdinaryObject}, @@ -1395,7 +1394,7 @@ impl ObjectTemplates { let ordinary_object = ObjectTemplate::with_prototype(root_shape, constructors.object().prototype()); let mut array = ObjectTemplate::new(root_shape); - let length_property_key: PropertyKey = js_str!("length").into(); + let length_property_key: PropertyKey = js_string!("length").into(); array.property( length_property_key.clone(), Attribute::WRITABLE | Attribute::PERMANENT | Attribute::NON_ENUMERABLE, @@ -1420,7 +1419,7 @@ impl ObjectTemplates { let mut regexp = regexp_without_proto.clone(); regexp.set_prototype(constructors.regexp().prototype()); - let name_property_key: PropertyKey = js_str!("name").into(); + let name_property_key: PropertyKey = js_string!("name").into(); let mut function = ObjectTemplate::new(root_shape); function.property( length_property_key.clone(), @@ -1479,7 +1478,7 @@ impl ObjectTemplates { // [[Get]]: %ThrowTypeError%, [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, // [[Configurable]]: false }). unmapped_arguments.accessor( - js_str!("callee").into(), + js_string!("callee").into(), true, true, Attribute::NON_ENUMERABLE | Attribute::PERMANENT, @@ -1488,17 +1487,17 @@ impl ObjectTemplates { // 21. Perform ! DefinePropertyOrThrow(obj, "callee", PropertyDescriptor { // [[Value]]: func, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true }). mapped_arguments.property( - js_str!("callee").into(), + js_string!("callee").into(), Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, ); let mut iterator_result = ordinary_object.clone(); iterator_result.property( - js_str!("value").into(), + js_string!("value").into(), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::ENUMERABLE, ); iterator_result.property( - js_str!("done").into(), + js_string!("done").into(), Attribute::WRITABLE | Attribute::CONFIGURABLE | Attribute::ENUMERABLE, ); @@ -1510,11 +1509,11 @@ impl ObjectTemplates { with_resolvers // 4. Perform ! CreateDataPropertyOrThrow(obj, "promise", promiseCapability.[[Promise]]). - .property(js_str!("promise").into(), Attribute::all()) + .property(js_string!("promise").into(), Attribute::all()) // 5. Perform ! CreateDataPropertyOrThrow(obj, "resolve", promiseCapability.[[Resolve]]). - .property(js_str!("resolve").into(), Attribute::all()) + .property(js_string!("resolve").into(), Attribute::all()) // 6. Perform ! CreateDataPropertyOrThrow(obj, "reject", promiseCapability.[[Reject]]). - .property(js_str!("reject").into(), Attribute::all()); + .property(js_string!("reject").into(), Attribute::all()); with_resolvers }; diff --git a/core/engine/src/context/mod.rs b/core/engine/src/context/mod.rs index 4ab70c3ac29..96172ffd500 100644 --- a/core/engine/src/context/mod.rs +++ b/core/engine/src/context/mod.rs @@ -51,7 +51,7 @@ thread_local! { /// /// ```rust /// use boa_engine::{ -/// js_str, +/// js_string, /// object::ObjectInitializer, /// property::{Attribute, PropertyDescriptor}, /// Context, Source, @@ -73,10 +73,10 @@ thread_local! { /// /// // Create an object that can be used in eval calls. /// let arg = ObjectInitializer::new(&mut context) -/// .property(js_str!("x"), 12, Attribute::READONLY) +/// .property(js_string!("x"), 12, Attribute::READONLY) /// .build(); /// context -/// .register_global_property(js_str!("arg"), arg, Attribute::all()) +/// .register_global_property(js_string!("arg"), arg, Attribute::all()) /// .expect("property shouldn't exist"); /// /// let value = context.eval(Source::from_bytes("test(arg)")).unwrap(); @@ -211,7 +211,7 @@ impl Context { /// # Example /// ``` /// use boa_engine::{ - /// js_str, + /// js_string, /// object::ObjectInitializer, /// property::{Attribute, PropertyDescriptor}, /// Context, @@ -220,15 +220,15 @@ impl Context { /// let mut context = Context::default(); /// /// context - /// .register_global_property(js_str!("myPrimitiveProperty"), 10, Attribute::all()) + /// .register_global_property(js_string!("myPrimitiveProperty"), 10, Attribute::all()) /// .expect("property shouldn't exist"); /// /// let object = ObjectInitializer::new(&mut context) - /// .property(js_str!("x"), 0, Attribute::all()) - /// .property(js_str!("y"), 1, Attribute::all()) + /// .property(js_string!("x"), 0, Attribute::all()) + /// .property(js_string!("y"), 1, Attribute::all()) /// .build(); /// context - /// .register_global_property(js_str!("myObjectProperty"), object, Attribute::all()) + /// .register_global_property(js_string!("myObjectProperty"), object, Attribute::all()) /// .expect("property shouldn't exist"); /// ``` pub fn register_global_property( diff --git a/core/engine/src/error.rs b/core/engine/src/error.rs index 577fa70a478..c88ac2d6c20 100644 --- a/core/engine/src/error.rs +++ b/core/engine/src/error.rs @@ -9,7 +9,6 @@ use crate::{ Context, JsString, JsValue, }; use boa_gc::{custom_trace, Finalize, Trace}; -use boa_macros::js_str; use std::{borrow::Cow, error, fmt}; use thiserror::Error; @@ -169,13 +168,13 @@ macro_rules! js_error { /// # Examples /// /// ```rust -/// # use boa_engine::{JsError, JsNativeError, JsNativeErrorKind, JsValue, js_str}; -/// let cause = JsError::from_opaque(js_str!("error!").into()); +/// # use boa_engine::{JsError, JsNativeError, JsNativeErrorKind, JsValue, js_string}; +/// let cause = JsError::from_opaque(js_string!("error!").into()); /// /// assert!(cause.as_opaque().is_some()); /// assert_eq!( /// cause.as_opaque().unwrap(), -/// &JsValue::from(js_str!("error!")) +/// &JsValue::from(js_string!("error!")) /// ); /// /// let native_error: JsError = JsNativeError::typ() @@ -429,7 +428,7 @@ impl JsError { ErrorObject::Syntax => JsNativeErrorKind::Syntax, ErrorObject::Uri => JsNativeErrorKind::Uri, ErrorObject::Aggregate => { - let errors = obj.get(js_str!("errors"), context).map_err(|e| { + let errors = obj.get(js_string!("errors"), context).map_err(|e| { TryNativeError::InaccessibleProperty { property: "errors", source: e, @@ -1066,7 +1065,7 @@ impl JsNativeError { /// # Examples /// /// ```rust - /// # use boa_engine::{Context, JsError, JsNativeError, js_str}; + /// # use boa_engine::{Context, JsError, JsNativeError, js_string}; /// # use boa_engine::builtins::error::ErrorObject; /// let context = &mut Context::default(); /// @@ -1075,8 +1074,8 @@ impl JsNativeError { /// /// assert!(error_obj.is::()); /// assert_eq!( - /// error_obj.get(js_str!("message"), context).unwrap(), - /// js_str!("error!").into() + /// error_obj.get(js_string!("message"), context).unwrap(), + /// js_string!("error!").into() /// ) /// ``` /// @@ -1129,14 +1128,14 @@ impl JsNativeError { JsObject::from_proto_and_data_with_shared_shape(context.root_shape(), prototype, tag); o.create_non_enumerable_data_property_or_throw( - js_str!("message"), + js_string!("message"), js_string!(message.as_ref()), context, ); if let Some(cause) = cause { o.create_non_enumerable_data_property_or_throw( - js_str!("cause"), + js_string!("cause"), cause.to_opaque(context), context, ); @@ -1149,7 +1148,7 @@ impl JsNativeError { .collect::>(); let errors = Array::create_array_from_list(errors, context); o.define_property_or_throw( - js_str!("errors"), + js_string!("errors"), PropertyDescriptor::builder() .configurable(true) .enumerable(false) diff --git a/core/engine/src/module/mod.rs b/core/engine/src/module/mod.rs index c8692895b6b..571f053570f 100644 --- a/core/engine/src/module/mod.rs +++ b/core/engine/src/module/mod.rs @@ -36,7 +36,6 @@ use boa_interner::Interner; use boa_parser::source::ReadChar; use boa_parser::{Parser, Source}; use boa_profiler::Profiler; -use boa_string::JsStr; pub use loader::*; pub use namespace::ModuleNamespace; use source::SourceTextModule; @@ -625,16 +624,17 @@ impl Module { /// Get an exported function, typed, from the module. #[inline] + #[allow(clippy::needless_pass_by_value)] pub fn get_typed_fn( &self, - name: JsStr<'_>, + name: JsString, context: &mut Context, ) -> JsResult> where A: crate::object::TryIntoJsArguments, R: crate::value::TryFromJs, { - let func = self.get_value(name, context)?; + let func = self.get_value(name.clone(), context)?; let func = func.as_function().ok_or_else(|| { JsNativeError::typ().with_message(format!("{name:?} is not a function")) })?; diff --git a/core/engine/src/object/builtins/jsdate.rs b/core/engine/src/object/builtins/jsdate.rs index cadf65877a8..2b080d1c8d6 100644 --- a/core/engine/src/object/builtins/jsdate.rs +++ b/core/engine/src/object/builtins/jsdate.rs @@ -14,7 +14,7 @@ use time::{format_description::well_known::Rfc3339, OffsetDateTime}; /// Create a `JsDate` object and set date to December 4 1995 /// /// ``` -/// use boa_engine::{js_str, object::builtins::JsDate, Context, JsResult, JsValue}; +/// use boa_engine::{js_string, object::builtins::JsDate, Context, JsResult, JsValue}; /// /// fn main() -> JsResult<()> { /// // JS mutable Context @@ -26,7 +26,7 @@ use time::{format_description::well_known::Rfc3339, OffsetDateTime}; /// /// assert_eq!( /// date.to_date_string(context)?, -/// JsValue::from(js_str!("Mon Dec 04 1995")) +/// JsValue::from(js_string!("Mon Dec 04 1995")) /// ); /// /// Ok(()) diff --git a/core/engine/src/object/builtins/jsmap.rs b/core/engine/src/object/builtins/jsmap.rs index af63ef90db5..fa27c52dd8d 100644 --- a/core/engine/src/object/builtins/jsmap.rs +++ b/core/engine/src/object/builtins/jsmap.rs @@ -6,13 +6,13 @@ use crate::{ Map, }, error::JsNativeError, + js_string, object::{JsFunction, JsMapIterator, JsObject}, value::TryFromJs, Context, JsResult, JsValue, }; use boa_gc::{Finalize, Trace}; -use boa_macros::js_str; use std::ops::Deref; /// `JsMap` provides a wrapper for Boa's implementation of the ECMAScript `Map` object. @@ -23,7 +23,7 @@ use std::ops::Deref; /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, -/// # Context, JsValue, JsResult, js_str +/// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// // Create default `Context` @@ -33,8 +33,8 @@ use std::ops::Deref; /// let map = JsMap::new(context); /// /// // Set key-value pairs for the `JsMap`. -/// map.set(js_str!("Key-1"), js_str!("Value-1"), context)?; -/// map.set(js_str!("Key-2"), 10, context)?; +/// map.set(js_string!("Key-1"), js_string!("Value-1"), context)?; +/// map.set(js_string!("Key-2"), 10, context)?; /// /// assert_eq!(map.get_size(context)?, 2.into()); /// # Ok(()) @@ -45,7 +45,7 @@ use std::ops::Deref; /// ``` /// # use boa_engine::{ /// # object::builtins::{JsArray, JsMap}, -/// # Context, JsValue, JsResult, js_str +/// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// // Create a default `Context` @@ -56,8 +56,8 @@ use std::ops::Deref; /// /// // Create a `[key, value]` pair of JsValues /// let vec_one: Vec = vec![ -/// js_str!("first-key").into(), -/// js_str!("first-value").into() +/// js_string!("first-key").into(), +/// js_string!("first-value").into() /// ]; /// /// // We create an push our `[key, value]` pair onto our array as a `JsArray` @@ -67,8 +67,8 @@ use std::ops::Deref; /// let js_iterable_map = JsMap::from_js_iterable(&js_array.into(), context)?; /// /// assert_eq!( -/// js_iterable_map.get(js_str!("first-key"), context)?, -/// js_str!("first-value").into() +/// js_iterable_map.get(js_string!("first-key"), context)?, +/// js_string!("first-value").into() /// ); /// /// # Ok(()) @@ -105,7 +105,7 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::{JsArray, JsMap}, - /// # Context, JsResult, JsValue, js_str + /// # Context, JsResult, JsValue, js_string /// # }; /// # fn main() -> JsResult<()> { /// # // Create a default `Context` @@ -114,7 +114,7 @@ impl JsMap { /// let js_array = JsArray::new(context); /// /// // Create a `[key, value]` pair of JsValues and add it to the `JsArray` as a `JsArray` - /// let vec_one: Vec = vec![js_str!("first-key").into(), js_str!("first-value").into()]; + /// let vec_one: Vec = vec![js_string!("first-key").into(), js_string!("first-value").into()]; /// js_array.push(JsArray::from_iter(vec_one, context), context)?; /// /// // Create a `JsMap` from the `JsArray` using it's iterable property. @@ -129,7 +129,7 @@ impl JsMap { // Let adder be Get(map, "set") per spec. This action should not fail with default map. let adder = map - .get(js_str!("set"), context)? + .get(js_string!("set"), context)? .as_function() .ok_or_else(|| { JsNativeError::typ().with_message("property `set` on new `Map` must be callable") @@ -226,16 +226,16 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, js_str + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); /// - /// js_map.set(js_str!("foo"), js_str!("bar"), context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// js_map.set(2, 4, context)?; /// - /// assert_eq!(js_map.get(js_str!("foo"), context)?, js_str!("bar").into()); + /// assert_eq!(js_map.get(js_string!("foo"), context)?, js_string!("bar").into()); /// assert_eq!(js_map.get(2, context)?, 4.into()); /// # Ok(()) /// # } @@ -259,13 +259,13 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, js_str + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); /// - /// js_map.set(js_str!("foo"), js_str!("bar"), context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// /// let map_size = js_map.get_size(context)?; /// @@ -285,18 +285,18 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, js_str + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set(js_str!("foo"), js_str!("bar"), context)?; - /// js_map.set(js_str!("hello"), js_str!("world"), context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; + /// js_map.set(js_string!("hello"), js_string!("world"), context)?; /// - /// js_map.delete(js_str!("foo"), context)?; + /// js_map.delete(js_string!("foo"), context)?; /// /// assert_eq!(js_map.get_size(context)?, 1.into()); - /// assert_eq!(js_map.get(js_str!("foo"), context)?, JsValue::undefined()); + /// assert_eq!(js_map.get(js_string!("foo"), context)?, JsValue::undefined()); /// # Ok(()) /// # } /// ``` @@ -314,16 +314,16 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, js_str + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set(js_str!("foo"), js_str!("bar"), context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// - /// let retrieved_value = js_map.get(js_str!("foo"), context)?; + /// let retrieved_value = js_map.get(js_string!("foo"), context)?; /// - /// assert_eq!(retrieved_value, js_str!("bar").into()); + /// assert_eq!(retrieved_value, js_string!("bar").into()); /// # Ok(()) /// # } /// ``` @@ -341,13 +341,13 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, js_str + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set(js_str!("foo"), js_str!("bar"), context)?; - /// js_map.set(js_str!("hello"), js_str!("world"), context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; + /// js_map.set(js_string!("hello"), js_string!("world"), context)?; /// /// js_map.clear(context)?; /// @@ -367,14 +367,14 @@ impl JsMap { /// ``` /// # use boa_engine::{ /// # object::builtins::JsMap, - /// # Context, JsValue, JsResult, js_str + /// # Context, JsValue, JsResult, js_string /// # }; /// # fn main() -> JsResult<()> { /// # let context = &mut Context::default(); /// let js_map = JsMap::new(context); - /// js_map.set(js_str!("foo"), js_str!("bar"), context)?; + /// js_map.set(js_string!("foo"), js_string!("bar"), context)?; /// - /// let has_key = js_map.has(js_str!("foo"), context)?; + /// let has_key = js_map.has(js_string!("foo"), context)?; /// /// assert_eq!(has_key, true.into()); /// # Ok(()) diff --git a/core/engine/src/object/builtins/jspromise.rs b/core/engine/src/object/builtins/jspromise.rs index 393e34e80a5..c05d8594ae3 100644 --- a/core/engine/src/object/builtins/jspromise.rs +++ b/core/engine/src/object/builtins/jspromise.rs @@ -25,7 +25,7 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; /// ``` /// # use boa_engine::{ /// # builtins::promise::PromiseState, -/// # js_str, +/// # js_string, /// # object::{builtins::JsPromise, FunctionObjectBuilder}, /// # property::Attribute, /// # Context, JsArgs, JsError, JsValue, NativeFunction, @@ -34,11 +34,11 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; /// # fn main() -> Result<(), Box> { /// let context = &mut Context::default(); /// -/// context.register_global_property(js_str!("finally"), false, Attribute::all()); +/// context.register_global_property(js_string!("finally"), false, Attribute::all()); /// /// let promise = JsPromise::new( /// |resolvers, context| { -/// let result = js_str!("hello world!").into(); +/// let result = js_string!("hello world!").into(); /// resolvers /// .resolve /// .call(&JsValue::undefined(), &[result], context)?; @@ -66,7 +66,7 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; /// .finally( /// NativeFunction::from_fn_ptr(|_, _, context| { /// context.global_object().clone().set( -/// js_str!("finally"), +/// js_string!("finally"), /// JsValue::from(true), /// true, /// context, @@ -81,14 +81,14 @@ use boa_gc::{Finalize, Gc, GcRefCell, Trace}; /// /// assert_eq!( /// promise.state(), -/// PromiseState::Fulfilled(js_str!("hello world!").into()) +/// PromiseState::Fulfilled(js_string!("hello world!").into()) /// ); /// /// assert_eq!( /// context /// .global_object() /// .clone() -/// .get(js_str!("finally"), context)?, +/// .get(js_string!("finally"), context)?, /// JsValue::from(true) /// ); /// diff --git a/core/engine/src/object/builtins/jsproxy.rs b/core/engine/src/object/builtins/jsproxy.rs index d96e9e7beb1..125723f71cb 100644 --- a/core/engine/src/object/builtins/jsproxy.rs +++ b/core/engine/src/object/builtins/jsproxy.rs @@ -2,7 +2,7 @@ use super::JsFunction; use crate::{ builtins::Proxy, - js_str, + js_string, native_function::{NativeFunction, NativeFunctionPointer}, object::{FunctionObjectBuilder, JsObject}, value::TryFromJs, @@ -401,7 +401,7 @@ impl JsProxyBuilder { .length(3) .build(); handler - .create_data_property_or_throw(js_str!("apply"), f, context) + .create_data_property_or_throw(js_string!("apply"), f, context) .expect("new object should be writable"); } if let Some(construct) = self.construct { @@ -410,7 +410,7 @@ impl JsProxyBuilder { .length(3) .build(); handler - .create_data_property_or_throw(js_str!("construct"), f, context) + .create_data_property_or_throw(js_string!("construct"), f, context) .expect("new object should be writable"); } if let Some(define_property) = self.define_property { @@ -421,7 +421,7 @@ impl JsProxyBuilder { .length(3) .build(); handler - .create_data_property_or_throw(js_str!("defineProperty"), f, context) + .create_data_property_or_throw(js_string!("defineProperty"), f, context) .expect("new object should be writable"); } if let Some(delete_property) = self.delete_property { @@ -432,7 +432,7 @@ impl JsProxyBuilder { .length(2) .build(); handler - .create_data_property_or_throw(js_str!("deleteProperty"), f, context) + .create_data_property_or_throw(js_string!("deleteProperty"), f, context) .expect("new object should be writable"); } if let Some(get) = self.get { @@ -440,7 +440,7 @@ impl JsProxyBuilder { .length(3) .build(); handler - .create_data_property_or_throw(js_str!("get"), f, context) + .create_data_property_or_throw(js_string!("get"), f, context) .expect("new object should be writable"); } if let Some(get_own_property_descriptor) = self.get_own_property_descriptor { @@ -451,7 +451,7 @@ impl JsProxyBuilder { .length(2) .build(); handler - .create_data_property_or_throw(js_str!("getOwnPropertyDescriptor"), f, context) + .create_data_property_or_throw(js_string!("getOwnPropertyDescriptor"), f, context) .expect("new object should be writable"); } if let Some(get_prototype_of) = self.get_prototype_of { @@ -462,7 +462,7 @@ impl JsProxyBuilder { .length(1) .build(); handler - .create_data_property_or_throw(js_str!("getPrototypeOf"), f, context) + .create_data_property_or_throw(js_string!("getPrototypeOf"), f, context) .expect("new object should be writable"); } if let Some(has) = self.has { @@ -470,7 +470,7 @@ impl JsProxyBuilder { .length(2) .build(); handler - .create_data_property_or_throw(js_str!("has"), f, context) + .create_data_property_or_throw(js_string!("has"), f, context) .expect("new object should be writable"); } if let Some(is_extensible) = self.is_extensible { @@ -481,7 +481,7 @@ impl JsProxyBuilder { .length(1) .build(); handler - .create_data_property_or_throw(js_str!("isExtensible"), f, context) + .create_data_property_or_throw(js_string!("isExtensible"), f, context) .expect("new object should be writable"); } if let Some(own_keys) = self.own_keys { @@ -490,7 +490,7 @@ impl JsProxyBuilder { .length(1) .build(); handler - .create_data_property_or_throw(js_str!("ownKeys"), f, context) + .create_data_property_or_throw(js_string!("ownKeys"), f, context) .expect("new object should be writable"); } if let Some(prevent_extensions) = self.prevent_extensions { @@ -501,7 +501,7 @@ impl JsProxyBuilder { .length(1) .build(); handler - .create_data_property_or_throw(js_str!("preventExtensions"), f, context) + .create_data_property_or_throw(js_string!("preventExtensions"), f, context) .expect("new object should be writable"); } if let Some(set) = self.set { @@ -509,7 +509,7 @@ impl JsProxyBuilder { .length(4) .build(); handler - .create_data_property_or_throw(js_str!("set"), f, context) + .create_data_property_or_throw(js_string!("set"), f, context) .expect("new object should be writable"); } if let Some(set_prototype_of) = self.set_prototype_of { @@ -520,7 +520,7 @@ impl JsProxyBuilder { .length(2) .build(); handler - .create_data_property_or_throw(js_str!("setPrototypeOf"), f, context) + .create_data_property_or_throw(js_string!("setPrototypeOf"), f, context) .expect("new object should be writable"); } diff --git a/core/engine/src/object/jsobject.rs b/core/engine/src/object/jsobject.rs index eccb1f81383..db02acd3c37 100644 --- a/core/engine/src/object/jsobject.rs +++ b/core/engine/src/object/jsobject.rs @@ -21,7 +21,6 @@ use crate::{ Context, JsResult, JsString, JsValue, }; use boa_gc::{self, Finalize, Gc, GcBox, GcRefCell, Trace}; -use boa_macros::js_str; use std::{ cell::RefCell, collections::HashMap, @@ -331,9 +330,9 @@ impl JsObject { // 4. Else, // a. Let methodNames be « "valueOf", "toString" ». let method_names = if hint == PreferredType::String { - [js_str!("toString"), js_str!("valueOf")] + [js_string!("toString"), js_string!("valueOf")] } else { - [js_str!("valueOf"), js_str!("toString")] + [js_string!("valueOf"), js_string!("toString")] }; // 5. For each name in methodNames in List order, do @@ -373,7 +372,7 @@ impl JsObject { // 3. Let hasEnumerable be ? HasProperty(Obj, "enumerable"). // 4. If hasEnumerable is true, then ... - if let Some(enumerable) = self.try_get(js_str!("enumerable"), context)? { + if let Some(enumerable) = self.try_get(js_string!("enumerable"), context)? { // a. Let enumerable be ! ToBoolean(? Get(Obj, "enumerable")). // b. Set desc.[[Enumerable]] to enumerable. desc = desc.enumerable(enumerable.to_boolean()); @@ -381,7 +380,7 @@ impl JsObject { // 5. Let hasConfigurable be ? HasProperty(Obj, "configurable"). // 6. If hasConfigurable is true, then ... - if let Some(configurable) = self.try_get(js_str!("configurable"), context)? { + if let Some(configurable) = self.try_get(js_string!("configurable"), context)? { // a. Let configurable be ! ToBoolean(? Get(Obj, "configurable")). // b. Set desc.[[Configurable]] to configurable. desc = desc.configurable(configurable.to_boolean()); @@ -389,7 +388,7 @@ impl JsObject { // 7. Let hasValue be ? HasProperty(Obj, "value"). // 8. If hasValue is true, then ... - if let Some(value) = self.try_get(js_str!("value"), context)? { + if let Some(value) = self.try_get(js_string!("value"), context)? { // a. Let value be ? Get(Obj, "value"). // b. Set desc.[[Value]] to value. desc = desc.value(value); @@ -397,7 +396,7 @@ impl JsObject { // 9. Let hasWritable be ? HasProperty(Obj, ). // 10. If hasWritable is true, then ... - if let Some(writable) = self.try_get(js_str!("writable"), context)? { + if let Some(writable) = self.try_get(js_string!("writable"), context)? { // a. Let writable be ! ToBoolean(? Get(Obj, "writable")). // b. Set desc.[[Writable]] to writable. desc = desc.writable(writable.to_boolean()); @@ -406,7 +405,7 @@ impl JsObject { // 11. Let hasGet be ? HasProperty(Obj, "get"). // 12. If hasGet is true, then // 12.a. Let getter be ? Get(Obj, "get"). - let get = if let Some(getter) = self.try_get(js_str!("get"), context)? { + let get = if let Some(getter) = self.try_get(js_string!("get"), context)? { // b. If IsCallable(getter) is false and getter is not undefined, throw a TypeError exception. // todo: extract IsCallable to be callable from Value if !getter.is_undefined() && getter.as_object().map_or(true, |o| !o.is_callable()) { @@ -423,7 +422,7 @@ impl JsObject { // 13. Let hasSet be ? HasProperty(Obj, "set"). // 14. If hasSet is true, then // 14.a. Let setter be ? Get(Obj, "set"). - let set = if let Some(setter) = self.try_get(js_str!("set"), context)? { + let set = if let Some(setter) = self.try_get(js_string!("set"), context)? { // 14.b. If IsCallable(setter) is false and setter is not undefined, throw a TypeError exception. // todo: extract IsCallable to be callable from Value if !setter.is_undefined() && setter.as_object().map_or(true, |o| !o.is_callable()) { diff --git a/core/engine/src/object/mod.rs b/core/engine/src/object/mod.rs index c42ec3d7fe4..3d8fb63bafc 100644 --- a/core/engine/src/object/mod.rs +++ b/core/engine/src/object/mod.rs @@ -2,7 +2,6 @@ //! //! For the builtin object wrappers, please see [`object::builtins`][builtins] for implementors. -use boa_macros::js_str; pub use jsobject::{RecursionLimiter, Ref, RefMut}; pub use operations::IntegrityLevel; pub use property_map::*; @@ -24,7 +23,7 @@ use crate::{ property::{Attribute, PropertyDescriptor, PropertyKey}, realm::Realm, string::StaticJsStrings, - Context, JsStr, JsString, JsSymbol, JsValue, + Context, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; @@ -51,10 +50,10 @@ pub use datatypes::JsData; pub use jsobject::*; /// Const `constructor`, usually set on prototypes as a key to point to their respective constructor object. -pub const CONSTRUCTOR: JsStr<'_> = js_str!("constructor"); +pub const CONSTRUCTOR: JsString = js_string!("constructor"); /// Const `prototype`, usually set on constructors as a key to point to their respective prototype object. -pub const PROTOTYPE: JsStr<'_> = js_str!("prototype"); +pub const PROTOTYPE: JsString = js_string!("prototype"); /// Common field names. @@ -1023,7 +1022,7 @@ impl<'ctx> ConstructorBuilder<'ctx> { }; constructor.insert(StaticJsStrings::LENGTH, length); - constructor.insert(js_str!("name"), name); + constructor.insert(js_string!("name"), name); if let Some(proto) = self.custom_prototype.take() { constructor.set_prototype(proto); diff --git a/core/engine/src/value/conversions/try_into_js.rs b/core/engine/src/value/conversions/try_into_js.rs index f497db05e7b..a4b31ea1564 100644 --- a/core/engine/src/value/conversions/try_into_js.rs +++ b/core/engine/src/value/conversions/try_into_js.rs @@ -1,5 +1,4 @@ -use crate::{Context, JsNativeError, JsResult, JsValue}; -use boa_string::JsString; +use crate::{Context, JsNativeError, JsResult, JsString, JsValue}; /// This trait adds a conversions from a Rust Type into [`JsValue`]. pub trait TryIntoJs: Sized { diff --git a/core/engine/src/value/display.rs b/core/engine/src/value/display.rs index cdf463ea1ae..9320bb5dd67 100644 --- a/core/engine/src/value/display.rs +++ b/core/engine/src/value/display.rs @@ -4,7 +4,7 @@ use crate::{ error::ErrorObject, map::ordered_map::OrderedMap, promise::PromiseState, set::ordered_set::OrderedSet, Array, Promise, }, - js_str, + js_string, property::PropertyDescriptor, JsError, JsString, }; @@ -118,7 +118,7 @@ pub(crate) fn log_string_from(x: &JsValue, print_internals: bool, print_children } else if v_bor.is::() { let len = v_bor .properties() - .get(&js_str!("length").into()) + .get(&js_string!("length").into()) .expect("array object must have 'length' property") // FIXME: handle accessor descriptors .expect_value() @@ -194,7 +194,7 @@ pub(crate) fn log_string_from(x: &JsValue, print_internals: bool, print_children } else if v_bor.is::() { drop(v_bor); let name: Cow<'static, str> = v - .get_property(&js_str!("name").into()) + .get_property(&js_string!("name").into()) .as_ref() .and_then(PropertyDescriptor::value) .map_or_else( @@ -209,7 +209,7 @@ pub(crate) fn log_string_from(x: &JsValue, print_internals: bool, print_children }, ); let message = v - .get_property(&js_str!("message").into()) + .get_property(&js_string!("message").into()) .as_ref() .and_then(PropertyDescriptor::value) .map(|v| { diff --git a/core/engine/src/value/mod.rs b/core/engine/src/value/mod.rs index f98c12607cf..6d19592028e 100644 --- a/core/engine/src/value/mod.rs +++ b/core/engine/src/value/mod.rs @@ -8,7 +8,6 @@ use std::{ ops::Sub, }; -use boa_macros::js_str; use num_bigint::BigInt; use num_integer::Integer; use num_traits::{ToPrimitive, Zero}; @@ -432,9 +431,9 @@ impl JsValue { // 1. Assert: preferredType is number. // 2. Let hint be "number". let hint = match preferred_type { - PreferredType::Default => js_str!("default"), - PreferredType::String => js_str!("string"), - PreferredType::Number => js_str!("number"), + PreferredType::Default => js_string!("default"), + PreferredType::String => js_string!("string"), + PreferredType::Number => js_string!("number"), } .into(); @@ -536,7 +535,11 @@ impl JsValue { match self { Self::Null => Ok(js_string!("null")), Self::Undefined => Ok(js_string!("undefined")), - Self::Boolean(boolean) => Ok(boolean.to_string().into()), + Self::Boolean(boolean) => Ok(if *boolean { + js_string!("true") + } else { + js_string!("false") + }), Self::Rational(rational) => Ok(Number::to_js_string(*rational)), Self::Integer(integer) => Ok(integer.to_string().into()), Self::String(string) => Ok(string.clone()), @@ -1034,22 +1037,21 @@ impl JsValue { #[must_use] pub fn js_type_of(&self) -> JsString { match *self { - Self::Rational(_) | Self::Integer(_) => js_str!("number"), - Self::String(_) => js_str!("string"), - Self::Boolean(_) => js_str!("boolean"), - Self::Symbol(_) => js_str!("symbol"), - Self::Null => js_str!("object"), - Self::Undefined => js_str!("undefined"), - Self::BigInt(_) => js_str!("bigint"), + Self::Rational(_) | Self::Integer(_) => js_string!("number"), + Self::String(_) => js_string!("string"), + Self::Boolean(_) => js_string!("boolean"), + Self::Symbol(_) => js_string!("symbol"), + Self::Null => js_string!("object"), + Self::Undefined => js_string!("undefined"), + Self::BigInt(_) => js_string!("bigint"), Self::Object(ref object) => { if object.is_callable() { - js_str!("function") + js_string!("function") } else { - js_str!("object") + js_string!("object") } } } - .into() } /// Maps a `JsValue` into a `Option` where T is the result of an diff --git a/core/engine/src/value/tests.rs b/core/engine/src/value/tests.rs index c689a1fc3cd..7f00f68708b 100644 --- a/core/engine/src/value/tests.rs +++ b/core/engine/src/value/tests.rs @@ -1,3 +1,4 @@ +use boa_macros::js_str; use indoc::indoc; use super::*; diff --git a/core/engine/src/vm/mod.rs b/core/engine/src/vm/mod.rs index ea4f019cd11..84525665fcf 100644 --- a/core/engine/src/vm/mod.rs +++ b/core/engine/src/vm/mod.rs @@ -6,12 +6,11 @@ use crate::{ environments::EnvironmentStack, realm::Realm, script::Script, vm::code_block::Readable, - Context, JsError, JsNativeError, JsObject, JsResult, JsValue, Module, + Context, JsError, JsNativeError, JsObject, JsResult, JsString, JsValue, Module, }; use boa_gc::{custom_trace, Finalize, Gc, Trace}; use boa_profiler::Profiler; -use boa_string::JsString; use std::{future::Future, mem::size_of, ops::ControlFlow, pin::Pin, task}; #[cfg(feature = "trace")] diff --git a/core/engine/src/vm/opcode/await/mod.rs b/core/engine/src/vm/opcode/await/mod.rs index ec480a7d12f..45f2df900fb 100644 --- a/core/engine/src/vm/opcode/await/mod.rs +++ b/core/engine/src/vm/opcode/await/mod.rs @@ -1,13 +1,13 @@ use std::cell::Cell; use boa_gc::Gc; -use boa_macros::js_str; use crate::{ builtins::{ async_generator::AsyncGenerator, generator::GeneratorContext, promise::PromiseCapability, Promise, }, + js_string, native_function::NativeFunction, object::FunctionObjectBuilder, vm::{opcode::Operation, CompletionType, GeneratorResumeKind}, @@ -85,7 +85,7 @@ impl Operation for Await { captures.clone(), ), ) - .name(js_str!("")) + .name(js_string!()) .length(1) .build(); @@ -124,7 +124,7 @@ impl Operation for Await { captures, ), ) - .name(js_str!("")) + .name(js_string!()) .length(1) .build(); diff --git a/core/engine/src/vm/opcode/generator/mod.rs b/core/engine/src/vm/opcode/generator/mod.rs index d7280244e41..c3591e5cad2 100644 --- a/core/engine/src/vm/opcode/generator/mod.rs +++ b/core/engine/src/vm/opcode/generator/mod.rs @@ -8,7 +8,7 @@ use crate::{ generator::{GeneratorContext, GeneratorState}, }, error::JsNativeError, - js_str, + js_string, object::PROTOTYPE, vm::{ call_frame::GeneratorResumeKind, @@ -252,7 +252,7 @@ impl Operation for GeneratorDelegateNext { GeneratorResumeKind::Throw => { let throw = iterator_record .iterator() - .get_method(js_str!("throw"), context)?; + .get_method(js_string!("throw"), context)?; if let Some(throw) = throw { let result = throw.call( &iterator_record.iterator().clone().into(), @@ -273,7 +273,7 @@ impl Operation for GeneratorDelegateNext { GeneratorResumeKind::Return => { let r#return = iterator_record .iterator() - .get_method(js_str!("return"), context)?; + .get_method(js_string!("return"), context)?; if let Some(r#return) = r#return { let result = r#return.call( &iterator_record.iterator().clone().into(), diff --git a/core/engine/src/vm/opcode/iteration/for_in.rs b/core/engine/src/vm/opcode/iteration/for_in.rs index ee6998f9a6c..0baa43e8dd6 100644 --- a/core/engine/src/vm/opcode/iteration/for_in.rs +++ b/core/engine/src/vm/opcode/iteration/for_in.rs @@ -1,6 +1,6 @@ use crate::{ builtins::{iterable::IteratorRecord, object::for_in_iterator::ForInIterator}, - js_str, + js_string, vm::{opcode::Operation, CompletionType}, Context, JsResult, JsValue, }; @@ -23,7 +23,7 @@ impl Operation for CreateForInIterator { let object = object.to_object(context)?; let iterator = ForInIterator::create_for_in_iterator(JsValue::new(object), context); let next_method = iterator - .get(js_str!("next"), context) + .get(js_string!("next"), context) .expect("ForInIterator must have a `next` method"); context diff --git a/core/engine/src/vm/opcode/iteration/iterator.rs b/core/engine/src/vm/opcode/iteration/iterator.rs index 369b014f081..2f734cf2953 100644 --- a/core/engine/src/vm/opcode/iteration/iterator.rs +++ b/core/engine/src/vm/opcode/iteration/iterator.rs @@ -1,6 +1,6 @@ use crate::{ builtins::{iterable::create_iter_result_object, Array}, - js_str, + js_string, vm::{opcode::Operation, CompletionType, GeneratorResumeKind}, Context, JsResult, JsValue, }; @@ -248,7 +248,10 @@ impl Operation for IteratorReturn { return Ok(CompletionType::Normal); } - let Some(ret) = record.iterator().get_method(js_str!("return"), context)? else { + let Some(ret) = record + .iterator() + .get_method(js_string!("return"), context)? + else { context.vm.push(false); return Ok(CompletionType::Normal); }; diff --git a/core/engine/src/vm/opcode/push/class/private.rs b/core/engine/src/vm/opcode/push/class/private.rs index d40b355597c..c016e4e3e88 100644 --- a/core/engine/src/vm/opcode/push/class/private.rs +++ b/core/engine/src/vm/opcode/push/class/private.rs @@ -36,7 +36,7 @@ impl PushClassPrivateMethod { .build(); method_object .__define_own_property__( - &js_str!("name").into(), + &js_string!("name").into(), desc, &mut InternalMethodContext::new(context), ) diff --git a/core/engine/src/vm/opcode/templates/mod.rs b/core/engine/src/vm/opcode/templates/mod.rs index affb3a723ea..7b8f7393501 100644 --- a/core/engine/src/vm/opcode/templates/mod.rs +++ b/core/engine/src/vm/opcode/templates/mod.rs @@ -1,6 +1,6 @@ use crate::{ builtins::array::Array, - js_str, + js_string, object::IntegrityLevel, property::PropertyDescriptor, vm::{opcode::Operation, CompletionType}, @@ -79,7 +79,7 @@ impl TemplateCreate { .expect("should never fail per spec"); template .define_property_or_throw( - js_str!("raw"), + js_string!("raw"), PropertyDescriptor::builder() .value(raw_obj) .writable(false) diff --git a/core/engine/tests/gcd.rs b/core/engine/tests/gcd.rs index eae2d16bc5f..3063a3b3de7 100644 --- a/core/engine/tests/gcd.rs +++ b/core/engine/tests/gcd.rs @@ -6,7 +6,7 @@ // You can execute this example with `cargo run --example gcd` -use boa_engine::{js_str, Context, Module}; +use boa_engine::{js_string, Context, Module}; use boa_parser::Source; use std::path::PathBuf; @@ -28,7 +28,7 @@ fn gcd() { .unwrap(); let js_gcd = module - .get_typed_fn::<(i32, i32), i32>(js_str!("gcd"), context) + .get_typed_fn::<(i32, i32), i32>(js_string!("gcd"), context) .unwrap(); assert_eq!(js_gcd.call(context, (6, 9)), Ok(3)); diff --git a/core/interop/tests/fibonacci.rs b/core/interop/tests/fibonacci.rs index 0ce64e3cab9..48355b5deea 100644 --- a/core/interop/tests/fibonacci.rs +++ b/core/interop/tests/fibonacci.rs @@ -4,7 +4,7 @@ // You can execute this example with `cargo run --example gcd` use boa_engine::object::builtins::{JsFunction, TypedJsFunction}; -use boa_engine::{js_error, js_str, Context, JsResult, Module, Source}; +use boa_engine::{js_error, js_string, Context, JsResult, Module, Source}; use boa_interop::IntoJsFunctionCopied; use std::path::PathBuf; @@ -56,7 +56,7 @@ fn fibonacci_test() { .unwrap(); let fibonacci_js = module - .get_typed_fn::<(usize, JsFunction, JsFunction), usize>(js_str!("fibonacci"), context) + .get_typed_fn::<(usize, JsFunction, JsFunction), usize>(js_string!("fibonacci"), context) .unwrap(); let fibonacci_rust = fibonacci diff --git a/core/interop/tests/gcd_callback.rs b/core/interop/tests/gcd_callback.rs index 359a79cbaf1..f4d821cd204 100644 --- a/core/interop/tests/gcd_callback.rs +++ b/core/interop/tests/gcd_callback.rs @@ -2,7 +2,7 @@ //! A test that mimics the `boa_engine`'s GCD test with a typed callback. use boa_engine::object::builtins::JsFunction; -use boa_engine::{js_str, Context, Module, Source}; +use boa_engine::{js_string, Context, Module, Source}; use boa_gc::Gc; use boa_interop::{ContextData, IntoJsFunctionCopied}; use std::path::PathBuf; @@ -32,7 +32,7 @@ fn gcd_callback() { .unwrap(); let js_gcd = module - .get_typed_fn::<(i32, i32, JsFunction), ()>(js_str!("gcd_callback"), context) + .get_typed_fn::<(i32, i32, JsFunction), ()>(js_string!("gcd_callback"), context) .unwrap(); let function = callback_from_js diff --git a/core/macros/src/lib.rs b/core/macros/src/lib.rs index a5bb12afefd..5913ef43ecb 100644 --- a/core/macros/src/lib.rs +++ b/core/macros/src/lib.rs @@ -598,7 +598,7 @@ fn generate_obj_properties(fields: FieldsNamed) -> Result JsResult { // If a JS value implements `toString()`, call it. let mut written = false; if let Some(obj) = arg.as_object() { - if let Ok(to_string) = obj.get(js_str!("toString"), context) { + if let Ok(to_string) = obj.get(js_string!("toString"), context) { if let Some(to_string_fn) = to_string.as_function() { let arg = to_string_fn .call(arg, &[], context)? @@ -240,7 +240,7 @@ pub struct Console { impl Console { /// Name of the built-in `console` property. - pub const NAME: JsStr<'static> = js_str!("console"); + pub const NAME: JsString = js_string!("console"); /// Modify the context to include the `console` object. /// diff --git a/core/runtime/src/console/tests.rs b/core/runtime/src/console/tests.rs index d521575e34e..61417c8db31 100644 --- a/core/runtime/src/console/tests.rs +++ b/core/runtime/src/console/tests.rs @@ -99,7 +99,7 @@ fn console_log_cyclic() { let mut context = Context::default(); let console = Console::init(&mut context); context - .register_global_property(js_string!(Console::NAME), console, Attribute::all()) + .register_global_property(Console::NAME, console, Attribute::all()) .unwrap(); run_test_actions_with( diff --git a/core/string/src/common.rs b/core/string/src/common.rs index c7427af68ea..e52093ef590 100644 --- a/core/string/src/common.rs +++ b/core/string/src/common.rs @@ -5,7 +5,7 @@ use crate::{tagged::Tagged, JsStr}; use super::JsString; use paste::paste; use rustc_hash::{FxBuildHasher, FxHashMap}; -use std::collections::HashMap; +use std::{collections::HashMap, sync::LazyLock}; macro_rules! well_known_statics { ( $( $(#[$attr:meta])* ($name:ident, $string:literal) ),+$(,)? ) => { @@ -71,7 +71,7 @@ impl StaticJsStrings { return None; } - let index = RAW_STATICS_CACHE.with(|map| map.get(string).copied())?; + let index = RAW_STATICS_CACHE.get(string).copied()?; Some(JsString { ptr: Tagged::from_tag(index), @@ -220,21 +220,14 @@ const MAX_STATIC_LENGTH: usize = { max }; -thread_local! { - /// Map from a string inside [`RAW_STATICS`] to its corresponding static index on `RAW_STATICS`. - static RAW_STATICS_CACHE: FxHashMap, usize> = { - let mut constants = HashMap::with_capacity_and_hasher( - RAW_STATICS.len(), - FxBuildHasher - ); - - for (idx, &s) in RAW_STATICS.iter().enumerate() { - constants.insert(s, idx); - } - - constants - }; -} +/// Map from a string inside [`RAW_STATICS`] to its corresponding static index on `RAW_STATICS`. +static RAW_STATICS_CACHE: LazyLock, usize>> = LazyLock::new(|| { + RAW_STATICS + .iter() + .enumerate() + .map(|(v, &k)| (k, v)) + .collect::, usize, FxBuildHasher>>() +}); /// Array of raw static strings that aren't reference counted. const RAW_STATICS: &[JsStr<'_>] = &[ diff --git a/examples/src/bin/loadfile.rs b/examples/src/bin/loadfile.rs index 98c38809e00..b4cfed91663 100644 --- a/examples/src/bin/loadfile.rs +++ b/examples/src/bin/loadfile.rs @@ -3,7 +3,7 @@ use std::{error::Error, path::Path}; -use boa_engine::{js_string, property::Attribute, Context, Source}; +use boa_engine::{property::Attribute, Context, Source}; use boa_runtime::Console; /// Adds the custom runtime to the context. @@ -11,7 +11,7 @@ fn add_runtime(context: &mut Context) { // We first add the `console` object, to be able to call `console.log()`. let console = Console::init(context); context - .register_global_property(js_string!(Console::NAME), console, Attribute::all()) + .register_global_property(Console::NAME, console, Attribute::all()) .expect("the console builtin shouldn't exist"); } From e416a318307e76bceca4d03be2a98b9c00a025fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:21:28 -0600 Subject: [PATCH 20/72] Bump thiserror from 1.0.67 to 1.0.69 (#4037) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.67 to 1.0.69. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.67...1.0.69) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cafaa431014..e6bfb050c8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3307,18 +3307,18 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3c6efbfc763e64eb85c11c25320f0737cb7364c4b6336db90aa9ebe27a0bbd" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 73d0cffb030..8062211c333 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,7 +100,7 @@ rand = "0.8.5" num-integer = "0.1.46" ryu-js = "1.0.1" tap = "1.0.1" -thiserror = "1.0.67" +thiserror = "1.0.69" dashmap = "5.5.3" num_enum = "0.7.3" itertools = { version = "0.13.0", default-features = false } From b8ea9bdb4e8f4c487e5bec9181e3807d2a36a894 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 18:38:29 -0600 Subject: [PATCH 21/72] Bump the rust-dependencies group with 3 updates (#4036) Bumps the rust-dependencies group with 3 updates: [arbitrary](https://github.com/rust-fuzz/arbitrary), [futures-lite](https://github.com/smol-rs/futures-lite) and [url](https://github.com/servo/rust-url). Updates `arbitrary` from 1.3.2 to 1.4.1 - [Changelog](https://github.com/rust-fuzz/arbitrary/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-fuzz/arbitrary/compare/v1.3.2...v1.4.1) Updates `futures-lite` from 2.4.0 to 2.5.0 - [Release notes](https://github.com/smol-rs/futures-lite/releases) - [Changelog](https://github.com/smol-rs/futures-lite/blob/master/CHANGELOG.md) - [Commits](https://github.com/smol-rs/futures-lite/compare/v2.4.0...v2.5.0) Updates `url` from 2.5.2 to 2.5.3 - [Release notes](https://github.com/servo/rust-url/releases) - [Commits](https://github.com/servo/rust-url/compare/v2.5.2...v2.5.3) --- updated-dependencies: - dependency-name: arbitrary dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: futures-lite dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: url dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 81 ++++++++++++++++------------------------- Cargo.toml | 2 +- core/runtime/Cargo.toml | 2 +- 3 files changed, 33 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6bfb050c8d..d9670e68c80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,9 +101,9 @@ dependencies = [ [[package]] name = "arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" dependencies = [ "derive_arbitrary", ] @@ -146,7 +146,7 @@ dependencies = [ "async-task", "concurrent-queue", "fastrand 2.1.0", - "futures-lite 2.4.0", + "futures-lite 2.5.0", "slab", ] @@ -158,7 +158,7 @@ checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" dependencies = [ "async-lock", "blocking", - "futures-lite 2.4.0", + "futures-lite 2.5.0", ] [[package]] @@ -171,7 +171,7 @@ dependencies = [ "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.4.0", + "futures-lite 2.5.0", "parking", "polling 3.7.2", "rustix", @@ -199,7 +199,7 @@ checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" dependencies = [ "async-io", "blocking", - "futures-lite 2.4.0", + "futures-lite 2.5.0", ] [[package]] @@ -216,7 +216,7 @@ dependencies = [ "blocking", "cfg-if", "event-listener 5.3.1", - "futures-lite 2.4.0", + "futures-lite 2.5.0", "rustix", "tracing", "windows-sys 0.52.0", @@ -303,7 +303,7 @@ dependencies = [ "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.4.0", + "futures-lite 2.5.0", "piper", ] @@ -363,7 +363,7 @@ dependencies = [ "fast-float", "fixed_decimal", "float-cmp", - "futures-lite 2.4.0", + "futures-lite 2.5.0", "hashbrown 0.14.5", "icu_calendar", "icu_casemap", @@ -1075,9 +1075,9 @@ dependencies = [ [[package]] name = "derive_arbitrary" -version = "1.3.2" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", @@ -1322,9 +1322,9 @@ dependencies = [ [[package]] name = "futures-lite" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1fa2f9765705486b33fd2acf1577f8ec449c2ba1f318ae5447697b7c08d210" +checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ "fastrand 2.1.0", "futures-core", @@ -1924,12 +1924,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -3121,7 +3132,7 @@ dependencies = [ "async-net", "async-process", "blocking", - "futures-lite 2.4.0", + "futures-lite 2.5.0", ] [[package]] @@ -3397,21 +3408,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "tinyvec" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" version = "0.5.11" @@ -3556,12 +3552,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "unicode-bidi" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" - [[package]] name = "unicode-ident" version = "1.0.12" @@ -3574,15 +3564,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" -[[package]] -name = "unicode-normalization" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -3626,9 +3607,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", "idna", diff --git a/Cargo.toml b/Cargo.toml index 8062211c333..8fd218cb15f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -115,7 +115,7 @@ temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "1e7901d0 web-time = "1.1.0" criterion = "0.5.1" float-cmp = "0.9.0" -futures-lite = "2.4.0" +futures-lite = "2.5.0" test-case = "3.3.1" winapi = { version = "0.3.9", default-features = false } diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 95c743b9841..1a6c3a56f92 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -15,7 +15,7 @@ boa_engine.workspace = true boa_gc.workspace = true boa_interop.workspace = true rustc-hash = { workspace = true, features = ["std"] } -url = { version = "2.5.2", optional = true } +url = { version = "2.5.3", optional = true } [dev-dependencies] indoc.workspace = true From e892d94f8dbf3a9cbb81f5620e35898b984b3ca2 Mon Sep 17 00:00:00 2001 From: Hans Larsen Date: Mon, 11 Nov 2024 23:26:12 -0800 Subject: [PATCH 22/72] Add a JsPromise::from_result for convenience (#4039) --- core/engine/src/object/builtins/jspromise.rs | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/core/engine/src/object/builtins/jspromise.rs b/core/engine/src/object/builtins/jspromise.rs index c05d8594ae3..c8af0652403 100644 --- a/core/engine/src/object/builtins/jspromise.rs +++ b/core/engine/src/object/builtins/jspromise.rs @@ -311,6 +311,47 @@ impl JsPromise { promise } + /// Creates a new `JsPromise` from a `Result`, where `T` is the fulfilled value of + /// the promise, and `JsError` is the rejection reason. This is a simpler way to create a + /// promise that is either fulfilled or rejected based on the result of a computation. + /// + /// # Examples + /// + /// ``` + /// # use std::error::Error; + /// # use boa_engine::{ + /// # object::builtins::JsPromise, + /// # builtins::promise::PromiseState, + /// # Context, JsResult, JsString, js_string, js_error + /// # }; + /// let context = &mut Context::default(); + /// + /// fn do_thing(success: bool) -> JsResult { + /// success.then(|| js_string!("resolved!")).ok_or(js_error!("rejected!")) + /// } + /// + /// let promise = JsPromise::from_result(do_thing(true), context); + /// assert_eq!( + /// promise.state(), + /// PromiseState::Fulfilled(js_string!("resolved!").into()) + /// ); + /// + /// let promise = JsPromise::from_result(do_thing(false), context); + /// assert_eq!( + /// promise.state(), + /// PromiseState::Rejected(js_string!("rejected!").into()) + /// ); + /// ``` + pub fn from_result, E: Into>( + value: Result, + context: &mut Context, + ) -> Self { + match value { + Ok(v) => Self::resolve(v, context), + Err(e) => Self::reject(e, context), + } + } + /// Resolves a `JsValue` into a `JsPromise`. /// /// Equivalent to the [`Promise.resolve()`] static method. From 1ddfcd5afee1e47f93d7a4c077bcfef71bffd4ed Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Tue, 12 Nov 2024 01:41:45 -0600 Subject: [PATCH 23/72] Use upload-rust-binary-action for nightly release (#4040) --- .github/workflows/nightly_build.yml | 51 +++++++++++------------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index e0a3c8ed77d..7bd7957efcf 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -1,4 +1,6 @@ name: Nightly Build +permisions: + "contents": "write" # Schedule this workflow to run at midnight every day on: @@ -8,40 +10,25 @@ on: jobs: build: - runs-on: ubuntu-latest + strategy: + matrix: + include: + - target: x86_64-unknown-linux-gnu + os: ubuntu-latest + - target: x86_64-apple-darwin + os: macos-latest + - target: x86_64-pc-windows-msvc + os: windows-latest + runs-on: ${{ matrix.os }} steps: - name: Check out the repository uses: actions/checkout@v4 - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - - name: Install Dependencies - run: | - cargo fetch - - - name: Build Project - run: | - cargo build --release - - - name: Set File Name - id: vars - run: | - DATE=$(date +'%Y%m%d') - COMMIT_HASH=$(git rev-parse --short HEAD) - echo "FILE_NAME=boa-nightly-linux-${DATE}-${COMMIT_HASH}" >> $GITHUB_ENV - - - name: Rename binary to file name - run: | - echo "Renaming binary to $FILE_NAME" - mv target/release/boa "target/release/$FILE_NAME" - - name: Upload binaries to release - uses: svenstaro/upload-release-action@v2 + uses: taiki-e/upload-rust-binary-action@v1 with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: target/release/$FILE_NAME - asset_name: ${{ env.FILE_NAME }} - tag: nightly - overwrite: true + bin: boa + # We may be able to provide a custom archive name, but + # currently just going with the example default. + archive: $bin-$tag-$target + ref: nightly + token: ${{ secrets.GITHUB_TOKEN }} From 2bc63120d568b719df87b3f24782c72d9238ccd2 Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:08:21 -0600 Subject: [PATCH 24/72] Misspelled permissions in file (#4041) --- .github/workflows/nightly_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index 7bd7957efcf..e73463d8a22 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -1,5 +1,5 @@ name: Nightly Build -permisions: +permissions: "contents": "write" # Schedule this workflow to run at midnight every day From 334fb3674db7137afe6af56d97711917f1ecf3d3 Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Wed, 13 Nov 2024 11:48:33 -0600 Subject: [PATCH 25/72] Fix ref to nightly and add target (#4042) --- .github/workflows/nightly_build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/nightly_build.yml b/.github/workflows/nightly_build.yml index e73463d8a22..3bdbd5f5dd7 100644 --- a/.github/workflows/nightly_build.yml +++ b/.github/workflows/nightly_build.yml @@ -29,6 +29,7 @@ jobs: bin: boa # We may be able to provide a custom archive name, but # currently just going with the example default. + target: ${{ matrix.target }} archive: $bin-$tag-$target - ref: nightly + ref: refs/tags/nightly token: ${{ secrets.GITHUB_TOKEN }} From e9586b8d004220c20ed1391a3e12a9011260cadc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:29:34 +0000 Subject: [PATCH 26/72] Bump the rust-dependencies group with 4 updates (#4045) Bumps the rust-dependencies group with 4 updates: [clap](https://github.com/clap-rs/clap), [serde_json](https://github.com/serde-rs/json), [serde](https://github.com/serde-rs/serde) and [comfy-table](https://github.com/nukesor/comfy-table). Updates `clap` from 4.5.20 to 4.5.21 - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.20...clap_complete-v4.5.21) Updates `serde_json` from 1.0.132 to 1.0.133 - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.132...v1.0.133) Updates `serde` from 1.0.214 to 1.0.215 - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.214...v1.0.215) Updates `comfy-table` from 7.1.1 to 7.1.3 - [Release notes](https://github.com/nukesor/comfy-table/releases) - [Changelog](https://github.com/Nukesor/comfy-table/blob/main/CHANGELOG.md) - [Commits](https://github.com/nukesor/comfy-table/compare/v7.1.1...v7.1.3) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: comfy-table dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 42 ++++++++++++++++++++++++------------------ Cargo.toml | 8 ++++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d9670e68c80..e7f4d6a71f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -739,9 +739,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -749,9 +749,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -837,14 +837,14 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.1.1" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" +checksum = "24f165e7b643266ea80cb858aed492ad9280e3e05ce24d4a99d7d7b889b6a4d9" dependencies = [ "crossterm", "strum", "strum_macros", - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -962,14 +962,14 @@ checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crossterm" -version = "0.27.0" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ "bitflags 2.6.0", "crossterm_winapi", - "libc", "parking_lot", + "rustix", "winapi", ] @@ -2896,7 +2896,7 @@ dependencies = [ "nix", "rustyline-derive", "unicode-segmentation", - "unicode-width", + "unicode-width 0.1.13", "utf8parse", "windows-sys 0.52.0", ] @@ -2974,9 +2974,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -2993,9 +2993,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -3004,9 +3004,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -3307,7 +3307,7 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width", + "unicode-width 0.1.13", ] [[package]] @@ -3576,6 +3576,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "unsafe-libyaml" version = "0.2.11" diff --git a/Cargo.toml b/Cargo.toml index 8fd218cb15f..fe51e1b9b1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ boa_string = { version = "~0.19.0", path = "core/string" } # Shared deps arbitrary = "1" bitflags = "2.5.0" -clap = "4.5.20" +clap = "4.5.21" colored = "2.1.0" fast-float = "0.2.0" hashbrown = { version = "0.14.5", default-features = false } @@ -63,8 +63,8 @@ pollster = "0.3.0" regex = "1.11.1" regress = { version = "0.10.1", features = ["utf16"] } rustc-hash = { version = "2.0.0", default-features = false } -serde_json = "1.0.132" -serde = "1.0.214" +serde_json = "1.0.133" +serde = "1.0.215" static_assertions = "1.1.0" textwrap = "0.16.0" thin-vec = "0.2.13" @@ -77,7 +77,7 @@ trybuild = "1.0.101" rayon = "1.10.0" toml = "0.8.19" color-eyre = "0.6.3" -comfy-table = "7.1.1" +comfy-table = "7.1.3" serde_repr = "0.1.19" bus = "2.4.1" wasm-bindgen = { version = "0.2.95", default-features = false } From 55532c0a5f5b3a8e42f9dca29314e112a998d945 Mon Sep 17 00:00:00 2001 From: 4yman <170770027+4yman-0@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:06:53 +0100 Subject: [PATCH 27/72] Remove dockerfile from documentation (#4046) * Remove Dockerfile from CONTRIBUTING.md Remove two lines referencing an absent Dockerfile. * Remove Dockerfile from debugging.md Remove one phrase referencing an absent Dockerfile --- CONTRIBUTING.md | 3 --- docs/debugging.md | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5565be0d950..ba65d0ed1a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,9 +62,6 @@ There are some pre-defined tasks in [tasks.json](.vscode/tasks.json) - Test - (there is no shortcut, you'll need to make one) - Runs `Cargo Test`. I personally set a shortcut of shift+cmd+option+T (or shift+ctrl+alt+T) -If you don't want to install everything on your machine, you can use the Dockerfile. -Start VSCode in container mode (you may need the docker container plugin) and use the Dockerfile. - ## Testing Boa provides its own test suite, and can also run the official ECMAScript test suite. To run the Boa test diff --git a/docs/debugging.md b/docs/debugging.md index c472456f0e0..feba3e6971f 100644 --- a/docs/debugging.md +++ b/docs/debugging.md @@ -110,8 +110,7 @@ more information [here][blog_debugging]. ### LLDB Manual debugging -You can also use rust-lldb. The `Dockerfile` already has this enabled, you -should be able to use that environment to run your code. +You can also use rust-lldb. You should be able to use that environment to run your code. ``` rust-lldb ./target/debug/boa [arguments] From f7f8470df08b53143f2568b86101f11827114c21 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Nov 2024 00:14:25 -0500 Subject: [PATCH 28/72] Bump codecov/codecov-action from 4 to 5 (#4044) Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v4...v5) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5c2f5c4edbd..41eae2a4fcf 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -46,7 +46,7 @@ jobs: run: cargo tarpaulin --workspace --features annex-b,intl_bundled,experimental --ignore-tests --engine llvm --out xml - name: Upload to codecov.io - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@v5 tests: name: Test From 9b7c8ce986d02aa383a34d4db5934216a4ed5700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Juli=C3=A1n=20Espina?= Date: Fri, 22 Nov 2024 04:27:11 +0000 Subject: [PATCH 29/72] Bump dependencies with breaking changes (#4050) --- Cargo.lock | 543 +++++++++++++++++-------------- Cargo.toml | 19 +- cli/src/helper.rs | 4 +- core/engine/src/host_defined.rs | 24 +- core/gc/Cargo.toml | 2 +- core/gc/src/pointers/weak_map.rs | 72 ++-- core/interner/Cargo.toml | 2 +- core/runtime/Cargo.toml | 3 +- examples/src/bin/host_defined.rs | 4 +- 9 files changed, 358 insertions(+), 315 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7f4d6a71f0..a98149275e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "ahash" version = "0.8.11" @@ -40,9 +46,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "anes" @@ -52,9 +58,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -67,36 +73,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -139,13 +145,13 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", + "fastrand 2.2.0", "futures-lite 2.5.0", "slab", ] @@ -163,9 +169,9 @@ dependencies = [ [[package]] name = "async-io" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" dependencies = [ "async-lock", "cfg-if", @@ -173,11 +179,11 @@ dependencies = [ "futures-io", "futures-lite 2.5.0", "parking", - "polling 3.7.2", + "polling 3.7.4", "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -204,9 +210,9 @@ dependencies = [ [[package]] name = "async-process" -version = "2.2.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" dependencies = [ "async-channel 2.3.1", "async-io", @@ -219,14 +225,13 @@ dependencies = [ "futures-lite 2.5.0", "rustix", "tracing", - "windows-sys 0.52.0", ] [[package]] name = "async-signal" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" dependencies = [ "async-io", "async-lock", @@ -237,7 +242,7 @@ dependencies = [ "rustix", "signal-hook-registry", "slab", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -254,9 +259,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -268,7 +273,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -364,7 +369,7 @@ dependencies = [ "fixed_decimal", "float-cmp", "futures-lite 2.5.0", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "icu_calendar", "icu_casemap", "icu_collator", @@ -403,7 +408,7 @@ dependencies = [ "test-case", "textwrap", "thin-vec", - "thiserror", + "thiserror 2.0.3", "time", "tinystr", "web-time", @@ -435,7 +440,7 @@ dependencies = [ "boa_macros", "boa_profiler", "boa_string", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "icu_locid", "thin-vec", ] @@ -467,7 +472,7 @@ dependencies = [ "arbitrary", "boa_gc", "boa_macros", - "hashbrown 0.14.5", + "hashbrown 0.15.1", "indexmap", "once_cell", "phf", @@ -608,18 +613,18 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", @@ -634,9 +639,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "calendrical_calculations" @@ -650,9 +655,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -668,16 +673,16 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.18.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +checksum = "afc309ed89476c8957c50fb818f56fe894db857866c3e163335faa91dc34eb85" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -694,9 +699,12 @@ checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" [[package]] name = "cc" -version = "1.0.100" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c891175c3fb232128f48de6590095e59198bbeb8620c310be349bfc3afd12c7b" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -706,9 +714,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "ciborium" @@ -773,15 +781,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clipboard-win" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad" +checksum = "15efe7a882b08f34e38556b14f2fb3daa98769d06c7f0c1b076dfd0d983bc892" dependencies = [ "error-code", ] @@ -821,9 +829,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" @@ -922,9 +930,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "1.1.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] name = "crossbeam-channel" @@ -990,9 +998,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "curl" -version = "0.4.46" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e2161dd6eba090ff1594084e95fd67aeccf04382ffea77999ea94ed42ec67b6" +checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" dependencies = [ "curl-sys", "libc", @@ -1005,9 +1013,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.72+curl-8.6.0" +version = "0.4.78+curl-8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbdc8314c447d11e8fd156dcdd031d9e02a7a976163e396b548c03153bc9ea" +checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" dependencies = [ "cc", "libc", @@ -1021,11 +1029,12 @@ dependencies = [ [[package]] name = "dashmap" -version = "5.5.3" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ "cfg-if", + "crossbeam-utils", "hashbrown 0.14.5", "lock_api", "once_cell", @@ -1138,11 +1147,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] @@ -1174,9 +1189,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.2.0" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" +checksum = "a5d9305ccc6942a704f4335694ecd3de2ea531b114ac2d51f5f843750787a92f" [[package]] name = "event-listener" @@ -1232,9 +1247,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fd-lock" @@ -1261,19 +1276,19 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] name = "float-cmp" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" dependencies = [ "num-traits", ] @@ -1284,6 +1299,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -1301,9 +1322,9 @@ checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-lite" @@ -1326,7 +1347,7 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" dependencies = [ - "fastrand 2.1.0", + "fastrand 2.2.0", "futures-core", "futures-io", "parking", @@ -1429,9 +1450,14 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "heck" @@ -1956,7 +1982,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", ] [[package]] @@ -1991,20 +2017,20 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "isahc" @@ -2053,9 +2079,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "540654e97a3f4470a492cd30ff187bc95d89557a903a2bbf112e2fae98104ef2" [[package]] name = "ixdtf" @@ -2103,15 +2129,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "libnghttp2-sys" @@ -2125,9 +2151,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.18" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -2168,9 +2194,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matrixmultiply" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a" dependencies = [ "autocfg", "rawpointer", @@ -2178,9 +2204,9 @@ dependencies = [ [[package]] name = "measureme" -version = "11.0.1" +version = "12.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d" +checksum = "3ed2d26a61b68ba37bf203340b6b6addf4da2c2e7cfb0cff700792088d69ebc9" dependencies = [ "log", "memmap2", @@ -2222,9 +2248,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minicov" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b" dependencies = [ "cc", "walkdir", @@ -2239,6 +2265,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "mintex" version = "0.1.3" @@ -2260,9 +2295,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -2387,9 +2422,9 @@ dependencies = [ [[package]] name = "oorandom" -version = "11.1.3" +version = "11.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "openssl-probe" @@ -2399,9 +2434,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.102" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -2417,9 +2452,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" @@ -2441,7 +2476,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -2509,18 +2544,18 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", @@ -2529,9 +2564,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2541,26 +2576,26 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand 2.2.0", "futures-io", ] [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "plotters" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" dependencies = [ "num-traits", "plotters-backend", @@ -2571,15 +2606,15 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" [[package]] name = "plotters-svg" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" dependencies = [ "plotters-backend", ] @@ -2602,9 +2637,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.2" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" dependencies = [ "cfg-if", "concurrent-queue", @@ -2612,14 +2647,14 @@ dependencies = [ "pin-project-lite", "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "pollster" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" +checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" [[package]] name = "portable-atomic" @@ -2629,12 +2664,13 @@ checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "postcard" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8" +checksum = "5f7f0a8d620d71c457dd1d47df76bb18960378da56af4527aaa10f515eee732e" dependencies = [ "cobs", - "embedded-io", + "embedded-io 0.4.0", + "embedded-io 0.6.1", "serde", ] @@ -2646,24 +2682,27 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit 0.21.1", + "toml_edit", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "307e3004becf10f5a6e0d59d20f3cd28231b0e0827a96cd3e0ce6d14bc1e4bb3" dependencies = [ "unicode-ident", ] @@ -2735,9 +2774,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -2750,7 +2789,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -2766,9 +2805,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -2832,9 +2871,9 @@ checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -2845,11 +2884,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.22.4" +version = "0.23.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" dependencies = [ "log", + "once_cell", "ring", "rustls-pki-types", "rustls-webpki", @@ -2859,15 +2899,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" -version = "0.102.4" +version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ "ring", "rustls-pki-types", @@ -2876,15 +2916,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rustyline" -version = "14.0.0" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63" +checksum = "2ee1e066dc922e513bda599c6ccb5f3bb2b0ea5870a579448f2622993f0a9a2f" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -2896,16 +2936,16 @@ dependencies = [ "nix", "rustyline-derive", "unicode-segmentation", - "unicode-width 0.1.13", + "unicode-width 0.2.0", "utf8parse", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustyline-derive" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5af959c8bf6af1aff6d2b463a57f71aae53d1332da58419e30ad8dc7011d951" +checksum = "327e9d075f6df7e25fbf594f1be7ef55cf0d567a6cb5112eeccbbd51ceb48e0d" dependencies = [ "proc-macro2", "quote", @@ -2935,11 +2975,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3027,9 +3067,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -3056,6 +3096,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -3202,9 +3248,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -3307,7 +3353,7 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" dependencies = [ "smawk", "unicode-linebreak", - "unicode-width 0.1.13", + "unicode-width 0.1.14", ] [[package]] @@ -3322,7 +3368,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", ] [[package]] @@ -3336,6 +3391,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thousands" version = "0.2.0" @@ -3426,7 +3492,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.20", + "toml_edit", ] [[package]] @@ -3440,26 +3506,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.18", + "winnow", ] [[package]] @@ -3554,9 +3609,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-linebreak" @@ -3566,15 +3621,15 @@ checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-width" @@ -3596,9 +3651,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.7" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" dependencies = [ "base64", "flate2", @@ -3606,7 +3661,6 @@ dependencies = [ "once_cell", "rustls", "rustls-pki-types", - "rustls-webpki", "url", "webpki-roots", ] @@ -3654,9 +3708,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "waker-fn" @@ -3815,9 +3869,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -3835,9 +3889,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -3860,11 +3914,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3888,7 +3942,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -3908,18 +3971,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -3930,9 +3993,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -3942,9 +4005,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -3954,15 +4017,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -3972,9 +4035,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -3984,9 +4047,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -3996,9 +4059,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -4008,24 +4071,15 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -4071,18 +4125,19 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.34" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index fe51e1b9b1b..d2bc014fd16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ bitflags = "2.5.0" clap = "4.5.21" colored = "2.1.0" fast-float = "0.2.0" -hashbrown = { version = "0.14.5", default-features = false } +hashbrown = "0.15.1" indexmap = { version = "2.6.0", default-features = false } indoc = "2.0.5" jemallocator = "0.5.4" @@ -59,7 +59,7 @@ num-bigint = "0.4.6" num-traits = "0.2.19" once_cell = { version = "1.20.2", default-features = false } phf = { version = "0.11.2", default-features = false } -pollster = "0.3.0" +pollster = "0.4.0" regex = "1.11.1" regress = { version = "0.10.1", features = ["utf16"] } rustc-hash = { version = "2.0.0", default-features = false } @@ -72,7 +72,7 @@ time = { version = "0.3.36", default-features = false, features = ["local-offset tinystr = "0.7.5" log = "0.4.22" simple_logger = "5.0.0" -cargo_metadata = "0.18.1" +cargo_metadata = "0.19.0" trybuild = "1.0.101" rayon = "1.10.0" toml = "0.8.19" @@ -87,21 +87,21 @@ wasm-bindgen-test = "0.3.45" smol = "2.0.2" futures-util = "0.3.31" isahc = "1.7.2" -rustyline = { version = "14.0.0", default-features = false } +rustyline = { version = "15.0.0", default-features = false } dhat = "0.3.3" quote = "1.0.37" -syn = { version = "2.0.87", default-features = false } +syn = { version = "2.0.89", default-features = false } proc-macro2 = "1.0" synstructure = "0.13" -measureme = "11.0.1" +measureme = "12.0.0" sptr = "0.3.2" paste = "1.0" rand = "0.8.5" num-integer = "0.1.46" ryu-js = "1.0.1" tap = "1.0.1" -thiserror = "1.0.69" -dashmap = "5.5.3" +thiserror = { version = "2.0.3", default-features = false } +dashmap = "6.1.0" num_enum = "0.7.3" itertools = { version = "0.13.0", default-features = false } portable-atomic = "1.9.0" @@ -114,10 +114,11 @@ sys-locale = "0.3.2" temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "1e7901d07a83211e62373ab94284a7d1ada4c913" } web-time = "1.1.0" criterion = "0.5.1" -float-cmp = "0.9.0" +float-cmp = "0.10.0" futures-lite = "2.5.0" test-case = "3.3.1" winapi = { version = "0.3.9", default-features = false } +url = "2.5.3" # ICU4X diff --git a/cli/src/helper.rs b/cli/src/helper.rs index ae56c98f413..f3d51211ab7 100644 --- a/cli/src/helper.rs +++ b/cli/src/helper.rs @@ -3,7 +3,7 @@ use phf::{phf_set, Set}; use regex::{Captures, Regex, Replacer}; use rustyline::{ error::ReadlineError, - highlight::Highlighter, + highlight::{CmdKind, Highlighter}, validate::{MatchingBracketValidator, ValidationContext, ValidationResult, Validator}, Completer, Helper, Hinter, }; @@ -97,7 +97,7 @@ impl Highlighter for RLHelper { self.highlighter.highlight(candidate, 0) } - fn highlight_char(&self, line: &str, _: usize, _: bool) -> bool { + fn highlight_char(&self, line: &str, _: usize, _: CmdKind) -> bool { !line.is_empty() } } diff --git a/core/engine/src/host_defined.rs b/core/engine/src/host_defined.rs index df523f27f45..241692b70de 100644 --- a/core/engine/src/host_defined.rs +++ b/core/engine/src/host_defined.rs @@ -80,16 +80,16 @@ impl HostDefined { .and_then(::downcast_mut::) } - /// Get type a tuple of types from [`HostDefined`], if they exist. + /// Get a tuple of types from [`HostDefined`], returning `None` for the types that are not on the map. #[track_caller] - pub fn get_many_mut(&mut self) -> Option> + pub fn get_many_mut(&mut self) -> T::NativeTupleMutRef<'_> where T: NativeTuple, { let ids = T::as_type_ids(); let refs: [&TypeId; SIZE] = std::array::from_fn(|i| &ids[i]); - self.types.get_many_mut(refs).and_then(T::mut_ref_from_anys) + T::mut_ref_from_anys(self.types.get_many_mut(refs)) } /// Clears all the objects. @@ -109,27 +109,27 @@ pub trait NativeTuple { fn as_type_ids() -> [TypeId; SIZE]; fn mut_ref_from_anys( - anys: [&'_ mut Box; SIZE], - ) -> Option>; + anys: [Option<&'_ mut Box>; SIZE], + ) -> Self::NativeTupleMutRef<'_>; } macro_rules! impl_native_tuple { ($size:literal $(,$name:ident)* ) => { impl<$($name: NativeObject,)*> NativeTuple<$size> for ($($name,)*) { - type NativeTupleMutRef<'a> = ($(&'a mut $name,)*); + type NativeTupleMutRef<'a> = ($(Option<&'a mut $name>,)*); fn as_type_ids() -> [TypeId; $size] { [$(TypeId::of::<$name>(),)*] } + #[allow(unused_variables, unused_mut, clippy::unused_unit)] fn mut_ref_from_anys( - anys: [&'_ mut Box; $size], - ) -> Option> { - #[allow(unused_variables, unused_mut)] + anys: [Option<&'_ mut Box>; $size], + ) -> Self::NativeTupleMutRef<'_> { let mut anys = anys.into_iter(); - Some(($( - anys.next().expect("Expect `anys` to be of length `SIZE`").downcast_mut::<$name>()?, - )*)) + ($( + anys.next().flatten().and_then(|v| v.downcast_mut::<$name>()), + )*) } } } diff --git a/core/gc/Cargo.toml b/core/gc/Cargo.toml index af223d07677..bdfd4e34cc5 100644 --- a/core/gc/Cargo.toml +++ b/core/gc/Cargo.toml @@ -21,7 +21,7 @@ boa_string = ["dep:boa_string"] [dependencies] boa_profiler.workspace = true boa_macros.workspace = true -hashbrown = { workspace = true, features = ["ahash", "raw"] } +hashbrown.workspace = true boa_string = { workspace = true, optional = true } thin-vec = { workspace = true, optional = true } diff --git a/core/gc/src/pointers/weak_map.rs b/core/gc/src/pointers/weak_map.rs index f5fed3fdf8c..858b237cbdc 100644 --- a/core/gc/src/pointers/weak_map.rs +++ b/core/gc/src/pointers/weak_map.rs @@ -2,13 +2,12 @@ // but with some adjustments to use `Ephemeron` instead of `(K,V)` use hashbrown::{ - hash_map::DefaultHashBuilder, - raw::{RawIter, RawTable}, - TryReserveError, + hash_table::{Entry as RawEntry, Iter as RawIter}, + DefaultHashBuilder, HashTable, TryReserveError, }; use crate::{custom_trace, Allocator, Ephemeron, Finalize, Gc, GcRefCell, Trace}; -use std::{fmt, hash::BuildHasher, marker::PhantomData, mem}; +use std::{fmt, hash::BuildHasher, marker::PhantomData}; /// A map that holds weak references to its keys and is traced by the garbage collector. #[derive(Clone, Debug, Default, Finalize)] @@ -68,7 +67,7 @@ where V: Trace + 'static, { hash_builder: S, - table: RawTable>, + table: HashTable>, } impl Finalize for RawWeakMap @@ -138,7 +137,7 @@ where pub(crate) const fn with_hasher(hash_builder: S) -> Self { Self { hash_builder, - table: RawTable::new(), + table: HashTable::new(), } } @@ -150,7 +149,7 @@ where pub(crate) fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { Self { hash_builder, - table: RawTable::with_capacity(capacity), + table: HashTable::with_capacity(capacity), } } @@ -172,12 +171,9 @@ where /// An iterator visiting all entries in arbitrary order. /// The iterator element type is [Ephemeron]. pub(crate) fn iter(&self) -> Iter<'_, K, V> { - // SAFETY: The returned iterator is tied to the lifetime of self. - unsafe { - Iter { - inner: self.table.iter(), - marker: PhantomData, - } + Iter { + inner: self.table.iter(), + marker: PhantomData, } } @@ -212,14 +208,7 @@ where // SAFETY: // - `item` is only used internally, which means it outlives self. // - `item` pointer is not used after the call to `erase`. - unsafe { - for item in self.table.iter() { - let eph = item.as_ref(); - if !f(eph) { - self.table.erase(item); - } - } - } + self.table.retain(|item| f(item)); } /// Clears the map, removing all key-value pairs. Keeps the allocated memory @@ -293,7 +282,7 @@ where None } else { let hash = make_hash_from_gc(&self.hash_builder, k); - self.table.get(hash, equivalent_key(k))?.value() + self.table.find(hash, equivalent_key(k))?.value() } } @@ -311,30 +300,29 @@ where pub(crate) fn insert(&mut self, k: &Gc, v: V) -> Option> { let hash = make_hash_from_gc(&self.hash_builder, k); let hasher = make_hasher(&self.hash_builder); - let eph = Ephemeron::new(k, v); - match self - .table - .find_or_find_insert_slot(hash, equivalent_key(k), hasher) - { - // SAFETY: `bucket` is only used inside the replace call, meaning it doesn't - // outlive self. - Ok(bucket) => Some(mem::replace(unsafe { bucket.as_mut() }, eph)), - Err(slot) => { - // SAFETY: `slot` comes from a call to `find_or_find_insert_slot`, and `self` - // is not mutated until the call to `insert_in_slot`. - unsafe { - self.table.insert_in_slot(hash, slot, eph); - } - None + let entry = self.table.entry(hash, equivalent_key(k), hasher); + let (old, slot) = match entry { + RawEntry::Occupied(occupied_entry) => { + let (v, slot) = occupied_entry.remove(); + (Some(v), slot) } - } + RawEntry::Vacant(vacant_entry) => (None, vacant_entry), + }; + + slot.insert(Ephemeron::new(k, v)); + old } /// Removes a key from the map, returning the value at the key if the key /// was previously in the map. Keeps the allocated memory for reuse. pub(crate) fn remove(&mut self, k: &Gc) -> Option { let hash = make_hash_from_gc(&self.hash_builder, k); - self.table.remove_entry(hash, equivalent_key(k))?.value() + self.table + .find_entry(hash, equivalent_key(k)) + .ok()? + .remove() + .0 + .value() } /// Clears all the expired keys in the map. @@ -348,7 +336,7 @@ where K: Trace + ?Sized + 'static, V: Trace + 'static, { - inner: RawIter>, + inner: RawIter<'a, Ephemeron>, marker: PhantomData<&'a Ephemeron>, } @@ -386,9 +374,7 @@ where #[inline] fn next(&mut self) -> Option { - // SAFETY: The original map outlives the iterator thanks to the lifetime parameter, - // and since the returned ephemeron carries that information, the call to `as_ref` is safe. - unsafe { self.inner.next().map(|b| b.as_ref()) } + self.inner.next() } #[inline] diff --git a/core/interner/Cargo.toml b/core/interner/Cargo.toml index 2f1d29cb1d9..805107b9f24 100644 --- a/core/interner/Cargo.toml +++ b/core/interner/Cargo.toml @@ -24,7 +24,7 @@ once_cell = { workspace = true, features = ["std"]} indexmap.workspace = true serde = { workspace = true, features = ["derive"], optional = true } arbitrary = { workspace = true, features = ["derive"], optional = true } -hashbrown = { workspace = true, default-features = false, features = ["inline-more"] } +hashbrown.workspace = true [lints] workspace = true diff --git a/core/runtime/Cargo.toml b/core/runtime/Cargo.toml index 1a6c3a56f92..821c1c4838d 100644 --- a/core/runtime/Cargo.toml +++ b/core/runtime/Cargo.toml @@ -15,7 +15,7 @@ boa_engine.workspace = true boa_gc.workspace = true boa_interop.workspace = true rustc-hash = { workspace = true, features = ["std"] } -url = { version = "2.5.3", optional = true } +url = { workspace = true, optional = true } [dev-dependencies] indoc.workspace = true @@ -30,3 +30,4 @@ all-features = true [features] default = ["all"] all = ["url"] +url = ["dep:url"] diff --git a/examples/src/bin/host_defined.rs b/examples/src/bin/host_defined.rs index 475e21cfab4..7104aff8206 100644 --- a/examples/src/bin/host_defined.rs +++ b/examples/src/bin/host_defined.rs @@ -96,11 +96,11 @@ fn main() -> Result<(), JsError> { let value: usize = args.get_or_undefined(0).try_js_into(context)?; let mut host_defined = context.realm().host_defined_mut(); - let Some((host_defined, metrics)) = + let (Some(host_defined), Some(metrics)) = host_defined.get_many_mut::<(CustomHostDefinedStruct, HostDefinedMetrics), 2>() else { return Err(JsNativeError::typ() - .with_message("Realm does not have HostDefined field") + .with_message("Realm does not have HostDefined fields") .into()); }; From 8f1d8d473ae56c4d8595c051b6f911597ec88a0f Mon Sep 17 00:00:00 2001 From: CrazyboyQCD <53971641+CrazyboyQCD@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:28:37 +0800 Subject: [PATCH 30/72] Add string builder to build `JsString` (#3915) * feat: add `JsStringBuilder` and test * chore: fix calculation on capacity and add `clone` impl * chore: some misc fix * fix: wrong capacity calculation in `extend` * chore: prevent `reserve` except for the shrink in `build` * chore: fix misc * perf: use `realloc` for allocation * chore: fix lint * fix: wrong ascii validation * fix: wrong allocated data bytes calculation * fix: wrong capacity calcultion on `with_capacity` * fix: clippy fix * chore: add public `reserve` * chore: comments and renaming * chore: update misc * chore: moved to module `builder` and implement `AddAssign` for `Builder` * chore: add zero case for `with_capacity` * chore: mark public methods `inline` * chore: extract allocation check into `allocate_if_needed` * chore: fix lint * chore: expose `JsStringData` * feat: add common string builder and export 1 byte and 2 bytes string builder * chore: add missed trait * chore: fix lint * chore: fix doc * chore: add `reserve_exact` * chore: typos * chore: fix argument * chore: fix doc * chore: mark `current_layout` unsafe * chore: fix lint * chore: remove `JsStringData` and rename builders * chore: add build methods to typed builders * chore: add more build methods to `CommonJsStringBuilder` * chore: rename `latin1` check to `ascii` check * chore: refine docs * chore: update tests * chore: limit the generic type `D` of `JsStringBuilder` to Copy * chore: move `entend` method under `Extend` trait * chore: should validate `Latin1` segement in `build_from_latin1` * chore: add `Add` trait implementation to builders * chore: refines docs and add `inline` to trait methods * chore: adds `clone_from` and related tests * chore: adds `as_mut_slice` to typed builders --- core/string/src/builder.rs | 915 +++++++++++++++++++++++++++++++++++++ core/string/src/lib.rs | 2 + core/string/src/tests.rs | 221 ++++++++- 3 files changed, 1137 insertions(+), 1 deletion(-) create mode 100644 core/string/src/builder.rs diff --git a/core/string/src/builder.rs b/core/string/src/builder.rs new file mode 100644 index 00000000000..7a2154e4383 --- /dev/null +++ b/core/string/src/builder.rs @@ -0,0 +1,915 @@ +use crate::{ + alloc_overflow, tagged::Tagged, JsStr, JsStrVariant, JsString, RawJsString, RefCount, + TaggedLen, DATA_OFFSET, +}; + +use std::{ + alloc::{alloc, dealloc, realloc, Layout}, + cell::Cell, + marker::PhantomData, + mem::ManuallyDrop, + ops::{Add, AddAssign}, + ptr::{self, addr_of_mut, NonNull}, + str::{self}, +}; + +/// A mutable builder to create instance of `JsString`. +/// +#[derive(Debug)] +pub struct JsStringBuilder { + cap: usize, + len: usize, + inner: NonNull, + phantom_data: PhantomData, +} + +impl Default for JsStringBuilder { + fn default() -> Self { + Self::new() + } +} + +impl JsStringBuilder { + const DATA_SIZE: usize = size_of::(); + const MIN_NON_ZERO_CAP: usize = 8 / Self::DATA_SIZE; + + /// Create a new `JsStringBuilder` with capacity of zero. + #[inline] + #[must_use] + pub const fn new() -> Self { + Self { + cap: 0, + len: 0, + inner: NonNull::dangling(), + phantom_data: PhantomData, + } + } + + /// Returns the number of elements that inner `RawJsString` holds. + #[inline] + #[must_use] + pub const fn len(&self) -> usize { + self.len + } + + /// Forces the length of the [`JsStringBuilder`] to `new_len`. + /// + /// # Safety + /// + /// - `new_len` must be less than or equal to `capacity()`. + /// - The elements at `old_len..new_len` must be initialized. + /// + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) { + debug_assert!(new_len <= self.capacity()); + + self.len = new_len; + } + + /// Returns the total number of elements can hold without reallocating + #[inline] + #[must_use] + pub const fn capacity(&self) -> usize { + self.cap + } + + /// Returns the allocated byte of inner `RawJsString`'s data. + #[must_use] + const fn allocated_data_byte_len(&self) -> usize { + self.len() * Self::DATA_SIZE + } + + /// Returns the capacity calculated from given layout. + #[must_use] + const fn capacity_from_layout(layout: Layout) -> usize { + (layout.size() - DATA_OFFSET) / Self::DATA_SIZE + } + + /// Create a new `JsStringBuilder` with specific capacity + #[inline] + #[must_use] + pub fn with_capacity(cap: usize) -> Self { + if cap == 0 { + return Self::new(); + } + let layout = Self::new_layout(cap); + #[allow(clippy::cast_ptr_alignment)] + // SAFETY: + // The layout size of `RawJsString` is never zero, since it has to store + // the length of the string and the reference count. + let ptr = unsafe { alloc(layout) }; + + let Some(ptr) = NonNull::new(ptr.cast()) else { + std::alloc::handle_alloc_error(layout) + }; + Self { + cap: Self::capacity_from_layout(layout), + len: 0, + inner: ptr, + phantom_data: PhantomData, + } + } + + /// Checks if the inner `RawJsString` is allocated. + #[must_use] + fn is_allocated(&self) -> bool { + self.inner != NonNull::dangling() + } + + /// Returns the inner `RawJsString`'s layout. + /// + /// # Safety + /// + /// Caller should ensure that the inner is allocated. + #[must_use] + unsafe fn current_layout(&self) -> Layout { + // SAFETY: + // Caller should ensure that the inner is allocated. + unsafe { + Layout::for_value(self.inner.as_ref()) + .extend(Layout::array::(self.capacity()).unwrap_unchecked()) + .unwrap_unchecked() + .0 + .pad_to_align() + } + } + + /// Returns the pointer of `data` of inner. + /// + /// # Safety + /// + /// Caller should ensure that the inner is allocated. + #[must_use] + unsafe fn data(&self) -> *mut D { + // SAFETY: + // Caller should ensure that the inner is allocated. + unsafe { addr_of_mut!((*self.inner.as_ptr()).data).cast() } + } + + /// Allocates when there is not sufficient capacity. + #[allow(clippy::inline_always)] + #[inline(always)] + fn allocate_if_needed(&mut self, reuired_cap: usize) { + if reuired_cap > self.capacity() { + self.allocate(reuired_cap); + } + } + + /// Inner logic of `allocate`. + /// + /// Use `realloc` here because it has a better performance than using combination of `alloc`, `copy` and `dealloc`. + #[allow(clippy::cast_ptr_alignment)] + fn allocate_inner(&mut self, new_layout: Layout) { + let new_ptr = if self.is_allocated() { + let old_ptr = self.inner.as_ptr(); + // SAFETY: + // Allocation check has been made above. + let old_layout = unsafe { self.current_layout() }; + // SAFETY: + // Valid pointer is required by `realloc` and pointer is checked above to be valid. + // The layout size of `RawJsString` is never zero, since it has to store + // the length of the string and the reference count. + unsafe { realloc(old_ptr.cast(), old_layout, new_layout.size()) } + } else { + // SAFETY: + // The layout size of `RawJsString` is never zero, since it has to store + // the length of the string and the reference count. + unsafe { alloc(new_layout) } + }; + let Some(new_ptr) = NonNull::new(new_ptr.cast::()) else { + std::alloc::handle_alloc_error(new_layout) + }; + self.inner = new_ptr; + self.cap = Self::capacity_from_layout(new_layout); + } + + /// Appends an element to the inner `RawJsString` of `JsStringBuilder`. + #[inline] + pub fn push(&mut self, v: D) { + let required_cap = self.len() + 1; + self.allocate_if_needed(required_cap); + // SAFETY: + // Capacity has been expanded to be large enough to hold elements. + unsafe { + self.push_unchecked(v); + } + } + + /// Pushes elements from slice to `JsStringBuilder` without doing capacity check. + /// + /// Unlike the standard vector, our holded element types are only `u8` and `u16`, which is [`Copy`] derived, + /// + /// so we only need to copy them instead of cloning. + /// + /// # Safety + /// + /// Caller should ensure the capacity is large enough to hold elements. + #[inline] + pub unsafe fn extend_from_slice_unchecked(&mut self, v: &[D]) { + // SAFETY: Caller should ensure the capacity is large enough to hold elements. + unsafe { + ptr::copy_nonoverlapping(v.as_ptr(), self.data().add(self.len()), v.len()); + } + self.len += v.len(); + } + + /// Pushes elements from slice to `JsStringBuilder`. + #[inline] + pub fn extend_from_slice(&mut self, v: &[D]) { + let required_cap = self.len() + v.len(); + self.allocate_if_needed(required_cap); + // SAFETY: + // Capacity has been expanded to be large enough to hold elements. + unsafe { + self.extend_from_slice_unchecked(v); + } + } + + fn new_layout(cap: usize) -> Layout { + let new_layout = Layout::array::(cap) + .and_then(|arr| Layout::new::().extend(arr)) + .map(|(layout, offset)| (layout.pad_to_align(), offset)) + .map_err(|_| None); + match new_layout { + Ok((new_layout, offset)) => { + debug_assert_eq!(offset, DATA_OFFSET); + new_layout + } + Err(None) => alloc_overflow(), + Err(Some(layout)) => std::alloc::handle_alloc_error(layout), + } + } + + /// Similar to [`Vec::reserve`] + /// + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the given `JsStringBuilder`. The collection may reserve more space to + /// speculatively avoid frequent reallocations. After calling `reserve`, + /// capacity will be greater than or equal to `self.len() + additional`. + /// Does nothing if capacity is already sufficient. + #[inline] + pub fn reserve(&mut self, additional: usize) { + if additional > self.capacity().wrapping_sub(self.len) { + let Some(cap) = self.len().checked_add(additional) else { + alloc_overflow() + }; + self.allocate(cap); + } + } + + /// Similar to [`Vec::reserve_exact`] + /// + /// Reserves the minimum capacity for at least `additional` more elements to + /// be inserted in the given `JsStringBuilder`. Unlike [`reserve`], this will not + /// deliberately over-allocate to speculatively avoid frequent allocations. + /// After calling `reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional`. Does nothing if the capacity is already + /// sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: JsStringBuilder::reserve + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + if additional > self.capacity().wrapping_sub(self.len) { + let Some(cap) = self.len().checked_add(additional) else { + alloc_overflow() + }; + self.allocate_inner(Self::new_layout(cap)); + } + } + + /// Allocates memory to the inner `RawJsString` by the given capacity. + /// Capacity calculation is from [`std::vec::Vec::reserve`]. + fn allocate(&mut self, cap: usize) { + let cap = std::cmp::max(self.capacity() * 2, cap); + let cap = std::cmp::max(Self::MIN_NON_ZERO_CAP, cap); + self.allocate_inner(Self::new_layout(cap)); + } + + /// Appends an element to the inner `RawJsString` of `JsStringBuilder` without doing bounds check. + /// # Safety + /// + /// Caller should ensure the capacity is large enough to hold elements. + #[inline] + pub unsafe fn push_unchecked(&mut self, v: D) { + // SAFETY: Caller should ensure the capacity is large enough to hold elements. + unsafe { + self.data().add(self.len()).write(v); + self.len += 1; + } + } + + /// Returns true if this `JsStringBuilder` has a length of zero, and false otherwise. + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Checks if all bytes in inner `RawJsString`'s data are ascii. + #[inline] + #[must_use] + pub fn is_ascii(&self) -> bool { + // SAFETY: + // `NonNull` verified for us that the pointer returned by `alloc` is valid, + // meaning we can read to its pointed memory. + let data = unsafe { + std::slice::from_raw_parts(self.data().cast::(), self.allocated_data_byte_len()) + }; + data.is_ascii() + } + + /// Extracts a slice containing the elements in the inner `RawJsString`. + #[inline] + #[must_use] + pub fn as_slice(&self) -> &[D] { + if self.is_allocated() { + // SAFETY: + // The inner `RawJsString` is allocated which means it is not null. + unsafe { std::slice::from_raw_parts(self.data(), self.len()) } + } else { + &[] + } + } + + /// Extracts a mutable slice containing the elements in the inner `RawJsString`. + /// + /// # Safety + /// The caller must ensure that the content of the slice is valid encoding before the borrow ends. + /// Use of a builder whose contents are not valid encoding is undefined behavior. + #[inline] + #[must_use] + pub unsafe fn as_mut_slice(&mut self) -> &mut [D] { + if self.is_allocated() { + // SAFETY: + // The inner `RawJsString` is allocated which means it is not null. + unsafe { std::slice::from_raw_parts_mut(self.data(), self.len()) } + } else { + &mut [] + } + } + + /// Builds `JsString` from `JsStringBuilder` + #[inline] + #[must_use] + fn build_inner(mut self, latin1: bool) -> JsString { + if self.is_empty() { + return JsString::default(); + } + let len = self.len(); + + // Shrink to fit the length. + if len != self.capacity() { + let layout = Self::new_layout(self.len()); + self.allocate_inner(layout); + } + + let inner = self.inner; + + // SAFETY: + // `NonNull` verified for us that the pointer returned by `alloc` is valid, + // meaning we can write to its pointed memory. + unsafe { + inner.as_ptr().write(RawJsString { + tagged_len: TaggedLen::new(len, latin1), + refcount: RefCount { + read_write: ManuallyDrop::new(Cell::new(1)), + }, + data: [0; 0], + }); + } + + // Tell the compiler not to call the destructor of `JsStringBuilder`, + // becuase we move inner `RawJsString` to `JsString`. + std::mem::forget(self); + JsString { + ptr: Tagged::from_non_null(inner), + } + } +} + +impl Drop for JsStringBuilder { + /// Set cold since [`JsStringBuilder`] should be created to build `JsString` + #[cold] + #[inline] + fn drop(&mut self) { + if self.is_allocated() { + // SAFETY: + // Allocation check has been made above. + let layout = unsafe { self.current_layout() }; + // SAFETY: + // layout: All the checks for the validity of the layout have already been made on `allocate_inner`. + // `NonNull` verified for us that the pointer returned by `alloc` is valid, + // meaning we can free its pointed memory. + unsafe { + dealloc(self.inner.as_ptr().cast(), layout); + } + } + } +} + +impl AddAssign<&JsStringBuilder> for JsStringBuilder { + #[inline] + fn add_assign(&mut self, rhs: &JsStringBuilder) { + self.extend_from_slice(rhs.as_slice()); + } +} + +impl AddAssign<&[D]> for JsStringBuilder { + #[inline] + fn add_assign(&mut self, rhs: &[D]) { + self.extend_from_slice(rhs); + } +} + +impl Add<&JsStringBuilder> for JsStringBuilder { + type Output = Self; + + #[inline] + #[must_use] + fn add(mut self, rhs: &JsStringBuilder) -> Self::Output { + self.extend_from_slice(rhs.as_slice()); + self + } +} + +impl Add<&[D]> for JsStringBuilder { + type Output = Self; + + #[inline] + #[must_use] + fn add(mut self, rhs: &[D]) -> Self::Output { + self.extend_from_slice(rhs); + self + } +} + +impl Extend for JsStringBuilder { + #[inline] + fn extend>(&mut self, iter: I) { + let iterator = iter.into_iter(); + let (lower_bound, _) = iterator.size_hint(); + let require_cap = self.len() + lower_bound; + self.allocate_if_needed(require_cap); + iterator.for_each(|c| self.push(c)); + } +} + +impl FromIterator for JsStringBuilder { + #[inline] + fn from_iter>(iter: T) -> Self { + let mut builder = Self::new(); + builder.extend(iter); + builder + } +} + +impl From<&[D]> for JsStringBuilder { + #[inline] + #[must_use] + fn from(value: &[D]) -> Self { + let mut builder = Self::with_capacity(value.len()); + // SAFETY: The capacity is large enough to hold elements. + unsafe { builder.extend_from_slice_unchecked(value) }; + builder + } +} + +impl PartialEq for JsStringBuilder { + #[inline] + #[must_use] + fn eq(&self, other: &Self) -> bool { + self.as_slice().eq(other.as_slice()) + } +} + +impl Clone for JsStringBuilder { + #[inline] + #[must_use] + fn clone(&self) -> Self { + if self.is_allocated() { + let mut builder = Self::with_capacity(self.capacity()); + // SAFETY: The capacity is large enough to hold elements. + unsafe { builder.extend_from_slice_unchecked(self.as_slice()) }; + builder + } else { + Self::new() + } + } + + /// Performs copy-assignment from `source`. + /// + /// Rewritten to avoid unnecessary allocation. + #[inline] + fn clone_from(&mut self, source: &Self) { + let source_len = source.len(); + + if source_len > self.capacity() { + self.allocate(source_len); + } else { + // At this point, inner `RawJsString` of self or source can be not allocated, + // returns earlier to avoid copying from/to `null`. + if source_len == 0 { + // SAFETY: 0 is always less or equal to self's capacity. + unsafe { self.set_len(0) }; + return; + } + } + + // SAFETY: self shoud be allocated after allocation. + let self_data = unsafe { self.data() }; + + // SAFETY: source_len is greter than 0 so source shoud be allocated. + let source_data = unsafe { source.data() }; + + // SAFETY: Borrow checker should not allow this to be overlapped and pointers are valid. + unsafe { ptr::copy_nonoverlapping(source_data, self_data, source_len) }; + + // SAFETY: source_len has checked to be less or equal to self's capacity. + unsafe { self.set_len(source_len) }; + } +} + +/// **`Latin1`** encoded `JsStringBuilder` +/// # Warning +/// If you are not sure the characters that will be added and don't want to preprocess them, +/// use [`CommonJsStringBuilder`] instead. +/// ## Examples +/// +/// ```rust +/// use boa_string::Latin1JsStringBuilder; +/// let mut s = Latin1JsStringBuilder::new(); +/// s.push(b'x'); +/// s.extend_from_slice(&[b'1', b'2', b'3']); +/// s.extend([b'1', b'2', b'3']); +/// let js_string = s.build(); +/// ``` +pub type Latin1JsStringBuilder = JsStringBuilder; + +impl Latin1JsStringBuilder { + /// Builds a `JsString` if the current instance is strictly `ASCII`. + /// + /// When the string contains characters outside the `ASCII` range, it cannot be determined + /// whether the encoding is `Latin1` or others. Therefore, this method only returns a + /// valid `JsString` when the instance is entirely `ASCII`. If any non-`ASCII` characters + /// are present, it returns `None` to avoid ambiguity in encoding. + /// + /// If the caller is certain that the string is encoded in `Latin1`, + /// [`build_as_latin1`](Self::build_as_latin1) can be used to avoid the `ASCII` check. + #[inline] + #[must_use] + pub fn build(self) -> Option { + if self.is_ascii() { + Some(self.build_inner(true)) + } else { + None + } + } + + /// Builds `JsString` from `Latin1JsStringBuilder`, assume that the inner data is `Latin1` encoded + /// + /// # Safety + /// Caller must ensure that the string is encoded in `Latin1`. + /// + /// If the string contains characters outside the `Latin1` range, it may lead to encoding errors, + /// resulting in an incorrect or malformed `JsString`. This could cause undefined behavior + /// when the resulting string is used in further operations or when interfacing with other + /// parts of the system that expect valid `Latin1` encoded string. + #[inline] + #[must_use] + pub unsafe fn build_as_latin1(self) -> JsString { + self.build_inner(true) + } +} + +/// **`UTF-16`** encoded `JsStringBuilder` +/// ## Examples +/// +/// ```rust +/// use boa_string::Utf16JsStringBuilder; +/// let mut s = Utf16JsStringBuilder::new(); +/// s.push(b'x' as u16); +/// s.extend_from_slice(&[b'1', b'2', b'3'].map(u16::from)); +/// s.extend([0xD83C, 0xDFB9, 0xD83C, 0xDFB6, 0xD83C, 0xDFB5,]); // 🎹🎶🎵 +/// let js_string = s.build(); +/// ``` +pub type Utf16JsStringBuilder = JsStringBuilder; + +impl Utf16JsStringBuilder { + /// Builds `JsString` from `Utf16JsStringBuilder` + #[inline] + #[must_use] + pub fn build(self) -> JsString { + self.build_inner(false) + } +} + +/// Represents a segment of a string used to construct a [`JsString`]. +#[derive(Clone, Debug)] +pub enum Segment<'a> { + /// A string segment represented as a `JsString`. + String(JsString), + + /// A string segment represented as a `JsStr`. + Str(JsStr<'a>), + + /// A string segment represented as a byte. + Latin1(u8), + + /// A Unicode code point segment represented as a character. + CodePoint(char), +} + +impl Segment<'_> { + /// Checks if the segment consists solely of `ASCII` characters. + #[inline] + #[must_use] + fn is_ascii(&self) -> bool { + match self { + Segment::String(s) => s.as_str().is_latin1(), + Segment::Str(s) => s.is_latin1(), + Segment::Latin1(b) => *b <= 0x7f, + Segment::CodePoint(ch) => *ch as u32 <= 0x7F, + } + } +} + +impl From for Segment<'_> { + #[inline] + fn from(value: JsString) -> Self { + Self::String(value) + } +} + +impl From for Segment<'_> { + #[inline] + fn from(value: String) -> Self { + Self::String(value.into()) + } +} + +impl From<&[u16]> for Segment<'_> { + #[inline] + fn from(value: &[u16]) -> Self { + Self::String(value.into()) + } +} + +impl From<&str> for Segment<'_> { + #[inline] + fn from(value: &str) -> Self { + Self::String(value.into()) + } +} + +impl<'seg, 'ref_str: 'seg> From> for Segment<'seg> { + #[inline] + fn from(value: JsStr<'ref_str>) -> Self { + Self::Str(value) + } +} + +impl From for Segment<'_> { + #[inline] + fn from(value: u8) -> Self { + Self::Latin1(value) + } +} + +impl From for Segment<'_> { + #[inline] + fn from(value: char) -> Self { + Self::CodePoint(value) + } +} + +/// Common `JsString` builder that accepts multiple variant of string or character. +/// +/// Originally based on [kiesel-js](https://codeberg.org/kiesel-js/kiesel/src/branch/main/src/types/language/String/Builder.zig) +#[derive(Clone, Debug, Default)] +pub struct CommonJsStringBuilder<'a> { + segments: Vec>, +} + +impl<'seg, 'ref_str: 'seg> CommonJsStringBuilder<'seg> { + /// Creates a new `CommonJsStringBuilder` with capacity of zero. + #[inline] + #[must_use] + pub const fn new() -> Self { + Self { + segments: Vec::new(), + } + } + + /// Similar to `Vec::with_capacity`. + /// + /// Creates a new `CommonJsStringBuilder` with given capacity. + #[inline] + #[must_use] + pub fn with_capacity(capacity: usize) -> Self { + Self { + segments: Vec::with_capacity(capacity), + } + } + + /// Similar to `Vec::reserve`. + /// + /// Reserves additional capacity for the inner vector. + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.segments.reserve(additional); + } + + /// Similar to `Vec::reserve_exact`. + /// + /// Reserves the minimum capacity for the inner vector. + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.segments.reserve_exact(additional); + } + + /// Appends string segments to the back of the inner vector. + #[inline] + pub fn push>>(&mut self, seg: T) { + self.segments.push(seg.into()); + } + + /// Checks if all string segments contains only `ASCII` bytes. + #[inline] + #[must_use] + pub fn is_ascii(&self) -> bool { + self.segments.iter().all(Segment::is_ascii) + } + + /// Returns the number of string segment in inner vector. + #[inline] + #[must_use] + pub fn len(&self) -> usize { + self.segments.len() + } + + /// Returns true if this `CommonJsStringBuilder` has a length of zero, and false otherwise. + #[inline] + #[must_use] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Builds `Latin1` encoded `JsString` from string segments. + /// + /// This doesn't consume the builder itself because it may fails to build + /// and the caller may wants to keep the builder for further operations. + /// + /// This processes the following types of segments: + /// + /// - `Segment::String(s)`: Encodes the string if it can be represented in `Latin1`. + /// - `Segment::Str(s)`: Encodes the string slice if it can be represented in `Latin1`. + /// - `Segment::Latin1(b)`: Encodes the byte if it's within the `ASCII` range. + /// - `Segment::CodePoint(ch)`: Encodes the code point by converting it to a byte if it's within the `ASCII` range. + /// + /// Return `None` if any segment fails to encode. + #[inline] + #[must_use] + #[allow(clippy::cast_lossless)] + pub fn build_from_latin1(&self) -> Option { + let mut builder = Latin1JsStringBuilder::new(); + for seg in &self.segments { + match seg { + Segment::String(s) => { + if let Some(data) = s.as_str().as_latin1() { + builder.extend_from_slice(data); + } else { + return None; + } + } + Segment::Str(s) => { + if let Some(data) = s.as_latin1() { + builder.extend_from_slice(data); + } else { + return None; + } + } + Segment::Latin1(b) => { + if *b <= 0x7f { + builder.push(*b); + } else { + return None; + } + } + Segment::CodePoint(ch) => { + if let Ok(b) = u8::try_from(*ch as u32) { + builder.push(b); + } else { + return None; + } + } + } + } + builder.build() + } + + /// Builds `Utf-16` encoded `JsString` from string segments. + #[inline] + #[must_use] + #[allow(clippy::cast_possible_truncation)] + pub fn build_from_utf16(self) -> JsString { + let mut builder = Utf16JsStringBuilder::new(); + for seg in self.segments { + match seg { + Segment::String(s) => { + let js_str = s.as_str(); + match js_str.variant() { + JsStrVariant::Latin1(s) => builder.extend(s.iter().copied().map(u16::from)), + JsStrVariant::Utf16(s) => builder.extend_from_slice(s), + } + } + Segment::Str(s) => match s.variant() { + JsStrVariant::Latin1(s) => builder.extend(s.iter().copied().map(u16::from)), + JsStrVariant::Utf16(s) => builder.extend_from_slice(s), + }, + Segment::Latin1(latin1) => builder.push(u16::from(latin1)), + Segment::CodePoint(code_point) => { + builder.extend_from_slice(code_point.encode_utf16(&mut [0_u16; 2])); + } + } + } + builder.build() + } + + /// Builds `JsString` from `CommonJsStringBuilder`, + /// + /// This function first checks if the instance is empty: + /// - If it is empty, it returns the default `JsString`. + /// - If it contains only ASCII characters, it safely encodes it as `Latin1`. + /// - If it contains non-ASCII characters, it falls back to encoding using `UTF-16`. + #[inline] + #[must_use] + pub fn build(self) -> JsString { + if self.is_empty() { + JsString::default() + } else if self.is_ascii() { + // SAFETY: + // All string segment contains only ascii byte, so this can be encoded as `Latin1`. + unsafe { self.build_as_latin1() } + } else { + self.build_from_utf16() + } + } + + /// Builds `Latin1` encoded `JsString` from `CommonJsStringBuilder`, return `None` if segments can't be encoded as `Latin1` + /// + /// # Safety + /// Caller must ensure that the string segments can be `Latin1` encoded. + /// + /// If string segments can't be `Latin1` encoded, it may lead to encoding errors, + /// resulting in an incorrect or malformed `JsString`. This could cause undefined behavior + /// when the resulting string is used in further operations or when interfacing with other + /// parts of the system that expect valid `Latin1` encoded string. + #[inline] + #[must_use] + pub unsafe fn build_as_latin1(self) -> JsString { + let mut builder = Latin1JsStringBuilder::new(); + for seg in self.segments { + match seg { + Segment::String(s) => { + let js_str = s.as_str(); + let Some(s) = js_str.as_latin1() else { + unreachable!("string segment shoud be latin1") + }; + builder.extend_from_slice(s); + } + Segment::Str(s) => { + let Some(s) = s.as_latin1() else { + unreachable!("string segment shoud be latin1") + }; + builder.extend_from_slice(s); + } + Segment::Latin1(latin1) => builder.push(latin1), + Segment::CodePoint(code_point) => builder.push(code_point as u8), + } + } + // SAFETY: All string segments can be encoded as `Latin1` string. + unsafe { builder.build_as_latin1() } + } +} + +impl<'ref_str, T: Into>> AddAssign for CommonJsStringBuilder<'ref_str> { + #[inline] + fn add_assign(&mut self, rhs: T) { + self.push(rhs); + } +} + +impl<'ref_str, T: Into>> Add for CommonJsStringBuilder<'ref_str> { + type Output = Self; + + #[inline] + #[must_use] + fn add(mut self, rhs: T) -> Self::Output { + self.push(rhs); + self + } +} diff --git a/core/string/src/lib.rs b/core/string/src/lib.rs index c4171c7f3df..1d4ed920e9f 100644 --- a/core/string/src/lib.rs +++ b/core/string/src/lib.rs @@ -16,6 +16,7 @@ #![allow(unstable_name_collisions)] #![allow(clippy::module_name_repetitions)] +mod builder; mod common; mod display; mod iter; @@ -30,6 +31,7 @@ use crate::display::{JsStrDisplayEscaped, JsStrDisplayLossy}; use crate::tagged::{Tagged, UnwrappedTagged}; #[doc(inline)] pub use crate::{ + builder::{CommonJsStringBuilder, Latin1JsStringBuilder, Utf16JsStringBuilder}, common::StaticJsStrings, iter::Iter, str::{JsStr, JsStrVariant}, diff --git a/core/string/src/tests.rs b/core/string/src/tests.rs index abf10c0c808..043f07a0c09 100644 --- a/core/string/src/tests.rs +++ b/core/string/src/tests.rs @@ -2,7 +2,10 @@ use std::hash::{BuildHasher, BuildHasherDefault, Hash}; -use crate::{JsStr, JsString, StaticJsString, StaticJsStrings, ToStringEscaped}; +use crate::{ + CommonJsStringBuilder, JsStr, JsString, Latin1JsStringBuilder, StaticJsString, StaticJsStrings, + ToStringEscaped, Utf16JsStringBuilder, +}; use rustc_hash::FxHasher; @@ -252,3 +255,219 @@ fn compare_static_and_dynamic_js_string() { assert!(!dynamic_latin1.is_static()); assert!(!dynamic_utf16.is_static()); } + +#[test] +#[allow(clippy::cast_possible_truncation)] +#[allow(clippy::undocumented_unsafe_blocks)] +fn js_string_builder() { + let s = "2024年5月21日"; + let utf16 = s.encode_utf16().collect::>(); + let s_utf16 = utf16.as_slice(); + let ascii = "Lorem ipsum dolor sit amet"; + let s_ascii = ascii.as_bytes(); + let latin1_as_utf8_literal = "Déjà vu"; + let s_latin1_literal: &[u8] = &[ + b'D', 0xE9, /* é */ + b'j', 0xE0, /* à */ + b' ', b'v', b'u', + ]; + + // latin1 builder -- test + + // push ascii + let mut builder = Latin1JsStringBuilder::new(); + for &code in s_ascii { + builder.push(code); + } + let s_builder = builder.build().unwrap_or_default(); + assert_eq!(s_builder, ascii); + + // push latin1 + let mut builder = Latin1JsStringBuilder::new(); + for &code in s_latin1_literal { + builder.push(code); + } + let s_builder = unsafe { builder.build_as_latin1() }; + assert_eq!( + s_builder.to_std_string().unwrap_or_default(), + latin1_as_utf8_literal + ); + + // from_iter ascii + let s_builder = s_ascii + .iter() + .copied() + .collect::() + .build() + .unwrap_or_default(); + assert_eq!(s_builder.to_std_string().unwrap_or_default(), ascii); + + // from_iter latin1 + let s_builder = unsafe { + s_latin1_literal + .iter() + .copied() + .collect::() + .build_as_latin1() + }; + assert_eq!( + s_builder.to_std_string().unwrap_or_default(), + latin1_as_utf8_literal + ); + + // extend_from_slice ascii + let mut builder = Latin1JsStringBuilder::new(); + builder.extend_from_slice(s_ascii); + let s_builder = builder.build().unwrap_or_default(); + assert_eq!(s_builder.to_std_string().unwrap_or_default(), ascii); + + // extend_from_slice latin1 + let mut builder = Latin1JsStringBuilder::new(); + builder.extend_from_slice(s_latin1_literal); + let s_builder = unsafe { builder.build_as_latin1() }; + assert_eq!( + s_builder.to_std_string().unwrap_or_default(), + latin1_as_utf8_literal + ); + + // build from utf16 encoded string + let s_builder = s + .as_bytes() + .iter() + .copied() + .collect::() + .build(); + assert_eq!(None, s_builder); + + let s_builder = s_utf16 + .iter() + .copied() + .map(|v| v as u8) + .collect::() + .build(); + assert_eq!(None, s_builder); + + // utf16 builder -- test + + // push + let mut builder = Utf16JsStringBuilder::new(); + for &code in s_utf16 { + builder.push(code); + } + let s_builder = builder.build(); + assert_eq!(s_builder.to_std_string().unwrap_or_default(), s); + + // from_iter + let s_builder = s_utf16 + .iter() + .copied() + .collect::() + .build(); + assert_eq!(s_builder.to_std_string().unwrap_or_default(), s); + + // extend_from_slice + let mut builder = Utf16JsStringBuilder::new(); + builder.extend_from_slice(s_utf16); + let s_builder = builder.build(); + assert_eq!(s_builder.to_std_string().unwrap_or_default(), s); +} + +#[test] +fn clone_builder() { + // latin1 builder -- test + let origin = Latin1JsStringBuilder::from(&b"0123456789"[..]); + let empty_origin = Latin1JsStringBuilder::new(); + + // clone == origin + let cloned = origin.clone(); + assert_eq!(origin, cloned); + + // clone_from == origin + let mut cloned_from = Latin1JsStringBuilder::new(); + cloned_from.clone_from(&origin); + assert_eq!(origin, cloned_from); + + // clone == origin(empty) + let cloned = empty_origin.clone(); + assert_eq!(empty_origin, cloned); + + // clone_from == origin(empty) + + cloned_from.clone_from(&empty_origin); + assert!(cloned_from.capacity() > 0); // Should not be reallocated so the capacity is preserved. + assert_eq!(empty_origin, cloned_from); + + // clone_from(empty) == origin(empty) + let mut cloned_from = Latin1JsStringBuilder::new(); + cloned_from.clone_from(&empty_origin); + assert!(cloned_from.capacity() == 0); + assert_eq!(empty_origin, cloned_from); + + // utf16 builder -- test + let s = "2024年5月21日"; + + let origin = Utf16JsStringBuilder::from(s.encode_utf16().collect::>().as_slice()); + let empty_origin = Utf16JsStringBuilder::new(); + // clone == origin + let cloned = origin.clone(); + assert_eq!(origin, cloned); + + // clone_from == origin(empty) + let mut cloned_from = Utf16JsStringBuilder::new(); + cloned_from.clone_from(&origin); + + assert_eq!(origin, cloned_from); + // clone == origin(empty) + let cloned = empty_origin.clone(); + assert_eq!(empty_origin, cloned); + + // clone_from == origin(empty) + + cloned_from.clone_from(&empty_origin); + assert!(cloned_from.capacity() > 0); // should not be reallocated so the capacity is preserved. + assert_eq!(empty_origin, cloned_from); + + // clone_from(empty) == origin(empty) + let mut cloned_from = Utf16JsStringBuilder::new(); + cloned_from.clone_from(&empty_origin); + assert!(cloned_from.capacity() == 0); + assert_eq!(empty_origin, cloned_from); +} + +#[test] +fn common_js_string_builder() { + let utf16 = "2024年5月21日".encode_utf16().collect::>(); + let s_utf16 = utf16.as_slice(); + let s = "Lorem ipsum dolor sit amet"; + let js_str_utf16 = JsStr::utf16(s_utf16); + let js_str_ascii = JsStr::latin1(s.as_bytes()); + let latin1_bytes = [ + b'D', 0xE9, /* é */ + b'j', 0xE0, /* à */ + b' ', b'v', b'u', + ]; + let ch = '🎹'; + let mut builder = CommonJsStringBuilder::with_capacity(10); + builder += ch; + builder += s; + builder += js_str_utf16; + builder += js_str_ascii; + builder += ch; + assert_eq!(builder.len(), 5); + let js_string = builder.build_from_utf16(); + assert_eq!( + js_string, + "🎹Lorem ipsum dolor sit amet2024年5月21日Lorem ipsum dolor sit amet🎹" + ); + let mut builder = CommonJsStringBuilder::new(); + for b in latin1_bytes { + builder += b; + } + builder += s_utf16; + builder += ch; + let js_string = builder.build(); + assert_eq!( + js_string.to_std_string().unwrap_or_default(), + "Déjà vu2024年5月21日🎹" + ); +} From 9d8f267770be93b7f34bb01655ad804466f487c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Juli=C3=A1n=20Espina?= Date: Sun, 24 Nov 2024 02:22:48 +0000 Subject: [PATCH 31/72] Migrate to fast-float2 (#4052) --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- core/engine/Cargo.toml | 2 +- core/engine/src/builtins/number/globals.rs | 2 +- core/parser/Cargo.toml | 2 +- core/parser/src/lexer/number.rs | 2 +- core/string/Cargo.toml | 2 +- core/string/src/lib.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a98149275e2..28eabf55454 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,7 +365,7 @@ dependencies = [ "criterion", "dashmap", "either", - "fast-float", + "fast-float2", "fixed_decimal", "float-cmp", "futures-lite 2.5.0", @@ -518,7 +518,7 @@ dependencies = [ "boa_interner", "boa_macros", "boa_profiler", - "fast-float", + "fast-float2", "icu_properties", "num-bigint", "num-traits", @@ -552,7 +552,7 @@ dependencies = [ name = "boa_string" version = "0.19.0" dependencies = [ - "fast-float", + "fast-float2", "paste", "rustc-hash 2.0.0", "sptr", @@ -1231,10 +1231,10 @@ dependencies = [ ] [[package]] -name = "fast-float" -version = "0.2.0" +name = "fast-float2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c" +checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" [[package]] name = "fastrand" diff --git a/Cargo.toml b/Cargo.toml index d2bc014fd16..57afce14e19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ arbitrary = "1" bitflags = "2.5.0" clap = "4.5.21" colored = "2.1.0" -fast-float = "0.2.0" +fast-float2 = "0.2.3" hashbrown = "0.15.1" indexmap = { version = "2.6.0", default-features = false } indoc = "2.0.5" diff --git a/core/engine/Cargo.toml b/core/engine/Cargo.toml index 5e7596f6c2c..9a0d603e427 100644 --- a/core/engine/Cargo.toml +++ b/core/engine/Cargo.toml @@ -86,7 +86,7 @@ num-integer.workspace = true bitflags.workspace = true indexmap = { workspace = true, features = ["std"] } ryu-js.workspace = true -fast-float.workspace = true +fast-float2.workspace = true once_cell = { workspace = true, features = ["std"] } tap.workspace = true sptr.workspace = true diff --git a/core/engine/src/builtins/number/globals.rs b/core/engine/src/builtins/number/globals.rs index 9e603200245..6fa8813f8d9 100644 --- a/core/engine/src/builtins/number/globals.rs +++ b/core/engine/src/builtins/number/globals.rs @@ -318,7 +318,7 @@ pub(crate) fn parse_float( // Prevent fast_float from parsing "inf", "+inf" as Infinity and "-inf" as -Infinity Ok(JsValue::nan()) } else { - Ok(fast_float::parse_partial::(s).map_or_else( + Ok(fast_float2::parse_partial::(s).map_or_else( |_| JsValue::nan(), |(f, len)| { if len > 0 { diff --git a/core/parser/Cargo.toml b/core/parser/Cargo.toml index 32b70a3918b..6da2ef48ee8 100644 --- a/core/parser/Cargo.toml +++ b/core/parser/Cargo.toml @@ -16,7 +16,7 @@ boa_macros.workspace = true boa_ast.workspace = true boa_profiler.workspace = true rustc-hash = { workspace = true, features = ["std"] } -fast-float.workspace = true +fast-float2.workspace = true num-traits.workspace = true bitflags.workspace = true num-bigint.workspace = true diff --git a/core/parser/src/lexer/number.rs b/core/parser/src/lexer/number.rs index c944eb878b8..787392001bb 100644 --- a/core/parser/src/lexer/number.rs +++ b/core/parser/src/lexer/number.rs @@ -402,7 +402,7 @@ impl Tokenizer for NumberLiteral { // casting precisely to check if the float doesn't lose info on truncation #[allow(clippy::cast_possible_truncation)] NumericKind::Rational /* base: 10 */ => { - let val: f64 = fast_float::parse(num_str).expect("Failed to parse float after checks"); + let val: f64 = fast_float2::parse(num_str).expect("Failed to parse float after checks"); let int_val = val as i32; // The truncated float should be identically to the non-truncated float for the conversion to be loss-less, diff --git a/core/string/Cargo.toml b/core/string/Cargo.toml index 0bee6f3615c..60268b4cc00 100644 --- a/core/string/Cargo.toml +++ b/core/string/Cargo.toml @@ -16,7 +16,7 @@ rustc-hash = { workspace = true, features = ["std"] } sptr.workspace = true static_assertions.workspace = true paste.workspace = true -fast-float.workspace = true +fast-float2.workspace = true [lints] workspace = true diff --git a/core/string/src/lib.rs b/core/string/src/lib.rs index 1d4ed920e9f..f39288289ce 100644 --- a/core/string/src/lib.rs +++ b/core/string/src/lib.rs @@ -717,7 +717,7 @@ impl JsString { return value; } - fast_float::parse(string).unwrap_or(f64::NAN) + fast_float2::parse(string).unwrap_or(f64::NAN) } /// Allocates a new [`RawJsString`] with an internal capacity of `str_len` chars. From 10cb765327162f183a0aad964518358f0a429a57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 21:50:55 +0000 Subject: [PATCH 32/72] Bump the rust-dependencies group with 6 updates (#4053) Bumps the rust-dependencies group with 6 updates: | Package | From | To | | --- | --- | --- | | [hashbrown](https://github.com/rust-lang/hashbrown) | `0.15.1` | `0.15.2` | | [proc-macro2](https://github.com/dtolnay/proc-macro2) | `1.0.91` | `1.0.92` | | [portable-atomic](https://github.com/taiki-e/portable-atomic) | `1.9.0` | `1.10.0` | | [url](https://github.com/servo/rust-url) | `2.5.3` | `2.5.4` | | [yoke](https://github.com/unicode-org/icu4x) | `0.7.4` | `0.7.5` | | [zerofrom](https://github.com/unicode-org/icu4x) | `0.1.4` | `0.1.5` | Updates `hashbrown` from 0.15.1 to 0.15.2 - [Changelog](https://github.com/rust-lang/hashbrown/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/hashbrown/commits) Updates `proc-macro2` from 1.0.91 to 1.0.92 - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.91...1.0.92) Updates `portable-atomic` from 1.9.0 to 1.10.0 - [Release notes](https://github.com/taiki-e/portable-atomic/releases) - [Changelog](https://github.com/taiki-e/portable-atomic/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/portable-atomic/compare/v1.9.0...v1.10.0) Updates `url` from 2.5.3 to 2.5.4 - [Release notes](https://github.com/servo/rust-url/releases) - [Commits](https://github.com/servo/rust-url/compare/v2.5.3...v2.5.4) Updates `yoke` from 0.7.4 to 0.7.5 - [Release notes](https://github.com/unicode-org/icu4x/releases) - [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md) - [Commits](https://github.com/unicode-org/icu4x/commits) Updates `zerofrom` from 0.1.4 to 0.1.5 - [Release notes](https://github.com/unicode-org/icu4x/releases) - [Changelog](https://github.com/unicode-org/icu4x/blob/main/CHANGELOG.md) - [Commits](https://github.com/unicode-org/icu4x/commits/ind/databake@0.1.5) --- updated-dependencies: - dependency-name: hashbrown dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: portable-atomic dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: url dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: yoke dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: zerofrom dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 36 ++++++++++++++++++------------------ Cargo.toml | 10 +++++----- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28eabf55454..2107353940c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,7 +369,7 @@ dependencies = [ "fixed_decimal", "float-cmp", "futures-lite 2.5.0", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "icu_calendar", "icu_casemap", "icu_collator", @@ -440,7 +440,7 @@ dependencies = [ "boa_macros", "boa_profiler", "boa_string", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "icu_locid", "thin-vec", ] @@ -472,7 +472,7 @@ dependencies = [ "arbitrary", "boa_gc", "boa_macros", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "indexmap", "once_cell", "phf", @@ -1450,9 +1450,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", @@ -1982,7 +1982,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", ] [[package]] @@ -2658,9 +2658,9 @@ checksum = "2f3a9f18d041e6d0e102a0a46750538147e5e8992d3b4873aaafee2520b00ce3" [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "postcard" @@ -2700,9 +2700,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307e3004becf10f5a6e0d59d20f3cd28231b0e0827a96cd3e0ce6d14bc1e4bb3" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -3667,9 +3667,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -4101,9 +4101,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -4113,9 +4113,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", @@ -4146,9 +4146,9 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] diff --git a/Cargo.toml b/Cargo.toml index 57afce14e19..bdcd485ab94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ bitflags = "2.5.0" clap = "4.5.21" colored = "2.1.0" fast-float2 = "0.2.3" -hashbrown = "0.15.1" +hashbrown = "0.15.2" indexmap = { version = "2.6.0", default-features = false } indoc = "2.0.5" jemallocator = "0.5.4" @@ -104,7 +104,7 @@ thiserror = { version = "2.0.3", default-features = false } dashmap = "6.1.0" num_enum = "0.7.3" itertools = { version = "0.13.0", default-features = false } -portable-atomic = "1.9.0" +portable-atomic = "1.10.0" bytemuck = { version = "1.19.0", default-features = false } arrayvec = "0.7.6" intrusive-collections = "0.9.7" @@ -118,7 +118,7 @@ float-cmp = "0.10.0" futures-lite = "2.5.0" test-case = "3.3.1" winapi = { version = "0.3.9", default-features = false } -url = "2.5.3" +url = "2.5.4" # ICU4X @@ -139,8 +139,8 @@ icu_properties = { version = "~1.5.0", default-features = true } icu_normalizer = { version = "~1.5.0", default-features = false } icu_decimal = { version = "~1.5.0", default-features = false } writeable = "~0.5.5" -yoke = "~0.7.4" -zerofrom = "~0.1.4" +yoke = "~0.7.5" +zerofrom = "~0.1.5" fixed_decimal = "~0.5.6" [workspace.metadata.workspaces] From 1c4f455554b4140910241e86f90474ae3ff9f095 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Nov 2024 21:51:05 +0000 Subject: [PATCH 33/72] Bump rustls from 0.23.17 to 0.23.18 (#4055) Bumps [rustls](https://github.com/rustls/rustls) from 0.23.17 to 0.23.18. - [Release notes](https://github.com/rustls/rustls/releases) - [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustls/rustls/compare/v/0.23.17...v/0.23.18) --- updated-dependencies: - dependency-name: rustls dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2107353940c..638f0524b09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2884,9 +2884,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.17" +version = "0.23.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" +checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" dependencies = [ "log", "once_cell", From 793a10035f101a93268b24be9d4167a5406e9203 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Tue, 3 Dec 2024 05:30:35 +0000 Subject: [PATCH 34/72] Fix rust 1.83.0 lints (#4060) * Fix rust 1.83.0 lints * Allow missing docs in wasm tests * Run tarpaulin on 1.82.0 --- .github/workflows/rust.yml | 4 +++- cli/src/main.rs | 9 ++++----- core/ast/src/expression/operator/assign/op.rs | 3 ++- core/engine/src/builtins/iterable/mod.rs | 1 - core/engine/src/builtins/temporal/mod.rs | 4 ++-- core/engine/src/object/mod.rs | 2 -- core/engine/src/property/mod.rs | 5 ++--- core/engine/tests/macros.rs | 3 +++ core/interop/src/lib.rs | 2 +- core/interop/tests/embedded.rs | 2 ++ core/macros/tests/tests.rs | 2 ++ core/parser/src/lexer/comment.rs | 1 - core/profiler/src/lib.rs | 2 ++ core/runtime/src/url.rs | 8 ++++---- ffi/wasm/tests/web.rs | 3 +++ tests/macros/tests/derive.rs | 2 ++ tests/macros/tests/optional.rs | 2 ++ 17 files changed, 34 insertions(+), 21 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 41eae2a4fcf..b7689fb3299 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -32,7 +32,9 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: - toolchain: stable + # TODO: There seems to be an issue with the 1.83.0 toolchain and tarpaulin. + # See: https://github.com/xd009642/tarpaulin/issues/1642 + toolchain: 1.82.0 - uses: Swatinem/rust-cache@v2 with: diff --git a/cli/src/main.rs b/cli/src/main.rs index 899b73f3139..8d5312a92b3 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -135,24 +135,23 @@ impl Opt { } } +/// The different types of format available for dumping. #[derive(Debug, Copy, Clone, Default, ValueEnum)] enum DumpFormat { - /// The different types of format available for dumping. // NOTE: This can easily support other formats just by // adding a field to this enum and adding the necessary // implementation. Example: Toml, Html, etc. // // NOTE: The fields of this enum are not doc comments because // arg_enum! macro does not support it. - - // This is the default format that you get from std::fmt::Debug. + /// This is the default format that you get from `std::fmt::Debug`. #[default] Debug, - // This is a minified json format. + /// This is a minified json format. Json, - // This is a pretty printed json format. + /// This is a pretty printed json format. JsonPretty, } diff --git a/core/ast/src/expression/operator/assign/op.rs b/core/ast/src/expression/operator/assign/op.rs index 6d32335c1d5..e71019d6bee 100644 --- a/core/ast/src/expression/operator/assign/op.rs +++ b/core/ast/src/expression/operator/assign/op.rs @@ -18,7 +18,7 @@ pub enum AssignOp { /// The assignment operator assigns the value of the right operand to the left operand. /// /// Syntax: `x = y` - + /// /// More information: /// - [ECMAScript reference][spec] /// - [MDN documentation][mdn] @@ -26,6 +26,7 @@ pub enum AssignOp { /// [spec]: https://tc39.es/ecma262/#prod-AssignmentOperator /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Assignment Assign, + /// The addition assignment operator adds the value of the right operand to a variable and assigns the result to the variable. /// /// Syntax: `x += y` diff --git a/core/engine/src/builtins/iterable/mod.rs b/core/engine/src/builtins/iterable/mod.rs index b2de198516f..ba5a1d6ad57 100644 --- a/core/engine/src/builtins/iterable/mod.rs +++ b/core/engine/src/builtins/iterable/mod.rs @@ -155,7 +155,6 @@ impl IteratorPrototypes { /// - [ECMA reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-%iteratorprototype%-object - pub(crate) struct Iterator; impl IntrinsicObject for Iterator { diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index bd4128b3a3b..5ef37ebca61 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -223,10 +223,10 @@ pub(crate) fn _iterator_to_list_of_types( // 13.6 `GetOption ( options, property, type, values, default )` // Implemented in builtin/options.rs -/// 13.7 `ToTemporalOverflow (options)` +// 13.7 `ToTemporalOverflow (options)` // Now implemented in temporal/options.rs -/// 13.10 `ToTemporalRoundingMode ( normalizedOptions, fallback )` +// 13.10 `ToTemporalRoundingMode ( normalizedOptions, fallback )` // Now implemented in builtin/options.rs // 13.11 `NegateTemporalRoundingMode ( roundingMode )` diff --git a/core/engine/src/object/mod.rs b/core/engine/src/object/mod.rs index 3d8fb63bafc..31657c97f1a 100644 --- a/core/engine/src/object/mod.rs +++ b/core/engine/src/object/mod.rs @@ -55,8 +55,6 @@ pub const CONSTRUCTOR: JsString = js_string!("constructor"); /// Const `prototype`, usually set on constructors as a key to point to their respective prototype object. pub const PROTOTYPE: JsString = js_string!("prototype"); -/// Common field names. - /// A type alias for an object prototype. /// /// A `None` values means that the prototype is the `null` value. diff --git a/core/engine/src/property/mod.rs b/core/engine/src/property/mod.rs index bb095142f2a..2ef676abd39 100644 --- a/core/engine/src/property/mod.rs +++ b/core/engine/src/property/mod.rs @@ -669,15 +669,14 @@ where impl From> for PropertyKey { #[inline] fn from(string: JsStr<'_>) -> Self { - return parse_u32_index(string.iter()) - .map_or_else(|| Self::String(string.into()), Self::Index); + parse_u32_index(string.iter()).map_or_else(|| Self::String(string.into()), Self::Index) } } impl From for PropertyKey { #[inline] fn from(string: JsString) -> Self { - return parse_u32_index(string.as_str().iter()).map_or(Self::String(string), Self::Index); + parse_u32_index(string.as_str().iter()).map_or(Self::String(string), Self::Index) } } diff --git a/core/engine/tests/macros.rs b/core/engine/tests/macros.rs index 85ec2a27ad7..7a891acc95f 100644 --- a/core/engine/tests/macros.rs +++ b/core/engine/tests/macros.rs @@ -1,4 +1,7 @@ +//! Tests for the macros in this crate. + #![allow(unused_crate_dependencies)] + use boa_engine::value::TryFromJs; use boa_engine::{js_string, Context, JsResult, JsValue, Source}; use boa_string::JsString; diff --git a/core/interop/src/lib.rs b/core/interop/src/lib.rs index af282f77d33..722f3e99b87 100644 --- a/core/interop/src/lib.rs +++ b/core/interop/src/lib.rs @@ -473,7 +473,7 @@ mod into_js_function_impls; #[test] #[allow(clippy::missing_panics_doc)] -pub fn into_js_module() { +fn into_js_module() { use boa_engine::{js_string, JsValue, Source}; use boa_gc::{Gc, GcRefCell}; use std::cell::RefCell; diff --git a/core/interop/tests/embedded.rs b/core/interop/tests/embedded.rs index 1ef0c4c4516..04b35a9f6ad 100644 --- a/core/interop/tests/embedded.rs +++ b/core/interop/tests/embedded.rs @@ -1,3 +1,5 @@ +//! Tests for the embedded module loader. + #![allow(unused_crate_dependencies)] use std::rc::Rc; diff --git a/core/macros/tests/tests.rs b/core/macros/tests/tests.rs index f0888e0c61d..fe350d3511a 100644 --- a/core/macros/tests/tests.rs +++ b/core/macros/tests/tests.rs @@ -1,3 +1,5 @@ +//! Tests for the macros in this crate. + #![allow(unused_crate_dependencies)] use boa_macros::utf16; diff --git a/core/parser/src/lexer/comment.rs b/core/parser/src/lexer/comment.rs index aca752df1f0..bfb8969c544 100644 --- a/core/parser/src/lexer/comment.rs +++ b/core/parser/src/lexer/comment.rs @@ -104,7 +104,6 @@ impl Tokenizer for MultiLineComment { /// - [ECMAScript reference][spec] /// /// [spec]: https://tc39.es/ecma262/#sec-ecmascript-language-lexical-grammar - pub(super) struct HashbangComment; impl Tokenizer for HashbangComment { diff --git a/core/profiler/src/lib.rs b/core/profiler/src/lib.rs index 69d1927cab1..66e4c802356 100644 --- a/core/profiler/src/lib.rs +++ b/core/profiler/src/lib.rs @@ -93,6 +93,7 @@ impl Profiler { /// Return the global instance of the profiler. #[must_use] + #[allow(static_mut_refs)] pub fn global() -> &'static Self { unsafe { INSTANCE.get_or_init(Self::default) } } @@ -102,6 +103,7 @@ impl Profiler { /// # Panics /// /// Calling `drop` will panic if `INSTANCE` cannot be taken back. + #[allow(static_mut_refs)] pub fn drop(&self) { // In order to drop the INSTANCE we need to get ownership of it, which isn't possible on a static unless you make it a mutable static // mutating statics is unsafe, so we need to wrap it as so. diff --git a/core/runtime/src/url.rs b/core/runtime/src/url.rs index f634ef96f88..2e07b8c19dc 100644 --- a/core/runtime/src/url.rs +++ b/core/runtime/src/url.rs @@ -40,7 +40,7 @@ impl Url { /// /// # Errors /// Any errors that might occur during URL parsing. - fn js_new(Convert(ref url): Convert, base: &Option>) -> JsResult { + fn js_new(Convert(ref url): Convert, base: Option<&Convert>) -> JsResult { if let Some(Convert(base)) = base { let base_url = url::Url::parse(base) .map_err(|e| js_error!(TypeError: "Failed to parse base URL: {}", e))?; @@ -194,7 +194,7 @@ js_class! { } constructor(url: Convert, base: Option>) { - Self::js_new(url, &base) + Self::js_new(url, base.as_ref()) } init(class: &mut ClassBuilder) -> JsResult<()> { @@ -203,11 +203,11 @@ js_class! { }) .into_js_function_copied(class.context()); let can_parse = (|url: Convert, base: Option>| { - Url::js_new(url, &base).is_ok() + Url::js_new(url, base.as_ref()).is_ok() }) .into_js_function_copied(class.context()); let parse = (|url: Convert, base: Option>, context: &mut Context| { - Url::js_new(url, &base) + Url::js_new(url, base.as_ref()) .map_or(Ok(JsValue::null()), |u| Url::from_data(u, context).map(JsValue::from)) }) .into_js_function_copied(class.context()); diff --git a/ffi/wasm/tests/web.rs b/ffi/wasm/tests/web.rs index d3ea23b9f4d..566bca5c75f 100644 --- a/ffi/wasm/tests/web.rs +++ b/ffi/wasm/tests/web.rs @@ -1,3 +1,5 @@ +//! Tests for the wasm module. + #![expect( unused_crate_dependencies, reason = "https://github.com/rust-lang/rust/issues/95513" @@ -6,6 +8,7 @@ any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown" ))] +#![allow(missing_docs)] use wasm_bindgen_test::*; diff --git a/tests/macros/tests/derive.rs b/tests/macros/tests/derive.rs index 1cef0d90770..fd786e7e1f9 100644 --- a/tests/macros/tests/derive.rs +++ b/tests/macros/tests/derive.rs @@ -1,3 +1,5 @@ +//! Tests for the `TryFromJs` derive macro. + #![allow(unused_crate_dependencies)] #[test] diff --git a/tests/macros/tests/optional.rs b/tests/macros/tests/optional.rs index 8c1b4ab0bcf..15893e4ee5e 100644 --- a/tests/macros/tests/optional.rs +++ b/tests/macros/tests/optional.rs @@ -1,3 +1,5 @@ +//! Tests for optional values in `TryFromJs` derive. + #![allow(unused_crate_dependencies)] use boa_engine::value::TryFromJs; From 3fb646a2463c43e473b21bacaa2ef292d7cad113 Mon Sep 17 00:00:00 2001 From: Jason Williams <936006+jasonwilliams@users.noreply.github.com> Date: Tue, 3 Dec 2024 18:21:37 +0000 Subject: [PATCH 35/72] update changelog for 0.20.0 (#4056) --- CHANGELOG.md | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 497c3a6712b..74306691937 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,100 @@ ## What's Changed +# [0.20.0 (2024-09-11)](https://github.com/boa-dev/boa/compare/v0.19.1...v0.20.0) + +### Feature Enhancements + +- Add a js_error! macro to create opaque errors by @hansl in https://github.com/boa-dev/boa/pull/3920 +- Update `Instant` for new Temporal functionality by @nekevss in https://github.com/boa-dev/boa/pull/3928 +- Add a way to add setters/getters in js_class! by @hansl in https://github.com/boa-dev/boa/pull/3911 +- Fix lints from rustc 1.80.0 by @jedel1043 in https://github.com/boa-dev/boa/pull/3936 +- Add a JsError::from_rust constructor to create native errors from Rust by @hansl in https://github.com/boa-dev/boa/pull/3921 +- add some temporal methods by @jasonwilliams in https://github.com/boa-dev/boa/pull/3856 +- Allow a custom Logger to be used as the backend for boa_runtime::Console by @hansl in https://github.com/boa-dev/boa/pull/3943 +- Add more utility functions around modules and exports by @hansl in https://github.com/boa-dev/boa/pull/3937 +- Allow trailing commas in js_class functions by @hansl in https://github.com/boa-dev/boa/pull/3964 +- Implement `Atomics.pause` by @jedel1043 in https://github.com/boa-dev/boa/pull/3956 +- Add a clone_inner method to allow cloning of inner data by @hansl in https://github.com/boa-dev/boa/pull/3968 +- fix: ignore `debugger` statement by @shurizzle in https://github.com/boa-dev/boa/pull/3976 +- Add support for boa(rename = "") in TryFromJs derive by @hansl in https://github.com/boa-dev/boa/pull/3980 +- Add an "iter()" method to Js\*Array for convenience by @hansl in https://github.com/boa-dev/boa/pull/3986 +- A simple module loader from a function by @hansl in https://github.com/boa-dev/boa/pull/3932 +- Add a way for js_error! macro to create native errors with message by @hansl in https://github.com/boa-dev/boa/pull/3971 +- Limit actions runs to 1 per branch and fix macos release by @jedel1043 in https://github.com/boa-dev/boa/pull/3996 +- Add TextEncoder, TextDecoder implementations to boa_runtime by @hansl in https://github.com/boa-dev/boa/pull/3994 +- Add TryFromJs for TypedJsFunction and more tests by @hansl in https://github.com/boa-dev/boa/pull/3981 +- Add context to the console `Logger` trait by @hansl in https://github.com/boa-dev/boa/pull/4005 +- Add a URL class to boa_runtime by @hansl in https://github.com/boa-dev/boa/pull/4004 +- Add a display_lossy() to write a JsString lossily by @hansl in https://github.com/boa-dev/boa/pull/4023 +- `TryIntoJs` trait and derive macro for it by @Nikita-str in https://github.com/boa-dev/boa/pull/3999 +- console.debug() should use a debug Logger method by @hansl in https://github.com/boa-dev/boa/pull/4019 +- `TryFromJs` from `JsMap` for `HashMap` & `BtreeMap` by @Nikita-str in https://github.com/boa-dev/boa/pull/3998 +- Add string builder to build `JsString` by @CrazyboyQCD in https://github.com/boa-dev/boa/pull/3915 + +### Bug Fixes + +- Implement `Math.pow` function according to ECMAScript specification by @magic-akari in https://github.com/boa-dev/boa/pull/3916 +- Fix temporal builtin properties by @nekevss in https://github.com/boa-dev/boa/pull/3930 +- Fix wrong `neg` operation by @CrazyboyQCD in https://github.com/boa-dev/boa/pull/3926 +- Fix destructuring assignment evaluation order by @raskad in https://github.com/boa-dev/boa/pull/3934 +- Fix various parser idempotency issues and parsing errors by @raskad in https://github.com/boa-dev/boa/pull/3917 +- Implement new spec changes for `AsyncGenerator` by @jedel1043 in https://github.com/boa-dev/boa/pull/3950 +- Refactor ast function types by @raskad in https://github.com/boa-dev/boa/pull/3931 +- Fix `js_str` macro to correctly handle latin1 strings by @jedel1043 in https://github.com/boa-dev/boa/pull/3959 +- Allow dead code for code that is newly detected as unused by @hansl in https://github.com/boa-dev/boa/pull/3984 +- Allow warnings when running CI on release branches by @jedel1043 in https://github.com/boa-dev/boa/pull/3990 +- docs: Fix link to examples by @it-a-me in https://github.com/boa-dev/boa/pull/4007 +- `IntegerOrInfinity` `eq` bug fix by @Nikita-str in https://github.com/boa-dev/boa/pull/4010 + +### Internal Improvements + +- Refactor `RawJsString`'s representation to make `JsString`s construction from string literal heap-allocation free by @CrazyboyQCD in https://github.com/boa-dev/boa/pull/3935 +- Split default icu data into lazily deserialized parts by @jedel1043 in https://github.com/boa-dev/boa/pull/3948 +- Add clippy for denying print and eprints by @hansl in https://github.com/boa-dev/boa/pull/3967 +- Refactor iterator APIs to be on parity with the latest spec by @jedel1043 in https://github.com/boa-dev/boa/pull/3962 +- Add support for Trace, Finalize and JsData for Convert<> by @hansl in https://github.com/boa-dev/boa/pull/3970 +- use with_capacity to reduce re-allocations fixes #3896 by @jasonwilliams in https://github.com/boa-dev/boa/pull/3961 +- add nightly build by @jasonwilliams in https://github.com/boa-dev/boa/pull/4026 +- Patch the indentation in nightly_build.yml by @nekevss in https://github.com/boa-dev/boa/pull/4028 +- Update night build's rename binary step by @nekevss in https://github.com/boa-dev/boa/pull/4032 +- Use upload-rust-binary-action for nightly release by @nekevss in https://github.com/boa-dev/boa/pull/4040 +- Fix `ref` value in nightly and add target to nightly release by @nekevss in https://github.com/boa-dev/boa/pull/4042 + +### Other Changes + +- Implement more Temporal functionality by @nekevss in https://github.com/boa-dev/boa/pull/3924 +- Add a Source::with_path method to set the path on a Source by @hansl in https://github.com/boa-dev/boa/pull/3941 +- Add spec edition 15 to the tester by @jedel1043 in https://github.com/boa-dev/boa/pull/3957 +- Rename as_promise to as_promise_object and add as_promise -> JsPromise by @hansl in https://github.com/boa-dev/boa/pull/3965 +- Build out partial record functionality, property bag construction, and `with` methods by @nekevss in https://github.com/boa-dev/boa/pull/3955 +- Enable CI for release branches by @jedel1043 in https://github.com/boa-dev/boa/pull/3987 +- Add a display type for JsString to allow formatting without allocations by @hansl in https://github.com/boa-dev/boa/pull/3951 +- Add TryIntoJsResult for vectors by @hansl in https://github.com/boa-dev/boa/pull/3993 +- Add tests from WPT and fix them in the Console by @hansl in https://github.com/boa-dev/boa/pull/3979 +- Update changelog for v0.19.1 by @jedel1043 in https://github.com/boa-dev/boa/pull/3995 +- Implement register allocation by @HalidOdat in https://github.com/boa-dev/boa/pull/3942 +- Implement scope analysis and local variables by @raskad in https://github.com/boa-dev/boa/pull/3988 +- `JsValue::to_json` fix integer property keys by @Nikita-str in https://github.com/boa-dev/boa/pull/4011 +- Some optimizations on `Error` by @CrazyboyQCD in https://github.com/boa-dev/boa/pull/4020 +- Option::None should try into Undefined, not Null by @hansl in https://github.com/boa-dev/boa/pull/4029 +- Some string optimizations by @CrazyboyQCD in https://github.com/boa-dev/boa/pull/4030 +- Add a JsPromise::from_result for convenience by @hansl in https://github.com/boa-dev/boa/pull/4039 +- Fix misspelled permissions in nightly build action by @nekevss in https://github.com/boa-dev/boa/pull/4041 +- Remove dockerfile from documentation by @4yman-0 in https://github.com/boa-dev/boa/pull/4046 +- Bump dependencies with breaking changes by @jedel1043 in https://github.com/boa-dev/boa/pull/4050 +- Migrate to fast-float2 by @jedel1043 in https://github.com/boa-dev/boa/pull/4052 + +## New Contributors + +- @magic-akari made their first contribution in https://github.com/boa-dev/boa/pull/3916 +- @shurizzle made their first contribution in https://github.com/boa-dev/boa/pull/3976 +- @it-a-me made their first contribution in https://github.com/boa-dev/boa/pull/4007 +- @Nikita-str made their first contribution in https://github.com/boa-dev/boa/pull/4010 +- @4yman-0 made their first contribution in https://github.com/boa-dev/boa/pull/4046 + +**Full Changelog**: https://github.com/boa-dev/boa/compare/v0.19...v0.20.0 + # [0.19.1 (2024-09-11)](https://github.com/boa-dev/boa/compare/v0.19...v0.19.1) ### Bug Fixes From 26681a0e2c4aeb527e7897ee8003a4c8b55dd007 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:02:32 +0100 Subject: [PATCH 36/72] Bump the rust-dependencies group across 1 directory with 6 updates (#4061) * Bump the rust-dependencies group across 1 directory with 6 updates Bumps the rust-dependencies group with 6 updates in the / directory: | Package | From | To | | --- | --- | --- | | [indexmap](https://github.com/indexmap-rs/indexmap) | `2.6.0` | `2.7.0` | | [rustc-hash](https://github.com/rust-lang/rustc-hash) | `2.0.0` | `2.1.0` | | [time](https://github.com/time-rs/time) | `0.3.36` | `0.3.37` | | [wasm-bindgen](https://github.com/rustwasm/wasm-bindgen) | `0.2.95` | `0.2.97` | | [wasm-bindgen-test](https://github.com/rustwasm/wasm-bindgen) | `0.3.45` | `0.3.47` | | [syn](https://github.com/dtolnay/syn) | `2.0.89` | `2.0.90` | Updates `indexmap` from 2.6.0 to 2.7.0 - [Changelog](https://github.com/indexmap-rs/indexmap/blob/master/RELEASES.md) - [Commits](https://github.com/indexmap-rs/indexmap/compare/2.6.0...2.7.0) Updates `rustc-hash` from 2.0.0 to 2.1.0 - [Changelog](https://github.com/rust-lang/rustc-hash/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/rustc-hash/compare/v2.0.0...v2.1.0) Updates `time` from 0.3.36 to 0.3.37 - [Release notes](https://github.com/time-rs/time/releases) - [Changelog](https://github.com/time-rs/time/blob/main/CHANGELOG.md) - [Commits](https://github.com/time-rs/time/compare/v0.3.36...v0.3.37) Updates `wasm-bindgen` from 0.2.95 to 0.2.97 - [Release notes](https://github.com/rustwasm/wasm-bindgen/releases) - [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustwasm/wasm-bindgen/compare/0.2.95...0.2.97) Updates `wasm-bindgen-test` from 0.3.45 to 0.3.47 - [Release notes](https://github.com/rustwasm/wasm-bindgen/releases) - [Changelog](https://github.com/rustwasm/wasm-bindgen/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustwasm/wasm-bindgen/commits) Updates `syn` from 2.0.89 to 2.0.90 - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.89...2.0.90) --- updated-dependencies: - dependency-name: indexmap dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: rustc-hash dependency-type: direct:production update-type: version-update:semver-minor dependency-group: rust-dependencies - dependency-name: time dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: wasm-bindgen dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: wasm-bindgen-test dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch dependency-group: rust-dependencies ... Signed-off-by: dependabot[bot] * Remove `time` sondness workarounds for tests * fix lockfile --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: raskad <32105367+raskad@users.noreply.github.com> --- Cargo.lock | 85 +++++++++++++------------- Cargo.toml | 12 ++-- core/engine/src/builtins/date/tests.rs | 9 +-- core/engine/src/context/hooks.rs | 10 --- tests/tester/Cargo.toml | 1 - tests/tester/src/main.rs | 6 -- 6 files changed, 50 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 638f0524b09..fb353c822b1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -323,7 +323,7 @@ dependencies = [ "boa_string", "indexmap", "num-bigint", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", ] @@ -396,7 +396,7 @@ dependencies = [ "portable-atomic", "rand", "regress", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "ryu-js", "serde", "serde_json", @@ -476,7 +476,7 @@ dependencies = [ "indexmap", "once_cell", "phf", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "static_assertions", ] @@ -488,7 +488,7 @@ dependencies = [ "boa_engine", "boa_gc", "boa_macros", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", ] [[package]] @@ -523,7 +523,7 @@ dependencies = [ "num-bigint", "num-traits", "regress", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", ] [[package]] @@ -532,7 +532,7 @@ version = "0.19.0" dependencies = [ "measureme", "once_cell", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", ] [[package]] @@ -543,7 +543,7 @@ dependencies = [ "boa_gc", "boa_interop", "indoc", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "textwrap", "url", ] @@ -554,7 +554,7 @@ version = "0.19.0" dependencies = [ "fast-float2", "paste", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "sptr", "static_assertions", ] @@ -574,12 +574,11 @@ dependencies = [ "comfy-table", "phf", "rayon", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "serde_json", "serde_repr", "serde_yaml", - "time", "toml 0.8.19", ] @@ -1977,9 +1976,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -2114,10 +2113,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -2865,9 +2865,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustix" @@ -3248,9 +3248,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.89" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -3299,7 +3299,7 @@ dependencies = [ "ixdtf", "num-bigint", "num-traits", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "tinystr", ] @@ -3420,9 +3420,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -3444,9 +3444,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -3736,9 +3736,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -3747,9 +3747,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", @@ -3762,21 +3762,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3784,9 +3785,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", @@ -3797,19 +3798,19 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-bindgen-test" -version = "0.3.45" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d381749acb0943d357dcbd8f0b100640679883fcdeeef04def49daf8d33a5426" +checksum = "3d919bb60ebcecb9160afee6c71b43a58a4f0517a2de0054cd050d02cec08201" dependencies = [ - "console_error_panic_hook", "js-sys", "minicov", + "once_cell", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -3818,9 +3819,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.45" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" +checksum = "222ebde6ea87fbfa6bdd2e9f1fd8a91d60aee5db68792632176c4e16a74fc7d8" dependencies = [ "proc-macro2", "quote", @@ -3869,9 +3870,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index bdcd485ab94..21a34ab6dc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,7 +52,7 @@ clap = "4.5.21" colored = "2.1.0" fast-float2 = "0.2.3" hashbrown = "0.15.2" -indexmap = { version = "2.6.0", default-features = false } +indexmap = { version = "2.7.0", default-features = false } indoc = "2.0.5" jemallocator = "0.5.4" num-bigint = "0.4.6" @@ -62,13 +62,13 @@ phf = { version = "0.11.2", default-features = false } pollster = "0.4.0" regex = "1.11.1" regress = { version = "0.10.1", features = ["utf16"] } -rustc-hash = { version = "2.0.0", default-features = false } +rustc-hash = { version = "2.1.0", default-features = false } serde_json = "1.0.133" serde = "1.0.215" static_assertions = "1.1.0" textwrap = "0.16.0" thin-vec = "0.2.13" -time = { version = "0.3.36", default-features = false, features = ["local-offset", "large-dates", "wasm-bindgen", "parsing", "formatting", "macros"] } +time = { version = "0.3.37", default-features = false, features = ["local-offset", "large-dates", "wasm-bindgen", "parsing", "formatting", "macros"] } tinystr = "0.7.5" log = "0.4.22" simple_logger = "5.0.0" @@ -80,17 +80,17 @@ color-eyre = "0.6.3" comfy-table = "7.1.3" serde_repr = "0.1.19" bus = "2.4.1" -wasm-bindgen = { version = "0.2.95", default-features = false } +wasm-bindgen = { version = "0.2.97", default-features = false } getrandom = { version = "0.2.15", default-features = false } console_error_panic_hook = "0.1.7" -wasm-bindgen-test = "0.3.45" +wasm-bindgen-test = "0.3.47" smol = "2.0.2" futures-util = "0.3.31" isahc = "1.7.2" rustyline = { version = "15.0.0", default-features = false } dhat = "0.3.3" quote = "1.0.37" -syn = { version = "2.0.89", default-features = false } +syn = { version = "2.0.90", default-features = false } proc-macro2 = "1.0" synstructure = "0.13" measureme = "12.0.0" diff --git a/core/engine/src/builtins/date/tests.rs b/core/engine/src/builtins/date/tests.rs index 7950722408c..7cd287352d9 100644 --- a/core/engine/src/builtins/date/tests.rs +++ b/core/engine/src/builtins/date/tests.rs @@ -1,7 +1,7 @@ use crate::{js_string, run_test_actions, JsNativeErrorKind, TestAction}; use boa_macros::js_str; use indoc::indoc; -use time::{macros::format_description, util::local_offset, OffsetDateTime}; +use time::{macros::format_description, OffsetDateTime}; // NOTE: Javascript Uses 0-based months, where time uses 1-based months. // Many of the assertions look wrong because of this. @@ -33,13 +33,6 @@ fn from_local( second: u8, millisecond: u16, ) -> OffsetDateTime { - // Safety: This is needed during tests because cargo is running tests in multiple threads. - // It is safe because tests do not modify the environment. - #[cfg(test)] - unsafe { - local_offset::set_soundness(local_offset::Soundness::Unsound); - } - let t = time::Date::from_calendar_date(year, month_from_u8(month), date) .unwrap() .with_hms_milli(hour, minute, second, millisecond) diff --git a/core/engine/src/context/hooks.rs b/core/engine/src/context/hooks.rs index be477e4d980..e30b8ea39ed 100644 --- a/core/engine/src/context/hooks.rs +++ b/core/engine/src/context/hooks.rs @@ -8,9 +8,6 @@ use crate::{ }; use time::{OffsetDateTime, UtcOffset}; -#[cfg(test)] -use time::util::local_offset; - /// [`Host Hooks`] customizable by the host code or engine. /// /// Every hook contains on its `Requirements` section the spec requirements @@ -191,13 +188,6 @@ pub trait HostHooks { /// Returns the offset of the local timezone to the `utc` timezone in seconds. fn local_timezone_offset_seconds(&self, unix_time_seconds: i64) -> i32 { - // Safety: This is needed during tests because cargo is running tests in multiple threads. - // It is safe because tests do not modify the environment. - #[cfg(test)] - unsafe { - local_offset::set_soundness(local_offset::Soundness::Unsound); - } - OffsetDateTime::from_unix_timestamp(unix_time_seconds) .ok() .and_then(|t| UtcOffset::local_offset_at(t).ok()) diff --git a/tests/tester/Cargo.toml b/tests/tester/Cargo.toml index 0216531282c..f2e5f165df3 100644 --- a/tests/tester/Cargo.toml +++ b/tests/tester/Cargo.toml @@ -29,7 +29,6 @@ phf = { workspace = true, features = ["macros"] } comfy-table.workspace = true serde_repr.workspace = true bus.workspace = true -time.workspace = true [features] default = ["boa_engine/intl_bundled", "boa_engine/experimental", "boa_engine/annex-b"] diff --git a/tests/tester/src/main.rs b/tests/tester/src/main.rs index bc2b8624833..8b35af0fb6a 100644 --- a/tests/tester/src/main.rs +++ b/tests/tester/src/main.rs @@ -193,12 +193,6 @@ const DEFAULT_TEST262_DIRECTORY: &str = "test262"; fn main() -> Result<()> { color_eyre::install()?; - // Safety: This is needed because we run tests in multiple threads. - // It is safe because tests do not modify the environment. - unsafe { - time::util::local_offset::set_soundness(time::util::local_offset::Soundness::Unsound); - } - // initializes the monotonic clock. START .set(Instant::now()) From 97c44239a4edadcaec086fbd28234ebec86eefcc Mon Sep 17 00:00:00 2001 From: Jason Williams <936006+jasonwilliams@users.noreply.github.com> Date: Tue, 3 Dec 2024 23:19:26 +0000 Subject: [PATCH 37/72] update the test262 data on release (#4057) --- .github/workflows/test262_release.yml | 60 +++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/test262_release.yml diff --git a/.github/workflows/test262_release.yml b/.github/workflows/test262_release.yml new file mode 100644 index 00000000000..af50f62fa08 --- /dev/null +++ b/.github/workflows/test262_release.yml @@ -0,0 +1,60 @@ +name: Update Test262 Results on Release + +on: + release: + types: + - published + +jobs: + update_test262_results: + name: Update Test262 Results + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + # Checkout the main repository + - name: Checkout repository + uses: actions/checkout@v4 + with: + path: boa + + # Install Rust toolchain + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + + # Cache cargo dependencies + - name: Cache cargo + uses: actions/cache@v4 + with: + path: | + target + ~/.cargo/git + ~/.cargo/registry + key: ${{ runner.os }}-cargo-test262-${{ hashFiles('**/Cargo.lock') }} + + # Checkout the `data` repository + - name: Checkout the data repo + uses: actions/checkout@v4 + with: + repository: boa-dev/data + token: ${{ secrets.GITHUB_TOKEN }} + path: data + + # Run the Test262 test suite + - name: Run the test262 test suite + run: | + cd boa + cargo run --release --bin boa_tester -- run -v -o ../data/test262 + + # Commit and push results back to the `data` repo + - name: Commit and push results + run: | + cd data + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git add test262/results/${{ github.ref_name }} + git commit -m "Update Test262 results for release ${{ github.ref_name }}" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From e1da91292e71f4c83a56119eef2b1f2d93642e54 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:18:13 +0000 Subject: [PATCH 38/72] Reduce environment allocations (#4002) * Skip environment creation when all bindings in the scope are local * Skip environment creation when possible for arrow functions * Do not allocate space for local bindings in runtime environments * Change RefCell to Cell --- core/ast/src/expression/literal/object.rs | 7 + core/ast/src/function/arrow_function.rs | 7 + core/ast/src/function/async_arrow_function.rs | 7 + core/ast/src/function/async_function.rs | 14 + core/ast/src/function/async_generator.rs | 14 + core/ast/src/function/class.rs | 7 + core/ast/src/function/generator.rs | 14 + core/ast/src/function/ordinary_function.rs | 14 + core/ast/src/scope.rs | 308 +++++++--- core/ast/src/scope_analyzer.rs | 544 +++++++++++++++++- core/ast/src/source.rs | 20 +- .../engine/src/builtins/function/arguments.rs | 16 +- core/engine/src/builtins/function/mod.rs | 11 +- core/engine/src/bytecompiler/class.rs | 30 +- core/engine/src/bytecompiler/declarations.rs | 169 +++--- core/engine/src/bytecompiler/env.rs | 32 +- core/engine/src/bytecompiler/function.rs | 19 +- core/engine/src/bytecompiler/mod.rs | 24 +- .../src/bytecompiler/statement/block.rs | 19 +- .../engine/src/bytecompiler/statement/loop.rs | 96 ++-- .../src/bytecompiler/statement/switch.rs | 17 +- core/engine/src/bytecompiler/statement/try.rs | 10 +- core/engine/src/environments/runtime/mod.rs | 4 +- core/engine/src/module/synthetic.rs | 2 + core/engine/src/vm/code_block.rs | 10 + core/engine/src/vm/opcode/push/environment.rs | 5 +- 26 files changed, 1093 insertions(+), 327 deletions(-) diff --git a/core/ast/src/expression/literal/object.rs b/core/ast/src/expression/literal/object.rs index 88355918b92..3191f20ae71 100644 --- a/core/ast/src/expression/literal/object.rs +++ b/core/ast/src/expression/literal/object.rs @@ -469,6 +469,13 @@ impl ObjectMethodDefinition { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the object method definition contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for ObjectMethodDefinition { diff --git a/core/ast/src/function/arrow_function.rs b/core/ast/src/function/arrow_function.rs index 26bf82437f9..9272febeb13 100644 --- a/core/ast/src/function/arrow_function.rs +++ b/core/ast/src/function/arrow_function.rs @@ -86,6 +86,13 @@ impl ArrowFunction { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the arrow function contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for ArrowFunction { diff --git a/core/ast/src/function/async_arrow_function.rs b/core/ast/src/function/async_arrow_function.rs index a6a360dc676..a800db5bc4a 100644 --- a/core/ast/src/function/async_arrow_function.rs +++ b/core/ast/src/function/async_arrow_function.rs @@ -86,6 +86,13 @@ impl AsyncArrowFunction { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the function declaration contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for AsyncArrowFunction { diff --git a/core/ast/src/function/async_function.rs b/core/ast/src/function/async_function.rs index f80be21962c..401a1694a02 100644 --- a/core/ast/src/function/async_function.rs +++ b/core/ast/src/function/async_function.rs @@ -78,6 +78,13 @@ impl AsyncFunctionDeclaration { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the async function declaration contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for AsyncFunctionDeclaration { @@ -207,6 +214,13 @@ impl AsyncFunctionExpression { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the async function expression contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for AsyncFunctionExpression { diff --git a/core/ast/src/function/async_generator.rs b/core/ast/src/function/async_generator.rs index b7a046e5fc5..72edcb1ef3c 100644 --- a/core/ast/src/function/async_generator.rs +++ b/core/ast/src/function/async_generator.rs @@ -77,6 +77,13 @@ impl AsyncGeneratorDeclaration { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the async generator declaration contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for AsyncGeneratorDeclaration { @@ -206,6 +213,13 @@ impl AsyncGeneratorExpression { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the async generator expression contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for AsyncGeneratorExpression { diff --git a/core/ast/src/function/class.rs b/core/ast/src/function/class.rs index 162b1b6933e..ad5a45d0664 100644 --- a/core/ast/src/function/class.rs +++ b/core/ast/src/function/class.rs @@ -748,6 +748,13 @@ impl ClassMethodDefinition { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the class method definition contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for ClassMethodDefinition { diff --git a/core/ast/src/function/generator.rs b/core/ast/src/function/generator.rs index 7911b922a6d..5ddb3a876d9 100644 --- a/core/ast/src/function/generator.rs +++ b/core/ast/src/function/generator.rs @@ -76,6 +76,13 @@ impl GeneratorDeclaration { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the generator declaration contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for GeneratorDeclaration { @@ -205,6 +212,13 @@ impl GeneratorExpression { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the generator expression contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for GeneratorExpression { diff --git a/core/ast/src/function/ordinary_function.rs b/core/ast/src/function/ordinary_function.rs index 84f8c4c6e37..bd4c456a153 100644 --- a/core/ast/src/function/ordinary_function.rs +++ b/core/ast/src/function/ordinary_function.rs @@ -77,6 +77,13 @@ impl FunctionDeclaration { pub const fn scopes(&self) -> &FunctionScopes { &self.scopes } + + /// Returns `true` if the function declaration contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } } impl ToIndentedString for FunctionDeclaration { @@ -207,6 +214,13 @@ impl FunctionExpression { &self.scopes } + /// Returns `true` if the function expression contains a direct call to `eval`. + #[inline] + #[must_use] + pub const fn contains_direct_eval(&self) -> bool { + self.contains_direct_eval + } + /// Analyze the scope of the function expression. pub fn analyze_scope(&mut self, strict: bool, scope: &Scope, interner: &Interner) -> bool { if !collect_bindings(self, strict, false, scope, interner) { diff --git a/core/ast/src/scope.rs b/core/ast/src/scope.rs index 621189ee79f..08481649955 100644 --- a/core/ast/src/scope.rs +++ b/core/ast/src/scope.rs @@ -3,12 +3,16 @@ //! Scopes are used to track the bindings of identifiers in the AST. use boa_string::JsString; -use rustc_hash::FxHashMap; -use std::{cell::RefCell, fmt::Debug, rc::Rc}; +use std::{ + cell::{Cell, RefCell}, + fmt::Debug, + rc::Rc, +}; #[derive(Clone, Debug, PartialEq)] #[allow(clippy::struct_excessive_bools)] struct Binding { + name: JsString, index: u32, mutable: bool, lex: bool, @@ -50,9 +54,10 @@ impl<'a> arbitrary::Arbitrary<'a> for Scope { #[derive(Debug, PartialEq)] pub(crate) struct Inner { + unique_id: u32, outer: Option, - index: u32, - bindings: RefCell>, + index: Cell, + bindings: RefCell>, function: bool, } @@ -62,8 +67,9 @@ impl Scope { pub fn new_global() -> Self { Self { inner: Rc::new(Inner { + unique_id: 0, outer: None, - index: 0, + index: Cell::default(), bindings: RefCell::default(), function: true, }), @@ -73,20 +79,32 @@ impl Scope { /// Creates a new scope. #[must_use] pub fn new(parent: Self, function: bool) -> Self { - let index = parent.inner.index + 1; + let index = parent.inner.index.get() + 1; Self { inner: Rc::new(Inner { + unique_id: index, outer: Some(parent), - index, + index: Cell::new(index), bindings: RefCell::default(), function, }), } } + /// Checks if the scope has only local bindings. + #[must_use] + pub fn all_bindings_local(&self) -> bool { + // if self.inner.function && self.inn + self.inner + .bindings + .borrow() + .iter() + .all(|binding| !binding.escapes) + } + /// Marks all bindings in this scope as escaping. pub fn escape_all_bindings(&self) { - for binding in self.inner.bindings.borrow_mut().values_mut() { + for binding in self.inner.bindings.borrow_mut().iter_mut() { binding.escapes = true; } } @@ -97,23 +115,29 @@ impl Scope { self.inner .bindings .borrow() - .get(name) + .iter() + .find(|b| &b.name == name) .map_or(false, |binding| binding.lex) } /// Check if the scope has a binding with the given name. #[must_use] pub fn has_binding(&self, name: &JsString) -> bool { - self.inner.bindings.borrow().contains_key(name) + self.inner.bindings.borrow().iter().any(|b| &b.name == name) } /// Get the binding locator for a binding with the given name. /// Fall back to the global scope if the binding is not found. #[must_use] pub fn get_identifier_reference(&self, name: JsString) -> IdentifierReference { - if let Some(binding) = self.inner.bindings.borrow().get(&name) { + if let Some(binding) = self.inner.bindings.borrow().iter().find(|b| b.name == name) { IdentifierReference::new( - BindingLocator::declarative(name, self.inner.index, binding.index), + BindingLocator::declarative( + name, + self.inner.index.get(), + binding.index, + self.inner.unique_id, + ), binding.lex, binding.escapes, ) @@ -131,10 +155,41 @@ impl Scope { self.inner.bindings.borrow().len() as u32 } + /// Returns the number of bindings in this scope that are not local. + #[must_use] + #[allow(clippy::cast_possible_truncation)] + pub fn num_bindings_non_local(&self) -> u32 { + self.inner + .bindings + .borrow() + .iter() + .filter(|binding| binding.escapes) + .count() as u32 + } + + /// Adjust the binding indices to exclude local bindings. + pub(crate) fn reorder_binding_indices(&self) { + let mut bindings = self.inner.bindings.borrow_mut(); + let mut index = 0; + for binding in bindings.iter_mut() { + if !binding.escapes { + binding.index = 0; + continue; + } + binding.index = index; + index += 1; + } + } + /// Returns the index of this scope. #[must_use] pub fn scope_index(&self) -> u32 { - self.inner.index + self.inner.index.get() + } + + /// Set the index of this scope. + pub(crate) fn set_index(&self, index: u32) { + self.inner.index.set(index); } /// Check if the scope is a function scope. @@ -152,21 +207,41 @@ impl Scope { /// Get the locator for a binding name. #[must_use] pub fn get_binding(&self, name: &JsString) -> Option { - self.inner.bindings.borrow().get(name).map(|binding| { - BindingLocator::declarative(name.clone(), self.inner.index, binding.index) - }) + self.inner + .bindings + .borrow() + .iter() + .find(|b| &b.name == name) + .map(|binding| { + BindingLocator::declarative( + name.clone(), + self.inner.index.get(), + binding.index, + self.inner.unique_id, + ) + }) } /// Get the locator for a binding name. #[must_use] pub fn get_binding_reference(&self, name: &JsString) -> Option { - self.inner.bindings.borrow().get(name).map(|binding| { - IdentifierReference::new( - BindingLocator::declarative(name.clone(), self.inner.index, binding.index), - binding.lex, - binding.escapes, - ) - }) + self.inner + .bindings + .borrow() + .iter() + .find(|b| &b.name == name) + .map(|binding| { + IdentifierReference::new( + BindingLocator::declarative( + name.clone(), + self.inner.index.get(), + binding.index, + self.inner.unique_id, + ), + binding.lex, + binding.escapes, + ) + }) } /// Simulate a binding access. @@ -177,7 +252,13 @@ impl Scope { let mut crossed_function_border = false; let mut current = self; loop { - if let Some(binding) = current.inner.bindings.borrow_mut().get_mut(name) { + if let Some(binding) = current + .inner + .bindings + .borrow_mut() + .iter_mut() + .find(|b| &b.name == name) + { if crossed_function_border || eval_or_with { binding.escapes = true; } @@ -198,34 +279,48 @@ impl Scope { #[must_use] #[allow(clippy::cast_possible_truncation)] pub fn create_mutable_binding(&self, name: JsString, function_scope: bool) -> BindingLocator { - let binding_index = self.inner.bindings.borrow().len() as u32; - self.inner.bindings.borrow_mut().insert( - name.clone(), - Binding { - index: binding_index, - mutable: true, - lex: !function_scope, - strict: false, - escapes: self.is_global(), - }, - ); - BindingLocator::declarative(name, self.inner.index, binding_index) + let mut bindings = self.inner.bindings.borrow_mut(); + let binding_index = bindings.len() as u32; + if let Some(binding) = bindings.iter().find(|b| b.name == name) { + return BindingLocator::declarative( + name, + self.inner.index.get(), + binding.index, + self.inner.unique_id, + ); + } + bindings.push(Binding { + name: name.clone(), + index: binding_index, + mutable: true, + lex: !function_scope, + strict: false, + escapes: self.is_global(), + }); + BindingLocator::declarative( + name, + self.inner.index.get(), + binding_index, + self.inner.unique_id, + ) } /// Crate an immutable binding. #[allow(clippy::cast_possible_truncation)] pub(crate) fn create_immutable_binding(&self, name: JsString, strict: bool) { - let binding_index = self.inner.bindings.borrow().len() as u32; - self.inner.bindings.borrow_mut().insert( + let mut bindings = self.inner.bindings.borrow_mut(); + if bindings.iter().any(|b| b.name == name) { + return; + } + let binding_index = bindings.len() as u32; + bindings.push(Binding { name, - Binding { - index: binding_index, - mutable: false, - lex: true, - strict, - escapes: self.is_global(), - }, - ); + index: binding_index, + mutable: false, + lex: true, + strict, + escapes: self.is_global(), + }); } /// Return the binding locator for a mutable binding. @@ -236,25 +331,34 @@ impl Scope { &self, name: JsString, ) -> Result { - Ok(match self.inner.bindings.borrow().get(&name) { - Some(binding) if binding.mutable => IdentifierReference::new( - BindingLocator::declarative(name, self.inner.index, binding.index), - binding.lex, - binding.escapes, - ), - Some(binding) if binding.strict => return Err(BindingLocatorError::MutateImmutable), - Some(_) => return Err(BindingLocatorError::Silent), - None => self.inner.outer.as_ref().map_or_else( - || { - Ok(IdentifierReference::new( - BindingLocator::global(name.clone()), - false, - true, - )) - }, - |outer| outer.set_mutable_binding(name.clone()), - )?, - }) + Ok( + match self.inner.bindings.borrow().iter().find(|b| b.name == name) { + Some(binding) if binding.mutable => IdentifierReference::new( + BindingLocator::declarative( + name, + self.inner.index.get(), + binding.index, + self.inner.unique_id, + ), + binding.lex, + binding.escapes, + ), + Some(binding) if binding.strict => { + return Err(BindingLocatorError::MutateImmutable) + } + Some(_) => return Err(BindingLocatorError::Silent), + None => self.inner.outer.as_ref().map_or_else( + || { + Ok(IdentifierReference::new( + BindingLocator::global(name.clone()), + false, + true, + )) + }, + |outer| outer.set_mutable_binding(name.clone()), + )?, + }, + ) } #[cfg(feature = "annex-b")] @@ -279,25 +383,34 @@ impl Scope { ); } - Ok(match self.inner.bindings.borrow().get(&name) { - Some(binding) if binding.mutable => IdentifierReference::new( - BindingLocator::declarative(name, self.inner.index, binding.index), - binding.lex, - binding.escapes, - ), - Some(binding) if binding.strict => return Err(BindingLocatorError::MutateImmutable), - Some(_) => return Err(BindingLocatorError::Silent), - None => self.inner.outer.as_ref().map_or_else( - || { - Ok(IdentifierReference::new( - BindingLocator::global(name.clone()), - false, - true, - )) - }, - |outer| outer.set_mutable_binding_var(name.clone()), - )?, - }) + Ok( + match self.inner.bindings.borrow().iter().find(|b| b.name == name) { + Some(binding) if binding.mutable => IdentifierReference::new( + BindingLocator::declarative( + name, + self.inner.index.get(), + binding.index, + self.inner.unique_id, + ), + binding.lex, + binding.escapes, + ), + Some(binding) if binding.strict => { + return Err(BindingLocatorError::MutateImmutable) + } + Some(_) => return Err(BindingLocatorError::Silent), + None => self.inner.outer.as_ref().map_or_else( + || { + Ok(IdentifierReference::new( + BindingLocator::global(name.clone()), + false, + true, + )) + }, + |outer| outer.set_mutable_binding_var(name.clone()), + )?, + }, + ) } /// Gets the outer scope of this scope. @@ -358,15 +471,23 @@ pub struct BindingLocator { /// Index of the binding in the scope. binding_index: u32, + + unique_scope_id: u32, } impl BindingLocator { /// Creates a new declarative binding locator that has knows indices. - pub(crate) const fn declarative(name: JsString, scope_index: u32, binding_index: u32) -> Self { + pub(crate) const fn declarative( + name: JsString, + scope_index: u32, + binding_index: u32, + unique_scope_id: u32, + ) -> Self { Self { name, scope: scope_index + 1, binding_index, + unique_scope_id, } } @@ -376,6 +497,7 @@ impl BindingLocator { name, scope: 0, binding_index: 0, + unique_scope_id: 0, } } @@ -480,7 +602,8 @@ impl FunctionScopes { } /// Returns the effective paramter scope for this function. - pub(crate) fn parameter_scope(&self) -> Scope { + #[must_use] + pub fn parameter_scope(&self) -> Scope { if let Some(parameters_eval_scope) = &self.parameters_eval_scope { return parameters_eval_scope.clone(); } @@ -514,6 +637,19 @@ impl FunctionScopes { lexical_scope.escape_all_bindings(); } } + + pub(crate) fn reorder_binding_indices(&self) { + self.function_scope.reorder_binding_indices(); + if let Some(parameters_eval_scope) = &self.parameters_eval_scope { + parameters_eval_scope.reorder_binding_indices(); + } + if let Some(parameters_scope) = &self.parameters_scope { + parameters_scope.reorder_binding_indices(); + } + if let Some(lexical_scope) = &self.lexical_scope { + lexical_scope.reorder_binding_indices(); + } + } } #[cfg(feature = "arbitrary")] diff --git a/core/ast/src/scope_analyzer.rs b/core/ast/src/scope_analyzer.rs index e40534e67a6..b81b0cbcc2d 100644 --- a/core/ast/src/scope_analyzer.rs +++ b/core/ast/src/scope_analyzer.rs @@ -16,8 +16,9 @@ use crate::{ FunctionExpression, GeneratorDeclaration, GeneratorExpression, }, operations::{ - bound_names, lexically_declared_names, lexically_scoped_declarations, var_declared_names, - var_scoped_declarations, LexicallyScopedDeclaration, VarScopedDeclaration, + bound_names, contains, lexically_declared_names, lexically_scoped_declarations, + var_declared_names, var_scoped_declarations, ContainsSymbol, LexicallyScopedDeclaration, + VarScopedDeclaration, }, property::PropertyName, scope::{FunctionScopes, IdentifierReference, Scope}, @@ -104,6 +105,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { try_break!(self.visit_statement_list_mut(&mut node.statements)); if let Some(scope) = &mut node.scope { std::mem::swap(&mut self.scope, scope); + scope.reorder_binding_indices(); } self.direct_eval = direct_eval_old; ControlFlow::Continue(()) @@ -124,6 +126,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { } if let Some(scope) = &mut node.scope { std::mem::swap(&mut self.scope, scope); + scope.reorder_binding_indices(); } self.direct_eval = direct_eval_old; ControlFlow::Continue(()) @@ -139,6 +142,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { std::mem::swap(&mut self.scope, &mut node.scope); try_break!(self.visit_statement_mut(&mut node.statement)); std::mem::swap(&mut self.scope, &mut node.scope); + node.scope.reorder_binding_indices(); self.with = with; ControlFlow::Continue(()) } @@ -155,6 +159,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { } try_break!(self.visit_block_mut(&mut node.block)); std::mem::swap(&mut self.scope, &mut node.scope); + node.scope.reorder_binding_indices(); self.direct_eval = direct_eval_old; ControlFlow::Continue(()) } @@ -180,6 +185,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { try_break!(self.visit_statement_mut(&mut node.inner.body)); if let Some(ForLoopInitializer::Lexical(decl)) = &mut node.inner.init { std::mem::swap(&mut self.scope, &mut decl.scope); + decl.scope.reorder_binding_indices(); } self.direct_eval = direct_eval_old; ControlFlow::Continue(()) @@ -198,6 +204,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { if let Some(scope) = &mut node.target_scope { self.direct_eval = direct_eval_old; std::mem::swap(&mut self.scope, scope); + scope.reorder_binding_indices(); } if let Some(scope) = &mut node.scope { self.direct_eval = node.contains_direct_eval || self.direct_eval; @@ -210,6 +217,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { try_break!(self.visit_statement_mut(&mut node.body)); if let Some(scope) = &mut node.scope { std::mem::swap(&mut self.scope, scope); + scope.reorder_binding_indices(); } self.direct_eval = direct_eval_old; ControlFlow::Continue(()) @@ -228,6 +236,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { if let Some(scope) = &mut node.iterable_scope { self.direct_eval = direct_eval_old; std::mem::swap(&mut self.scope, scope); + scope.reorder_binding_indices(); } if let Some(scope) = &mut node.scope { self.direct_eval = node.contains_direct_eval || self.direct_eval; @@ -240,6 +249,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { try_break!(self.visit_statement_mut(&mut node.body)); if let Some(scope) = &mut node.scope { std::mem::swap(&mut self.scope, scope); + scope.reorder_binding_indices(); } self.direct_eval = direct_eval_old; ControlFlow::Continue(()) @@ -252,7 +262,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -264,7 +274,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -276,7 +286,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -288,7 +298,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -300,7 +310,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -312,7 +322,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -324,7 +334,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -336,7 +346,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -348,7 +358,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -360,7 +370,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -381,6 +391,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { try_break!(self.visit_class_element_mut(element)); } std::mem::swap(&mut self.scope, &mut node.name_scope); + node.name_scope.reorder_binding_indices(); ControlFlow::Continue(()) } @@ -406,6 +417,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { } if let Some(name_scope) = &mut node.name_scope { std::mem::swap(&mut self.scope, name_scope); + name_scope.reorder_binding_indices(); } ControlFlow::Continue(()) } @@ -414,15 +426,41 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { &mut self, node: &'ast mut ClassElement, ) -> ControlFlow { - if let ClassElement::MethodDefinition(node) = node { - self.visit_function_like( + match node { + ClassElement::MethodDefinition(node) => self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, - ) - } else { - ControlFlow::Continue(()) + ), + ClassElement::FieldDefinition(field) | ClassElement::StaticFieldDefinition(field) => { + try_break!(self.visit_property_name_mut(&mut field.name)); + if let Some(e) = &mut field.field { + try_break!(self.visit_expression_mut(e)); + } + ControlFlow::Continue(()) + } + ClassElement::PrivateFieldDefinition(field) => { + if let Some(e) = &mut field.field { + try_break!(self.visit_expression_mut(e)); + } + ControlFlow::Continue(()) + } + ClassElement::PrivateStaticFieldDefinition(_, e) => { + if let Some(e) = e { + try_break!(self.visit_expression_mut(e)); + } + ControlFlow::Continue(()) + } + ClassElement::StaticBlock(node) => { + let contains_direct_eval = contains(node.statements(), ContainsSymbol::DirectEval); + self.visit_function_like( + &mut FormalParameterList::default(), + &mut node.body, + &mut node.scopes, + contains_direct_eval, + ) + } } } @@ -434,7 +472,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { self.visit_function_like( &mut node.parameters, &mut node.body, - &node.scopes, + &mut node.scopes, node.contains_direct_eval, ) } @@ -484,6 +522,7 @@ impl<'ast> VisitorMut<'ast> for BindingEscapeAnalyzer<'_> { std::mem::swap(&mut self.scope, &mut scope); try_break!(self.visit_module_item_list_mut(&mut node.items)); std::mem::swap(&mut self.scope, &mut scope); + scope.reorder_binding_indices(); ControlFlow::Continue(()) } } @@ -493,7 +532,7 @@ impl BindingEscapeAnalyzer<'_> { &mut self, parameters: &mut FormalParameterList, body: &mut FunctionBody, - scopes: &FunctionScopes, + scopes: &mut FunctionScopes, contains_direct_eval: bool, ) -> ControlFlow<&'static str> { let direct_eval_old = self.direct_eval; @@ -509,6 +548,7 @@ impl BindingEscapeAnalyzer<'_> { std::mem::swap(&mut self.scope, &mut scope); try_break!(self.visit_function_body_mut(body)); std::mem::swap(&mut self.scope, &mut scope); + scopes.reorder_binding_indices(); self.direct_eval = direct_eval_old; ControlFlow::Continue(()) } @@ -1149,6 +1189,470 @@ impl BindingCollectorVisitor<'_> { } } +/// Optimize scope indicies when scopes only contain local bindings. +pub(crate) fn optimize_scope_indicies<'a, N>(node: &'a mut N, scope: &Scope) +where + &'a mut N: Into>, +{ + let mut visitor = ScopeIndexVisitor { + index: scope.scope_index(), + }; + visitor.visit(node.into()); +} + +struct ScopeIndexVisitor { + index: u32, +} + +impl<'ast> VisitorMut<'ast> for ScopeIndexVisitor { + type BreakTy = (); + + fn visit_function_declaration_mut( + &mut self, + node: &'ast mut FunctionDeclaration, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + false, + contains_direct_eval, + ) + } + + fn visit_generator_declaration_mut( + &mut self, + node: &'ast mut GeneratorDeclaration, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + false, + contains_direct_eval, + ) + } + + fn visit_async_function_declaration_mut( + &mut self, + node: &'ast mut AsyncFunctionDeclaration, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + false, + contains_direct_eval, + ) + } + + fn visit_async_generator_declaration_mut( + &mut self, + node: &'ast mut AsyncGeneratorDeclaration, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + false, + contains_direct_eval, + ) + } + + fn visit_function_expression_mut( + &mut self, + node: &'ast mut FunctionExpression, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut node.name_scope, + false, + contains_direct_eval, + ) + } + + fn visit_generator_expression_mut( + &mut self, + node: &'ast mut GeneratorExpression, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut node.name_scope, + false, + contains_direct_eval, + ) + } + + fn visit_async_function_expression_mut( + &mut self, + node: &'ast mut AsyncFunctionExpression, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut node.name_scope, + false, + contains_direct_eval, + ) + } + + fn visit_async_generator_expression_mut( + &mut self, + node: &'ast mut AsyncGeneratorExpression, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut node.name_scope, + false, + contains_direct_eval, + ) + } + + fn visit_arrow_function_mut( + &mut self, + node: &'ast mut ArrowFunction, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + true, + contains_direct_eval, + ) + } + + fn visit_async_arrow_function_mut( + &mut self, + node: &'ast mut AsyncArrowFunction, + ) -> ControlFlow { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + true, + contains_direct_eval, + ) + } + + fn visit_class_declaration_mut( + &mut self, + node: &'ast mut ClassDeclaration, + ) -> ControlFlow { + let index = self.index; + if !node.name_scope.all_bindings_local() { + self.index += 1; + } + node.name_scope.set_index(self.index); + if let Some(super_ref) = &mut node.super_ref { + try_break!(self.visit_expression_mut(super_ref)); + } + if let Some(constructor) = &mut node.constructor { + try_break!(self.visit_function_expression_mut(constructor)); + } + for element in &mut *node.elements { + try_break!(self.visit_class_element_mut(element)); + } + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_class_expression_mut( + &mut self, + node: &'ast mut ClassExpression, + ) -> ControlFlow { + let index = self.index; + if let Some(scope) = &node.name_scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + if let Some(super_ref) = &mut node.super_ref { + try_break!(self.visit_expression_mut(super_ref)); + } + if let Some(constructor) = &mut node.constructor { + try_break!(self.visit_function_expression_mut(constructor)); + } + for element in &mut *node.elements { + try_break!(self.visit_class_element_mut(element)); + } + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_class_element_mut( + &mut self, + node: &'ast mut ClassElement, + ) -> ControlFlow { + match node { + ClassElement::MethodDefinition(node) => { + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + false, + contains_direct_eval, + ) + } + ClassElement::FieldDefinition(field) | ClassElement::StaticFieldDefinition(field) => { + try_break!(self.visit_property_name_mut(&mut field.name)); + let index = self.index; + self.index += 1; + field.scope.set_index(self.index); + if let Some(e) = &mut field.field { + try_break!(self.visit_expression_mut(e)); + } + self.index = index; + ControlFlow::Continue(()) + } + ClassElement::PrivateFieldDefinition(field) => { + let index = self.index; + self.index += 1; + field.scope.set_index(self.index); + if let Some(e) = &mut field.field { + try_break!(self.visit_expression_mut(e)); + } + self.index = index; + ControlFlow::Continue(()) + } + ClassElement::PrivateStaticFieldDefinition(_, e) => { + if let Some(e) = e { + try_break!(self.visit_expression_mut(e)); + } + ControlFlow::Continue(()) + } + ClassElement::StaticBlock(node) => { + let contains_direct_eval = contains(node.statements(), ContainsSymbol::DirectEval); + self.visit_function_like( + &mut node.body, + &mut FormalParameterList::default(), + &mut node.scopes, + &mut None, + false, + contains_direct_eval, + ) + } + } + } + + fn visit_object_method_definition_mut( + &mut self, + node: &'ast mut ObjectMethodDefinition, + ) -> ControlFlow { + match &mut node.name { + PropertyName::Literal(_) => {} + PropertyName::Computed(name) => { + try_break!(self.visit_expression_mut(name)); + } + } + let contains_direct_eval = node.contains_direct_eval(); + self.visit_function_like( + &mut node.body, + &mut node.parameters, + &mut node.scopes, + &mut None, + false, + contains_direct_eval, + ) + } + + fn visit_block_mut(&mut self, node: &'ast mut Block) -> ControlFlow { + let index = self.index; + if let Some(scope) = &node.scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + try_break!(self.visit_statement_list_mut(&mut node.statements)); + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_switch_mut(&mut self, node: &'ast mut Switch) -> ControlFlow { + let index = self.index; + try_break!(self.visit_expression_mut(&mut node.val)); + if let Some(scope) = &node.scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + for case in &mut *node.cases { + try_break!(self.visit_case_mut(case)); + } + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_with_mut(&mut self, node: &'ast mut With) -> ControlFlow { + let index = self.index; + try_break!(self.visit_expression_mut(&mut node.expression)); + self.index += 1; + node.scope.set_index(self.index); + try_break!(self.visit_statement_mut(&mut node.statement)); + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_catch_mut(&mut self, node: &'ast mut Catch) -> ControlFlow { + let index = self.index; + if !node.scope.all_bindings_local() { + self.index += 1; + } + node.scope.set_index(self.index); + if let Some(binding) = &mut node.parameter { + try_break!(self.visit_binding_mut(binding)); + } + try_break!(self.visit_block_mut(&mut node.block)); + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_for_loop_mut(&mut self, node: &'ast mut ForLoop) -> ControlFlow { + let index = self.index; + if let Some(ForLoopInitializer::Lexical(decl)) = &mut node.inner.init { + if !decl.scope.all_bindings_local() { + self.index += 1; + } + decl.scope.set_index(self.index); + } + if let Some(fli) = &mut node.inner.init { + try_break!(self.visit_for_loop_initializer_mut(fli)); + } + if let Some(expr) = &mut node.inner.condition { + try_break!(self.visit_expression_mut(expr)); + } + if let Some(expr) = &mut node.inner.final_expr { + try_break!(self.visit_expression_mut(expr)); + } + self.visit_statement_mut(&mut node.inner.body); + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_for_in_loop_mut(&mut self, node: &'ast mut ForInLoop) -> ControlFlow { + { + let index = self.index; + if let Some(scope) = &node.target_scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + try_break!(self.visit_expression_mut(&mut node.target)); + self.index = index; + } + let index = self.index; + if let Some(scope) = &node.scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + try_break!(self.visit_iterable_loop_initializer_mut(&mut node.initializer)); + try_break!(self.visit_statement_mut(&mut node.body)); + self.index = index; + ControlFlow::Continue(()) + } + + fn visit_for_of_loop_mut(&mut self, node: &'ast mut ForOfLoop) -> ControlFlow { + { + let index = self.index; + if let Some(scope) = &node.iterable_scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + try_break!(self.visit_expression_mut(&mut node.iterable)); + self.index = index; + } + let index = self.index; + if let Some(scope) = &node.scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + try_break!(self.visit_iterable_loop_initializer_mut(&mut node.init)); + try_break!(self.visit_statement_mut(&mut node.body)); + self.index = index; + ControlFlow::Continue(()) + } +} + +impl ScopeIndexVisitor { + fn visit_function_like( + &mut self, + body: &mut FunctionBody, + parameters: &mut FormalParameterList, + scopes: &mut FunctionScopes, + name_scope: &mut Option, + arrow: bool, + contains_direct_eval: bool, + ) -> ControlFlow<()> { + let index = self.index; + if let Some(scope) = name_scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + if !(arrow && scopes.function_scope.all_bindings_local() && !contains_direct_eval) { + self.index += 1; + } + scopes.function_scope.set_index(self.index); + if let Some(scope) = &scopes.parameters_eval_scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + try_break!(self.visit_formal_parameter_list_mut(parameters)); + if let Some(scope) = &scopes.parameters_scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + if let Some(scope) = &scopes.lexical_scope { + if !scope.all_bindings_local() { + self.index += 1; + } + scope.set_index(self.index); + } + try_break!(self.visit_function_body_mut(body)); + self.index = index; + ControlFlow::Continue(()) + } +} + /// `GlobalDeclarationInstantiation ( script, env )` /// /// More information: diff --git a/core/ast/src/source.rs b/core/ast/src/source.rs index f1220a76213..e7a4ad1633b 100644 --- a/core/ast/src/source.rs +++ b/core/ast/src/source.rs @@ -7,7 +7,7 @@ use crate::{ scope::Scope, scope_analyzer::{ analyze_binding_escapes, collect_bindings, eval_declaration_instantiation_scope, - EvalDeclarationBindings, + optimize_scope_indicies, EvalDeclarationBindings, }, visitor::{VisitWith, Visitor, VisitorMut}, ModuleItemList, StatementList, @@ -56,7 +56,11 @@ impl Script { if !collect_bindings(self, self.strict(), false, scope, interner) { return false; } - analyze_binding_escapes(self, false, scope.clone(), interner) + if !analyze_binding_escapes(self, false, scope.clone(), interner) { + return false; + } + optimize_scope_indicies(self, scope); + true } /// Analyze the scope of the script in eval mode. @@ -84,10 +88,14 @@ impl Script { if !collect_bindings(self, strict, true, lexical_scope, interner) { return Err(String::from("Failed to analyze scope")); } - if !analyze_binding_escapes(self, true, lexical_scope.clone(), interner) { return Err(String::from("Failed to analyze scope")); } + variable_scope.escape_all_bindings(); + lexical_scope.escape_all_bindings(); + variable_scope.reorder_binding_indices(); + lexical_scope.reorder_binding_indices(); + optimize_scope_indicies(self, lexical_scope); Ok(bindings) } @@ -158,7 +166,11 @@ impl Module { if !collect_bindings(self, true, false, scope, interner) { return false; } - analyze_binding_escapes(self, false, scope.clone(), interner) + if !analyze_binding_escapes(self, false, scope.clone(), interner) { + return false; + } + optimize_scope_indicies(self, &self.scope.clone()); + true } } diff --git a/core/engine/src/builtins/function/arguments.rs b/core/engine/src/builtins/function/arguments.rs index 83fd821287e..01f28a23ffd 100644 --- a/core/engine/src/builtins/function/arguments.rs +++ b/core/engine/src/builtins/function/arguments.rs @@ -1,4 +1,5 @@ use crate::{ + bytecompiler::ToJsString, environments::DeclarativeEnvironment, object::{ internal_methods::{ @@ -11,8 +12,9 @@ use crate::{ property::{DescriptorKind, PropertyDescriptor, PropertyKey}, Context, JsData, JsResult, JsValue, }; -use boa_ast::{function::FormalParameterList, operations::bound_names}; +use boa_ast::{function::FormalParameterList, operations::bound_names, scope::Scope}; use boa_gc::{Finalize, Gc, Trace}; +use boa_interner::Interner; use rustc_hash::FxHashMap; use thin_vec::{thin_vec, ThinVec}; @@ -141,7 +143,11 @@ impl MappedArguments { } impl MappedArguments { - pub(crate) fn binding_indices(formals: &FormalParameterList) -> ThinVec> { + pub(crate) fn binding_indices( + formals: &FormalParameterList, + scope: &Scope, + interner: &Interner, + ) -> ThinVec> { // Section 17-19 are done first, for easier object creation in 11. // // The section 17-19 differs from the spec, due to the way the runtime environments work. @@ -180,8 +186,10 @@ impl MappedArguments { let mut bindings = FxHashMap::default(); let mut property_index = 0; for name in bound_names(formals) { - // NOTE(HalidOdat): Offset by +1 to account for the first binding ("argument"). - let binding_index = bindings.len() as u32 + 1; + let binding_index = scope + .get_binding(&name.to_js_string(interner)) + .expect("binding must exist") + .binding_index(); let entry = bindings .entry(name) diff --git a/core/engine/src/builtins/function/mod.rs b/core/engine/src/builtins/function/mod.rs index bd662fe4d7c..94751379289 100644 --- a/core/engine/src/builtins/function/mod.rs +++ b/core/engine/src/builtins/function/mod.rs @@ -657,6 +657,7 @@ impl BuiltInFunctionObject { context.realm().scope().clone(), context.realm().scope().clone(), function.scopes(), + function.contains_direct_eval(), context.interner_mut(), ); @@ -1028,10 +1029,12 @@ pub(crate) fn function_call( last_env += 1; } - context.vm.environments.push_function( - code.constant_scope(last_env), - FunctionSlots::new(this, function_object.clone(), None), - ); + if code.has_function_scope() { + context.vm.environments.push_function( + code.constant_scope(last_env), + FunctionSlots::new(this, function_object.clone(), None), + ); + } Ok(CallValue::Ready) } diff --git a/core/engine/src/bytecompiler/class.rs b/core/engine/src/bytecompiler/class.rs index bfc69002291..1e360be4920 100644 --- a/core/engine/src/bytecompiler/class.rs +++ b/core/engine/src/bytecompiler/class.rs @@ -79,14 +79,7 @@ impl ByteCompiler<'_> { .map_or(Sym::EMPTY_STRING, Identifier::sym) .to_js_string(self.interner()); - let outer_scope = if let Some(name_scope) = class.name_scope { - let outer_scope = self.lexical_scope.clone(); - let scope_index = self.push_scope(name_scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - Some(outer_scope) - } else { - None - }; + let outer_scope = self.push_declarative_scope(class.name_scope); let mut compiler = ByteCompiler::new( class_name.clone(), @@ -103,10 +96,12 @@ impl ByteCompiler<'_> { compiler.code_block_flags |= CodeBlockFlags::IS_CLASS_CONSTRUCTOR; if let Some(expr) = &class.constructor { + compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; let _ = compiler.push_scope(expr.scopes().function_scope()); compiler.length = expr.parameters().length(); compiler.params = expr.parameters().clone(); + compiler.parameter_scope = expr.scopes().parameter_scope(); compiler.function_declaration_instantiation( expr.body(), @@ -122,11 +117,13 @@ impl ByteCompiler<'_> { compiler.emit_opcode(Opcode::PushUndefined); } else if class.super_ref.is_some() { // We push an empty, unused function scope since the compiler expects a function scope. + compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; let _ = compiler.push_scope(&Scope::new(compiler.lexical_scope.clone(), true)); compiler.emit_opcode(Opcode::SuperCallDerived); compiler.emit_opcode(Opcode::BindThisValue); } else { // We push an empty, unused function scope since the compiler expects a function scope. + compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; let _ = compiler.push_scope(&Scope::new(compiler.lexical_scope.clone(), true)); compiler.emit_opcode(Opcode::PushUndefined); } @@ -181,9 +178,11 @@ impl ByteCompiler<'_> { let mut static_elements = Vec::new(); let mut static_field_name_count = 0; - if outer_scope.is_some() { + if let Some(scope) = class.name_scope { + let binding = scope.get_identifier_reference(class_name.clone()); + let index = self.get_or_insert_binding(binding); self.emit_opcode(Opcode::Dup); - self.emit_binding(BindingOpcode::InitLexical, class_name.clone()); + self.emit_binding_access(Opcode::PutLexicalValue, &index); } for element in class.elements { @@ -293,6 +292,7 @@ impl ByteCompiler<'_> { ); // Function environment + field_compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; let _ = field_compiler.push_scope(field.scope()); let is_anonymous_function = if let Some(node) = &field.field() { field_compiler.compile_expr(node, true); @@ -327,6 +327,7 @@ impl ByteCompiler<'_> { self.interner, self.in_with, ); + field_compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; let _ = field_compiler.push_scope(field.scope()); if let Some(node) = field.field() { field_compiler.compile_expr(node, true); @@ -368,6 +369,7 @@ impl ByteCompiler<'_> { self.interner, self.in_with, ); + field_compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; let _ = field_compiler.push_scope(field.scope()); let is_anonymous_function = if let Some(node) = &field.field() { field_compiler.compile_expr(node, true); @@ -411,6 +413,7 @@ impl ByteCompiler<'_> { self.interner, self.in_with, ); + compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; let _ = compiler.push_scope(block.scopes().function_scope()); compiler.function_declaration_instantiation( @@ -474,12 +477,7 @@ impl ByteCompiler<'_> { self.emit_opcode(Opcode::Swap); self.emit_opcode(Opcode::Pop); - if let Some(outer_scope) = outer_scope { - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); - } - + self.pop_declarative_scope(outer_scope); self.emit_opcode(Opcode::PopPrivateEnvironment); if !expression { diff --git a/core/engine/src/bytecompiler/declarations.rs b/core/engine/src/bytecompiler/declarations.rs index e040c99a5d7..06b91d9293c 100644 --- a/core/engine/src/bytecompiler/declarations.rs +++ b/core/engine/src/bytecompiler/declarations.rs @@ -479,41 +479,46 @@ impl ByteCompiler<'_> { // 16. For each Parse Node f of functionsToInitialize, do for function in functions_to_initialize { // a. Let fn be the sole element of the BoundNames of f. - let (name, generator, r#async, parameters, body, scopes) = match &function { - VarScopedDeclaration::FunctionDeclaration(f) => ( - f.name(), - false, - false, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::GeneratorDeclaration(f) => ( - f.name(), - true, - false, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::AsyncFunctionDeclaration(f) => ( - f.name(), - false, - true, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::AsyncGeneratorDeclaration(f) => ( - f.name(), - true, - true, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::VariableDeclaration(_) => continue, - }; + let (name, generator, r#async, parameters, body, scopes, contains_direct_eval) = + match &function { + VarScopedDeclaration::FunctionDeclaration(f) => ( + f.name(), + false, + false, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::GeneratorDeclaration(f) => ( + f.name(), + true, + false, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::AsyncFunctionDeclaration(f) => ( + f.name(), + false, + true, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => ( + f.name(), + true, + true, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::VariableDeclaration(_) => continue, + }; let code = FunctionCompiler::new() .name(name.sym().to_js_string(self.interner())) @@ -527,6 +532,7 @@ impl ByteCompiler<'_> { self.variable_scope.clone(), self.lexical_scope.clone(), &scopes, + contains_direct_eval, self.interner, ); @@ -737,43 +743,48 @@ impl ByteCompiler<'_> { // 17. For each Parse Node f of functionsToInitialize, do for function in functions_to_initialize { // a. Let fn be the sole element of the BoundNames of f. - let (name, generator, r#async, parameters, body, scopes) = match &function { - VarScopedDeclaration::FunctionDeclaration(f) => ( - f.name(), - false, - false, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::GeneratorDeclaration(f) => ( - f.name(), - true, - false, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::AsyncFunctionDeclaration(f) => ( - f.name(), - false, - true, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::AsyncGeneratorDeclaration(f) => ( - f.name(), - true, - true, - f.parameters(), - f.body(), - f.scopes().clone(), - ), - VarScopedDeclaration::VariableDeclaration(_) => { - continue; - } - }; + let (name, generator, r#async, parameters, body, scopes, contains_direct_eval) = + match &function { + VarScopedDeclaration::FunctionDeclaration(f) => ( + f.name(), + false, + false, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::GeneratorDeclaration(f) => ( + f.name(), + true, + false, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::AsyncFunctionDeclaration(f) => ( + f.name(), + false, + true, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::AsyncGeneratorDeclaration(f) => ( + f.name(), + true, + true, + f.parameters(), + f.body(), + f.scopes().clone(), + f.contains_direct_eval(), + ), + VarScopedDeclaration::VariableDeclaration(_) => { + continue; + } + }; let code = FunctionCompiler::new() .name(name.sym().to_js_string(self.interner())) @@ -788,6 +799,7 @@ impl ByteCompiler<'_> { self.variable_scope.clone(), self.lexical_scope.clone(), &scopes, + contains_direct_eval, self.interner, ); @@ -963,10 +975,7 @@ impl ByteCompiler<'_> { } // 19-20 - if let Some(scope) = scopes.parameters_eval_scope() { - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - } + drop(self.push_declarative_scope(scopes.parameters_eval_scope())); let scope = self.lexical_scope.clone(); @@ -1057,8 +1066,7 @@ impl ByteCompiler<'_> { // visibility of declarations in the function body. // b. Let varEnv be NewDeclarativeEnvironment(env). // c. Set the VariableEnvironment of calleeContext to varEnv. - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); + drop(self.push_declarative_scope(Some(scope))); let mut variable_scope = self.lexical_scope.clone(); @@ -1177,10 +1185,7 @@ impl ByteCompiler<'_> { } // 30-31 - if let Some(scope) = scopes.lexical_scope() { - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - } + drop(self.push_declarative_scope(scopes.lexical_scope())); // 35. Let privateEnv be the PrivateEnvironment of calleeContext. // 36. For each Parse Node f of functionsToInitialize, do diff --git a/core/engine/src/bytecompiler/env.rs b/core/engine/src/bytecompiler/env.rs index 59b65184e35..1fddff71ac2 100644 --- a/core/engine/src/bytecompiler/env.rs +++ b/core/engine/src/bytecompiler/env.rs @@ -1,5 +1,7 @@ use boa_ast::scope::Scope; +use crate::vm::{Constant, Opcode}; + use super::ByteCompiler; impl ByteCompiler<'_> { @@ -9,8 +11,7 @@ impl ByteCompiler<'_> { self.current_open_environments_count += 1; let index = self.constants.len() as u32; - self.constants - .push(crate::vm::Constant::Scope(scope.clone())); + self.constants.push(Constant::Scope(scope.clone())); if scope.is_function() { self.variable_scope = scope.clone(); @@ -21,6 +22,33 @@ impl ByteCompiler<'_> { index } + /// Push a declarative scope. + /// + /// Returns the outer scope. + #[must_use] + pub(crate) fn push_declarative_scope(&mut self, scope: Option<&Scope>) -> Option { + let mut scope = scope?.clone(); + if !scope.all_bindings_local() { + self.current_open_environments_count += 1; + let index = self.constants.len() as u32; + self.constants.push(Constant::Scope(scope.clone())); + self.emit_with_varying_operand(Opcode::PushScope, index); + } + std::mem::swap(&mut self.lexical_scope, &mut scope); + Some(scope) + } + + /// Pop a declarative scope. + pub(crate) fn pop_declarative_scope(&mut self, scope: Option) { + if let Some(mut scope) = scope { + std::mem::swap(&mut self.lexical_scope, &mut scope); + if !scope.all_bindings_local() { + self.current_open_environments_count -= 1; + self.emit_opcode(Opcode::PopEnvironment); + } + } + } + /// Pops the top scope. pub(crate) fn pop_scope(&mut self) { self.current_open_environments_count -= 1; diff --git a/core/engine/src/bytecompiler/function.rs b/core/engine/src/bytecompiler/function.rs index 3fef0a612d6..5909783b025 100644 --- a/core/engine/src/bytecompiler/function.rs +++ b/core/engine/src/bytecompiler/function.rs @@ -94,6 +94,7 @@ impl FunctionCompiler { } /// Compile a function statement list and it's parameters into bytecode. + #[allow(clippy::too_many_arguments)] pub(crate) fn compile( mut self, parameters: &FormalParameterList, @@ -101,6 +102,7 @@ impl FunctionCompiler { variable_environment: Scope, lexical_environment: Scope, scopes: &FunctionScopes, + contains_direct_eval: bool, interner: &mut Interner, ) -> Gc { self.strict = self.strict || body.strict(); @@ -129,11 +131,19 @@ impl FunctionCompiler { } if let Some(scope) = self.name_scope { - compiler.code_block_flags |= CodeBlockFlags::HAS_BINDING_IDENTIFIER; - let _ = compiler.push_scope(&scope); + if !scope.all_bindings_local() { + compiler.code_block_flags |= CodeBlockFlags::HAS_BINDING_IDENTIFIER; + let _ = compiler.push_scope(&scope); + } + } + + if self.arrow && scopes.function_scope().all_bindings_local() && !contains_direct_eval { + compiler.variable_scope = scopes.function_scope().clone(); + compiler.lexical_scope = scopes.function_scope().clone(); + } else { + compiler.code_block_flags |= CodeBlockFlags::HAS_FUNCTION_SCOPE; + let _ = compiler.push_scope(scopes.function_scope()); } - // Function environment - let _ = compiler.push_scope(scopes.function_scope()); // Taken from: // - 15.9.3 Runtime Semantics: EvaluateAsyncConciseBody: @@ -185,6 +195,7 @@ impl FunctionCompiler { compiler.compile_statement_list(body.statement_list(), false, false); compiler.params = parameters.clone(); + compiler.parameter_scope = scopes.parameter_scope(); let code = compiler.finish(); diff --git a/core/engine/src/bytecompiler/mod.rs b/core/engine/src/bytecompiler/mod.rs index da428e4e2d2..657261f3e80 100644 --- a/core/engine/src/bytecompiler/mod.rs +++ b/core/engine/src/bytecompiler/mod.rs @@ -122,6 +122,7 @@ pub(crate) struct FunctionSpec<'a> { body: &'a FunctionBody, pub(crate) scopes: &'a FunctionScopes, pub(crate) name_scope: Option<&'a Scope>, + pub(crate) contains_direct_eval: bool, } impl<'a> From<&'a FunctionDeclaration> for FunctionSpec<'a> { @@ -133,6 +134,7 @@ impl<'a> From<&'a FunctionDeclaration> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: None, + contains_direct_eval: function.contains_direct_eval(), } } } @@ -146,6 +148,7 @@ impl<'a> From<&'a GeneratorDeclaration> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: None, + contains_direct_eval: function.contains_direct_eval(), } } } @@ -159,6 +162,7 @@ impl<'a> From<&'a AsyncFunctionDeclaration> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: None, + contains_direct_eval: function.contains_direct_eval(), } } } @@ -172,6 +176,7 @@ impl<'a> From<&'a AsyncGeneratorDeclaration> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: None, + contains_direct_eval: function.contains_direct_eval(), } } } @@ -185,6 +190,7 @@ impl<'a> From<&'a FunctionExpression> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: function.name_scope(), + contains_direct_eval: function.contains_direct_eval(), } } } @@ -198,6 +204,7 @@ impl<'a> From<&'a ArrowFunction> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: None, + contains_direct_eval: function.contains_direct_eval(), } } } @@ -211,6 +218,7 @@ impl<'a> From<&'a AsyncArrowFunction> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: None, + contains_direct_eval: function.contains_direct_eval(), } } } @@ -224,6 +232,7 @@ impl<'a> From<&'a AsyncFunctionExpression> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: function.name_scope(), + contains_direct_eval: function.contains_direct_eval(), } } } @@ -237,6 +246,7 @@ impl<'a> From<&'a GeneratorExpression> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: function.name_scope(), + contains_direct_eval: function.contains_direct_eval(), } } } @@ -250,6 +260,7 @@ impl<'a> From<&'a AsyncGeneratorExpression> for FunctionSpec<'a> { body: function.body(), scopes: function.scopes(), name_scope: function.name_scope(), + contains_direct_eval: function.contains_direct_eval(), } } } @@ -270,6 +281,7 @@ impl<'a> From<&'a ClassMethodDefinition> for FunctionSpec<'a> { body: method.body(), scopes: method.scopes(), name_scope: None, + contains_direct_eval: method.contains_direct_eval(), } } } @@ -290,6 +302,7 @@ impl<'a> From<&'a ObjectMethodDefinition> for FunctionSpec<'a> { body: method.body(), scopes: method.scopes(), name_scope: None, + contains_direct_eval: method.contains_direct_eval(), } } } @@ -388,6 +401,9 @@ pub struct ByteCompiler<'ctx> { /// Parameters passed to this function. pub(crate) params: FormalParameterList, + /// Scope of the function parameters. + pub(crate) parameter_scope: Scope, + /// Bytecode pub(crate) bytecode: Vec, @@ -500,6 +516,7 @@ impl<'ctx> ByteCompiler<'ctx> { local_binding_registers: FxHashMap::default(), this_mode: ThisMode::Global, params: FormalParameterList::default(), + parameter_scope: Scope::default(), current_open_environments_count: 0, register_allocator, @@ -1518,6 +1535,7 @@ impl<'ctx> ByteCompiler<'ctx> { self.variable_scope.clone(), self.lexical_scope.clone(), scopes, + function.contains_direct_eval, self.interner, ); @@ -1595,6 +1613,7 @@ impl<'ctx> ByteCompiler<'ctx> { self.variable_scope.clone(), self.lexical_scope.clone(), scopes, + function.contains_direct_eval, self.interner, ); @@ -1638,6 +1657,7 @@ impl<'ctx> ByteCompiler<'ctx> { self.variable_scope.clone(), self.lexical_scope.clone(), scopes, + function.contains_direct_eval, self.interner, ); @@ -1756,7 +1776,9 @@ impl<'ctx> ByteCompiler<'ctx> { let mapped_arguments_binding_indices = self .emitted_mapped_arguments_object_opcode - .then(|| MappedArguments::binding_indices(&self.params)) + .then(|| { + MappedArguments::binding_indices(&self.params, &self.parameter_scope, self.interner) + }) .unwrap_or_default(); let max_local_binding_register_index = diff --git a/core/engine/src/bytecompiler/statement/block.rs b/core/engine/src/bytecompiler/statement/block.rs index f4fa8bdb638..99da2023627 100644 --- a/core/engine/src/bytecompiler/statement/block.rs +++ b/core/engine/src/bytecompiler/statement/block.rs @@ -1,25 +1,12 @@ -use crate::{bytecompiler::ByteCompiler, vm::Opcode}; +use crate::bytecompiler::ByteCompiler; use boa_ast::statement::Block; impl ByteCompiler<'_> { /// Compile a [`Block`] `boa_ast` node pub(crate) fn compile_block(&mut self, block: &Block, use_expr: bool) { - let outer_scope = if let Some(scope) = block.scope() { - let outer_scope = self.lexical_scope.clone(); - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - Some(outer_scope) - } else { - None - }; - + let scope = self.push_declarative_scope(block.scope()); self.block_declaration_instantiation(block); self.compile_statement_list(block.statement_list(), use_expr, true); - - if let Some(outer_scope) = outer_scope { - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); - } + self.pop_declarative_scope(scope); } } diff --git a/core/engine/src/bytecompiler/statement/loop.rs b/core/engine/src/bytecompiler/statement/loop.rs index e0589efd7d9..b02c93bcc1f 100644 --- a/core/engine/src/bytecompiler/statement/loop.rs +++ b/core/engine/src/bytecompiler/statement/loop.rs @@ -22,6 +22,7 @@ impl ByteCompiler<'_> { use_expr: bool, ) { let mut let_binding_indices = None; + let mut outer_scope_local = None; let mut outer_scope = None; if let Some(init) = for_loop.init() { @@ -31,9 +32,16 @@ impl ByteCompiler<'_> { self.compile_var_decl(decl); } ForLoopInitializer::Lexical(decl) => { - outer_scope = Some(self.lexical_scope.clone()); - let scope_index = self.push_scope(decl.scope()); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); + let scope_index = if decl.scope().all_bindings_local() { + outer_scope_local = Some(self.lexical_scope.clone()); + self.lexical_scope = decl.scope().clone(); + None + } else { + outer_scope = Some(self.lexical_scope.clone()); + let scope_index = self.push_scope(decl.scope()); + self.emit_with_varying_operand(Opcode::PushScope, scope_index); + Some(scope_index) + }; let names = bound_names(decl.declaration()); if decl.declaration().is_const() { @@ -41,8 +49,8 @@ impl ByteCompiler<'_> { let mut indices = Vec::new(); for name in &names { let name = name.to_js_string(self.interner()); - let binding = self - .lexical_scope + let binding = decl + .scope() .get_binding_reference(&name) .expect("binding must exist"); let index = self.get_or_insert_binding(binding); @@ -62,8 +70,10 @@ impl ByteCompiler<'_> { self.emit_binding_access(Opcode::GetName, index); } - self.emit_opcode(Opcode::PopEnvironment); - self.emit_with_varying_operand(Opcode::PushScope, *scope_index); + if let Some(index) = scope_index { + self.emit_opcode(Opcode::PopEnvironment); + self.emit_with_varying_operand(Opcode::PushScope, *index); + } for index in let_binding_indices.iter().rev() { self.emit_binding_access(Opcode::PutLexicalValue, index); @@ -85,8 +95,10 @@ impl ByteCompiler<'_> { self.emit_binding_access(Opcode::GetName, index); } - self.emit_opcode(Opcode::PopEnvironment); - self.emit_with_varying_operand(Opcode::PushScope, *scope_index); + if let Some(index) = scope_index { + self.emit_opcode(Opcode::PopEnvironment); + self.emit_with_varying_operand(Opcode::PushScope, *index); + } for index in let_binding_indices.iter().rev() { self.emit_binding_access(Opcode::PutLexicalValue, index); @@ -115,11 +127,10 @@ impl ByteCompiler<'_> { self.patch_jump(exit); self.pop_loop_control_info(); - if let Some(outer_scope) = outer_scope { - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); + if let Some(outer_scope_local) = outer_scope_local { + self.lexical_scope = outer_scope_local; } + self.pop_declarative_scope(outer_scope); } pub(crate) fn compile_for_in_loop( @@ -138,17 +149,9 @@ impl ByteCompiler<'_> { } } } - if let Some(scope) = for_in_loop.target_scope() { - let outer_scope = self.lexical_scope.clone(); - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - self.compile_expr(for_in_loop.target(), true); - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); - } else { - self.compile_expr(for_in_loop.target(), true); - } + let outer_scope = self.push_declarative_scope(for_in_loop.target_scope()); + self.compile_expr(for_in_loop.target(), true); + self.pop_declarative_scope(outer_scope); let early_exit = self.jump_if_null_or_undefined(); self.emit_opcode(Opcode::CreateForInIterator); @@ -163,13 +166,7 @@ impl ByteCompiler<'_> { self.emit_opcode(Opcode::IteratorValue); - let mut outer_scope = None; - - if let Some(scope) = for_in_loop.scope() { - outer_scope = Some(self.lexical_scope.clone()); - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - } + let outer_scope = self.push_declarative_scope(for_in_loop.scope()); match for_in_loop.initializer() { IterableLoopInitializer::Identifier(ident) => { @@ -208,12 +205,7 @@ impl ByteCompiler<'_> { } self.compile_stmt(for_in_loop.body(), use_expr, true); - - if let Some(outer_scope) = outer_scope { - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); - } + self.pop_declarative_scope(outer_scope); self.emit(Opcode::Jump, &[Operand::U32(start_address)]); @@ -234,17 +226,9 @@ impl ByteCompiler<'_> { label: Option, use_expr: bool, ) { - if let Some(scope) = for_of_loop.iterable_scope() { - let outer_scope = self.lexical_scope.clone(); - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - self.compile_expr(for_of_loop.iterable(), true); - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); - } else { - self.compile_expr(for_of_loop.iterable(), true); - } + let outer_scope = self.push_declarative_scope(for_of_loop.iterable_scope()); + self.compile_expr(for_of_loop.iterable(), true); + self.pop_declarative_scope(outer_scope); if for_of_loop.r#await() { self.emit_opcode(Opcode::GetAsyncIterator); @@ -271,14 +255,7 @@ impl ByteCompiler<'_> { let exit = self.jump_if_true(); self.emit_opcode(Opcode::IteratorValue); - let mut outer_scope = None; - - if let Some(scope) = for_of_loop.scope() { - outer_scope = Some(self.lexical_scope.clone()); - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - } - + let outer_scope = self.push_declarative_scope(for_of_loop.scope()); let handler_index = self.push_handler(); match for_of_loop.initializer() { @@ -354,12 +331,7 @@ impl ByteCompiler<'_> { self.patch_jump(exit); } - if let Some(outer_scope) = outer_scope { - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); - } - + self.pop_declarative_scope(outer_scope); self.emit(Opcode::Jump, &[Operand::U32(start_address)]); self.patch_jump(exit); diff --git a/core/engine/src/bytecompiler/statement/switch.rs b/core/engine/src/bytecompiler/statement/switch.rs index d1bb4b8d38c..3a53d9cc39a 100644 --- a/core/engine/src/bytecompiler/statement/switch.rs +++ b/core/engine/src/bytecompiler/statement/switch.rs @@ -5,15 +5,7 @@ impl ByteCompiler<'_> { /// Compile a [`Switch`] `boa_ast` node pub(crate) fn compile_switch(&mut self, switch: &Switch, use_expr: bool) { self.compile_expr(switch.val(), true); - - let outer_scope = if let Some(scope) = switch.scope() { - let outer_scope = self.lexical_scope.clone(); - let scope_index = self.push_scope(scope); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); - Some(outer_scope) - } else { - None - }; + let outer_scope = self.push_declarative_scope(switch.scope()); self.block_declaration_instantiation(switch); @@ -55,11 +47,6 @@ impl ByteCompiler<'_> { } self.pop_switch_control_info(); - - if let Some(outer_scope) = outer_scope { - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); - } + self.pop_declarative_scope(outer_scope); } } diff --git a/core/engine/src/bytecompiler/statement/try.rs b/core/engine/src/bytecompiler/statement/try.rs index ad0b626c5ad..98073bdf320 100644 --- a/core/engine/src/bytecompiler/statement/try.rs +++ b/core/engine/src/bytecompiler/statement/try.rs @@ -108,11 +108,7 @@ impl ByteCompiler<'_> { } pub(crate) fn compile_catch_stmt(&mut self, catch: &Catch, _has_finally: bool, use_expr: bool) { - // stack: exception - - let outer_scope = self.lexical_scope.clone(); - let scope_index = self.push_scope(catch.scope()); - self.emit_with_varying_operand(Opcode::PushScope, scope_index); + let outer_scope = self.push_declarative_scope(Some(catch.scope())); if let Some(binding) = catch.parameter() { match binding { @@ -130,9 +126,7 @@ impl ByteCompiler<'_> { self.compile_catch_finally_block(catch.block(), use_expr); - self.pop_scope(); - self.lexical_scope = outer_scope; - self.emit_opcode(Opcode::PopEnvironment); + self.pop_declarative_scope(outer_scope); } pub(crate) fn compile_finally_stmt(&mut self, finally: &Finally, has_catch: bool) { diff --git a/core/engine/src/environments/runtime/mod.rs b/core/engine/src/environments/runtime/mod.rs index ba2a03dda5f..4dce94a9f89 100644 --- a/core/engine/src/environments/runtime/mod.rs +++ b/core/engine/src/environments/runtime/mod.rs @@ -186,7 +186,7 @@ impl EnvironmentStack { /// Push a function environment on the environments stack. pub(crate) fn push_function(&mut self, scope: Scope, function_slots: FunctionSlots) { - let num_bindings = scope.num_bindings(); + let num_bindings = scope.num_bindings_non_local(); let (poisoned, with) = { // Check if the outer environment is a declarative environment. @@ -214,7 +214,7 @@ impl EnvironmentStack { /// Push a module environment on the environments stack. pub(crate) fn push_module(&mut self, scope: Scope) { - let num_bindings = scope.num_bindings(); + let num_bindings = scope.num_bindings_non_local(); self.stack.push(Environment::Declarative(Gc::new( DeclarativeEnvironment::new(DeclarativeEnvironmentKind::Module( ModuleEnvironment::new(num_bindings, scope), diff --git a/core/engine/src/module/synthetic.rs b/core/engine/src/module/synthetic.rs index 5e8309e0b6c..99e8f278264 100644 --- a/core/engine/src/module/synthetic.rs +++ b/core/engine/src/module/synthetic.rs @@ -307,6 +307,8 @@ impl SyntheticModule { }) .collect::>(); + module_scope.escape_all_bindings(); + let cb = Gc::new(compiler.finish()); let mut envs = EnvironmentStack::new(global_env); diff --git a/core/engine/src/vm/code_block.rs b/core/engine/src/vm/code_block.rs index 6c461b1b21a..dd44daf1e8e 100644 --- a/core/engine/src/vm/code_block.rs +++ b/core/engine/src/vm/code_block.rs @@ -66,6 +66,9 @@ bitflags! { /// Arrow and method functions don't have `"prototype"` property. const HAS_PROTOTYPE_PROPERTY = 0b1000_0000; + /// If the function requires a function scope. + const HAS_FUNCTION_SCOPE = 0b1_0000_0000; + /// Trace instruction execution to `stdout`. #[cfg(feature = "trace")] const TRACEABLE = 0b1000_0000_0000_0000; @@ -271,6 +274,13 @@ impl CodeBlock { .contains(CodeBlockFlags::HAS_PROTOTYPE_PROPERTY) } + /// Returns true if this function requires a function scope. + pub(crate) fn has_function_scope(&self) -> bool { + self.flags + .get() + .contains(CodeBlockFlags::HAS_FUNCTION_SCOPE) + } + /// Find exception [`Handler`] in the code block given the current program counter (`pc`). #[inline] pub(crate) fn find_handler(&self, pc: u32) -> Option<(usize, &Handler)> { diff --git a/core/engine/src/vm/opcode/push/environment.rs b/core/engine/src/vm/opcode/push/environment.rs index cfd66eca846..81fb983569b 100644 --- a/core/engine/src/vm/opcode/push/environment.rs +++ b/core/engine/src/vm/opcode/push/environment.rs @@ -17,7 +17,10 @@ impl PushScope { #[allow(clippy::unnecessary_wraps)] fn operation(context: &mut Context, index: usize) -> JsResult { let scope = context.vm.frame().code_block().constant_scope(index); - context.vm.environments.push_lexical(scope.num_bindings()); + context + .vm + .environments + .push_lexical(scope.num_bindings_non_local()); Ok(CompletionType::Normal) } } From 20fe60fcc6b2c738a13d9f42a125b1ec58b06ae2 Mon Sep 17 00:00:00 2001 From: Jason Williams <936006+jasonwilliams@users.noreply.github.com> Date: Thu, 5 Dec 2024 00:13:59 +0000 Subject: [PATCH 39/72] update changelog and bump versions for release (#4064) --- CHANGELOG.md | 3 ++- Cargo.lock | 34 +++++++++++++++++----------------- Cargo.toml | 24 ++++++++++++------------ 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74306691937..3d75c8e7bc6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## What's Changed -# [0.20.0 (2024-09-11)](https://github.com/boa-dev/boa/compare/v0.19.1...v0.20.0) +# [0.20.0 (2024-12-5)](https://github.com/boa-dev/boa/compare/v0.19.1...v0.20.0) ### Feature Enhancements @@ -61,6 +61,7 @@ - Update night build's rename binary step by @nekevss in https://github.com/boa-dev/boa/pull/4032 - Use upload-rust-binary-action for nightly release by @nekevss in https://github.com/boa-dev/boa/pull/4040 - Fix `ref` value in nightly and add target to nightly release by @nekevss in https://github.com/boa-dev/boa/pull/4042 +- Reduce environment allocations by @raskad in https://github.com/boa-dev/boa/pull/4002 ### Other Changes diff --git a/Cargo.lock b/Cargo.lock index fb353c822b1..2de2a9dfadc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -314,7 +314,7 @@ dependencies = [ [[package]] name = "boa_ast" -version = "0.19.0" +version = "0.20.0" dependencies = [ "arbitrary", "bitflags 2.6.0", @@ -329,7 +329,7 @@ dependencies = [ [[package]] name = "boa_cli" -version = "0.19.0" +version = "0.20.0" dependencies = [ "boa_engine", "boa_gc", @@ -348,7 +348,7 @@ dependencies = [ [[package]] name = "boa_engine" -version = "0.19.0" +version = "0.20.0" dependencies = [ "arrayvec", "bitflags 2.6.0", @@ -419,7 +419,7 @@ dependencies = [ [[package]] name = "boa_examples" -version = "0.19.0" +version = "0.20.0" dependencies = [ "boa_ast", "boa_engine", @@ -435,7 +435,7 @@ dependencies = [ [[package]] name = "boa_gc" -version = "0.19.0" +version = "0.20.0" dependencies = [ "boa_macros", "boa_profiler", @@ -447,7 +447,7 @@ dependencies = [ [[package]] name = "boa_icu_provider" -version = "0.19.0" +version = "0.20.0" dependencies = [ "icu_casemap", "icu_collator", @@ -467,7 +467,7 @@ dependencies = [ [[package]] name = "boa_interner" -version = "0.19.0" +version = "0.20.0" dependencies = [ "arbitrary", "boa_gc", @@ -483,7 +483,7 @@ dependencies = [ [[package]] name = "boa_interop" -version = "0.19.0" +version = "0.20.0" dependencies = [ "boa_engine", "boa_gc", @@ -493,7 +493,7 @@ dependencies = [ [[package]] name = "boa_macros" -version = "0.19.0" +version = "0.20.0" dependencies = [ "proc-macro2", "quote", @@ -503,7 +503,7 @@ dependencies = [ [[package]] name = "boa_macros_tests" -version = "0.19.0" +version = "0.20.0" dependencies = [ "boa_engine", "trybuild", @@ -511,7 +511,7 @@ dependencies = [ [[package]] name = "boa_parser" -version = "0.19.0" +version = "0.20.0" dependencies = [ "bitflags 2.6.0", "boa_ast", @@ -528,7 +528,7 @@ dependencies = [ [[package]] name = "boa_profiler" -version = "0.19.0" +version = "0.20.0" dependencies = [ "measureme", "once_cell", @@ -537,7 +537,7 @@ dependencies = [ [[package]] name = "boa_runtime" -version = "0.19.0" +version = "0.20.0" dependencies = [ "boa_engine", "boa_gc", @@ -550,7 +550,7 @@ dependencies = [ [[package]] name = "boa_string" -version = "0.19.0" +version = "0.20.0" dependencies = [ "fast-float2", "paste", @@ -561,7 +561,7 @@ dependencies = [ [[package]] name = "boa_tester" -version = "0.19.0" +version = "0.20.0" dependencies = [ "bitflags 2.6.0", "boa_engine", @@ -584,7 +584,7 @@ dependencies = [ [[package]] name = "boa_wasm" -version = "0.19.0" +version = "0.20.0" dependencies = [ "boa_engine", "console_error_panic_hook", @@ -1386,7 +1386,7 @@ dependencies = [ [[package]] name = "gen-icu4x-data" -version = "0.19.0" +version = "0.20.0" dependencies = [ "icu_casemap", "icu_collator", diff --git a/Cargo.toml b/Cargo.toml index 21a34ab6dc3..73ad8aa8c53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ exclude = [ [workspace.package] edition = "2021" -version = "0.19.0" +version = "0.20.0" rust-version = "1.82.0" authors = ["boa-dev"] repository = "https://github.com/boa-dev/boa" @@ -33,17 +33,17 @@ description = "Boa is a Javascript lexer, parser and compiler written in Rust. C [workspace.dependencies] # Repo Crates -boa_ast = { version = "~0.19.0", path = "core/ast" } -boa_engine = { version = "~0.19.0", path = "core/engine" } -boa_gc = { version = "~0.19.0", path = "core/gc" } -boa_icu_provider = { version = "~0.19.0", path = "core/icu_provider" } -boa_interner = { version = "~0.19.0", path = "core/interner" } -boa_interop = { version = "~0.19.0", path = "core/interop" } -boa_macros = { version = "~0.19.0", path = "core/macros" } -boa_parser = { version = "~0.19.0", path = "core/parser" } -boa_profiler = { version = "~0.19.0", path = "core/profiler" } -boa_runtime = { version = "~0.19.0", path = "core/runtime" } -boa_string = { version = "~0.19.0", path = "core/string" } +boa_ast = { version = "~0.20.0", path = "core/ast" } +boa_engine = { version = "~0.20.0", path = "core/engine" } +boa_gc = { version = "~0.20.0", path = "core/gc" } +boa_icu_provider = { version = "~0.20.0", path = "core/icu_provider" } +boa_interner = { version = "~0.20.0", path = "core/interner" } +boa_interop = { version = "~0.20.0", path = "core/interop" } +boa_macros = { version = "~0.20.0", path = "core/macros" } +boa_parser = { version = "~0.20.0", path = "core/parser" } +boa_profiler = { version = "~0.20.0", path = "core/profiler" } +boa_runtime = { version = "~0.20.0", path = "core/runtime" } +boa_string = { version = "~0.20.0", path = "core/string" } # Shared deps arbitrary = "1" From b345775138f56401bd627b1f36daadfc5bf75772 Mon Sep 17 00:00:00 2001 From: Jason Williams <936006+jasonwilliams@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:16:41 +0000 Subject: [PATCH 40/72] update Boa to be inline with Temporal (#4034) * update Boa to be inline with Temporal * use TinyAsciiStr * tidyup * updates MonthDay * remove commented code * use intoOrUndefined * add documentation to macros tests * use tinyasciiistr from temporal * patch update_temporal per discussion + version 0.0.4 bump changes --------- Co-authored-by: Kevin Ness <46825870+nekevss@users.noreply.github.com> --- Cargo.lock | 54 ++++++- Cargo.toml | 2 +- .../src/builtins/temporal/calendar/mod.rs | 2 +- .../src/builtins/temporal/duration/mod.rs | 3 +- .../src/builtins/temporal/instant/mod.rs | 34 ++--- core/engine/src/builtins/temporal/mod.rs | 5 +- core/engine/src/builtins/temporal/now.rs | 2 +- core/engine/src/builtins/temporal/options.rs | 4 +- .../src/builtins/temporal/plain_date/mod.rs | 132 +++++++++++------- .../builtins/temporal/plain_date_time/mod.rs | 32 ++--- .../builtins/temporal/plain_month_day/mod.rs | 108 +++++++++----- .../src/builtins/temporal/plain_time/mod.rs | 30 ++-- .../builtins/temporal/plain_year_month/mod.rs | 26 +--- .../builtins/temporal/zoned_date_time/mod.rs | 2 +- 14 files changed, 258 insertions(+), 178 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2de2a9dfadc..c3feb302480 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,6 +50,15 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anes" version = "0.1.6" @@ -873,6 +882,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "core_maths" version = "0.1.0" @@ -1487,6 +1502,29 @@ dependencies = [ "itoa", ] +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu" version = "1.5.0" @@ -3291,13 +3329,14 @@ checksum = "42a4d50cdb458045afc8131fd91b64904da29548bcb63c7236e0844936c13078" [[package]] name = "temporal_rs" -version = "0.0.3" -source = "git+https://github.com/boa-dev/temporal.git?rev=1e7901d07a83211e62373ab94284a7d1ada4c913#1e7901d07a83211e62373ab94284a7d1ada4c913" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abc1a6b736bd71cd492b8810334efff905c4a09787a46e9a0ddd54b46a2f4e08" dependencies = [ "bitflags 2.6.0", + "iana-time-zone", "icu_calendar", "ixdtf", - "num-bigint", "num-traits", "rustc-hash 2.1.0", "tinystr", @@ -3928,6 +3967,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 73ad8aa8c53..9f8af784096 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,7 +111,7 @@ intrusive-collections = "0.9.7" cfg-if = "1.0.0" either = "1.13.0" sys-locale = "0.3.2" -temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "1e7901d07a83211e62373ab94284a7d1ada4c913" } +temporal_rs = "0.0.4" web-time = "1.1.0" criterion = "0.5.1" float-cmp = "0.10.0" diff --git a/core/engine/src/builtins/temporal/calendar/mod.rs b/core/engine/src/builtins/temporal/calendar/mod.rs index 665daee341f..04ff76f1310 100644 --- a/core/engine/src/builtins/temporal/calendar/mod.rs +++ b/core/engine/src/builtins/temporal/calendar/mod.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use super::extract_from_temporal_type; use crate::{js_string, Context, JsNativeError, JsObject, JsResult, JsValue}; -use temporal_rs::components::calendar::Calendar; +use temporal_rs::Calendar; // -- `Calendar` Abstract Operations -- diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index 30f053f00ea..379e4f33100 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -16,9 +16,10 @@ use crate::{ use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ - components::{duration::PartialDuration, Duration as InnerDuration}, options::{RelativeTo, RoundingIncrement, RoundingOptions, TemporalRoundingMode, TemporalUnit}, + partial::PartialDuration, primitive::FiniteF64, + Duration as InnerDuration, }; use super::{ diff --git a/core/engine/src/builtins/temporal/instant/mod.rs b/core/engine/src/builtins/temporal/instant/mod.rs index a5746555325..6e8d3b22d54 100644 --- a/core/engine/src/builtins/temporal/instant/mod.rs +++ b/core/engine/src/builtins/temporal/instant/mod.rs @@ -24,8 +24,8 @@ use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use num_traits::ToPrimitive; use temporal_rs::{ - components::Instant as InnerInstant, options::{RoundingIncrement, RoundingOptions, TemporalRoundingMode}, + Instant as InnerInstant, }; use super::options::get_difference_settings; @@ -46,19 +46,19 @@ impl IntrinsicObject for Instant { fn init(realm: &Realm) { let _timer = Profiler::global().start_event(std::any::type_name::(), "init"); - let get_seconds = BuiltInBuilder::callable(realm, Self::get_epoc_seconds) + let get_seconds = BuiltInBuilder::callable(realm, Self::get_epoch_seconds) .name(js_string!("get epochSeconds")) .build(); - let get_millis = BuiltInBuilder::callable(realm, Self::get_epoc_milliseconds) + let get_millis = BuiltInBuilder::callable(realm, Self::get_epoch_milliseconds) .name(js_string!("get epochMilliseconds")) .build(); - let get_micros = BuiltInBuilder::callable(realm, Self::get_epoc_microseconds) + let get_micros = BuiltInBuilder::callable(realm, Self::get_epoch_microseconds) .name(js_string!("get epochMicroseconds")) .build(); - let get_nanos = BuiltInBuilder::callable(realm, Self::get_epoc_nanoseconds) + let get_nanos = BuiltInBuilder::callable(realm, Self::get_epoch_nanoseconds) .name(js_string!("get epochNanoseconds")) .build(); @@ -150,7 +150,7 @@ impl BuiltInConstructor for Instant { // 3. If ! IsValidEpochNanoseconds(epochNanoseconds) is false, throw a RangeError exception. // NOTE: temporal_rs::Instant asserts that the epochNanoseconds are valid. - let instant = InnerInstant::new(epoch_nanos.as_inner().to_i128().unwrap_or(i128::MAX))?; + let instant = InnerInstant::try_new(epoch_nanos.as_inner().to_i128().unwrap_or(i128::MAX))?; // 4. Return ? CreateTemporalInstant(epochNanoseconds, NewTarget). create_temporal_instant(instant, Some(new_target.clone()), context) } @@ -201,7 +201,7 @@ impl Instant { // 3. Return ! CreateTemporalInstant(epochNanoseconds). let nanos = epoch_nanos.as_inner().to_i128(); create_temporal_instant( - InnerInstant::new(nanos.unwrap_or(i128::MAX))?, + InnerInstant::try_new(nanos.unwrap_or(i128::MAX))?, None, context, ) @@ -226,7 +226,7 @@ impl Instant { impl Instant { /// 8.3.3 get Temporal.Instant.prototype.epochSeconds - pub(crate) fn get_epoc_seconds( + pub(crate) fn get_epoch_seconds( this: &JsValue, _: &[JsValue], _: &mut Context, @@ -240,11 +240,11 @@ impl Instant { JsNativeError::typ().with_message("the this object must be an instant object.") })?; // 3. Let ns be instant.[[Nanoseconds]]. - Ok(instant.inner.epoch_seconds().into()) + Ok(JsBigInt::from(instant.inner.epoch_seconds()).into()) } /// 8.3.4 get Temporal.Instant.prototype.epochMilliseconds - pub(crate) fn get_epoc_milliseconds( + pub(crate) fn get_epoch_milliseconds( this: &JsValue, _: &[JsValue], _: &mut Context, @@ -260,11 +260,11 @@ impl Instant { // 3. Let ns be instant.[[Nanoseconds]]. // 4. Let ms be floor(ℝ(ns) / 106). // 5. Return 𝔽(ms). - Ok(instant.inner.epoch_milliseconds().into()) + Ok(JsBigInt::from(instant.inner.epoch_milliseconds()).into()) } /// 8.3.5 get Temporal.Instant.prototype.epochMicroseconds - pub(crate) fn get_epoc_microseconds( + pub(crate) fn get_epoch_microseconds( this: &JsValue, _: &[JsValue], _: &mut Context, @@ -280,13 +280,11 @@ impl Instant { // 3. Let ns be instant.[[Nanoseconds]]. // 4. Let µs be floor(ℝ(ns) / 103). // 5. Return ℤ(µs). - let big_int = JsBigInt::try_from(instant.inner.epoch_microseconds()) - .expect("valid microseconds is in range of BigInt"); - Ok(big_int.into()) + Ok(JsBigInt::from(instant.inner.epoch_microseconds()).into()) } /// 8.3.6 get Temporal.Instant.prototype.epochNanoseconds - pub(crate) fn get_epoc_nanoseconds( + pub(crate) fn get_epoch_nanoseconds( this: &JsValue, _: &[JsValue], _: &mut Context, @@ -301,9 +299,7 @@ impl Instant { })?; // 3. Let ns be instant.[[Nanoseconds]]. // 4. Return ns. - let big_int = JsBigInt::try_from(instant.inner.epoch_nanoseconds()) - .expect("valid nanoseconds is in range of BigInt"); - Ok(big_int.into()) + Ok(JsBigInt::from(instant.inner.epoch_nanoseconds()).into()) } /// 8.3.7 `Temporal.Instant.prototype.add ( temporalDurationLike )` diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index 5ef37ebca61..3dcef45942f 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -37,10 +37,7 @@ use crate::{ Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; -use temporal_rs::{ - components::{Date as TemporalDate, ZonedDateTime as TemporalZonedDateTime}, - NS_PER_DAY, -}; +use temporal_rs::{PlainDate as TemporalDate, ZonedDateTime as TemporalZonedDateTime, NS_PER_DAY}; // TODO: Remove in favor of `temporal_rs` pub(crate) fn ns_max_instant() -> JsBigInt { diff --git a/core/engine/src/builtins/temporal/now.rs b/core/engine/src/builtins/temporal/now.rs index 45da161bc26..d0e9f4caef4 100644 --- a/core/engine/src/builtins/temporal/now.rs +++ b/core/engine/src/builtins/temporal/now.rs @@ -11,7 +11,7 @@ use crate::{ Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; -use temporal_rs::components::tz::TimeZone; +use temporal_rs::TimeZone; use super::{ns_max_instant, ns_min_instant, time_zone::default_time_zone}; diff --git a/core/engine/src/builtins/temporal/options.rs b/core/engine/src/builtins/temporal/options.rs index 0d369ff776e..46883c52eeb 100644 --- a/core/engine/src/builtins/temporal/options.rs +++ b/core/engine/src/builtins/temporal/options.rs @@ -13,7 +13,7 @@ use crate::{ js_string, Context, JsNativeError, JsObject, JsResult, JsString, JsValue, }; use temporal_rs::options::{ - ArithmeticOverflow, CalendarName, DifferenceSettings, DurationOverflow, InstantDisambiguation, + ArithmeticOverflow, CalendarName, DifferenceSettings, Disambiguation, DurationOverflow, OffsetDisambiguation, RoundingIncrement, TemporalRoundingMode, TemporalUnit, }; @@ -113,7 +113,7 @@ fn datetime_units() -> impl Iterator { impl ParsableOptionType for TemporalUnit {} impl ParsableOptionType for ArithmeticOverflow {} impl ParsableOptionType for DurationOverflow {} -impl ParsableOptionType for InstantDisambiguation {} +impl ParsableOptionType for Disambiguation {} impl ParsableOptionType for OffsetDisambiguation {} impl ParsableOptionType for TemporalRoundingMode {} impl ParsableOptionType for CalendarName {} diff --git a/core/engine/src/builtins/temporal/plain_date/mod.rs b/core/engine/src/builtins/temporal/plain_date/mod.rs index f85cb56036f..c3f2b43789b 100644 --- a/core/engine/src/builtins/temporal/plain_date/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date/mod.rs @@ -3,8 +3,6 @@ // TODO (nekevss): DOCS DOCS AND MORE DOCS -use std::str::FromStr; - use crate::{ builtins::{ options::{get_option, get_options_object}, @@ -16,19 +14,15 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, + value::IntoOrUndefined, Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ - components::{ - calendar::{Calendar, GetTemporalCalendar}, - Date as InnerDate, DateTime, MonthCode, PartialDate, - }, - iso::IsoDateSlots, - options::ArithmeticOverflow, - TemporalFields, TinyAsciiStr, + options::ArithmeticOverflow, partial::PartialDate, Calendar, PlainDate as InnerDate, + TinyAsciiStr, }; use super::{ @@ -51,18 +45,6 @@ impl PlainDate { } } -impl IsoDateSlots for JsObject { - fn iso_date(&self) -> temporal_rs::iso::IsoDate { - self.borrow().data().inner.iso_date() - } -} - -impl GetTemporalCalendar for JsObject { - fn get_calendar(&self) -> Calendar { - self.borrow().data().inner.get_calendar() - } -} - impl BuiltInObject for PlainDate { const NAME: JsString = StaticJsStrings::PLAIN_DATE_NAME; } @@ -262,15 +244,15 @@ impl BuiltInConstructor for PlainDate { let iso_day = super::to_integer_with_truncation(args.get_or_undefined(2), context)?; let calendar_slot = to_temporal_calendar_slot_value(args.get_or_undefined(3))?; - let date = InnerDate::new( + Ok(create_temporal_date( iso_year, iso_month, iso_day, calendar_slot, - ArithmeticOverflow::Reject, - )?; - - Ok(create_temporal_date(date, Some(new_target), context)?.into()) + Some(new_target), + context, + )? + .into()) } } @@ -391,7 +373,7 @@ impl PlainDate { .into()); }; - Ok(date.inner.week_of_year()?.into()) + Ok(date.inner.week_of_year()?.into_or_undefined()) } /// 3.3.11 get `Temporal.PlainDate.prototype.yearOfWeek` @@ -406,7 +388,7 @@ impl PlainDate { .into()); }; - Ok(date.inner.year_of_week()?.into()) + Ok(date.inner.year_of_week()?.into_or_undefined()) } /// 3.3.12 get `Temporal.PlainDate.prototype.daysInWeek` @@ -504,11 +486,23 @@ impl PlainDate { if let Some(date) = item.as_object().and_then(JsObject::downcast_ref::) { let options = get_options_object(options.unwrap_or(&JsValue::undefined()))?; let _ = get_option::(&options, js_string!("overflow"), context)?; - return create_temporal_date(date.inner.clone(), None, context).map(Into::into); + return create_temporal_date( + date.inner.iso_year(), + date.inner.iso_month().into(), + date.inner.iso_day().into(), + date.inner.calendar().clone(), + None, + context, + ) + .map(Into::into); } + let resolved_date = to_temporal_date(item, options.cloned(), context)?; create_temporal_date( - to_temporal_date(item, options.cloned(), context)?, + resolved_date.iso_year(), + resolved_date.iso_month().into(), + resolved_date.iso_day().into(), + resolved_date.calendar().clone(), None, context, ) @@ -600,7 +594,16 @@ impl PlainDate { // 5. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 6. Return ? AddDate(calendarRec, temporalDate, duration, options). - create_temporal_date(date.inner.add(&duration, overflow)?, None, context).map(Into::into) + let resolved_date = date.inner.add(&duration, overflow)?; + create_temporal_date( + resolved_date.iso_year(), + resolved_date.iso_month().into(), + resolved_date.iso_day().into(), + resolved_date.calendar().clone(), + None, + context, + ) + .map(Into::into) } fn subtract(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { @@ -623,8 +626,16 @@ impl PlainDate { // 5. Let negatedDuration be CreateNegatedTemporalDuration(duration). // 6. Let calendarRec be ? CreateCalendarMethodsRecord(temporalDate.[[Calendar]], « date-add »). // 7. Return ? AddDate(calendarRec, temporalDate, negatedDuration, options). - create_temporal_date(date.inner.subtract(&duration, overflow)?, None, context) - .map(Into::into) + let resolved_date = date.inner.subtract(&duration, overflow)?; + create_temporal_date( + resolved_date.iso_year(), + resolved_date.iso_month().into(), + resolved_date.iso_day().into(), + resolved_date.calendar().clone(), + None, + context, + ) + .map(Into::into) } // 3.3.24 Temporal.PlainDate.prototype.with ( temporalDateLike [ , options ] ) @@ -659,7 +670,16 @@ impl PlainDate { let partial = to_partial_date_record(partial_object, context)?; // 10. Return ? CalendarDateFromFields(calendarRec, fields, resolvedOptions). - create_temporal_date(date.inner.with(partial, overflow)?, None, context).map(Into::into) + let resolved_date = date.inner.with(partial, overflow)?; + create_temporal_date( + resolved_date.iso_year(), + resolved_date.iso_month().into(), + resolved_date.iso_day().into(), + resolved_date.calendar().clone(), + None, + context, + ) + .map(Into::into) } /// 3.3.26 Temporal.PlainDate.prototype.withCalendar ( calendarLike ) @@ -672,8 +692,16 @@ impl PlainDate { })?; let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(0))?; - - create_temporal_date(date.inner.with_calendar(calendar)?, None, context).map(Into::into) + let resolved_date = date.inner.with_calendar(calendar)?; + create_temporal_date( + resolved_date.iso_year(), + resolved_date.iso_month().into(), + resolved_date.iso_day().into(), + resolved_date.calendar().clone(), + None, + context, + ) + .map(Into::into) } fn until(this: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult { @@ -757,7 +785,14 @@ impl PlainDate { impl PlainDate { /// Utitily function for translating a `Temporal.PlainDate` into a `JsObject`. pub(crate) fn as_object(&self, context: &mut Context) -> JsResult { - create_temporal_date(self.inner.clone(), None, context) + create_temporal_date( + self.inner.iso_year(), + self.inner.iso_month().into(), + self.inner.iso_day().into(), + self.inner.calendar().clone(), + None, + context, + ) } } @@ -766,19 +801,16 @@ impl PlainDate { /// 3.5.3 `CreateTemporalDate ( isoYear, isoMonth, isoDay, calendar [ , newTarget ] )` pub(crate) fn create_temporal_date( - inner: InnerDate, + iso_year: i32, + iso_month: i32, + iso_day: i32, + calendar_slot: Calendar, new_target: Option<&JsValue>, context: &mut Context, ) -> JsResult { - // NOTE (nekevss): The below should never trigger as `IsValidISODate` is enforced by Date. // 1. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception. - // 2. If ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0) is false, throw a RangeError exception. - if !DateTime::validate(&inner) { - return Err(JsNativeError::range() - .with_message("Date is not within ISO date time limits.") - .into()); - } + let inner = InnerDate::try_new(iso_year, iso_month, iso_day, calendar_slot)?; // 3. If newTarget is not present, set newTarget to %Temporal.PlainDate%. let new_target = if let Some(new_target) = new_target { @@ -843,7 +875,7 @@ pub(crate) fn to_temporal_date( let _o = get_option(&options_obj, js_string!("overflow"), context)? .unwrap_or(ArithmeticOverflow::Constrain); - let date = InnerDate::from(date_time.inner().clone()); + let date = InnerDate::from(date_time.inner.clone()); // ii. Return ! CreateTemporalDate(item.[[ISOYear]], item.[[ISOMonth]], item.[[ISODay]], item.[[Calendar]]). return Ok(date); @@ -867,11 +899,10 @@ pub(crate) fn to_temporal_date( .with_message("A partial date must have at least one defined field.") .into()); } - let mut fields = TemporalFields::from(partial); // g. Return ? CalendarDateFromFields(calendar, fields, options). return calendar - .date_from_fields(&mut fields, overflow) + .date_from_partial(&partial, overflow) .map_err(Into::into); } @@ -920,7 +951,8 @@ pub(crate) fn to_partial_date_record( .with_message("The monthCode field value must be a string.") .into()); }; - MonthCode::from_str(&month_code.to_std_string_escaped()).map_err(Into::::into) + TinyAsciiStr::<4>::from_str(&month_code.to_std_string_escaped()) + .map_err(|e| JsError::from(JsNativeError::typ().with_message(e.to_string()))) }) .transpose()?; let year = partial_object @@ -943,7 +975,7 @@ pub(crate) fn to_partial_date_record( )); }; // TODO: double check if an invalid monthCode is a range or type error. - TinyAsciiStr::<16>::from_str(&era.to_std_string_escaped()) + TinyAsciiStr::<19>::from_str(&era.to_std_string_escaped()) .map_err(|e| JsError::from(JsNativeError::range().with_message(e.to_string()))) }) .transpose()?; diff --git a/core/engine/src/builtins/temporal/plain_date_time/mod.rs b/core/engine/src/builtins/temporal/plain_date_time/mod.rs index b8f965d6c78..18cb14c3e56 100644 --- a/core/engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date_time/mod.rs @@ -13,6 +13,7 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, + value::IntoOrUndefined, Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_gc::{Finalize, Trace}; @@ -22,13 +23,9 @@ use boa_profiler::Profiler; mod tests; use temporal_rs::{ - components::{ - calendar::{Calendar, GetTemporalCalendar}, - DateTime as InnerDateTime, PartialDateTime, Time, - }, - iso::{IsoDate, IsoDateSlots}, options::{ArithmeticOverflow, RoundingIncrement, RoundingOptions, TemporalRoundingMode}, - TemporalFields, + partial::PartialDateTime, + PlainDateTime as InnerDateTime, PlainTime, }; use super::{ @@ -55,18 +52,6 @@ impl PlainDateTime { } } -impl IsoDateSlots for JsObject { - fn iso_date(&self) -> IsoDate { - self.borrow().data().inner.iso_date() - } -} - -impl GetTemporalCalendar for JsObject { - fn get_calendar(&self) -> Calendar { - self.borrow().data().inner.get_calendar() - } -} - impl BuiltInObject for PlainDateTime { const NAME: JsString = StaticJsStrings::PLAIN_DATETIME_NAME; } @@ -558,7 +543,7 @@ impl PlainDateTime { JsNativeError::typ().with_message("the this object must be a PlainDateTime object.") })?; - Ok(dt.inner.week_of_year()?.into()) + Ok(dt.inner.week_of_year()?.into_or_undefined()) } /// 5.3.17 get `Temporal.PlainDatedt.prototype.yearOfWeek` @@ -570,7 +555,7 @@ impl PlainDateTime { JsNativeError::typ().with_message("the this object must be a PlainDateTime object.") })?; - Ok(dt.inner.year_of_week()?.into()) + Ok(dt.inner.year_of_week()?.into_or_undefined()) } /// 5.3.18 get `Temporal.PlainDatedt.prototype.daysInWeek` @@ -1034,18 +1019,17 @@ pub(crate) fn to_temporal_datetime( } // g. Let result be ? InterpretTemporalDateTimeFields(calendarRec, fields, resolvedOptions). let overflow = get_option::(&options, js_string!("overflow"), context)?; - let date = calendar.date_from_fields( - &mut TemporalFields::from(partial_date), + let date = calendar.date_from_partial( + &partial_date, overflow.unwrap_or(ArithmeticOverflow::Constrain), )?; - let time = Time::new( + let time = PlainTime::new( partial_time.hour.unwrap_or(0), partial_time.minute.unwrap_or(0), partial_time.second.unwrap_or(0), partial_time.millisecond.unwrap_or(0), partial_time.microsecond.unwrap_or(0), partial_time.nanosecond.unwrap_or(0), - ArithmeticOverflow::Constrain, )?; return InnerDateTime::new( diff --git a/core/engine/src/builtins/temporal/plain_month_day/mod.rs b/core/engine/src/builtins/temporal/plain_month_day/mod.rs index 8eace7d6d90..c2dce5b9d9e 100644 --- a/core/engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/core/engine/src/builtins/temporal/plain_month_day/mod.rs @@ -13,18 +13,16 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ - components::{ - calendar::{Calendar, GetTemporalCalendar}, - DateTime, MonthDay as InnerMonthDay, - }, - iso::IsoDateSlots, options::{ArithmeticOverflow, CalendarName}, + partial::PartialDate, + PlainDateTime, PlainMonthDay as InnerMonthDay, TinyAsciiStr, }; use super::{calendar::to_temporal_calendar_slot_value, DateTimeValues}; @@ -118,17 +116,6 @@ impl PlainMonthDay { Ok(month_day_to_string(inner, show_calendar)) } } -impl IsoDateSlots for JsObject { - fn iso_date(&self) -> temporal_rs::iso::IsoDate { - self.borrow().data().inner.iso_date() - } -} - -impl GetTemporalCalendar for JsObject { - fn get_calendar(&self) -> Calendar { - self.borrow().data().inner.get_calendar() - } -} impl BuiltInObject for PlainMonthDay { const NAME: JsString = StaticJsStrings::PLAIN_MD_NAME; @@ -196,9 +183,33 @@ impl BuiltInConstructor for PlainMonthDay { args: &[JsValue], context: &mut Context, ) -> JsResult { - Err(JsNativeError::range() - .with_message("Not yet implemented.") - .into()) + // 1. If NewTarget is undefined, then + if new_target.is_undefined() { + // a. Throw a TypeError exception. + return Err(JsNativeError::typ() + .with_message("NewTarget cannot be undefined when constructing a PlainYearMonth.") + .into()); + } + + let year = args.get_or_undefined(3); + let ref_year = if year.is_undefined() { + None + } else { + Some(super::to_integer_with_truncation(year, context)?) + }; + + // We can ignore 2 as the underlying temporal library handles the reference year + let m = super::to_integer_with_truncation(args.get_or_undefined(0), context)?; + let d = super::to_integer_with_truncation(args.get_or_undefined(1), context)?; + let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(2))?; + let inner = InnerMonthDay::new_with_overflow( + m, + d, + calendar, + ArithmeticOverflow::Constrain, + ref_year, + )?; + create_temporal_month_day(inner, Some(new_target), context) } } @@ -214,6 +225,7 @@ fn month_day_to_string(inner: &InnerMonthDay, show_calendar: CalendarName) -> Js // 3. Let result be the string-concatenation of month and the code unit 0x002D (HYPHEN-MINUS). let mut result = format!("{month:0>2}-{day:0>2}"); + // 4. Let calendarId be monthDay.[[Calendar]].[[id]]. let calendar_id = inner.calendar().identifier(); // 5. Let calendar be monthDay.[[Calendar]]. @@ -227,12 +239,13 @@ fn month_day_to_string(inner: &InnerMonthDay, show_calendar: CalendarName) -> Js CalendarName::Critical | CalendarName::Always | CalendarName::Auto )) && !(matches!(show_calendar, CalendarName::Auto) && calendar_id == "iso8601") { + let year = inner.iso_year().to_string(); let flag = if matches!(show_calendar, CalendarName::Critical) { "!" } else { "" }; - result.push_str(&format!("[{flag}c={calendar_id}]",)); + result = format!("{year}-{result}[{flag}u-ca={calendar_id}]"); } // 8. Return result. js_string!(result).into() @@ -245,7 +258,7 @@ pub(crate) fn create_temporal_month_day( ) -> JsResult { // 1. If IsValidISODate(referenceISOYear, isoMonth, isoDay) is false, throw a RangeError exception. // 2. If ISODateTimeWithinLimits(referenceISOYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0) is false, throw a RangeError exception. - if !DateTime::validate(&inner) { + if !PlainDateTime::validate(&inner) { return Err(JsNativeError::range() .with_message("PlainMonthDay does not hold a valid ISO date time.") .into()); @@ -301,18 +314,45 @@ fn to_temporal_month_day( } else if let Some(item_string) = item.as_string() { InnerMonthDay::from_str(item_string.to_std_string_escaped().as_str())? } else if item.is_object() { - InnerMonthDay::new( - item.get_v(js_string!("month"), context) - .expect("Month not found") - .to_i32(context) - .expect("Cannot convert month to i32"), - item.get_v(js_string!("day"), context) - .expect("Day not found") - .to_i32(context) - .expect("Cannot convert day to i32"), - calendar, - overflow, - )? + let day = item + .get_v(js_string!("day"), context) + .expect("Day not found") + .to_i32(context) + .expect("Cannot convert day to i32"); + let month = item + .get_v(js_string!("month"), context) + .expect("Month not found") + .to_i32(context) + .expect("Cannot convert month to i32"); + + let month_code = item + .get_v(js_string!("monthCode"), context) + .expect("monthCode not found"); + let resolved_month_code = if month_code.is_undefined() { + None + } else { + TinyAsciiStr::<4>::from_str( + &month_code + .to_string(context) + .expect("Cannot convert monthCode to string") + .to_std_string_escaped(), + ) + .map_err(|e| JsError::from(JsNativeError::range().with_message(e.to_string()))) + .ok() + }; + let year = item.get_v(js_string!("year"), context).map_or(1972, |val| { + val.to_i32(context).expect("Cannot convert year to i32") + }); + + let partial_date = &PartialDate { + month: Some(month), + day: Some(day), + year: Some(year), + month_code: resolved_month_code, + ..Default::default() + }; + + calendar.month_day_from_partial(partial_date, overflow)? } else { return Err(JsNativeError::typ() .with_message("item must be an object or a string") diff --git a/core/engine/src/builtins/temporal/plain_time/mod.rs b/core/engine/src/builtins/temporal/plain_time/mod.rs index 52d34cbbbb7..ffa97d54531 100644 --- a/core/engine/src/builtins/temporal/plain_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_time/mod.rs @@ -16,8 +16,9 @@ use crate::{ use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ - components::{PartialTime, Time}, options::{ArithmeticOverflow, TemporalRoundingMode}, + partial::PartialTime, + PlainTime as PlainTimeInner, }; use super::{ @@ -31,7 +32,7 @@ use super::{ // Safety: Time does not contain any traceable types. #[boa_gc(unsafe_empty_trace)] pub struct PlainTime { - inner: Time, + inner: PlainTimeInner, } impl BuiltInObject for PlainTime { @@ -184,15 +185,8 @@ impl BuiltInConstructor for PlainTime { .transpose()? .unwrap_or(0); - let inner = Time::new( - hour, - minute, - second, - millisecond, - microsecond, - nanosecond, - ArithmeticOverflow::Reject, - )?; + let inner = + PlainTimeInner::new(hour, minute, second, millisecond, microsecond, nanosecond)?; // 8. Return ? CreateTemporalTime(hour, minute, second, millisecond, microsecond, nanosecond, NewTarget). create_temporal_time(inner, Some(new_target), context).map(Into::into) @@ -597,7 +591,7 @@ impl PlainTime { // ==== PlainTime Abstract Operations ==== pub(crate) fn create_temporal_time( - inner: Time, + inner: PlainTimeInner, new_target: Option<&JsValue>, context: &mut Context, ) -> JsResult { @@ -633,12 +627,14 @@ pub(crate) fn create_temporal_time( Ok(obj) } +/// 4.5.3 `ToTemporalTime ( item [ , overflow ] )` pub(crate) fn to_temporal_time( value: &JsValue, overflow: Option, context: &mut Context, -) -> JsResult