Bug 936700 - Worker Preferences cache. r=bent

This commit is contained in:
Nikhil Marathe 2013-11-24 11:27:15 -08:00
parent 2b1b97f534
commit 552ae51362
9 changed files with 162 additions and 84 deletions

View File

@ -20,8 +20,6 @@
#include "nsPIDOMWindow.h"
#include "nsJSEnvironment.h"
#include "mozilla/dom/RuntimeService.h"
namespace mozilla {
namespace dom {
@ -256,23 +254,14 @@ Promise::EnabledForScope(JSContext* aCx, JSObject* /* unused */)
return true;
}
} else {
RuntimeService* service = RuntimeService::GetService();
MOZ_ASSERT(service);
// Can't just do return ... since the chrome worker/certified app checks
// below should also run.
if (service->PromiseEnabled()) {
return true;
}
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
return workerPrivate->PromiseEnabled() || workerPrivate->UsesSystemPrincipal();
}
// Enable if the pref is enabled or if we're chrome or if we're a
// certified app.
// Note that we have no concept of a certified app in workers.
// XXXbz well, why not?
// FIXME(nsm): Remove these checks once promises are enabled by default.
if (!NS_IsMainThread()) {
return workers::GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal();
}
nsIPrincipal* prin = nsContentUtils::GetSubjectPrincipal();
return nsContentUtils::IsSystemPrincipal(prin) ||
prin->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;

View File

