Bug 1361900: Part 2 - Add process types field to cached script data. r?erahm
MozReview-Commit-ID: Gvh672XD0ar
--- a/js/xpconnect/loader/ScriptPreloader-inl.h
+++ b/js/xpconnect/loader/ScriptPreloader-inl.h
@@ -4,16 +4,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ScriptPreloader_inl_h
#define ScriptPreloader_inl_h
#include "mozilla/Attributes.h"
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
+#include "mozilla/EnumSet.h"
#include "mozilla/Range.h"
#include "mozilla/Result.h"
#include "mozilla/Unused.h"
#include "nsString.h"
#include "nsTArray.h"
#include <prio.h>
@@ -51,16 +52,32 @@ public:
write(size_t size)
{
auto buf = data.AppendElements(size);
cursor_ += size;
return buf;
}
void
+ codeUint8(const uint8_t& val)
+ {
+ *write(sizeof val) = val;
+ }
+
+ template<typename T>
+ void
+ codeUint8(const EnumSet<T>& val)
+ {
+ // EnumSets are always represented as uint32_t values, so we need to
+ // assert that the value actually fits in a uint8 before writing it.
+ uint32_t value = val.serialize();
+ codeUint8(CheckedUint8(value).value());
+ }
+
+ void
codeUint16(const uint16_t& val)
{
LittleEndian::writeUint16(write(sizeof val), val);
}
void
codeUint32(const uint32_t& val)
{
@@ -101,16 +118,36 @@ public:
MOZ_ASSERT(checkCapacity(size));
auto buf = &data[cursor_];
cursor_ += size;
return buf;
}
bool
+ codeUint8(uint8_t& val)
+ {
+ if (checkCapacity(sizeof val)) {
+ val = *read(sizeof val);
+ }
+ return !error_;
+ }
+
+ template<typename T>
+ bool
+ codeUint8(EnumSet<T>& val)
+ {
+ uint8_t value;
+ if (codeUint8(value)) {
+ val.deserialize(value);
+ }
+ return !error_;
+ }
+
+ bool
codeUint16(uint16_t& val)
{
if (checkCapacity(sizeof val)) {
val = LittleEndian::readUint16(read(sizeof val));
}
return !error_;
}
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -8,16 +8,18 @@
#include "ScriptPreloader-inl.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/FileUtils.h"
#include "mozilla/Logging.h"
#include "mozilla/Services.h"
#include "mozilla/Unused.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ScriptSettings.h"
#include "MainThreadUtils.h"
#include "nsDebug.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIFile.h"
#include "nsIObserverService.h"
#include "nsJSUtils.h"
@@ -36,16 +38,19 @@ namespace {
static LazyLogModule gLog("ScriptPreloader");
#define LOG(level, ...) MOZ_LOG(gLog, LogLevel::level, (__VA_ARGS__))
}
using mozilla::dom::AutoJSAPI;
using namespace mozilla::loader;
+ProcessType ScriptPreloader::sProcessType;
+
+
nsresult
ScriptPreloader::CollectReports(nsIHandleReportCallback* aHandleReport,
nsISupports* aData, bool aAnonymize)
{
MOZ_COLLECT_REPORT(
"explicit/script-preloader/heap/saved-scripts", KIND_HEAP, UNITS_BYTES,
SizeOfLinkedList(mSavedScripts, MallocSizeOf),
"Memory used to hold the scripts which have been executed in this "
@@ -80,16 +85,25 @@ ScriptPreloader::GetSingleton()
singleton = new ScriptPreloader();
ClearOnShutdown(&singleton);
}
return *singleton;
}
+ProcessType
+ScriptPreloader::GetChildProcessType(const nsAString& remoteType)
+{
+ if (remoteType.EqualsLiteral(EXTENSION_REMOTE_TYPE)) {
+ return ProcessType::Extension;
+ }
+ return ProcessType::Web;
+}
+
namespace {
struct MOZ_RAII AutoSafeJSAPI : public AutoJSAPI
{
AutoSafeJSAPI() { Init(); }
};
@@ -115,16 +129,22 @@ ScriptPreloader::Trace(JSTracer* trc)
}
}
ScriptPreloader::ScriptPreloader()
: mMonitor("[ScriptPreloader.mMonitor]")
, mSaveMonitor("[ScriptPreloader.mSaveMonitor]")
{
+ if (XRE_IsParentProcess()) {
+ sProcessType = ProcessType::Parent;
+ } else {
+ sProcessType = GetChildProcessType(dom::ContentChild::GetSingleton()->GetRemoteType());
+ }
+
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
MOZ_RELEASE_ASSERT(obs);
obs->AddObserver(this, DELAYED_STARTUP_TOPIC, false);
obs->AddObserver(this, SHUTDOWN_TOPIC, false);
obs->AddObserver(this, CLEANUP_TOPIC, false);
obs->AddObserver(this, CACHE_FLUSH_TOPIC, false);
AutoSafeJSAPI jsapi;
@@ -236,17 +256,17 @@ ScriptPreloader::GetCacheFile(const char
NS_TRY(cacheFile->AppendNative(NS_LITERAL_CSTRING("startupCache")));
Unused << cacheFile->Create(nsIFile::DIRECTORY_TYPE, 0777);
NS_TRY(cacheFile->AppendNative(nsDependentCString(leafName)));
return Move(cacheFile);
}
-static const uint8_t MAGIC[] = "mozXDRcache";
+static const uint8_t MAGIC[] = "mozXDRcachev001";
Result<Ok, nsresult>
ScriptPreloader::OpenCache()
{
NS_TRY(NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(mProfD)));
nsCOMPtr<nsIFile> cacheFile;
MOZ_TRY_VAR(cacheFile, GetCacheFile("scriptCache.bin"));
@@ -348,17 +368,18 @@ ScriptPreloader::InitCache()
MOZ_RELEASE_ASSERT(jsapi.Init(xpc::CompilationScope()));
JSContext* cx = jsapi.cx();
auto start = TimeStamp::Now();
LOG(Info, "Off-thread decoding scripts...\n");
JS::CompileOptions options(cx, JSVERSION_LATEST);
for (auto script : mRestoredScripts) {
- if (script->mSize > MIN_OFFTHREAD_SIZE &&
+ if (script->mProcessTypes.contains(CurrentProcessType()) &&
+ script->mSize > MIN_OFFTHREAD_SIZE &&
JS::CanCompileOffThread(cx, options, script->mSize)) {
DecodeScriptOffThread(cx, script);
} else {
script->mReadyToExecute = true;
}
}
LOG(Info, "Initialized decoding in %fms\n",
@@ -438,16 +459,17 @@ ScriptPreloader::PrepareCacheWrite()
//
// - A uint32 containing the size of the header block.
//
// - A header entry for each file stored in the cache containing:
// - The URL that the script was originally read from.
// - Its cache key.
// - The offset of its XDR data within the XDR data block.
// - The size of its XDR data in the XDR data block.
+// - A bit field describing which process types the script is used in.
//
// - A block of XDR data for the encoded scripts, with each script's data at
// an offset from the start of the block, as specified above.
Result<Ok, nsresult>
ScriptPreloader::WriteCache()
{
MOZ_ASSERT(!NS_IsMainThread());
@@ -559,20 +581,23 @@ ScriptPreloader::NoteScript(const nsCStr
restored = FindScript(mRestoredScripts, cachePath);
}
if (restored) {
restored->remove();
mSavedScripts.insertBack(restored);
MOZ_ASSERT(script);
+ restored->mProcesses += CurrentProcessType();
restored->mScript = script;
restored->mReadyToExecute = true;
} else if (!exists) {
auto cachedScript = new CachedScript(url, cachePath, script);
+ cachedScript->mProcesses += CurrentProcessType();
+
mSavedScripts.insertBack(cachedScript);
mScripts.Put(cachePath, cachedScript);
}
}
JSScript*
ScriptPreloader::GetCachedScript(JSContext* cx, const nsCString& path)
{
--- a/js/xpconnect/loader/ScriptPreloader.h
+++ b/js/xpconnect/loader/ScriptPreloader.h
@@ -1,16 +1,18 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
/* 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/CheckedInt.h"
+#include "mozilla/EnumSet.h"
#include "mozilla/LinkedList.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/Maybe.h"
#include "mozilla/Monitor.h"
#include "mozilla/Range.h"
#include "mozilla/Vector.h"
#include "mozilla/Result.h"
#include "mozilla/loader/AutoMemMap.h"
@@ -22,16 +24,22 @@
#include "jsapi.h"
#include <prio.h>
namespace mozilla {
namespace loader {
class InputBuffer;
+
+ enum class ProcessType : uint8_t {
+ Parent,
+ Web,
+ Extension,
+ };
}
using namespace mozilla::loader;
class ScriptPreloader : public nsIObserver
, public nsIMemoryReporter
, public nsIRunnable
{
@@ -40,30 +48,37 @@ class ScriptPreloader : public nsIObserv
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIMEMORYREPORTER
NS_DECL_NSIRUNNABLE
static ScriptPreloader& GetSingleton();
+ static ProcessType GetChildProcessType(const nsAString& remoteType);
+
// 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 nsCString& name);
// 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.
void NoteScript(const nsCString& url, const nsCString& cachePath, JS::HandleScript script);
// Initializes the script cache from the startup script cache file.
Result<Ok, nsresult> InitCache();
void Trace(JSTracer* trc);
+ static ProcessType CurrentProcessType()
+ {
+ return sProcessType;
+ }
+
protected:
virtual ~ScriptPreloader() = default;
private:
// 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.
//
@@ -121,16 +136,17 @@ private:
// 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& Data()
{
MOZ_ASSERT(mXDRData.isSome());
return mXDRData.ref();
@@ -175,16 +191,19 @@ private:
// is too small to be decoded off-thread, and may be immediately decoded
// whenever it is first executed.
bool mReadyToExecute = false;
// The off-thread decode token for a completed off-thread decode, which
// has not yet been finalized on the main thread.
void* mToken = nullptr;
+ // The set of processes in which this script has been used.
+ EnumSet<ProcessType> mProcessTypes{};
+
// 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.
Maybe<JS::TranscodeBuffer> mXDRData;
@@ -272,16 +291,19 @@ private:
// 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;
+ // The process type of the current process.
+ static ProcessType sProcessType;
+
nsCOMPtr<nsIFile> mProfD;
nsCOMPtr<nsIThread> mSaveThread;
// The mmapped cache data from this session's cache file.
AutoMemMap mCacheData;
Monitor mMonitor;
Monitor mSaveMonitor;
--- a/js/xpconnect/loader/moz.build
+++ b/js/xpconnect/loader/moz.build
@@ -38,10 +38,12 @@ EXTRA_JS_MODULES += [
FINAL_LIBRARY = 'xul'
LOCAL_INCLUDES += [
'../src',
'../wrappers',
'/dom/base',
]
+include('/ipc/chromium/chromium-config.mozbuild')
+
if CONFIG['GNU_CXX']:
CXXFLAGS += ['-Wno-shadow']