From d9b283cbc2e8d464bef0d32ffc3514915525e56d Mon Sep 17 00:00:00 2001 From: Samson <16504129+sagudev@users.noreply.github.com> Date: Wed, 2 Oct 2024 20:06:23 +0200 Subject: [PATCH] Update SpiderMonkey to 128.3 (#511) * Update SpiderMonkey to 128.3 Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * update COMMIT hash Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * bump mozjs-sys version Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * add commit signoff and format update.py Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --- mozjs-sys/Cargo.toml | 2 +- mozjs-sys/etc/COMMIT | 2 +- mozjs-sys/etc/update.py | 46 +- mozjs-sys/mozjs/.cargo/config.toml.in | 4 +- mozjs-sys/mozjs/Cargo.lock | 18 +- .../mozjs/build/clang-plugin/ThreadAllows.txt | 3 + .../mozjs/build/debian-packages/valgrind.diff | 121 ++++ .../build/moz.configure/libraries.configure | 2 +- mozjs-sys/mozjs/config/milestone.txt | 2 +- mozjs-sys/mozjs/js/public/GCHashTable.h | 409 ++++++++++++++ mozjs-sys/mozjs/js/public/StructuredClone.h | 1 + mozjs-sys/mozjs/js/public/SweepingAPI.h | 125 +++++ .../mozjs/js/public/friend/ErrorNumbers.msg | 1 + mozjs-sys/mozjs/js/src/build/Makefile.in | 2 +- mozjs-sys/mozjs/js/src/gc/Compacting.cpp | 6 +- mozjs-sys/mozjs/js/src/gc/GC.cpp | 12 +- mozjs-sys/mozjs/js/src/gc/GCRuntime.h | 9 +- mozjs-sys/mozjs/js/src/gc/Sweeping.cpp | 112 ++-- mozjs-sys/mozjs/js/src/gc/SweepingAPI.h | 515 ------------------ mozjs-sys/mozjs/js/src/gc/Verifier.cpp | 8 +- mozjs-sys/mozjs/js/src/gc/Zone.cpp | 4 +- mozjs-sys/mozjs/js/src/gc/Zone.h | 8 +- .../js/src/jit/BacktrackingAllocator.cpp | 8 +- .../mozjs/js/src/jit/CacheIRCompiler.cpp | 2 +- mozjs-sys/mozjs/js/src/jit/CodeGenerator.cpp | 3 +- mozjs-sys/mozjs/js/src/jit/IonAnalysis.cpp | 55 +- mozjs-sys/mozjs/js/src/jit/JitFrames.cpp | 19 +- mozjs-sys/mozjs/js/src/jit/Lowering.cpp | 3 +- mozjs-sys/mozjs/js/src/jit/MacroAssembler.cpp | 42 +- mozjs-sys/mozjs/js/src/jit/MacroAssembler.h | 8 +- .../js/src/jit/arm/MacroAssembler-arm.cpp | 21 +- .../js/src/jit/arm64/Architecture-arm64.h | 11 +- .../js/src/jit/arm64/MacroAssembler-arm64.cpp | 22 +- .../jit/loong64/MacroAssembler-loong64.cpp | 17 +- .../MacroAssembler-mips-shared-inl.h | 4 + .../src/jit/mips32/MacroAssembler-mips32.cpp | 8 +- .../src/jit/mips64/MacroAssembler-mips64.cpp | 17 +- .../js/src/jit/mips64/MoveEmitter-mips64.cpp | 4 +- .../jit/riscv64/MacroAssembler-riscv64.cpp | 18 +- .../js/src/jit/x64/MacroAssembler-x64.cpp | 8 +- .../x86-shared/MacroAssembler-x86-shared.cpp | 9 + .../js/src/jit/x86/MacroAssembler-x86.cpp | 8 +- .../js/src/jsapi-tests/testGCWeakCache.cpp | 23 +- .../src/jsapi-tests/testWasmReturnCalls.cpp | 4 +- mozjs-sys/mozjs/js/src/moz.build | 1 + mozjs-sys/mozjs/js/src/shell/js.cpp | 1 + mozjs-sys/mozjs/js/src/shell/jsshell.h | 2 +- mozjs-sys/mozjs/js/src/vm/Compartment.cpp | 17 +- mozjs-sys/mozjs/js/src/vm/Compartment.h | 2 +- mozjs-sys/mozjs/js/src/vm/Interpreter-inl.h | 8 +- mozjs-sys/mozjs/js/src/vm/InvalidatingFuse.h | 4 +- mozjs-sys/mozjs/js/src/vm/Realm.h | 2 +- mozjs-sys/mozjs/js/src/vm/RegExpShared.h | 3 +- mozjs-sys/mozjs/js/src/vm/Runtime.cpp | 4 +- mozjs-sys/mozjs/js/src/vm/Runtime.h | 7 +- mozjs-sys/mozjs/js/src/vm/ShapeZone.h | 23 +- mozjs-sys/mozjs/js/src/vm/StructuredClone.cpp | 56 +- .../mozjs/js/src/wasm/WasmBaselineCompile.cpp | 52 +- mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.cpp | 21 +- mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.h | 2 +- mozjs-sys/mozjs/js/src/wasm/WasmDump.cpp | 8 +- .../mozjs/js/src/wasm/WasmGcObject-inl.h | 4 +- mozjs-sys/mozjs/js/src/wasm/WasmGcObject.cpp | 32 +- mozjs-sys/mozjs/js/src/wasm/WasmGcObject.h | 4 +- mozjs-sys/mozjs/js/src/wasm/WasmInstance.cpp | 12 +- .../mozjs/js/src/wasm/WasmIonCompile.cpp | 42 +- mozjs-sys/mozjs/js/src/wasm/WasmJS.cpp | 4 +- mozjs-sys/mozjs/js/src/wasm/WasmJS.h | 9 +- mozjs-sys/mozjs/js/src/wasm/WasmOpIter.h | 34 +- mozjs-sys/mozjs/js/src/wasm/WasmPI.cpp | 2 +- mozjs-sys/mozjs/js/src/wasm/WasmSerialize.cpp | 13 +- mozjs-sys/mozjs/js/src/wasm/WasmStubs.cpp | 32 +- mozjs-sys/mozjs/js/src/wasm/WasmStubs.h | 5 + mozjs-sys/mozjs/js/src/wasm/WasmTable.h | 7 +- mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.cpp | 10 +- mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.h | 101 ++-- mozjs-sys/mozjs/js/src/wasm/WasmValidate.cpp | 2 +- mozjs-sys/mozjs/memory/build/Mutex.h | 8 +- mozjs-sys/mozjs/memory/build/mozjemalloc.cpp | 46 +- mozjs-sys/mozjs/memory/build/zone.c | 5 +- mozjs-sys/mozjs/mfbt/Attributes.h | 15 +- .../modules/libpref/init/StaticPrefList.yaml | 47 +- .../mozjs/python/mach/mach/mixin/process.py | 7 +- .../mozjs/python/mozboot/mozboot/gentoo.py | 3 +- .../mozbuild/backend/recursivemake.py | 19 +- .../python/mozbuild/mozbuild/frontend/data.py | 30 +- .../test/backend/test_recursivemake.py | 25 +- .../mozprocess/mozprocess/processhandler.py | 232 ++++---- 88 files changed, 1512 insertions(+), 1177 deletions(-) create mode 100644 mozjs-sys/mozjs/build/debian-packages/valgrind.diff create mode 100644 mozjs-sys/mozjs/js/public/SweepingAPI.h delete mode 100644 mozjs-sys/mozjs/js/src/gc/SweepingAPI.h diff --git a/mozjs-sys/Cargo.toml b/mozjs-sys/Cargo.toml index 5004acd56c8..0848caa909d 100644 --- a/mozjs-sys/Cargo.toml +++ b/mozjs-sys/Cargo.toml @@ -2,7 +2,7 @@ name = "mozjs_sys" description = "System crate for the Mozilla SpiderMonkey JavaScript engine." repository.workspace = true -version = "0.128.0-13" +version = "0.128.3-0" authors = ["Mozilla"] links = "mozjs" build = "build.rs" diff --git a/mozjs-sys/etc/COMMIT b/mozjs-sys/etc/COMMIT index 96e62b27efb..f86ab5a2236 100644 --- a/mozjs-sys/etc/COMMIT +++ b/mozjs-sys/etc/COMMIT @@ -1 +1 @@ -4cff37e891cdf778f142fd8005c71b1dd88898b2 +e2cb3d9c8cfc18acad7f77add351416dc95b67c4 diff --git a/mozjs-sys/etc/update.py b/mozjs-sys/etc/update.py index f04a73bc057..6516e759017 100644 --- a/mozjs-sys/etc/update.py +++ b/mozjs-sys/etc/update.py @@ -9,6 +9,7 @@ TARGET = "mozjs-sys/mozjs" + def extract_tarball(tarball, commit): print("Extracting tarball.") @@ -20,24 +21,33 @@ def extract_tarball(tarball, commit): contents = os.listdir(directory) if len(contents) != 1: - raise Exception("Found more than one directory in the tarball: %s" % - ", ".join(contents)) + raise Exception( + "Found more than one directory in the tarball: %s" % ", ".join(contents) + ) subdirectory = contents[0] - subprocess.check_call([ - "rsync", - "--delete-excluded", - "--filter=merge mozjs-sys/etc/filters.txt", - "--prune-empty-dirs", - "--quiet", - "--recursive", - os.path.join(directory, subdirectory, ""), - os.path.join(TARGET, ""), - ]) + subprocess.check_call( + [ + "rsync", + "--delete-excluded", + "--filter=merge mozjs-sys/etc/filters.txt", + "--prune-empty-dirs", + "--quiet", + "--recursive", + os.path.join(directory, subdirectory, ""), + os.path.join(TARGET, ""), + ] + ) if commit: - subprocess.check_call(["git", "add", "--all", TARGET], stdout=subprocess.DEVNULL) - subprocess.check_call(["git", "commit", "-m", "Update SpiderMonkey"], stdout=subprocess.DEVNULL) + subprocess.check_call( + ["git", "add", "--all", TARGET], stdout=subprocess.DEVNULL + ) + subprocess.check_call( + ["git", "commit", "-s", "-m", "Update SpiderMonkey"], + stdout=subprocess.DEVNULL, + ) + def apply_patches(): print("Applying patches.") @@ -49,7 +59,11 @@ def apply_patches(): ) for p in patches: print(" Applying patch: %s." % p) - subprocess.check_call(["git", "apply", "--reject", "--directory=" + TARGET, p], stdout=subprocess.DEVNULL) + subprocess.check_call( + ["git", "apply", "--reject", "--directory=" + TARGET, p], + stdout=subprocess.DEVNULL, + ) + def main(args): extract = None @@ -67,6 +81,8 @@ def main(args): if patch: apply_patches() + if __name__ == "__main__": import sys + main(sys.argv[1:]) diff --git a/mozjs-sys/mozjs/.cargo/config.toml.in b/mozjs-sys/mozjs/.cargo/config.toml.in index 4b320cf6421..99400f9ccbb 100644 --- a/mozjs-sys/mozjs/.cargo/config.toml.in +++ b/mozjs-sys/mozjs/.cargo/config.toml.in @@ -65,9 +65,9 @@ git = "https://github.com/mozilla/application-services" rev = "7c275b9088557abcbc8f3c2834f9aaa9064ca5e4" replace-with = "vendored-sources" -[source."git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0"] +[source."git+https://github.com/mozilla/audioipc?branch=cherry-pick-firefox-128-129"] git = "https://github.com/mozilla/audioipc" -rev = "3495905752a4263827f5d43737f9ca3ed0243ce0" +branch = "cherry-pick-firefox-128-129" replace-with = "vendored-sources" [source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=8bce3b333a920999055397a397e59c2b81a93b9a"] diff --git a/mozjs-sys/mozjs/Cargo.lock b/mozjs-sys/mozjs/Cargo.lock index 409b94693d5..3d988de4b18 100644 --- a/mozjs-sys/mozjs/Cargo.lock +++ b/mozjs-sys/mozjs/Cargo.lock @@ -260,7 +260,7 @@ dependencies = [ [[package]] name = "audioipc2" version = "0.6.0" -source = "git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0#3495905752a4263827f5d43737f9ca3ed0243ce0" +source = "git+https://github.com/mozilla/audioipc?branch=cherry-pick-firefox-128-129#e1071472c55193032aa4c1403317844005f9d0fc" dependencies = [ "arrayvec", "ashmem", @@ -288,7 +288,7 @@ dependencies = [ [[package]] name = "audioipc2-client" version = "0.6.0" -source = "git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0#3495905752a4263827f5d43737f9ca3ed0243ce0" +source = "git+https://github.com/mozilla/audioipc?branch=cherry-pick-firefox-128-129#e1071472c55193032aa4c1403317844005f9d0fc" dependencies = [ "audio_thread_priority", "audioipc2", @@ -299,7 +299,7 @@ dependencies = [ [[package]] name = "audioipc2-server" version = "0.6.0" -source = "git+https://github.com/mozilla/audioipc?rev=3495905752a4263827f5d43737f9ca3ed0243ce0#3495905752a4263827f5d43737f9ca3ed0243ce0" +source = "git+https://github.com/mozilla/audioipc?branch=cherry-pick-firefox-128-129#e1071472c55193032aa4c1403317844005f9d0fc" dependencies = [ "audio_thread_priority", "audioipc2", @@ -7051,9 +7051,9 @@ dependencies = [ [[package]] name = "zerofrom" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d76c3251de27615dfcce21e636c172dafb2549cd7fd93e21c66f6ca6bea2" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] @@ -7072,9 +7072,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.10.1" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff4439ae91fb5c72b8abc12f3f2dbf51bd27e6eadb9f8a5bc8898dddb0e27ea" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" dependencies = [ "yoke", "zerofrom", @@ -7083,9 +7083,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", diff --git a/mozjs-sys/mozjs/build/clang-plugin/ThreadAllows.txt b/mozjs-sys/mozjs/build/clang-plugin/ThreadAllows.txt index 801e57504ff..f48e187d729 100644 --- a/mozjs-sys/mozjs/build/clang-plugin/ThreadAllows.txt +++ b/mozjs-sys/mozjs/build/clang-plugin/ThreadAllows.txt @@ -20,6 +20,9 @@ # Used by `nsUpdateProcessor` to check for updates. May also be used for polling # the update process. UpdateProcessor +# Used by `BackgroundClipboardContentAnalysisParent` to handle clipboard requests +# from content processes. +BkgrndClipboard ###### # Thunderbird-only thread names diff --git a/mozjs-sys/mozjs/build/debian-packages/valgrind.diff b/mozjs-sys/mozjs/build/debian-packages/valgrind.diff new file mode 100644 index 00000000000..096e9d7fc2a --- /dev/null +++ b/mozjs-sys/mozjs/build/debian-packages/valgrind.diff @@ -0,0 +1,121 @@ +diff -Nru valgrind-3.20.0/debian/changelog valgrind-3.20.0/debian/changelog +--- valgrind-3.20.0/debian/changelog 2023-01-11 00:51:40.000000000 +0900 ++++ valgrind-3.20.0/debian/changelog 2024-09-10 08:52:50.000000000 +0900 +@@ -1,3 +1,9 @@ ++valgrind (1:3.20.0-1moz1) UNRELEASED; urgency=medium ++ ++ * Apply fix for https://bugs.kde.org/show_bug.cgi?id=492663 ++ ++ -- Mike Hommey Tue, 10 Sep 2024 08:52:50 +0900 ++ + valgrind (1:3.20.0-1) experimental; urgency=medium + + * New upstream release. +diff -Nru valgrind-3.20.0/debian/patches/fix-upstream-bug492663 valgrind-3.20.0/debian/patches/fix-upstream-bug492663 +--- valgrind-3.20.0/debian/patches/fix-upstream-bug492663 1970-01-01 09:00:00.000000000 +0900 ++++ valgrind-3.20.0/debian/patches/fix-upstream-bug492663 2024-09-10 08:52:39.000000000 +0900 +@@ -0,0 +1,96 @@ ++--- valgrind-3.20.0.orig/coregrind/m_debuginfo/debuginfo.c +++++ valgrind-3.20.0/coregrind/m_debuginfo/debuginfo.c ++@@ -1073,7 +1073,8 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST ++ load_client -> VG_(do_exec) -> VG_(do_exec_inner) -> ++ exe_handlers->load_fn ( == VG_(load_ELF) ). ++ ++- This does the mmap'ing and creats the associated NSegments. +++ This does the mmap'ing with VG_(am_do_mmap_NO_NOTIFY) +++ and creates the associated NSegments. ++ ++ The NSegments may get merged, (see maybe_merge_nsegments) ++ so there could be more PT_LOADs than there are NSegments. ++@@ -1124,7 +1125,7 @@ static ULong di_notify_ACHIEVE_ACCEPT_ST ++ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) ++ { ++ NSegment const * seg; ++- Int rw_load_count; +++ Int expected_rw_load_count; ++ const HChar* filename; ++ Bool is_rx_map, is_rw_map, is_ro_map; ++ ++@@ -1348,9 +1349,9 @@ ULong VG_(di_notify_mmap)( Addr a, Bool ++ /* We're only interested in mappings of object files. */ ++ # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) ++ ++- rw_load_count = 0; +++ expected_rw_load_count = 0; ++ ++- elf_ok = ML_(check_elf_and_get_rw_loads) ( actual_fd, filename, &rw_load_count ); +++ elf_ok = ML_(check_elf_and_get_rw_loads) ( actual_fd, filename, &expected_rw_load_count, use_fd == -1 ); ++ ++ if (use_fd == -1) { ++ VG_(close)( actual_fd ); ++@@ -1363,7 +1364,7 @@ ULong VG_(di_notify_mmap)( Addr a, Bool ++ # elif defined(VGO_darwin) ++ if (!ML_(is_macho_object_file)( buf1k, (SizeT)sr_Res(preadres) )) ++ return 0; ++- rw_load_count = 1; +++ expected_rw_load_count = 1; ++ # else ++ # error "unknown OS" ++ # endif ++@@ -1423,8 +1424,8 @@ ULong VG_(di_notify_mmap)( Addr a, Bool ++ /* So, finally, are we in an accept state? */ ++ vg_assert(!di->have_dinfo); ++ if (di->fsm.have_rx_map && ++- rw_load_count >= 1 && ++- di->fsm.rw_map_count == rw_load_count) { +++ expected_rw_load_count >= 1 && +++ di->fsm.rw_map_count == expected_rw_load_count) { ++ /* Ok, so, finally, we found what we need, and we haven't ++ already read debuginfo for this object. So let's do so now. ++ Yee-ha! */ ++@@ -1437,7 +1438,8 @@ ULong VG_(di_notify_mmap)( Addr a, Bool ++ /* If we don't have an rx and rw mapping, go no further. */ ++ if (debug) ++ VG_(dmsg)("di_notify_mmap-6: " ++- "no dinfo loaded %s (no rx or no rw mapping)\n", filename); +++ "no dinfo loaded %s (no rx or rw mappings (%d) not reached expected count (%d))\n", +++ filename, di->fsm.rw_map_count, expected_rw_load_count); ++ return 0; ++ } ++ } ++--- valgrind-3.20.0.orig/coregrind/m_debuginfo/priv_readelf.h +++++ valgrind-3.20.0/coregrind/m_debuginfo/priv_readelf.h ++@@ -52,7 +52,8 @@ extern Bool ML_(is_elf_object_file)( con ++ */ ++ extern Bool ML_(read_elf_debug_info) ( DebugInfo* di ); ++ ++-extern Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_load_count ); +++extern Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, +++ Int * rw_load_count, Bool from_nsegments ); ++ ++ ++ #endif /* ndef __PRIV_READELF_H */ ++--- valgrind-3.20.0.orig/coregrind/m_debuginfo/readelf.c +++++ valgrind-3.20.0/coregrind/m_debuginfo/readelf.c ++@@ -3650,7 +3650,8 @@ Bool ML_(read_elf_debug_info) ( struct _ ++ /* NOTREACHED */ ++ } ++ ++-Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_load_count ) +++Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, +++ Int * rw_load_count, Bool from_nsegments ) ++ { ++ Bool res, ok; ++ UWord i; ++@@ -3719,7 +3720,7 @@ Bool ML_(check_elf_and_get_rw_loads) ( I ++ * second PT_LOAD falls exactly on 0x1000) then the NSegements ++ * will get merged and VG_(di_notify_mmap) only gets called once. */ ++ if (*rw_load_count == 2 && ++- ehdr_m.e_type == ET_EXEC && +++ from_nsegments && ++ a_phdr.p_offset == VG_PGROUNDDN(a_phdr.p_offset) ) ++ { ++ *rw_load_count = 1; +diff -Nru valgrind-3.20.0/debian/patches/series valgrind-3.20.0/debian/patches/series +--- valgrind-3.20.0/debian/patches/series 2022-11-11 00:49:21.000000000 +0900 ++++ valgrind-3.20.0/debian/patches/series 2024-09-10 08:52:21.000000000 +0900 +@@ -7,3 +7,4 @@ + 11_arm64-cache-flush.patch + 13_fix-path-to-vgdb.patch + armhf_neon.patch ++fix-upstream-bug492663 diff --git a/mozjs-sys/mozjs/build/moz.configure/libraries.configure b/mozjs-sys/mozjs/build/moz.configure/libraries.configure index 3c3c713a40f..26ca886f60f 100644 --- a/mozjs-sys/mozjs/build/moz.configure/libraries.configure +++ b/mozjs-sys/mozjs/build/moz.configure/libraries.configure @@ -131,7 +131,7 @@ with only_when(building_with_gnu_compatible_cc): is_libatomic_optional = check_std_atomic_requirements() is_libatomic_required = check_std_atomic_requirements( - flag="-latomic", when=~is_libatomic_optional + flag=["-latomic"], when=~is_libatomic_optional ) @depends(is_libatomic_optional, is_libatomic_required) diff --git a/mozjs-sys/mozjs/config/milestone.txt b/mozjs-sys/mozjs/config/milestone.txt index 329436732f1..58c8720643c 100644 --- a/mozjs-sys/mozjs/config/milestone.txt +++ b/mozjs-sys/mozjs/config/milestone.txt @@ -10,4 +10,4 @@ # hardcoded milestones in the tree from these two files. #-------------------------------------------------------- -128.0 +128.3.0 diff --git a/mozjs-sys/mozjs/js/public/GCHashTable.h b/mozjs-sys/mozjs/js/public/GCHashTable.h index ec8fe10c251..5d9b0e9c771 100644 --- a/mozjs-sys/mozjs/js/public/GCHashTable.h +++ b/mozjs-sys/mozjs/js/public/GCHashTable.h @@ -12,6 +12,7 @@ #include "js/GCPolicyAPI.h" #include "js/HashTable.h" #include "js/RootingAPI.h" +#include "js/SweepingAPI.h" #include "js/TypeDecls.h" class JSTracer; @@ -394,4 +395,412 @@ class MutableWrappedPtrOperations, Wrapper> } /* namespace js */ +namespace JS { + +// Specialize WeakCache for GCHashMap to provide a barriered map that does not +// need to be swept immediately. +template +class WeakCache< + GCHashMap> + final : protected detail::WeakCacheBase { + using Map = GCHashMap; + using Self = WeakCache; + + Map map; + JSTracer* barrierTracer = nullptr; + + public: + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), map(std::forward(args)...) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), map(std::forward(args)...) {} + ~WeakCache() { MOZ_ASSERT(!barrierTracer); } + + bool empty() override { return map.empty(); } + + size_t traceWeak(JSTracer* trc, NeedsLock needsLock) override { + size_t steps = map.count(); + + // Create an Enum and sweep the table entries. + mozilla::Maybe e; + e.emplace(map); + map.traceWeakEntries(trc, e.ref()); + + // Potentially take a lock while the Enum's destructor is called as this can + // rehash/resize the table and access the store buffer. + mozilla::Maybe lock; + if (needsLock) { + lock.emplace(trc->runtime()); + } + e.reset(); + + return steps; + } + + bool setIncrementalBarrierTracer(JSTracer* trc) override { + MOZ_ASSERT(bool(barrierTracer) != bool(trc)); + barrierTracer = trc; + return true; + } + + bool needsIncrementalBarrier() const override { return barrierTracer; } + + private: + using Entry = typename Map::Entry; + + static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& entry) { + return MapEntryGCPolicy::needsSweep(barrierTracer, &entry.key(), + &entry.value()); + } + + public: + using Lookup = typename Map::Lookup; + using Ptr = typename Map::Ptr; + using AddPtr = typename Map::AddPtr; + + // Iterator over the whole collection. + struct Range { + explicit Range(Self& self) : cache(self), range(self.map.all()) { + settle(); + } + Range() = default; + + bool empty() const { return range.empty(); } + const Entry& front() const { return range.front(); } + + void popFront() { + range.popFront(); + settle(); + } + + private: + Self& cache; + typename Map::Range range; + + void settle() { + if (JSTracer* trc = cache.barrierTracer) { + while (!empty() && entryNeedsSweep(trc, front())) { + popFront(); + } + } + } + }; + + struct Enum : public Map::Enum { + explicit Enum(Self& cache) : Map::Enum(cache.map) { + // This operation is not allowed while barriers are in place as we + // may also need to enumerate the set for sweeping. + MOZ_ASSERT(!cache.barrierTracer); + } + }; + + Ptr lookup(const Lookup& l) const { + Ptr ptr = map.lookup(l); + if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { + const_cast(map).remove(ptr); + return Ptr(); + } + return ptr; + } + + AddPtr lookupForAdd(const Lookup& l) { + AddPtr ptr = map.lookupForAdd(l); + if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { + const_cast(map).remove(ptr); + return map.lookupForAdd(l); + } + return ptr; + } + + Range all() const { return Range(*const_cast(this)); } + + bool empty() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the map and the caller expects a + // constant time operation. + MOZ_ASSERT(!barrierTracer); + return map.empty(); + } + + uint32_t count() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!barrierTracer); + return map.count(); + } + + size_t capacity() const { return map.capacity(); } + + bool has(const Lookup& l) const { return lookup(l).found(); } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return map.sizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + map.shallowSizeOfExcludingThis(mallocSizeOf); + } + + void clear() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!barrierTracer); + map.clear(); + } + + void clearAndCompact() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!barrierTracer); + map.clearAndCompact(); + } + + void remove(Ptr p) { + // This currently supports removing entries during incremental + // sweeping. If we allow these tables to be swept incrementally this may + // no longer be possible. + map.remove(p); + } + + void remove(const Lookup& l) { + Ptr p = lookup(l); + if (p) { + remove(p); + } + } + + template + bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map.add(p, std::forward(k), std::forward(v)); + } + + template + bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { + return map.relookupOrAdd(p, std::forward(k), + std::forward(v)); + } + + template + bool put(KeyInput&& k, ValueInput&& v) { + return map.put(std::forward(k), std::forward(v)); + } + + template + bool putNew(KeyInput&& k, ValueInput&& v) { + return map.putNew(std::forward(k), std::forward(v)); + } +} JS_HAZ_NON_GC_POINTER; + +// Specialize WeakCache for GCHashSet to provide a barriered set that does not +// need to be swept immediately. +template +class WeakCache> final + : protected detail::WeakCacheBase { + using Set = GCHashSet; + using Self = WeakCache; + + Set set; + JSTracer* barrierTracer = nullptr; + + public: + using Entry = typename Set::Entry; + + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), set(std::forward(args)...) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), set(std::forward(args)...) {} + + size_t traceWeak(JSTracer* trc, NeedsLock needsLock) override { + size_t steps = set.count(); + + // Create an Enum and sweep the table entries. It's not necessary to take + // the store buffer lock yet. + mozilla::Maybe e; + e.emplace(set); + set.traceWeakEntries(trc, e.ref()); + + // Destroy the Enum, potentially rehashing or resizing the table. Since this + // can access the store buffer, we need to take a lock for this if we're + // called off main thread. + mozilla::Maybe lock; + if (needsLock) { + lock.emplace(trc->runtime()); + } + e.reset(); + + return steps; + } + + bool empty() override { return set.empty(); } + + bool setIncrementalBarrierTracer(JSTracer* trc) override { + MOZ_ASSERT(bool(barrierTracer) != bool(trc)); + barrierTracer = trc; + return true; + } + + bool needsIncrementalBarrier() const override { return barrierTracer; } + + private: + static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& prior) { + Entry entry(prior); + bool needsSweep = !GCPolicy::traceWeak(barrierTracer, &entry); + MOZ_ASSERT_IF(!needsSweep, prior == entry); // We shouldn't update here. + return needsSweep; + } + + public: + using Lookup = typename Set::Lookup; + using Ptr = typename Set::Ptr; + using AddPtr = typename Set::AddPtr; + + // Iterator over the whole collection. + struct Range { + explicit Range(Self& self) : cache(self), range(self.set.all()) { + settle(); + } + Range() = default; + + bool empty() const { return range.empty(); } + const Entry& front() const { return range.front(); } + + void popFront() { + range.popFront(); + settle(); + } + + private: + Self& cache; + typename Set::Range range; + + void settle() { + if (JSTracer* trc = cache.barrierTracer) { + while (!empty() && entryNeedsSweep(trc, front())) { + popFront(); + } + } + } + }; + + struct Enum : public Set::Enum { + explicit Enum(Self& cache) : Set::Enum(cache.set) { + // This operation is not allowed while barriers are in place as we + // may also need to enumerate the set for sweeping. + MOZ_ASSERT(!cache.barrierTracer); + } + }; + + Ptr lookup(const Lookup& l) const { + Ptr ptr = set.lookup(l); + if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { + const_cast(set).remove(ptr); + return Ptr(); + } + return ptr; + } + + AddPtr lookupForAdd(const Lookup& l) { + AddPtr ptr = set.lookupForAdd(l); + if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { + const_cast(set).remove(ptr); + return set.lookupForAdd(l); + } + return ptr; + } + + Range all() const { return Range(*const_cast(this)); } + + bool empty() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!barrierTracer); + return set.empty(); + } + + uint32_t count() const { + // This operation is not currently allowed while barriers are in place + // as it would require iterating the set and the caller expects a + // constant time operation. + MOZ_ASSERT(!barrierTracer); + return set.count(); + } + + size_t capacity() const { return set.capacity(); } + + bool has(const Lookup& l) const { return lookup(l).found(); } + + size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return set.shallowSizeOfExcludingThis(mallocSizeOf); + } + size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { + return mallocSizeOf(this) + set.shallowSizeOfExcludingThis(mallocSizeOf); + } + + void clear() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!barrierTracer); + set.clear(); + } + + void clearAndCompact() { + // This operation is not currently allowed while barriers are in place + // since it doesn't make sense to clear a cache while it is being swept. + MOZ_ASSERT(!barrierTracer); + set.clearAndCompact(); + } + + void remove(Ptr p) { + // This currently supports removing entries during incremental + // sweeping. If we allow these tables to be swept incrementally this may + // no longer be possible. + set.remove(p); + } + + void remove(const Lookup& l) { + Ptr p = lookup(l); + if (p) { + remove(p); + } + } + + template + void replaceKey(Ptr p, const Lookup& l, TInput&& newValue) { + set.replaceKey(p, l, std::forward(newValue)); + } + + template + bool add(AddPtr& p, TInput&& t) { + return set.add(p, std::forward(t)); + } + + template + bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { + return set.relookupOrAdd(p, l, std::forward(t)); + } + + template + bool put(TInput&& t) { + return set.put(std::forward(t)); + } + + template + bool putNew(TInput&& t) { + return set.putNew(std::forward(t)); + } + + template + bool putNew(const Lookup& l, TInput&& t) { + return set.putNew(l, std::forward(t)); + } +} JS_HAZ_NON_GC_POINTER; + +} // namespace JS + #endif /* GCHashTable_h */ diff --git a/mozjs-sys/mozjs/js/public/StructuredClone.h b/mozjs-sys/mozjs/js/public/StructuredClone.h index 7fef48ee24b..ab151a3be56 100644 --- a/mozjs-sys/mozjs/js/public/StructuredClone.h +++ b/mozjs-sys/mozjs/js/public/StructuredClone.h @@ -745,6 +745,7 @@ class JS_PUBLIC_API JSAutoStructuredCloneBuffer { #define JS_SCERR_WASM_NO_TRANSFER 6 #define JS_SCERR_NOT_CLONABLE 7 #define JS_SCERR_NOT_CLONABLE_WITH_COOP_COEP 8 +#define JS_SCERR_TRANSFERABLE_TWICE 9 JS_PUBLIC_API bool JS_ReadUint32Pair(JSStructuredCloneReader* r, uint32_t* p1, uint32_t* p2); diff --git a/mozjs-sys/mozjs/js/public/SweepingAPI.h b/mozjs-sys/mozjs/js/public/SweepingAPI.h new file mode 100644 index 00000000000..4dc440b40bf --- /dev/null +++ b/mozjs-sys/mozjs/js/public/SweepingAPI.h @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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/. */ + +#ifndef js_SweepingAPI_h +#define js_SweepingAPI_h + +#include "mozilla/LinkedList.h" +#include "mozilla/Maybe.h" + +#include "jstypes.h" + +#include "js/GCAnnotations.h" +#include "js/GCPolicyAPI.h" +#include "js/RootingAPI.h" + +namespace js { +namespace gc { + +JS_PUBLIC_API void LockStoreBuffer(JSRuntime* runtime); +JS_PUBLIC_API void UnlockStoreBuffer(JSRuntime* runtim); + +class AutoLockStoreBuffer { + JSRuntime* runtime; + + public: + explicit AutoLockStoreBuffer(JSRuntime* runtime) : runtime(runtime) { + LockStoreBuffer(runtime); + } + ~AutoLockStoreBuffer() { UnlockStoreBuffer(runtime); } +}; + +} // namespace gc +} // namespace js + +namespace JS { +namespace detail { +class WeakCacheBase; +} // namespace detail + +namespace shadow { +JS_PUBLIC_API void RegisterWeakCache(JS::Zone* zone, + JS::detail::WeakCacheBase* cachep); +JS_PUBLIC_API void RegisterWeakCache(JSRuntime* rt, + JS::detail::WeakCacheBase* cachep); +} // namespace shadow + +namespace detail { + +class WeakCacheBase : public mozilla::LinkedListElement { + WeakCacheBase() = delete; + explicit WeakCacheBase(const WeakCacheBase&) = delete; + + public: + enum NeedsLock : bool { LockStoreBuffer = true, DontLockStoreBuffer = false }; + + explicit WeakCacheBase(JS::Zone* zone) { + shadow::RegisterWeakCache(zone, this); + } + explicit WeakCacheBase(JSRuntime* rt) { shadow::RegisterWeakCache(rt, this); } + WeakCacheBase(WeakCacheBase&& other) = default; + virtual ~WeakCacheBase() = default; + + virtual size_t traceWeak(JSTracer* trc, NeedsLock needLock) = 0; + + // Sweeping will be skipped if the cache is empty already. + virtual bool empty() = 0; + + // Enable/disable read barrier during incremental sweeping and set the tracer + // to use. + virtual bool setIncrementalBarrierTracer(JSTracer* trc) { + // Derived classes do not support incremental barriers by default. + return false; + } + virtual bool needsIncrementalBarrier() const { + // Derived classes do not support incremental barriers by default. + return false; + } +}; + +} // namespace detail + +// A WeakCache stores the given Sweepable container and links itself into a +// list of such caches that are swept during each GC. A WeakCache can be +// specific to a zone, or across a whole runtime, depending on which +// constructor is used. +template +class WeakCache : protected detail::WeakCacheBase, + public js::MutableWrappedPtrOperations> { + T cache; + + public: + using Type = T; + + template + explicit WeakCache(Zone* zone, Args&&... args) + : WeakCacheBase(zone), cache(std::forward(args)...) {} + template + explicit WeakCache(JSRuntime* rt, Args&&... args) + : WeakCacheBase(rt), cache(std::forward(args)...) {} + + const T& get() const { return cache; } + T& get() { return cache; } + + size_t traceWeak(JSTracer* trc, NeedsLock needsLock) override { + // Take the store buffer lock in case sweeping triggers any generational + // post barriers. This is not always required and WeakCache specializations + // may delay or skip taking the lock as appropriate. + mozilla::Maybe lock; + if (needsLock) { + lock.emplace(trc->runtime()); + } + + GCPolicy::traceWeak(trc, &cache); + return 0; + } + + bool empty() override { return cache.empty(); } +} JS_HAZ_NON_GC_POINTER; + +} // namespace JS + +#endif // js_SweepingAPI_h diff --git a/mozjs-sys/mozjs/js/public/friend/ErrorNumbers.msg b/mozjs-sys/mozjs/js/public/friend/ErrorNumbers.msg index 833d9463aa6..3155e3179e7 100644 --- a/mozjs-sys/mozjs/js/public/friend/ErrorNumbers.msg +++ b/mozjs-sys/mozjs/js/public/friend/ErrorNumbers.msg @@ -555,6 +555,7 @@ MSG_DEF(JSMSG_SC_BAD_CLONE_VERSION, 0, JSEXN_ERR, "unsupported structured clo MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})") MSG_DEF(JSMSG_SC_DUP_TRANSFERABLE, 0, JSEXN_TYPEERR, "duplicate transferable for structured clone") MSG_DEF(JSMSG_SC_NOT_TRANSFERABLE, 0, JSEXN_TYPEERR, "invalid transferable array for structured clone") +MSG_DEF(JSMSG_SC_TRANSFERABLE_TWICE, 0, JSEXN_TYPEERR, "structured clone cannot transfer twice") MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE, 0, JSEXN_TYPEERR, "unsupported type for structured data") MSG_DEF(JSMSG_SC_NOT_CLONABLE, 1, JSEXN_TYPEERR, "The {0} object cannot be serialized. The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP headers will enable this in the future.") MSG_DEF(JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP, 1, JSEXN_TYPEERR, "The {0} object cannot be serialized. The Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP headers can be used to enable this.") diff --git a/mozjs-sys/mozjs/js/src/build/Makefile.in b/mozjs-sys/mozjs/js/src/build/Makefile.in index d810384d412..99a2ffe3d4c 100644 --- a/mozjs-sys/mozjs/js/src/build/Makefile.in +++ b/mozjs-sys/mozjs/js/src/build/Makefile.in @@ -80,7 +80,7 @@ endif ifneq (,$(SHARED_LIBRARY)) $(SYSINSTALL) $(SHARED_LIBRARY) $(DESTDIR)$(libdir) ifeq ($(OS_ARCH),Darwin) - $(INSTALL_NAME_TOOL) -id $(abspath $(libdir)/$(SHARED_LIBRARY)) $(DESTDIR)$(libdir)/$(SHARED_LIBRARY) + $(INSTALL_NAME_TOOL) -id $(abspath $(libdir)/$(notdir $(SHARED_LIBRARY))) $(DESTDIR)$(libdir)/$(notdir $(SHARED_LIBRARY)) endif endif ifneq (,$(IMPORT_LIBRARY)) diff --git a/mozjs-sys/mozjs/js/src/gc/Compacting.cpp b/mozjs-sys/mozjs/js/src/gc/Compacting.cpp index 79e8e0b71d2..b42162b2e34 100644 --- a/mozjs-sys/mozjs/js/src/gc/Compacting.cpp +++ b/mozjs-sys/mozjs/js/src/gc/Compacting.cpp @@ -468,7 +468,7 @@ void GCRuntime::sweepZoneAfterCompacting(MovingTracer* trc, Zone* zone) { traceWeakFinalizationObserverEdges(trc, zone); for (auto* cache : zone->weakCaches()) { - cache->traceWeak(trc, WeakCacheBase::DontLockStoreBuffer); + cache->traceWeak(trc, JS::detail::WeakCacheBase::DontLockStoreBuffer); } if (jit::JitZone* jitZone = zone->jitZone()) { @@ -822,8 +822,8 @@ void GCRuntime::updateRuntimePointersToRelocatedCells(AutoGCSession& session) { // Sweep everything to fix up weak pointers. jit::JitRuntime::TraceWeakJitcodeGlobalTable(rt, &trc); - for (WeakCacheBase* cache : rt->weakCaches()) { - cache->traceWeak(&trc, WeakCacheBase::DontLockStoreBuffer); + for (JS::detail::WeakCacheBase* cache : rt->weakCaches()) { + cache->traceWeak(&trc, JS::detail::WeakCacheBase::DontLockStoreBuffer); } if (rt->hasJitRuntime() && rt->jitRuntime()->hasInterpreterEntryMap()) { diff --git a/mozjs-sys/mozjs/js/src/gc/GC.cpp b/mozjs-sys/mozjs/js/src/gc/GC.cpp index 7580c3e3618..5a077ce5571 100644 --- a/mozjs-sys/mozjs/js/src/gc/GC.cpp +++ b/mozjs-sys/mozjs/js/src/gc/GC.cpp @@ -3811,10 +3811,7 @@ void GCRuntime::incrementalSlice(SliceBudget& budget, JS::GCReason reason, case State::Mark: if (mightSweepInThisSlice(budget.isUnlimited())) { - // Trace wrapper rooters before marking if we might start sweeping in - // this slice. - rt->mainContextFromOwnThread()->traceWrapperGCRooters( - marker().tracer()); + prepareForSweepSlice(reason); // Incremental marking validation re-runs all marking non-incrementally, // which requires collecting the nursery. If that might happen in this @@ -3871,13 +3868,8 @@ void GCRuntime::incrementalSlice(SliceBudget& budget, JS::GCReason reason, [[fallthrough]]; case State::Sweep: - if (storeBuffer().mayHavePointersToDeadCells()) { - collectNurseryFromMajorGC(reason); - } - if (initialState == State::Sweep) { - rt->mainContextFromOwnThread()->traceWrapperGCRooters( - marker().tracer()); + prepareForSweepSlice(reason); } if (performSweepActions(budget) == NotFinished) { diff --git a/mozjs-sys/mozjs/js/src/gc/GCRuntime.h b/mozjs-sys/mozjs/js/src/gc/GCRuntime.h index 2c78c2cc2b2..122e5f3ebee 100644 --- a/mozjs-sys/mozjs/js/src/gc/GCRuntime.h +++ b/mozjs-sys/mozjs/js/src/gc/GCRuntime.h @@ -23,7 +23,6 @@ #include "gc/Scheduling.h" #include "gc/Statistics.h" #include "gc/StoreBuffer.h" -#include "gc/SweepingAPI.h" #include "js/friend/PerformanceHint.h" #include "js/GCAnnotations.h" #include "js/UniquePtr.h" @@ -236,11 +235,13 @@ class ZoneList { }; struct WeakCacheToSweep { - WeakCacheBase* cache; + JS::detail::WeakCacheBase* cache; JS::Zone* zone; }; class WeakCacheSweepIterator { + using WeakCacheBase = JS::detail::WeakCacheBase; + JS::Zone* sweepZone; WeakCacheBase* sweepCache; @@ -900,6 +901,7 @@ class GCRuntime { void sweepBackgroundThings(ZoneList& zones); void backgroundFinalize(JS::GCContext* gcx, Zone* zone, AllocKind kind, Arena** empty); + void prepareForSweepSlice(JS::GCReason reason); void assertBackgroundSweepingFinished(); bool allCCVisibleZonesWereCollected(); @@ -1249,7 +1251,8 @@ class GCRuntime { * used during shutdown GCs. In either case, unmarked objects may need to be * discarded. */ - WeakCache, 0, SystemAllocPolicy>> testMarkQueue; + JS::WeakCache, 0, SystemAllocPolicy>> + testMarkQueue; /* Position within the test mark queue. */ size_t queuePos = 0; diff --git a/mozjs-sys/mozjs/js/src/gc/Sweeping.cpp b/mozjs-sys/mozjs/js/src/gc/Sweeping.cpp index e0294294887..5afb4c9ee21 100644 --- a/mozjs-sys/mozjs/js/src/gc/Sweeping.cpp +++ b/mozjs-sys/mozjs/js/src/gc/Sweeping.cpp @@ -559,23 +559,32 @@ IncrementalProgress GCRuntime::markWeakReferencesInCurrentGroup( template IncrementalProgress GCRuntime::markGrayRoots(SliceBudget& budget, gcstats::PhaseKind phase) { - MOZ_ASSERT(marker().markColor() == MarkColor::Gray); + MOZ_ASSERT(marker().markColor() == MarkColor::Black); gcstats::AutoPhase ap(stats(), phase); - AutoUpdateLiveCompartments updateLive(this); - marker().setRootMarkingMode(true); - auto guard = - mozilla::MakeScopeExit([this]() { marker().setRootMarkingMode(false); }); + { + AutoSetMarkColor setColorGray(marker(), MarkColor::Gray); - IncrementalProgress result = - traceEmbeddingGrayRoots(marker().tracer(), budget); - if (result == NotFinished) { - return NotFinished; + AutoUpdateLiveCompartments updateLive(this); + marker().setRootMarkingMode(true); + auto guard = mozilla::MakeScopeExit( + [this]() { marker().setRootMarkingMode(false); }); + + IncrementalProgress result = + traceEmbeddingGrayRoots(marker().tracer(), budget); + if (result == NotFinished) { + return NotFinished; + } + + Compartment::traceIncomingCrossCompartmentEdgesForZoneGC( + marker().tracer(), Compartment::GrayEdges); } + // Also mark any incoming cross compartment edges that were originally gray + // but have been marked black by a barrier. Compartment::traceIncomingCrossCompartmentEdgesForZoneGC( - marker().tracer(), Compartment::GrayEdges); + marker().tracer(), Compartment::BlackEdges); return Finished; } @@ -1122,8 +1131,6 @@ IncrementalProgress GCRuntime::markGrayRootsInCurrentGroup( JS::GCContext* gcx, SliceBudget& budget) { gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::MARK); - AutoSetMarkColor setColorGray(marker(), MarkColor::Gray); - return markGrayRoots(budget, gcstats::PhaseKind::MARK_GRAY); } @@ -1176,10 +1183,11 @@ IncrementalProgress GCRuntime::endMarkingSweepGroup(JS::GCContext* gcx, // Causes the given WeakCache to be swept when run. class ImmediateSweepWeakCacheTask : public GCParallelTask { Zone* zone; - WeakCacheBase& cache; + JS::detail::WeakCacheBase& cache; public: - ImmediateSweepWeakCacheTask(GCRuntime* gc, Zone* zone, WeakCacheBase& wc) + ImmediateSweepWeakCacheTask(GCRuntime* gc, Zone* zone, + JS::detail::WeakCacheBase& wc) : GCParallelTask(gc, gcstats::PhaseKind::SWEEP_WEAK_CACHES), zone(zone), cache(wc) {} @@ -1195,7 +1203,7 @@ class ImmediateSweepWeakCacheTask : public GCParallelTask { AutoUnlockHelperThreadState unlock(lock); AutoSetThreadIsSweeping threadIsSweeping(zone); SweepingTracer trc(gc->rt); - cache.traceWeak(&trc, WeakCacheBase::LockStoreBuffer); + cache.traceWeak(&trc, JS::detail::WeakCacheBase::LockStoreBuffer); } }; @@ -1420,14 +1428,14 @@ using WeakCacheTaskVector = template static inline bool IterateWeakCaches(JSRuntime* rt, Functor f) { for (SweepGroupZonesIter zone(rt); !zone.done(); zone.next()) { - for (WeakCacheBase* cache : zone->weakCaches()) { + for (JS::detail::WeakCacheBase* cache : zone->weakCaches()) { if (!f(cache, zone.get())) { return false; } } } - for (WeakCacheBase* cache : rt->weakCaches()) { + for (JS::detail::WeakCacheBase* cache : rt->weakCaches()) { if (!f(cache, nullptr)) { return false; } @@ -1444,18 +1452,19 @@ static bool PrepareWeakCacheTasks(JSRuntime* rt, MOZ_ASSERT(immediateTasks->empty()); GCRuntime* gc = &rt->gc; - bool ok = IterateWeakCaches(rt, [&](WeakCacheBase* cache, Zone* zone) { - if (cache->empty()) { - return true; - } + bool ok = + IterateWeakCaches(rt, [&](JS::detail::WeakCacheBase* cache, Zone* zone) { + if (cache->empty()) { + return true; + } - // Caches that support incremental sweeping will be swept later. - if (zone && cache->setIncrementalBarrierTracer(&gc->sweepingTracer)) { - return true; - } + // Caches that support incremental sweeping will be swept later. + if (zone && cache->setIncrementalBarrierTracer(&gc->sweepingTracer)) { + return true; + } - return immediateTasks->emplaceBack(gc, zone, *cache); - }); + return immediateTasks->emplaceBack(gc, zone, *cache); + }); if (!ok) { immediateTasks->clearAndFree(); @@ -1468,11 +1477,11 @@ static void SweepAllWeakCachesOnMainThread(JSRuntime* rt) { // If we ran out of memory, do all the work on the main thread. gcstats::AutoPhase ap(rt->gc.stats(), gcstats::PhaseKind::SWEEP_WEAK_CACHES); SweepingTracer trc(rt); - IterateWeakCaches(rt, [&](WeakCacheBase* cache, Zone* zone) { + IterateWeakCaches(rt, [&](JS::detail::WeakCacheBase* cache, Zone* zone) { if (cache->needsIncrementalBarrier()) { cache->setIncrementalBarrierTracer(nullptr); } - cache->traceWeak(&trc, WeakCacheBase::LockStoreBuffer); + cache->traceWeak(&trc, JS::detail::WeakCacheBase::LockStoreBuffer); return true; }); } @@ -1875,11 +1884,12 @@ static size_t IncrementalSweepWeakCache(GCRuntime* gc, const WeakCacheToSweep& item) { AutoSetThreadIsSweeping threadIsSweeping(item.zone); - WeakCacheBase* cache = item.cache; + JS::detail::WeakCacheBase* cache = item.cache; MOZ_ASSERT(cache->needsIncrementalBarrier()); SweepingTracer trc(gc->rt); - size_t steps = cache->traceWeak(&trc, WeakCacheBase::LockStoreBuffer); + size_t steps = + cache->traceWeak(&trc, JS::detail::WeakCacheBase::LockStoreBuffer); cache->setIncrementalBarrierTracer(nullptr); return steps; @@ -2320,7 +2330,26 @@ bool GCRuntime::initSweepActions() { return sweepActions != nullptr; } +void GCRuntime::prepareForSweepSlice(JS::GCReason reason) { + // Work that must be done at the start of each slice where we sweep. + // + // Since this must happen at the start of the slice, it must be called in + // marking slices before any sweeping happens. Therefore it is called + // conservatively since we may not always transition to sweeping from marking. + + // Clear out whole cell store buffer entries to unreachable cells. + if (storeBuffer().mayHavePointersToDeadCells()) { + collectNurseryFromMajorGC(reason); + } + + // Trace wrapper rooters before marking if we might start sweeping in + // this slice. + rt->mainContextFromOwnThread()->traceWrapperGCRooters(marker().tracer()); +} + IncrementalProgress GCRuntime::performSweepActions(SliceBudget& budget) { + MOZ_ASSERT(!storeBuffer().mayHavePointersToDeadCells()); + AutoMajorGCProfilerEntry s(this); gcstats::AutoPhase ap(stats(), gcstats::PhaseKind::SWEEP); @@ -2334,24 +2363,17 @@ IncrementalProgress GCRuntime::performSweepActions(SliceBudget& budget) { // Drain the mark stack, possibly in a parallel task if we're in a part of // sweeping that allows it. // - // In the first sweep slice where we must not yield to the mutator until we've - // starting sweeping a sweep group but in that case the stack must be empty - // already. + // The first time we enter the sweep phase we must not yield to the mutator + // until we've starting sweeping a sweep group but in that case the stack must + // be empty already. -#ifdef DEBUG MOZ_ASSERT(initialState <= State::Sweep); - if (initialState != State::Sweep) { - assertNoMarkingWork(); - } -#endif + bool startOfSweeping = initialState < State::Sweep; - if (initialState == State::Sweep) { - if (markDuringSweeping(gcx, budget) == NotFinished) { - return NotFinished; - } + if (startOfSweeping) { + assertNoMarkingWork(); } else { - budget.forceCheck(); - if (budget.isOverBudget()) { + if (markDuringSweeping(gcx, budget) == NotFinished) { return NotFinished; } } diff --git a/mozjs-sys/mozjs/js/src/gc/SweepingAPI.h b/mozjs-sys/mozjs/js/src/gc/SweepingAPI.h deleted file mode 100644 index 493713956fa..00000000000 --- a/mozjs-sys/mozjs/js/src/gc/SweepingAPI.h +++ /dev/null @@ -1,515 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * 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/. */ - -#ifndef js_SweepingAPI_h -#define js_SweepingAPI_h - -#include "mozilla/LinkedList.h" -#include "mozilla/Maybe.h" - -#include "jstypes.h" - -#include "js/GCAnnotations.h" -#include "js/GCHashTable.h" -#include "js/GCPolicyAPI.h" -#include "js/RootingAPI.h" - -namespace js { -namespace gc { - -JS_PUBLIC_API void LockStoreBuffer(JSRuntime* runtime); -JS_PUBLIC_API void UnlockStoreBuffer(JSRuntime* runtim); - -class AutoLockStoreBuffer { - JSRuntime* runtime; - - public: - explicit AutoLockStoreBuffer(JSRuntime* runtime) : runtime(runtime) { - LockStoreBuffer(runtime); - } - ~AutoLockStoreBuffer() { UnlockStoreBuffer(runtime); } -}; - -class WeakCacheBase; -JS_PUBLIC_API void RegisterWeakCache(JS::Zone* zone, WeakCacheBase* cachep); -JS_PUBLIC_API void RegisterWeakCache(JSRuntime* rt, WeakCacheBase* cachep); - -class WeakCacheBase : public mozilla::LinkedListElement { - WeakCacheBase() = delete; - explicit WeakCacheBase(const WeakCacheBase&) = delete; - - public: - enum NeedsLock : bool { LockStoreBuffer = true, DontLockStoreBuffer = false }; - - explicit WeakCacheBase(JS::Zone* zone) { RegisterWeakCache(zone, this); } - explicit WeakCacheBase(JSRuntime* rt) { RegisterWeakCache(rt, this); } - WeakCacheBase(WeakCacheBase&& other) = default; - virtual ~WeakCacheBase() = default; - - virtual size_t traceWeak(JSTracer* trc, NeedsLock needLock) = 0; - - // Sweeping will be skipped if the cache is empty already. - virtual bool empty() = 0; - - // Enable/disable read barrier during incremental sweeping and set the tracer - // to use. - virtual bool setIncrementalBarrierTracer(JSTracer* trc) { - // Derived classes do not support incremental barriers by default. - return false; - } - virtual bool needsIncrementalBarrier() const { - // Derived classes do not support incremental barriers by default. - return false; - } -}; - -} // namespace gc - -// A WeakCache stores the given Sweepable container and links itself into a -// list of such caches that are swept during each GC. A WeakCache can be -// specific to a zone, or across a whole runtime, depending on which -// constructor is used. -template -class WeakCache : protected gc::WeakCacheBase, - public js::MutableWrappedPtrOperations> { - T cache; - - public: - using Type = T; - - template - explicit WeakCache(Zone* zone, Args&&... args) - : WeakCacheBase(zone), cache(std::forward(args)...) {} - template - explicit WeakCache(JSRuntime* rt, Args&&... args) - : WeakCacheBase(rt), cache(std::forward(args)...) {} - - const T& get() const { return cache; } - T& get() { return cache; } - - size_t traceWeak(JSTracer* trc, NeedsLock needsLock) override { - // Take the store buffer lock in case sweeping triggers any generational - // post barriers. This is not always required and WeakCache specializations - // may delay or skip taking the lock as appropriate. - mozilla::Maybe lock; - if (needsLock) { - lock.emplace(trc->runtime()); - } - - JS::GCPolicy::traceWeak(trc, &cache); - return 0; - } - - bool empty() override { return cache.empty(); } -} JS_HAZ_NON_GC_POINTER; - -// Specialize WeakCache for GCHashMap to provide a barriered map that does not -// need to be swept immediately. -template -class WeakCache< - GCHashMap> - final : protected gc::WeakCacheBase { - using Map = GCHashMap; - using Self = WeakCache; - - Map map; - JSTracer* barrierTracer = nullptr; - - public: - template - explicit WeakCache(Zone* zone, Args&&... args) - : WeakCacheBase(zone), map(std::forward(args)...) {} - template - explicit WeakCache(JSRuntime* rt, Args&&... args) - : WeakCacheBase(rt), map(std::forward(args)...) {} - ~WeakCache() { MOZ_ASSERT(!barrierTracer); } - - bool empty() override { return map.empty(); } - - size_t traceWeak(JSTracer* trc, NeedsLock needsLock) override { - size_t steps = map.count(); - - // Create an Enum and sweep the table entries. - mozilla::Maybe e; - e.emplace(map); - map.traceWeakEntries(trc, e.ref()); - - // Potentially take a lock while the Enum's destructor is called as this can - // rehash/resize the table and access the store buffer. - mozilla::Maybe lock; - if (needsLock) { - lock.emplace(trc->runtime()); - } - e.reset(); - - return steps; - } - - bool setIncrementalBarrierTracer(JSTracer* trc) override { - MOZ_ASSERT(bool(barrierTracer) != bool(trc)); - barrierTracer = trc; - return true; - } - - bool needsIncrementalBarrier() const override { return barrierTracer; } - - private: - using Entry = typename Map::Entry; - - static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& entry) { - return MapEntryGCPolicy::needsSweep(barrierTracer, &entry.key(), - &entry.value()); - } - - public: - using Lookup = typename Map::Lookup; - using Ptr = typename Map::Ptr; - using AddPtr = typename Map::AddPtr; - - // Iterator over the whole collection. - struct Range { - explicit Range(Self& self) : cache(self), range(self.map.all()) { - settle(); - } - Range() = default; - - bool empty() const { return range.empty(); } - const Entry& front() const { return range.front(); } - - void popFront() { - range.popFront(); - settle(); - } - - private: - Self& cache; - typename Map::Range range; - - void settle() { - if (JSTracer* trc = cache.barrierTracer) { - while (!empty() && entryNeedsSweep(trc, front())) { - popFront(); - } - } - } - }; - - struct Enum : public Map::Enum { - explicit Enum(Self& cache) : Map::Enum(cache.map) { - // This operation is not allowed while barriers are in place as we - // may also need to enumerate the set for sweeping. - MOZ_ASSERT(!cache.barrierTracer); - } - }; - - Ptr lookup(const Lookup& l) const { - Ptr ptr = map.lookup(l); - if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { - const_cast(map).remove(ptr); - return Ptr(); - } - return ptr; - } - - AddPtr lookupForAdd(const Lookup& l) { - AddPtr ptr = map.lookupForAdd(l); - if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { - const_cast(map).remove(ptr); - return map.lookupForAdd(l); - } - return ptr; - } - - Range all() const { return Range(*const_cast(this)); } - - bool empty() const { - // This operation is not currently allowed while barriers are in place - // as it would require iterating the map and the caller expects a - // constant time operation. - MOZ_ASSERT(!barrierTracer); - return map.empty(); - } - - uint32_t count() const { - // This operation is not currently allowed while barriers are in place - // as it would require iterating the set and the caller expects a - // constant time operation. - MOZ_ASSERT(!barrierTracer); - return map.count(); - } - - size_t capacity() const { return map.capacity(); } - - bool has(const Lookup& l) const { return lookup(l).found(); } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return map.sizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + map.shallowSizeOfExcludingThis(mallocSizeOf); - } - - void clear() { - // This operation is not currently allowed while barriers are in place - // since it doesn't make sense to clear a cache while it is being swept. - MOZ_ASSERT(!barrierTracer); - map.clear(); - } - - void clearAndCompact() { - // This operation is not currently allowed while barriers are in place - // since it doesn't make sense to clear a cache while it is being swept. - MOZ_ASSERT(!barrierTracer); - map.clearAndCompact(); - } - - void remove(Ptr p) { - // This currently supports removing entries during incremental - // sweeping. If we allow these tables to be swept incrementally this may - // no longer be possible. - map.remove(p); - } - - void remove(const Lookup& l) { - Ptr p = lookup(l); - if (p) { - remove(p); - } - } - - template - bool add(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map.add(p, std::forward(k), std::forward(v)); - } - - template - bool relookupOrAdd(AddPtr& p, KeyInput&& k, ValueInput&& v) { - return map.relookupOrAdd(p, std::forward(k), - std::forward(v)); - } - - template - bool put(KeyInput&& k, ValueInput&& v) { - return map.put(std::forward(k), std::forward(v)); - } - - template - bool putNew(KeyInput&& k, ValueInput&& v) { - return map.putNew(std::forward(k), std::forward(v)); - } -} JS_HAZ_NON_GC_POINTER; - -// Specialize WeakCache for GCHashSet to provide a barriered set that does not -// need to be swept immediately. -template -class WeakCache> final - : protected gc::WeakCacheBase { - using Set = GCHashSet; - using Self = WeakCache; - - Set set; - JSTracer* barrierTracer = nullptr; - - public: - using Entry = typename Set::Entry; - - template - explicit WeakCache(Zone* zone, Args&&... args) - : WeakCacheBase(zone), set(std::forward(args)...) {} - template - explicit WeakCache(JSRuntime* rt, Args&&... args) - : WeakCacheBase(rt), set(std::forward(args)...) {} - - size_t traceWeak(JSTracer* trc, NeedsLock needsLock) override { - size_t steps = set.count(); - - // Create an Enum and sweep the table entries. It's not necessary to take - // the store buffer lock yet. - mozilla::Maybe e; - e.emplace(set); - set.traceWeakEntries(trc, e.ref()); - - // Destroy the Enum, potentially rehashing or resizing the table. Since this - // can access the store buffer, we need to take a lock for this if we're - // called off main thread. - mozilla::Maybe lock; - if (needsLock) { - lock.emplace(trc->runtime()); - } - e.reset(); - - return steps; - } - - bool empty() override { return set.empty(); } - - bool setIncrementalBarrierTracer(JSTracer* trc) override { - MOZ_ASSERT(bool(barrierTracer) != bool(trc)); - barrierTracer = trc; - return true; - } - - bool needsIncrementalBarrier() const override { return barrierTracer; } - - private: - static bool entryNeedsSweep(JSTracer* barrierTracer, const Entry& prior) { - Entry entry(prior); - bool needsSweep = !JS::GCPolicy::traceWeak(barrierTracer, &entry); - MOZ_ASSERT_IF(!needsSweep, prior == entry); // We shouldn't update here. - return needsSweep; - } - - public: - using Lookup = typename Set::Lookup; - using Ptr = typename Set::Ptr; - using AddPtr = typename Set::AddPtr; - - // Iterator over the whole collection. - struct Range { - explicit Range(Self& self) : cache(self), range(self.set.all()) { - settle(); - } - Range() = default; - - bool empty() const { return range.empty(); } - const Entry& front() const { return range.front(); } - - void popFront() { - range.popFront(); - settle(); - } - - private: - Self& cache; - typename Set::Range range; - - void settle() { - if (JSTracer* trc = cache.barrierTracer) { - while (!empty() && entryNeedsSweep(trc, front())) { - popFront(); - } - } - } - }; - - struct Enum : public Set::Enum { - explicit Enum(Self& cache) : Set::Enum(cache.set) { - // This operation is not allowed while barriers are in place as we - // may also need to enumerate the set for sweeping. - MOZ_ASSERT(!cache.barrierTracer); - } - }; - - Ptr lookup(const Lookup& l) const { - Ptr ptr = set.lookup(l); - if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { - const_cast(set).remove(ptr); - return Ptr(); - } - return ptr; - } - - AddPtr lookupForAdd(const Lookup& l) { - AddPtr ptr = set.lookupForAdd(l); - if (barrierTracer && ptr && entryNeedsSweep(barrierTracer, *ptr)) { - const_cast(set).remove(ptr); - return set.lookupForAdd(l); - } - return ptr; - } - - Range all() const { return Range(*const_cast(this)); } - - bool empty() const { - // This operation is not currently allowed while barriers are in place - // as it would require iterating the set and the caller expects a - // constant time operation. - MOZ_ASSERT(!barrierTracer); - return set.empty(); - } - - uint32_t count() const { - // This operation is not currently allowed while barriers are in place - // as it would require iterating the set and the caller expects a - // constant time operation. - MOZ_ASSERT(!barrierTracer); - return set.count(); - } - - size_t capacity() const { return set.capacity(); } - - bool has(const Lookup& l) const { return lookup(l).found(); } - - size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return set.shallowSizeOfExcludingThis(mallocSizeOf); - } - size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const { - return mallocSizeOf(this) + set.shallowSizeOfExcludingThis(mallocSizeOf); - } - - void clear() { - // This operation is not currently allowed while barriers are in place - // since it doesn't make sense to clear a cache while it is being swept. - MOZ_ASSERT(!barrierTracer); - set.clear(); - } - - void clearAndCompact() { - // This operation is not currently allowed while barriers are in place - // since it doesn't make sense to clear a cache while it is being swept. - MOZ_ASSERT(!barrierTracer); - set.clearAndCompact(); - } - - void remove(Ptr p) { - // This currently supports removing entries during incremental - // sweeping. If we allow these tables to be swept incrementally this may - // no longer be possible. - set.remove(p); - } - - void remove(const Lookup& l) { - Ptr p = lookup(l); - if (p) { - remove(p); - } - } - - template - void replaceKey(Ptr p, const Lookup& l, TInput&& newValue) { - set.replaceKey(p, l, std::forward(newValue)); - } - - template - bool add(AddPtr& p, TInput&& t) { - return set.add(p, std::forward(t)); - } - - template - bool relookupOrAdd(AddPtr& p, const Lookup& l, TInput&& t) { - return set.relookupOrAdd(p, l, std::forward(t)); - } - - template - bool put(TInput&& t) { - return set.put(std::forward(t)); - } - - template - bool putNew(TInput&& t) { - return set.putNew(std::forward(t)); - } - - template - bool putNew(const Lookup& l, TInput&& t) { - return set.putNew(l, std::forward(t)); - } -} JS_HAZ_NON_GC_POINTER; - -} // namespace js - -#endif // js_SweepingAPI_h diff --git a/mozjs-sys/mozjs/js/src/gc/Verifier.cpp b/mozjs-sys/mozjs/js/src/gc/Verifier.cpp index 8191af34b0f..aa9de492b77 100644 --- a/mozjs-sys/mozjs/js/src/gc/Verifier.cpp +++ b/mozjs-sys/mozjs/js/src/gc/Verifier.cpp @@ -617,9 +617,13 @@ void js::gc::MarkingValidator::nonIncrementalMark(AutoGCSession& session) { zone->changeGCState(zone->initialMarkingState(), Zone::MarkBlackAndGray); } - AutoSetMarkColor setColorGray(*gcmarker, MarkColor::Gray); - + /* + * markAllGrayReferences may mark both gray and black, so it manages the + * mark color internally. + */ gc->markAllGrayReferences(gcstats::PhaseKind::MARK_GRAY); + + AutoSetMarkColor setColorGray(*gcmarker, MarkColor::Gray); gc->markAllWeakReferences(); /* Restore zone state. */ diff --git a/mozjs-sys/mozjs/js/src/gc/Zone.cpp b/mozjs-sys/mozjs/js/src/gc/Zone.cpp index 13324d7e436..e7c058dfd5e 100644 --- a/mozjs-sys/mozjs/js/src/gc/Zone.cpp +++ b/mozjs-sys/mozjs/js/src/gc/Zone.cpp @@ -780,8 +780,8 @@ void ZoneList::clear() { } } -JS_PUBLIC_API void js::gc::RegisterWeakCache(JS::Zone* zone, - WeakCacheBase* cachep) { +JS_PUBLIC_API void JS::shadow::RegisterWeakCache( + JS::Zone* zone, detail::WeakCacheBase* cachep) { zone->registerWeakCache(cachep); } diff --git a/mozjs-sys/mozjs/js/src/gc/Zone.h b/mozjs-sys/mozjs/js/src/gc/Zone.h index 60f5cbeee9d..81e55e53aab 100644 --- a/mozjs-sys/mozjs/js/src/gc/Zone.h +++ b/mozjs-sys/mozjs/js/src/gc/Zone.h @@ -78,7 +78,7 @@ class MissingAllocSites { using ScriptMap = JS::GCHashMap, SiteMap, StableCellHasher>, SystemAllocPolicy>; - WeakCache scriptMap; + JS::WeakCache scriptMap; explicit MissingAllocSites(JS::Zone* zone) : scriptMap(zone) {} }; @@ -468,7 +468,7 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase { // List of non-ephemeron weak containers to sweep during // beginSweepingSweepGroup. - js::MainThreadOrGCTaskData> + js::MainThreadOrGCTaskData> weakCaches_; // Mapping from not yet marked keys to a vector of all values that the key @@ -766,10 +766,10 @@ class Zone : public js::ZoneAllocator, public js::gc::GraphNodeBase { } } - mozilla::LinkedList& weakCaches() { + mozilla::LinkedList& weakCaches() { return weakCaches_.ref(); } - void registerWeakCache(js::gc::WeakCacheBase* cachep) { + void registerWeakCache(detail::WeakCacheBase* cachep) { weakCaches().insertBack(cachep); } diff --git a/mozjs-sys/mozjs/js/src/jit/BacktrackingAllocator.cpp b/mozjs-sys/mozjs/js/src/jit/BacktrackingAllocator.cpp index 8095107de1f..b6d23becf1f 100644 --- a/mozjs-sys/mozjs/js/src/jit/BacktrackingAllocator.cpp +++ b/mozjs-sys/mozjs/js/src/jit/BacktrackingAllocator.cpp @@ -1888,7 +1888,13 @@ bool BacktrackingAllocator::tryMergeBundles(LiveBundle* bundle0, // arguments through a lazy arguments object or rest parameter. if (IsArgumentSlotDefinition(reg0.def()) || IsArgumentSlotDefinition(reg1.def())) { - if (graph.mir().entryBlock()->info().mayReadFrameArgsDirectly()) { +#ifdef JS_PUNBOX64 + bool canSpillToArgSlots = + !graph.mir().entryBlock()->info().mayReadFrameArgsDirectly(); +#else + bool canSpillToArgSlots = false; +#endif + if (!canSpillToArgSlots) { if (*reg0.def()->output() != *reg1.def()->output()) { return true; } diff --git a/mozjs-sys/mozjs/js/src/jit/CacheIRCompiler.cpp b/mozjs-sys/mozjs/js/src/jit/CacheIRCompiler.cpp index ba3c8ed09ec..402365867c8 100644 --- a/mozjs-sys/mozjs/js/src/jit/CacheIRCompiler.cpp +++ b/mozjs-sys/mozjs/js/src/jit/CacheIRCompiler.cpp @@ -20,7 +20,6 @@ #include "builtin/DataViewObject.h" #include "builtin/Object.h" #include "gc/GCEnum.h" -#include "gc/SweepingAPI.h" // js::gc::AutoLockStoreBuffer #include "jit/BaselineCacheIRCompiler.h" #include "jit/CacheIRGenerator.h" #include "jit/IonCacheIRCompiler.h" @@ -33,6 +32,7 @@ #include "js/friend/DOMProxy.h" // JS::ExpandoAndGeneration #include "js/friend/XrayJitInfo.h" // js::jit::GetXrayJitInfo #include "js/ScalarType.h" // js::Scalar::Type +#include "js/SweepingAPI.h" #include "proxy/DOMProxy.h" #include "proxy/Proxy.h" #include "proxy/ScriptedProxyHandler.h" diff --git a/mozjs-sys/mozjs/js/src/jit/CodeGenerator.cpp b/mozjs-sys/mozjs/js/src/jit/CodeGenerator.cpp index 8c59f98b2b8..c998f9d3364 100644 --- a/mozjs-sys/mozjs/js/src/jit/CodeGenerator.cpp +++ b/mozjs-sys/mozjs/js/src/jit/CodeGenerator.cpp @@ -9361,7 +9361,8 @@ void CodeGenerator::visitWasmCall(LWasmCall* lir) { // Note the assembler offset and framePushed for use by the adjunct // LSafePoint, see visitor for LWasmCallIndirectAdjunctSafepoint below. - if (callee.which() == wasm::CalleeDesc::WasmTable) { + if (callee.which() == wasm::CalleeDesc::WasmTable || + callee.which() == wasm::CalleeDesc::FuncRef) { lir->adjunctSafepoint()->recordSafepointInfo(secondRetOffset, framePushedAtStackMapBase); } diff --git a/mozjs-sys/mozjs/js/src/jit/IonAnalysis.cpp b/mozjs-sys/mozjs/js/src/jit/IonAnalysis.cpp index 543ed0eb837..ea60be6a967 100644 --- a/mozjs-sys/mozjs/js/src/jit/IonAnalysis.cpp +++ b/mozjs-sys/mozjs/js/src/jit/IonAnalysis.cpp @@ -29,8 +29,9 @@ using MPhiUseIteratorStack = // Look for Phi uses with a depth-first search. If any uses are found the stack // of MPhi instructions is returned in the |worklist| argument. -static bool DepthFirstSearchUse(MIRGenerator* mir, - MPhiUseIteratorStack& worklist, MPhi* phi) { +[[nodiscard]] static bool DepthFirstSearchUse(MIRGenerator* mir, + MPhiUseIteratorStack& worklist, + MPhi* phi) { // Push a Phi and the next use to iterate over in the worklist. auto push = [&worklist](MPhi* phi, MUseIterator use) -> bool { phi->setInWorklist(); @@ -131,9 +132,9 @@ static bool DepthFirstSearchUse(MIRGenerator* mir, return true; } -static bool FlagPhiInputsAsImplicitlyUsed(MIRGenerator* mir, MBasicBlock* block, - MBasicBlock* succ, - MPhiUseIteratorStack& worklist) { +[[nodiscard]] static bool FlagPhiInputsAsImplicitlyUsed( + MIRGenerator* mir, MBasicBlock* block, MBasicBlock* succ, + MPhiUseIteratorStack& worklist) { // When removing an edge between 2 blocks, we might remove the ability of // later phases to figure out that the uses of a Phi should be considered as // a use of all its inputs. Thus we need to mark the Phi inputs as being @@ -265,7 +266,7 @@ static MInstructionIterator FindFirstInstructionAfterBail(MBasicBlock* block) { // Given an iterator pointing to the first removed instruction, mark // the operands of each removed instruction as having implicit uses. -static bool FlagOperandsAsImplicitlyUsedAfter( +[[nodiscard]] static bool FlagOperandsAsImplicitlyUsedAfter( MIRGenerator* mir, MBasicBlock* block, MInstructionIterator firstRemoved) { MOZ_ASSERT(firstRemoved->block() == block); @@ -312,8 +313,8 @@ static bool FlagOperandsAsImplicitlyUsedAfter( return true; } -static bool FlagEntryResumePointOperands(MIRGenerator* mir, - MBasicBlock* block) { +[[nodiscard]] static bool FlagEntryResumePointOperands(MIRGenerator* mir, + MBasicBlock* block) { // Flag observable operands of the entry resume point as having implicit uses. MResumePoint* rp = block->entryResumePoint(); while (rp) { @@ -334,8 +335,8 @@ static bool FlagEntryResumePointOperands(MIRGenerator* mir, return true; } -static bool FlagAllOperandsAsImplicitlyUsed(MIRGenerator* mir, - MBasicBlock* block) { +[[nodiscard]] static bool FlagAllOperandsAsImplicitlyUsed(MIRGenerator* mir, + MBasicBlock* block) { return FlagEntryResumePointOperands(mir, block) && FlagOperandsAsImplicitlyUsedAfter(mir, block, block->begin()); } @@ -420,12 +421,16 @@ bool jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph) { if (!block->isMarked()) { // If we are removing the block entirely, mark the operands of every // instruction as being implicitly used. - FlagAllOperandsAsImplicitlyUsed(mir, block); + if (!FlagAllOperandsAsImplicitlyUsed(mir, block)) { + return false; + } } else if (block->alwaysBails()) { // If we are only trimming instructions after a bail, only mark operands // of removed instructions. MInstructionIterator firstRemoved = FindFirstInstructionAfterBail(block); - FlagOperandsAsImplicitlyUsedAfter(mir, block, firstRemoved); + if (!FlagOperandsAsImplicitlyUsedAfter(mir, block, firstRemoved)) { + return false; + } } } @@ -503,7 +508,8 @@ bool jit::PruneUnusedBranches(MIRGenerator* mir, MIRGraph& graph) { return true; } -static bool SplitCriticalEdgesForBlock(MIRGraph& graph, MBasicBlock* block) { +[[nodiscard]] static bool SplitCriticalEdgesForBlock(MIRGraph& graph, + MBasicBlock* block) { if (block->numSuccessors() < 2) { return true; } @@ -767,8 +773,8 @@ static bool IsDiamondPattern(MBasicBlock* initialBlock) { return true; } -static bool MaybeFoldDiamondConditionBlock(MIRGraph& graph, - MBasicBlock* initialBlock) { +[[nodiscard]] static bool MaybeFoldDiamondConditionBlock( + MIRGraph& graph, MBasicBlock* initialBlock) { MOZ_ASSERT(IsDiamondPattern(initialBlock)); // Optimize the MIR graph to improve the code generated for conditional @@ -936,8 +942,8 @@ static bool IsTrianglePattern(MBasicBlock* initialBlock) { return false; } -static bool MaybeFoldTriangleConditionBlock(MIRGraph& graph, - MBasicBlock* initialBlock) { +[[nodiscard]] static bool MaybeFoldTriangleConditionBlock( + MIRGraph& graph, MBasicBlock* initialBlock) { MOZ_ASSERT(IsTrianglePattern(initialBlock)); // Optimize the MIR graph to improve the code generated for boolean @@ -1089,8 +1095,8 @@ static bool MaybeFoldTriangleConditionBlock(MIRGraph& graph, return true; } -static bool MaybeFoldConditionBlock(MIRGraph& graph, - MBasicBlock* initialBlock) { +[[nodiscard]] static bool MaybeFoldConditionBlock(MIRGraph& graph, + MBasicBlock* initialBlock) { if (IsDiamondPattern(initialBlock)) { return MaybeFoldDiamondConditionBlock(graph, initialBlock); } @@ -1100,7 +1106,8 @@ static bool MaybeFoldConditionBlock(MIRGraph& graph, return true; } -static bool MaybeFoldTestBlock(MIRGraph& graph, MBasicBlock* initialBlock) { +[[nodiscard]] static bool MaybeFoldTestBlock(MIRGraph& graph, + MBasicBlock* initialBlock) { // Handle test expressions on more than two inputs. For example // |if ((x > 10) && (y > 20) && (z > 30)) { ... }|, which results in the below // pattern. @@ -2984,7 +2991,9 @@ bool jit::RemoveUnmarkedBlocks(MIRGenerator* mir, MIRGraph& graph, continue; } - FlagAllOperandsAsImplicitlyUsed(mir, block); + if (!FlagAllOperandsAsImplicitlyUsed(mir, block)) { + return false; + } } // Find unmarked blocks and remove them. @@ -4236,8 +4245,8 @@ bool jit::EliminateRedundantShapeGuards(MIRGraph& graph) { return true; } -static bool TryEliminateGCBarriersForAllocation(TempAllocator& alloc, - MInstruction* allocation) { +[[nodiscard]] static bool TryEliminateGCBarriersForAllocation( + TempAllocator& alloc, MInstruction* allocation) { MOZ_ASSERT(allocation->type() == MIRType::Object); JitSpew(JitSpew_RedundantGCBarriers, "Analyzing allocation %s", diff --git a/mozjs-sys/mozjs/js/src/jit/JitFrames.cpp b/mozjs-sys/mozjs/js/src/jit/JitFrames.cpp index 69c259994e2..e4995fc30f8 100644 --- a/mozjs-sys/mozjs/js/src/jit/JitFrames.cpp +++ b/mozjs-sys/mozjs/js/src/jit/JitFrames.cpp @@ -688,11 +688,10 @@ static JitFrameLayout* GetLastProfilingFrame(ResumeFromException* rfe) { return nullptr; } -void HandleExceptionWasm(JSContext* cx, wasm::WasmFrameIter* iter, - ResumeFromException* rfe) { +static void HandleExceptionWasm(JSContext* cx, wasm::WasmFrameIter* iter, + ResumeFromException* rfe) { MOZ_ASSERT(cx->activation()->asJit()->hasWasmExitFP()); wasm::HandleThrow(cx, *iter, rfe); - MOZ_ASSERT(iter->done()); } void HandleException(ResumeFromException* rfe) { @@ -743,15 +742,15 @@ void HandleException(ResumeFromException* rfe) { if (iter.isWasm()) { prevJitFrame = nullptr; HandleExceptionWasm(cx, &iter.asWasm(), rfe); - // If a wasm try-catch handler is found, we can immediately jump to it - // and quit iterating through the stack. if (rfe->kind == ExceptionResumeKind::WasmCatch) { - return; - } - if (!iter.done()) { - ++iter; + // Jump to a Wasm try-catch handler. + MOZ_ASSERT(!iter.done()); + } else { + // Return to the Wasm entry frame. + MOZ_ASSERT(rfe->kind == ExceptionResumeKind::Wasm); + MOZ_ASSERT(iter.done()); } - continue; + return; } JSJitFrameIter& frame = iter.asJSJit(); diff --git a/mozjs-sys/mozjs/js/src/jit/Lowering.cpp b/mozjs-sys/mozjs/js/src/jit/Lowering.cpp index f84ed576b46..67dd1688988 100644 --- a/mozjs-sys/mozjs/js/src/jit/Lowering.cpp +++ b/mozjs-sys/mozjs/js/src/jit/Lowering.cpp @@ -6454,7 +6454,8 @@ void LIRGenerator::visitWasmCall(MWasmCallT ins) { // safepoint associated with them. Create a second safepoint here; the node // otherwise does nothing, and codegen for it only marks the safepoint at the // node. - if (ins->callee().which() == wasm::CalleeDesc::WasmTable && + if ((ins->callee().which() == wasm::CalleeDesc::WasmTable || + ins->callee().which() == wasm::CalleeDesc::FuncRef) && !ins->isWasmReturnCall()) { auto* adjunctSafepoint = new (alloc()) LWasmCallIndirectAdjunctSafepoint(); add(adjunctSafepoint); diff --git a/mozjs-sys/mozjs/js/src/jit/MacroAssembler.cpp b/mozjs-sys/mozjs/js/src/jit/MacroAssembler.cpp index dc1a98d544d..7676ae2ee77 100644 --- a/mozjs-sys/mozjs/js/src/jit/MacroAssembler.cpp +++ b/mozjs-sys/mozjs/js/src/jit/MacroAssembler.cpp @@ -5374,22 +5374,29 @@ struct ReturnCallTrampolineData { static ReturnCallTrampolineData MakeReturnCallTrampoline(MacroAssembler& masm) { uint32_t savedPushed = masm.framePushed(); - // Build simple trampoline code: load the instance slot from the frame, - // restore FP, and return to prevous caller. ReturnCallTrampolineData data; + + { +# if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) + AutoForbidPoolsAndNops afp(&masm, 1); +# elif defined(JS_CODEGEN_RISCV64) + BlockTrampolinePoolScope block_trampoline_pool(&masm, 1); +# endif + + // Build simple trampoline code: load the instance slot from the frame, + // restore FP, and return to prevous caller. # ifdef JS_CODEGEN_ARM - data.trampolineOffset = masm.currentOffset(); + data.trampolineOffset = masm.currentOffset(); # else - masm.bind(&data.trampoline); + masm.bind(&data.trampoline); # endif - masm.setFramePushed( - AlignBytes(wasm::FrameWithInstances::sizeOfInstanceFieldsAndShadowStack(), - WasmStackAlignment)); + masm.setFramePushed(AlignBytes( + wasm::FrameWithInstances::sizeOfInstanceFieldsAndShadowStack(), + WasmStackAlignment)); -# ifdef ENABLE_WASM_TAIL_CALLS - masm.wasmMarkSlowCall(); -# endif + masm.wasmMarkCallAsSlow(); + } masm.loadPtr( Address(masm.getStackPointer(), WasmCallerInstanceOffsetBeforeCall), @@ -5736,9 +5743,10 @@ CodeOffset MacroAssembler::wasmCallImport(const wasm::CallSiteDesc& desc, Address(getStackPointer(), WasmCalleeInstanceOffsetBeforeCall)); loadWasmPinnedRegsFromInstance(); - CodeOffset res = call(desc, ABINonArgReg0); #ifdef ENABLE_WASM_TAIL_CALLS - wasmMarkSlowCall(); + CodeOffset res = wasmMarkedSlowCall(desc, ABINonArgReg0); +#else + CodeOffset res = call(desc, ABINonArgReg0); #endif return res; } @@ -6002,9 +6010,10 @@ void MacroAssembler::wasmCallIndirect(const wasm::CallSiteDesc& desc, loadPtr(Address(calleeScratch, offsetof(wasm::FunctionTableElem, code)), calleeScratch); - *slowCallOffset = call(desc, calleeScratch); #ifdef ENABLE_WASM_TAIL_CALLS - wasmMarkSlowCall(); + *slowCallOffset = wasmMarkedSlowCall(desc, calleeScratch); +#else + *slowCallOffset = call(desc, calleeScratch); #endif // Restore registers and realm and join up with the fast path. @@ -6195,9 +6204,10 @@ void MacroAssembler::wasmCallRef(const wasm::CallSiteDesc& desc, FunctionExtended::WASM_FUNC_UNCHECKED_ENTRY_SLOT); loadPtr(Address(calleeFnObj, uncheckedEntrySlotOffset), calleeScratch); - *slowCallOffset = call(desc, calleeScratch); #ifdef ENABLE_WASM_TAIL_CALLS - wasmMarkSlowCall(); + *slowCallOffset = wasmMarkedSlowCall(desc, calleeScratch); +#else + *slowCallOffset = call(desc, calleeScratch); #endif // Restore registers and realm and back to this caller's. diff --git a/mozjs-sys/mozjs/js/src/jit/MacroAssembler.h b/mozjs-sys/mozjs/js/src/jit/MacroAssembler.h index b4ad95b86bb..2a294413a42 100644 --- a/mozjs-sys/mozjs/js/src/jit/MacroAssembler.h +++ b/mozjs-sys/mozjs/js/src/jit/MacroAssembler.h @@ -3900,8 +3900,14 @@ class MacroAssembler : public MacroAssemblerSpecific { Register temp2) DEFINED_ON(x86, x64, arm, arm64, loong64, mips64, riscv64); - void wasmMarkSlowCall() + // Places slow class marker for tail calls. + void wasmMarkCallAsSlow() DEFINED_ON(x86, x64, arm, arm64, loong64, mips64, riscv64); + + // Combines slow class marker with actual assembler call. + CodeOffset wasmMarkedSlowCall(const wasm::CallSiteDesc& desc, + const Register reg) + DEFINED_ON(x86_shared, arm, arm64, loong64, mips64, riscv64); #endif // WasmTableCallIndexReg must contain the index of the indirect call. This is diff --git a/mozjs-sys/mozjs/js/src/jit/arm/MacroAssembler-arm.cpp b/mozjs-sys/mozjs/js/src/jit/arm/MacroAssembler-arm.cpp index be8348a1fc4..b5f92ec5e43 100644 --- a/mozjs-sys/mozjs/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/mozjs-sys/mozjs/js/src/jit/arm/MacroAssembler-arm.cpp @@ -28,6 +28,7 @@ #include "vm/JitActivation.h" // js::jit::JitActivation #include "vm/JSContext.h" #include "vm/StringType.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -3540,15 +3541,7 @@ void MacroAssemblerARMCompat::handleFailureWithHandlerTail( // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - { - ScratchRegisterScope scratch(asMasm()); - ma_ldr(Address(sp, ResumeFromException::offsetOfTarget()), r1, scratch); - ma_ldr(Address(sp, ResumeFromException::offsetOfFramePointer()), r11, - scratch); - ma_ldr(Address(sp, ResumeFromException::offsetOfStackPointer()), sp, - scratch); - } - jump(r1); + wasm::GenerateJumpToCatchHandler(asMasm(), sp, r0, r1); } Assembler::Condition MacroAssemblerARMCompat::testStringTruthy( @@ -6097,7 +6090,7 @@ void MacroAssembler::shiftIndex32AndAdd(Register indexTemp32, int shift, } #ifdef ENABLE_WASM_TAIL_CALLS -void MacroAssembler::wasmMarkSlowCall() { ma_and(lr, lr, lr); } +void MacroAssembler::wasmMarkCallAsSlow() { ma_and(lr, lr, lr); } const int32_t SlowCallMarker = 0xe00ee00e; @@ -6110,6 +6103,14 @@ void MacroAssembler::wasmCheckSlowCallsite(Register ra, Label* notSlow, ma_cmp(temp2, temp1); j(Assembler::NotEqual, notSlow); } + +CodeOffset MacroAssembler::wasmMarkedSlowCall(const wasm::CallSiteDesc& desc, + const Register reg) { + AutoForbidPoolsAndNops afp(this, 2); + CodeOffset offset = call(desc, reg); + wasmMarkCallAsSlow(); + return offset; +} #endif // ENABLE_WASM_TAIL_CALLS //}}} check_macroassembler_style diff --git a/mozjs-sys/mozjs/js/src/jit/arm64/Architecture-arm64.h b/mozjs-sys/mozjs/js/src/jit/arm64/Architecture-arm64.h index 7101709f181..8b42e37fa90 100644 --- a/mozjs-sys/mozjs/js/src/jit/arm64/Architecture-arm64.h +++ b/mozjs-sys/mozjs/js/src/jit/arm64/Architecture-arm64.h @@ -485,20 +485,11 @@ class FloatRegisters { static_assert(ShiftSingle == 0, "Or the NonVolatileMask must be computed differently"); - // s31 is the ScratchFloatReg. static constexpr SetType NonVolatileSingleMask = SetType((1 << FloatRegisters::s8) | (1 << FloatRegisters::s9) | (1 << FloatRegisters::s10) | (1 << FloatRegisters::s11) | (1 << FloatRegisters::s12) | (1 << FloatRegisters::s13) | - (1 << FloatRegisters::s14) | (1 << FloatRegisters::s15) | - (1 << FloatRegisters::s16) | (1 << FloatRegisters::s17) | - (1 << FloatRegisters::s18) | (1 << FloatRegisters::s19) | - (1 << FloatRegisters::s20) | (1 << FloatRegisters::s21) | - (1 << FloatRegisters::s22) | (1 << FloatRegisters::s23) | - (1 << FloatRegisters::s24) | (1 << FloatRegisters::s25) | - (1 << FloatRegisters::s26) | (1 << FloatRegisters::s27) | - (1 << FloatRegisters::s28) | (1 << FloatRegisters::s29) | - (1 << FloatRegisters::s30)); + (1 << FloatRegisters::s14) | (1 << FloatRegisters::s15)); static constexpr SetType NonVolatileMask = (NonVolatileSingleMask << ShiftSingle) | diff --git a/mozjs-sys/mozjs/js/src/jit/arm64/MacroAssembler-arm64.cpp b/mozjs-sys/mozjs/js/src/jit/arm64/MacroAssembler-arm64.cpp index 511df5b4b2d..41a564adb3f 100644 --- a/mozjs-sys/mozjs/js/src/jit/arm64/MacroAssembler-arm64.cpp +++ b/mozjs-sys/mozjs/js/src/jit/arm64/MacroAssembler-arm64.cpp @@ -22,6 +22,7 @@ #include "vm/JitActivation.h" // js::jit::JitActivation #include "vm/JSContext.h" #include "vm/StringType.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -378,16 +379,7 @@ void MacroAssemblerCompat::handleFailureWithHandlerTail(Label* profilerExitTail, // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - loadPtr(Address(PseudoStackPointer, ResumeFromException::offsetOfTarget()), - r0); - loadPtr( - Address(PseudoStackPointer, ResumeFromException::offsetOfFramePointer()), - r29); - loadPtr( - Address(PseudoStackPointer, ResumeFromException::offsetOfStackPointer()), - PseudoStackPointer); - syncStackPtr(); - Br(x0); + wasm::GenerateJumpToCatchHandler(asMasm(), PseudoStackPointer, r0, r1); MOZ_ASSERT(GetStackPointer64().Is(PseudoStackPointer64)); } @@ -3414,7 +3406,7 @@ void MacroAssembler::shiftIndex32AndAdd(Register indexTemp32, int shift, } #ifdef ENABLE_WASM_TAIL_CALLS -void MacroAssembler::wasmMarkSlowCall() { Mov(x28, x28); } +void MacroAssembler::wasmMarkCallAsSlow() { Mov(x28, x28); } const int32_t SlowCallMarker = 0xaa1c03fc; @@ -3425,6 +3417,14 @@ void MacroAssembler::wasmCheckSlowCallsite(Register ra, Label* notSlow, Cmp(W(temp2), Operand(SlowCallMarker)); B(Assembler::NotEqual, notSlow); } + +CodeOffset MacroAssembler::wasmMarkedSlowCall(const wasm::CallSiteDesc& desc, + const Register reg) { + AutoForbidPoolsAndNops afp(this, !GetStackPointer64().Is(vixl::sp) ? 3 : 2); + CodeOffset offset = call(desc, reg); + wasmMarkCallAsSlow(); + return offset; +} #endif // ENABLE_WASM_TAIL_CALLS //}}} check_macroassembler_style diff --git a/mozjs-sys/mozjs/js/src/jit/loong64/MacroAssembler-loong64.cpp b/mozjs-sys/mozjs/js/src/jit/loong64/MacroAssembler-loong64.cpp index 1c07f7f91a0..d43dbdae880 100644 --- a/mozjs-sys/mozjs/js/src/jit/loong64/MacroAssembler-loong64.cpp +++ b/mozjs-sys/mozjs/js/src/jit/loong64/MacroAssembler-loong64.cpp @@ -18,6 +18,7 @@ #include "util/Memory.h" #include "vm/JitActivation.h" // js::jit::JitActivation #include "vm/JSContext.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -5486,12 +5487,7 @@ void MacroAssemblerLOONG64Compat::handleFailureWithHandlerTail( // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - loadPtr(Address(sp, ResumeFromException::offsetOfTarget()), a1); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()), - FramePointer); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()), - StackPointer); - jump(a1); + wasm::GenerateJumpToCatchHandler(asMasm(), sp, a1, a2); } CodeOffset MacroAssemblerLOONG64Compat::toggledJump(Label* label) { @@ -5529,7 +5525,7 @@ void MacroAssembler::shiftIndex32AndAdd(Register indexTemp32, int shift, } #ifdef ENABLE_WASM_TAIL_CALLS -void MacroAssembler::wasmMarkSlowCall() { mov(ra, ra); } +void MacroAssembler::wasmMarkCallAsSlow() { mov(ra, ra); } const int32_t SlowCallMarker = 0x03800021; // ori ra, ra, 0 @@ -5539,6 +5535,13 @@ void MacroAssembler::wasmCheckSlowCallsite(Register ra_, Label* notSlow, load32(Address(ra_, 0), temp2); branch32(Assembler::NotEqual, temp2, Imm32(SlowCallMarker), notSlow); } + +CodeOffset MacroAssembler::wasmMarkedSlowCall(const wasm::CallSiteDesc& desc, + const Register reg) { + CodeOffset offset = call(desc, reg); + wasmMarkCallAsSlow(); + return offset; +} #endif // ENABLE_WASM_TAIL_CALLS //}}} check_macroassembler_style diff --git a/mozjs-sys/mozjs/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/mozjs-sys/mozjs/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index debd3b67ff9..7a9fcf7c1b5 100644 --- a/mozjs-sys/mozjs/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/mozjs-sys/mozjs/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -22,6 +22,10 @@ void MacroAssembler::moveGPRToFloat32(Register src, FloatRegister dest) { moveToFloat32(src, dest); } +void MacroAssembler::move8ZeroExtend(Register src, Register dest) { + as_andi(dest, src, 0xff); +} + void MacroAssembler::move8SignExtend(Register src, Register dest) { ma_seb(dest, src); } diff --git a/mozjs-sys/mozjs/js/src/jit/mips32/MacroAssembler-mips32.cpp b/mozjs-sys/mozjs/js/src/jit/mips32/MacroAssembler-mips32.cpp index 747db537991..c15a7be7228 100644 --- a/mozjs-sys/mozjs/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/mozjs-sys/mozjs/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -21,6 +21,7 @@ #include "util/Memory.h" #include "vm/JitActivation.h" // js::jit::JitActivation #include "vm/JSContext.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -1898,12 +1899,7 @@ void MacroAssemblerMIPSCompat::handleFailureWithHandlerTail( // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - loadPtr(Address(sp, ResumeFromException::offsetOfTarget()), a1); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()), - FramePointer); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()), - StackPointer); - jump(a1); + wasm::GenerateJumpToCatchHandler(asMasm(), sp, a1, a2); } CodeOffset MacroAssemblerMIPSCompat::toggledJump(Label* label) { diff --git a/mozjs-sys/mozjs/js/src/jit/mips64/MacroAssembler-mips64.cpp b/mozjs-sys/mozjs/js/src/jit/mips64/MacroAssembler-mips64.cpp index 1530bfcbc8b..bd1b9022a40 100644 --- a/mozjs-sys/mozjs/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/mozjs-sys/mozjs/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -20,6 +20,7 @@ #include "util/Memory.h" #include "vm/JitActivation.h" // js::jit::JitActivation #include "vm/JSContext.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -1929,12 +1930,7 @@ void MacroAssemblerMIPS64Compat::handleFailureWithHandlerTail( // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - loadPtr(Address(sp, ResumeFromException::offsetOfTarget()), a1); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()), - FramePointer); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()), - StackPointer); - jump(a1); + wasm::GenerateJumpToCatchHandler(asMasm(), sp, a1, a2); } CodeOffset MacroAssemblerMIPS64Compat::toggledJump(Label* label) { @@ -2860,7 +2856,7 @@ void MacroAssembler::convertUInt64ToFloat32(Register64 src_, FloatRegister dest, } #ifdef ENABLE_WASM_TAIL_CALLS -void MacroAssembler::wasmMarkSlowCall() { mov(ra, ra); } +void MacroAssembler::wasmMarkCallAsSlow() { mov(ra, ra); } const int32_t SlowCallMarker = 0x37ff0000; // ori ra, ra, 0 @@ -2870,6 +2866,13 @@ void MacroAssembler::wasmCheckSlowCallsite(Register ra_, Label* notSlow, load32(Address(ra_, 0), temp2); branch32(Assembler::NotEqual, temp2, Imm32(SlowCallMarker), notSlow); } + +CodeOffset MacroAssembler::wasmMarkedSlowCall(const wasm::CallSiteDesc& desc, + const Register reg) { + CodeOffset offset = call(desc, reg); + wasmMarkCallAsSlow(); + return offset; +} #endif // ENABLE_WASM_TAIL_CALLS //}}} check_macroassembler_style diff --git a/mozjs-sys/mozjs/js/src/jit/mips64/MoveEmitter-mips64.cpp b/mozjs-sys/mozjs/js/src/jit/mips64/MoveEmitter-mips64.cpp index 53ee23820ae..70217a37f8d 100644 --- a/mozjs-sys/mozjs/js/src/jit/mips64/MoveEmitter-mips64.cpp +++ b/mozjs-sys/mozjs/js/src/jit/mips64/MoveEmitter-mips64.cpp @@ -30,7 +30,7 @@ void MoveEmitterMIPS64::breakCycle(const MoveOperand& from, masm.storeFloat32(to.floatReg(), cycleSlot(slotId)); } break; - case ABIType::Float64: + case MoveOp::DOUBLE: if (to.isMemory()) { FloatRegister temp = ScratchDoubleReg; masm.loadDouble(getAdjustedAddress(to), temp); @@ -85,7 +85,7 @@ void MoveEmitterMIPS64::completeCycle(const MoveOperand& from, masm.loadFloat32(cycleSlot(slotId), to.floatReg()); } break; - case ABIType::Float64: + case MoveOp::DOUBLE: if (to.isMemory()) { FloatRegister temp = ScratchDoubleReg; masm.loadDouble(cycleSlot(slotId), temp); diff --git a/mozjs-sys/mozjs/js/src/jit/riscv64/MacroAssembler-riscv64.cpp b/mozjs-sys/mozjs/js/src/jit/riscv64/MacroAssembler-riscv64.cpp index dc5721ea9f9..969acc9ec8b 100644 --- a/mozjs-sys/mozjs/js/src/jit/riscv64/MacroAssembler-riscv64.cpp +++ b/mozjs-sys/mozjs/js/src/jit/riscv64/MacroAssembler-riscv64.cpp @@ -20,6 +20,7 @@ #include "util/Memory.h" #include "vm/JitActivation.h" // jit::JitActivation #include "vm/JSContext.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -2061,12 +2062,7 @@ void MacroAssemblerRiscv64Compat::handleFailureWithHandlerTail( // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - loadPtr(Address(sp, ResumeFromException::offsetOfTarget()), a1); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfFramePointer()), - FramePointer); - loadPtr(Address(StackPointer, ResumeFromException::offsetOfStackPointer()), - StackPointer); - jump(a1); + wasm::GenerateJumpToCatchHandler(asMasm(), sp, a1, a2); } CodeOffset MacroAssemblerRiscv64Compat::toggledJump(Label* label) { @@ -4334,7 +4330,7 @@ void MacroAssembler::widenInt32(Register r) { } #ifdef ENABLE_WASM_TAIL_CALLS -void MacroAssembler::wasmMarkSlowCall() { mv(ra, ra); } +void MacroAssembler::wasmMarkCallAsSlow() { mv(ra, ra); } const int32_t SlowCallMarker = 0x8093; // addi ra, ra, 0 @@ -4344,6 +4340,14 @@ void MacroAssembler::wasmCheckSlowCallsite(Register ra_, Label* notSlow, load32(Address(ra_, 0), temp2); branch32(Assembler::NotEqual, temp2, Imm32(SlowCallMarker), notSlow); } + +CodeOffset MacroAssembler::wasmMarkedSlowCall(const wasm::CallSiteDesc& desc, + const Register reg) { + BlockTrampolinePoolScope block_trampoline_pool(this, 2); + CodeOffset offset = call(desc, reg); + wasmMarkCallAsSlow(); + return offset; +} #endif // ENABLE_WASM_TAIL_CALLS //}}} check_macroassembler_style diff --git a/mozjs-sys/mozjs/js/src/jit/x64/MacroAssembler-x64.cpp b/mozjs-sys/mozjs/js/src/jit/x64/MacroAssembler-x64.cpp index c42fe844f62..5ccfe60321e 100644 --- a/mozjs-sys/mozjs/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/mozjs-sys/mozjs/js/src/jit/x64/MacroAssembler-x64.cpp @@ -16,6 +16,7 @@ #include "vm/JitActivation.h" // js::jit::JitActivation #include "vm/JSContext.h" #include "vm/StringType.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" @@ -638,10 +639,7 @@ void MacroAssemblerX64::handleFailureWithHandlerTail(Label* profilerExitTail, // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - loadPtr(Address(rsp, ResumeFromException::offsetOfTarget()), rax); - loadPtr(Address(rsp, ResumeFromException::offsetOfFramePointer()), rbp); - loadPtr(Address(rsp, ResumeFromException::offsetOfStackPointer()), rsp); - jmp(Operand(rax)); + wasm::GenerateJumpToCatchHandler(asMasm(), rsp, rax, rbx); } void MacroAssemblerX64::profilerEnterFrame(Register framePtr, @@ -1656,7 +1654,7 @@ void MacroAssembler::wasmBoundsCheck64(Condition cond, Register64 index, } #ifdef ENABLE_WASM_TAIL_CALLS -void MacroAssembler::wasmMarkSlowCall() { +void MacroAssembler::wasmMarkCallAsSlow() { static_assert(InstanceReg == r14); orPtr(Imm32(0), r14); } diff --git a/mozjs-sys/mozjs/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/mozjs-sys/mozjs/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp index 15203212601..825c4488589 100644 --- a/mozjs-sys/mozjs/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp +++ b/mozjs-sys/mozjs/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp @@ -2151,4 +2151,13 @@ void MacroAssembler::shiftIndex32AndAdd(Register indexTemp32, int shift, addPtr(indexTemp32, pointer); } +#ifdef ENABLE_WASM_TAIL_CALLS +CodeOffset MacroAssembler::wasmMarkedSlowCall(const wasm::CallSiteDesc& desc, + const Register reg) { + CodeOffset offset = call(desc, reg); + wasmMarkCallAsSlow(); + return offset; +} +#endif // ENABLE_WASM_TAIL_CALLS + //}}} check_macroassembler_style diff --git a/mozjs-sys/mozjs/js/src/jit/x86/MacroAssembler-x86.cpp b/mozjs-sys/mozjs/js/src/jit/x86/MacroAssembler-x86.cpp index 5c4f1e9901a..9d3ca3a4b45 100644 --- a/mozjs-sys/mozjs/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/mozjs-sys/mozjs/js/src/jit/x86/MacroAssembler-x86.cpp @@ -21,6 +21,7 @@ #include "vm/JitActivation.h" // js::jit::JitActivation #include "vm/JSContext.h" #include "vm/StringType.h" +#include "wasm/WasmStubs.h" #include "jit/MacroAssembler-inl.h" #include "vm/JSScript-inl.h" @@ -643,10 +644,7 @@ void MacroAssemblerX86::handleFailureWithHandlerTail(Label* profilerExitTail, // Found a wasm catch handler, restore state and jump to it. bind(&wasmCatch); - loadPtr(Address(esp, ResumeFromException::offsetOfTarget()), eax); - loadPtr(Address(esp, ResumeFromException::offsetOfFramePointer()), ebp); - loadPtr(Address(esp, ResumeFromException::offsetOfStackPointer()), esp); - jmp(Operand(eax)); + wasm::GenerateJumpToCatchHandler(asMasm(), esp, eax, ebx); } void MacroAssemblerX86::profilerEnterFrame(Register framePtr, @@ -1879,7 +1877,7 @@ void MacroAssembler::wasmBoundsCheck64(Condition cond, Register64 index, } #ifdef ENABLE_WASM_TAIL_CALLS -void MacroAssembler::wasmMarkSlowCall() { +void MacroAssembler::wasmMarkCallAsSlow() { static_assert(esi == InstanceReg); or32(esi, esi); } diff --git a/mozjs-sys/mozjs/js/src/jsapi-tests/testGCWeakCache.cpp b/mozjs-sys/mozjs/js/src/jsapi-tests/testGCWeakCache.cpp index fd3d9f2c857..b90c216b5ec 100644 --- a/mozjs-sys/mozjs/js/src/jsapi-tests/testGCWeakCache.cpp +++ b/mozjs-sys/mozjs/js/src/jsapi-tests/testGCWeakCache.cpp @@ -6,10 +6,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "gc/Policy.h" -#include "gc/SweepingAPI.h" #include "gc/Zone.h" #include "js/GCHashTable.h" #include "js/RootingAPI.h" +#include "js/SweepingAPI.h" #include "jsapi-tests/tests.h" @@ -29,7 +29,7 @@ BEGIN_TEST(testWeakCacheSet) { using ObjectSet = GCHashSet, StableCellHasher>, SystemAllocPolicy>; - using Cache = WeakCache; + using Cache = JS::WeakCache; Cache cache(JS::GetObjectZone(tenured1)); cache.put(tenured1); @@ -68,7 +68,7 @@ BEGIN_TEST(testWeakCacheMap) { using ObjectMap = js::GCHashMap, uint32_t, js::StableCellHasher>>; - using Cache = WeakCache; + using Cache = JS::WeakCache; Cache cache(JS::GetObjectZone(tenured1), cx); cache.put(tenured1, 1); @@ -101,7 +101,7 @@ BEGIN_TEST(testWeakCacheMapWithUniquePtr) { using ObjectMap = js::GCHashMap, UniquePtr, js::StableCellHasher>>; - using Cache = WeakCache; + using Cache = JS::WeakCache; Cache cache(JS::GetObjectZone(tenured1), cx); cache.put(tenured1, MakeUnique(1)); @@ -136,7 +136,7 @@ BEGIN_TEST(testWeakCacheGCVector) { JS::RootedObject nursery1(cx, JS_NewPlainObject(cx)); JS::RootedObject nursery2(cx, JS_NewPlainObject(cx)); - using ObjectVector = WeakCache>>; + using ObjectVector = JS::WeakCache>>; ObjectVector cache(JS::GetObjectZone(tenured1), cx); CHECK(cache.append(tenured1)); @@ -313,7 +313,7 @@ bool TestSet() { using ObjectSet = GCHashSet, StableCellHasher>, TempAllocPolicy>; - using Cache = WeakCache; + using Cache = JS::WeakCache; Cache cache(JS::GetObjectZone(global), cx); // Sweep empty cache. @@ -442,7 +442,7 @@ bool TestMap() { using ObjectMap = GCHashMap, uint32_t, StableCellHasher>, TempAllocPolicy>; - using Cache = WeakCache; + using Cache = JS::WeakCache; Cache cache(JS::GetObjectZone(global), cx); // Sweep empty cache. @@ -573,7 +573,7 @@ bool TestReplaceDyingInSet() { // Test replacing dying entries with ones that have the same key using the // various APIs. - using Cache = WeakCache< + using Cache = JS::WeakCache< GCHashSet, TempAllocPolicy>>; Cache cache(JS::GetObjectZone(global), cx); @@ -632,8 +632,9 @@ bool TestReplaceDyingInMap() { // Test replacing dying entries with ones that have the same key using the // various APIs. - using Cache = WeakCache, - DefaultHasher, TempAllocPolicy>>; + using Cache = + JS::WeakCache, + DefaultHasher, TempAllocPolicy>>; Cache cache(JS::GetObjectZone(global), cx); RootedObject value1(cx, JS_NewPlainObject(cx)); @@ -695,7 +696,7 @@ bool TestUniqueIDLookups() { const size_t DeadFactor = 3; const size_t ObjectCount = 100; - using Cache = WeakCache< + using Cache = JS::WeakCache< GCHashSet, TempAllocPolicy>>; Cache cache(JS::GetObjectZone(global), cx); diff --git a/mozjs-sys/mozjs/js/src/jsapi-tests/testWasmReturnCalls.cpp b/mozjs-sys/mozjs/js/src/jsapi-tests/testWasmReturnCalls.cpp index ef06bf47105..b1e85569455 100644 --- a/mozjs-sys/mozjs/js/src/jsapi-tests/testWasmReturnCalls.cpp +++ b/mozjs-sys/mozjs/js/src/jsapi-tests/testWasmReturnCalls.cpp @@ -17,7 +17,7 @@ using namespace js::jit; #if defined(ENABLE_WASM_TAIL_CALLS) && !defined(JS_CODEGEN_NONE) -// Check if wasmMarkSlowCall produces the byte sequence that can +// Check if wasmMarkCallAsSlow produces the byte sequence that can // wasmCheckSlowCallsite detect. BEGIN_TEST(testWasmCheckSlowCallMarkerHit) { js::LifoAlloc lifo(4096); @@ -30,7 +30,7 @@ BEGIN_TEST(testWasmCheckSlowCallMarkerHit) { Label check, fail, end; masm.call(&check); - masm.wasmMarkSlowCall(); + masm.wasmMarkCallAsSlow(); masm.jump(&end); masm.bind(&check); diff --git a/mozjs-sys/mozjs/js/src/moz.build b/mozjs-sys/mozjs/js/src/moz.build index cddfb0c2f4d..95871835c0d 100755 --- a/mozjs-sys/mozjs/js/src/moz.build +++ b/mozjs-sys/mozjs/js/src/moz.build @@ -205,6 +205,7 @@ EXPORTS.js += [ "../public/StreamConsumer.h", "../public/String.h", "../public/StructuredClone.h", + "../public/SweepingAPI.h", "../public/Symbol.h", "../public/TelemetryTimers.h", "../public/TraceKind.h", diff --git a/mozjs-sys/mozjs/js/src/shell/js.cpp b/mozjs-sys/mozjs/js/src/shell/js.cpp index 907374858d4..020ca0f019e 100644 --- a/mozjs-sys/mozjs/js/src/shell/js.cpp +++ b/mozjs-sys/mozjs/js/src/shell/js.cpp @@ -163,6 +163,7 @@ #include "js/Stack.h" #include "js/StreamConsumer.h" #include "js/StructuredClone.h" +#include "js/SweepingAPI.h" #include "js/Transcoding.h" // JS::TranscodeBuffer, JS::TranscodeRange, JS::IsTranscodeFailureResult #include "js/Warnings.h" // JS::SetWarningReporter #include "js/WasmModule.h" // JS::WasmModule diff --git a/mozjs-sys/mozjs/js/src/shell/jsshell.h b/mozjs-sys/mozjs/js/src/shell/jsshell.h index d3dead8286c..190504b6c0f 100644 --- a/mozjs-sys/mozjs/js/src/shell/jsshell.h +++ b/mozjs-sys/mozjs/js/src/shell/jsshell.h @@ -180,7 +180,7 @@ class NonshrinkingGCObjectVector } }; -using MarkBitObservers = WeakCache; +using MarkBitObservers = JS::WeakCache; #ifdef SINGLESTEP_PROFILING using StackChars = Vector; diff --git a/mozjs-sys/mozjs/js/src/vm/Compartment.cpp b/mozjs-sys/mozjs/js/src/vm/Compartment.cpp index 749342b1670..f0353cf7f6c 100644 --- a/mozjs-sys/mozjs/js/src/vm/Compartment.cpp +++ b/mozjs-sys/mozjs/js/src/vm/Compartment.cpp @@ -470,13 +470,18 @@ bool Compartment::wrap(JSContext* cx, MutableHandle> vec) { static inline bool ShouldTraceWrapper(JSObject* wrapper, Compartment::EdgeSelector whichEdges) { - if (whichEdges == Compartment::AllEdges) { - return true; + switch (whichEdges) { + case Compartment::AllEdges: + return true; + case Compartment::NonGrayEdges: + return !wrapper->isMarkedGray(); + case Compartment::GrayEdges: + return wrapper->isMarkedGray(); + case Compartment::BlackEdges: + return wrapper->isMarkedBlack(); + default: + MOZ_CRASH("Unexpected EdgeSelector value"); } - - bool isGray = wrapper->isMarkedGray(); - return (whichEdges == Compartment::NonGrayEdges && !isGray) || - (whichEdges == Compartment::GrayEdges && isGray); } void Compartment::traceWrapperTargetsInCollectedZones(JSTracer* trc, diff --git a/mozjs-sys/mozjs/js/src/vm/Compartment.h b/mozjs-sys/mozjs/js/src/vm/Compartment.h index 6cea7a7c3db..34aaf2dd00c 100644 --- a/mozjs-sys/mozjs/js/src/vm/Compartment.h +++ b/mozjs-sys/mozjs/js/src/vm/Compartment.h @@ -417,7 +417,7 @@ class JS::Compartment { * dangling (full GCs naturally follow pointers across compartments) and * when compacting to update cross-compartment pointers. */ - enum EdgeSelector { AllEdges, NonGrayEdges, GrayEdges }; + enum EdgeSelector { AllEdges, NonGrayEdges, GrayEdges, BlackEdges }; void traceWrapperTargetsInCollectedZones(JSTracer* trc, EdgeSelector whichEdges); static void traceIncomingCrossCompartmentEdgesForZoneGC( diff --git a/mozjs-sys/mozjs/js/src/vm/Interpreter-inl.h b/mozjs-sys/mozjs/js/src/vm/Interpreter-inl.h index fce9e9c2cb0..0bbea04d117 100644 --- a/mozjs-sys/mozjs/js/src/vm/Interpreter-inl.h +++ b/mozjs-sys/mozjs/js/src/vm/Interpreter-inl.h @@ -125,7 +125,8 @@ inline bool FetchName(JSContext* cx, HandleObject receiver, HandleObject holder, } /* Take the slow path if shape was not found in a native object. */ - if (!receiver->is() || !holder->is()) { + if (!receiver->is() || !holder->is() || + receiver->is()) { Rooted id(cx, NameToId(name)); if (!GetProperty(cx, receiver, receiver, id, vp)) { return false; @@ -136,11 +137,8 @@ inline bool FetchName(JSContext* cx, HandleObject receiver, HandleObject holder, /* Fast path for Object instance properties. */ vp.set(holder->as().getSlot(propInfo.slot())); } else { - // Unwrap 'with' environments for reasons given in - // GetNameBoundInEnvironment. - RootedObject normalized(cx, MaybeUnwrapWithEnvironment(receiver)); RootedId id(cx, NameToId(name)); - if (!NativeGetExistingProperty(cx, normalized, holder.as(), + if (!NativeGetExistingProperty(cx, receiver, holder.as(), id, propInfo, vp)) { return false; } diff --git a/mozjs-sys/mozjs/js/src/vm/InvalidatingFuse.h b/mozjs-sys/mozjs/js/src/vm/InvalidatingFuse.h index b8760e8e0f5..103b026500f 100644 --- a/mozjs-sys/mozjs/js/src/vm/InvalidatingFuse.h +++ b/mozjs-sys/mozjs/js/src/vm/InvalidatingFuse.h @@ -8,7 +8,7 @@ #define vm_InvalidatingFuse_h #include "gc/Barrier.h" -#include "gc/SweepingAPI.h" +#include "js/SweepingAPI.h" #include "vm/GuardFuse.h" class JSScript; @@ -54,7 +54,7 @@ class DependentScriptSet { using WeakScriptSet = GCHashSet, StableCellHasher>, js::SystemAllocPolicy>; - js::WeakCache weakScripts; + JS::WeakCache weakScripts; }; class DependentScriptGroup { diff --git a/mozjs-sys/mozjs/js/src/vm/Realm.h b/mozjs-sys/mozjs/js/src/vm/Realm.h index 4518b4ced46..bc55ed714f6 100644 --- a/mozjs-sys/mozjs/js/src/vm/Realm.h +++ b/mozjs-sys/mozjs/js/src/vm/Realm.h @@ -240,7 +240,7 @@ class ObjectRealm { public: // Map from array buffers to views sharing that storage. - WeakCache innerViews; + JS::WeakCache innerViews; // Keep track of the metadata objects which can be associated with each JS // object. Both keys and values are in this realm. diff --git a/mozjs-sys/mozjs/js/src/vm/RegExpShared.h b/mozjs-sys/mozjs/js/src/vm/RegExpShared.h index 5aa17864b32..9cb6cc9e216 100644 --- a/mozjs-sys/mozjs/js/src/vm/RegExpShared.h +++ b/mozjs-sys/mozjs/js/src/vm/RegExpShared.h @@ -18,7 +18,6 @@ #include "gc/Barrier.h" #include "gc/Policy.h" -#include "gc/SweepingAPI.h" #include "gc/ZoneAllocator.h" #include "irregexp/RegExpTypes.h" #include "jit/JitCode.h" @@ -324,7 +323,7 @@ class RegExpZone { * The set of all RegExpShareds in the zone. On every GC, every RegExpShared * that was not marked is deleted and removed from the set. */ - using Set = WeakCache< + using Set = JS::WeakCache< JS::GCHashSet, Key, ZoneAllocPolicy>>; Set set_; diff --git a/mozjs-sys/mozjs/js/src/vm/Runtime.cpp b/mozjs-sys/mozjs/js/src/vm/Runtime.cpp index d894bf57bf0..83864e9d17f 100644 --- a/mozjs-sys/mozjs/js/src/vm/Runtime.cpp +++ b/mozjs-sys/mozjs/js/src/vm/Runtime.cpp @@ -798,8 +798,8 @@ JS_PUBLIC_API void JS::DisableRecordingAllocations(JSContext* cx) { cx->runtime()->stopRecordingAllocations(); } -JS_PUBLIC_API void js::gc::RegisterWeakCache(JSRuntime* rt, - gc::WeakCacheBase* cachep) { +JS_PUBLIC_API void JS::shadow::RegisterWeakCache( + JSRuntime* rt, detail::WeakCacheBase* cachep) { rt->registerWeakCache(cachep); } diff --git a/mozjs-sys/mozjs/js/src/vm/Runtime.h b/mozjs-sys/mozjs/js/src/vm/Runtime.h index 57d4fb14118..39e29d5deca 100644 --- a/mozjs-sys/mozjs/js/src/vm/Runtime.h +++ b/mozjs-sys/mozjs/js/src/vm/Runtime.h @@ -561,13 +561,14 @@ struct JSRuntime { private: // List of non-ephemeron weak containers to sweep during // beginSweepingSweepGroup. - js::MainThreadData> weakCaches_; + js::MainThreadData> + weakCaches_; public: - mozilla::LinkedList& weakCaches() { + mozilla::LinkedList& weakCaches() { return weakCaches_.ref(); } - void registerWeakCache(js::gc::WeakCacheBase* cachep) { + void registerWeakCache(JS::detail::WeakCacheBase* cachep) { weakCaches().insertBack(cachep); } diff --git a/mozjs-sys/mozjs/js/src/vm/ShapeZone.h b/mozjs-sys/mozjs/js/src/vm/ShapeZone.h index 9680af93d9a..43421e7d52e 100644 --- a/mozjs-sys/mozjs/js/src/vm/ShapeZone.h +++ b/mozjs-sys/mozjs/js/src/vm/ShapeZone.h @@ -10,7 +10,6 @@ #include "mozilla/MemoryReporting.h" #include "gc/Barrier.h" -#include "gc/SweepingAPI.h" #include "js/GCHashTable.h" #include "vm/PropertyKey.h" #include "vm/PropMap.h" @@ -40,7 +39,7 @@ struct BaseShapeHasher { key.unbarrieredGet()->proto() == lookup.proto; } }; -using BaseShapeSet = WeakCache< +using BaseShapeSet = JS::WeakCache< JS::GCHashSet, BaseShapeHasher, SystemAllocPolicy>>; // Hash policy for the per-zone initialPropMaps set, mapping property key + info @@ -63,8 +62,8 @@ struct InitialPropMapHasher { } }; using InitialPropMapSet = - WeakCache, InitialPropMapHasher, - SystemAllocPolicy>>; + JS::WeakCache, + InitialPropMapHasher, SystemAllocPolicy>>; // Helper class to hash information relevant for all shapes. struct ShapeBaseHasher { @@ -118,8 +117,8 @@ struct InitialShapeHasher { } }; using InitialShapeSet = - WeakCache, InitialShapeHasher, - SystemAllocPolicy>>; + JS::WeakCache, InitialShapeHasher, + SystemAllocPolicy>>; // Hash policy for the per-zone propMapShapes set storing shared shapes with // shared property maps. @@ -159,8 +158,8 @@ struct PropMapShapeHasher { } }; using PropMapShapeSet = - WeakCache, PropMapShapeHasher, - SystemAllocPolicy>>; + JS::WeakCache, PropMapShapeHasher, + SystemAllocPolicy>>; // Hash policy for the per-zone proxyShapes set storing shapes for proxy objects // in the zone. @@ -171,8 +170,8 @@ struct ProxyShapeHasher : public ShapeBaseHasher { } }; using ProxyShapeSet = - WeakCache, ProxyShapeHasher, - SystemAllocPolicy>>; + JS::WeakCache, ProxyShapeHasher, + SystemAllocPolicy>>; // Hash policy for the per-zone wasmGCShapes set storing shapes for Wasm GC // objects in the zone. @@ -200,8 +199,8 @@ struct WasmGCShapeHasher : public ShapeBaseHasher { } }; using WasmGCShapeSet = - WeakCache, WasmGCShapeHasher, - SystemAllocPolicy>>; + JS::WeakCache, WasmGCShapeHasher, + SystemAllocPolicy>>; struct ShapeZone { // Set of all base shapes in the Zone. diff --git a/mozjs-sys/mozjs/js/src/vm/StructuredClone.cpp b/mozjs-sys/mozjs/js/src/vm/StructuredClone.cpp index 405c18670be..45a0c1f39ea 100644 --- a/mozjs-sys/mozjs/js/src/vm/StructuredClone.cpp +++ b/mozjs-sys/mozjs/js/src/vm/StructuredClone.cpp @@ -178,17 +178,27 @@ enum StructuredDataType : uint32_t { /* * Format of transfer map: - * - * numTransferables (64 bits) - * array of: - * - * pointer (64 bits) - * extraData (64 bits), eg byte length for ArrayBuffers + * - + * - numTransferables (64 bits) + * - array of: + * - pointer (64 + * bits) + * - extraData (64 bits), eg byte length for ArrayBuffers + * - any data written for custom transferables */ // Data associated with an SCTAG_TRANSFER_MAP_HEADER that tells whether the -// contents have been read out yet or not. -enum TransferableMapHeader { SCTAG_TM_UNREAD = 0, SCTAG_TM_TRANSFERRED }; +// contents have been read out yet or not. TRANSFERRING is for the case where we +// have started but not completed reading, which due to errors could mean that +// there are things still owned by the clone buffer that need to be released, so +// discarding should not just be skipped. +enum TransferableMapHeader { + SCTAG_TM_UNREAD = 0, + SCTAG_TM_TRANSFERRING, + SCTAG_TM_TRANSFERRED, + + SCTAG_TM_END +}; static inline uint64_t PairToUInt64(uint32_t tag, uint32_t data) { return uint64_t(data) | (uint64_t(tag) << 32); @@ -701,6 +711,10 @@ static void ReportDataCloneError(JSContext* cx, errorNumber = JSMSG_SC_SHMEM_TRANSFERABLE; break; + case JS_SCERR_TRANSFERABLE_TWICE: + errorNumber = JSMSG_SC_TRANSFERABLE_TWICE; + break; + case JS_SCERR_TYPED_ARRAY_DETACHED: errorNumber = JSMSG_TYPED_ARRAY_DETACHED; break; @@ -3350,11 +3364,31 @@ bool JSStructuredCloneReader::readTransferMap() { return in.reportTruncated(); } - if (tag != SCTAG_TRANSFER_MAP_HEADER || - TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED) { + if (tag != SCTAG_TRANSFER_MAP_HEADER) { + // No transfer map header found. return true; } + if (data >= SCTAG_TM_END) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_SC_BAD_SERIALIZED_DATA, + "invalid transfer map header"); + return false; + } + auto transferState = static_cast(data); + + if (transferState == SCTAG_TM_TRANSFERRED) { + return true; + } + + if (transferState == SCTAG_TM_TRANSFERRING) { + ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE_TWICE, closure); + return false; + } + + headerPos.write( + PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRING)); + uint64_t numTransferables; MOZ_ALWAYS_TRUE(in.readPair(&tag, &data)); if (!in.read(&numTransferables)) { @@ -3475,7 +3509,7 @@ bool JSStructuredCloneReader::readTransferMap() { #ifdef DEBUG SCInput::getPair(headerPos.peek(), &tag, &data); MOZ_ASSERT(tag == SCTAG_TRANSFER_MAP_HEADER); - MOZ_ASSERT(TransferableMapHeader(data) != SCTAG_TM_TRANSFERRED); + MOZ_ASSERT(TransferableMapHeader(data) == SCTAG_TM_TRANSFERRING); #endif headerPos.write( PairToUInt64(SCTAG_TRANSFER_MAP_HEADER, SCTAG_TM_TRANSFERRED)); diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmBaselineCompile.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmBaselineCompile.cpp index dbd5bf11d4c..ae3637d77f7 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmBaselineCompile.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmBaselineCompile.cpp @@ -5313,23 +5313,17 @@ bool BaseCompiler::emitReturnCallRef() { uint32_t numArgs = funcType->args().length() + 1; - ResultType resultType(ResultType::Vector(funcType->results())); - StackResultsLoc results; - if (!pushStackResultsForCall(resultType, RegPtr(ABINonArgReg0), &results)) { - return false; - } - FunctionCall baselineCall{}; // State and realm are restored as needed by by callRef (really by // MacroAssembler::wasmCallRef). beginCall(baselineCall, UseABI::Wasm, RestoreRegisterStateAndRealm::False); - if (!emitCallArgs(funcType->args(), NormalCallResults(results), &baselineCall, + if (!emitCallArgs(funcType->args(), TailCallResults(*funcType), &baselineCall, CalleeOnStack::True)) { return false; } - const Stk& callee = peek(results.count()); + const Stk& callee = peek(0); returnCallRef(callee, baselineCall, funcType); MOZ_ASSERT(stackMapGenerator_.framePushedExcludingOutboundCallArgs.isSome()); @@ -7156,7 +7150,7 @@ bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index, // shift immediate. If not we shift the index manually and then unshift // it after the store. We don't use an extra register for this because we // don't have any to spare on x86. - uint32_t shift = arrayType.elementType_.indexingShift(); + uint32_t shift = arrayType.elementType().indexingShift(); Scale scale; bool shiftedIndex = false; if (IsShiftInScaleRange(shift)) { @@ -7173,9 +7167,9 @@ bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index, }); // Easy path if the field is a scalar - if (!arrayType.elementType_.isRefRepr()) { + if (!arrayType.elementType().isRefRepr()) { emitGcSetScalar(BaseIndex(data, index, scale, 0), - arrayType.elementType_, value); + arrayType.elementType(), value); return true; } @@ -7317,9 +7311,9 @@ bool BaseCompiler::emitStructNew() { uint32_t fieldIndex = structType.fields_.length(); while (fieldIndex-- > 0) { - const StructField& field = structType.fields_[fieldIndex]; + const FieldType& field = structType.fields_[fieldIndex]; StorageType type = field.type; - uint32_t fieldOffset = field.offset; + uint32_t fieldOffset = structType.fieldOffset(fieldIndex); bool areaIsOutline; uint32_t areaOffset; @@ -7406,7 +7400,7 @@ bool BaseCompiler::emitStructGet(FieldWideningOp wideningOp) { // Decide whether we're accessing inline or outline, and at what offset StorageType fieldType = structType.fields_[fieldIndex].type; - uint32_t fieldOffset = structType.fields_[fieldIndex].offset; + uint32_t fieldOffset = structType.fieldOffset(fieldIndex); bool areaIsOutline; uint32_t areaOffset; @@ -7447,11 +7441,11 @@ bool BaseCompiler::emitStructSet() { } const StructType& structType = (*moduleEnv_.types)[typeIndex].structType(); - const StructField& structField = structType.fields_[fieldIndex]; + const FieldType& structField = structType.fields_[fieldIndex]; // Decide whether we're accessing inline or outline, and at what offset StorageType fieldType = structType.fields_[fieldIndex].type; - uint32_t fieldOffset = structType.fields_[fieldIndex].offset; + uint32_t fieldOffset = structType.fieldOffset(fieldIndex); bool areaIsOutline; uint32_t areaOffset; @@ -7626,14 +7620,14 @@ bool BaseCompiler::emitArrayNew() { // Reserve this register early if we will need it so that it is not taken by // any register used in this function. - if (arrayType.elementType_.isRefRepr()) { + if (arrayType.elementType().isRefRepr()) { needPtr(RegPtr(PreBarrierReg)); } RegRef object = needRef(); RegI32 numElements = popI32(); if (!emitArrayAlloc(typeIndex, object, numElements, - arrayType.elementType_.size())) { + arrayType.elementType().size())) { return false; } @@ -7646,7 +7640,7 @@ bool BaseCompiler::emitArrayNew() { numElements = emitGcArrayGetNumElements(object); // Free the barrier reg after we've allocated all registers - if (arrayType.elementType_.isRefRepr()) { + if (arrayType.elementType().isRefRepr()) { freePtr(RegPtr(PreBarrierReg)); } @@ -7694,14 +7688,14 @@ bool BaseCompiler::emitArrayNewFixed() { // Reserve this register early if we will need it so that it is not taken by // any register used in this function. - bool avoidPreBarrierReg = arrayType.elementType_.isRefRepr(); + bool avoidPreBarrierReg = arrayType.elementType().isRefRepr(); if (avoidPreBarrierReg) { needPtr(RegPtr(PreBarrierReg)); } RegRef object = needRef(); if (!emitArrayAllocFixed(typeIndex, object, numElements, - arrayType.elementType_.size())) { + arrayType.elementType().size())) { return false; } @@ -7764,7 +7758,7 @@ bool BaseCompiler::emitArrayNewDefault() { RegRef object = needRef(); RegI32 numElements = popI32(); if (!emitArrayAlloc(typeIndex, object, numElements, - arrayType.elementType_.size())) { + arrayType.elementType().size())) { return false; } @@ -7881,14 +7875,14 @@ bool BaseCompiler::emitArrayGet(FieldWideningOp wideningOp) { RegPtr rdata = emitGcArrayGetData(rp); // Load the value - uint32_t shift = arrayType.elementType_.indexingShift(); + uint32_t shift = arrayType.elementType().indexingShift(); if (IsShiftInScaleRange(shift)) { emitGcGet( - arrayType.elementType_, wideningOp, + arrayType.elementType(), wideningOp, BaseIndex(rdata, index, ShiftToScale(shift), 0)); } else { masm.lshiftPtr(Imm32(shift), index); - emitGcGet(arrayType.elementType_, wideningOp, + emitGcGet(arrayType.elementType(), wideningOp, BaseIndex(rdata, index, TimesOne, 0)); } @@ -7914,7 +7908,7 @@ bool BaseCompiler::emitArraySet() { // Reserve this register early if we will need it so that it is not taken by // any register used in this function. - if (arrayType.elementType_.isRefRepr()) { + if (arrayType.elementType().isRefRepr()) { needPtr(RegPtr(PreBarrierReg)); } @@ -7933,7 +7927,7 @@ bool BaseCompiler::emitArraySet() { RegPtr rdata = emitGcArrayGetData(rp); // Free the barrier reg after we've allocated all registers - if (arrayType.elementType_.isRefRepr()) { + if (arrayType.elementType().isRefRepr()) { freePtr(RegPtr(PreBarrierReg)); } @@ -8010,7 +8004,7 @@ bool BaseCompiler::emitArrayFill() { const TypeDef& typeDef = moduleEnv_.types->type(typeIndex); const ArrayType& arrayType = typeDef.arrayType(); - StorageType elementType = arrayType.elementType_; + StorageType elementType = arrayType.elementType(); // On x86 (32-bit), we are very short of registers, hence the code // generation scheme is less straightforward than it might otherwise be. @@ -8169,7 +8163,7 @@ bool BaseCompiler::emitArrayFill() { // Currently `rdata` points at the start of the array data area. Move it // forwards by `index` units so as to make it point at the start of the area // to be filled. - uint32_t shift = arrayType.elementType_.indexingShift(); + uint32_t shift = arrayType.elementType().indexingShift(); if (shift > 0) { masm.lshift32(Imm32(shift), index); // `index` is a 32 bit value, so we must zero-extend it to 64 bits before diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.cpp index 342f55598f7..88c6fa87bc2 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.cpp @@ -655,18 +655,15 @@ static const wasm::TryNote* FindNonDelegateTryNote(const wasm::Code& code, return tryNote; } -// Unwind the entire activation in response to a thrown exception. This function -// is responsible for notifying the debugger of each unwound frame. The return -// value is the new stack address which the calling stub will set to the sp -// register before executing a return instruction. +// Unwind the activation in response to a thrown exception. This function is +// responsible for notifying the debugger of each unwound frame. // -// This function will also look for try-catch handlers and, if not trapping or -// throwing an uncatchable exception, will write the handler info in the return -// argument and return true. +// This function will look for try-catch handlers and, if not trapping or +// throwing an uncatchable exception, will write the handler info in |*rfe|. // -// Returns false if a handler isn't found or shouldn't be used (e.g., traps). - -bool wasm::HandleThrow(JSContext* cx, WasmFrameIter& iter, +// If no try-catch handler is found, initialize |*rfe| for a return to the entry +// frame that called into Wasm. +void wasm::HandleThrow(JSContext* cx, WasmFrameIter& iter, jit::ResumeFromException* rfe) { // WasmFrameIter iterates down wasm frames in the activation starting at // JitActivation::wasmExitFP(). Calling WasmFrameIter::startUnwinding pops @@ -743,8 +740,7 @@ bool wasm::HandleThrow(JSContext* cx, WasmFrameIter& iter, activation->finishWasmTrap(); } activation->setWasmExitFP(nullptr); - - return true; + return; } } @@ -802,7 +798,6 @@ bool wasm::HandleThrow(JSContext* cx, WasmFrameIter& iter, rfe->stackPointer = (uint8_t*)iter.unwoundAddressOfReturnAddress(); rfe->instance = (Instance*)FailInstanceReg; rfe->target = nullptr; - return false; } static void* WasmHandleThrow(jit::ResumeFromException* rfe) { diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.h b/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.h index 55f9b55a9c0..6e0566bbefa 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmBuiltins.h @@ -313,7 +313,7 @@ bool LookupBuiltinThunk(void* pc, const CodeRange** codeRange, bool EnsureBuiltinThunksInitialized(); -bool HandleThrow(JSContext* cx, WasmFrameIter& iter, +void HandleThrow(JSContext* cx, WasmFrameIter& iter, jit::ResumeFromException* rfe); void* SymbolicAddressTarget(SymbolicAddress sym); diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmDump.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmDump.cpp index f92125077aa..be0c08ebb21 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmDump.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmDump.cpp @@ -193,7 +193,7 @@ void wasm::Dump(const StructType& structType, IndentedPrinter& out) { out.printf("(struct\n"); { IndentedPrinter::AutoIndent innerIndent(out); - for (const StructField& field : structType.fields_) { + for (const FieldType& field : structType.fields_) { out.printf("(field "); if (field.isMutable) { out.printf("(mut "); @@ -216,11 +216,11 @@ void wasm::Dump(const ArrayType& arrayType) { void wasm::Dump(const ArrayType& arrayType, IndentedPrinter& out) { out.printf("(array "); - if (arrayType.isMutable_) { + if (arrayType.isMutable()) { out.printf("(mut "); } - Dump(arrayType.elementType_, out); - if (arrayType.isMutable_) { + Dump(arrayType.elementType(), out); + if (arrayType.isMutable()) { out.printf(")"); } out.printf(")\n"); diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmGcObject-inl.h b/mozjs-sys/mozjs/js/src/wasm/WasmGcObject-inl.h index 4714aafc06b..ea7347d4665 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmGcObject-inl.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmGcObject-inl.h @@ -170,7 +170,7 @@ inline gc::AllocKind WasmArrayObject::allocKindForIL(uint32_t storageBytes) { inline gc::AllocKind WasmArrayObject::allocKind() const { if (isDataInline()) { uint32_t storageBytes = calcStorageBytes( - typeDef().arrayType().elementType_.size(), numElements_); + typeDef().arrayType().elementType().size(), numElements_); return allocKindForIL(storageBytes); } @@ -337,7 +337,7 @@ MOZ_ALWAYS_INLINE WasmArrayObject* WasmArrayObject::createArray( JSContext* cx, wasm::TypeDefInstanceData* typeDefData, js::gc::Heap initialHeap, uint32_t numElements) { MOZ_ASSERT(typeDefData->arrayElemSize == - typeDefData->typeDef->arrayType().elementType_.size()); + typeDefData->typeDef->arrayType().elementType().size()); CheckedUint32 storageBytes = calcStorageBytesChecked(typeDefData->arrayElemSize, numElements); if (!storageBytes.isValid() || diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.cpp index 4bf574aa12c..d60752d45c1 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.cpp @@ -249,9 +249,8 @@ bool WasmGcObject::lookUpProperty(JSContext* cx, Handle obj, JSMSG_WASM_OUT_OF_BOUNDS); return false; } - const StructField& field = structType.fields_[index]; - offset->set(field.offset); - *type = field.type; + offset->set(structType.fieldOffset(index)); + *type = structType.fields_[index].type; return true; } case wasm::TypeDefKind::Array: { @@ -266,13 +265,13 @@ bool WasmGcObject::lookUpProperty(JSContext* cx, Handle obj, return false; } uint64_t scaledIndex = - uint64_t(index) * uint64_t(arrayType.elementType_.size()); + uint64_t(index) * uint64_t(arrayType.elementType().size()); if (scaledIndex >= uint64_t(UINT32_MAX)) { // It's unrepresentable as an WasmGcObject::PropOffset. Give up. return false; } offset->set(uint32_t(scaledIndex)); - *type = arrayType.elementType_; + *type = arrayType.elementType(); return true; } default: @@ -370,12 +369,12 @@ void WasmArrayObject::obj_trace(JSTracer* trc, JSObject* object) { const auto& typeDef = arrayObj.typeDef(); const auto& arrayType = typeDef.arrayType(); - if (!arrayType.elementType_.isRefRepr()) { + if (!arrayType.elementType().isRefRepr()) { return; } uint32_t numElements = arrayObj.numElements_; - uint32_t elemSize = arrayType.elementType_.size(); + uint32_t elemSize = arrayType.elementType().size(); for (uint32_t i = 0; i < numElements; i++) { AnyRef* elementPtr = reinterpret_cast(data + i * elemSize); TraceManuallyBarrieredEdge(trc, elementPtr, "wasm-array-element"); @@ -398,7 +397,7 @@ void WasmArrayObject::obj_finalize(JS::GCContext* gcx, JSObject* object) { const TypeDef& typeDef = arrayObj.typeDef(); MOZ_ASSERT(typeDef.isArrayType()); size_t trailerSize = calcStorageBytes( - typeDef.arrayType().elementType_.size(), arrayObj.numElements_); + typeDef.arrayType().elementType().size(), arrayObj.numElements_); // Ensured by WasmArrayObject::createArrayNonEmpty. MOZ_RELEASE_ASSERT(trailerSize <= size_t(MaxArrayPayloadBytes)); gcx->removeCellMemory(&arrayObj, trailerSize + TrailerBlockOverhead, @@ -427,7 +426,7 @@ size_t WasmArrayObject::obj_moved(JSObject* obj, JSObject* old) { const TypeDef& typeDef = arrayObj.typeDef(); MOZ_ASSERT(typeDef.isArrayType()); size_t trailerSize = calcStorageBytes( - typeDef.arrayType().elementType_.size(), arrayObj.numElements_); + typeDef.arrayType().elementType().size(), arrayObj.numElements_); // Ensured by WasmArrayObject::createArrayOOL. MOZ_RELEASE_ASSERT(trailerSize <= size_t(MaxArrayPayloadBytes)); nursery.trackTrailerOnPromotion(arrayObj.dataHeader(), obj, trailerSize, @@ -441,20 +440,20 @@ size_t WasmArrayObject::obj_moved(JSObject* obj, JSObject* old) { void WasmArrayObject::storeVal(const Val& val, uint32_t itemIndex) { const ArrayType& arrayType = typeDef().arrayType(); - size_t elementSize = arrayType.elementType_.size(); + size_t elementSize = arrayType.elementType().size(); MOZ_ASSERT(itemIndex < numElements_); uint8_t* data = data_ + elementSize * itemIndex; - WriteValTo(val, arrayType.elementType_, data); + WriteValTo(val, arrayType.elementType(), data); } void WasmArrayObject::fillVal(const Val& val, uint32_t itemIndex, uint32_t len) { const ArrayType& arrayType = typeDef().arrayType(); - size_t elementSize = arrayType.elementType_.size(); + size_t elementSize = arrayType.elementType().size(); uint8_t* data = data_ + elementSize * itemIndex; MOZ_ASSERT(itemIndex <= numElements_ && len <= numElements_ - itemIndex); for (uint32_t i = 0; i < len; i++) { - WriteValTo(val, arrayType.elementType_, data); + WriteValTo(val, arrayType.elementType(), data); data += elementSize; } } @@ -520,9 +519,10 @@ bool WasmStructObject::getField(JSContext* cx, uint32_t index, MutableHandle val) { const StructType& resultType = typeDef().structType(); MOZ_ASSERT(index <= resultType.fields_.length()); - const StructField& field = resultType.fields_[index]; + const FieldType& field = resultType.fields_[index]; + uint32_t fieldOffset = resultType.fieldOffset(index); StorageType ty = field.type.storageType(); - return ToJSValue(cx, fieldOffsetToAddress(ty, field.offset), ty, val); + return ToJSValue(cx, fieldOffsetToAddress(ty, fieldOffset), ty, val); } /* static */ @@ -585,7 +585,7 @@ size_t WasmStructObject::obj_moved(JSObject* obj, JSObject* old) { void WasmStructObject::storeVal(const Val& val, uint32_t fieldIndex) { const StructType& structType = typeDef().structType(); StorageType fieldType = structType.fields_[fieldIndex].type; - uint32_t fieldOffset = structType.fields_[fieldIndex].offset; + uint32_t fieldOffset = structType.fieldOffset(fieldIndex); MOZ_ASSERT(fieldIndex < structType.fields_.length()); bool areaIsOutline; diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.h b/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.h index d88061c238e..663bd87cbcc 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmGcObject.h @@ -89,8 +89,8 @@ class WasmGcObject : public JSObject { // single contiguous area of memory: // // * If the object in question is a WasmStructObject, it is the value of - // `wasm::StructField::offset` for the relevant field, without regard to - // the inline/outline split. + // `wasm::StructType::fieldOffset()` for the relevant field, without regard + // to the inline/outline split. // // * If the object in question is a WasmArrayObject, then // - u32 == UINT32_MAX (0xFFFF'FFFF) means the "length" property diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmInstance.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmInstance.cpp index 9183715ca70..2b8aeb2028d 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmInstance.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmInstance.cpp @@ -1514,7 +1514,7 @@ static bool ArrayCopyFromData(JSContext* cx, Handle arrayObj, // Compute the number of bytes to copy, ensuring it's below 2^32. CheckedUint32 numBytesToCopy = CheckedUint32(numElements) * - CheckedUint32(typeDef->arrayType().elementType_.size()); + CheckedUint32(typeDef->arrayType().elementType().size()); if (!numBytesToCopy.isValid()) { // Because the request implies that 2^32 or more bytes are to be copied. ReportTrapError(cx, JSMSG_WASM_OUT_OF_BOUNDS); @@ -1665,7 +1665,7 @@ static bool ArrayCopyFromElem(JSContext* cx, Handle arrayObj, // Any data coming from an element segment will be an AnyRef. Writes into // array memory are done with raw pointers, so we must ensure here that the // destination size is correct. - MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType_.size() == + MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType().size() == sizeof(AnyRef)); Rooted arrayObj( @@ -1771,7 +1771,7 @@ static bool ArrayCopyFromElem(JSContext* cx, Handle arrayObj, // Any data coming from an element segment will be an AnyRef. Writes into // array memory are done with raw pointers, so we must ensure here that the // destination size is correct. - MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType_.size() == + MOZ_RELEASE_ASSERT(typeDef->arrayType().elementType().size() == sizeof(AnyRef)); // Get hold of the array. @@ -1969,8 +1969,8 @@ static WasmArrayObject* UncheckedCastToArrayI16(HandleAnyRef ref) { JSObject& object = ref.toJSObject(); WasmArrayObject& array = object.as(); DebugOnly type(&array.typeDef().arrayType()); - MOZ_ASSERT(type->elementType_ == StorageType::I16); - MOZ_ASSERT(type->isMutable_ == isMutable); + MOZ_ASSERT(type->elementType() == StorageType::I16); + MOZ_ASSERT(type->isMutable() == isMutable); return &array; } @@ -2369,7 +2369,7 @@ bool Instance::init(JSContext* cx, const JSObjectVector& funcImports, // StructLayout::close ensures this is an integral number of words. MOZ_ASSERT((typeDefData->structTypeSize % sizeof(uintptr_t)) == 0); } else { - uint32_t arrayElemSize = typeDef.arrayType().elementType_.size(); + uint32_t arrayElemSize = typeDef.arrayType().elementType().size(); typeDefData->arrayElemSize = arrayElemSize; MOZ_ASSERT(arrayElemSize == 16 || arrayElemSize == 8 || arrayElemSize == 4 || arrayElemSize == 2 || diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmIonCompile.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmIonCompile.cpp index e592a6d8650..c17d083b5f0 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmIonCompile.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmIonCompile.cpp @@ -4200,11 +4200,11 @@ class FunctionCompiler { // WasmStructObject, a MIR pointer to a value, and a field descriptor, // generate MIR to write the value to the relevant field in the object. [[nodiscard]] bool writeValueToStructField( - uint32_t lineOrBytecode, const StructField& field, - MDefinition* structObject, MDefinition* value, + uint32_t lineOrBytecode, const StructType& structType, + uint32_t fieldIndex, MDefinition* structObject, MDefinition* value, WasmPreBarrierKind preBarrierKind) { - StorageType fieldType = field.type; - uint32_t fieldOffset = field.offset; + StorageType fieldType = structType.fields_[fieldIndex].type; + uint32_t fieldOffset = structType.fieldOffset(fieldIndex); bool areaIsOutline; uint32_t areaOffset; @@ -4251,10 +4251,10 @@ class FunctionCompiler { // WasmStructObject, a field descriptor and a field widening operation, // generate MIR to read the value from the relevant field in the object. [[nodiscard]] MDefinition* readValueFromStructField( - const StructField& field, FieldWideningOp wideningOp, - MDefinition* structObject) { - StorageType fieldType = field.type; - uint32_t fieldOffset = field.offset; + const StructType& structType, uint32_t fieldIndex, + FieldWideningOp wideningOp, MDefinition* structObject) { + StorageType fieldType = structType.fields_[fieldIndex].type; + uint32_t fieldOffset = structType.fieldOffset(fieldIndex); bool areaIsOutline; uint32_t areaOffset; @@ -4436,7 +4436,7 @@ class FunctionCompiler { MDefinition* numElements, MDefinition* val, WasmPreBarrierKind preBarrierKind) { mozilla::DebugOnly valMIRType = val->type(); - StorageType elemType = arrayType.elementType_; + StorageType elemType = arrayType.elementType(); MOZ_ASSERT(elemType.widenToValType().toMIRType() == valMIRType); uint32_t elemSize = elemType.size(); @@ -4563,7 +4563,7 @@ class FunctionCompiler { // Create the array object, uninitialized. MDefinition* arrayObject = createArrayObject(lineOrBytecode, typeIndex, numElements, - arrayType.elementType_.size(), /*zeroFields=*/false); + arrayType.elementType().size(), /*zeroFields=*/false); if (!arrayObject) { return nullptr; } @@ -7329,9 +7329,8 @@ static bool EmitStructNew(FunctionCompiler& f) { if (!f.mirGen().ensureBallast()) { return false; } - const StructField& field = structType.fields_[fieldIndex]; - if (!f.writeValueToStructField(lineOrBytecode, field, structObject, - args[fieldIndex], + if (!f.writeValueToStructField(lineOrBytecode, structType, fieldIndex, + structObject, args[fieldIndex], WasmPreBarrierKind::None)) { return false; } @@ -7399,8 +7398,8 @@ static bool EmitStructSet(FunctionCompiler& f) { // And fill in the field. const StructType& structType = (*f.moduleEnv().types)[typeIndex].structType(); - const StructField& field = structType.fields_[fieldIndex]; - return f.writeValueToStructField(lineOrBytecode, field, structObject, value, + return f.writeValueToStructField(lineOrBytecode, structType, fieldIndex, + structObject, value, WasmPreBarrierKind::Normal); } @@ -7421,9 +7420,8 @@ static bool EmitStructGet(FunctionCompiler& f, FieldWideningOp wideningOp) { // And fetch the data. const StructType& structType = (*f.moduleEnv().types)[typeIndex].structType(); - const StructField& field = structType.fields_[fieldIndex]; - MDefinition* load = - f.readValueFromStructField(field, wideningOp, structObject); + MDefinition* load = f.readValueFromStructField(structType, fieldIndex, + wideningOp, structObject); if (!load) { return false; } @@ -7477,7 +7475,7 @@ static bool EmitArrayNewDefault(FunctionCompiler& f) { const ArrayType& arrayType = (*f.moduleEnv().types)[typeIndex].arrayType(); MDefinition* arrayObject = f.createArrayObject(lineOrBytecode, typeIndex, numElements, - arrayType.elementType_.size(), /*zeroFields=*/true); + arrayType.elementType().size(), /*zeroFields=*/true); if (!arrayObject) { return false; } @@ -7508,7 +7506,7 @@ static bool EmitArrayNewFixed(FunctionCompiler& f) { // Create the array object, uninitialized. const ArrayType& arrayType = (*f.moduleEnv().types)[typeIndex].arrayType(); - StorageType elemType = arrayType.elementType_; + StorageType elemType = arrayType.elementType(); uint32_t elemSize = elemType.size(); MDefinition* arrayObject = f.createArrayObject(lineOrBytecode, typeIndex, numElementsDef, elemSize, @@ -7739,7 +7737,7 @@ static bool EmitArraySet(FunctionCompiler& f) { // And do the store. const ArrayType& arrayType = (*f.moduleEnv().types)[typeIndex].arrayType(); - StorageType elemType = arrayType.elementType_; + StorageType elemType = arrayType.elementType(); uint32_t elemSize = elemType.size(); MOZ_ASSERT(elemSize >= 1 && elemSize <= 16); @@ -7771,7 +7769,7 @@ static bool EmitArrayGet(FunctionCompiler& f, FieldWideningOp wideningOp) { // And do the load. const ArrayType& arrayType = (*f.moduleEnv().types)[typeIndex].arrayType(); - StorageType elemType = arrayType.elementType_; + StorageType elemType = arrayType.elementType(); MDefinition* load = f.readGcArrayValueAtIndex(elemType, wideningOp, arrayObject, diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmJS.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmJS.cpp index 8a7e967a809..1ba7067d078 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmJS.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmJS.cpp @@ -1627,8 +1627,8 @@ bool WasmInstanceObject::isNewborn() const { // This is defined here in order to avoid recursive dependency between // WasmJS.h and Scope.h. using WasmFunctionScopeMap = - WeakCache, - DefaultHasher, CellAllocPolicy>>; + JS::WeakCache, + DefaultHasher, CellAllocPolicy>>; class WasmInstanceObject::UnspecifiedScopeMap { public: WasmFunctionScopeMap& asWasmFunctionScopeMap() { diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmJS.h b/mozjs-sys/mozjs/js/src/wasm/WasmJS.h index 3ebc2d9705e..668e282a465 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmJS.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmJS.h @@ -25,7 +25,6 @@ #include // int32_t, int64_t, uint32_t #include "gc/Barrier.h" // HeapPtr -#include "gc/SweepingAPI.h" // WeakCache #include "gc/ZoneAllocator.h" // ZoneAllocPolicy #include "js/AllocPolicy.h" // SystemAllocPolicy #include "js/Class.h" // JSClassOps, ClassSpec @@ -33,6 +32,7 @@ #include "js/GCVector.h" // GCVector #include "js/PropertySpec.h" // JSPropertySpec, JSFunctionSpec #include "js/RootingAPI.h" // StableCellHasher +#include "js/SweepingAPI.h" // JS::WeakCache #include "js/TypeDecls.h" // HandleValue, HandleObject, MutableHandleObject, MutableHandleFunction #include "js/Vector.h" // JS::Vector #include "js/WasmFeatures.h" @@ -284,10 +284,9 @@ class WasmMemoryObject : public NativeObject { static bool discard(JSContext* cx, unsigned argc, Value* vp); static uint64_t growShared(Handle memory, uint64_t delta); - using InstanceSet = - WeakCache, - StableCellHasher>, - CellAllocPolicy>>; + using InstanceSet = JS::WeakCache, + StableCellHasher>, CellAllocPolicy>>; bool hasObservers() const; InstanceSet& observers() const; InstanceSet* getOrCreateObservers(JSContext* cx); diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmOpIter.h b/mozjs-sys/mozjs/js/src/wasm/WasmOpIter.h index 9ea44bac923..0805fb1b37c 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmOpIter.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmOpIter.h @@ -3487,7 +3487,7 @@ inline bool OpIter::readArrayNew(uint32_t* typeIndex, return false; } - if (!popWithType(arrayType.elementType_.widenToValType(), argValue)) { + if (!popWithType(arrayType.elementType().widenToValType(), argValue)) { return false; } @@ -3520,7 +3520,7 @@ inline bool OpIter::readArrayNewFixed(uint32_t* typeIndex, return false; } - ValType widenedElementType = arrayType.elementType_.widenToValType(); + ValType widenedElementType = arrayType.elementType().widenToValType(); for (uint32_t i = 0; i < *numElements; i++) { Value v; if (!popWithType(widenedElementType, &v)) { @@ -3548,7 +3548,7 @@ inline bool OpIter::readArrayNewDefault(uint32_t* typeIndex, return false; } - if (!arrayType.elementType_.isDefaultable()) { + if (!arrayType.elementType().isDefaultable()) { return fail("array must be defaultable"); } @@ -3571,7 +3571,7 @@ inline bool OpIter::readArrayNewData(uint32_t* typeIndex, const TypeDef& typeDef = env_.types->type(*typeIndex); const ArrayType& arrayType = typeDef.arrayType(); - StorageType elemType = arrayType.elementType_; + StorageType elemType = arrayType.elementType(); if (!elemType.isNumber() && !elemType.isPacked() && !elemType.isVector()) { return fail("element type must be i8/i16/i32/i64/f32/f64/v128"); } @@ -3608,7 +3608,7 @@ inline bool OpIter::readArrayNewElem(uint32_t* typeIndex, const TypeDef& typeDef = env_.types->type(*typeIndex); const ArrayType& arrayType = typeDef.arrayType(); - StorageType dstElemType = arrayType.elementType_; + StorageType dstElemType = arrayType.elementType(); if (!dstElemType.isRefType()) { return fail("element type is not a reftype"); } @@ -3650,11 +3650,11 @@ inline bool OpIter::readArrayInitData(uint32_t* typeIndex, const TypeDef& typeDef = env_.types->type(*typeIndex); const ArrayType& arrayType = typeDef.arrayType(); - StorageType elemType = arrayType.elementType_; + StorageType elemType = arrayType.elementType(); if (!elemType.isNumber() && !elemType.isPacked() && !elemType.isVector()) { return fail("element type must be i8/i16/i32/i64/f32/f64/v128"); } - if (!arrayType.isMutable_) { + if (!arrayType.isMutable()) { return fail("destination array is not mutable"); } if (env_.dataCount.isNothing()) { @@ -3693,8 +3693,8 @@ inline bool OpIter::readArrayInitElem(uint32_t* typeIndex, const TypeDef& typeDef = env_.types->type(*typeIndex); const ArrayType& arrayType = typeDef.arrayType(); - StorageType dstElemType = arrayType.elementType_; - if (!arrayType.isMutable_) { + StorageType dstElemType = arrayType.elementType(); + if (!arrayType.isMutable()) { return fail("destination array is not mutable"); } if (!dstElemType.isRefType()) { @@ -3744,7 +3744,7 @@ inline bool OpIter::readArrayGet(uint32_t* typeIndex, return false; } - StorageType elementType = arrayType.elementType_; + StorageType elementType = arrayType.elementType(); if (elementType.isValType() && wideningOp != FieldWideningOp::None) { return fail("must not specify signedness for unpacked element type"); @@ -3769,11 +3769,11 @@ inline bool OpIter::readArraySet(uint32_t* typeIndex, Value* val, const TypeDef& typeDef = env_.types->type(*typeIndex); const ArrayType& arrayType = typeDef.arrayType(); - if (!arrayType.isMutable_) { + if (!arrayType.isMutable()) { return fail("array is not mutable"); } - if (!popWithType(arrayType.elementType_.widenToValType(), val)) { + if (!popWithType(arrayType.elementType().widenToValType(), val)) { return false; } @@ -3821,9 +3821,9 @@ inline bool OpIter::readArrayCopy(int32_t* elemSize, const ArrayType& dstArrayType = dstTypeDef.arrayType(); const TypeDef& srcTypeDef = env_.types->type(srcTypeIndex); const ArrayType& srcArrayType = srcTypeDef.arrayType(); - StorageType dstElemType = dstArrayType.elementType_; - StorageType srcElemType = srcArrayType.elementType_; - if (!dstArrayType.isMutable_) { + StorageType dstElemType = dstArrayType.elementType(); + StorageType srcElemType = srcArrayType.elementType(); + if (!dstArrayType.isMutable()) { return fail("destination array is not mutable"); } @@ -3866,14 +3866,14 @@ inline bool OpIter::readArrayFill(uint32_t* typeIndex, Value* array, const TypeDef& typeDef = env_.types->type(*typeIndex); const ArrayType& arrayType = typeDef.arrayType(); - if (!arrayType.isMutable_) { + if (!arrayType.isMutable()) { return fail("destination array is not mutable"); } if (!popWithType(ValType::I32, length)) { return false; } - if (!popWithType(arrayType.elementType_.widenToValType(), val)) { + if (!popWithType(arrayType.elementType().widenToValType(), val)) { return false; } if (!popWithType(ValType::I32, index)) { diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmPI.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmPI.cpp index 289ac6c5ee4..52928459923 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmPI.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmPI.cpp @@ -1689,7 +1689,7 @@ JSObject* GetSuspendingPromiseResult(Instance* instance, Rooted results( cx, instance->constantStructNewDefault( cx, SuspendingFunctionModuleFactory::ResultsTypeIndex)); - const StructFieldVector& fields = results->typeDef().structType().fields_; + const FieldTypeVector& fields = results->typeDef().structType().fields_; if (fields.length() > 0) { RootedValue jsValue(cx, promise->value()); diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmSerialize.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmSerialize.cpp index e8cf9040640..6f9298bc97e 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmSerialize.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmSerialize.cpp @@ -531,10 +531,8 @@ CoderResult CodeFuncType(Coder& coder, CoderArg item) { } template -CoderResult CodeStructField(Coder& coder, - CoderArg item) { +CoderResult CodeFieldType(Coder& coder, CoderArg item) { MOZ_TRY(CodeStorageType(coder, &item->type)); - MOZ_TRY(CodePod(coder, &item->offset)); MOZ_TRY(CodePod(coder, &item->isMutable)); return Ok(); } @@ -542,9 +540,9 @@ CoderResult CodeStructField(Coder& coder, template CoderResult CodeStructType(Coder& coder, CoderArg item) { - WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::StructType, 136); - MOZ_TRY((CodeVector>( - coder, &item->fields_))); + WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::StructType, 184); + MOZ_TRY((CodeVector>(coder, + &item->fields_))); if constexpr (mode == MODE_DECODE) { if (!item->init()) { return Err(OutOfMemory()); @@ -556,8 +554,7 @@ CoderResult CodeStructType(Coder& coder, template CoderResult CodeArrayType(Coder& coder, CoderArg item) { WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::ArrayType, 16); - MOZ_TRY(CodeStorageType(coder, &item->elementType_)); - MOZ_TRY(CodePod(coder, &item->isMutable_)); + MOZ_TRY(CodeFieldType(coder, &item->fieldType_)); return Ok(); } diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmStubs.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmStubs.cpp index 76f015d34b7..6fff1c8ded2 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmStubs.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmStubs.cpp @@ -2754,6 +2754,24 @@ static void ClobberWasmRegsForLongJmp(MacroAssembler& masm, Register jumpReg) { } } +// Generates code to jump to a Wasm catch handler after unwinding the stack. +// The |rfe| register stores a pointer to the ResumeFromException struct +// allocated on the stack. +void wasm::GenerateJumpToCatchHandler(MacroAssembler& masm, Register rfe, + Register scratch1, Register scratch2) { + masm.loadPtr(Address(rfe, ResumeFromException::offsetOfInstance()), + InstanceReg); + masm.loadWasmPinnedRegsFromInstance(); + masm.switchToWasmInstanceRealm(scratch1, scratch2); + masm.loadPtr(Address(rfe, ResumeFromException::offsetOfTarget()), scratch1); + masm.loadPtr(Address(rfe, ResumeFromException::offsetOfFramePointer()), + FramePointer); + masm.loadStackPtr(Address(rfe, ResumeFromException::offsetOfStackPointer())); + MoveSPForJitABI(masm); + ClobberWasmRegsForLongJmp(masm, scratch1); + masm.jump(scratch1); +} + // Generate a stub that restores the stack pointer to what it was on entry to // the wasm activation, sets the return register to 'false' and then executes a // return which will return from this wasm activation to the caller. This stub @@ -2823,19 +2841,7 @@ static bool GenerateThrowStub(MacroAssembler& masm, Label* throwLabel, // The case where a Wasm catch handler was found while unwinding the stack. masm.bind(&resumeCatch); - masm.loadPtr(Address(ReturnReg, ResumeFromException::offsetOfInstance()), - InstanceReg); - masm.loadWasmPinnedRegsFromInstance(); - masm.switchToWasmInstanceRealm(scratch1, scratch2); - masm.loadPtr(Address(ReturnReg, ResumeFromException::offsetOfTarget()), - scratch1); - masm.loadPtr(Address(ReturnReg, ResumeFromException::offsetOfFramePointer()), - FramePointer); - masm.loadStackPtr( - Address(ReturnReg, ResumeFromException::offsetOfStackPointer())); - MoveSPForJitABI(masm); - ClobberWasmRegsForLongJmp(masm, scratch1); - masm.jump(scratch1); + GenerateJumpToCatchHandler(masm, ReturnReg, scratch1, scratch2); // No catch handler was found, so we will just return out. masm.bind(&leaveWasm); diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmStubs.h b/mozjs-sys/mozjs/js/src/wasm/WasmStubs.h index 6a6622fdf2d..be0bbeb0ed8 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmStubs.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmStubs.h @@ -364,6 +364,11 @@ extern void GenerateDirectCallFromJit(jit::MacroAssembler& masm, jit::Register scratch, uint32_t* callOffset); +extern void GenerateJumpToCatchHandler(jit::MacroAssembler& masm, + jit::Register rfe, + jit::Register scratch1, + jit::Register scratch2); + } // namespace wasm } // namespace js diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmTable.h b/mozjs-sys/mozjs/js/src/wasm/WasmTable.h index a6e690cdd64..f8f59644bbe 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmTable.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmTable.h @@ -37,10 +37,9 @@ namespace wasm { using TableAnyRefVector = GCVector, 0, SystemAllocPolicy>; class Table : public ShareableBase { - using InstanceSet = - WeakCache, - StableCellHasher>, - SystemAllocPolicy>>; + using InstanceSet = JS::WeakCache, + StableCellHasher>, SystemAllocPolicy>>; using FuncRefVector = Vector; WeakHeapPtr maybeObject_; diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.cpp index ee005681c5b..e0943d0f81a 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.cpp @@ -330,19 +330,21 @@ CheckedInt32 StructLayout::close() { bool StructType::init() { StructLayout layout; - for (StructField& field : fields_) { + for (FieldType& field : fields_) { CheckedInt32 offset = layout.addField(field.type); if (!offset.isValid()) { return false; } - field.offset = offset.value(); + if (!fieldOffsets_.append(offset.value())) { + return false; + } if (!field.type.isRefRepr()) { continue; } bool isOutline; uint32_t adjustedOffset; - WasmStructObject::fieldOffsetToAreaAndOffset(field.type, field.offset, + WasmStructObject::fieldOffsetToAreaAndOffset(field.type, offset.value(), &isOutline, &adjustedOffset); if (isOutline) { if (!outlineTraceOffsets_.append(adjustedOffset)) { @@ -367,7 +369,7 @@ bool StructType::init() { /* static */ bool StructType::createImmutable(const ValTypeVector& types, StructType* struct_) { - StructFieldVector fields; + FieldTypeVector fields; if (!fields.resize(types.length())) { return false; } diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.h b/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.h index 24f4c951eb1..84c69ea1e8c 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.h +++ b/mozjs-sys/mozjs/js/src/wasm/WasmTypeDef.h @@ -255,11 +255,14 @@ class FuncType { // structure types that the module knows about. It is created from the sparse // array of types in the ModuleEnvironment when the Module is created. -struct StructField { +struct FieldType { StorageType type; - uint32_t offset; bool isMutable; + FieldType() : isMutable(false) {} + FieldType(StorageType type, bool isMutable) + : type(type), isMutable(isMutable) {} + HashNumber hash(const RecGroup* recGroup) const { HashNumber hn = 0; hn = mozilla::AddToHash(hn, type.forMatch(recGroup).hash()); @@ -267,10 +270,18 @@ struct StructField { return hn; } + // Matches two field types for isorecursive equality. See + // "Matching type definitions" in WasmValType.h for more background. + static bool matches(const RecGroup* lhsRecGroup, const FieldType& lhs, + const RecGroup* rhsRecGroup, const FieldType& rhs) { + return lhs.isMutable == rhs.isMutable && + lhs.type.forMatch(lhsRecGroup) == rhs.type.forMatch(rhsRecGroup); + } + // Checks if two struct fields are compatible in a given subtyping // relationship. - static bool canBeSubTypeOf(const StructField& subType, - const StructField& superType) { + static bool canBeSubTypeOf(const FieldType& subType, + const FieldType& superType) { // Mutable fields are invariant w.r.t. field types if (subType.isMutable && superType.isMutable) { return subType.type == superType.type; @@ -285,35 +296,30 @@ struct StructField { } }; -using StructFieldVector = Vector; +using FieldTypeVector = Vector; +using FieldOffsetVector = Vector; using InlineTraceOffsetVector = Vector; using OutlineTraceOffsetVector = Vector; class StructType { public: - StructFieldVector fields_; // Field type, offset, and mutability + FieldTypeVector fields_; // Field type and mutability + uint32_t size_; // The size of the type in bytes. + FieldOffsetVector fieldOffsets_; InlineTraceOffsetVector inlineTraceOffsets_; OutlineTraceOffsetVector outlineTraceOffsets_; public: StructType() : size_(0) {} - explicit StructType(StructFieldVector&& fields) + explicit StructType(FieldTypeVector&& fields) : fields_(std::move(fields)), size_(0) {} StructType(StructType&&) = default; StructType& operator=(StructType&&) = default; - [[nodiscard]] bool clone(const StructType& src) { - if (!fields_.appendAll(src.fields_)) { - return false; - } - size_ = src.size_; - return true; - } - [[nodiscard]] bool init(); bool isDefaultable() const { @@ -325,9 +331,13 @@ class StructType { return true; } + uint32_t fieldOffset(uint32_t fieldIndex) const { + return fieldOffsets_[fieldIndex]; + } + HashNumber hash(const RecGroup* recGroup) const { HashNumber hn = 0; - for (const StructField& field : fields_) { + for (const FieldType& field : fields_) { hn = mozilla::AddToHash(hn, field.hash(recGroup)); } return hn; @@ -341,11 +351,9 @@ class StructType { return false; } for (uint32_t i = 0; i < lhs.fields_.length(); i++) { - const StructField& lhsField = lhs.fields_[i]; - const StructField& rhsField = rhs.fields_[i]; - if (lhsField.isMutable != rhsField.isMutable || - lhsField.type.forMatch(lhsRecGroup) != - rhsField.type.forMatch(rhsRecGroup)) { + const FieldType& lhsField = lhs.fields_[i]; + const FieldType& rhsField = rhs.fields_[i]; + if (!FieldType::matches(lhsRecGroup, lhsField, rhsRecGroup, rhsField)) { return false; } } @@ -363,8 +371,8 @@ class StructType { // Every field that is in both superType and subType must be compatible for (uint32_t i = 0; i < superType.fields_.length(); i++) { - if (!StructField::canBeSubTypeOf(subType.fields_[i], - superType.fields_[i])) { + if (!FieldType::canBeSubTypeOf(subType.fields_[i], + superType.fields_[i])) { return false; } } @@ -414,14 +422,12 @@ class StructLayout { class ArrayType { public: // The kind of value stored in this array - StorageType elementType_; - // Whether this array is mutable or not - bool isMutable_; + FieldType fieldType_; public: - ArrayType() : isMutable_(false) {} + ArrayType() = default; ArrayType(StorageType elementType, bool isMutable) - : elementType_(elementType), isMutable_(isMutable) {} + : fieldType_(FieldType(elementType, isMutable)) {} ArrayType(const ArrayType&) = default; ArrayType& operator=(const ArrayType&) = default; @@ -429,45 +435,26 @@ class ArrayType { ArrayType(ArrayType&&) = default; ArrayType& operator=(ArrayType&&) = default; - [[nodiscard]] bool clone(const ArrayType& src) { - elementType_ = src.elementType_; - isMutable_ = src.isMutable_; - return true; - } - - bool isDefaultable() const { return elementType_.isDefaultable(); } + StorageType elementType() const { return fieldType_.type; } + bool isMutable() const { return fieldType_.isMutable; } + bool isDefaultable() const { return elementType().isDefaultable(); } HashNumber hash(const RecGroup* recGroup) const { - HashNumber hn = 0; - hn = mozilla::AddToHash(hn, elementType_.forMatch(recGroup).hash()); - hn = mozilla::AddToHash(hn, HashNumber(isMutable_)); - return hn; + return fieldType_.hash(recGroup); } // Matches two array types for isorecursive equality. See // "Matching type definitions" in WasmValType.h for more background. static bool matches(const RecGroup* lhsRecGroup, const ArrayType& lhs, const RecGroup* rhsRecGroup, const ArrayType& rhs) { - return lhs.isMutable_ == rhs.isMutable_ && - lhs.elementType_.forMatch(lhsRecGroup) == - rhs.elementType_.forMatch(rhsRecGroup); + return FieldType::matches(lhsRecGroup, lhs.fieldType_, rhsRecGroup, + rhs.fieldType_); } // Checks if two arrays are compatible in a given subtyping relationship. static bool canBeSubTypeOf(const ArrayType& subType, const ArrayType& superType) { - // Mutable fields are invariant w.r.t. field types - if (subType.isMutable_ && superType.isMutable_) { - return subType.elementType_ == superType.elementType_; - } - - // Immutable fields are covariant w.r.t. field types - if (!subType.isMutable_ && !superType.isMutable_) { - return StorageType::isSubTypeOf(subType.elementType_, - superType.elementType_); - } - - return true; + return FieldType::canBeSubTypeOf(subType.fieldType_, superType.fieldType_); } size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; @@ -842,11 +829,12 @@ class TypeDef { return true; } const SuperTypeVector* subSTV = subTypeDef->superTypeVector(); + const SuperTypeVector* superSTV = superTypeDef->superTypeVector(); // During construction of a recursion group, the super type vector may not // have been computed yet, in which case we need to fall back to a linear // search. - if (!subSTV) { + if (!subSTV || !superSTV) { while (subTypeDef) { if (subTypeDef == superTypeDef) { return true; @@ -868,7 +856,6 @@ class TypeDef { return false; } - const SuperTypeVector* superSTV = superTypeDef->superTypeVector(); MOZ_ASSERT(superSTV); MOZ_ASSERT(superSTV->typeDef() == superTypeDef); @@ -1008,7 +995,7 @@ class RecGroup : public AtomicRefCounted { } case TypeDefKind::Array: { const ArrayType& arrayType = typeDef.arrayType(); - visitStorageType(arrayType.elementType_); + visitStorageType(arrayType.elementType()); break; } case TypeDefKind::None: { diff --git a/mozjs-sys/mozjs/js/src/wasm/WasmValidate.cpp b/mozjs-sys/mozjs/js/src/wasm/WasmValidate.cpp index 3a0f865d46e..e650fb0b092 100644 --- a/mozjs-sys/mozjs/js/src/wasm/WasmValidate.cpp +++ b/mozjs-sys/mozjs/js/src/wasm/WasmValidate.cpp @@ -1662,7 +1662,7 @@ static bool DecodeStructType(Decoder& d, ModuleEnvironment* env, return d.fail("too many fields in struct"); } - StructFieldVector fields; + FieldTypeVector fields; if (!fields.resize(numFields)) { return false; } diff --git a/mozjs-sys/mozjs/memory/build/Mutex.h b/mozjs-sys/mozjs/memory/build/Mutex.h index f360084f64d..3f60f1045ce 100644 --- a/mozjs-sys/mozjs/memory/build/Mutex.h +++ b/mozjs-sys/mozjs/memory/build/Mutex.h @@ -153,9 +153,13 @@ typedef Mutex StaticMutex; #ifdef XP_WIN typedef DWORD ThreadId; inline ThreadId GetThreadId() { return GetCurrentThreadId(); } +inline bool ThreadIdEqual(ThreadId a, ThreadId b) { return a == b; } #else typedef pthread_t ThreadId; inline ThreadId GetThreadId() { return pthread_self(); } +inline bool ThreadIdEqual(ThreadId a, ThreadId b) { + return pthread_equal(a, b); +} #endif class MOZ_CAPABILITY("mutex") MaybeMutex : public Mutex { @@ -212,7 +216,7 @@ class MOZ_CAPABILITY("mutex") MaybeMutex : public Mutex { // protected resource. #ifdef MOZ_DEBUG bool SafeOnThisThread() const { - return mDoLock == MUST_LOCK || GetThreadId() == mThreadId; + return mDoLock == MUST_LOCK || ThreadIdEqual(GetThreadId(), mThreadId); } #endif @@ -228,7 +232,7 @@ class MOZ_CAPABILITY("mutex") MaybeMutex : public Mutex { return true; } - MOZ_ASSERT(GetThreadId() == mThreadId); + MOZ_ASSERT(ThreadIdEqual(GetThreadId(), mThreadId)); return false; } diff --git a/mozjs-sys/mozjs/memory/build/mozjemalloc.cpp b/mozjs-sys/mozjs/memory/build/mozjemalloc.cpp index bf2ca807866..f17f9935680 100644 --- a/mozjs-sys/mozjs/memory/build/mozjemalloc.cpp +++ b/mozjs-sys/mozjs/memory/build/mozjemalloc.cpp @@ -1392,7 +1392,8 @@ class ArenaCollection { // We're running on the main thread which is set by a call to SetMainThread(). bool IsOnMainThread() const { - return mMainThreadId.isSome() && mMainThreadId.value() == GetThreadId(); + return mMainThreadId.isSome() && + ThreadIdEqual(mMainThreadId.value(), GetThreadId()); } // We're running on the main thread or SetMainThread() has never been called. @@ -1401,11 +1402,10 @@ class ArenaCollection { } // After a fork set the new thread ID in the child. - void PostForkFixMainThread() { - if (mMainThreadId.isSome()) { - // Only if the main thread has been defined. - mMainThreadId = Some(GetThreadId()); - } + void ResetMainThread() { + // The post fork handler in the child can run from a MacOS worker thread, + // so we can't set our main thread to it here. Instead we have to clear it. + mMainThreadId = Nothing(); } void SetMainThread() { @@ -1550,6 +1550,9 @@ static bool malloc_init_hard(); FORK_HOOK void _malloc_prefork(void); FORK_HOOK void _malloc_postfork_parent(void); FORK_HOOK void _malloc_postfork_child(void); +# ifdef XP_DARWIN +FORK_HOOK void _malloc_postfork(void); +# endif #endif // End forward declarations. @@ -5178,13 +5181,23 @@ inline void MozJemalloc::moz_set_max_dirty_page_modifier(int32_t aModifier) { // state for the child is if fork is called from the main thread only. Or the // child must not use them, eg it should call exec(). We attempt to prevent the // child for accessing these arenas by refusing to re-initialise them. +// +// This is only accessed in the fork handlers while gArenas.mLock is held. static pthread_t gForkingThread; +# ifdef XP_DARWIN +// This is only accessed in the fork handlers while gArenas.mLock is held. +static pid_t gForkingProcess; +# endif + FORK_HOOK void _malloc_prefork(void) MOZ_NO_THREAD_SAFETY_ANALYSIS { // Acquire all mutexes in a safe order. gArenas.mLock.Lock(); gForkingThread = pthread_self(); +# ifdef XP_DARWIN + gForkingProcess = getpid(); +# endif for (auto arena : gArenas.iter()) { if (arena->mLock.LockIsEnabled()) { @@ -5215,6 +5228,9 @@ void _malloc_postfork_parent(void) MOZ_NO_THREAD_SAFETY_ANALYSIS { FORK_HOOK void _malloc_postfork_child(void) { + // Do this before iterating over the arenas. + gArenas.ResetMainThread(); + // Reinitialize all mutexes, now that fork() has completed. huge_mtx.Init(); @@ -5224,10 +5240,24 @@ void _malloc_postfork_child(void) { arena->mLock.Reinit(gForkingThread); } - gArenas.PostForkFixMainThread(); gArenas.mLock.Init(); } -#endif // XP_WIN + +# ifdef XP_DARWIN +FORK_HOOK +void _malloc_postfork(void) { + // On MacOS we need to check if this is running in the parent or child + // process. + bool is_in_parent = getpid() == gForkingProcess; + gForkingProcess = 0; + if (is_in_parent) { + _malloc_postfork_parent(); + } else { + _malloc_postfork_child(); + } +} +# endif // XP_DARWIN +#endif // ! XP_WIN // End library-private functions. // *************************************************************************** diff --git a/mozjs-sys/mozjs/memory/build/zone.c b/mozjs-sys/mozjs/memory/build/zone.c index 7311ccf27bc..eaabcf01bdb 100644 --- a/mozjs-sys/mozjs/memory/build/zone.c +++ b/mozjs-sys/mozjs/memory/build/zone.c @@ -232,8 +232,9 @@ static void zone_print(malloc_zone_t* zone, boolean_t verbose) {} static void zone_log(malloc_zone_t* zone, void* address) {} +// On Darwin the postfork handler is called in both the parent and the child. extern void _malloc_prefork(void); -extern void _malloc_postfork_child(void); +extern void _malloc_postfork(void); static void zone_force_lock(malloc_zone_t* zone) { // /!\ This calls into mozjemalloc. It works because we're linked in the @@ -244,7 +245,7 @@ static void zone_force_lock(malloc_zone_t* zone) { static void zone_force_unlock(malloc_zone_t* zone) { // /!\ This calls into mozjemalloc. It works because we're linked in the // same library. - _malloc_postfork_child(); + _malloc_postfork(); } static void zone_statistics(malloc_zone_t* zone, malloc_statistics_t* stats) { diff --git a/mozjs-sys/mozjs/mfbt/Attributes.h b/mozjs-sys/mozjs/mfbt/Attributes.h index 3be46cf5a82..2e93c634704 100644 --- a/mozjs-sys/mozjs/mfbt/Attributes.h +++ b/mozjs-sys/mozjs/mfbt/Attributes.h @@ -78,6 +78,13 @@ # define MOZ_HAVE_NO_STACK_PROTECTOR __attribute__((no_stack_protector)) #endif +/* if defined(__clang__) && __has_attribute (attr) may not be portable */ +#if defined(__clang__) +# define MOZ_HAS_CLANG_ATTRIBUTE(attr) __has_attribute(attr) +#else +# define MOZ_HAS_CLANG_ATTRIBUTE(attr) 0 +#endif + /* * When built with clang analyzer (a.k.a scan-build), define MOZ_HAVE_NORETURN * to mark some false positives @@ -88,15 +95,13 @@ # endif #endif -#if defined(__GNUC__) || \ - (defined(__clang__) && __has_attribute(no_profile_instrument_function)) +#if defined(__GNUC__) || MOZ_HAS_CLANG_ATTRIBUTE(no_profile_instrument_function) # define MOZ_NOPROFILE __attribute__((no_profile_instrument_function)) #else # define MOZ_NOPROFILE #endif -#if defined(__GNUC__) || \ - (defined(__clang__) && __has_attribute(no_instrument_function)) +#if defined(__GNUC__) || (MOZ_HAS_CLANG_ATTRIBUTE(no_instrument_function)) # define MOZ_NOINSTRUMENT __attribute__((no_instrument_function)) #else # define MOZ_NOINSTRUMENT @@ -121,7 +126,7 @@ * * This is useful to have clearer information on assertion failures. */ -#if defined(__clang__) && __has_attribute(nomerge) +#if MOZ_HAS_CLANG_ATTRIBUTE(nomerge) # define MOZ_NOMERGE __attribute__((nomerge)) #else # define MOZ_NOMERGE diff --git a/mozjs-sys/mozjs/modules/libpref/init/StaticPrefList.yaml b/mozjs-sys/mozjs/modules/libpref/init/StaticPrefList.yaml index 824bc50ed83..1a89a174540 100644 --- a/mozjs-sys/mozjs/modules/libpref/init/StaticPrefList.yaml +++ b/mozjs-sys/mozjs/modules/libpref/init/StaticPrefList.yaml @@ -3013,6 +3013,14 @@ value: @IS_EARLY_BETA_OR_EARLIER@ mirror: always +# Does mousewheel-scrolling over a focused or +# field cause the value to increase/decrease (rather +# than scrolling the page)? +- name: dom.input.number_and_range_modified_by_mousewheel + type: RelaxedAtomicBool + value: false + mirror: always + # Whether to allow or disallow web apps to cancel `beforeinput` events caused # by MozEditableElement#setUserInput() which is used by autocomplete, autofill # and password manager. @@ -10124,6 +10132,8 @@ value: true #elif defined(XP_OPENBSD) value: true +#elif defined(XP_SOLARIS) + value: true #else value: false #endif @@ -10166,6 +10176,8 @@ value: true #elif defined(XP_OPENBSD) value: true +#elif defined(XP_SOLARIS) + value: true #else value: false #endif @@ -10214,6 +10226,8 @@ value: true #elif defined(XP_OPENBSD) value: true +#elif defined(XP_SOLARIS) + value: true #else value: false #endif @@ -10231,6 +10245,8 @@ value: true #elif defined(XP_OPENBSD) value: true +#elif defined(XP_SOLARIS) + value: true #else value: false #endif @@ -10248,6 +10264,8 @@ value: true #elif defined(XP_OPENBSD) value: true +#elif defined(XP_SOLARIS) + value: true #else value: false #endif @@ -10265,6 +10283,8 @@ value: true #elif defined(XP_OPENBSD) value: true +#elif defined(XP_SOLARIS) + value: true #else value: false #endif @@ -10294,6 +10314,8 @@ value: true #elif defined(XP_OPENBSD) value: true +#elif defined(XP_SOLARIS) + value: true #else value: false #endif @@ -11350,6 +11372,11 @@ #endif mirror: always +- name: media.webrtc.tls_tunnel_for_all_proxy + type: bool + value: true + mirror: always + # If true, then we require explicit approval from the embedding app (ex. Fenix) # on GeckoView to know if we can allow audible, inaudible media or both kinds # of media to autoplay. @@ -11687,7 +11714,7 @@ # whether to redirect the channel for auth redirects. See Bug 1820807 - name: network.auth.use_redirect_for_retries type: RelaxedAtomicBool - value: true + value: @IS_EARLY_BETA_OR_EARLIER@ mirror: always # When true, authentication challenges will be sorted even if @@ -13126,7 +13153,7 @@ - name: network.http.http2.enabled.deps type: RelaxedAtomicBool - value: false + value: true mirror: always - name: network.http.http2.enforce-tls-profile @@ -14741,6 +14768,13 @@ mirror: once #endif +#if defined(XP_LINUX) && defined(MOZ_SANDBOX) +- name: security.sandbox.warn_unprivileged_namespaces + type: bool + value: true + mirror: always +#endif + # Pref to show warning when submitting from secure to insecure. - name: security.warn_submit_secure_to_insecure type: bool @@ -15007,6 +15041,15 @@ value: 3 mirror: always +# The CRLite filter channel to which the user is subscribed. +# - "all" => filters that contain all revocations, +# - "specified" => filters that contain revocations with specified reason codes, +# - "priority" => filters that contain high priority revocations. +- name: security.pki.crlite_channel + type: String + value: "specified" + mirror: never + - name: security.tls.version.min type: RelaxedAtomicUint32 value: 3 diff --git a/mozjs-sys/mozjs/python/mach/mach/mixin/process.py b/mozjs-sys/mozjs/python/mach/mach/mixin/process.py index f9b50463b68..535a469b594 100644 --- a/mozjs-sys/mozjs/python/mach/mach/mixin/process.py +++ b/mozjs-sys/mozjs/python/mach/mach/mixin/process.py @@ -170,13 +170,10 @@ def handleLine(line): p.processOutput() status = None sig = None - # XXX: p.wait() sometimes fails to detect the process exit and never returns a status code. - # Time out and check if the pid still exists. - # See bug 1845125 for example. - while status is None and p.pid_exists(p.pid): + while status is None: try: if sig is None: - status = p.wait(5) + status = p.wait() else: status = p.kill(sig=sig) except KeyboardInterrupt: diff --git a/mozjs-sys/mozjs/python/mozboot/mozboot/gentoo.py b/mozjs-sys/mozjs/python/mozboot/mozboot/gentoo.py index 4ddf86696fd..3518b5c2634 100644 --- a/mozjs-sys/mozjs/python/mozboot/mozboot/gentoo.py +++ b/mozjs-sys/mozjs/python/mozboot/mozboot/gentoo.py @@ -20,7 +20,8 @@ def install_packages(self, packages): } # watchman is available but requires messing with USEs. packages = [DISAMBIGUATE.get(p, p) for p in packages if p != "watchman"] - self.run_as_root(["emerge", "--noreplace"] + packages) + if packages: + self.run_as_root(["emerge", "--noreplace"] + packages) def _update_package_manager(self): self.run_as_root(["emerge", "--sync"]) diff --git a/mozjs-sys/mozjs/python/mozbuild/mozbuild/backend/recursivemake.py b/mozjs-sys/mozjs/python/mozbuild/mozbuild/backend/recursivemake.py index e3b5649d7e7..3ccf77de3b9 100644 --- a/mozjs-sys/mozjs/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/mozjs-sys/mozjs/python/mozbuild/mozbuild/backend/recursivemake.py @@ -1365,7 +1365,10 @@ def _process_non_default_target(self, libdef, target_name, backend_file): def _process_shared_library(self, libdef, backend_file): backend_file.write_once("LIBRARY_NAME := %s\n" % libdef.basename) backend_file.write("FORCE_SHARED_LIB := 1\n") - backend_file.write("IMPORT_LIBRARY := %s\n" % libdef.import_name) + backend_file.write( + "IMPORT_LIBRARY := %s\n" + % self._pretty_path(libdef.import_path, backend_file) + ) shared_lib = self._pretty_path(libdef.output_path, backend_file) backend_file.write("SHARED_LIBRARY := %s\n" % shared_lib) if libdef.soname: @@ -1389,9 +1392,8 @@ def _process_sandboxed_wasm_library(self, libdef, backend_file): backend_file.write("WASM_ARCHIVE := %s\n" % libdef.basename) def _process_rust_library(self, libdef, backend_file): - backend_file.write_once( - "%s := %s\n" % (libdef.LIB_FILE_VAR, libdef.import_name) - ) + rust_lib = self._pretty_path(libdef.import_path, backend_file) + backend_file.write_once("%s := %s\n" % (libdef.LIB_FILE_VAR, rust_lib)) backend_file.write_once("CARGO_FILE := $(srcdir)/Cargo.toml\n") # Need to normalize the path so Cargo sees the same paths from all # possible invocations of Cargo with this CARGO_TARGET_DIR. Otherwise, @@ -1404,7 +1406,7 @@ def _process_rust_library(self, libdef, backend_file): "%s := %s\n" % (libdef.FEATURES_VAR, " ".join(libdef.features)) ) if libdef.output_category: - self._process_non_default_target(libdef, libdef.import_name, backend_file) + self._process_non_default_target(libdef, rust_lib, backend_file) def _process_host_shared_library(self, libdef, backend_file): backend_file.write("HOST_SHARED_LIBRARY = %s\n" % libdef.lib_name) @@ -1424,9 +1426,6 @@ def _build_target_for_obj(self, obj): ) def _process_linked_libraries(self, obj, backend_file): - def pretty_relpath(path): - return os.path.normpath(mozpath.relpath(path, obj.objdir)) - objs, shared_libs, os_libs, static_libs = self._expand_libs(obj) obj_target = obj.name @@ -1480,7 +1479,7 @@ def pretty_relpath(path): for lib in shared_libs: assert obj.KIND != "host" and obj.KIND != "wasm" backend_file.write_once( - "SHARED_LIBS += %s\n" % pretty_relpath(lib.import_path) + "SHARED_LIBS += %s\n" % self._pretty_path(lib.import_path, backend_file) ) # We have to link any Rust libraries after all intermediate static @@ -1492,7 +1491,7 @@ def pretty_relpath(path): (l for l in static_libs if isinstance(l, BaseRustLibrary)), ): backend_file.write_once( - "%s += %s\n" % (var, pretty_relpath(lib.import_path)) + "%s += %s\n" % (var, self._pretty_path(lib.import_path, backend_file)) ) for lib in os_libs: diff --git a/mozjs-sys/mozjs/python/mozbuild/mozbuild/frontend/data.py b/mozjs-sys/mozjs/python/mozbuild/mozbuild/frontend/data.py index b2b11736ae3..dfc0e647a7a 100644 --- a/mozjs-sys/mozjs/python/mozbuild/mozbuild/frontend/data.py +++ b/mozjs-sys/mozjs/python/mozbuild/mozbuild/frontend/data.py @@ -639,7 +639,7 @@ def name(self): @property def import_path(self): - return mozpath.join(self.objdir, self.import_name) + return ObjDirPath(self._context, "!" + self.import_name) class Library(BaseLibrary): @@ -696,7 +696,6 @@ class BaseRustLibrary(object): "cargo_file", "crate_type", "dependencies", - "deps_path", "features", "output_category", "is_gkrust", @@ -735,15 +734,21 @@ def init( # build in that case. if not context.config.substs.get("COMPILE_ENVIRONMENT"): return - build_dir = mozpath.join( - context.config.topobjdir, - cargo_output_directory(context, self.TARGET_SUBST_VAR), + self.import_name = self.lib_name + + @property + def import_path(self): + return ObjDirPath( + self._context, + "!/" + + mozpath.join( + cargo_output_directory(self._context, self.TARGET_SUBST_VAR), + self.import_name, + ), ) - self.import_name = mozpath.join(build_dir, self.lib_name) - self.deps_path = mozpath.join(build_dir, "deps") -class RustLibrary(StaticLibrary, BaseRustLibrary): +class RustLibrary(BaseRustLibrary, StaticLibrary): """Context derived container object for a rust static library""" KIND = "target" @@ -882,10 +887,9 @@ def import_path(self): if self.config.substs.get("OS_ARCH") == "WINNT": # We build import libs on windows in a library's objdir # to avoid cluttering up dist/bin. - return mozpath.join(self.objdir, self.import_name) - return mozpath.join( - mozpath.dirname(self.output_path.full_path), self.import_name - ) + return ObjDirPath(self._context, "!" + self.import_name) + assert self.import_name == self.name + return self.output_path class HostSharedLibrary(HostMixin, Library): @@ -927,7 +931,7 @@ class HostLibrary(HostMixin, BaseLibrary): no_expand_lib = False -class HostRustLibrary(HostLibrary, BaseRustLibrary): +class HostRustLibrary(BaseRustLibrary, HostLibrary): """Context derived container object for a host rust library""" KIND = "host" diff --git a/mozjs-sys/mozjs/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/mozjs-sys/mozjs/python/mozbuild/mozbuild/test/backend/test_recursivemake.py index a120ff81ce9..53dd9be0276 100644 --- a/mozjs-sys/mozjs/python/mozbuild/mozbuild/test/backend/test_recursivemake.py +++ b/mozjs-sys/mozjs/python/mozbuild/mozbuild/test/backend/test_recursivemake.py @@ -944,8 +944,7 @@ def test_rust_library(self): ] expected = [ - "RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libtest_library.a" - % env.topobjdir, # noqa + "RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libtest_library.a", "CARGO_FILE := $(srcdir)/Cargo.toml", "CARGO_TARGET_DIR := %s" % env.topobjdir, ] @@ -965,8 +964,7 @@ def test_host_rust_library(self): ] expected = [ - "HOST_RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libhostrusttool.a" - % env.topobjdir, # noqa + "HOST_RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libhostrusttool.a", "CARGO_FILE := $(srcdir)/Cargo.toml", "CARGO_TARGET_DIR := %s" % env.topobjdir, ] @@ -986,8 +984,7 @@ def test_host_rust_library_with_features(self): ] expected = [ - "HOST_RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libhostrusttool.a" - % env.topobjdir, # noqa + "HOST_RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libhostrusttool.a", "CARGO_FILE := $(srcdir)/Cargo.toml", "CARGO_TARGET_DIR := %s" % env.topobjdir, "HOST_RUST_LIBRARY_FEATURES := musthave cantlivewithout", @@ -1008,8 +1005,7 @@ def test_rust_library_with_features(self): ] expected = [ - "RUST_LIBRARY_FILE := %s/x86_64-unknown-linux-gnu/release/libfeature_library.a" - % env.topobjdir, # noqa + "RUST_LIBRARY_FILE := x86_64-unknown-linux-gnu/release/libfeature_library.a", "CARGO_FILE := $(srcdir)/Cargo.toml", "CARGO_TARGET_DIR := %s" % env.topobjdir, "RUST_LIBRARY_FEATURES := musthave cantlivewithout", @@ -1203,23 +1199,23 @@ def test_linkage(self): env = self._consume("linkage", RecursiveMakeBackend) expected_linkage = { "prog": { - "SHARED_LIBS": ["../dist/bin/qux.so", "../dist/bin/baz.so"], - "STATIC_LIBS": ["../real/foo.a"], + "SHARED_LIBS": ["$(DEPTH)/dist/bin/qux.so", "$(DEPTH)/dist/bin/baz.so"], + "STATIC_LIBS": ["$(DEPTH)/real/foo.a"], "OS_LIBS": ["-lfoo", "-lbaz", "-lbar"], }, "shared": { "OS_LIBS": ["-lfoo"], - "SHARED_LIBS": ["../dist/bin/qux.so"], + "SHARED_LIBS": ["$(DEPTH)/dist/bin/qux.so"], "STATIC_LIBS": [], }, "static": { - "STATIC_LIBS": ["../real/foo.a"], + "STATIC_LIBS": ["$(DEPTH)/real/foo.a"], "OS_LIBS": ["-lbar"], - "SHARED_LIBS": ["../dist/bin/qux.so"], + "SHARED_LIBS": ["$(DEPTH)/dist/bin/qux.so"], }, "real": { "STATIC_LIBS": [], - "SHARED_LIBS": ["../dist/bin/qux.so"], + "SHARED_LIBS": ["$(DEPTH)/dist/bin/qux.so"], "OS_LIBS": ["-lbaz"], }, } @@ -1230,7 +1226,6 @@ def test_linkage(self): for name in expected_linkage: for var in expected_linkage[name]: for val in expected_linkage[name][var]: - val = os.path.normpath(val) line = "%s += %s" % (var, val) self.assertIn(line, actual_linkage[name]) actual_linkage[name].remove(line) diff --git a/mozjs-sys/mozjs/testing/mozbase/mozprocess/mozprocess/processhandler.py b/mozjs-sys/mozjs/testing/mozbase/mozprocess/mozprocess/processhandler.py index 705ff5a2106..668120aa325 100644 --- a/mozjs-sys/mozjs/testing/mozbase/mozprocess/mozprocess/processhandler.py +++ b/mozjs-sys/mozjs/testing/mozbase/mozprocess/mozprocess/processhandler.py @@ -12,6 +12,7 @@ import codecs import errno +import io import os import signal import subprocess @@ -88,7 +89,6 @@ class Process(subprocess.Popen): """ MAX_IOCOMPLETION_PORT_NOTIFICATION_DELAY = 180 - MAX_PROCESS_KILL_DELAY = 30 TIMEOUT_BEFORE_SIGKILL = 1.0 def __init__( @@ -114,6 +114,8 @@ def __init__( self._ignore_children = ignore_children self._job = None self._io_port = None + if isWin: + self._cleanup_lock = threading.Lock() if not self._ignore_children and not isWin: # Set the process group id for linux systems @@ -170,7 +172,7 @@ def __del__(self): else: subprocess.Popen.__del__(self) - def kill(self, sig=None, timeout=None): + def send_signal(self, sig=None): if isWin: try: if not self._ignore_children and self._handle and self._job: @@ -237,6 +239,8 @@ def send_sig(sig, retries=0): # a signal was explicitly set or not posix send_sig(sig or signal.SIGKILL) + def kill(self, sig=None, timeout=None): + self.send_signal(sig) self.returncode = self.wait(timeout) self._cleanup() return self.returncode @@ -245,11 +249,13 @@ def poll(self): """Popen.poll Check if child process has terminated. Set and return returncode attribute. """ - # If we have a handle, the process is alive - if isWin and getattr(self, "_handle", None): - return None - - return subprocess.Popen.poll(self) + if isWin: + returncode = self._custom_wait(timeout=0) + else: + returncode = subprocess.Popen.poll(self) + if returncode is not None: + self._cleanup() + return returncode def wait(self, timeout=None): """Popen.wait @@ -259,7 +265,8 @@ def wait(self, timeout=None): """ # This call will be different for each OS self.returncode = self._custom_wait(timeout=timeout) - self._cleanup() + if self.returncode is not None: + self._cleanup() return self.returncode """ Private Members of Process class """ @@ -453,6 +460,11 @@ def _procmgr(self): try: self._poll_iocompletion_port() + except Exception: + traceback.print_exc() + # If _poll_iocompletion_port threw an exception for some unexpected reason, + # send an event that will make _custom_wait throw an Exception. + self._process_events.put({}) except KeyboardInterrupt: raise KeyboardInterrupt @@ -501,7 +513,7 @@ def _poll_iocompletion_port(self): file=sys.stderr, ) - self.kill() + self.send_signal() self._process_events.put({self.pid: "FINISHED"}) break @@ -585,25 +597,19 @@ def _custom_wait(self, timeout=None): """ # First, check to see if the process is still running if self._handle: - self.returncode = winprocess.GetExitCodeProcess(self._handle) + returncode = winprocess.GetExitCodeProcess(self._handle) + if returncode != winprocess.STILL_ACTIVE: + self.returncode = returncode else: # Dude, the process is like totally dead! return self.returncode - threadalive = False - if hasattr(self, "_procmgrthread"): - threadalive = self._procmgrthread.is_alive() - if ( - self._job - and threadalive - and threading.current_thread() != self._procmgrthread - ): + # On Windows, an unlimited timeout prevents KeyboardInterrupt from + # being caught. + the_timeout = 0.1 if timeout is None else timeout + + if self._job: self.debug("waiting with IO completion port") - if timeout is None: - timeout = ( - self.MAX_IOCOMPLETION_PORT_NOTIFICATION_DELAY - + self.MAX_PROCESS_KILL_DELAY - ) # Then we are managing with IO Completion Ports # wait on a signal so we know when we have seen the last # process come through. @@ -611,12 +617,26 @@ def _custom_wait(self, timeout=None): # function because events just didn't have robust enough error # handling on pre-2.7 versions try: - # timeout is the max amount of time the procmgr thread will wait for - # child processes to shutdown before killing them with extreme prejudice. - item = self._process_events.get(timeout=timeout) + while True: + try: + item = self._process_events.get(timeout=the_timeout) + except Empty: + # The timeout was not given by the user, we just have a + # timeout to allow KeyboardInterrupt, so retry. + if timeout is None: + continue + else: + raise + break + + # re-emit the event in case some other thread is also calling wait() + self._process_events.put(item) if item[self.pid] == "FINISHED": self.debug("received 'FINISHED' from _procmgrthread") self._process_events.task_done() + except Empty: + # There was no event within the expected time. + pass except Exception: traceback.print_exc() raise OSError( @@ -624,10 +644,9 @@ def _custom_wait(self, timeout=None): ) finally: if self._handle: - self.returncode = winprocess.GetExitCodeProcess( - self._handle - ) - self._cleanup() + returncode = winprocess.GetExitCodeProcess(self._handle) + if returncode != winprocess.STILL_ACTIVE: + self.returncode = returncode else: # Not managing with job objects, so all we can reasonably do @@ -637,27 +656,26 @@ def _custom_wait(self, timeout=None): if not self._ignore_children: self.debug("NOT USING JOB OBJECTS!!!") # First, make sure we have not already ended - if self.returncode != winprocess.STILL_ACTIVE: - self._cleanup() + if self.returncode is not None: return self.returncode rc = None if self._handle: - if timeout is None: - timeout = -1 - else: - # timeout for WaitForSingleObject is in ms - timeout = timeout * 1000 - - rc = winprocess.WaitForSingleObject(self._handle, timeout) + # timeout for WaitForSingleObject is in ms + the_timeout = int(the_timeout * 1000) + while True: + rc = winprocess.WaitForSingleObject( + self._handle, the_timeout + ) + # The timeout was not given by the user, we just have a + # timeout to allow KeyboardInterrupt, so retry. + if timeout is None and rc == winprocess.WAIT_TIMEOUT: + continue + break if rc == winprocess.WAIT_TIMEOUT: - # The process isn't dead, so kill it - print( - "Timed out waiting for process to close, " - "attempting TerminateProcess" - ) - self.kill() + # Timeout happened as asked. + pass elif rc == winprocess.WAIT_OBJECT_0: # We caught WAIT_OBJECT_0, which indicates all is well print("Single process terminated successfully") @@ -668,8 +686,6 @@ def _custom_wait(self, timeout=None): if rc: raise WinError(rc) - self._cleanup() - return self.returncode def _cleanup_job_io_port(self): @@ -701,6 +717,7 @@ def _cleanup_job_io_port(self): self._procmgrthread = None def _cleanup(self): + self._cleanup_lock.acquire() self._cleanup_job_io_port() if self._thread and self._thread != winprocess.INVALID_HANDLE_VALUE: self._thread.Close() @@ -713,6 +730,7 @@ def _cleanup(self): self._handle = None else: self._handle = None + self._cleanup_lock.release() else: @@ -879,7 +897,7 @@ def kill(self, sig=None, timeout=None): # When we kill the the managed process we also have to wait for the # reader thread to be finished. Otherwise consumers would have to assume # that it still has not completely shutdown. - rc = self.wait(timeout) + rc = self.wait(0) if rc is None: self.debug("kill: wait failed -- process is still alive") return rc @@ -899,7 +917,7 @@ def poll(self): # Ensure that we first check for the reader status. Otherwise # we might mark the process as finished while output is still getting # processed. - elif self.reader.is_alive(): + elif not self._ignore_children and self.reader.is_alive(): return None elif hasattr(self, "returncode"): return self.returncode @@ -942,18 +960,22 @@ def wait(self, timeout=None): - '0' if the process ended without failures """ - # Thread.join() blocks the main thread until the reader thread is finished - # wake up once a second in case a keyboard interrupt is sent - if self.reader.thread and self.reader.thread is not threading.current_thread(): - count = 0 - while self.reader.is_alive(): - if timeout is not None and count > timeout: - self.debug("wait timeout for reader thread") - return None - self.reader.join(timeout=1) - count += 1 - self.returncode = self.proc.wait(timeout) + if ( + self.returncode is not None + and self.reader.thread + and self.reader.thread is not threading.current_thread() + ): + # If children are ignored and a child is still running because it's + # been daemonized or something, the reader might still be attached + # to that child'd output... and joining will deadlock. + # So instead, we wait for there to be no more active reading still + # happening. + if self._ignore_children: + while self.reader.is_still_reading(timeout=0.1): + time.sleep(0.1) + else: + self.reader.join() return self.returncode @property @@ -1058,6 +1080,7 @@ def __init__( self.timeout = timeout self.output_timeout = output_timeout self.thread = None + self.got_data = threading.Event() self.didOutputTimeout = False def debug(self, msg): @@ -1074,87 +1097,74 @@ def _create_stream_reader(self, name, stream, queue, callback): return thread def _read_stream(self, stream, queue, callback): - while True: - line = stream.readline() - if not line: - break + sentinel = "" if isinstance(stream, io.TextIOBase) else b"" + for line in iter(stream.readline, sentinel): queue.put((line, callback)) + # Give a chance to the reading loop to exit without a timeout. + queue.put((b"", None)) stream.close() def start(self, proc): queue = Queue() - stdout_reader = None + readers = 0 if proc.stdout: - stdout_reader = self._create_stream_reader( + self._create_stream_reader( "ProcessReaderStdout", proc.stdout, queue, self.stdout_callback ) - stderr_reader = None + readers += 1 if proc.stderr and proc.stderr != proc.stdout: - stderr_reader = self._create_stream_reader( + self._create_stream_reader( "ProcessReaderStderr", proc.stderr, queue, self.stderr_callback ) + readers += 1 self.thread = threading.Thread( name="ProcessReader", target=self._read, - args=(stdout_reader, stderr_reader, queue), + args=(queue, readers), ) self.thread.daemon = True self.thread.start() self.debug("ProcessReader started") - def _read(self, stdout_reader, stderr_reader, queue): + def _read(self, queue, readers): start_time = time.time() - timed_out = False timeout = self.timeout if timeout is not None: timeout += start_time output_timeout = self.output_timeout - if output_timeout is not None: - output_timeout += start_time - while (stdout_reader and stdout_reader.is_alive()) or ( - stderr_reader and stderr_reader.is_alive() - ): - has_line = True - try: - line, callback = queue.get(True, INTERVAL_PROCESS_ALIVE_CHECK) - except Empty: - has_line = False - now = time.time() - if not has_line: - if output_timeout is not None and now > output_timeout: - timed_out = True - self.didOutputTimeout = True - break - else: - if output_timeout is not None: - output_timeout = now + self.output_timeout - callback(line.rstrip()) - if timeout is not None and now > timeout: - timed_out = True - break - self.debug("_read loop exited") - # process remaining lines to read - while not queue.empty(): - line, callback = queue.get(False) + def get_line(): + queue_timeout = None + if timeout: + queue_timeout = timeout - time.time() + if output_timeout: + if queue_timeout: + queue_timeout = min(queue_timeout, output_timeout) + else: + queue_timeout = output_timeout + return queue.get(timeout=queue_timeout) + + try: + # We need to wait for as many `(b"", None)` sentinels as there are + # reader threads setup in start. + for n in range(readers): + for line, callback in iter(get_line, (b"", None)): + self.got_data.set() + try: + callback(line.rstrip()) + except Exception: + traceback.print_exc() try: - callback(line.rstrip()) + self.finished_callback() except Exception: traceback.print_exc() - if timed_out: + except Empty: + if timeout and time.time() < timeout: + self.didOutputTimeout = True try: self.timeout_callback() except Exception: traceback.print_exc() - if stdout_reader: - stdout_reader.join() - if stderr_reader: - stderr_reader.join() - if not timed_out: - try: - self.finished_callback() - except Exception: - traceback.print_exc() self.debug("_read exited") def is_alive(self): @@ -1162,6 +1172,10 @@ def is_alive(self): return self.thread.is_alive() return False + def is_still_reading(self, timeout): + self.got_data.clear() + return self.got_data.wait(timeout) + def join(self, timeout=None): if self.thread: self.thread.join(timeout=timeout)