@ -56,11 +56,6 @@ WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
return false;
}
bool promiseEnabled = false;
RuntimeService* service = RuntimeService::GetService();
MOZ_ASSERT(service);
promiseEnabled = service->PromiseEnabled();
// Init other paris-bindings.
if (!DOMExceptionBinding::GetConstructorObject(aCx, aGlobal) ||
!EventBinding::GetConstructorObject(aCx, aGlobal) ||
@ -68,7 +63,8 @@ WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
!ImageDataBinding::GetConstructorObject(aCx, aGlobal) ||
!MessageEventBinding::GetConstructorObject(aCx, aGlobal) ||
!MessagePortBinding::GetConstructorObject(aCx, aGlobal) ||
(promiseEnabled && !PromiseBinding::GetConstructorObject(aCx, aGlobal)) ||
(PromiseEnabled() &&
!PromiseBinding::GetConstructorObject(aCx, aGlobal)) ||
!TextDecoderBinding::GetConstructorObject(aCx, aGlobal) ||
!TextEncoderBinding::GetConstructorObject(aCx, aGlobal) ||
!XMLHttpRequestBinding_workers::GetConstructorObject(aCx, aGlobal) ||

View File

@ -176,43 +176,10 @@ static_assert(NS_ARRAY_LENGTH(gStringChars) == ID_COUNT,
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
#define DUMP_CONTROLLED_BY_PREF 1
#define PREF_DOM_WINDOW_DUMP_ENABLED "browser.dom.window.dump.enabled"
// Protected by RuntimeService::mMutex.
// Initialized by DumpPrefChanged via RuntimeService::Init().
bool gWorkersDumpEnabled;
static int
DumpPrefChanged(const char* aPrefName, void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
bool enabled = Preferences::GetBool(PREF_DOM_WINDOW_DUMP_ENABLED, false);
Mutex* mutex = static_cast<Mutex*>(aClosure);
MutexAutoLock lock(*mutex);
gWorkersDumpEnabled = enabled;
return 0;
}
#endif
#define PREF_PROMISE_ENABLED "dom.promise.enabled"
// Protected by RuntimeService::mMutex.
bool gPromiseEnabled;
static int
PromiseEnableChanged(const char* aPrefName, void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
bool enabled = Preferences::GetBool(PREF_PROMISE_ENABLED, false);
Mutex* mutex = static_cast<Mutex*>(aClosure);
MutexAutoLock lock(*mutex);
gPromiseEnabled = enabled;
return 0;
}
class LiteralRebindingCString : public nsDependentCString
{
public:
@ -1177,6 +1144,7 @@ END_WORKERS_NAMESPACE
// This is only touched on the main thread. Initialized in Init() below.
JSSettings RuntimeService::sDefaultJSSettings;
bool RuntimeService::sDefaultPreferences[WORKERPREF_COUNT] = { false };
RuntimeService::RuntimeService()
: mMutex("RuntimeService::mMutex"), mObserved(false),
@ -1587,6 +1555,11 @@ RuntimeService::Init()
WORKER_DEFAULT_ALLOCATION_THRESHOLD);
}
// If dump is not controlled by pref, it's set to true.
#ifndef DUMP_CONTROLLED_BY_PREF
sDefaultPreferences[WORKERPREF_DUMP] = true;
#endif
mIdleThreadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
NS_ENSURE_STATE(mIdleThreadTimer);
@ -1642,14 +1615,14 @@ RuntimeService::Init()
#endif
#if DUMP_CONTROLLED_BY_PREF
NS_FAILED(Preferences::RegisterCallbackAndCall(
DumpPrefChanged,
WorkerPrefChanged,
PREF_DOM_WINDOW_DUMP_ENABLED,
&mMutex)) ||
reinterpret_cast<void *>(WORKERPREF_DUMP))) ||
#endif
NS_FAILED(Preferences::RegisterCallbackAndCall(
PromiseEnableChanged,
WorkerPrefChanged,
PREF_PROMISE_ENABLED,
&mMutex)) ||
reinterpret_cast<void *>(WORKERPREF_PROMISE))) ||
NS_FAILED(Preferences::RegisterCallback(LoadJSContextOptions,
PREF_JS_OPTIONS_PREFIX,
nullptr)) ||
@ -1812,13 +1785,13 @@ RuntimeService::Cleanup()
NS_FAILED(Preferences::UnregisterCallback(LoadJSContextOptions,
PREF_WORKERS_OPTIONS_PREFIX,
nullptr)) ||
NS_FAILED(Preferences::UnregisterCallback(PromiseEnableChanged,
NS_FAILED(Preferences::UnregisterCallback(WorkerPrefChanged,
PREF_PROMISE_ENABLED,
&mMutex)) ||
reinterpret_cast<void *>(WORKERPREF_PROMISE))) ||
#if DUMP_CONTROLLED_BY_PREF
NS_FAILED(Preferences::UnregisterCallback(DumpPrefChanged,
NS_FAILED(Preferences::UnregisterCallback(WorkerPrefChanged,
PREF_DOM_WINDOW_DUMP_ENABLED,
&mMutex)) ||
reinterpret_cast<void *>(WORKERPREF_DUMP))) ||
#endif
#ifdef JS_GC_ZEAL
NS_FAILED(Preferences::UnregisterCallback(
@ -2196,6 +2169,12 @@ RuntimeService::UpdateAllWorkerJSContextOptions()
sDefaultJSSettings.chrome.options);
}
void
RuntimeService::UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue)
{
BROADCAST_ALL_WORKERS(UpdatePreference, aPref, aValue);
}
void
RuntimeService::UpdateAllWorkerMemoryParameter(JSGCParamKey aKey,
uint32_t aValue)
@ -2255,22 +2234,33 @@ RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
return NS_OK;
}
bool
RuntimeService::WorkersDumpEnabled()
/* static */ int
RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure)
{
#if DUMP_CONTROLLED_BY_PREF
MutexAutoLock lock(mMutex);
// In optimized builds we check a pref that controls if we should
// enable output from dump() or not, in debug builds it's always
// enabled.
return gWorkersDumpEnabled;
#else
return true;
#endif
}
AssertIsOnMainThread();
bool
RuntimeService::PromiseEnabled()
{
return gPromiseEnabled;
uintptr_t tmp = reinterpret_cast<uintptr_t>(aClosure);
MOZ_ASSERT(tmp >= 0 && tmp < WORKERPREF_COUNT);
WorkerPreference key = static_cast<WorkerPreference>(tmp);
if (key == WORKERPREF_PROMISE) {
sDefaultPreferences[WORKERPREF_PROMISE] =
Preferences::GetBool(PREF_PROMISE_ENABLED, false);
#ifdef DUMP_CONTROLLED_BY_PREF
} else if (key == WORKERPREF_DUMP) {
key = WORKERPREF_DUMP;
sDefaultPreferences[WORKERPREF_DUMP] =
Preferences::GetBool(PREF_DOM_WINDOW_DUMP_ENABLED, false);
#endif
}
// This function should never be registered as a callback for a preference it
// does not handle.
MOZ_ASSERT(key != WORKERPREF_COUNT);
RuntimeService* rts = RuntimeService::GetService();
if (rts) {
rts->UpdateAllWorkerPreference(key, sDefaultPreferences[key]);
}
return 0;
}

View File

@ -101,6 +101,7 @@ class RuntimeService MOZ_FINAL : public nsIObserver
nsCString mSystemCharset;
static JSSettings sDefaultJSSettings;
static bool sDefaultPreferences[WORKERPREF_COUNT];
public:
struct NavigatorStrings
@ -181,6 +182,13 @@ public:
aSettings = sDefaultJSSettings;
}
static void
GetDefaultPreferences(bool aPreferences[WORKERPREF_COUNT])
{
AssertIsOnMainThread();
memcpy(aPreferences, sDefaultPreferences, WORKERPREF_COUNT * sizeof(bool));
}
static void
SetDefaultJSContextOptions(const JS::ContextOptions& aContentOptions,
const JS::ContextOptions& aChromeOptions)
@ -193,6 +201,9 @@ public:
void
UpdateAllWorkerJSContextOptions();
void
UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue);
static void
SetDefaultJSGCSettings(JSGCParamKey aKey, uint32_t aValue)
{
@ -241,12 +252,6 @@ public:
void
GarbageCollectAllWorkers(bool aShrinking);
bool
WorkersDumpEnabled();
bool
PromiseEnabled();
private:
RuntimeService();
~RuntimeService();
@ -284,6 +289,9 @@ private:
static void
ShutdownIdleThreads(nsITimer* aTimer, void* aClosure);
static int
WorkerPrefChanged(const char* aPrefName, void* aClosure);
};
END_WORKERS_NAMESPACE

