From 2bb9af8156f09d7fc9877ea869e44d02b7a4f533 Mon Sep 17 00:00:00 2001 From: Ben Dean-Kawamura Date: Wed, 10 Apr 2024 17:23:00 +0000 Subject: [PATCH] Bug 1888683 - Upgrade UniFFI to 0.27.1. r=markh,janerik,glandium,supply-chain-reviewers,mach-reviewers,android-reviewers,kaya Update: - UniFFI to 0.27.1 - Glean to 59.0.0 - App-services to a recent version This removes the need for the goblin build hack, although we still have duplicate versions of goblin since UniFFI is ahead of the moz-central version. I think that should be easy to resolve as a follow-up. Updating uniffi-bindget-gecko-js based on upstream changes: - Clone objects before lowering them (https://github.com/mozilla/uniffi-rs/pull/1880) - Use u64 for the RustBuffer length and capacity field (https://github.com/mozilla/uniffi-rs/pull/1978) I didn't implement the new callback interface VTable code. Instead I simply disabled the one fixture that tests it. I'd rather implement https://bugzilla.mozilla.org/show_bug.cgi?id=1888668 first, since that will simplify the process a bunch. The only real-world use-case for callbacks that I know of is Mark's logging changes, but that will require implementing trait interfaces anyways so I'd rather wait than write a bunch of C++ code that we then throw away. Differential Revision: https://phabricator.services.mozilla.com/D206130 --- Cargo.lock | 8 +++ Cargo.toml | 35 ++++++------ build/rust/goblin/Cargo.toml | 19 ++++++- build/rust/scroll/Cargo.toml | 17 ++++++ build/rust/scroll/lib.rs | 11 ++++ dom/chrome-webidl/UniFFI.webidl | 2 +- gfx/wr/servo-tidy.toml | 2 + gfx/wr/webrender/Cargo.toml | 2 +- gfx/wr/wr_glyph_rasterizer/Cargo.toml | 2 +- .../src/main/java/DependenciesPlugin.kt | 2 +- python/sites/mach.txt | 2 +- supply-chain/audits.toml | 5 ++ toolkit/components/glean/Cargo.toml | 2 +- toolkit/components/glean/api/Cargo.toml | 2 +- .../components/glean/api/src/common_test.rs | 1 + toolkit/components/glean/src/init/mod.rs | 1 + .../uniffi-bindgen-gecko-js/Cargo.toml | 2 +- .../uniffi-bindgen-gecko-js/config.toml | 27 ++++++--- .../fixtures/moz.build | 1 + .../fixtures/tests/xpcshell/test_refcounts.js | 57 +++++++++++++++++++ .../fixtures/tests/xpcshell/xpcshell.toml | 15 +++++ .../uniffi-bindgen-gecko-js/src/render/cpp.rs | 40 ++++++------- .../uniffi-bindgen-gecko-js/src/render/js.rs | 4 +- .../src/templates/UniFFIScaffolding.cpp | 3 +- .../uniffi-fixture-external-types/Cargo.toml | 2 +- .../uniffi-fixture-refcounts/Cargo.toml | 12 ++++ .../uniffi-fixture-refcounts/build.rs | 7 +++ .../uniffi-fixture-refcounts/src/lib.rs | 28 +++++++++ .../src/refcounts.udl | 8 +++ .../components/uniffi-js/OwnedRustBuffer.cpp | 4 +- .../uniffi-js/ScaffoldingConverter.h | 2 +- .../components/uniffi-js/UniFFIPointer.cpp | 19 +++++-- toolkit/components/uniffi-js/UniFFIPointer.h | 14 ++--- .../components/uniffi-js/UniFFIPointerType.h | 4 +- toolkit/components/uniffi-js/UniFFIRust.h | 6 +- toolkit/library/rust/shared/Cargo.toml | 15 ++--- toolkit/library/rust/shared/lib.rs | 3 +- tools/lint/trojan-source.yml | 1 + 38 files changed, 299 insertions(+), 88 deletions(-) create mode 100644 build/rust/scroll/Cargo.toml create mode 100644 build/rust/scroll/lib.rs create mode 100644 toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js create mode 100644 toolkit/components/uniffi-fixture-refcounts/Cargo.toml create mode 100644 toolkit/components/uniffi-fixture-refcounts/build.rs create mode 100644 toolkit/components/uniffi-fixture-refcounts/src/lib.rs create mode 100644 toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl diff --git a/Cargo.lock b/Cargo.lock index b985fabf4687..fdbb975f19f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2330,6 +2330,7 @@ dependencies = [ "uniffi-example-todolist", "uniffi-fixture-callbacks", "uniffi-fixture-external-types", + "uniffi-fixture-refcounts", "url", "viaduct", "webext_storage_bridge", @@ -6107,6 +6108,13 @@ dependencies = [ "uniffi-example-geometry", ] +[[package]] +name = "uniffi-fixture-refcounts" +version = "0.21.0" +dependencies = [ + "uniffi", +] + [[package]] name = "uniffi_bindgen" version = "0.25.3" diff --git a/Cargo.toml b/Cargo.toml index 7b26009e165d..441e8c66b15e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,8 @@ resolver = "2" [workspace.dependencies] # Shared across multiple UniFFI consumers. -uniffi = "0.25.3" +uniffi = "0.27.1" +uniffi_bindgen = "0.27.1" # Shared across multiple application-services consumers. rusqlite = "0.30.0" @@ -164,10 +165,12 @@ derive_more = { path = "build/rust/derive_more" } # Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30 autocfg = { path = "third_party/rust/autocfg" } -# Patch goblin 0.6.0 to 0.7.0 because uniffi crates still use the older version -# and we want to avoid duplications +# Patch goblin 0.7.0 to 0.8 goblin = { path = "build/rust/goblin" } +# Patch scroll 0.11 to 0.12 +scroll = { path = "build/rust/scroll" } + # Patch memoffset from 0.8.0 to 0.9.0 since it's compatible and it avoids duplication memoffset = { path = "build/rust/memoffset" } @@ -209,14 +212,14 @@ warp = { git = "https://github.com/seanmonstar/warp", rev = "9d081461ae1167eb321 malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" } # application-services overrides to make updating them all simpler. -interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } -relevancy = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } -sql-support = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } -suggest = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } -sync15 = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } -tabs = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } -viaduct = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } -webext-storage = { git = "https://github.com/mozilla/application-services", rev = "9054db4bb5031881550ceab3448665ef6499a706" } +interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +relevancy = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +sql-support = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +suggest = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +sync15 = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +tabs = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +viaduct = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } +webext-storage = { git = "https://github.com/mozilla/application-services", rev = "e6ccfed09ebe663f464a33968f42e656c152e584" } # Patch mio 0.8.8 to use windows-sys 0.52 (backport https://github.com/tokio-rs/mio/commit/eea9e3e0c469480e5c59c01e6c3c7e5fd88f0848) mio_0_8 = { package = "mio", git = "https://github.com/glandium/mio", rev = "9a2ef335c366044ffe73b1c4acabe50a1daefe05" } @@ -227,8 +230,8 @@ mio_0_8 = { package = "mio", git = "https://github.com/glandium/mio", rev = "9a2 path = "third_party/rust/mio-0.6.23" [patch."https://github.com/mozilla/uniffi-rs.git"] -uniffi = "=0.25.3" -uniffi_bindgen = "=0.25.3" -uniffi_build = "=0.25.3" -uniffi_macros = "=0.25.3" -weedle2 = "=4.0.0" +uniffi = "0.27.1" +uniffi_bindgen = "0.27.1" +uniffi_build = "0.27.1" +uniffi_macros = "0.27.1" +weedle2 = "=5.0.0" diff --git a/build/rust/goblin/Cargo.toml b/build/rust/goblin/Cargo.toml index 52e8dfe66df1..4b6ea811e97e 100644 --- a/build/rust/goblin/Cargo.toml +++ b/build/rust/goblin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "goblin" -version = "0.6.999" +version = "0.7.999" edition = "2018" license = "MIT/Apache-2.0" @@ -8,4 +8,19 @@ license = "MIT/Apache-2.0" path = "lib.rs" [dependencies.goblin] -version = "0.7.0" +version = "0.8.0" + +default-features = false + +[features] +alloc = ["goblin/alloc"] +archive = ["goblin/archive"] +default = ["goblin/default"] +elf32 = ["goblin/elf32"] +elf64 = ["goblin/elf64"] +endian_fd = ["goblin/endian_fd"] +mach32 = ["goblin/mach32"] +mach64 = ["goblin/mach64"] +pe32 = ["goblin/pe32"] +pe64 = ["goblin/pe64"] +std = ["goblin/std"] diff --git a/build/rust/scroll/Cargo.toml b/build/rust/scroll/Cargo.toml new file mode 100644 index 000000000000..dea2c21fd1ac --- /dev/null +++ b/build/rust/scroll/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "scroll" +version = "0.11.999" +edition = "2018" +license = "MIT/Apache-2.0" + +[lib] +path = "lib.rs" + +[dependencies.scroll] +version = "0.12.0" +default-features = false + +[features] +default = ["scroll/default"] +derive = ["scroll/derive"] +std = ["scroll/std"] diff --git a/build/rust/scroll/lib.rs b/build/rust/scroll/lib.rs new file mode 100644 index 000000000000..f7d352d6d2a8 --- /dev/null +++ b/build/rust/scroll/lib.rs @@ -0,0 +1,11 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use scroll::*; diff --git a/dom/chrome-webidl/UniFFI.webidl b/dom/chrome-webidl/UniFFI.webidl index 7a3f68fbbde5..e24fc9cc5dc1 100644 --- a/dom/chrome-webidl/UniFFI.webidl +++ b/dom/chrome-webidl/UniFFI.webidl @@ -35,7 +35,7 @@ typedef unsigned long long UniFFICallbackObjectHandle; // Opaque type used to represent a pointer from Rust [ChromeOnly, Exposed=Window] -interface UniFFIPointer {}; +interface UniFFIPointer { }; // Types that can be passed or returned from scaffolding functions // diff --git a/gfx/wr/servo-tidy.toml b/gfx/wr/servo-tidy.toml index 442c407fcaa7..d548c5089f26 100644 --- a/gfx/wr/servo-tidy.toml +++ b/gfx/wr/servo-tidy.toml @@ -32,6 +32,8 @@ packages = [ # transition to syn 2 is underway. "syn", "synstructure", + # Requires an update to clap v4 + "textwrap", # Can be fixed by removing time dependency - see bug 1765324 "wasi", ] diff --git a/gfx/wr/webrender/Cargo.toml b/gfx/wr/webrender/Cargo.toml index 506226becafe..b99404de0d28 100644 --- a/gfx/wr/webrender/Cargo.toml +++ b/gfx/wr/webrender/Cargo.toml @@ -52,7 +52,7 @@ svg_fmt = "0.4" tracy-rs = "0.1.2" derive_more = { version = "0.99", default-features = false, features = ["add_assign"] } etagere = "0.2.6" -glean = { version = "58.1.0", optional = true } +glean = { version = "59.0.0", optional = true } firefox-on-glean = { version = "0.1.0", optional = true } swgl = { path = "../swgl", optional = true } topological-sort = "0.1" diff --git a/gfx/wr/wr_glyph_rasterizer/Cargo.toml b/gfx/wr/wr_glyph_rasterizer/Cargo.toml index b06cd0f08406..93877277b5f3 100644 --- a/gfx/wr/wr_glyph_rasterizer/Cargo.toml +++ b/gfx/wr/wr_glyph_rasterizer/Cargo.toml @@ -25,7 +25,7 @@ tracy-rs = "0.1.2" log = "0.4" lazy_static = "1" fxhash = "0.2.1" -glean = { version = "58.1.0", optional = true } +glean = { version = "59.0.0", optional = true } firefox-on-glean = { version = "0.1.0", optional = true } serde = { optional = true, version = "1.0", features = ["serde_derive"] } diff --git a/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt b/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt index 6a3d4c212dfc..a58ac29588c1 100644 --- a/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt +++ b/mobile/android/android-components/plugins/dependencies/src/main/java/DependenciesPlugin.kt @@ -19,7 +19,7 @@ object Versions { const val serialization = "1.6.3" const val python_envs_plugin = "0.0.31" - const val mozilla_glean = "58.1.0" + const val mozilla_glean = "59.0.0" const val junit = "4.13.2" const val robolectric = "4.11.1" diff --git a/python/sites/mach.txt b/python/sites/mach.txt index e1cb8f159c06..90d6f153fc99 100644 --- a/python/sites/mach.txt +++ b/python/sites/mach.txt @@ -93,7 +93,7 @@ vendored:third_party/python/wheel vendored:third_party/python/zipp # glean-sdk may not be installable if a wheel isn't available # and it has to be built from source. -pypi-optional:glean-sdk==58.1.0:telemetry will not be collected +pypi-optional:glean-sdk==59.0.0:telemetry will not be collected # Mach gracefully handles the case where `psutil` is unavailable. # We aren't (yet) able to pin packages in automation, so we have to # support down to the oldest locally-installed version (5.4.2). diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 0f9a2f75e977..b21bde4f1024 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -3750,6 +3750,11 @@ who = "Mike Hommey " criteria = "safe-to-deploy" delta = "0.15.2 -> 0.16.0" +[[audits.textwrap]] +who = "Jan-Erik Rediger " +criteria = "safe-to-deploy" +delta = "0.16.0 -> 0.16.1" + [[audits.thin-vec]] who = "Aria Beingessner " criteria = "safe-to-deploy" diff --git a/toolkit/components/glean/Cargo.toml b/toolkit/components/glean/Cargo.toml index 98b8d8a95b2b..ba563f514a3a 100644 --- a/toolkit/components/glean/Cargo.toml +++ b/toolkit/components/glean/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" license = "MPL-2.0" [dependencies] -glean = "58.1.0" +glean = "59.0.0" log = "0.4" nserror = { path = "../../../xpcom/rust/nserror" } nsstring = { path = "../../../xpcom/rust/nsstring" } diff --git a/toolkit/components/glean/api/Cargo.toml b/toolkit/components/glean/api/Cargo.toml index dc688dc41efa..af507f499f05 100644 --- a/toolkit/components/glean/api/Cargo.toml +++ b/toolkit/components/glean/api/Cargo.toml @@ -9,7 +9,7 @@ license = "MPL-2.0" [dependencies] bincode = "1.0" chrono = "0.4.10" -glean = "58.1.0" +glean = "59.0.0" inherent = "1.0.0" log = "0.4" nsstring = { path = "../../../../xpcom/rust/nsstring", optional = true } diff --git a/toolkit/components/glean/api/src/common_test.rs b/toolkit/components/glean/api/src/common_test.rs index 3c8c2c71e1cc..46062736f263 100644 --- a/toolkit/components/glean/api/src/common_test.rs +++ b/toolkit/components/glean/api/src/common_test.rs @@ -43,6 +43,7 @@ fn setup_glean(tempdir: Option) -> tempfile::TempDir { rate_limit: None, enable_event_timestamps: false, experimentation_id: None, + enable_internal_pings: true }; let client_info = glean::ClientInfoMetrics { diff --git a/toolkit/components/glean/src/init/mod.rs b/toolkit/components/glean/src/init/mod.rs index f430cd73840d..6c5772ae7f3a 100644 --- a/toolkit/components/glean/src/init/mod.rs +++ b/toolkit/components/glean/src/init/mod.rs @@ -184,6 +184,7 @@ fn build_configuration( rate_limit, enable_event_timestamps, experimentation_id: None, + enable_internal_pings: true, }; Ok((configuration, client_info)) diff --git a/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml index 32232c64b97d..5ef165dc73a5 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml +++ b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml @@ -15,7 +15,7 @@ clap = { version = "4", default-features = false, features = ["std", "derive", " extend = "1.1" heck = "0.4" uniffi = { workspace = true } -uniffi_bindgen = "0.25" +uniffi_bindgen = { workspace = true } serde = "1" toml = "0.5" camino = "1.0.8" diff --git a/toolkit/components/uniffi-bindgen-gecko-js/config.toml b/toolkit/components/uniffi-bindgen-gecko-js/config.toml index 7b7943dfbdcf..d8404f51428e 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/config.toml +++ b/toolkit/components/uniffi-bindgen-gecko-js/config.toml @@ -72,16 +72,27 @@ crate_name = "uniffi_todolist" udl_file = "third_party/rust/uniffi-example-todolist/src/todolist.udl" fixture = true -[fixture_callbacks] -crate_name = "uniffi_fixture_callbacks" -udl_file = "toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl" +[fixture_refcounts] +crate_name = "uniffi_fixture_refcounts" +udl_file = "toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl" fixture = true -[fixture_callbacks.receiver_thread] -default = "worker" -main = [ - "log_even_numbers_main_thread", -] +[fixture_refcounts.receiver_thread] +default = "main" + +# Temporarily disabled until we can re-enable callback support +# +# I think this can be done when we implement https://bugzilla.mozilla.org/show_bug.cgi?id=1888668 +# [fixture_callbacks] +# crate_name = "uniffi_fixture_callbacks" +# udl_file = "toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl" +# fixture = true +# +# [fixture_callbacks.receiver_thread] +# default = "worker" +# main = [ +# "log_even_numbers_main_thread", +# ] [custom_types] crate_name = "uniffi_custom_types" diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build index d5ff2d7cb6c6..eed04220cb56 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build @@ -12,6 +12,7 @@ components = [ "ExternalTypes", "FixtureCallbacks", "Geometry", + "Refcounts", "Rondpoint", "Sprites", "Todolist", diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js new file mode 100644 index 000000000000..790d981104ce --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_refcounts.js @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const { getSingleton, getJsRefcount } = ChromeUtils.importESModule( + "resource://gre/modules/RustRefcounts.sys.mjs" +); + +// Test refcounts when we call methods. +// +// Each method call requires that we clone the Arc pointer on the JS side, then pass it to Rust +// which will consumer the reference. Make sure we get this right + +function createObjectAndCallMethods() { + const obj = getSingleton(); + obj.method(); +} + +add_test(() => { + // Create an object that we'll keep around. If the ref count ends up being low, we don't want + // to reduce it below 0, since the Rust code may catch that and clamp it + const obj = getSingleton(); + createObjectAndCallMethods(); + Cu.forceGC(); + Cu.forceCC(); + do_test_pending(); + do_timeout(500, () => { + Assert.equal(getJsRefcount(), 1); + // Use `obj` to avoid unused warnings and try to ensure that JS doesn't destroy it early + obj.method(); + do_test_finished(); + run_next_test(); + }); +}); + +// Test refcounts when creating/destroying objects +function createAndDeleteObjects() { + [getSingleton(), getSingleton(), getSingleton()]; +} + +add_test(() => { + const obj = getSingleton(); + createAndDeleteObjects(); + Cu.forceGC(); + Cu.forceCC(); + do_timeout(500, () => { + Assert.equal(getJsRefcount(), 1); + obj.method(); + do_test_finished(); + run_next_test(); + }); +}); + +// As we implement more UniFFI features we should probably add refcount tests for it. +// Some features that should probably have tests: +// - Async methods +// - UniFFI builtin trait methods like 'to_string' +// - Rust trait objects diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml index 76814ff1991d..801e95382f7b 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml @@ -2,18 +2,33 @@ ["test_arithmetic.js"] +# I think this can be re-enabled when we implement https://bugzilla.mozilla.org/show_bug.cgi?id=1888668 +lineno = "3" + ["test_callbacks.js"] +disabled = "Temporarily disabled until we can re-enable callback support" +lineno = "8" ["test_custom_types.js"] +lineno = "12" ["test_external_types.js"] +lineno = "15" ["test_geometry.js"] +lineno = "18" + +["test_refcounts.js"] +lineno = "21" ["test_rondpoint.js"] +lineno = "24" ["test_sprites.js"] +lineno = "27" ["test_todolist.js"] +lineno = "30" ["test_type_checking.js"] +lineno = "33" diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs index 685c3c2bf370..7b63e8f3af7a 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs @@ -136,31 +136,25 @@ pub impl FfiType { // Type for the Rust scaffolding code fn rust_type(&self) -> String { match self { - FfiType::UInt8 => "uint8_t", - FfiType::Int8 => "int8_t", - FfiType::UInt16 => "uint16_t", - FfiType::Int16 => "int16_t", - FfiType::UInt32 => "uint32_t", - FfiType::Int32 => "int32_t", - FfiType::UInt64 => "uint64_t", - FfiType::Int64 => "int64_t", - FfiType::Float32 => "float", - FfiType::Float64 => "double", - FfiType::RustBuffer(_) => "RustBuffer", - FfiType::RustArcPtr(_) => "void *", - FfiType::ForeignCallback => "ForeignCallback", + FfiType::UInt8 => "uint8_t".to_owned(), + FfiType::Int8 => "int8_t".to_owned(), + FfiType::UInt16 => "uint16_t".to_owned(), + FfiType::Int16 => "int16_t".to_owned(), + FfiType::UInt32 => "uint32_t".to_owned(), + FfiType::Int32 => "int32_t".to_owned(), + FfiType::UInt64 => "uint64_t".to_owned(), + FfiType::Int64 => "int64_t".to_owned(), + FfiType::Float32 => "float".to_owned(), + FfiType::Float64 => "double".to_owned(), + FfiType::RustBuffer(_) => "RustBuffer".to_owned(), + FfiType::RustArcPtr(_) => "void *".to_owned(), FfiType::ForeignBytes => unimplemented!("ForeignBytes not supported"), - FfiType::ForeignExecutorHandle => unimplemented!("ForeignExecutorHandle not supported"), - FfiType::ForeignExecutorCallback => { - unimplemented!("ForeignExecutorCallback not supported") - } - FfiType::RustFutureHandle - | FfiType::RustFutureContinuationCallback - | FfiType::RustFutureContinuationData => { - unimplemented!("Rust async functions not supported") - } + FfiType::Handle => "uint64_t".to_owned(), + FfiType::RustCallStatus => "RustCallStatus".to_owned(), + FfiType::Callback(name) | FfiType::Struct(name) => name.to_owned(), + FfiType::VoidPointer => "void *".to_owned(), + FfiType::Reference(_) => unimplemented!("References not supported"), } - .to_owned() } } diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs index efd7b4245628..cd9af529a7c4 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs @@ -92,7 +92,8 @@ pub impl Literal { Literal::Enum(name, typ) => render_enum_literal(typ, name), Literal::EmptyMap => "{}".to_string(), Literal::EmptySequence => "[]".to_string(), - Literal::Null => "null".to_string(), + Literal::Some { inner } => inner.render(), + Literal::None => "null".to_string(), } } } @@ -258,7 +259,6 @@ pub impl Type { | Type::CallbackInterface { name, .. } => format!("Type{name}"), Type::Timestamp => "Timestamp".into(), Type::Duration => "Duration".into(), - Type::ForeignExecutor => "ForeignExecutor".into(), Type::Optional { inner_type } => format!("Optional{}", inner_type.canonical_name()), Type::Sequence { inner_type } => format!("Sequence{}", inner_type.canonical_name()), Type::Map { diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp index 5c4ed8c2f56f..83aeae808650 100644 --- a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp @@ -37,7 +37,8 @@ extern "C" { {%- let pointer_type = ci.pointer_type(object) %} const static mozilla::uniffi::UniFFIPointerType {{ pointer_type }} { "{{ "{}::{}"|format(ci.namespace(), object.name()) }}"_ns, - {{ object.ffi_object_free().rust_name() }} + {{ object.ffi_object_clone().rust_name() }}, + {{ object.ffi_object_free().rust_name() }}, }; {%- endfor %} {%- endfor %} diff --git a/toolkit/components/uniffi-fixture-external-types/Cargo.toml b/toolkit/components/uniffi-fixture-external-types/Cargo.toml index f9ac840c3fa3..46ee01662d22 100644 --- a/toolkit/components/uniffi-fixture-external-types/Cargo.toml +++ b/toolkit/components/uniffi-fixture-external-types/Cargo.toml @@ -7,7 +7,7 @@ license = "MPL-2.0" publish = false [dependencies] -uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b" } +uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de" } uniffi = { workspace = true } thiserror = "1.0" diff --git a/toolkit/components/uniffi-fixture-refcounts/Cargo.toml b/toolkit/components/uniffi-fixture-refcounts/Cargo.toml new file mode 100644 index 000000000000..877e5027112e --- /dev/null +++ b/toolkit/components/uniffi-fixture-refcounts/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "uniffi-fixture-refcounts" +edition = "2021" +version = "0.21.0" +license = "MPL-2.0" +publish = false + +[dependencies] +uniffi = { workspace = true } + +[build-dependencies] +uniffi = { workspace = true, features = ["build"] } diff --git a/toolkit/components/uniffi-fixture-refcounts/build.rs b/toolkit/components/uniffi-fixture-refcounts/build.rs new file mode 100644 index 000000000000..9ea03e12de13 --- /dev/null +++ b/toolkit/components/uniffi-fixture-refcounts/build.rs @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +fn main() { + uniffi::generate_scaffolding("./src/refcounts.udl").unwrap(); +} diff --git a/toolkit/components/uniffi-fixture-refcounts/src/lib.rs b/toolkit/components/uniffi-fixture-refcounts/src/lib.rs new file mode 100644 index 000000000000..e453b22a4ad3 --- /dev/null +++ b/toolkit/components/uniffi-fixture-refcounts/src/lib.rs @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/// This crate exists to test managing the Rust Arc strong counts as JS objects are +/// created/destroyed. See `test_refcounts.js` for how it's used. + +use std::sync::{Arc, Mutex}; + +pub struct SingletonObject; + +impl SingletonObject { + pub fn method(&self) { } +} + +static SINGLETON: Mutex>> = Mutex::new(None); + +pub fn get_singleton() -> Arc { + Arc::clone(SINGLETON.lock().unwrap().get_or_insert_with(|| Arc::new(SingletonObject))) +} + +pub fn get_js_refcount() -> i32 { + // Subtract 2: one for the reference in the Mutex and one for the temporary reference that + // we're calling Arc::strong_count on. + (Arc::strong_count(&get_singleton()) as i32) - 2 +} + +include!(concat!(env!("OUT_DIR"), "/refcounts.uniffi.rs")); diff --git a/toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl b/toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl new file mode 100644 index 000000000000..25ec83cfcc5d --- /dev/null +++ b/toolkit/components/uniffi-fixture-refcounts/src/refcounts.udl @@ -0,0 +1,8 @@ +namespace refcounts { + SingletonObject get_singleton(); + i32 get_js_refcount(); +}; + +interface SingletonObject { + void method(); +}; diff --git a/toolkit/components/uniffi-js/OwnedRustBuffer.cpp b/toolkit/components/uniffi-js/OwnedRustBuffer.cpp index 4e334a966e75..f14033a21392 100644 --- a/toolkit/components/uniffi-js/OwnedRustBuffer.cpp +++ b/toolkit/components/uniffi-js/OwnedRustBuffer.cpp @@ -27,7 +27,7 @@ Result OwnedRustBuffer::FromArrayBuffer( RustCallStatus status{}; RustBuffer buf = uniffi_rustbuffer_alloc( - static_cast(aData.Length()), &status); + static_cast(aData.Length()), &status); buf.len = aData.Length(); if (status.code != 0) { if (status.error_buf.data) { @@ -84,7 +84,7 @@ RustBuffer OwnedRustBuffer::IntoRustBuffer() { JSObject* OwnedRustBuffer::IntoArrayBuffer(JSContext* cx) { JS::Rooted obj(cx); { - int32_t len = mBuf.len; + auto len = mBuf.len; void* data = mBuf.data; auto userData = MakeUnique(std::move(*this)); UniquePtr dataPtr{ diff --git a/toolkit/components/uniffi-js/ScaffoldingConverter.h b/toolkit/components/uniffi-js/ScaffoldingConverter.h index ae5629e2e4f3..d11fd0c31458 100644 --- a/toolkit/components/uniffi-js/ScaffoldingConverter.h +++ b/toolkit/components/uniffi-js/ScaffoldingConverter.h @@ -173,7 +173,7 @@ class ScaffoldingObjectConverter { if (!value.IsSamePtrType(PointerType)) { return Err("Bad pointer type"_ns); } - return value.GetPtr(); + return value.ClonePtr(); } static void* IntoRust(void* aValue) { return aValue; } diff --git a/toolkit/components/uniffi-js/UniFFIPointer.cpp b/toolkit/components/uniffi-js/UniFFIPointer.cpp index c3a1eba93dc0..8e79bac0dbb8 100644 --- a/toolkit/components/uniffi-js/UniFFIPointer.cpp +++ b/toolkit/components/uniffi-js/UniFFIPointer.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPrintfCString.h" +#include "js/GCAPI.h" #include "mozilla/EndianUtils.h" #include "mozilla/dom/UniFFIPointer.h" #include "mozilla/dom/UniFFIBinding.h" @@ -81,8 +82,14 @@ void UniFFIPointer::Write(const ArrayBuffer& aArrayBuff, uint32_t aPosition, // in Rust and Read(), a u64 is read as BigEndian and then converted to // a pointer we do the reverse here const auto& data_ptr = aData.Subspan(aPosition, 8); + // The hazard checker assumes all calls to a function pointer may result + // in a GC call and `ClonePtr` calls mType->clone. However, we know that + // mtype->clone won't make a GC call since it's essentially just a call + // to Rust's `Arc::clone()`. Use AutoSuppressGCAnalysis to tell the + // hazard checker to ignore the call. + JS::AutoSuppressGCAnalysis suppress; mozilla::BigEndian::writeUint64(data_ptr.Elements(), - (uint64_t)GetPtr()); + (uint64_t)ClonePtr()); return true; })) { aError.ThrowRangeError("position is out of range"); @@ -100,10 +107,14 @@ JSObject* UniFFIPointer::WrapObject(JSContext* aCx, return dom::UniFFIPointer_Binding::Wrap(aCx, this, aGivenProto); } -void* UniFFIPointer::GetPtr() const { +void* UniFFIPointer::ClonePtr() const { MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, - ("[UniFFI] Getting raw pointer")); - return this->mPtr; + ("[UniFFI] Cloning raw pointer")); + RustCallStatus status{}; + auto cloned = this->mType->clone(this->mPtr, &status); + MOZ_DIAGNOSTIC_ASSERT(status.code == RUST_CALL_SUCCESS, + "UniFFI clone call returned a non-success result"); + return cloned; } bool UniFFIPointer::IsSamePtrType(const UniFFIPointerType* aType) const { diff --git a/toolkit/components/uniffi-js/UniFFIPointer.h b/toolkit/components/uniffi-js/UniFFIPointer.h index 59acc0ca666c..f9a95c309ea1 100644 --- a/toolkit/components/uniffi-js/UniFFIPointer.h +++ b/toolkit/components/uniffi-js/UniFFIPointer.h @@ -36,15 +36,13 @@ class UniFFIPointer final : public nsISupports, public nsWrapperCache { nsISupports* GetParentObject() { return nullptr; } /** - * returns the raw pointer `UniFFIPointer` holds - * This is safe because: - * - The pointer was allocated in Rust as a reference counted `Arc` - * - Rust cloned the pointer without destructing it when passed into C++ - * - Eventually, when the destructor of `UniFFIPointer` runs, we return - * ownership to Rust, which then decrements the count and deallocates the - * memory the pointer points to. + * Clone the raw pointer that `UniFFIPointer` holds + * + * Use this when lowering the pointer to pass it across the FFI, for example: + * - When calling a method + * - When passing the object as an argument to a function */ - void* GetPtr() const; + void* ClonePtr() const; /** * Returns true if the pointer type `this` holds is the same as the argument diff --git a/toolkit/components/uniffi-js/UniFFIPointerType.h b/toolkit/components/uniffi-js/UniFFIPointerType.h index 7236e50cb79c..25294cfc9de1 100644 --- a/toolkit/components/uniffi-js/UniFFIPointerType.h +++ b/toolkit/components/uniffi-js/UniFFIPointerType.h @@ -21,7 +21,9 @@ namespace mozilla::uniffi { **/ struct UniFFIPointerType { nsLiteralCString typeName; - // The Rust destructor for the pointer, this gives back ownership to Rust + // Rust FFI function to clone for the pointer + void* (*clone)(void*, RustCallStatus*); + // Rust FFI function to destroy for the pointer void (*destructor)(void*, RustCallStatus*); }; } // namespace mozilla::uniffi diff --git a/toolkit/components/uniffi-js/UniFFIRust.h b/toolkit/components/uniffi-js/UniFFIRust.h index 2907af8f51a1..608b8063aeff 100644 --- a/toolkit/components/uniffi-js/UniFFIRust.h +++ b/toolkit/components/uniffi-js/UniFFIRust.h @@ -28,8 +28,8 @@ constexpr int8_t CALLBACK_INTERFACE_UNEXPECTED_ERROR = 2; // structs/functions from UniFFI extern "C" { struct RustBuffer { - int32_t capacity; - int32_t len; + uint64_t capacity; + uint64_t len; uint8_t* data; }; @@ -42,7 +42,7 @@ typedef int (*ForeignCallback)(uint64_t handle, uint32_t method, const uint8_t* argsData, int32_t argsLen, RustBuffer* buf_ptr); -RustBuffer uniffi_rustbuffer_alloc(int32_t size, RustCallStatus* call_status); +RustBuffer uniffi_rustbuffer_alloc(uint64_t size, RustCallStatus* call_status); void uniffi_rustbuffer_free(RustBuffer buf, RustCallStatus* call_status); } diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index 6e7aa00a2c47..08b3ccea2add 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -72,18 +72,19 @@ origin-trials-ffi = { path = "../../../../dom/origin-trials/ffi" } jog = { path = "../../../components/glean/bindings/jog" } dap_ffi = { path = "../../../components/telemetry/dap/ffi" } data-encoding-ffi = { path = "../../../../dom/fs/parent/rust/data-encoding-ffi" } -uniffi-example-arithmetic = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } -uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } -uniffi-example-rondpoint = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } -uniffi-example-sprites = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } -uniffi-example-todolist = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "afb29ebdc1d9edf15021b1c5332fc9f285bbe13b", optional = true } +uniffi-example-arithmetic = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } +uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } +uniffi-example-rondpoint = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } +uniffi-example-sprites = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } +uniffi-example-todolist = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "d52c5460ae42ecad1e73a5b394ac96d48f4769de", optional = true } uniffi-example-custom-types = { path = "../../../components/uniffi-example-custom-types/", optional = true } uniffi-fixture-callbacks = { path = "../../../components/uniffi-fixture-callbacks/", optional = true } uniffi-fixture-external-types = { path = "../../../components/uniffi-fixture-external-types/", optional = true } +uniffi-fixture-refcounts = { path = "../../../components/uniffi-fixture-refcounts/", optional = true } binary_http = { path = "../../../../netwerk/protocol/http/binary_http" } oblivious_http = { path = "../../../../netwerk/protocol/http/oblivious_http" } mime-guess-ffi = { path = "../../../../dom/fs/parent/rust/mime-guess-ffi" } -uniffi = { version = "0.25.2" } +uniffi = { workspace = true } # Note: `modern_sqlite` means rusqlite's bindings file be for a sqlite with # version less than or equal to what we link to. This isn't a problem because we @@ -145,7 +146,7 @@ thread_sanitizer = ["xpcom/thread_sanitizer"] uniffi_fixtures = [ "uniffi-example-arithmetic", "uniffi-example-geometry", "uniffi-example-rondpoint", "uniffi-example-sprites", "uniffi-example-todolist", "uniffi-example-custom-types", "uniffi-fixture-callbacks", - "uniffi-fixture-external-types", + "uniffi-fixture-external-types", "uniffi-fixture-refcounts", ] webmidi_midir_impl = ["midir_impl"] icu4x = ["jsrust_shared/icu4x"] diff --git a/toolkit/library/rust/shared/lib.rs b/toolkit/library/rust/shared/lib.rs index a6dfe60411f9..7108e3c17c06 100644 --- a/toolkit/library/rust/shared/lib.rs +++ b/toolkit/library/rust/shared/lib.rs @@ -136,6 +136,7 @@ mod uniffi_fixtures { uniffi_fixture_callbacks::uniffi_reexport_scaffolding!(); uniffi_custom_types::uniffi_reexport_scaffolding!(); uniffi_fixture_external_types::uniffi_reexport_scaffolding!(); + uniffi_fixture_refcounts::uniffi_reexport_scaffolding!(); uniffi_geometry::uniffi_reexport_scaffolding!(); uniffi_rondpoint::uniffi_reexport_scaffolding!(); uniffi_sprites::uniffi_reexport_scaffolding!(); @@ -174,7 +175,7 @@ pub unsafe extern "C" fn debug_log(target: *const c_char, message: *const c_char // Define extern "C" versions of these UniFFI functions, so that they can be called from C++ #[no_mangle] pub extern "C" fn uniffi_rustbuffer_alloc( - size: i32, + size: u64, call_status: &mut uniffi::RustCallStatus, ) -> uniffi::RustBuffer { uniffi::uniffi_rustbuffer_alloc(size, call_status) diff --git a/tools/lint/trojan-source.yml b/tools/lint/trojan-source.yml index 611ab660f505..a273626b588b 100644 --- a/tools/lint/trojan-source.yml +++ b/tools/lint/trojan-source.yml @@ -14,6 +14,7 @@ trojan-source: - third_party/python/arrow/arrow/locales.py - third_party/rust/chardetng/src/data.rs - third_party/rust/clap_builder/src/output/textwrap/core.rs + - third_party/rust/textwrap/src/core.rs - third_party/rust/icu_provider/src/hello_world.rs - third_party/rust/uniffi-example-rondpoint/tests/bindings/test_rondpoint.py - third_party/rust/error-chain/tests/tests.rs