commit 326b02025ec685428465a45cf71972225f9ebdea
parent a8dfb8b4c814b294b02f737575a15810107c60c9
Author: Tooru Fujisawa <arai_a@mac.com>
Date: Tue, 2 Dec 2025 08:27:53 +0000
Bug 1956867 - Take a snapshot of the load time before sorting the cached stencils. r=mccr8
Differential Revision: https://phabricator.services.mozilla.com/D273803
Diffstat:
2 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/js/xpconnect/loader/ScriptPreloader.cpp b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -675,6 +675,36 @@ void ScriptPreloader::PrepareCacheWrite() {
PrepareCacheWriteInternal();
}
+// A struct to hold reference to a CachedStencil and the snapshot of the
+// CachedStencil::mLoadTime field.
+// CachedStencil::mLoadTime field can be modified concurrently, and we need
+// to create a snapshot, in order to sort scripts.
+struct CachedStencilRefAndTime {
+ using CachedStencil = ScriptPreloader::CachedStencil;
+ CachedStencil* mStencil;
+ TimeStamp mLoadTime;
+
+ explicit CachedStencilRefAndTime(CachedStencil* aStencil)
+ : mStencil(aStencil), mLoadTime(aStencil->mLoadTime) {}
+
+ // For use with nsTArray::Sort.
+ //
+ // Orders scripts by script load time, so that scripts which are needed
+ // earlier are stored earlier, and scripts needed at approximately the
+ // same time are stored approximately contiguously.
+ struct Comparator {
+ bool Equals(const CachedStencilRefAndTime& a,
+ const CachedStencilRefAndTime& b) const {
+ return a.mLoadTime == b.mLoadTime;
+ }
+
+ bool LessThan(const CachedStencilRefAndTime& a,
+ const CachedStencilRefAndTime& b) const {
+ return a.mLoadTime < b.mLoadTime;
+ }
+ };
+} JS_HAZ_NON_GC_POINTER;
+
// Writes out a script cache file for the scripts accessed during early
// startup in this session. The cache file is a little-endian binary file with
// the following format:
@@ -727,19 +757,20 @@ Result<Ok, nsresult> ScriptPreloader::WriteCache() {
mMonitor.AssertNotCurrentThreadOwns();
MonitorAutoLock mal(mMonitor);
- nsTArray<CachedStencil*> scripts;
+ nsTArray<CachedStencilRefAndTime> scriptRefs;
for (auto& script : IterHash(mScripts, Match<ScriptStatus::Saved>())) {
- scripts.AppendElement(script);
+ scriptRefs.AppendElement(CachedStencilRefAndTime(script));
}
// Sort scripts by load time, with async loaded scripts before sync scripts.
// Since async scripts are always loaded immediately at startup, it helps to
// have them stored contiguously.
- scripts.Sort(CachedStencil::Comparator());
+ scriptRefs.Sort(CachedStencilRefAndTime::Comparator());
OutputBuffer buf;
size_t offset = 0;
- for (auto script : scripts) {
+ for (auto& scriptRef : scriptRefs) {
+ auto* script = scriptRef.mStencil;
script->mOffset = offset;
MOZ_DIAGNOSTIC_ASSERT(
JS::IsTranscodingBytecodeOffsetAligned(script->mOffset));
@@ -769,7 +800,8 @@ Result<Ok, nsresult> ScriptPreloader::WriteCache() {
written += padding;
}
- for (auto script : scripts) {
+ for (auto& scriptRef : scriptRefs) {
+ auto* script = scriptRef.mStencil;
MOZ_DIAGNOSTIC_ASSERT(JS::IsTranscodingBytecodeOffsetAligned(written));
MOZ_TRY(Write(fd, script->Range().begin().get(), script->mSize));
diff --git a/js/xpconnect/loader/ScriptPreloader.h b/js/xpconnect/loader/ScriptPreloader.h
@@ -66,6 +66,8 @@ struct Matcher {
using namespace mozilla::loader;
+struct CachedStencilRefAndTime;
+
class ScriptPreloader : public nsIObserver,
public nsIMemoryReporter,
public nsIRunnable,
@@ -215,21 +217,6 @@ class ScriptPreloader : public nsIObserver,
: ScriptStatus::Saved;
}
- // For use with nsTArray::Sort.
- //
- // Orders scripts by script load time, so that scripts which are needed
- // earlier are stored earlier, and scripts needed at approximately the
- // same time are stored approximately contiguously.
- struct Comparator {
- bool Equals(const CachedStencil* a, const CachedStencil* b) const {
- return a->mLoadTime == b->mLoadTime;
- }
-
- bool LessThan(const CachedStencil* a, const CachedStencil* b) const {
- return a->mLoadTime < b->mLoadTime;
- }
- };
-
struct StatusMatcher final : public Matcher<CachedStencil*> {
explicit StatusMatcher(ScriptStatus status) : mStatus(status) {}
@@ -387,6 +374,8 @@ class ScriptPreloader : public nsIObserver,
MaybeOneOf<JS::TranscodeBuffer, nsTArray<uint8_t>> mXDRData;
} JS_HAZ_NON_GC_POINTER;
+ friend struct CachedStencilRefAndTime;
+
template <ScriptStatus status>
static Matcher<CachedStencil*>* Match() {
static CachedStencil::StatusMatcher matcher{status};