forked from mirrors/gecko-dev
		
	 c90491dbe9
			
		
	
	
		c90491dbe9
		
	
	
	
	
		
			
			Add `mWaitingForDecode` to indicate that main-thread is blocked on the Monitor and should be woken. This avoids generating some of the unused Runnables. Also ensure `mFinishDecodeRunnablePending` is only accessed while holding the lock. Depends on D99403 Differential Revision: https://phabricator.services.mozilla.com/D99404
		
			
				
	
	
		
			563 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			563 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
 | |
| /* 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 ScriptPreloader_h
 | |
| #define ScriptPreloader_h
 | |
| 
 | |
| #include "mozilla/Atomics.h"
 | |
| #include "mozilla/CheckedInt.h"
 | |
| #include "mozilla/EnumSet.h"
 | |
| #include "mozilla/LinkedList.h"
 | |
| #include "mozilla/MemoryReporting.h"
 | |
| #include "mozilla/Maybe.h"
 | |
| #include "mozilla/MaybeOneOf.h"
 | |
| #include "mozilla/Monitor.h"
 | |
| #include "mozilla/Range.h"
 | |
| #include "mozilla/Vector.h"
 | |
| #include "mozilla/Result.h"
 | |
| #include "mozilla/loader/AutoMemMap.h"
 | |
| #include "nsClassHashtable.h"
 | |
| #include "nsIAsyncShutdown.h"
 | |
| #include "nsIFile.h"
 | |
| #include "nsIMemoryReporter.h"
 | |
| #include "nsIObserver.h"
 | |
| #include "nsIThread.h"
 | |
| #include "nsITimer.h"
 | |
| 
 | |
| #include "js/GCAnnotations.h"  // for JS_HAZ_NON_GC_POINTER
 | |
| #include "js/RootingAPI.h"     // for Handle, Heap
 | |
| #include "js/Transcoding.h"  // for TranscodeBuffer, TranscodeRange, TranscodeSources
 | |
| #include "js/TypeDecls.h"  // for HandleObject, HandleScript
 | |
| 
 | |
| #include <prio.h>
 | |
| 
 | |
| namespace JS {
 | |
| class CompileOptions;
 | |
| class OffThreadToken;
 | |
| }  // namespace JS
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| class ContentParent;
 | |
| }
 | |
| namespace ipc {
 | |
| class FileDescriptor;
 | |
| }
 | |
| namespace loader {
 | |
| class InputBuffer;
 | |
| class ScriptCacheChild;
 | |
| 
 | |
| enum class ProcessType : uint8_t {
 | |
|   Uninitialized,
 | |
|   Parent,
 | |
|   Web,
 | |
|   Extension,
 | |
|   PrivilegedAbout,
 | |
| };
 | |
| 
 | |
| template <typename T>
 | |
| struct Matcher {
 | |
|   virtual bool Matches(T) = 0;
 | |
| };
 | |
| }  // namespace loader
 | |
| 
 | |
| using namespace mozilla::loader;
 | |
| 
 | |
| class ScriptPreloader : public nsIObserver,
 | |
|                         public nsIMemoryReporter,
 | |
|                         public nsIRunnable,
 | |
|                         public nsIAsyncShutdownBlocker {
 | |
|   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
 | |
| 
 | |
|   friend class mozilla::loader::ScriptCacheChild;
 | |
| 
 | |
|  public:
 | |
|   NS_DECL_THREADSAFE_ISUPPORTS
 | |
|   NS_DECL_NSIOBSERVER
 | |
|   NS_DECL_NSIMEMORYREPORTER
 | |
|   NS_DECL_NSIRUNNABLE
 | |
|   NS_DECL_NSIASYNCSHUTDOWNBLOCKER
 | |
| 
 | |
|   static ScriptPreloader& GetSingleton();
 | |
|   static ScriptPreloader& GetChildSingleton();
 | |
| 
 | |
|   static ProcessType GetChildProcessType(const nsACString& remoteType);
 | |
| 
 | |
|   // Fill some options that should be consistent across all scripts stored
 | |
|   // into preloader cache.
 | |
|   static void FillCompileOptionsForCachedScript(JS::CompileOptions& options);
 | |
| 
 | |
|   // Retrieves the script with the given cache key from the script cache.
 | |
|   // Returns null if the script is not cached.
 | |
|   JSScript* GetCachedScript(JSContext* cx,
 | |
|                             const JS::ReadOnlyCompileOptions& options,
 | |
|                             const nsCString& path);
 | |
| 
 | |
|   // Notes the execution of a script with the given URL and cache key.
 | |
|   // Depending on the stage of startup, the script may be serialized and
 | |
|   // stored to the startup script cache.
 | |
|   //
 | |
|   // If isRunOnce is true, this script is expected to run only once per
 | |
|   // process per browser session. A cached instance will not be kept alive
 | |
|   // for repeated execution.
 | |
|   void NoteScript(const nsCString& url, const nsCString& cachePath,
 | |
|                   JS::HandleScript script, bool isRunOnce = false);
 | |
| 
 | |
|   void NoteScript(const nsCString& url, const nsCString& cachePath,
 | |
|                   ProcessType processType, nsTArray<uint8_t>&& xdrData,
 | |
|                   TimeStamp loadTime);
 | |
| 
 | |
|   // Initializes the script cache from the startup script cache file.
 | |
|   Result<Ok, nsresult> InitCache(const nsAString& = u"scriptCache"_ns);
 | |
| 
 | |
|   Result<Ok, nsresult> InitCache(const Maybe<ipc::FileDescriptor>& cacheFile,
 | |
|                                  ScriptCacheChild* cacheChild);
 | |
| 
 | |
|   bool Active() { return mCacheInitialized && !mStartupFinished; }
 | |
| 
 | |
|  private:
 | |
|   Result<Ok, nsresult> InitCacheInternal(JS::HandleObject scope = nullptr);
 | |
|   JSScript* GetCachedScriptInternal(JSContext* cx,
 | |
|                                     const JS::ReadOnlyCompileOptions& options,
 | |
|                                     const nsCString& path);
 | |
| 
 | |
|  public:
 | |
|   void Trace(JSTracer* trc);
 | |
| 
 | |
|   static ProcessType CurrentProcessType() {
 | |
|     MOZ_ASSERT(sProcessType != ProcessType::Uninitialized);
 | |
|     return sProcessType;
 | |
|   }
 | |
| 
 | |
|   static void InitContentChild(dom::ContentParent& parent);
 | |
| 
 | |
|  protected:
 | |
|   virtual ~ScriptPreloader() = default;
 | |
| 
 | |
|  private:
 | |
|   enum class ScriptStatus {
 | |
|     Restored,
 | |
|     Saved,
 | |
|   };
 | |
| 
 | |
|   // Represents a cached JS script, either initially read from the script
 | |
|   // cache file, to be added to the next session's script cache file, or
 | |
|   // both.
 | |
|   //
 | |
|   // A script which was read from the cache file may be in any of the
 | |
|   // following states:
 | |
|   //
 | |
|   //  - Read from the cache, and being compiled off thread. In this case,
 | |
|   //    mReadyToExecute is false, and mToken is null.
 | |
|   //  - Off-thread compilation has finished, but the script has not yet been
 | |
|   //    executed. In this case, mReadyToExecute is true, and mToken has a
 | |
|   //    non-null value.
 | |
|   //  - Read from the cache, but too small or needed to immediately to be
 | |
|   //    compiled off-thread. In this case, mReadyToExecute is true, and both
 | |
|   //    mToken and mScript are null.
 | |
|   //  - Fully decoded, and ready to be added to the next session's cache
 | |
|   //    file. In this case, mReadyToExecute is true, and mScript is non-null.
 | |
|   //
 | |
|   // A script to be added to the next session's cache file always has a
 | |
|   // non-null mScript value. If it was read from the last session's cache
 | |
|   // file, it also has a non-empty mXDRRange range, which will be stored in
 | |
|   // the next session's cache file. If it was compiled in this session, its
 | |
|   // mXDRRange will initially be empty, and its mXDRData buffer will be
 | |
|   // populated just before it is written to the cache file.
 | |
|   class CachedScript : public LinkedListElement<CachedScript> {
 | |
|    public:
 | |
|     CachedScript(CachedScript&&) = delete;
 | |
| 
 | |
|     CachedScript(ScriptPreloader& cache, const nsCString& url,
 | |
|                  const nsCString& cachePath, JSScript* script)
 | |
|         : mCache(cache),
 | |
|           mURL(url),
 | |
|           mCachePath(cachePath),
 | |
|           mScript(script),
 | |
|           mReadyToExecute(true),
 | |
|           mIsRunOnce(false) {}
 | |
| 
 | |
|     inline CachedScript(ScriptPreloader& cache, InputBuffer& buf);
 | |
| 
 | |
|     ~CachedScript() = default;
 | |
| 
 | |
|     ScriptStatus Status() const {
 | |
|       return mProcessTypes.isEmpty() ? ScriptStatus::Restored
 | |
|                                      : 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 CachedScript* a, const CachedScript* b) const {
 | |
|         return a->mLoadTime == b->mLoadTime;
 | |
|       }
 | |
| 
 | |
|       bool LessThan(const CachedScript* a, const CachedScript* b) const {
 | |
|         return a->mLoadTime < b->mLoadTime;
 | |
|       }
 | |
|     };
 | |
| 
 | |
|     struct StatusMatcher final : public Matcher<CachedScript*> {
 | |
|       explicit StatusMatcher(ScriptStatus status) : mStatus(status) {}
 | |
| 
 | |
|       virtual bool Matches(CachedScript* script) override {
 | |
|         return script->Status() == mStatus;
 | |
|       }
 | |
| 
 | |
|       const ScriptStatus mStatus;
 | |
|     };
 | |
| 
 | |
|     // The purpose of this helper class is to avoid a race between
 | |
|     // ScriptPreloader::WriteCache() and the GC on a JSScript*.
 | |
|     // The former checks if the actual JSScript* is null on the save thread
 | |
|     // while holding mMonitor. Aside from GC tracing, all places that mutate
 | |
|     // the JSScript* either hold mMonitor or don't run at the same time as the
 | |
|     // save thread. The GC can move the script, which will cause the value to
 | |
|     // change, but this will not change whether it is null or not.
 | |
|     //
 | |
|     // We can't hold mMonitor while tracing, because we can end running the
 | |
|     // GC while the current thread already holds mMonitor. Instead, this class
 | |
|     // avoids the race by storing a separate field to indicate if the script is
 | |
|     // null or not. To enforce this, the mutation by the GC that cannot affect
 | |
|     // the nullness of the script is split out from other mutation.
 | |
|     class MOZ_HEAP_CLASS ScriptHolder {
 | |
|      public:
 | |
|       explicit ScriptHolder(JSScript* script)
 | |
|           : mScript(script), mHasScript(script) {}
 | |
|       ScriptHolder() : mHasScript(false) {}
 | |
| 
 | |
|       // This should only be called on the main thread (either while holding
 | |
|       // the preloader's mMonitor or while the save thread isn't running), or on
 | |
|       // the save thread while holding the preloader's mMonitor.
 | |
|       explicit operator bool() const { return mHasScript; }
 | |
| 
 | |
|       // This should only be called on the main thread.
 | |
|       JSScript* Get() const {
 | |
|         MOZ_ASSERT(NS_IsMainThread());
 | |
|         return mScript;
 | |
|       }
 | |
| 
 | |
|       // This should only be called on the main thread (or from a GC thread
 | |
|       // while the main thread is GCing).
 | |
|       void Trace(JSTracer* trc);
 | |
| 
 | |
|       // These should only be called on the main thread, either while holding
 | |
|       // the preloader's mMonitor or while the save thread isn't running.
 | |
|       void Set(JS::HandleScript jsscript);
 | |
|       void Clear();
 | |
| 
 | |
|      private:
 | |
|       JS::Heap<JSScript*> mScript;
 | |
|       bool mHasScript;  // true iff mScript is non-null.
 | |
|     };
 | |
| 
 | |
|     void FreeData() {
 | |
|       // If the script data isn't mmapped, we need to release both it
 | |
|       // and the Range that points to it at the same time.
 | |
|       if (!mXDRData.empty()) {
 | |
|         mXDRRange.reset();
 | |
|         mXDRData.destroy();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     void UpdateLoadTime(const TimeStamp& loadTime) {
 | |
|       if (mLoadTime.IsNull() || loadTime < mLoadTime) {
 | |
|         mLoadTime = loadTime;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // Checks whether the cached JSScript for this entry will be needed
 | |
|     // again and, if not, drops it and returns true. This is the case for
 | |
|     // run-once scripts that do not still need to be encoded into the
 | |
|     // cache.
 | |
|     //
 | |
|     // If this method returns false, callers may set mScript to a cached
 | |
|     // JSScript instance for this entry. If it returns true, they should
 | |
|     // not.
 | |
|     bool MaybeDropScript() {
 | |
|       if (mIsRunOnce && (HasRange() || !mCache.WillWriteScripts())) {
 | |
|         mScript.Clear();
 | |
|         return true;
 | |
|       }
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     // Encodes this script into XDR data, and stores the result in mXDRData.
 | |
|     // Returns true on success, false on failure.
 | |
|     bool XDREncode(JSContext* cx);
 | |
| 
 | |
|     // Encodes or decodes this script, in the storage format required by the
 | |
|     // script cache file.
 | |
|     template <typename Buffer>
 | |
|     void Code(Buffer& buffer) {
 | |
|       buffer.codeString(mURL);
 | |
|       buffer.codeString(mCachePath);
 | |
|       buffer.codeUint32(mOffset);
 | |
|       buffer.codeUint32(mSize);
 | |
|       buffer.codeUint8(mProcessTypes);
 | |
|     }
 | |
| 
 | |
|     // Returns the XDR data generated for this script during this session. See
 | |
|     // mXDRData.
 | |
|     JS::TranscodeBuffer& Buffer() {
 | |
|       MOZ_ASSERT(HasBuffer());
 | |
|       return mXDRData.ref<JS::TranscodeBuffer>();
 | |
|     }
 | |
| 
 | |
|     bool HasBuffer() { return mXDRData.constructed<JS::TranscodeBuffer>(); }
 | |
| 
 | |
|     // Returns the read-only XDR data for this script. See mXDRRange.
 | |
|     const JS::TranscodeRange& Range() {
 | |
|       MOZ_ASSERT(HasRange());
 | |
|       return mXDRRange.ref();
 | |
|     }
 | |
| 
 | |
|     bool HasRange() { return mXDRRange.isSome(); }
 | |
| 
 | |
|     nsTArray<uint8_t>& Array() {
 | |
|       MOZ_ASSERT(HasArray());
 | |
|       return mXDRData.ref<nsTArray<uint8_t>>();
 | |
|     }
 | |
| 
 | |
|     bool HasArray() { return mXDRData.constructed<nsTArray<uint8_t>>(); }
 | |
| 
 | |
|     JSScript* GetJSScript(JSContext* cx,
 | |
|                           const JS::ReadOnlyCompileOptions& options);
 | |
| 
 | |
|     size_t HeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
 | |
|       auto size = mallocSizeOf(this);
 | |
| 
 | |
|       if (HasArray()) {
 | |
|         size += Array().ShallowSizeOfExcludingThis(mallocSizeOf);
 | |
|       } else if (HasBuffer()) {
 | |
|         size += Buffer().sizeOfExcludingThis(mallocSizeOf);
 | |
|       } else {
 | |
|         return size;
 | |
|       }
 | |
| 
 | |
|       // Note: mURL and mCachePath use the same string for scripts loaded
 | |
|       // by the message manager. The following statement avoids
 | |
|       // double-measuring in that case.
 | |
|       size += (mURL.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
 | |
|                mCachePath.SizeOfExcludingThisEvenIfShared(mallocSizeOf));
 | |
| 
 | |
|       return size;
 | |
|     }
 | |
| 
 | |
|     ScriptPreloader& mCache;
 | |
| 
 | |
|     // The URL from which this script was initially read and compiled.
 | |
|     nsCString mURL;
 | |
|     // A unique identifier for this script's filesystem location, used as a
 | |
|     // primary cache lookup value.
 | |
|     nsCString mCachePath;
 | |
| 
 | |
|     // The offset of this script in the cache file, from the start of the XDR
 | |
|     // data block.
 | |
|     uint32_t mOffset = 0;
 | |
|     // The size of this script's encoded XDR data.
 | |
|     uint32_t mSize = 0;
 | |
| 
 | |
|     TimeStamp mLoadTime{};
 | |
| 
 | |
|     ScriptHolder mScript;
 | |
| 
 | |
|     // True if this script is ready to be executed. This means that either the
 | |
|     // off-thread portion of an off-thread decode has finished, or the script
 | |
|     // is too small to be decoded off-thread, and may be immediately decoded
 | |
|     // whenever it is first executed.
 | |
|     bool mReadyToExecute = false;
 | |
| 
 | |
|     // True if this script is expected to run once per process. If so, its
 | |
|     // JSScript instance will be dropped as soon as the script has
 | |
|     // executed and been encoded into the cache.
 | |
|     bool mIsRunOnce = false;
 | |
| 
 | |
|     // The set of processes in which this script has been used.
 | |
|     EnumSet<ProcessType> mProcessTypes{};
 | |
| 
 | |
|     // The set of processes which the script was loaded into during the
 | |
|     // last session, as read from the cache file.
 | |
|     EnumSet<ProcessType> mOriginalProcessTypes{};
 | |
| 
 | |
|     // The read-only XDR data for this script, which was either read from an
 | |
|     // existing cache file, or generated by encoding a script which was
 | |
|     // compiled during this session.
 | |
|     Maybe<JS::TranscodeRange> mXDRRange;
 | |
| 
 | |
|     // XDR data which was generated from a script compiled during this
 | |
|     // session, and will be written to the cache file.
 | |
|     MaybeOneOf<JS::TranscodeBuffer, nsTArray<uint8_t>> mXDRData;
 | |
|   } JS_HAZ_NON_GC_POINTER;
 | |
| 
 | |
|   template <ScriptStatus status>
 | |
|   static Matcher<CachedScript*>* Match() {
 | |
|     static CachedScript::StatusMatcher matcher{status};
 | |
|     return &matcher;
 | |
|   }
 | |
| 
 | |
|   // There's a significant setup cost for each off-thread decode operation,
 | |
|   // so scripts are decoded in chunks to minimize the overhead. There's a
 | |
|   // careful balancing act in choosing the size of chunks, to minimize the
 | |
|   // number of decode operations, while also minimizing the number of buffer
 | |
|   // underruns that require the main thread to wait for a script to finish
 | |
|   // decoding.
 | |
|   //
 | |
|   // For the first chunk, we don't have much time between the start of the
 | |
|   // decode operation and the time the first script is needed, so that chunk
 | |
|   // needs to be fairly small. After the first chunk is finished, we have
 | |
|   // some buffered scripts to fall back on, and a lot more breathing room,
 | |
|   // so the chunks can be a bit bigger, but still not too big.
 | |
|   static constexpr int OFF_THREAD_FIRST_CHUNK_SIZE = 128 * 1024;
 | |
|   static constexpr int OFF_THREAD_CHUNK_SIZE = 512 * 1024;
 | |
| 
 | |
|   // Ideally, we want every chunk to be smaller than the chunk sizes
 | |
|   // specified above. However, if we have some number of small scripts
 | |
|   // followed by a huge script that would put us over the normal chunk size,
 | |
|   // we're better off processing them as a single chunk.
 | |
|   //
 | |
|   // In order to guarantee that the JS engine will process a chunk
 | |
|   // off-thread, it needs to be at least 100K (which is an implementation
 | |
|   // detail that can change at any time), so make sure that we always hit at
 | |
|   // least that size, with a bit of breathing room to be safe.
 | |
|   static constexpr int SMALL_SCRIPT_CHUNK_THRESHOLD = 128 * 1024;
 | |
| 
 | |
|   // The maximum size of scripts to re-decode on the main thread if off-thread
 | |
|   // decoding hasn't finished yet. In practice, we don't hit this very often,
 | |
|   // but when we do, re-decoding some smaller scripts on the main thread gives
 | |
|   // the background decoding a chance to catch up without blocking the main
 | |
|   // thread for quite as long.
 | |
|   static constexpr int MAX_MAINTHREAD_DECODE_SIZE = 50 * 1024;
 | |
| 
 | |
|   ScriptPreloader();
 | |
| 
 | |
|   void Cleanup();
 | |
| 
 | |
|   void FinishPendingParses(MonitorAutoLock& aMal);
 | |
|   void InvalidateCache();
 | |
| 
 | |
|   // Opens the cache file for reading.
 | |
|   Result<Ok, nsresult> OpenCache();
 | |
| 
 | |
|   // Writes a new cache file to disk. Must not be called on the main thread.
 | |
|   Result<Ok, nsresult> WriteCache();
 | |
| 
 | |
|   void StartCacheWrite();
 | |
| 
 | |
|   // Prepares scripts for writing to the cache, serializing new scripts to
 | |
|   // XDR, and calculating their size-based offsets.
 | |
|   void PrepareCacheWrite();
 | |
| 
 | |
|   void PrepareCacheWriteInternal();
 | |
| 
 | |
|   void CacheWriteComplete();
 | |
| 
 | |
|   void FinishContentStartup();
 | |
| 
 | |
|   // Returns true if scripts added to the cache now will be encoded and
 | |
|   // written to the cache. If we've already encoded scripts for the cache
 | |
|   // write, or this is a content process which hasn't been asked to return
 | |
|   // script bytecode, this will return false.
 | |
|   bool WillWriteScripts();
 | |
| 
 | |
|   // Returns a file pointer for the cache file with the given name in the
 | |
|   // current profile.
 | |
|   Result<nsCOMPtr<nsIFile>, nsresult> GetCacheFile(const nsAString& suffix);
 | |
| 
 | |
|   // Waits for the given cached script to finish compiling off-thread, or
 | |
|   // decodes it synchronously on the main thread, as appropriate.
 | |
|   JSScript* WaitForCachedScript(JSContext* cx,
 | |
|                                 const JS::ReadOnlyCompileOptions& options,
 | |
|                                 CachedScript* script);
 | |
| 
 | |
|   void DecodeNextBatch(size_t chunkSize, JS::HandleObject scope = nullptr);
 | |
| 
 | |
|   static void OffThreadDecodeCallback(JS::OffThreadToken* token, void* context);
 | |
|   void FinishOffThreadDecode(JS::OffThreadToken* token);
 | |
|   void DoFinishOffThreadDecode();
 | |
| 
 | |
|   already_AddRefed<nsIAsyncShutdownClient> GetShutdownBarrier();
 | |
| 
 | |
|   size_t ShallowHeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
 | |
|     return (mallocSizeOf(this) +
 | |
|             mScripts.ShallowSizeOfExcludingThis(mallocSizeOf) +
 | |
|             mallocSizeOf(mSaveThread.get()) + mallocSizeOf(mProfD.get()));
 | |
|   }
 | |
| 
 | |
|   using ScriptHash = nsClassHashtable<nsCStringHashKey, CachedScript>;
 | |
| 
 | |
|   template <ScriptStatus status>
 | |
|   static size_t SizeOfHashEntries(ScriptHash& scripts,
 | |
|                                   mozilla::MallocSizeOf mallocSizeOf) {
 | |
|     size_t size = 0;
 | |
|     for (auto elem : IterHash(scripts, Match<status>())) {
 | |
|       size += elem->HeapSizeOfIncludingThis(mallocSizeOf);
 | |
|     }
 | |
|     return size;
 | |
|   }
 | |
| 
 | |
|   ScriptHash mScripts;
 | |
| 
 | |
|   // True after we've shown the first window, and are no longer adding new
 | |
|   // scripts to the cache.
 | |
|   bool mStartupFinished = false;
 | |
| 
 | |
|   bool mCacheInitialized = false;
 | |
|   bool mSaveComplete = false;
 | |
|   bool mDataPrepared = false;
 | |
|   // May only be changed on the main thread, while `mSaveMonitor` is held.
 | |
|   bool mCacheInvalidated = false;
 | |
| 
 | |
|   // The list of scripts that we read from the initial startup cache file,
 | |
|   // but have yet to initiate a decode task for.
 | |
|   LinkedList<CachedScript> mPendingScripts;
 | |
| 
 | |
|   // The lists of scripts and their sources that make up the chunk currently
 | |
|   // being decoded in a background thread.
 | |
|   JS::TranscodeSources mParsingSources;
 | |
|   Vector<CachedScript*> mParsingScripts;
 | |
| 
 | |
|   // The token for the completed off-thread decode task.
 | |
|   Atomic<JS::OffThreadToken*, ReleaseAcquire> mToken{nullptr};
 | |
| 
 | |
|   // True if a runnable has been dispatched to the main thread to finish an
 | |
|   // off-thread decode operation. Access only while 'mMonitor' is held.
 | |
|   bool mFinishDecodeRunnablePending = false;
 | |
| 
 | |
|   // True is main-thread is blocked and we should notify with Monitor. Access
 | |
|   // only while `mMonitor` is held.
 | |
|   bool mWaitingForDecode = false;
 | |
| 
 | |
|   // The process type of the current process.
 | |
|   static ProcessType sProcessType;
 | |
| 
 | |
|   // The process types for which remote processes have been initialized, and
 | |
|   // are expected to send back script data.
 | |
|   EnumSet<ProcessType> mInitializedProcesses{};
 | |
| 
 | |
|   RefPtr<ScriptPreloader> mChildCache;
 | |
|   ScriptCacheChild* mChildActor = nullptr;
 | |
| 
 | |
|   nsString mBaseName;
 | |
|   nsCString mContentStartupFinishedTopic;
 | |
| 
 | |
|   nsCOMPtr<nsIFile> mProfD;
 | |
|   nsCOMPtr<nsIThread> mSaveThread;
 | |
|   nsCOMPtr<nsITimer> mSaveTimer;
 | |
| 
 | |
|   // The mmapped cache data from this session's cache file.
 | |
|   AutoMemMap mCacheData;
 | |
| 
 | |
|   Monitor mMonitor;
 | |
|   Monitor mSaveMonitor;
 | |
| };
 | |
| 
 | |
| }  // namespace mozilla
 | |
| 
 | |
| #endif  // ScriptPreloader_h
 |