Bug 1416174 - part 1 - OSFileConstants must be a singleton, r=smaug

This commit is contained in:
Andrea Marchesini 2017-11-10 19:27:03 +01:00
Родитель 3ff4869cbb
Коммит b06af90b93
5 изменённых файлов: 114 добавлений и 109 удалений

Просмотреть файл

@ -69,6 +69,9 @@
#include "nsAppDirectoryServiceDefs.h"
#include "mozJSComponentLoader.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPtr.h"
#include "OSFileConstants.h"
#include "nsIOSFileConstantsService.h"
#include "nsZipArchive.h"
@ -86,13 +89,9 @@
namespace mozilla {
// Use an anonymous namespace to hide the symbols and avoid any collision
// with, for instance, |extern bool gInitialized;|
namespace {
/**
* |true| if this module has been initialized, |false| otherwise
*/
bool gInitialized = false;
StaticRefPtr<OSFileConstantsService> gInstance;
struct Paths {
/**
@ -254,15 +253,14 @@ DelayedPathSetter::Observe(nsISupports*, const char * aTopic, const char16_t*)
* Perform the part of initialization that can only be
* executed on the main thread.
*/
nsresult InitOSFileConstants()
nsresult
OSFileConstantsService::InitOSFileConstants()
{
MOZ_ASSERT(NS_IsMainThread());
if (gInitialized) {
if (mInitialized) {
return NS_OK;
}
gInitialized = true;
nsAutoPtr<Paths> paths(new Paths);
// Initialize paths->libDir
@ -333,25 +331,10 @@ nsresult InitOSFileConstants()
// to initialize the service.
gUserUmask = nsSystemInfo::gUserUmask;
mInitialized = true;
return NS_OK;
}
/**
* Perform the cleaning up that can only be executed on the main thread.
*/
void CleanupOSFileConstants()
{
MOZ_ASSERT(NS_IsMainThread());
if (!gInitialized) {
return;
}
gInitialized = false;
delete gPaths;
gPaths = nullptr;
}
/**
* Define a simple read-only property holding an integer.
*
@ -875,54 +858,56 @@ bool SetStringProperty(JSContext *cx, JS::Handle<JSObject*> aObject, const char
* This function creates or uses JS object |OS.Constants| to store
* all its constants.
*/
bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
bool
OSFileConstantsService::DefineOSFileConstants(JSContext* aCx,
JS::Handle<JSObject*> aGlobal)
{
if (!gInitialized || gPaths == nullptr) {
if (!mInitialized || gPaths == nullptr) {
// If an initialization error was ignored, we may end up with
// |gInitialized == true| but |gPaths == nullptr|. We cannot
// |MOZ_ASSERT| this, as this would kill precompile_cache.js,
// so we simply return an error.
JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
JSMSG_CANT_OPEN,
"OSFileConstants", "initialization has failed");
return false;
}
JS::Rooted<JSObject*> objOS(cx);
if (!(objOS = GetOrCreateObjectProperty(cx, global, "OS"))) {
JS::Rooted<JSObject*> objOS(aCx);
if (!(objOS = GetOrCreateObjectProperty(aCx, aGlobal, "OS"))) {
return false;
}
JS::Rooted<JSObject*> objConstants(cx);
if (!(objConstants = GetOrCreateObjectProperty(cx, objOS, "Constants"))) {
JS::Rooted<JSObject*> objConstants(aCx);
if (!(objConstants = GetOrCreateObjectProperty(aCx, objOS, "Constants"))) {
return false;
}
// Build OS.Constants.libc
JS::Rooted<JSObject*> objLibc(cx);
if (!(objLibc = GetOrCreateObjectProperty(cx, objConstants, "libc"))) {
JS::Rooted<JSObject*> objLibc(aCx);
if (!(objLibc = GetOrCreateObjectProperty(aCx, objConstants, "libc"))) {
return false;
}
if (!dom::DefineConstants(cx, objLibc, gLibcProperties)) {
if (!dom::DefineConstants(aCx, objLibc, gLibcProperties)) {
return false;
}
#if defined(XP_WIN)
// Build OS.Constants.Win
JS::Rooted<JSObject*> objWin(cx);
if (!(objWin = GetOrCreateObjectProperty(cx, objConstants, "Win"))) {
JS::Rooted<JSObject*> objWin(aCx);
if (!(objWin = GetOrCreateObjectProperty(aCx, objConstants, "Win"))) {
return false;
}
if (!dom::DefineConstants(cx, objWin, gWinProperties)) {
if (!dom::DefineConstants(aCx, objWin, gWinProperties)) {
return false;
}
#endif // defined(XP_WIN)
// Build OS.Constants.Sys
JS::Rooted<JSObject*> objSys(cx);
if (!(objSys = GetOrCreateObjectProperty(cx, objConstants, "Sys"))) {
JS::Rooted<JSObject*> objSys(aCx);
if (!(objSys = GetOrCreateObjectProperty(aCx, objConstants, "Sys"))) {
return false;
}
@ -932,42 +917,42 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
DebugOnly<nsresult> rv = runtime->GetOS(os);
MOZ_ASSERT(NS_SUCCEEDED(rv));
JSString* strVersion = JS_NewStringCopyZ(cx, os.get());
JSString* strVersion = JS_NewStringCopyZ(aCx, os.get());
if (!strVersion) {
return false;
}
JS::Rooted<JS::Value> valVersion(cx, JS::StringValue(strVersion));
if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
JS::Rooted<JS::Value> valVersion(aCx, JS::StringValue(strVersion));
if (!JS_SetProperty(aCx, objSys, "Name", valVersion)) {
return false;
}
}
#if defined(DEBUG)
JS::Rooted<JS::Value> valDebug(cx, JS::TrueValue());
if (!JS_SetProperty(cx, objSys, "DEBUG", valDebug)) {
JS::Rooted<JS::Value> valDebug(aCx, JS::TrueValue());
if (!JS_SetProperty(aCx, objSys, "DEBUG", valDebug)) {
return false;
}
#endif
#if defined(HAVE_64BIT_BUILD)
JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(64));
JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(64));
#else
JS::Rooted<JS::Value> valBits(cx, JS::Int32Value(32));
JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(32));
#endif //defined (HAVE_64BIT_BUILD)
if (!JS_SetProperty(cx, objSys, "bits", valBits)) {
if (!JS_SetProperty(aCx, objSys, "bits", valBits)) {
return false;
}
if (!JS_DefineProperty(cx, objSys, "umask", gUserUmask,
if (!JS_DefineProperty(aCx, objSys, "umask", gUserUmask,
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
return false;
}
// Build OS.Constants.Path
JS::Rooted<JSObject*> objPath(cx);
if (!(objPath = GetOrCreateObjectProperty(cx, objConstants, "Path"))) {
JS::Rooted<JSObject*> objPath(aCx);
if (!(objPath = GetOrCreateObjectProperty(aCx, objConstants, "Path"))) {
return false;
}
@ -990,62 +975,62 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
libxul.AppendLiteral(DLL_SUFFIX);
#endif // defined(XP_MACOSX)
if (!SetStringProperty(cx, objPath, "libxul", libxul)) {
if (!SetStringProperty(aCx, objPath, "libxul", libxul)) {
return false;
}
if (!SetStringProperty(cx, objPath, "libDir", gPaths->libDir)) {
if (!SetStringProperty(aCx, objPath, "libDir", gPaths->libDir)) {
return false;
}
if (!SetStringProperty(cx, objPath, "tmpDir", gPaths->tmpDir)) {
if (!SetStringProperty(aCx, objPath, "tmpDir", gPaths->tmpDir)) {
return false;
}
// Configure profileDir only if it is available at this stage
if (!gPaths->profileDir.IsVoid()
&& !SetStringProperty(cx, objPath, "profileDir", gPaths->profileDir)) {
&& !SetStringProperty(aCx, objPath, "profileDir", gPaths->profileDir)) {
return false;
}
// Configure localProfileDir only if it is available at this stage
if (!gPaths->localProfileDir.IsVoid()
&& !SetStringProperty(cx, objPath, "localProfileDir", gPaths->localProfileDir)) {
&& !SetStringProperty(aCx, objPath, "localProfileDir", gPaths->localProfileDir)) {
return false;
}
if (!SetStringProperty(cx, objPath, "homeDir", gPaths->homeDir)) {
if (!SetStringProperty(aCx, objPath, "homeDir", gPaths->homeDir)) {
return false;
}
if (!SetStringProperty(cx, objPath, "desktopDir", gPaths->desktopDir)) {
if (!SetStringProperty(aCx, objPath, "desktopDir", gPaths->desktopDir)) {
return false;
}
if (!SetStringProperty(cx, objPath, "userApplicationDataDir", gPaths->userApplicationDataDir)) {
if (!SetStringProperty(aCx, objPath, "userApplicationDataDir", gPaths->userApplicationDataDir)) {
return false;
}
#if defined(XP_WIN)
if (!SetStringProperty(cx, objPath, "winAppDataDir", gPaths->winAppDataDir)) {
if (!SetStringProperty(aCx, objPath, "winAppDataDir", gPaths->winAppDataDir)) {
return false;
}
if (!SetStringProperty(cx, objPath, "winStartMenuProgsDir", gPaths->winStartMenuProgsDir)) {
if (!SetStringProperty(aCx, objPath, "winStartMenuProgsDir", gPaths->winStartMenuProgsDir)) {
return false;
}
#endif // defined(XP_WIN)
#if defined(XP_MACOSX)
if (!SetStringProperty(cx, objPath, "macUserLibDir", gPaths->macUserLibDir)) {
if (!SetStringProperty(aCx, objPath, "macUserLibDir", gPaths->macUserLibDir)) {
return false;
}
if (!SetStringProperty(cx, objPath, "macLocalApplicationsDir", gPaths->macLocalApplicationsDir)) {
if (!SetStringProperty(aCx, objPath, "macLocalApplicationsDir", gPaths->macLocalApplicationsDir)) {
return false;
}
if (!SetStringProperty(cx, objPath, "macTrashDir", gPaths->macTrashDir)) {
if (!SetStringProperty(aCx, objPath, "macTrashDir", gPaths->macTrashDir)) {
return false;
}
#endif // defined(XP_MACOSX)
@ -1067,7 +1052,7 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
libsqlite3 = libxul;
#endif // defined(ANDROID) || defined(XP_WIN)
if (!SetStringProperty(cx, objPath, "libsqlite3", libsqlite3)) {
if (!SetStringProperty(aCx, objPath, "libsqlite3", libsqlite3)) {
return false;
}
@ -1076,21 +1061,48 @@ bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
NS_IMPL_ISUPPORTS(OSFileConstantsService, nsIOSFileConstantsService)
/* static */ already_AddRefed<OSFileConstantsService>
OSFileConstantsService::GetOrCreate()
{
if (!gInstance) {
MOZ_ASSERT(NS_IsMainThread());
RefPtr<OSFileConstantsService> service = new OSFileConstantsService();
nsresult rv = service->InitOSFileConstants();
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
gInstance = service.forget();
ClearOnShutdown(&gInstance);
}
RefPtr<OSFileConstantsService> copy = gInstance;
return copy.forget();
}
OSFileConstantsService::OSFileConstantsService()
: mInitialized(false)
{
MOZ_ASSERT(NS_IsMainThread());
}
OSFileConstantsService::~OSFileConstantsService()
{
mozilla::CleanupOSFileConstants();
}
MOZ_ASSERT(NS_IsMainThread());
if (mInitialized) {
delete gPaths;
gPaths = nullptr;
}
}
NS_IMETHODIMP
OSFileConstantsService::Init(JSContext *aCx)
{
nsresult rv = mozilla::InitOSFileConstants();
MOZ_ASSERT(NS_IsMainThread());
nsresult rv = InitOSFileConstants();
if (NS_FAILED(rv)) {
return rv;
}
@ -1099,7 +1111,7 @@ OSFileConstantsService::Init(JSContext *aCx)
JS::Rooted<JSObject*> targetObj(aCx);
loader->FindTargetObject(aCx, &targetObj);
if (!mozilla::DefineOSFileConstants(aCx, targetObj)) {
if (!DefineOSFileConstants(aCx, targetObj)) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -12,47 +12,33 @@
namespace mozilla {
/**
* Perform initialization of this module.
*
* This function _must_ be called:
* - from the main thread;
* - before any Chrome Worker is created.
*
* The function is idempotent.
*/
nsresult InitOSFileConstants();
/**
* Perform cleanup of this module.
*
* This function _must_ be called:
* - from the main thread;
* - after all Chrome Workers are dead.
*
* The function is idempotent.
*/
void CleanupOSFileConstants();
/**
* Define OS-specific constants.
*
* This function creates or uses JS object |OS.Constants| to store
* all its constants.
*/
bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global);
/**
* XPConnect initializer, for use in the main thread.
* This class is thread-safe but it must be first be initialized on the
* main-thread.
*/
class OSFileConstantsService final : public nsIOSFileConstantsService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIOSFILECONSTANTSSERVICE
OSFileConstantsService();
static already_AddRefed<OSFileConstantsService>
GetOrCreate();
bool
DefineOSFileConstants(JSContext* aCx,
JS::Handle<JSObject*> aGlobal);
private:
nsresult
InitOSFileConstants();
OSFileConstantsService();
~OSFileConstantsService();
bool mInitialized;
};
} // namespace mozilla

Просмотреть файл

@ -25,8 +25,13 @@ WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
}
if (IsChromeWorker()) {
if (!DefineChromeWorkerFunctions(aCx, aGlobal) ||
!DefineOSFileConstants(aCx, aGlobal)) {
if (!DefineChromeWorkerFunctions(aCx, aGlobal)) {
return false;
}
RefPtr<OSFileConstantsService> service =
OSFileConstantsService::GetOrCreate();
if (!service->DefineOSFileConstants(aCx, aGlobal)) {
return false;
}
}

Просмотреть файл

@ -2032,9 +2032,10 @@ RuntimeService::Init()
MAX_HARDWARE_CONCURRENCY);
gMaxHardwareConcurrency = std::max(0, maxHardwareConcurrency);
rv = InitOSFileConstants();
if (NS_FAILED(rv)) {
return rv;
RefPtr<OSFileConstantsService> osFileConstantsService =
OSFileConstantsService::GetOrCreate();
if (NS_WARN_IF(!osFileConstantsService)) {
return NS_ERROR_FAILURE;
}
if (NS_WARN_IF(!IndexedDatabaseManager::GetOrCreate())) {
@ -2205,7 +2206,6 @@ RuntimeService::Cleanup()
}
}
CleanupOSFileConstants();
nsLayoutStatics::Release();
}

Просмотреть файл

@ -532,7 +532,9 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemPrincipal,
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NullPrincipal, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer)
NS_GENERIC_FACTORY_CONSTRUCTOR(OSFileConstantsService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(OSFileConstantsService,
OSFileConstantsService::GetOrCreate);
NS_GENERIC_FACTORY_CONSTRUCTOR(UDPSocketChild)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(GeckoMediaPluginService, GeckoMediaPluginService::GetGeckoMediaPluginService)