View File

@ -1465,6 +1465,29 @@ public:
}
};
class UpdatePreferenceRunnable : public WorkerControlRunnable
{
WorkerPreference mPref;
bool mValue;
public:
UpdatePreferenceRunnable(WorkerPrivate* aWorkerPrivate,
WorkerPreference aPref,
bool aValue)
: WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
mPref(aPref),
mValue(aValue)
{
}
bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->UpdatePreferenceInternal(aCx, mPref, mValue);
return true;
}
};
class UpdateJSWorkerMemoryParameterRunnable : public WorkerControlRunnable
{
uint32_t mValue;
@ -2778,6 +2801,21 @@ WorkerPrivateParent<Derived>::UpdateJSContextOptions(JSContext* aCx,
}
}
template <class Derived>
void
WorkerPrivateParent<Derived>::UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue)
{
AssertIsOnParentThread();
MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
nsRefPtr<UpdatePreferenceRunnable> runnable =
new UpdatePreferenceRunnable(ParentAsWorkerPrivate(), aPref, aValue);
if (!runnable->Dispatch(aCx)) {
NS_WARNING("Failed to update worker preferences!");
JS_ClearPendingException(aCx);
}
}
template <class Derived>
void
WorkerPrivateParent<Derived>::UpdateJSWorkerMemoryParameter(JSContext* aCx,
@ -3284,6 +3322,15 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx,
{
MOZ_ASSERT_IF(IsSharedWorker(), !aSharedWorkerName.IsVoid());
MOZ_ASSERT_IF(!IsSharedWorker(), aSharedWorkerName.IsEmpty());
if (aParent) {
aParent->AssertIsOnWorkerThread();
aParent->GetAllPreferences(mPreferences);
}
else {
AssertIsOnMainThread();
RuntimeService::GetDefaultPreferences(mPreferences);
}
}
WorkerPrivate::~WorkerPrivate()
@ -5083,6 +5130,19 @@ WorkerPrivate::UpdateJSContextOptionsInternal(JSContext* aCx,
}
}
void
WorkerPrivate::UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue)
{
AssertIsOnWorkerThread();
MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
mPreferences[aPref] = aValue;
for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
mChildWorkers[index]->UpdatePreference(aCx, aPref, aValue);
}
}
void
WorkerPrivate::UpdateJSWorkerMemoryParameterInternal(JSContext* aCx,
JSGCParamKey aKey,

View File

@ -476,6 +476,9 @@ public:
UpdateJSContextOptions(JSContext* aCx, const JS::ContextOptions& aChromeOptions,
const JS::ContextOptions& aContentOptions);
void
UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue);
void
UpdateJSWorkerMemoryParameter(JSContext* aCx, JSGCParamKey key,
uint32_t value);
@ -815,6 +818,8 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
nsCOMPtr<nsIThread> mThread;
#endif
bool mPreferences[WORKERPREF_COUNT];
protected:
~WorkerPrivate();
@ -977,6 +982,9 @@ public:
UpdateJSContextOptionsInternal(JSContext* aCx, const JS::ContextOptions& aContentOptions,
const JS::ContextOptions& aChromeOptions);
void
UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue);
void
UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
@ -1069,6 +1077,20 @@ public:
bool
RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
bool
DumpEnabled() const
{
AssertIsOnWorkerThread();
return mPreferences[WORKERPREF_DUMP];
}
bool
PromiseEnabled() const
{
AssertIsOnWorkerThread();
return mPreferences[WORKERPREF_PROMISE];
}
private:
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
const nsAString& aScriptURL, bool aIsChromeWorker,
@ -1146,6 +1168,13 @@ private:
bool aToMessagePort,
uint64_t aMessagePortSerial,
ErrorResult& aRv);
void
GetAllPreferences(bool aPreferences[WORKERPREF_COUNT]) const
{
AssertIsOnWorkerThread();
memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
}
};
// This class is only used to trick the DOM bindings. We never create

View File

@ -237,7 +237,7 @@ WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const
RuntimeService* runtimeService = RuntimeService::GetService();
MOZ_ASSERT(runtimeService);
if (!runtimeService->WorkersDumpEnabled()) {
if (!mWorkerPrivate->DumpEnabled()) {
return;
}

View File

@ -162,6 +162,13 @@ struct JSSettings
}
};
enum WorkerPreference
{
WORKERPREF_DUMP = 0, // browser.dom.window.dump.enabled
WORKERPREF_PROMISE, // dom.promise.enabled
WORKERPREF_COUNT
};
// All of these are implemented in RuntimeService.cpp
bool
ResolveWorkerClasses(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId,

View File

@ -8,7 +8,6 @@ TEST_DIRS += ['test']
# Public stuff.
EXPORTS.mozilla.dom += [
'RuntimeService.h',
'WorkerPrivate.h',
'WorkerScope.h',
]