From 4331197e1bcb0b4391a20c1180f8947437b4a2f6 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:28 -0700 Subject: [PATCH 01/86] Bug 1052089 - Sprinkle some assert against using nsContentUtils too early. r=billm And earlier version of these patches called nsContentUtils::GetSystemPrincipal() too early, which returned null, and caused xpc::CreateSandboxObject to create an nsNullPrincipal. Let's avoid having that happen again. --- content/base/src/nsContentUtils.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 972aeb79492..1029a092582 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -2632,6 +2632,7 @@ nsContentUtils::GenerateStateKey(nsIContent* aContent, nsIPrincipal* nsContentUtils::SubjectPrincipal() { + MOZ_ASSERT(IsInitialized()); JSContext* cx = GetCurrentJSContext(); if (!cx) { return GetSystemPrincipal(); @@ -4697,6 +4698,7 @@ nsContentUtils::CheckSecurityBeforeLoad(nsIURI* aURIToLoad, bool nsContentUtils::IsSystemPrincipal(nsIPrincipal* aPrincipal) { + MOZ_ASSERT(IsInitialized()); return aPrincipal == sSystemPrincipal; } @@ -4710,6 +4712,7 @@ nsContentUtils::IsExpandedPrincipal(nsIPrincipal* aPrincipal) nsIPrincipal* nsContentUtils::GetSystemPrincipal() { + MOZ_ASSERT(IsInitialized()); return sSystemPrincipal; } @@ -5521,6 +5524,7 @@ JSContext * nsContentUtils::GetCurrentJSContext() { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(IsInitialized()); return sXPConnect->GetCurrentJSContext(); } @@ -5529,6 +5533,7 @@ JSContext * nsContentUtils::GetSafeJSContext() { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(IsInitialized()); return sXPConnect->GetSafeJSContext(); } @@ -5536,6 +5541,7 @@ nsContentUtils::GetSafeJSContext() JSContext * nsContentUtils::GetDefaultJSContextForThread() { + MOZ_ASSERT(IsInitialized()); if (MOZ_LIKELY(NS_IsMainThread())) { return GetSafeJSContext(); } else { @@ -5547,6 +5553,7 @@ nsContentUtils::GetDefaultJSContextForThread() JSContext * nsContentUtils::GetCurrentJSContextForThread() { + MOZ_ASSERT(IsInitialized()); if (MOZ_LIKELY(NS_IsMainThread())) { return GetCurrentJSContext(); } else { From c0a0c702aac468467c21fc2250eaf54fbc3d4da5 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:29 -0700 Subject: [PATCH 02/86] Bug 1052089 - Add a System Principal accessor to nsXPConnect and use it in Sandbox creation. r=billm nsContentUtils isn't ready by this point. --- js/xpconnect/src/Sandbox.cpp | 2 +- js/xpconnect/src/nsXPConnect.cpp | 6 +++++- js/xpconnect/src/xpcprivate.h | 9 +++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 9eaa4d53038..0385b3b7315 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -911,7 +911,7 @@ xpc::CreateSandboxObject(JSContext *cx, MutableHandleValue vp, nsISupports *prin // Don't try to mirror the properties that are set below. AutoSkipPropertyMirroring askip(CompartmentPrivate::Get(sandbox)); - bool allowComponents = nsContentUtils::IsSystemPrincipal(principal) || + bool allowComponents = principal == nsXPConnect::SystemPrincipal() || nsContentUtils::IsExpandedPrincipal(principal); if (options.wantComponents && allowComponents && !ObjectScope(sandbox)->AttachComponentsObject(cx)) diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 5b2aa9eb422..62033940458 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -54,8 +54,9 @@ bool nsXPConnect::gOnceAliveNowDead = false; uint32_t nsXPConnect::gReportAllJSExceptions = 0; // Global cache of the default script security manager (QI'd to -// nsIScriptSecurityManager) +// nsIScriptSecurityManager) and the system principal. nsIScriptSecurityManager *nsXPConnect::gScriptSecurityManager = nullptr; +nsIPrincipal *nsXPConnect::gSystemPrincipal = nullptr; const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1"; const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1"; @@ -102,6 +103,7 @@ nsXPConnect::~nsXPConnect() // maps that our finalize callback depends on. JS_GC(mRuntime->Runtime()); + NS_RELEASE(gSystemPrincipal); gScriptSecurityManager = nullptr; // shutdown the logging system @@ -135,6 +137,8 @@ nsXPConnect::InitStatics() // Fire up the SSM. nsScriptSecurityManager::InitStatics(); gScriptSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager(); + gScriptSecurityManager->GetSystemPrincipal(&gSystemPrincipal); + MOZ_RELEASE_ASSERT(gSystemPrincipal); // Initialize the SafeJSContext. gSelf->mRuntime->GetJSContextStack()->InitSafeJSContext(); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 33f83b64a1c..98571f6292b 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -283,9 +283,17 @@ public: static nsIScriptSecurityManager* SecurityManager() { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(gScriptSecurityManager); return gScriptSecurityManager; } + static nsIPrincipal* SystemPrincipal() + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(gSystemPrincipal); + return gSystemPrincipal; + } + // This returns an AddRef'd pointer. It does not do this with an 'out' param // only because this form is required by the generic module macro: // NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR @@ -339,6 +347,7 @@ private: public: static nsIScriptSecurityManager *gScriptSecurityManager; + static nsIPrincipal *gSystemPrincipal; }; /***************************************************************************/ From ed9975b9031348ff7d81f820272791172baaeff4 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:29 -0700 Subject: [PATCH 03/86] Bug 1052089 - Stop using a contractid to create a null principal during sandbox creation. r=billm This causes problems when used too early in startup. --- js/xpconnect/src/Sandbox.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 0385b3b7315..0c7029542f8 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -21,6 +21,7 @@ #include "nsIURI.h" #include "nsJSUtils.h" #include "nsNetUtil.h" +#include "nsNullPrincipal.h" #include "nsPrincipal.h" #include "nsXMLHttpRequest.h" #include "WrapperFactory.h" @@ -813,19 +814,13 @@ xpc::CreateSandboxObject(JSContext *cx, MutableHandleValue vp, nsISupports *prin if (sop) { principal = sop->GetPrincipal(); } else { - principal = do_CreateInstance("@mozilla.org/nullprincipal;1", &rv); - MOZ_ASSERT(NS_FAILED(rv) || principal, "Bad return from do_CreateInstance"); - - if (!principal || NS_FAILED(rv)) { - if (NS_SUCCEEDED(rv)) { - rv = NS_ERROR_FAILURE; - } - - return rv; - } + nsRefPtr nullPrin = new nsNullPrincipal(); + rv = nullPrin->Init(); + NS_ENSURE_SUCCESS(rv, rv); + principal = nullPrin; } - MOZ_ASSERT(principal); } + MOZ_ASSERT(principal); JS::CompartmentOptions compartmentOptions; if (options.sameZoneAs) From e90a53352cb6e9fa9d7fe94beab9798d029d70c9 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:29 -0700 Subject: [PATCH 04/86] Bug 1052089 - Don't require the cx to be in a compartment during sandbox creation. r=billm --- js/xpconnect/src/Sandbox.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 0c7029542f8..f41dc20f67a 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -933,8 +933,10 @@ xpc::CreateSandboxObject(JSContext *cx, MutableHandleValue vp, nsISupports *prin return NS_ERROR_XPC_UNEXPECTED; } + // We handle the case where the context isn't in a compartment for the + // benefit of InitSingletonScopes. vp.setObject(*sandbox); - if (!JS_WrapValue(cx, vp)) + if (js::GetContextCompartment(cx) && !JS_WrapValue(cx, vp)) return NS_ERROR_UNEXPECTED; // Set the location information for the new global, so that tools like From ff340370af9093892f4b2025f8f32ef9fbf59937 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:29 -0700 Subject: [PATCH 05/86] Bug 1052089 - Don't fuss around with remote-XUL XBL-scope special cases for sandboxes. r=billm --- js/xpconnect/src/XPCWrappedNativeScope.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index 2c85c40f2da..12f2a76d800 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -58,7 +58,9 @@ RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal) // end up calling into AllowXULXBLForPrincipal, which depends on all kinds // of persistent storage and permission machinery that may or not be running. // We know the answer to the question here, so just short-circuit. - if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass) + // + // We do the same for sandboxes, for similar reasons. + if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass || IsSandbox(aGlobal)) return false; // AllowXULXBLForPrincipal will return true for system principal, but we From bfe01a01cfca5373ff2beeb9ff94934baa5688a8 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:30 -0700 Subject: [PATCH 06/86] Bug 1052089 - Make the junk scope invisible to the debugger and Components-less. r=billm This prevents the JS engine from trying to fire off debugger notifications and do other complicated things when we create this thing early in startup in the upcoming patches. --- js/xpconnect/src/XPCJSRuntime.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index bf8f372fc0a..049d86c1bd5 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -3558,6 +3558,8 @@ XPCJSRuntime::GetJunkScope() AutoSafeJSContext cx; SandboxOptions options; options.sandboxName.AssignLiteral("XPConnect Junk Compartment"); + options.invisibleToDebugger = true; + options.wantComponents = false; RootedValue v(cx); nsresult rv = CreateSandboxObject(cx, &v, nsContentUtils::GetSystemPrincipal(), options); NS_ENSURE_SUCCESS(rv, nullptr); From 0a751ae4d7fe5800271adaf40213cddd686ec3cc Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:30 -0700 Subject: [PATCH 07/86] Bug 1052089 - Infallibly init singleton scopes in the XPCJSRuntime constructor. r=billm We've had some problems with GetJunkScope returning null and causing crashes in the past, but I'm now pretty convinced that just null-checking it isn't the answer. Rather than creating it lazily, we should create it at a defined point in startup. Any problems will then be much more reproducible, and we can track them down and fix them. --- js/xpconnect/src/XPCJSRuntime.cpp | 61 +++++++++++++------------------ js/xpconnect/src/nsXPConnect.cpp | 3 ++ js/xpconnect/src/xpcprivate.h | 6 ++- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 049d86c1bd5..7dc9c063be5 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -565,7 +565,7 @@ GetJunkScope() { XPCJSRuntime *self = nsXPConnect::GetRuntimeInstance(); NS_ENSURE_TRUE(self, nullptr); - return self->GetJunkScope(); + return self->JunkScope(); } nsIGlobalObject * @@ -584,7 +584,7 @@ GetCompilationScope() { XPCJSRuntime *self = nsXPConnect::GetRuntimeInstance(); NS_ENSURE_TRUE(self, nullptr); - return self->GetCompilationScope(); + return self->CompilationScope(); } JSObject * @@ -3551,43 +3551,34 @@ XPCJSRuntime::RemoveContextCallback(xpcContextCallback cb) } } -JSObject * -XPCJSRuntime::GetJunkScope() +void +XPCJSRuntime::InitSingletonScopes() { - if (!mJunkScope) { - AutoSafeJSContext cx; - SandboxOptions options; - options.sandboxName.AssignLiteral("XPConnect Junk Compartment"); - options.invisibleToDebugger = true; - options.wantComponents = false; - RootedValue v(cx); - nsresult rv = CreateSandboxObject(cx, &v, nsContentUtils::GetSystemPrincipal(), options); - NS_ENSURE_SUCCESS(rv, nullptr); + // This all happens very early, so we don't bother with cx pushing. + JSContext *cx = GetJSContextStack()->GetSafeJSContext(); + JSAutoRequest ar(cx); + RootedValue v(cx); + nsresult rv; - mJunkScope = js::UncheckedUnwrap(&v.toObject()); - } - return mJunkScope; + // Create the Junk Scope. + SandboxOptions junkScopeOptions; + junkScopeOptions.sandboxName.AssignLiteral("XPConnect Junk Compartment"); + junkScopeOptions.invisibleToDebugger = true; + junkScopeOptions.wantComponents = false; + rv = CreateSandboxObject(cx, &v, nsXPConnect::SystemPrincipal(), junkScopeOptions); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); + mJunkScope = js::UncheckedUnwrap(&v.toObject()); + + // Create the Compilation Scope. + SandboxOptions compilationScopeOptions; + compilationScopeOptions.sandboxName.AssignLiteral("XPConnect Compilation Compartment"); + compilationScopeOptions.invisibleToDebugger = true; + compilationScopeOptions.discardSource = ShouldDiscardSystemSource(); + rv = CreateSandboxObject(cx, &v, /* principal = */ nullptr, compilationScopeOptions); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); + mCompilationScope = js::UncheckedUnwrap(&v.toObject()); } -JSObject * -XPCJSRuntime::GetCompilationScope() -{ - if (!mCompilationScope) { - AutoSafeJSContext cx; - SandboxOptions options; - options.sandboxName.AssignLiteral("XPConnect Compilation Compartment"); - options.invisibleToDebugger = true; - options.discardSource = ShouldDiscardSystemSource(); - RootedValue v(cx); - nsresult rv = CreateSandboxObject(cx, &v, /* principal = */ nullptr, options); - NS_ENSURE_SUCCESS(rv, nullptr); - - mCompilationScope = js::UncheckedUnwrap(&v.toObject()); - } - return mCompilationScope; -} - - void XPCJSRuntime::DeleteSingletonScopes() { diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 62033940458..d1ccc398662 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -142,6 +142,9 @@ nsXPConnect::InitStatics() // Initialize the SafeJSContext. gSelf->mRuntime->GetJSContextStack()->InitSafeJSContext(); + + // Initialize our singleton scopes. + gSelf->mRuntime->InitSingletonScopes(); } nsXPConnect* diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 98571f6292b..bd0c52ab852 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -619,8 +619,10 @@ public: AutoMarkingPtr** GetAutoRootsAdr() {return &mAutoRoots;} - JSObject* GetJunkScope(); - JSObject* GetCompilationScope(); + JSObject* JunkScope() { return mJunkScope; } + JSObject* CompilationScope() { return mCompilationScope; } + + void InitSingletonScopes(); void DeleteSingletonScopes(); PRTime GetWatchdogTimestamp(WatchdogTimestampCategory aCategory); From 4c2d9e0211dd45ab7eb4a90a684f54e0fc9b45ba Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:30 -0700 Subject: [PATCH 08/86] Bug 1052089 - Rename JunkScope to PrivilegedJunkScope and remove fallibility of singleton scope access. r=billm These two things ended up getting mushed together in my tree. --- content/base/src/nsDOMFileReader.cpp | 4 +-- content/base/src/nsDocument.cpp | 2 +- content/base/src/nsXMLHttpRequest.cpp | 4 +-- content/xul/content/src/nsXULElement.cpp | 12 +++----- dom/base/Console.cpp | 2 +- dom/mobilemessage/src/ipc/SmsParent.cpp | 2 +- dom/xbl/nsXBLDocumentInfo.cpp | 3 +- dom/xbl/nsXBLProtoImpl.cpp | 3 +- dom/xbl/nsXBLPrototypeBinding.cpp | 6 ++-- js/ipc/JavaScriptShared.cpp | 2 +- js/xpconnect/src/XPCJSRuntime.cpp | 39 ++++++++---------------- js/xpconnect/src/nsXPConnect.cpp | 2 +- js/xpconnect/src/xpcprivate.h | 4 +-- js/xpconnect/src/xpcpublic.h | 11 ++----- 14 files changed, 32 insertions(+), 64 deletions(-) diff --git a/content/base/src/nsDOMFileReader.cpp b/content/base/src/nsDOMFileReader.cpp index 16b587eb9de..b8ed3b49fa1 100644 --- a/content/base/src/nsDOMFileReader.cpp +++ b/content/base/src/nsDOMFileReader.cpp @@ -107,9 +107,7 @@ nsDOMFileReader::Init() // Instead of grabbing some random global from the context stack, // let's use the default one (junk scope) for now. // We should move away from this Init... - nsCOMPtr global = xpc::GetJunkScopeGlobal(); - NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); - BindToOwner(global); + BindToOwner(xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope())); return NS_OK; } diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 0e34c46d8a8..65eb4a1baaf 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -2142,7 +2142,7 @@ nsDocument::Init() // we use the default compartment for this document, instead of creating // wrapper in some random compartment when the document is exposed to js // via some events. - nsCOMPtr global = xpc::GetJunkScopeGlobal(); + nsCOMPtr global = xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope()); NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); mScopeObject = do_GetWeakReference(global); MOZ_ASSERT(mScopeObject); diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 2f980968a02..a35a693835b 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -352,9 +352,7 @@ nsXMLHttpRequest::Init() // Instead of grabbing some random global from the context stack, // let's use the default one (junk scope) for now. // We should move away from this Init... - nsCOMPtr global = xpc::GetJunkScopeGlobal(); - NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); - Construct(subjectPrincipal, global); + Construct(subjectPrincipal, xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope())); return NS_OK; } diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index e77e4516a72..c2cf661dc33 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -2531,7 +2531,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream, { NS_ENSURE_TRUE(aProtoDoc, NS_ERROR_UNEXPECTED); AutoSafeJSContext cx; - JS::Rooted global(cx, xpc::GetCompilationScope()); + JS::Rooted global(cx, xpc::CompilationScope()); NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED); JSAutoCompartment ac(cx, global); @@ -2553,8 +2553,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream, // been set. JS::Handle script = JS::Handle::fromMarkedLocation(mScriptObject.address()); - // Note - Inverting the order of these operands is a rooting hazard. - MOZ_ASSERT(xpc::GetCompilationScope() == JS::CurrentGlobalOrNull(cx)); + MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx)); return nsContentUtils::XPConnect()->WriteScript(aStream, cx, xpc_UnmarkGrayScript(script)); } @@ -2621,7 +2620,7 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream, aStream->Read32(&mLangVersion); AutoSafeJSContext cx; - JS::Rooted global(cx, xpc::GetCompilationScope()); + JS::Rooted global(cx, xpc::CompilationScope()); NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED); JSAutoCompartment ac(cx, global); @@ -2731,7 +2730,7 @@ NotifyOffThreadScriptCompletedRunnable::Run() JSScript *script; { AutoSafeJSContext cx; - JSAutoCompartment ac(cx, xpc::GetCompilationScope()); + JSAutoCompartment ac(cx, xpc::CompilationScope()); script = JS::FinishOffThreadScript(cx, JS_GetRuntime(cx), mToken); } @@ -2757,9 +2756,8 @@ nsXULPrototypeScript::Compile(JS::SourceBufferHolder& aSrcBuf, nsIOffThreadScriptReceiver *aOffThreadReceiver /* = nullptr */) { // We'll compile the script in the compilation scope. - NS_ENSURE_TRUE(xpc::GetCompilationScope(), NS_ERROR_UNEXPECTED); AutoSafeJSContext cx; - JSAutoCompartment ac(cx, xpc::GetCompilationScope()); + JSAutoCompartment ac(cx, xpc::CompilationScope()); nsAutoCString urlspec; nsContentUtils::GetWrapperSafeScriptFilename(aDocument, aURI, urlspec); diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index bea87b8f89d..e1dc28f5ae4 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -1113,7 +1113,7 @@ Console::ProcessCallData(ConsoleCallData* aData) // mStorage, but that's a bit fragile. Instead, we just use the junk scope, // with explicit permission from the XPConnect module owner. If you're // tempted to do that anywhere else, talk to said module owner first. - JSAutoCompartment ac2(cx, xpc::GetJunkScope()); + JSAutoCompartment ac2(cx, xpc::PrivilegedJunkScope()); JS::Rooted eventValue(cx); if (!ToJSValue(cx, event, &eventValue)) { diff --git a/dom/mobilemessage/src/ipc/SmsParent.cpp b/dom/mobilemessage/src/ipc/SmsParent.cpp index 987d74ea0fd..6f761786045 100644 --- a/dom/mobilemessage/src/ipc/SmsParent.cpp +++ b/dom/mobilemessage/src/ipc/SmsParent.cpp @@ -495,7 +495,7 @@ SmsRequestParent::DoRequest(const SendMessageRequest& aRequest) // jsval to ::Send. Only system code should be looking at the result here, // so we just create it in the System-Principaled Junk Scope. AutoJSContext cx; - JSAutoCompartment ac(cx, xpc::GetJunkScope()); + JSAutoCompartment ac(cx, xpc::PrivilegedJunkScope()); JS::Rooted params(cx); const SendMmsMessageRequest &req = aRequest.get_SendMmsMessageRequest(); if (!GetParamsFromSendMmsMessageRequest(cx, diff --git a/dom/xbl/nsXBLDocumentInfo.cpp b/dom/xbl/nsXBLDocumentInfo.cpp index 3931f8666ac..265c6235418 100644 --- a/dom/xbl/nsXBLDocumentInfo.cpp +++ b/dom/xbl/nsXBLDocumentInfo.cpp @@ -359,7 +359,6 @@ void AssertInCompilationScope() { AutoJSContext cx; - // Note - Inverting the order of these operands is a rooting hazard. - MOZ_ASSERT(xpc::GetCompilationScope() == JS::CurrentGlobalOrNull(cx)); + MOZ_ASSERT(xpc::CompilationScope() == JS::CurrentGlobalOrNull(cx)); } #endif diff --git a/dom/xbl/nsXBLProtoImpl.cpp b/dom/xbl/nsXBLProtoImpl.cpp index 56020202600..83ce7ca48ef 100644 --- a/dom/xbl/nsXBLProtoImpl.cpp +++ b/dom/xbl/nsXBLProtoImpl.cpp @@ -240,8 +240,7 @@ nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding) // bind the prototype to a real xbl instance, we'll clone the pre-compiled JS into the real instance's // context. AutoSafeJSContext cx; - JS::Rooted compilationGlobal(cx, xpc::GetCompilationScope()); - NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED); + JS::Rooted compilationGlobal(cx, xpc::CompilationScope()); JSAutoCompartment ac(cx, compilationGlobal); mPrecompiledMemberHolder = JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), compilationGlobal); diff --git a/dom/xbl/nsXBLPrototypeBinding.cpp b/dom/xbl/nsXBLPrototypeBinding.cpp index 0dada380fc7..7ffb2ee5433 100644 --- a/dom/xbl/nsXBLPrototypeBinding.cpp +++ b/dom/xbl/nsXBLPrototypeBinding.cpp @@ -911,8 +911,7 @@ nsXBLPrototypeBinding::Read(nsIObjectInputStream* aStream, } AutoSafeJSContext cx; - JS::Rooted compilationGlobal(cx, xpc::GetCompilationScope()); - NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED); + JS::Rooted compilationGlobal(cx, xpc::CompilationScope()); JSAutoCompartment ac(cx, compilationGlobal); bool isFirstBinding = aFlags & XBLBinding_Serialize_IsFirstBinding; @@ -1064,8 +1063,7 @@ nsXBLPrototypeBinding::Write(nsIObjectOutputStream* aStream) // computed on demand. AutoSafeJSContext cx; - JS::Rooted compilationGlobal(cx, xpc::GetCompilationScope()); - NS_ENSURE_TRUE(compilationGlobal, NS_ERROR_UNEXPECTED); + JS::Rooted compilationGlobal(cx, xpc::CompilationScope()); JSAutoCompartment ac(cx, compilationGlobal); uint8_t flags = mInheritStyle ? XBLBinding_Serialize_InheritStyle : 0; diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp index 2c96f3fea70..492f82890ae 100644 --- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -395,7 +395,7 @@ JavaScriptShared::findObjectById(JSContext *cx, uint32_t objId) } // If there's no TabChildGlobal, we use the junk scope. - JSAutoCompartment ac(cx, xpc::GetJunkScope()); + JSAutoCompartment ac(cx, xpc::PrivilegedJunkScope()); if (!JS_WrapObject(cx, &obj)) return nullptr; return obj; diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 7dc9c063be5..aa91ed8b6d7 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -561,30 +561,15 @@ EnableUniversalXPConnect(JSContext *cx) } JSObject * -GetJunkScope() +PrivilegedJunkScope() { - XPCJSRuntime *self = nsXPConnect::GetRuntimeInstance(); - NS_ENSURE_TRUE(self, nullptr); - return self->JunkScope(); -} - -nsIGlobalObject * -GetJunkScopeGlobal() -{ - JSObject *junkScope = GetJunkScope(); - // GetJunkScope would ideally never fail, currently it is not yet the case - // unfortunately...(see Bug 874158) - if (!junkScope) - return nullptr; - return GetNativeForGlobal(junkScope); + return XPCJSRuntime::Get()->PrivilegedJunkScope(); } JSObject * -GetCompilationScope() +CompilationScope() { - XPCJSRuntime *self = nsXPConnect::GetRuntimeInstance(); - NS_ENSURE_TRUE(self, nullptr); - return self->CompilationScope(); + return XPCJSRuntime::Get()->CompilationScope(); } JSObject * @@ -3130,7 +3115,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) mWrappedJSRoots(nullptr), mObjectHolderRoots(nullptr), mWatchdogManager(new WatchdogManager(MOZ_THIS_IN_INITIALIZER_LIST())), - mJunkScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr), + mPrivilegedJunkScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr), mCompilationScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr), mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite()) { @@ -3561,13 +3546,13 @@ XPCJSRuntime::InitSingletonScopes() nsresult rv; // Create the Junk Scope. - SandboxOptions junkScopeOptions; - junkScopeOptions.sandboxName.AssignLiteral("XPConnect Junk Compartment"); - junkScopeOptions.invisibleToDebugger = true; - junkScopeOptions.wantComponents = false; - rv = CreateSandboxObject(cx, &v, nsXPConnect::SystemPrincipal(), junkScopeOptions); + SandboxOptions privilegedJunkScopeOptions; + privilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Privileged Junk Compartment"); + privilegedJunkScopeOptions.invisibleToDebugger = true; + privilegedJunkScopeOptions.wantComponents = false; + rv = CreateSandboxObject(cx, &v, nsXPConnect::SystemPrincipal(), privilegedJunkScopeOptions); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); - mJunkScope = js::UncheckedUnwrap(&v.toObject()); + mPrivilegedJunkScope = js::UncheckedUnwrap(&v.toObject()); // Create the Compilation Scope. SandboxOptions compilationScopeOptions; @@ -3582,6 +3567,6 @@ XPCJSRuntime::InitSingletonScopes() void XPCJSRuntime::DeleteSingletonScopes() { - mJunkScope = nullptr; + mPrivilegedJunkScope = nullptr; mCompilationScope = nullptr; } diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index d1ccc398662..7f1293764de 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1468,7 +1468,7 @@ SetAddonInterposition(const nsACString &addonIdStr, nsIAddonInterposition *inter // We enter the junk scope just to allocate a string, which actually will go // in the system zone. AutoJSAPI jsapi; - jsapi.Init(xpc::GetJunkScopeGlobal()); + jsapi.Init(xpc::GetNativeForGlobal(xpc::PrivilegedJunkScope())); addonId = NewAddonId(jsapi.cx(), addonIdStr); if (!addonId) return false; diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index bd0c52ab852..4c3ae90d98c 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -619,7 +619,7 @@ public: AutoMarkingPtr** GetAutoRootsAdr() {return &mAutoRoots;} - JSObject* JunkScope() { return mJunkScope; } + JSObject* PrivilegedJunkScope() { return mPrivilegedJunkScope; } JSObject* CompilationScope() { return mCompilationScope; } void InitSingletonScopes(); @@ -663,7 +663,7 @@ private: nsTArray extraContextCallbacks; nsRefPtr mWatchdogManager; JS::GCSliceCallback mPrevGCSliceCallback; - JS::PersistentRootedObject mJunkScope; + JS::PersistentRootedObject mPrivilegedJunkScope; JS::PersistentRootedObject mCompilationScope; nsRefPtr mAsyncSnowWhiteFreer; diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index ff618fdd6c0..660867e127b 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -448,14 +448,7 @@ UnwrapReflectorToISupports(JSObject *reflector); * using this compartment. If you don't, bholley will hunt you down. */ JSObject * -GetJunkScope(); - -/** - * Returns the native global of the junk scope. See comment of GetJunkScope - * about the conditions of using it. - */ -nsIGlobalObject * -GetJunkScopeGlobal(); +PrivilegedJunkScope(); /** * Shared compilation scope for XUL prototype documents and XBL @@ -463,7 +456,7 @@ GetJunkScopeGlobal(); * it is invisible to the debugger. */ JSObject * -GetCompilationScope(); +CompilationScope(); /** * If |aObj| is a window, returns the associated nsGlobalWindow. From 0cb72d2e6cdb003d2b4987407551196f0f18af6d Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 10:57:30 -0700 Subject: [PATCH 09/86] Bug 1052089 - Swap out the SafeJSContextGlobal for the new UnprivilegedJunkScope. r=billm --- dom/base/ScriptSettings.cpp | 2 +- dom/base/nsJSUtils.cpp | 2 +- dom/bindings/Codegen.py | 4 +- js/xpconnect/src/XPCJSContextStack.cpp | 69 +--------------------- js/xpconnect/src/XPCJSRuntime.cpp | 24 +++++--- js/xpconnect/src/XPCWrappedNativeScope.cpp | 14 ++--- js/xpconnect/src/xpcprivate.h | 7 +-- js/xpconnect/src/xpcpublic.h | 20 ++----- 8 files changed, 35 insertions(+), 107 deletions(-) diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index d3d2fa0737e..5f765714910 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -499,7 +499,7 @@ ThreadsafeAutoJSContext::operator JSContext*() const AutoSafeJSContext::AutoSafeJSContext(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) : AutoJSContext(true MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) - , mAc(mCx, XPCJSRuntime::Get()->GetJSContextStack()->GetSafeJSContextGlobal()) + , mAc(mCx, xpc::UnprivilegedJunkScope()) { } diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 44ba363b7f8..d5c47f687a4 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -124,7 +124,7 @@ nsJSUtils::ReportPendingException(JSContext *aContext) // The SafeJSContext has no default object associated with it. MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aContext == nsContentUtils::GetSafeJSContext()); - scope = xpc::GetSafeJSContextGlobal(); + scope = xpc::UnprivilegedJunkScope(); // Usage approved by bholley } JSAutoCompartment ac(aContext, scope); JS_ReportPendingException(aContext); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 6ae351b4aff..505c146e9fe 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -11104,7 +11104,7 @@ class CGDictionary(CGThing): AutoJSAPI jsapi; jsapi.Init(); JSContext *cx = jsapi.cx(); - JSAutoCompartment ac(cx, xpc::GetSafeJSContextGlobal()); // Usage approved by bholley + JSAutoCompartment ac(cx, xpc::UnprivilegedJunkScope()); // Usage approved by bholley JS::Rooted obj(cx); return ToObjectInternal(cx, &obj) && StringifyToJSON(cx, &obj, aJSON); """)) @@ -11892,7 +11892,7 @@ class CGBindingRoot(CGThing): bindingHeaders["WrapperFactory.h"] = descriptors bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors bindingHeaders["mozilla/dom/ScriptSettings.h"] = dictionaries # AutoJSAPI - bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::GetSafeJSContextGlobal + bindingHeaders["xpcpublic.h"] = dictionaries ## xpc::UnprivilegedJunkScope # Do codegen for all the dictionaries. We have to be a bit careful # here, because we have to generate these in order from least derived diff --git a/js/xpconnect/src/XPCJSContextStack.cpp b/js/xpconnect/src/XPCJSContextStack.cpp index 5bdf09d2496..5792b4306b3 100644 --- a/js/xpconnect/src/XPCJSContextStack.cpp +++ b/js/xpconnect/src/XPCJSContextStack.cpp @@ -22,7 +22,6 @@ using mozilla::dom::DestroyProtoAndIfaceCache; XPCJSContextStack::~XPCJSContextStack() { if (mSafeJSContext) { - mSafeJSContextGlobal = nullptr; JS_DestroyContextNoGC(mSafeJSContext); mSafeJSContext = nullptr; } @@ -109,31 +108,6 @@ XPCJSContextStack::HasJSContext(JSContext *cx) return false; } -static bool -SafeGlobalResolve(JSContext *cx, HandleObject obj, HandleId id) -{ - bool resolved; - return JS_ResolveStandardClass(cx, obj, id, &resolved); -} - -static void -SafeFinalize(JSFreeOp *fop, JSObject* obj) -{ - SandboxPrivate* sop = - static_cast(xpc_GetJSPrivate(obj)); - sop->ForgetGlobalObject(); - NS_IF_RELEASE(sop); - DestroyProtoAndIfaceCache(obj); -} - -const JSClass xpc::SafeJSContextGlobalClass = { - "global_for_XPCJSContextStack_SafeJSContext", - XPCONNECT_GLOBAL_FLAGS, - JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, - JS_EnumerateStub, SafeGlobalResolve, JS_ConvertStub, SafeFinalize, - nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook -}; - JSContext* XPCJSContextStack::GetSafeJSContext() { @@ -141,55 +115,14 @@ XPCJSContextStack::GetSafeJSContext() return mSafeJSContext; } -JSObject* -XPCJSContextStack::GetSafeJSContextGlobal() -{ - MOZ_ASSERT(mSafeJSContextGlobal); - return mSafeJSContextGlobal; -} - JSContext* XPCJSContextStack::InitSafeJSContext() { MOZ_ASSERT(!mSafeJSContext); - - // Start by getting the principal holder and principal for this - // context. If we can't manage that, don't bother with the rest. - nsRefPtr principal = new nsNullPrincipal(); - nsresult rv = principal->Init(); - if (NS_FAILED(rv)) - MOZ_CRASH(); - - nsXPConnect* xpc = nsXPConnect::XPConnect(); - JSRuntime *rt = xpc->GetRuntime()->Runtime(); - if (!rt) - MOZ_CRASH(); - - mSafeJSContext = JS_NewContext(rt, 8192); + mSafeJSContext = JS_NewContext(XPCJSRuntime::Get()->Runtime(), 8192); if (!mSafeJSContext) MOZ_CRASH(); - JSAutoRequest req(mSafeJSContext); ContextOptionsRef(mSafeJSContext).setNoDefaultCompartmentObject(true); - JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter); - - // Note - We intentionally avoid firing OnNewGlobalObject while - // simultaneously skipping the call to setInvisibleToDebugger(true) here. - // This lets us piggy-back on the assertions in the JS engine (which make - // sure that, for non-invisible globals, we always fire onNewGlobalObject - // before creating scripts), to assert that we never create scripts with - // the SafeJSContextGlobal. This is all happening way before anyone could be - // listening for debugger notifications anyway. - JS::CompartmentOptions options; - options.setZone(JS::SystemZone) - .setTrace(TraceXPCGlobal); - mSafeJSContextGlobal = CreateGlobalObject(mSafeJSContext, - &SafeJSContextGlobalClass, - principal, options); - if (!mSafeJSContextGlobal) - MOZ_CRASH(); - - nsRefPtr sp = new SandboxPrivate(principal, mSafeJSContextGlobal); - JS_SetPrivate(mSafeJSContextGlobal, sp.forget().take()); return mSafeJSContext; } diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index aa91ed8b6d7..74b98273153 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -560,6 +560,12 @@ EnableUniversalXPConnect(JSContext *cx) return scope->AttachComponentsObject(cx); } +JSObject * +UnprivilegedJunkScope() +{ + return XPCJSRuntime::Get()->UnprivilegedJunkScope(); +} + JSObject * PrivilegedJunkScope() { @@ -572,12 +578,6 @@ CompilationScope() return XPCJSRuntime::Get()->CompilationScope(); } -JSObject * -GetSafeJSContextGlobal() -{ - return XPCJSRuntime::Get()->GetJSContextStack()->GetSafeJSContextGlobal(); -} - nsGlobalWindow* WindowOrNull(JSObject *aObj) { @@ -3115,6 +3115,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) mWrappedJSRoots(nullptr), mObjectHolderRoots(nullptr), mWatchdogManager(new WatchdogManager(MOZ_THIS_IN_INITIALIZER_LIST())), + mUnprivilegedJunkScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr), mPrivilegedJunkScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr), mCompilationScope(MOZ_THIS_IN_INITIALIZER_LIST()->Runtime(), nullptr), mAsyncSnowWhiteFreer(new AsyncFreeSnowWhite()) @@ -3545,7 +3546,15 @@ XPCJSRuntime::InitSingletonScopes() RootedValue v(cx); nsresult rv; - // Create the Junk Scope. + // Create the Unprivileged Junk Scope. + SandboxOptions unprivilegedJunkScopeOptions; + unprivilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Junk Compartment"); + unprivilegedJunkScopeOptions.invisibleToDebugger = true; + rv = CreateSandboxObject(cx, &v, nullptr, unprivilegedJunkScopeOptions); + MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); + mUnprivilegedJunkScope = js::UncheckedUnwrap(&v.toObject()); + + // Create the Privileged Junk Scope. SandboxOptions privilegedJunkScopeOptions; privilegedJunkScopeOptions.sandboxName.AssignLiteral("XPConnect Privileged Junk Compartment"); privilegedJunkScopeOptions.invisibleToDebugger = true; @@ -3567,6 +3576,7 @@ XPCJSRuntime::InitSingletonScopes() void XPCJSRuntime::DeleteSingletonScopes() { + mUnprivilegedJunkScope = nullptr; mPrivilegedJunkScope = nullptr; mCompilationScope = nullptr; } diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index 12f2a76d800..5df633c69fa 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -52,15 +52,11 @@ RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal) { MOZ_ASSERT(aPrincipal); - // The SafeJSContext is lazily created, and tends to be created at really - // weird times, at least for xpcshell (often very early in startup or late - // in shutdown). Its scope isn't system principal, so if we proceeded we'd - // end up calling into AllowXULXBLForPrincipal, which depends on all kinds - // of persistent storage and permission machinery that may or not be running. - // We know the answer to the question here, so just short-circuit. - // - // We do the same for sandboxes, for similar reasons. - if (JS_GetClass(aGlobal) == &SafeJSContextGlobalClass || IsSandbox(aGlobal)) + // Certain singleton sandoxes are created very early in startup - too early + // to call into AllowXULXBLForPrincipal. We never create XBL scopes for + // sandboxes anway, and certainly not for these singleton scopes. So we just + // short-circuit here. + if (IsSandbox(aGlobal)) return false; // AllowXULXBLForPrincipal will return true for system principal, but we diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 4c3ae90d98c..c2fb9d63a91 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -619,6 +619,7 @@ public: AutoMarkingPtr** GetAutoRootsAdr() {return &mAutoRoots;} + JSObject* UnprivilegedJunkScope() { return mUnprivilegedJunkScope; } JSObject* PrivilegedJunkScope() { return mPrivilegedJunkScope; } JSObject* CompilationScope() { return mCompilationScope; } @@ -663,6 +664,7 @@ private: nsTArray extraContextCallbacks; nsRefPtr mWatchdogManager; JS::GCSliceCallback mPrevGCSliceCallback; + JS::PersistentRootedObject mUnprivilegedJunkScope; JS::PersistentRootedObject mPrivilegedJunkScope; JS::PersistentRootedObject mCompilationScope; nsRefPtr mAsyncSnowWhiteFreer; @@ -2857,7 +2859,6 @@ public: explicit XPCJSContextStack(XPCJSRuntime *aRuntime) : mRuntime(aRuntime) , mSafeJSContext(nullptr) - , mSafeJSContextGlobal(aRuntime->Runtime(), nullptr) { } virtual ~XPCJSContextStack(); @@ -2874,7 +2875,6 @@ public: JSContext *InitSafeJSContext(); JSContext *GetSafeJSContext(); - JSObject *GetSafeJSContextGlobal(); bool HasJSContext(JSContext *cx); const InfallibleTArray* GetStack() @@ -2893,7 +2893,6 @@ private: AutoInfallibleTArray mStack; XPCJSRuntime* mRuntime; JSContext* mSafeJSContext; - JS::PersistentRootedObject mSafeJSContextGlobal; }; /***************************************************************************/ @@ -3730,8 +3729,6 @@ ObjectScope(JSObject *obj) return CompartmentPrivate::Get(obj)->scope; } -extern const JSClass SafeJSContextGlobalClass; - JSObject* NewOutObject(JSContext* cx, JSObject* scope); bool IsOutObject(JSContext* cx, JSObject* obj); diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 660867e127b..4f8cabca5e9 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -437,16 +437,15 @@ nsISupports * UnwrapReflectorToISupports(JSObject *reflector); /** - * In some cases a native object does not really belong to any compartment (XBL, - * document created from by XHR of a worker, etc.). But when for some reason we - * have to wrap these natives (because of an event for example) instead of just - * wrapping them into some random compartment we find on the context stack (like - * we did previously) a default compartment is used. This function returns that - * compartment's global. It is a singleton on the runtime. - * If you find yourself wanting to use this compartment, you're probably doing + * Singleton scopes for stuff that really doesn't fit anywhere else. + * + * If you find yourself wanting to use these compartments, you're probably doing * something wrong. Callers MUST consult with the XPConnect module owner before * using this compartment. If you don't, bholley will hunt you down. */ +JSObject * +UnprivilegedJunkScope(); + JSObject * PrivilegedJunkScope(); @@ -465,13 +464,6 @@ CompilationScope(); nsGlobalWindow* WindowOrNull(JSObject *aObj); -/* - * Returns the dummy global associated with the SafeJSContext. Callers MUST - * consult with the XPConnect module owner before using this function. - */ -JSObject * -GetSafeJSContextGlobal(); - /** * If |aObj| has a window for a global, returns the associated nsGlobalWindow. * Otherwise, returns null. From e81244438d6508de5aecf00c95aeffdd3128df78 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 11:11:55 -0700 Subject: [PATCH 10/86] Bug 1054541 - IonMonkey: Set infallible flags using truncation levels r=nbp --- js/src/jit/RangeAnalysis.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 9bdf73b3203..32aa76c28f6 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -2274,7 +2274,8 @@ MToDouble::truncate(TruncateKind kind) bool MLoadTypedArrayElementStatic::truncate(TruncateKind kind) { - setInfallible(); + if (kind >= IndirectTruncate) + setInfallible(); return false; } From 0fa715c05ead2b6de338b62bab731055576b1888 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 11:11:57 -0700 Subject: [PATCH 11/86] Bug 1054568 - IonMonkey: Be prepared to check for a remainder after unsigned division r=nbp --- js/src/jit/shared/CodeGenerator-x86-shared.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/js/src/jit/shared/CodeGenerator-x86-shared.cpp b/js/src/jit/shared/CodeGenerator-x86-shared.cpp index aaa22824270..3826cb1213c 100644 --- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp @@ -838,6 +838,14 @@ CodeGeneratorX86Shared::visitUDivOrMod(LUDivOrMod *ins) masm.mov(ImmWord(0), edx); masm.udiv(rhs); + // If the remainder is > 0, bailout since this must be a double. + if (ins->mir()->isDiv() && !ins->mir()->toDiv()->canTruncateRemainder()) { + Register remainder = ToRegister(ins->remainder()); + masm.testl(remainder, remainder); + if (!bailoutIf(Assembler::NonZero, ins->snapshot())) + return false; + } + // Unsigned div or mod can return a value that's not a signed int32. // If our users aren't expecting that, bail. if (!ins->mir()->isTruncated()) { From ae562efb3f988c05c04bfd2e841a8a16c2415e06 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 6 Aug 2014 12:28:37 -0400 Subject: [PATCH 12/86] Bug 1045617 followup - remove dummy mach command DONTBUILD; r=me --- services/common/tests/mach_commands.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/services/common/tests/mach_commands.py b/services/common/tests/mach_commands.py index b2eacacfc4a..b3930dd90f4 100644 --- a/services/common/tests/mach_commands.py +++ b/services/common/tests/mach_commands.py @@ -111,10 +111,6 @@ class SyncTestCommands(MachCommandBase): print 'Removing profile directory %s' % profile_dir rmtree(profile_dir) - @Command('doesthiswork', category='testing', description='Example command') - def doesthiswork(self): - print 'hi!' - @Command('storage-server', category='services', description='Run a storage server.') @SyncStorageCommand From e7f72adf612f3c6f4bc3658ba2228a259b839296 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Mon, 18 Aug 2014 20:45:43 +0200 Subject: [PATCH 13/86] Bug 1054322 - sort more messages in js.msg. r=till --- js/src/builtin/Map.js | 5 +- js/src/builtin/Set.js | 5 +- js/src/js.msg | 140 ++++++++++++++++++++++++------------------ js/src/json.cpp | 6 +- 4 files changed, 91 insertions(+), 65 deletions(-) diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index 0a3a77944da..8c734277f72 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -8,13 +8,14 @@ function MapForEach(callbackfn, thisArg = undefined) { /* Step 1-2. */ var M = this; if (!IsObject(M)) - ThrowError(JSMSG_BAD_TYPE, typeof M); + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Map", "forEach", typeof M); /* Step 3-4. */ try { callFunction(std_Map_has, M); } catch (e) { - ThrowError(JSMSG_BAD_TYPE, typeof M); + // has will throw on non-Map objects, throw our own error in that case. + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Map", "forEach", typeof M); } /* Step 5. */ diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js index 67181c96969..5373f1227b5 100644 --- a/js/src/builtin/Set.js +++ b/js/src/builtin/Set.js @@ -8,13 +8,14 @@ function SetForEach(callbackfn, thisArg = undefined) { /* Step 1-2. */ var S = this; if (!IsObject(S)) - ThrowError(JSMSG_BAD_TYPE, typeof S); + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Set", "forEach", typeof S); /* Step 3-4. */ try { callFunction(std_Set_has, S); } catch (e) { - ThrowError(JSMSG_BAD_TYPE, typeof S); + // has will throw on non-Set objects, throw our own error in that case. + ThrowError(JSMSG_INCOMPATIBLE_PROTO, "Set", "forEach", typeof S); } /* Step 5-6. */ diff --git a/js/src/js.msg b/js/src/js.msg index d03d1dfed3e..9966f4da6d0 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -43,85 +43,42 @@ MSG_DEF(JSMSG_NOT_AN_ERROR, 0, JSEXN_NONE, "") MSG_DEF(JSMSG_NOT_DEFINED, 1, JSEXN_REFERENCEERR, "{0} is not defined") -MSG_DEF(JSMSG_INACTIVE, 0, JSEXN_INTERNALERR, "nothing active on context") MSG_DEF(JSMSG_MORE_ARGS_NEEDED, 3, JSEXN_TYPEERR, "{0} requires more than {1} argument{2}") -MSG_DEF(JSMSG_BAD_CHAR, 1, JSEXN_INTERNALERR, "invalid format character {0}") -MSG_DEF(JSMSG_BAD_TYPE, 1, JSEXN_TYPEERR, "unknown type {0}") -MSG_DEF(JSMSG_ALLOC_OVERFLOW, 0, JSEXN_INTERNALERR, "allocation size overflow") MSG_DEF(JSMSG_INCOMPATIBLE_PROTO, 3, JSEXN_TYPEERR, "{0}.prototype.{1} called on incompatible {2}") MSG_DEF(JSMSG_NO_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} has no constructor") -MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a scripted function") MSG_DEF(JSMSG_BAD_SORT_ARG, 0, JSEXN_TYPEERR, "invalid Array.prototype.sort argument") MSG_DEF(JSMSG_CANT_WATCH, 1, JSEXN_TYPEERR, "can't watch non-native objects of class {0}") -MSG_DEF(JSMSG_NEED_DIET, 1, JSEXN_INTERNALERR, "{0} too large") MSG_DEF(JSMSG_READ_ONLY, 1, JSEXN_TYPEERR, "{0} is read-only") -MSG_DEF(JSMSG_BAD_FORMAL, 0, JSEXN_SYNTAXERR, "malformed formal parameter") MSG_DEF(JSMSG_CANT_DELETE, 1, JSEXN_TYPEERR, "property {0} is non-configurable and can't be deleted") MSG_DEF(JSMSG_NOT_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a function") MSG_DEF(JSMSG_NOT_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} is not a constructor") -MSG_DEF(JSMSG_INVALID_DATE, 0, JSEXN_RANGEERR, "invalid date") -MSG_DEF(JSMSG_TOO_DEEP, 1, JSEXN_INTERNALERR, "{0} nested too deeply") -MSG_DEF(JSMSG_OVER_RECURSED, 0, JSEXN_INTERNALERR, "too much recursion") -MSG_DEF(JSMSG_IN_NOT_OBJECT, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}") -MSG_DEF(JSMSG_BAD_NEW_RESULT, 1, JSEXN_TYPEERR, "invalid new expression result {0}") -MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") -MSG_DEF(JSMSG_BAD_BYTECODE, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}") -MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36") MSG_DEF(JSMSG_CANT_CONVERT, 1, JSEXN_ERR, "can't convert {0} to an integer") -MSG_DEF(JSMSG_CYCLIC_VALUE, 1, JSEXN_TYPEERR, "cyclic {0} value") MSG_DEF(JSMSG_CANT_CONVERT_TO, 2, JSEXN_TYPEERR, "can't convert {0} to {1}") MSG_DEF(JSMSG_NO_PROPERTIES, 1, JSEXN_TYPEERR, "{0} has no properties") -MSG_DEF(JSMSG_DEAD_OBJECT, 0, JSEXN_TYPEERR, "can't access dead object") -MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})") -MSG_DEF(JSMSG_UNKNOWN_FORMAT, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}") MSG_DEF(JSMSG_BAD_REGEXP_FLAG, 1, JSEXN_SYNTAXERR, "invalid regular expression flag {0}") -MSG_DEF(JSMSG_CANT_OPEN, 2, JSEXN_ERR, "can't open {0}: {1}") -MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large") -MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE, 0, JSEXN_INTERNALERR, "data are to big to encode") MSG_DEF(JSMSG_ARG_INDEX_OUT_OF_RANGE, 1, JSEXN_RANGEERR, "argument {0} accesses an index that is out of range") MSG_DEF(JSMSG_SPREAD_TOO_LARGE, 0, JSEXN_RANGEERR, "array too large due to spread operand(s)") MSG_DEF(JSMSG_BAD_WEAKMAP_KEY, 0, JSEXN_TYPEERR, "cannot use the given object as a weak map key") -MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 0, JSEXN_INTERNALERR, "bad script XDR magic number") -MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property '{0}'") -MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?") -MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side") -MSG_DEF(JSMSG_BAD_PROTOTYPE, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object") -MSG_DEF(JSMSG_OUT_OF_MEMORY, 0, JSEXN_ERR, "out of memory") -MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain") -MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size") -MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 1, JSEXN_INTERNALERR, "uncaught exception: {0}") -MSG_DEF(JSMSG_PRECISION_RANGE, 1, JSEXN_RANGEERR, "precision {0} out of range") MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 1, JSEXN_TYPEERR, "invalid {0} usage") MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 0, JSEXN_RANGEERR, "invalid array length") -MSG_DEF(JSMSG_BAD_APPLY_ARGS, 1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array") MSG_DEF(JSMSG_REDECLARED_VAR, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}") MSG_DEF(JSMSG_UNDECLARED_VAR, 1, JSEXN_REFERENCEERR, "assignment to undeclared variable {0}") -MSG_DEF(JSMSG_DEPRECATED_USAGE, 1, JSEXN_REFERENCEERR, "deprecated {0} usage") -MSG_DEF(JSMSG_BAD_URI, 0, JSEXN_URIERR, "malformed URI sequence") MSG_DEF(JSMSG_GETTER_ONLY, 0, JSEXN_TYPEERR, "setting a property that has only a getter") MSG_DEF(JSMSG_UNDEFINED_PROP, 1, JSEXN_REFERENCEERR, "reference to undefined property {0}") -MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 0, JSEXN_RANGEERR, "repeat count must be non-negative") MSG_DEF(JSMSG_INVALID_MAP_ITERABLE, 0, JSEXN_TYPEERR, "iterable for map should have array-like objects") -MSG_DEF(JSMSG_NOT_A_CODEPOINT, 1, JSEXN_RANGEERR, "{0} is not a valid code point") MSG_DEF(JSMSG_NESTING_GENERATOR, 0, JSEXN_TYPEERR, "already executing generator") -MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM, 0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'") MSG_DEF(JSMSG_INCOMPATIBLE_METHOD, 3, JSEXN_TYPEERR, "{0} {1} called on incompatible {2}") MSG_DEF(JSMSG_OBJECT_WATCH_DEPRECATED, 0, JSEXN_NONE, "Object.prototype.watch and unwatch are very slow, non-standard, and deprecated; use a getter/setter instead") MSG_DEF(JSMSG_TYPE_ERR_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") -MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 0, JSEXN_INTERNALERR, "buffer too small") MSG_DEF(JSMSG_BAD_SURROGATE_CHAR, 1, JSEXN_TYPEERR, "bad surrogate character {0}") MSG_DEF(JSMSG_UTF8_CHAR_TOO_LARGE, 1, JSEXN_TYPEERR, "UTF-8 character {0} too large") MSG_DEF(JSMSG_MALFORMED_UTF8_CHAR, 1, JSEXN_TYPEERR, "malformed UTF-8 character sequence at offset {0}") -MSG_DEF(JSMSG_USER_DEFINED_ERROR, 0, JSEXN_ERR, "JS_ReportError was called") MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 1, JSEXN_TYPEERR, "wrong constructor called for {0}") MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 0, JSEXN_NONE, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create") MSG_DEF(JSMSG_BAD_GENERATOR_YIELD, 1, JSEXN_TYPEERR, "yield from closing generator {0}") -MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 1, JSEXN_SYNTAXERR, "{0} expression must be parenthesized") MSG_DEF(JSMSG_EMPTY_ARRAY_REDUCE, 0, JSEXN_TYPEERR, "reduce of empty array with no initial value") MSG_DEF(JSMSG_UNEXPECTED_TYPE, 2, JSEXN_TYPEERR, "{0} is {1}") -MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties") MSG_DEF(JSMSG_MISSING_FUN_ARG, 2, JSEXN_TYPEERR, "missing argument {0} when calling function {1}") -MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") MSG_DEF(JSMSG_NOT_NONNULL_OBJECT, 0, JSEXN_TYPEERR, "value is not a non-null object") MSG_DEF(JSMSG_INVALID_DESCRIPTOR, 0, JSEXN_TYPEERR, "property descriptors must not specify a value or be writable when a getter or setter has been specified") MSG_DEF(JSMSG_OBJECT_NOT_EXTENSIBLE, 1, JSEXN_TYPEERR, "{0} is not extensible") @@ -129,33 +86,90 @@ MSG_DEF(JSMSG_CANT_REDEFINE_PROP, 1, JSEXN_TYPEERR, "can't redefine non-con MSG_DEF(JSMSG_CANT_APPEND_TO_ARRAY, 0, JSEXN_TYPEERR, "can't add elements past the end of an array if its length property is unwritable") MSG_DEF(JSMSG_CANT_REDEFINE_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't redefine array length") MSG_DEF(JSMSG_CANT_DEFINE_PAST_ARRAY_LENGTH, 0, JSEXN_TYPEERR, "can't define array index property past the end of an array with non-writable length") -MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_ERR, "call to Function() blocked by CSP") MSG_DEF(JSMSG_BAD_GET_SET_FIELD, 1, JSEXN_TYPEERR, "property descriptor's {0} field is neither undefined nor a function") MSG_DEF(JSMSG_THROW_TYPE_ERROR, 0, JSEXN_TYPEERR, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them") -MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP, 0, JSEXN_TYPEERR, "toISOString property is not callable") MSG_DEF(JSMSG_NOT_EXPECTED_TYPE, 3, JSEXN_TYPEERR, "{0}: expected {1}, got {2}") -MSG_DEF(JSMSG_CALLER_IS_STRICT, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored") MSG_DEF(JSMSG_NEED_DEBUG_MODE, 0, JSEXN_ERR, "function can be called only in debug mode") -MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 0, JSEXN_TYPEERR, "can't clone object") -MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_ERR, "call to eval() blocked by CSP") MSG_DEF(JSMSG_NOT_ITERABLE, 1, JSEXN_TYPEERR, "{0} is not iterable") -MSG_DEF(JSMSG_PARAMETER_AFTER_REST, 0, JSEXN_SYNTAXERR, "parameter after rest parameter") -MSG_DEF(JSMSG_NO_REST_NAME, 0, JSEXN_SYNTAXERR, "no parameter name after ...") -MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used") MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 2, JSEXN_NONE, "{0} is being assigned a {1}, but already has one") -MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 0, JSEXN_RANGEERR, "invalid parallel method argument") MSG_DEF(JSMSG_NEXT_RETURNED_PRIMITIVE, 0, JSEXN_TYPEERR, "iterator.next() returned a non-object value") -MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 0, JSEXN_ERR, "no conflict resolution function provided") -MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS,0, JSEXN_ERR, "index in scatter vector out of bounds") -MSG_DEF(JSMSG_UNWRAP_DENIED, 0, JSEXN_ERR, "permission denied to unwrap object") MSG_DEF(JSMSG_WRONG_VALUE, 2, JSEXN_ERR, "expected {0} but found {1}") -MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 1, JSEXN_ERR, "target for index {0} is not an integer") -MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 0, JSEXN_RANGEERR, "too many constructor arguments") -MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 0, JSEXN_RANGEERR, "too many function arguments") MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL, 1, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed on {0}") MSG_DEF(JSMSG_INVALID_ARG_TYPE, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}") MSG_DEF(JSMSG_TERMINATED, 1, JSEXN_ERR, "Script terminated by timeout at:\n{0}") +// JSON +MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data") +MSG_DEF(JSMSG_JSON_CYCLIC_VALUE, 1, JSEXN_TYPEERR, "cyclic {0} value") + +// Runtime errors +MSG_DEF(JSMSG_BAD_INSTANCEOF_RHS, 1, JSEXN_TYPEERR, "invalid 'instanceof' operand {0}") +MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 0, JSEXN_REFERENCEERR, "invalid assignment left-hand side") +MSG_DEF(JSMSG_BAD_PROTOTYPE, 1, JSEXN_TYPEERR, "'prototype' property of {0} is not an object") +MSG_DEF(JSMSG_IN_NOT_OBJECT, 1, JSEXN_TYPEERR, "invalid 'in' operand {0}") +MSG_DEF(JSMSG_TOO_MANY_CON_SPREADARGS, 0, JSEXN_RANGEERR, "too many constructor arguments") +MSG_DEF(JSMSG_TOO_MANY_FUN_SPREADARGS, 0, JSEXN_RANGEERR, "too many function arguments") + +// Date +MSG_DEF(JSMSG_INVALID_DATE, 0, JSEXN_RANGEERR, "invalid date") +MSG_DEF(JSMSG_BAD_TOISOSTRING_PROP, 0, JSEXN_TYPEERR, "toISOString property is not callable") + +// String +MSG_DEF(JSMSG_BAD_URI, 0, JSEXN_URIERR, "malformed URI sequence") +MSG_DEF(JSMSG_INVALID_NORMALIZE_FORM, 0, JSEXN_RANGEERR, "form must be one of 'NFC', 'NFD', 'NFKC', or 'NFKD'") +MSG_DEF(JSMSG_NEGATIVE_REPETITION_COUNT, 0, JSEXN_RANGEERR, "repeat count must be non-negative") +MSG_DEF(JSMSG_NOT_A_CODEPOINT, 1, JSEXN_RANGEERR, "{0} is not a valid code point") +MSG_DEF(JSMSG_RESULTING_STRING_TOO_LARGE, 0, JSEXN_RANGEERR, "repeat count must be less than infinity and not overflow maximum string size") + +// Number +MSG_DEF(JSMSG_BAD_RADIX, 0, JSEXN_RANGEERR, "radix must be an integer at least 2 and no greater than 36") +MSG_DEF(JSMSG_PRECISION_RANGE, 1, JSEXN_RANGEERR, "precision {0} out of range") + +// Function +MSG_DEF(JSMSG_BAD_APPLY_ARGS, 1, JSEXN_TYPEERR, "second argument to Function.prototype.{0} must be an array") +MSG_DEF(JSMSG_BAD_FORMAL, 0, JSEXN_SYNTAXERR, "malformed formal parameter") +MSG_DEF(JSMSG_CALLER_IS_STRICT, 0, JSEXN_TYPEERR, "access to strict mode caller function is censored") +MSG_DEF(JSMSG_DEPRECATED_USAGE, 1, JSEXN_REFERENCEERR, "deprecated {0} usage") +MSG_DEF(JSMSG_FUNCTION_ARGUMENTS_AND_REST, 0, JSEXN_ERR, "the 'arguments' property of a function with a rest parameter may not be used") +MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION, 1, JSEXN_TYPEERR, "{0} is not a scripted function") +MSG_DEF(JSMSG_NO_REST_NAME, 0, JSEXN_SYNTAXERR, "no parameter name after ...") +MSG_DEF(JSMSG_PARAMETER_AFTER_REST, 0, JSEXN_SYNTAXERR, "parameter after rest parameter") +MSG_DEF(JSMSG_TOO_MANY_FUN_APPLY_ARGS, 0, JSEXN_RANGEERR, "arguments array passed to Function.prototype.apply is too large") + +// CSP +MSG_DEF(JSMSG_CSP_BLOCKED_EVAL, 0, JSEXN_ERR, "call to eval() blocked by CSP") +MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION, 0, JSEXN_ERR, "call to Function() blocked by CSP") + +// Wrappers +MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED, 1, JSEXN_ERR, "Permission denied to define accessor property '{0}'") +MSG_DEF(JSMSG_DEAD_OBJECT, 0, JSEXN_TYPEERR, "can't access dead object") +MSG_DEF(JSMSG_UNWRAP_DENIED, 0, JSEXN_ERR, "permission denied to unwrap object") + +// JSAPI-only (Not thrown as JS exceptions) +MSG_DEF(JSMSG_BAD_CHAR, 1, JSEXN_INTERNALERR, "invalid format character {0}") +MSG_DEF(JSMSG_BAD_CLONE_FUNOBJ_SCOPE, 0, JSEXN_TYPEERR, "bad cloned function scope chain") +MSG_DEF(JSMSG_BAD_NEW_RESULT, 1, JSEXN_TYPEERR, "invalid new expression result {0}") +MSG_DEF(JSMSG_BAD_TYPE, 1, JSEXN_TYPEERR, "unknown type {0}") +MSG_DEF(JSMSG_CANT_CLONE_OBJECT, 0, JSEXN_TYPEERR, "can't clone object") +MSG_DEF(JSMSG_CANT_OPEN, 2, JSEXN_ERR, "can't open {0}: {1}") +MSG_DEF(JSMSG_USER_DEFINED_ERROR, 0, JSEXN_ERR, "JS_ReportError was called") + +// Internal errors +MSG_DEF(JSMSG_ALLOC_OVERFLOW, 0, JSEXN_INTERNALERR, "allocation size overflow") +MSG_DEF(JSMSG_BAD_BYTECODE, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}") +MSG_DEF(JSMSG_BAD_SCRIPT_MAGIC, 0, JSEXN_INTERNALERR, "bad script XDR magic number") +MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 0, JSEXN_INTERNALERR, "buffer too small") +MSG_DEF(JSMSG_BYTECODE_TOO_BIG, 2, JSEXN_INTERNALERR, "bytecode {0} too large (limit {1})") +MSG_DEF(JSMSG_CANT_SET_ARRAY_ATTRS, 0, JSEXN_INTERNALERR, "can't set attributes on indexed array properties") +MSG_DEF(JSMSG_INACTIVE, 0, JSEXN_INTERNALERR, "nothing active on context") +MSG_DEF(JSMSG_NEED_DIET, 1, JSEXN_INTERNALERR, "{0} too large") +MSG_DEF(JSMSG_OUT_OF_MEMORY, 0, JSEXN_INTERNALERR, "out of memory") +MSG_DEF(JSMSG_OVER_RECURSED, 0, JSEXN_INTERNALERR, "too much recursion") +MSG_DEF(JSMSG_TOO_BIG_TO_ENCODE, 0, JSEXN_INTERNALERR, "data are to big to encode") +MSG_DEF(JSMSG_TOO_DEEP, 1, JSEXN_INTERNALERR, "{0} nested too deeply") +MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 1, JSEXN_INTERNALERR, "uncaught exception: {0}") +MSG_DEF(JSMSG_UNKNOWN_FORMAT, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}") + // Frontend MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}") MSG_DEF(JSMSG_ARGUMENTS_AND_REST, 0, JSEXN_SYNTAXERR, "'arguments' object may not be used in conjunction with a rest parameter") @@ -173,6 +187,7 @@ MSG_DEF(JSMSG_BAD_DUP_ARGS, 0, JSEXN_SYNTAXERR, "duplicate argument n MSG_DEF(JSMSG_BAD_FOR_EACH_LOOP, 0, JSEXN_SYNTAXERR, "invalid for each loop") MSG_DEF(JSMSG_BAD_FOR_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid for/in left-hand side") MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 1, JSEXN_TYPEERR, "generator function {0} returns a value") +MSG_DEF(JSMSG_BAD_GENERATOR_SYNTAX, 1, JSEXN_SYNTAXERR, "{0} expression must be parenthesized") MSG_DEF(JSMSG_BAD_GENEXP_BODY, 1, JSEXN_SYNTAXERR, "illegal use of {0} in generator expression") MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 0, JSEXN_REFERENCEERR, "invalid increment/decrement operand") MSG_DEF(JSMSG_BAD_OCTAL, 1, JSEXN_SYNTAXERR, "{0} is not a legal ECMA-262 octal constant") @@ -214,6 +229,7 @@ MSG_DEF(JSMSG_DUPLICATE_FORMAL, 1, JSEXN_SYNTAXERR, "duplicate formal arg MSG_DEF(JSMSG_DUPLICATE_LABEL, 0, JSEXN_SYNTAXERR, "duplicate label") MSG_DEF(JSMSG_DUPLICATE_PROPERTY, 1, JSEXN_SYNTAXERR, "property name {0} appears more than once in object literal") MSG_DEF(JSMSG_EMPTY_CONSEQUENT, 0, JSEXN_SYNTAXERR, "mistyped ; after conditional?") +MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (==) mistyped as assignment (=)?") MSG_DEF(JSMSG_EXPORT_DECL_AT_TOP_LEVEL,0, JSEXN_SYNTAXERR, "export declarations may only appear at top level") MSG_DEF(JSMSG_FINALLY_WITHOUT_TRY, 0, JSEXN_SYNTAXERR, "finally without try") MSG_DEF(JSMSG_FROM_AFTER_IMPORT_SPEC_SET, 0, JSEXN_SYNTAXERR, "missing keyword 'from' after import specifier set") @@ -384,7 +400,7 @@ MSG_DEF(JSMSG_TOO_MANY_PARENS, 0, JSEXN_INTERNALERR, "too many parenthes MSG_DEF(JSMSG_UNMATCHED_RIGHT_PAREN, 0, JSEXN_SYNTAXERR, "unmatched ) in regular expression") MSG_DEF(JSMSG_UNTERM_CLASS, 0, JSEXN_SYNTAXERR, "unterminated character class") -// Self hosting +// Self-hosting MSG_DEF(JSMSG_DEFAULT_LOCALE_ERROR, 0, JSEXN_ERR, "internal error getting the default locale") MSG_DEF(JSMSG_NO_SUCH_SELF_HOSTED_PROP,1, JSEXN_ERR, "No such property on self-hosted object: {0}") @@ -403,6 +419,12 @@ MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_ERR, "invalid arguments") MSG_DEF(JSMSG_TYPED_ARRAY_BAD_INDEX, 0, JSEXN_ERR, "invalid or out-of-range index") MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_ERR, "argument {0} must be >= 0") +// Parallel array +MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 0, JSEXN_RANGEERR, "invalid parallel method argument") +MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BAD_TARGET, 1, JSEXN_ERR, "target for index {0} is not an integer") +MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_BOUNDS,0, JSEXN_ERR, "index in scatter vector out of bounds") +MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 0, JSEXN_ERR, "no conflict resolution function provided") + // Reflect MSG_DEF(JSMSG_BAD_PARSE_NODE, 0, JSEXN_INTERNALERR, "bad parse node") diff --git a/js/src/json.cpp b/js/src/json.cpp index 03355bd2810..c3e03cbf0e9 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -314,7 +314,8 @@ JO(JSContext *cx, HandleObject obj, StringifyContext *scx) if (!detect.init()) return false; if (detect.foundCycle()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CYCLIC_VALUE, js_object_str); + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_JSON_CYCLIC_VALUE, + js_object_str); return false; } @@ -404,7 +405,8 @@ JA(JSContext *cx, HandleObject obj, StringifyContext *scx) if (!detect.init()) return false; if (detect.foundCycle()) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CYCLIC_VALUE, js_object_str); + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_JSON_CYCLIC_VALUE, + js_object_str); return false; } From 90ac1fc8351ba172db70bbecf9b5ba377a4fb61e Mon Sep 17 00:00:00 2001 From: Michal Novotny Date: Mon, 18 Aug 2014 21:11:40 +0200 Subject: [PATCH 14/86] Bug 1054425 - cache2: leak in CacheFileMetadata::WriteMetadata, r=jduell --- netwerk/cache2/CacheFileIOManager.cpp | 5 +++++ netwerk/cache2/CacheFileMetadata.cpp | 23 ++++++++--------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/netwerk/cache2/CacheFileIOManager.cpp b/netwerk/cache2/CacheFileIOManager.cpp index 8ff79a6405c..353caf2b3d3 100644 --- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -1867,6 +1867,11 @@ CacheFileIOManager::Write(CacheFileHandle *aHandle, int64_t aOffset, nsRefPtr ioMan = gInstance; if (aHandle->IsClosed() || !ioMan) { + if (!aCallback) { + // When no callback is provided, CacheFileIOManager is responsible for + // releasing the buffer. We must release it even in case of failure. + free(const_cast(aBuf)); + } return NS_ERROR_NOT_INITIALIZED; } diff --git a/netwerk/cache2/CacheFileMetadata.cpp b/netwerk/cache2/CacheFileMetadata.cpp index e8d2266c472..f290ea03b9b 100644 --- a/netwerk/cache2/CacheFileMetadata.cpp +++ b/netwerk/cache2/CacheFileMetadata.cpp @@ -260,33 +260,26 @@ CacheFileMetadata::WriteMetadata(uint32_t aOffset, NetworkEndian::writeUint32(p, aOffset); p += sizeof(uint32_t); - char * writeBuffer; + char * writeBuffer = mWriteBuf; if (aListener) { mListener = aListener; - writeBuffer = mWriteBuf; } else { - // We are not going to pass |this| as callback to CacheFileIOManager::Write - // so we must allocate a new buffer that will be released automatically when - // write is finished. This is actually better than to let - // CacheFileMetadata::OnDataWritten do the job, since when dispatching the - // result from some reason fails during shutdown, we would unnecessarily leak - // both this object and the buffer. - writeBuffer = static_cast(moz_xmalloc(p - mWriteBuf)); - memcpy(writeBuffer, mWriteBuf, p - mWriteBuf); + // We are not going to pass |this| as a callback so the buffer will be + // released by CacheFileIOManager. Just null out mWriteBuf here. + mWriteBuf = nullptr; } - rv = CacheFileIOManager::Write(mHandle, aOffset, writeBuffer, p - mWriteBuf, + rv = CacheFileIOManager::Write(mHandle, aOffset, writeBuffer, p - writeBuffer, true, aListener ? this : nullptr); if (NS_FAILED(rv)) { LOG(("CacheFileMetadata::WriteMetadata() - CacheFileIOManager::Write() " "failed synchronously. [this=%p, rv=0x%08x]", this, rv)); mListener = nullptr; - if (writeBuffer != mWriteBuf) { - free(writeBuffer); + if (mWriteBuf) { + free(mWriteBuf); + mWriteBuf = nullptr; } - free(mWriteBuf); - mWriteBuf = nullptr; NS_ENSURE_SUCCESS(rv, rv); } From 61e21d45dffdcf1abb7b3a339c70ec619d8d527b Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 18 Aug 2014 15:18:30 -0400 Subject: [PATCH 15/86] Bug 1055001 - Make Maybe's constructor explicit; r=froydnj --- mfbt/Maybe.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mfbt/Maybe.h b/mfbt/Maybe.h index 9d223015d3c..e4288c696d4 100644 --- a/mfbt/Maybe.h +++ b/mfbt/Maybe.h @@ -93,7 +93,7 @@ public: Maybe() : mIsSome(false) { } ~Maybe() { reset(); } - Maybe(Nothing) : mIsSome(false) { } + explicit Maybe(Nothing) : mIsSome(false) { } Maybe(const Maybe& aOther) : mIsSome(false) From 70a7c8657effa3fec907e5dc4a8c4280a479398f Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 12:20:39 -0700 Subject: [PATCH 16/86] Bug 1054334 - SpiderMonkey: Delete unneeded semicolons r=nbp --- js/public/ProfilingStack.h | 2 +- js/public/UbiNode.h | 6 +++--- js/public/WeakMapPtr.h | 4 ++-- js/src/builtin/SIMD.cpp | 4 ++-- js/src/ctypes/CTypes.cpp | 4 ++-- js/src/jit/BaselineBailouts.cpp | 2 +- js/src/jit/RangeAnalysis.cpp | 4 ++-- js/src/jit/shared/IonAssemblerBuffer.h | 4 ++-- js/src/jsapi-tests/testPersistentRooted.cpp | 2 +- js/src/jsapi.cpp | 4 ++-- js/src/jsapi.h | 10 +++++----- js/src/jsarray.cpp | 2 +- js/src/jsfriendapi.h | 4 ++-- js/src/jsgc.cpp | 2 +- js/src/jsproxy.cpp | 2 +- js/src/jsproxy.h | 4 ++-- js/src/vm/Interpreter-inl.h | 2 +- js/src/vm/Interpreter.cpp | 6 +++--- js/xpconnect/src/xpcprivate.h | 8 ++++---- 19 files changed, 38 insertions(+), 38 deletions(-) diff --git a/js/public/ProfilingStack.h b/js/public/ProfilingStack.h index 3c9cbb9d71d..99f2ef87607 100644 --- a/js/public/ProfilingStack.h +++ b/js/public/ProfilingStack.h @@ -92,7 +92,7 @@ class ProfileEntry bool isCpp() const volatile { return hasFlag(IS_CPP_ENTRY); } bool isJs() const volatile { return !isCpp(); } - bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); }; + bool isCopyLabel() const volatile { return hasFlag(FRAME_LABEL_COPY); } void setLabel(const char *aString) volatile { string = aString; } const char *label() const volatile { return string; } diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index de16868727b..6c369938b05 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -406,7 +406,7 @@ class EdgeRange { EdgeRange() : front_(nullptr) { } public: - virtual ~EdgeRange() { }; + virtual ~EdgeRange() { } // True if there are no more edges in this range. bool empty() const { return !front_; } @@ -444,7 +444,7 @@ class TracerConcrete : public Base { public: static const jschar concreteTypeName[]; - static void construct(void *storage, Referent *ptr) { new (storage) TracerConcrete(ptr); }; + static void construct(void *storage, Referent *ptr) { new (storage) TracerConcrete(ptr); } }; // For JS_TraceChildren-based types that have a 'compartment' method. @@ -460,7 +460,7 @@ class TracerConcreteWithCompartment : public TracerConcrete { public: static void construct(void *storage, Referent *ptr) { new (storage) TracerConcreteWithCompartment(ptr); - }; + } }; template<> struct Concrete : TracerConcreteWithCompartment { }; diff --git a/js/public/WeakMapPtr.h b/js/public/WeakMapPtr.h index f5822bef4b2..887cfa4d592 100644 --- a/js/public/WeakMapPtr.h +++ b/js/public/WeakMapPtr.h @@ -23,9 +23,9 @@ template class JS_PUBLIC_API(WeakMapPtr) { public: - WeakMapPtr() : ptr(nullptr) {}; + WeakMapPtr() : ptr(nullptr) {} bool init(JSContext *cx); - bool initialized() { return ptr != nullptr; }; + bool initialized() { return ptr != nullptr; } void destroy(); virtual ~WeakMapPtr() { MOZ_ASSERT(!initialized()); } void trace(JSTracer *tracer); diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index e9fc6c4b47e..438f2303151 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -690,7 +690,7 @@ FuncShuffle(JSContext *cx, unsigned argc, Value *vp) if (!IsVectorObject(args[0]) || !args[1].isInt32()) return ErrorBadArgs(cx); - Elem *val = TypedObjectMemory(args[0]);; + Elem *val = TypedObjectMemory(args[0]); int32_t maskArg; if (!ToInt32(cx, args[1], &maskArg)) return false; @@ -734,7 +734,7 @@ Int32x4BinaryScalar(JSContext *cx, unsigned argc, Value *vp) if (!IsVectorObject(args[0]) || !args[1].isNumber()) return ErrorBadArgs(cx); - int32_t *val = TypedObjectMemory(args[0]);; + int32_t *val = TypedObjectMemory(args[0]); int32_t bits; if (!ToInt32(cx, args[1], &bits)) return false; diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index b0a1905b271..71bd1ed09ca 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -4429,7 +4429,7 @@ ArrayType::GetSafeLength(JSObject* obj, size_t* result) // The "length" property can be an int, a double, or JSVAL_VOID // (for arrays of undefined length), and must always fit in a size_t. if (length.isInt32()) { - *result = length.toInt32();; + *result = length.toInt32(); return true; } if (length.isDouble()) { @@ -4455,7 +4455,7 @@ ArrayType::GetLength(JSObject* obj) // (for arrays of undefined length), and must always fit in a size_t. // For callers who know it can never be JSVAL_VOID, return a size_t directly. if (length.isInt32()) - return length.toInt32();; + return length.toInt32(); return Convert(length.toDouble()); } diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 13d1d8ce84f..917206706c7 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -79,7 +79,7 @@ struct BaselineStackBuilder static size_t HeaderSize() { return AlignBytes(sizeof(BaselineBailoutInfo), sizeof(void *)); - }; + } size_t bufferTotal_; size_t bufferAvail_; size_t bufferUsed_; diff --git a/js/src/jit/RangeAnalysis.cpp b/js/src/jit/RangeAnalysis.cpp index 32aa76c28f6..2db5637f52c 100644 --- a/js/src/jit/RangeAnalysis.cpp +++ b/js/src/jit/RangeAnalysis.cpp @@ -677,13 +677,13 @@ Range::or_(TempAllocator &alloc, const Range *lhs, const Range *rhs) if (lhs->lower() == 0) return new(alloc) Range(*rhs); if (lhs->lower() == -1) - return new(alloc) Range(*lhs);; + return new(alloc) Range(*lhs); } if (rhs->lower() == rhs->upper()) { if (rhs->lower() == 0) return new(alloc) Range(*lhs); if (rhs->lower() == -1) - return new(alloc) Range(*rhs);; + return new(alloc) Range(*rhs); } // The code below uses CountLeadingZeroes32, which has undefined behavior diff --git a/js/src/jit/shared/IonAssemblerBuffer.h b/js/src/jit/shared/IonAssemblerBuffer.h index bad2cff236c..1ff94997aa6 100644 --- a/js/src/jit/shared/IonAssemblerBuffer.h +++ b/js/src/jit/shared/IonAssemblerBuffer.h @@ -50,7 +50,7 @@ class BufferOffset } BufferOffset() : offset(INT_MIN) {} - bool assigned() const { return offset != INT_MIN; }; + bool assigned() const { return offset != INT_MIN; } }; template @@ -278,7 +278,7 @@ struct AssemblerBuffer Inst *i = m_buffer->getInst(bo); bo = BufferOffset(bo.getOffset() + i->size()); return cur(); - }; + } Inst *cur() { return m_buffer->getInst(bo); } diff --git a/js/src/jsapi-tests/testPersistentRooted.cpp b/js/src/jsapi-tests/testPersistentRooted.cpp index 437245367fb..cd04197dfee 100644 --- a/js/src/jsapi-tests/testPersistentRooted.cpp +++ b/js/src/jsapi-tests/testPersistentRooted.cpp @@ -41,7 +41,7 @@ const JSClass BarkWhenTracedClass::class_ = { struct Kennel { PersistentRootedObject obj; explicit Kennel(JSContext *cx) : obj(cx) { } - Kennel(JSContext *cx, const HandleObject &woof) : obj(cx, woof) { }; + Kennel(JSContext *cx, const HandleObject &woof) : obj(cx, woof) { } }; // A function for allocating a Kennel and a barker. Only allocating diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 80791e66440..60d14ca22b0 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1151,8 +1151,8 @@ JS_InitStandardClasses(JSContext *cx, HandleObject obj) typedef struct JSStdName { size_t atomOffset; /* offset of atom pointer in JSAtomState */ JSProtoKey key; - bool isDummy() const { return key == JSProto_Null; }; - bool isSentinel() const { return key == JSProto_LIMIT; }; + bool isDummy() const { return key == JSProto_Null; } + bool isSentinel() const { return key == JSProto_LIMIT; } } JSStdName; static const JSStdName* diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 035d2b23915..b6d6b70ca28 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1320,8 +1320,8 @@ class JSAutoRequest #if 0 private: - static void *operator new(size_t) CPP_THROW_NEW { return 0; }; - static void operator delete(void *, size_t) { }; + static void *operator new(size_t) CPP_THROW_NEW { return 0; } + static void operator delete(void *, size_t) { } #endif }; @@ -2518,11 +2518,11 @@ class JS_PUBLIC_API(CompartmentOptions) if (mode_ == Default) return defaultValue; return mode_ == ForceTrue; - }; + } void set(bool overrideValue) { mode_ = overrideValue ? ForceTrue : ForceFalse; - }; + } void reset() { mode_ = Default; @@ -2610,7 +2610,7 @@ class JS_PUBLIC_API(CompartmentOptions) } bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; - }; + } // A null add-on ID means that the compartment is not associated with an // add-on. diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index e7438265fa1..5ea5469505b 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -947,7 +947,7 @@ template struct CharSeparatorOp { const CharT sep; - explicit CharSeparatorOp(CharT sep) : sep(sep) {}; + explicit CharSeparatorOp(CharT sep) : sep(sep) {} bool operator()(JSContext *, StringBuffer &sb) { return sb.append(sep); } }; diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index fbcdda1d3a0..f49b0024cfe 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1289,7 +1289,7 @@ class MOZ_STACK_CLASS AutoStableStringChars public: explicit AutoStableStringChars(JSContext *cx) : s_(cx), state_(Uninitialized), ownsChars_(false) - {}; + {} ~AutoStableStringChars(); bool init(JSContext *cx, JSString *s); @@ -2379,7 +2379,7 @@ JS_FRIEND_API(void) Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx); #else inline void -Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx) {}; +Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx) {} #endif diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 6fba654c6a8..10026d87d92 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6323,7 +6323,7 @@ JS::AutoAssertOnGC::AutoAssertOnGC() JSRuntime *runtime = data->runtimeIfOnOwnerThread(); if (runtime) { gc = &runtime->gc; - gcNumber = gc->gcNumber();; + gcNumber = gc->gcNumber(); gc->enterUnsafeRegion(); } } diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index ae41836dc40..a944fa632a0 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -1866,7 +1866,7 @@ ScriptedDirectProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, return false; // step 9 - bool success = ToBoolean(trapResult);; + bool success = ToBoolean(trapResult); // step 11 if (!success) { diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index cac5730de3e..37730ea483b 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -501,7 +501,7 @@ class JS_FRIEND_API(AutoEnterPolicy) : context(nullptr) , enteredAction(BaseProxyHandler::NONE) #endif - {}; + {} void reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id); bool allow; bool rv; @@ -553,7 +553,7 @@ assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id, #else inline void assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id, BaseProxyHandler::Action act) -{}; +{} #endif } /* namespace js */ diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 0ff7444c2da..b6a3a954666 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -562,7 +562,7 @@ ProcessCallSiteObjOperation(JSContext *cx, RootedObject &cso, RootedObject &raw, } else { \ double l, r; \ if (!ToNumber(cx, lhs, &l) || !ToNumber(cx, rhs, &r)) \ - return false;; \ + return false; \ *res = (l OP r); \ } \ } \ diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index e5fc625344b..fdb53b6c44a 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1993,7 +1993,7 @@ CASE(JSOP_SETCONST) if (!SetConstOperation(cx, obj, name, rval)) goto error; } -END_CASE(JSOP_SETCONST); +END_CASE(JSOP_SETCONST) CASE(JSOP_BINDGNAME) PUSH_OBJECT(REGS.fp()->global()); @@ -3106,7 +3106,7 @@ CASE(JSOP_MUTATEPROTO) REGS.sp--; } -END_CASE(JSOP_MUTATEPROTO); +END_CASE(JSOP_MUTATEPROTO) CASE(JSOP_INITPROP) { @@ -3130,7 +3130,7 @@ CASE(JSOP_INITPROP) REGS.sp--; } -END_CASE(JSOP_INITPROP); +END_CASE(JSOP_INITPROP) CASE(JSOP_INITELEM) { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index c2fb9d63a91..684f6a555b7 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -2882,7 +2882,7 @@ public: private: friend class mozilla::dom::danger::AutoCxPusher; - friend bool xpc::PushJSContextNoScriptContext(JSContext *aCx);; + friend bool xpc::PushJSContextNoScriptContext(JSContext *aCx); friend void xpc::PopJSContextNoScriptContext(); // We make these private so that stack manipulation can only happen @@ -3466,7 +3466,7 @@ public: , defineAs(cx, JSID_VOID) { } - virtual bool Parse() { return ParseId("defineAs", &defineAs); }; + virtual bool Parse() { return ParseId("defineAs", &defineAs); } JS::RootedId defineAs; }; @@ -3481,7 +3481,7 @@ public: virtual bool Parse() { return ParseId("defineAs", &defineAs); - }; + } JS::RootedId defineAs; }; @@ -3498,7 +3498,7 @@ public: virtual bool Parse() { return ParseBoolean("wrapReflectors", &wrapReflectors) && ParseBoolean("cloneFunctions", &cloneFunctions); - }; + } // When a reflector is encountered, wrap it rather than aborting the clone. bool wrapReflectors; From da8c75a9ed12d2450c14b4dafe8b6ec9e4cb88c3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 12:20:39 -0700 Subject: [PATCH 17/86] Bug 1054334 - SpiderMonkey: Use () instead of (void) in C++ files r=nbp --- js/src/builtin/Intl.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 6236e526229..d6ba37fb293 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -131,7 +131,7 @@ enum UCollationResult { }; static int32_t -ucol_countAvailable(void) +ucol_countAvailable() { MOZ_CRASH("ucol_countAvailable: Intl API disabled"); } @@ -206,7 +206,7 @@ enum UNumberFormatTextAttribute { }; static int32_t -unum_countAvailable(void) +unum_countAvailable() { MOZ_CRASH("unum_countAvailable: Intl API disabled"); } @@ -345,7 +345,7 @@ enum UDateFormatStyle { }; static int32_t -udat_countAvailable(void) +udat_countAvailable() { MOZ_CRASH("udat_countAvailable: Intl API disabled"); } @@ -430,7 +430,7 @@ CreateDefaultOptions(JSContext *cx, MutableHandleValue defaultOptions) // CountAvailable and GetAvailable describe the signatures used for ICU API // to determine available locales for various functionality. typedef int32_t -(* CountAvailable)(void); +(* CountAvailable)(); typedef const char * (* GetAvailable)(int32_t localeIndex); From d4dcf10a95486f83102374d48124872959099dd3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 12:20:40 -0700 Subject: [PATCH 18/86] Bug 1054334 - SpiderMonkey: Eliminate unnecessary parentheses around return values r=nbp --- js/public/Id.h | 4 ++-- js/public/Value.h | 6 +++--- js/src/jit/BaselineDebugModeOSR.cpp | 14 +++++++------- js/src/jit/BaselineIC.cpp | 6 +++--- js/src/jit/BaselineIC.h | 8 ++++---- js/src/jit/IonBuilder.cpp | 4 ++-- js/src/jit/IonCaches.cpp | 12 ++++++------ js/src/jit/LiveRangeAllocator.h | 4 ++-- js/src/jit/MIR.h | 24 ++++++++++++------------ js/src/jit/ParallelFunctions.cpp | 4 ++-- js/src/jsapi.cpp | 6 +++--- js/src/vm/Probes-inl.h | 4 ++-- js/xpconnect/src/XPCMaps.cpp | 8 ++++---- 13 files changed, 52 insertions(+), 52 deletions(-) diff --git a/js/public/Id.h b/js/public/Id.h index 7103df82d28..f2d89df5bd9 100644 --- a/js/public/Id.h +++ b/js/public/Id.h @@ -150,13 +150,13 @@ JSID_IS_VOID(const jsid id) { MOZ_ASSERT_IF(((size_t)JSID_BITS(id) & JSID_TYPE_MASK) == JSID_TYPE_VOID, JSID_BITS(id) == JSID_TYPE_VOID); - return ((size_t)JSID_BITS(id) == JSID_TYPE_VOID); + return (size_t)JSID_BITS(id) == JSID_TYPE_VOID; } static MOZ_ALWAYS_INLINE bool JSID_IS_EMPTY(const jsid id) { - return ((size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL); + return (size_t)JSID_BITS(id) == JSID_TYPE_SYMBOL; } extern JS_PUBLIC_DATA(const jsid) JSID_VOID; diff --git a/js/public/Value.h b/js/public/Value.h index 291b0fedc4e..e0dd6c335b5 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1945,9 +1945,9 @@ DOUBLE_TO_JSVAL(double d) static inline JS_VALUE_CONSTEXPR jsval UINT_TO_JSVAL(uint32_t i) { - return (i <= JSVAL_INT_MAX - ? INT_TO_JSVAL((int32_t)i) - : DOUBLE_TO_JSVAL((double)i)); + return i <= JSVAL_INT_MAX + ? INT_TO_JSVAL((int32_t)i) + : DOUBLE_TO_JSVAL((double)i); } static inline jsval diff --git a/js/src/jit/BaselineDebugModeOSR.cpp b/js/src/jit/BaselineDebugModeOSR.cpp index 6472f8f1bf6..c69c6087e11 100644 --- a/js/src/jit/BaselineDebugModeOSR.cpp +++ b/js/src/jit/BaselineDebugModeOSR.cpp @@ -87,10 +87,10 @@ struct DebugModeOSREntry } bool needsRecompileInfo() const { - return (frameKind == ICEntry::Kind_CallVM || - frameKind == ICEntry::Kind_DebugTrap || - frameKind == ICEntry::Kind_DebugPrologue || - frameKind == ICEntry::Kind_DebugEpilogue); + return frameKind == ICEntry::Kind_CallVM || + frameKind == ICEntry::Kind_DebugTrap || + frameKind == ICEntry::Kind_DebugPrologue || + frameKind == ICEntry::Kind_DebugEpilogue; } bool recompiled() const { @@ -805,9 +805,9 @@ JitRuntime::getBaselineDebugModeOSRHandlerAddress(JSContext *cx, bool popFrameRe { if (!getBaselineDebugModeOSRHandler(cx)) return nullptr; - return (popFrameReg - ? baselineDebugModeOSRHandler_->raw() - : baselineDebugModeOSRHandlerNoFrameRegPopAddr_); + return popFrameReg + ? baselineDebugModeOSRHandler_->raw() + : baselineDebugModeOSRHandlerNoFrameRegPopAddr_; } JitCode * diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 5e6c6871aab..878fafa3202 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -3890,9 +3890,9 @@ static bool TypedArrayRequiresFloatingPoint(TypedArrayObject *tarr) { uint32_t type = tarr->type(); - return (type == Scalar::Uint32 || - type == Scalar::Float32 || - type == Scalar::Float64); + return type == Scalar::Uint32 || + type == Scalar::Float32 || + type == Scalar::Float64; } static bool diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index e3a545e5218..a95143421f7 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -2255,8 +2255,8 @@ class ICCompare_Int32WithBoolean : public ICStub bool generateStubCode(MacroAssembler &masm); virtual int32_t getKey() const { - return (static_cast(kind) | (static_cast(op_) << 16) | - (static_cast(lhsIsInt32_) << 24)); + return static_cast(kind) | (static_cast(op_) << 16) | + (static_cast(lhsIsInt32_) << 24); } public: @@ -2568,8 +2568,8 @@ class ICBinaryArith_Int32 : public ICStub // Stub keys shift-stubs need to encode the kind, the JSOp and if we allow doubles. virtual int32_t getKey() const { - return (static_cast(kind) | (static_cast(op_) << 16) | - (static_cast(allowDouble_) << 24)); + return static_cast(kind) | (static_cast(op_) << 16) | + (static_cast(allowDouble_) << 24); } public: diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index a069b417b6a..f5bf43c9d80 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -9250,8 +9250,8 @@ IonBuilder::needsToMonitorMissingProperties(types::TemporaryTypeSet *types) // TypeScript::Monitor to ensure that the observed type set contains // undefined. To account for possible missing properties, which property // types do not track, we must always insert a type barrier. - return (info().executionMode() == ParallelExecution && - !types->hasType(types::Type::UndefinedType())); + return info().executionMode() == ParallelExecution && + !types->hasType(types::Type::UndefinedType()); } bool diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index a752ffccf1b..83f9c5cf4cc 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -2986,10 +2986,10 @@ const size_t GetElementIC::MAX_FAILED_UPDATES = 16; GetElementIC::canAttachGetProp(JSObject *obj, const Value &idval, jsid id) { uint32_t dummy; - return (obj->isNative() && - idval.isString() && - JSID_IS_ATOM(id) && - !JSID_TO_ATOM(id)->isIndex(&dummy)); + return obj->isNative() && + idval.isString() && + JSID_IS_ATOM(id) && + !JSID_TO_ATOM(id)->isIndex(&dummy); } static bool @@ -3562,8 +3562,8 @@ static bool IsTypedArrayElementSetInlineable(JSObject *obj, const Value &idval, const Value &value) { // Don't bother attaching stubs for assigning strings and objects. - return (obj->is() && idval.isInt32() && - !value.isString() && !value.isObject()); + return obj->is() && idval.isInt32() && + !value.isString() && !value.isObject(); } static void diff --git a/js/src/jit/LiveRangeAllocator.h b/js/src/jit/LiveRangeAllocator.h index e3e7753539a..92eef0b8ace 100644 --- a/js/src/jit/LiveRangeAllocator.h +++ b/js/src/jit/LiveRangeAllocator.h @@ -568,8 +568,8 @@ static inline bool IsNunbox(VirtualRegister *vreg) { #ifdef JS_NUNBOX32 - return (vreg->type() == LDefinition::TYPE || - vreg->type() == LDefinition::PAYLOAD); + return vreg->type() == LDefinition::TYPE || + vreg->type() == LDefinition::PAYLOAD; #else return false; #endif diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 36159bd4f9a..8a729e6cc1a 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -7559,13 +7559,13 @@ class MStoreTypedArrayElement return arrayType_; } bool isByteArray() const { - return (arrayType_ == Scalar::Int8 || - arrayType_ == Scalar::Uint8 || - arrayType_ == Scalar::Uint8Clamped); + return arrayType_ == Scalar::Int8 || + arrayType_ == Scalar::Uint8 || + arrayType_ == Scalar::Uint8Clamped; } bool isFloatArray() const { - return (arrayType_ == Scalar::Float32 || - arrayType_ == Scalar::Float64); + return arrayType_ == Scalar::Float32 || + arrayType_ == Scalar::Float64; } TypePolicy *typePolicy() { return this; @@ -7632,13 +7632,13 @@ class MStoreTypedArrayElementHole return arrayType_; } bool isByteArray() const { - return (arrayType_ == Scalar::Int8 || - arrayType_ == Scalar::Uint8 || - arrayType_ == Scalar::Uint8Clamped); + return arrayType_ == Scalar::Int8 || + arrayType_ == Scalar::Uint8 || + arrayType_ == Scalar::Uint8Clamped; } bool isFloatArray() const { - return (arrayType_ == Scalar::Float32 || - arrayType_ == Scalar::Float64); + return arrayType_ == Scalar::Float32 || + arrayType_ == Scalar::Float64; } TypePolicy *typePolicy() { return this; @@ -7695,8 +7695,8 @@ class MStoreTypedArrayElementStatic : return typedArray_->type(); } bool isFloatArray() const { - return (viewType() == Scalar::Float32 || - viewType() == Scalar::Float64); + return viewType() == Scalar::Float32 || + viewType() == Scalar::Float64; } void *base() const; diff --git a/js/src/jit/ParallelFunctions.cpp b/js/src/jit/ParallelFunctions.cpp index 4fbae4fccb6..87b32651581 100644 --- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -123,8 +123,8 @@ jit::IsInTargetRegion(ForkJoinContext *cx, TypedObject *typedObj) { JS_ASSERT(typedObj->is()); // in case JIT supplies something bogus uint8_t *typedMem = typedObj->typedMem(); - return (typedMem >= cx->targetRegionStart && - typedMem < cx->targetRegionEnd); + return typedMem >= cx->targetRegionStart && + typedMem < cx->targetRegionEnd; } bool diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 60d14ca22b0..55d12fdb555 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -4332,9 +4332,9 @@ JS::OwningCompileOptions::copy(JSContext *cx, const ReadOnlyCompileOptions &rhs) setElementAttributeName(rhs.elementAttributeName()); setIntroductionScript(rhs.introductionScript()); - return (setFileAndLine(cx, rhs.filename(), rhs.lineno) && - setSourceMapURL(cx, rhs.sourceMapURL()) && - setIntroducerFilename(cx, rhs.introducerFilename())); + return setFileAndLine(cx, rhs.filename(), rhs.lineno) && + setSourceMapURL(cx, rhs.sourceMapURL()) && + setIntroducerFilename(cx, rhs.introducerFilename()); } bool diff --git a/js/src/vm/Probes-inl.h b/js/src/vm/Probes-inl.h index c828a37bb9a..453abaa1cdd 100644 --- a/js/src/vm/Probes-inl.h +++ b/js/src/vm/Probes-inl.h @@ -35,8 +35,8 @@ probes::CallTrackingActive(JSContext *cx) inline bool probes::WantNativeAddressInfo(JSContext *cx) { - return (cx->reportGranularity >= JITREPORT_GRANULARITY_FUNCTION && - JITGranularityRequested(cx) >= JITREPORT_GRANULARITY_FUNCTION); + return cx->reportGranularity >= JITREPORT_GRANULARITY_FUNCTION && + JITGranularityRequested(cx) >= JITREPORT_GRANULARITY_FUNCTION; } inline bool diff --git a/js/xpconnect/src/XPCMaps.cpp b/js/xpconnect/src/XPCMaps.cpp index 695bac41133..5fc5a8bbf58 100644 --- a/js/xpconnect/src/XPCMaps.cpp +++ b/js/xpconnect/src/XPCMaps.cpp @@ -375,10 +375,10 @@ NativeSetMap::Entry::Match(PLDHashTable *table, // it would end up really being a set with two interfaces (except for // the case where the one interface happened to be nsISupports). - return ((SetInTable->GetInterfaceCount() == 1 && - SetInTable->GetInterfaceAt(0) == Addition) || - (SetInTable->GetInterfaceCount() == 2 && - SetInTable->GetInterfaceAt(1) == Addition)); + return (SetInTable->GetInterfaceCount() == 1 && + SetInTable->GetInterfaceAt(0) == Addition) || + (SetInTable->GetInterfaceCount() == 2 && + SetInTable->GetInterfaceAt(1) == Addition); } if (!Addition && Set == SetInTable) From c3c37bfac8fc704b6d0b9d053c5d5a77a8e35abc Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 12:20:41 -0700 Subject: [PATCH 19/86] Bug 1054334 - SpiderMonkey: Use static and internal name linkage for more symbols r=nbp --- js/src/jsarray.cpp | 24 ++++++++++++------------ js/src/jsweakmap.cpp | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 5ea5469505b..be89385e01f 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1417,9 +1417,7 @@ array_reverse(JSContext *cx, unsigned argc, Value *vp) return true; } -namespace { - -inline bool +static inline bool CompareStringValues(JSContext *cx, const Value &a, const Value &b, bool *lessOrEqualp) { if (!CheckForInterrupt(cx)) @@ -1513,6 +1511,8 @@ CompareSubStringValues(JSContext *cx, const Char1 *s1, size_t len1, const Char2 return true; } +namespace { + struct SortComparatorStrings { JSContext *const cx; @@ -1619,7 +1619,7 @@ struct NumericElement size_t elementIndex; }; -bool +static bool ComparatorNumericLeftMinusRight(const NumericElement &a, const NumericElement &b, bool *lessOrEqualp) { @@ -1627,7 +1627,7 @@ ComparatorNumericLeftMinusRight(const NumericElement &a, const NumericElement &b return true; } -bool +static bool ComparatorNumericRightMinusLeft(const NumericElement &a, const NumericElement &b, bool *lessOrEqualp) { @@ -1645,14 +1645,14 @@ ComparatorNumeric SortComparatorNumerics[] = { ComparatorNumericRightMinusLeft }; -bool +static bool ComparatorInt32LeftMinusRight(const Value &a, const Value &b, bool *lessOrEqualp) { *lessOrEqualp = (a.toInt32() <= b.toInt32()); return true; } -bool +static bool ComparatorInt32RightMinusLeft(const Value &a, const Value &b, bool *lessOrEqualp) { *lessOrEqualp = (b.toInt32() <= a.toInt32()); @@ -1677,11 +1677,13 @@ enum ComparatorMatchResult { Match_RightMinusLeft }; +} /* namespace anonymous */ + /* * Specialize behavior for comparator functions with particular common bytecode * patterns: namely, |return x - y| and |return y - x|. */ -ComparatorMatchResult +static ComparatorMatchResult MatchNumericComparator(JSContext *cx, const Value &v) { if (!v.isObject()) @@ -1779,7 +1781,7 @@ MergeSortByKey(K keys, size_t len, K scratch, C comparator, AutoValueVector *vec * To minimize #conversions, SortLexicographically() first converts all Values * to strings at once, then sorts the elements by these cached strings. */ -bool +static bool SortLexicographically(JSContext *cx, AutoValueVector *vec, size_t len) { JS_ASSERT(vec->length() >= len); @@ -1819,7 +1821,7 @@ SortLexicographically(JSContext *cx, AutoValueVector *vec, size_t len) * To minimize #conversions, SortNumerically first converts all Values to * numerics at once, then sorts the elements by these cached numerics. */ -bool +static bool SortNumerically(JSContext *cx, AutoValueVector *vec, size_t len, ComparatorMatchResult comp) { JS_ASSERT(vec->length() >= len); @@ -1851,8 +1853,6 @@ SortNumerically(JSContext *cx, AutoValueVector *vec, size_t len, ComparatorMatch SortComparatorNumerics[comp], vec); } -} /* namespace anonymous */ - bool js::array_sort(JSContext *cx, unsigned argc, Value *vp) { diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index c25a0dc2a14..3bb49070f00 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -368,7 +368,7 @@ WeakMapPostWriteBarrier(JSRuntime *rt, ObjectValueMap *weakMap, JSObject *key) #endif } -MOZ_ALWAYS_INLINE bool +static MOZ_ALWAYS_INLINE bool SetWeakMapEntryInternal(JSContext *cx, Handle mapObj, HandleObject key, HandleValue value) { From e9506a4b875666ac8278e514d1450ee7df72a997 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 12:20:42 -0700 Subject: [PATCH 20/86] Bug 1054334 - SpiderMonkey: Constify some static variables r=nbp --- js/src/asmjs/AsmJSValidate.cpp | 6 +++--- js/src/builtin/TypedObject.cpp | 4 ++-- js/src/jsarray.cpp | 4 ++-- js/src/jsproxy.cpp | 2 +- js/src/shell/js.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 4cb1341ffa5..679541e76f2 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -6129,9 +6129,9 @@ GenerateFFIInterpExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &e JS_ASSERT(masm.framePushed() == 0); // Argument types for InvokeFromAsmJS_*: - MIRType typeArray[] = { MIRType_Pointer, // exitDatum - MIRType_Int32, // argc - MIRType_Pointer }; // argv + static const MIRType typeArray[] = { MIRType_Pointer, // exitDatum + MIRType_Int32, // argc + MIRType_Pointer }; // argv MIRTypeVector invokeArgTypes(m.cx()); invokeArgTypes.infallibleAppend(typeArray, ArrayLength(typeArray)); diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 412cbebf99f..fcd82f7d871 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -348,7 +348,7 @@ const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = { JS_FS_END }; -static int32_t ReferenceSizes[] = { +static const int32_t ReferenceSizes[] = { #define REFERENCE_SIZE(_kind, _type, _name) \ sizeof(_type), JS_FOR_EACH_REFERENCE_TYPE_REPR(REFERENCE_SIZE) 0 @@ -427,7 +427,7 @@ js::ReferenceTypeDescr::call(JSContext *cx, unsigned argc, Value *vp) * Note: these are partially defined in SIMD.cpp */ -static int32_t X4Sizes[] = { +static const int32_t X4Sizes[] = { #define X4_SIZE(_kind, _type, _name) \ sizeof(_type) * 4, JS_FOR_EACH_X4_TYPE_REPR(X4_SIZE) 0 diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index be89385e01f..1ffbe4840fe 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1638,7 +1638,7 @@ ComparatorNumericRightMinusLeft(const NumericElement &a, const NumericElement &b typedef bool (*ComparatorNumeric)(const NumericElement &a, const NumericElement &b, bool *lessOrEqualp); -ComparatorNumeric SortComparatorNumerics[] = { +static const ComparatorNumeric SortComparatorNumerics[] = { nullptr, nullptr, ComparatorNumericLeftMinusRight, @@ -1661,7 +1661,7 @@ ComparatorInt32RightMinusLeft(const Value &a, const Value &b, bool *lessOrEqualp typedef bool (*ComparatorInt32)(const Value &a, const Value &b, bool *lessOrEqualp); -ComparatorInt32 SortComparatorInt32s[] = { +static const ComparatorInt32 SortComparatorInt32s[] = { nullptr, nullptr, ComparatorInt32LeftMinusRight, diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index a944fa632a0..360a9daea05 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -796,7 +796,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler * eventually moving towards eliminating one of those slots, and so we don't * want to add a dependency here. */ -static Class CallConstructHolder = { +static const Class CallConstructHolder = { "CallConstructHolder", JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS }; diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index cc2121822c7..c8e74f991ef 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5096,7 +5096,7 @@ static const JSClass env_class = { * setter and method with attached JitInfo. This object can be used to test * IonMonkey DOM optimizations in the shell. */ -static uint32_t DOM_OBJECT_SLOT = 0; +static const uint32_t DOM_OBJECT_SLOT = 0; static bool dom_genericGetter(JSContext* cx, unsigned argc, JS::Value *vp); @@ -5554,7 +5554,7 @@ ShellBuildId(JS::BuildIdCharVector *buildId) return buildId->append(buildid, sizeof(buildid)); } -static JS::AsmJSCacheOps asmJSCacheOps = { +static const JS::AsmJSCacheOps asmJSCacheOps = { ShellOpenAsmJSCacheEntryForRead, ShellCloseAsmJSCacheEntryForRead, ShellOpenAsmJSCacheEntryForWrite, From 875b3dcb017d42e63c3daea4a1277327fb45c0fe Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 18 Aug 2014 12:20:42 -0700 Subject: [PATCH 21/86] Bug 1054334 - Constify xpconnect's gNoString r=nbp --- js/xpconnect/src/XPCJSID.cpp | 8 +++++--- js/xpconnect/src/xpcprivate.h | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index 6f1e65eceed..fb5a412efc7 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -21,10 +21,12 @@ using namespace JS; NS_IMPL_CLASSINFO(nsJSID, nullptr, 0, NS_JS_ID_CID) NS_IMPL_ISUPPORTS_CI(nsJSID, nsIJSID) -char nsJSID::gNoString[] = ""; +const char nsJSID::gNoString[] = ""; nsJSID::nsJSID() - : mID(GetInvalidIID()), mNumber(gNoString), mName(gNoString) + : mID(GetInvalidIID()), + mNumber(const_cast(gNoString)), + mName(const_cast(gNoString)) { } @@ -78,7 +80,7 @@ nsJSID::GetNumber(char * *aNumber) if (!mNumber) { if (!(mNumber = mID.ToString())) - mNumber = gNoString; + mNumber = const_cast(gNoString); } *aNumber = NS_strdup(mNumber); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 684f6a555b7..e43a1666650 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -2743,7 +2743,7 @@ public: bool InitWithName(const nsID& id, const char *nameString); bool SetName(const char* name); void SetNameToNoString() - {MOZ_ASSERT(!mName, "name already set"); mName = gNoString;} + {MOZ_ASSERT(!mName, "name already set"); mName = const_cast(gNoString);} bool NameIsSet() const {return nullptr != mName;} const nsID& ID() const {return mID;} bool IsValid() const {return !mID.Equals(GetInvalidIID());} @@ -2758,7 +2758,7 @@ public: protected: virtual ~nsJSID(); - static char gNoString[]; + static const char gNoString[]; nsID mID; char* mNumber; char* mName; From efb0f403d1d000dfc08dc291a30fe5e79f5fc595 Mon Sep 17 00:00:00 2001 From: Hannes Verschore Date: Mon, 18 Aug 2014 21:37:10 +0200 Subject: [PATCH 22/86] Bug 1054512: IonMonkey: Run the type policy of added instructions during type analysis, r=jandem --- js/src/jit-test/tests/ion/bug1054512.js | 11 +++ js/src/jit/MIR.h | 16 +++- js/src/jit/TypePolicy.cpp | 105 +++++++----------------- js/src/jit/arm/Lowering-arm.cpp | 1 + js/src/jit/mips/Lowering-mips.cpp | 1 + js/src/jit/x64/Lowering-x64.cpp | 2 + js/src/jit/x86/Lowering-x86.cpp | 1 + 7 files changed, 58 insertions(+), 79 deletions(-) create mode 100644 js/src/jit-test/tests/ion/bug1054512.js diff --git a/js/src/jit-test/tests/ion/bug1054512.js b/js/src/jit-test/tests/ion/bug1054512.js new file mode 100644 index 00000000000..4da554dc643 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1054512.js @@ -0,0 +1,11 @@ +function f(x) { + x((x | 0) + x); +}; +try { + f(1); +} catch (e) {} +for (var k = 0; k < 1; ++k) { + try { + f(Symbol()); + } catch (e) {} +} diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 8a729e6cc1a..bf496e347bf 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3112,7 +3112,11 @@ class MUnbox : public MUnaryInstruction, public BoxInputsPolicy : MUnaryInstruction(ins), mode_(mode) { - JS_ASSERT(ins->type() == MIRType_Value); + // Only allow unboxing a non MIRType_Value when input and output types + // don't match. This is often used to force a bailout. Boxing happens + // during type analysis. + JS_ASSERT_IF(ins->type() != MIRType_Value, type != ins->type()); + JS_ASSERT(type == MIRType_Boolean || type == MIRType_Int32 || type == MIRType_Double || @@ -3839,7 +3843,9 @@ class MToInt32 // Converts a value or typed input to a truncated int32, for use with bitwise // operations. This is an infallible ValueToECMAInt32. -class MTruncateToInt32 : public MUnaryInstruction +class MTruncateToInt32 + : public MUnaryInstruction, + public ToInt32Policy { explicit MTruncateToInt32(MDefinition *def) : MUnaryInstruction(def) @@ -3850,7 +3856,6 @@ class MTruncateToInt32 : public MUnaryInstruction // An object might have "valueOf", which means it is effectful. // ToInt32(symbol) throws. MOZ_ASSERT(def->type() != MIRType_Object); - MOZ_ASSERT(def->type() != MIRType_Symbol); if (def->mightBeType(MIRType_Object) || def->mightBeType(MIRType_Symbol)) setGuard(); } @@ -3881,6 +3886,10 @@ class MTruncateToInt32 : public MUnaryInstruction } #endif + TypePolicy *typePolicy() { + return this; + } + ALLOW_CLONE(MTruncateToInt32) }; @@ -6100,6 +6109,7 @@ class MStringReplace bool congruentTo(const MDefinition *ins) const { return congruentIfOperandsEqual(ins); } + AliasSet getAliasSet() const { return AliasSet::None(); } diff --git a/js/src/jit/TypePolicy.cpp b/js/src/jit/TypePolicy.cpp index 474aa3c43bc..b9a2cf0c3ab 100644 --- a/js/src/jit/TypePolicy.cpp +++ b/js/src/jit/TypePolicy.cpp @@ -76,15 +76,6 @@ ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) MInstruction *replace; - // If the input is a string or object, the conversion is not - // possible--at least, we can't specialize. So box the input. - if (in->type() == MIRType_Object || - in->type() == MIRType_String || - (in->type() == MIRType_Undefined && specialization_ == MIRType_Int32)) - { - in = boxAt(alloc, ins, in); - } - if (ins->type() == MIRType_Double) replace = MToDouble::New(alloc, in); else if (ins->type() == MIRType_Float32) @@ -94,6 +85,9 @@ ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) ins->block()->insertBefore(ins, replace); ins->replaceOperand(i, replace); + + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; } return true; @@ -194,13 +188,6 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def) MInstruction *replace; - // See ArithPolicy::adjustInputs for an explanation of the following. - if (in->type() == MIRType_Object || in->type() == MIRType_String || - in->type() == MIRType_Undefined) - { - in = boxAt(alloc, def, in); - } - switch (type) { case MIRType_Double: { MToDouble::ConversionKind convert = MToDouble::NumbersOnly; @@ -265,6 +252,9 @@ ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def) def->block()->insertBefore(def, replace); def->replaceOperand(i, replace); + + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; } return true; @@ -362,17 +352,12 @@ BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) if (in->type() == MIRType_Int32) continue; - // See ArithPolicy::adjustInputs for an explanation of the following. - // MTruncateToInt32 in particular does not support MIRType_Symbol input. - if (in->type() == MIRType_Object || in->type() == MIRType_String || - in->type() == MIRType_Symbol) - { - in = boxAt(alloc, ins, in); - } - MInstruction *replace = MTruncateToInt32::New(alloc, in); ins->block()->insertBefore(ins, replace); ins->replaceOperand(i, replace); + + if (!replace->typePolicy()->adjustInputs(alloc, replace)) + return false; } return true; @@ -467,7 +452,8 @@ ConvertToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction MToInt32 *replace = MToInt32::New(alloc, in); def->block()->insertBefore(def, replace); def->replaceOperand(Op, replace); - return true; + + return replace->typePolicy()->adjustInputs(alloc, replace); } template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); @@ -480,25 +466,11 @@ DoublePolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) if (in->type() == MIRType_Double) return true; - // Force a bailout. Objects may be effectful; strings and symbols are - // currently unhandled. - if (in->type() == MIRType_Object || - in->type() == MIRType_String || - in->type() == MIRType_Symbol) - { - MBox *box = MBox::New(alloc, in); - def->block()->insertBefore(def, box); - - MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible); - def->block()->insertBefore(def, unbox); - def->replaceOperand(Op, unbox); - return true; - } - MToDouble *replace = MToDouble::New(alloc, in); def->block()->insertBefore(def, replace); def->replaceOperand(Op, replace); - return true; + + return replace->typePolicy()->adjustInputs(alloc, replace); } template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); @@ -512,32 +484,11 @@ Float32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *def) if (in->type() == MIRType_Float32) return true; - // Force a bailout. Objects may be effectful; strings and symbols are - // currently unhandled. - if (in->type() == MIRType_Object || - in->type() == MIRType_String || - in->type() == MIRType_Symbol) - { - MToDouble *toDouble = MToDouble::New(alloc, in); - def->block()->insertBefore(def, toDouble); - - MBox *box = MBox::New(alloc, toDouble); - def->block()->insertBefore(def, box); - - MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible); - def->block()->insertBefore(def, unbox); - - MToFloat32 *toFloat32 = MToFloat32::New(alloc, unbox); - def->block()->insertBefore(def, toFloat32); - - def->replaceOperand(Op, unbox); - return true; - } - MToFloat32 *replace = MToFloat32::New(alloc, in); def->block()->insertBefore(def, replace); def->replaceOperand(Op, replace); - return true; + + return replace->typePolicy()->adjustInputs(alloc, replace); } template bool Float32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def); @@ -609,18 +560,24 @@ ToDoublePolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) bool ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) { - JS_ASSERT(ins->isToInt32()); + JS_ASSERT(ins->isToInt32() || ins->isTruncateToInt32()); MDefinition *in = ins->getOperand(0); switch (in->type()) { case MIRType_Object: case MIRType_String: case MIRType_Symbol: - case MIRType_Undefined: - // Objects might be effectful. Undefined and symbols coerce to NaN, not int32. + // Objects might be effectful. Symbols give TypeError. in = boxAt(alloc, ins, in); ins->replaceOperand(0, in); break; + case MIRType_Undefined: + // Undefined coerce to NaN, not int32, when not truncated. + if (ins->isToInt32()) { + in = boxAt(alloc, ins, in); + ins->replaceOperand(0, in); + } + break; default: break; } @@ -656,13 +613,11 @@ ObjectPolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins) return true; } - if (in->type() != MIRType_Value) - in = boxAt(alloc, ins, in); - MUnbox *replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Fallible); ins->block()->insertBefore(ins, replace); ins->replaceOperand(Op, replace); - return true; + + return replace->typePolicy()->adjustInputs(alloc, replace); } template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins); @@ -677,14 +632,12 @@ CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins) MDefinition *func = call->getFunction(); if (func->type() != MIRType_Object) { - // If the function is impossible to call, - // bail out by causing a subsequent unbox to fail. - if (func->type() != MIRType_Value) - func = boxAt(alloc, call, func); - MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible); call->block()->insertBefore(call, unbox); call->replaceFunction(unbox); + + if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) + return false; } for (uint32_t i = 0; i < call->numStackArgs(); i++) diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index a5d6ab16464..15bd4a96193 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -126,6 +126,7 @@ LIRGeneratorARM::visitUnbox(MUnbox *unbox) // a payload. Unlike most instructions conusming a box, we ask for the type // second, so that the result can re-use the first input. MDefinition *inner = unbox->getOperand(0); + JS_ASSERT(inner->type() == MIRType_Value); if (!ensureDefined(inner)) return false; diff --git a/js/src/jit/mips/Lowering-mips.cpp b/js/src/jit/mips/Lowering-mips.cpp index 8912c576507..a0af79066d2 100644 --- a/js/src/jit/mips/Lowering-mips.cpp +++ b/js/src/jit/mips/Lowering-mips.cpp @@ -128,6 +128,7 @@ LIRGeneratorMIPS::visitUnbox(MUnbox *unbox) // a payload. Unlike most instructions consuming a box, we ask for the type // second, so that the result can re-use the first input. MDefinition *inner = unbox->getOperand(0); + JS_ASSERT(inner->type() == MIRType_Value); if (!ensureDefined(inner)) return false; diff --git a/js/src/jit/x64/Lowering-x64.cpp b/js/src/jit/x64/Lowering-x64.cpp index d99ba94c434..a6478ae7200 100644 --- a/js/src/jit/x64/Lowering-x64.cpp +++ b/js/src/jit/x64/Lowering-x64.cpp @@ -75,6 +75,8 @@ bool LIRGeneratorX64::visitUnbox(MUnbox *unbox) { MDefinition *box = unbox->getOperand(0); + JS_ASSERT(box->type() == MIRType_Value); + LUnboxBase *lir; if (IsFloatingPointType(unbox->type())) lir = new(alloc()) LUnboxFloatingPoint(useRegisterAtStart(box), unbox->type()); diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp index 05f948770f3..af38b4b79d9 100644 --- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -119,6 +119,7 @@ LIRGeneratorX86::visitUnbox(MUnbox *unbox) // a payload. Unlike most instructions conusming a box, we ask for the type // second, so that the result can re-use the first input. MDefinition *inner = unbox->getOperand(0); + JS_ASSERT(inner->type() == MIRType_Value); if (!ensureDefined(inner)) return false; From a9cf36a728ddf971c71e47b0f8b9a238eb55794f Mon Sep 17 00:00:00 2001 From: William Lachance Date: Mon, 18 Aug 2014 16:00:07 -0400 Subject: [PATCH 23/86] Bug 1055188 - Bump mozdevice to 0.40;r=bc DONTBUILD NPOTB --- testing/mozbase/mozdevice/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mozbase/mozdevice/setup.py b/testing/mozbase/mozdevice/setup.py index e4da3787057..9be81ac4d69 100644 --- a/testing/mozbase/mozdevice/setup.py +++ b/testing/mozbase/mozdevice/setup.py @@ -5,7 +5,7 @@ from setuptools import setup PACKAGE_NAME = 'mozdevice' -PACKAGE_VERSION = '0.39' +PACKAGE_VERSION = '0.40' deps = ['mozfile >= 1.0', 'mozlog >= 2.1', From a308375588a016ead52dc7f4b3c7127c8e928538 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Thu, 14 Aug 2014 11:46:21 -0400 Subject: [PATCH 24/86] Bug 1052751 - Part 1: Cull translated layers on the compositor. r=roc --- .../composite/ContainerLayerComposite.cpp | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index 5ef409df39d..cd418c0fa2c 100644 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -34,6 +34,9 @@ #include "TextRenderer.h" // for TextRenderer #include +#define CULLING_LOG(...) +// #define CULLING_LOG(...) printf_stderr("CULLING: " __VA_ARGS__) + namespace mozilla { namespace layers { @@ -52,6 +55,8 @@ GetOpaqueRect(Layer* aLayer) // Just bail if there's anything difficult to handle. if (!is2D || aLayer->GetMaskLayer() || + aLayer->GetIsFixedPosition() || + aLayer->GetIsStickyPosition() || aLayer->GetEffectiveOpacity() != 1.0f || matrix.HasNonIntegerTranslation()) { return result; @@ -321,16 +326,26 @@ ContainerPrepare(ContainerT* aContainer, continue; } + CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer()); + nsIntRegion savedVisibleRegion; bool restoreVisibleRegion = false; + gfx::Matrix matrix; + bool is2D = layerToRender->GetLayer()->GetBaseTransform().Is2D(&matrix); if (i + 1 < children.Length() && - layerToRender->GetLayer()->GetEffectiveTransform().IsIdentity()) { + is2D && !matrix.HasNonIntegerTranslation()) { LayerComposite* nextLayer = static_cast(children.ElementAt(i + 1)->ImplData()); + CULLING_LOG("Culling against %p\n", nextLayer->GetLayer()); nsIntRect nextLayerOpaqueRect; if (nextLayer && nextLayer->GetLayer()) { nextLayerOpaqueRect = GetOpaqueRect(nextLayer->GetLayer()); + gfx::Point point = matrix.GetTranslation(); + nextLayerOpaqueRect.MoveBy(static_cast(-point.x), static_cast(-point.y)); + CULLING_LOG(" point %i, %i\n", static_cast(-point.x), static_cast(-point.y)); + CULLING_LOG(" opaque rect %i, %i, %i, %i\n", nextLayerOpaqueRect.x, nextLayerOpaqueRect.y, nextLayerOpaqueRect.width, nextLayerOpaqueRect.height); } if (!nextLayerOpaqueRect.IsEmpty()) { + CULLING_LOG(" draw\n"); savedVisibleRegion = layerToRender->GetShadowVisibleRegion(); nsIntRegion visibleRegion; visibleRegion.Sub(savedVisibleRegion, nextLayerOpaqueRect); @@ -339,12 +354,16 @@ ContainerPrepare(ContainerT* aContainer, } layerToRender->SetShadowVisibleRegion(visibleRegion); restoreVisibleRegion = true; + } else { + CULLING_LOG(" skip\n"); } } layerToRender->Prepare(clipRect); aContainer->mPrepared->mLayers.AppendElement(PreparedLayer(layerToRender, clipRect, restoreVisibleRegion, savedVisibleRegion)); } + CULLING_LOG("Preparing container layer %p\n", aContainer->GetLayer()); + /** * Setup our temporary surface for rendering the contents of this container. */ From 0ee11797a951b6835a3d661ab46d7d21e7092f0f Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Mon, 18 Aug 2014 12:50:23 -0800 Subject: [PATCH 25/86] Bug 1033946 - Fix treatment of unicode chars with ascii lower/upper case versions in case insensitive regexp matching, r=jandem. --- js/src/irregexp/RegExpEngine.cpp | 51 ++++++++++++-------- js/src/jit-test/tests/basic/bug1033946.js | 3 ++ js/src/tests/js1_5/Regress/regress-440926.js | 9 +--- 3 files changed, 37 insertions(+), 26 deletions(-) create mode 100644 js/src/jit-test/tests/basic/bug1033946.js diff --git a/js/src/irregexp/RegExpEngine.cpp b/js/src/irregexp/RegExpEngine.cpp index 2f0af8dce44..d413439d964 100644 --- a/js/src/irregexp/RegExpEngine.cpp +++ b/js/src/irregexp/RegExpEngine.cpp @@ -186,35 +186,48 @@ RangesContainLatin1Equivalents(const CharacterRangeVector &ranges) static const size_t kEcma262UnCanonicalizeMaxWidth = 4; // Returns the number of characters in the equivalence class, omitting those -// that cannot occur in the source string because it is ASCII. +// that cannot occur in the source string if it is a one byte string. static int GetCaseIndependentLetters(jschar character, bool ascii_subject, jschar *letters) { - jschar lower = unicode::ToLowerCase(character); - jschar upper = unicode::ToUpperCase(character); + jschar choices[] = { + character, + unicode::ToLowerCase(character), + unicode::ToUpperCase(character) + }; - // The standard requires that non-ASCII characters cannot have ASCII - // character codes in their equivalence class. - if (ascii_subject && character > kMaxOneByteCharCode) - return 0; + size_t count = 0; + for (size_t i = 0; i < ArrayLength(choices); i++) { + jschar c = choices[i]; - letters[0] = character; + // The standard requires that non-ASCII characters cannot have ASCII + // character codes in their equivalence class, even though this + // situation occurs multiple times in the unicode tables. + static const unsigned kMaxAsciiCharCode = 127; + if (character > kMaxAsciiCharCode && c <= kMaxAsciiCharCode) + continue; - if (lower != character) { - letters[1] = lower; - if (upper != character && upper != lower) { - letters[2] = upper; - return 3; + // Skip characters that can't appear in one byte strings. + if (ascii_subject && c > kMaxOneByteCharCode) + continue; + + // Watch for duplicates. + bool found = false; + for (size_t j = 0; j < count; j++) { + if (letters[j] == c) { + found = true; + break; + } } - return 2; + if (found) + continue; + + letters[count++] = c; } - if (upper != character) { - letters[1] = upper; - return 2; - } - return 1; + + return count; } static jschar diff --git a/js/src/jit-test/tests/basic/bug1033946.js b/js/src/jit-test/tests/basic/bug1033946.js new file mode 100644 index 00000000000..a9dda468cbd --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1033946.js @@ -0,0 +1,3 @@ + +assertEq((/(?!(?!(?!6)[\Wc]))/i).test(), false); +assertEq("foobar\xff5baz\u1200".search(/bar\u0178\d/i), 3); diff --git a/js/src/tests/js1_5/Regress/regress-440926.js b/js/src/tests/js1_5/Regress/regress-440926.js index 795a6dc7280..ebd90e7b7d3 100644 --- a/js/src/tests/js1_5/Regress/regress-440926.js +++ b/js/src/tests/js1_5/Regress/regress-440926.js @@ -7,8 +7,7 @@ var BUGNUMBER = 440926; var summary = 'Correctly match regexps with special "i" characters'; var actual = ''; -var expect0 = '#I#,#I#;#I#,#I#'; -var expect1 = 'iI#,iI#;iI#,iI#'; +var expect = 'iI#,iI#;iI#,iI#'; //----------------------------------------------------------------------------- test(); @@ -28,11 +27,7 @@ function test() actual += ',' + 'iI\u0130'.replace(/\u0130/gi, '#'); jit(false); - // The result we get depends on the regexp engine in use. - if (actual == expect0) - reportCompare(expect0, actual, summary); - else - reportCompare(expect1, actual, summary); + reportCompare(expect, actual, summary); exitFunc ('test'); } From 4ecc0e4ae13d760b5086ce5726fae7dbd9106583 Mon Sep 17 00:00:00 2001 From: josullivan Date: Fri, 15 Aug 2014 17:25:06 -0700 Subject: [PATCH 26/86] Bug 820391: Use DnsQuery on Windows. r=sworkman From 21e22e494541d5e4c085a6ba84e1bc5b4c92330e Mon Sep 17 00:00:00 2001 --- netwerk/dns/DNS.cpp | 65 +++++++- netwerk/dns/DNS.h | 6 + netwerk/dns/GetAddrInfo.cpp | 362 +++++++++++++++++++++++++++++++++++++++++ netwerk/dns/GetAddrInfo.h | 65 ++++++++ netwerk/dns/moz.build | 1 + netwerk/dns/nsHostResolver.cpp | 320 ++++++++++++++++++++++++++---------- netwerk/dns/nsHostResolver.h | 43 ++++- 7 files changed, 766 insertions(+), 96 deletions(-) create mode 100644 netwerk/dns/GetAddrInfo.cpp create mode 100644 netwerk/dns/GetAddrInfo.h --- netwerk/dns/DNS.cpp | 65 +++++- netwerk/dns/DNS.h | 6 + netwerk/dns/GetAddrInfo.cpp | 362 +++++++++++++++++++++++++++++++++ netwerk/dns/GetAddrInfo.h | 65 ++++++ netwerk/dns/moz.build | 1 + netwerk/dns/nsHostResolver.cpp | 322 +++++++++++++++++++++-------- netwerk/dns/nsHostResolver.h | 43 +++- 7 files changed, 767 insertions(+), 97 deletions(-) create mode 100644 netwerk/dns/GetAddrInfo.cpp create mode 100644 netwerk/dns/GetAddrInfo.h diff --git a/netwerk/dns/DNS.cpp b/netwerk/dns/DNS.cpp index a2aaa534de2..c3b6efdd750 100644 --- a/netwerk/dns/DNS.cpp +++ b/netwerk/dns/DNS.cpp @@ -255,6 +255,11 @@ NetAddrElement::NetAddrElement(const NetAddrElement& netAddr) mAddress = netAddr.mAddress; } +NetAddrElement::NetAddrElement(const NetAddr& aNetAddr) +{ + mAddress = aNetAddr; +} + NetAddrElement::~NetAddrElement() { } @@ -291,6 +296,21 @@ AddrInfo::~AddrInfo() moz_free(mCanonicalName); } +void +AddrInfo::SetCanonicalName(const char* cname) +{ + if (mCanonicalName) { + moz_free(mCanonicalName); + mCanonicalName = nullptr; + } + + if (cname) { + size_t cnameLen = strlen(cname); + mCanonicalName = static_cast(moz_xmalloc(cnameLen + 1)); + memcpy(mCanonicalName, cname, cnameLen + 1); + } +} + void AddrInfo::Init(const char *host, const char *cname) { @@ -299,14 +319,9 @@ AddrInfo::Init(const char *host, const char *cname) size_t hostlen = strlen(host); mHostName = static_cast(moz_xmalloc(hostlen + 1)); memcpy(mHostName, host, hostlen + 1); - if (cname) { - size_t cnameLen = strlen(cname); - mCanonicalName = static_cast(moz_xmalloc(cnameLen + 1)); - memcpy(mCanonicalName, cname, cnameLen + 1); - } - else { - mCanonicalName = nullptr; - } + + mCanonicalName = nullptr; + SetCanonicalName(cname); } void @@ -327,5 +342,39 @@ AddrInfo::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const return n; } +void +AddrInfo::MergeAndConsume(AddrInfo* aOther, uint16_t aAddressFamily) { + // Remove all of the addresses of the resolved type + NetAddrElement* iter = mAddresses.getFirst(); + while (iter) { + NetAddrElement* next = iter->getNext(); + + if (iter->mAddress.raw.family == aAddressFamily) { + iter->removeFrom(mAddresses); + delete iter; + } + + iter = next; + } + + // Add in the new results + if (aOther) { + iter = aOther->mAddresses.getFirst(); + while (iter) { + NetAddrElement* next = iter->getNext(); + + // Move it from one linked list to the aOther + iter->removeFrom(aOther->mAddresses); + mAddresses.insertBack(iter); + + iter = next; + } + + if (aOther->mCanonicalName && strlen(aOther->mCanonicalName)) { + SetCanonicalName(aOther->mCanonicalName); + } + } +} + } // namespace dns } // namespace mozilla diff --git a/netwerk/dns/DNS.h b/netwerk/dns/DNS.h index e3beaf5646b..6f464fae825 100644 --- a/netwerk/dns/DNS.h +++ b/netwerk/dns/DNS.h @@ -120,6 +120,7 @@ class NetAddrElement : public LinkedListElement { public: explicit NetAddrElement(const PRNetAddr *prNetAddr); NetAddrElement(const NetAddrElement& netAddr); + NetAddrElement(const NetAddr& aNetAddr); ~NetAddrElement(); NetAddr mAddress; @@ -137,6 +138,7 @@ public: ~AddrInfo(); void AddAddress(NetAddrElement *address); + void SetCanonicalName(const char* cname); size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; @@ -144,6 +146,10 @@ public: char *mCanonicalName; LinkedList mAddresses; + // Removes every address of addressFamily, then takes every address in other + // as well as copying its canonicalName if it has one. other may be null. + void MergeAndConsume(AddrInfo* aOther, uint16_t aAddressFamily); + private: void Init(const char *host, const char *cname); }; diff --git a/netwerk/dns/GetAddrInfo.cpp b/netwerk/dns/GetAddrInfo.cpp new file mode 100644 index 00000000000..f846426f66d --- /dev/null +++ b/netwerk/dns/GetAddrInfo.cpp @@ -0,0 +1,362 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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/. */ + +#if defined(MOZ_LOGGING) +#define FORCE_PR_LOG +#endif + +#include "GetAddrInfo.h" +#include "mozilla/net/DNS.h" +#include "prnetdb.h" +#include "nsHostResolver.h" +#include "nsError.h" +#include "mozilla/Mutex.h" +#include "nsAutoPtr.h" +#include "mozilla/StaticPtr.h" +#include "MainThreadUtils.h" +#include "mozilla/DebugOnly.h" + +#include "prlog.h" +#if defined(PR_LOGGING) +static PRLogModuleInfo *gGetAddrInfoLog = PR_NewLogModule("GetAddrInfo"); +#define LOG(msg, ...) \ + PR_LOG(gGetAddrInfoLog, PR_LOG_DEBUG, ("[DNS]: " msg, ##__VA_ARGS__)) +#define LOG_WARNING(msg, ...) \ + PR_LOG(gGetAddrInfoLog, PR_LOG_WARNING, ("[DNS]: " msg, ##__VA_ARGS__)) +#else +#define LOG(args) +#define LOG_WARNING(args) +#endif + +#if DNS_API == DNS_API_WINDOWS_DNS_QUERY +// There is a bug in Windns.h where the type of parameter ppQueryResultsSet for +// DnsQuery_A is dependent on UNICODE being set. It should *always* be +// PDNS_RECORDA, but if UNICODE is set it is PDNS_RECORDW. To get around this +// we make sure that UNICODE is unset. +#undef UNICODE +#include "Windns.h" +#endif + +namespace mozilla { +namespace net { + +#if DNS_API == DNS_API_WINDOWS_DNS_QUERY +//////////////////////////// +// WINDOWS IMPLEMENTATION // +//////////////////////////// + +// Ensure consistency of PR_* and AF_* constants to allow for legacy usage of +// PR_* constants with this API. +static_assert(PR_AF_INET == AF_INET && PR_AF_INET6 == AF_INET6 + && PR_AF_UNSPEC == AF_UNSPEC, "PR_AF_* must match AF_*"); + +// We intentionally leak this mutex. This is because we can run into a +// situation where the worker threads are still running until the process +// is actually fully shut down, and at any time one of those worker +// threads can access gDnsapiInfoLock. +static OffTheBooksMutex* gDnsapiInfoLock = nullptr; + +struct DnsapiInfo +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DnsapiInfo); + + HMODULE mLibrary; + decltype(&DnsQuery_A) mDnsQueryFunc; + decltype(&DnsFree) mDnsFreeFunc; + +private: + // This will either be called during shutdown of the GetAddrInfo module, or + // when a worker thread is done doing a lookup (ie: within + // _GetAddrInfo_Windows). Note that the lock must be held when this is + // called. + ~DnsapiInfo() + { + if (gDnsapiInfoLock) { + gDnsapiInfoLock->AssertCurrentThreadOwns(); + } else { + MOZ_ASSERT_UNREACHABLE("No mutex available during GetAddrInfo shutdown."); + } + + LOG("Freeing Dnsapi.dll"); + MOZ_ASSERT(mLibrary); + DebugOnly rv = FreeLibrary(mLibrary); + NS_WARN_IF_FALSE(rv, "Failed to free Dnsapi.dll."); + } +}; + +static StaticRefPtr gDnsapiInfo; + +static MOZ_ALWAYS_INLINE nsresult +_GetAddrInfoInit_Windows() +{ + // This is necessary to ensure strict thread safety because if two threads + // run this function at the same time they can potentially create two + // mutexes. + MOZ_ASSERT(NS_IsMainThread(), + "Do not initialize GetAddrInfo off main thread!"); + + if (!gDnsapiInfoLock) { + gDnsapiInfoLock = new OffTheBooksMutex("GetAddrInfo.cpp::gDnsapiInfoLock"); + } + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + + if (gDnsapiInfo) { + MOZ_ASSERT_UNREACHABLE("GetAddrInfo is being initialized multiple times!"); + return NS_ERROR_ALREADY_INITIALIZED; + } + + HMODULE library = LoadLibraryA("Dnsapi.dll"); + if (NS_WARN_IF(!library)) { + return NS_ERROR_FAILURE; + } + + FARPROC dnsQueryFunc = GetProcAddress(library, "DnsQuery_A"); + FARPROC dnsFreeFunc = GetProcAddress(library, "DnsFree"); + if (NS_WARN_IF(!dnsQueryFunc) || NS_WARN_IF(!dnsFreeFunc)) { + DebugOnly rv = FreeLibrary(library); + NS_WARN_IF_FALSE(rv, "Failed to free Dnsapi.dll."); + return NS_ERROR_FAILURE; + } + + DnsapiInfo* info = new DnsapiInfo; + info->mLibrary = library; + info->mDnsQueryFunc = (decltype(info->mDnsQueryFunc)) dnsQueryFunc; + info->mDnsFreeFunc = (decltype(info->mDnsFreeFunc)) dnsFreeFunc; + gDnsapiInfo = info; + + return NS_OK; +} + +static MOZ_ALWAYS_INLINE nsresult +_GetAddrInfoShutdown_Windows() +{ + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + + if (NS_WARN_IF(!gDnsapiInfo) || NS_WARN_IF(!gDnsapiInfoLock)) { + MOZ_ASSERT_UNREACHABLE("GetAddrInfo not initialized!"); + return NS_ERROR_NOT_INITIALIZED; + } + + gDnsapiInfo = nullptr; + + return NS_OK; +} + +static MOZ_ALWAYS_INLINE nsresult +_GetAddrInfo_Windows(const char* aHost, uint16_t aAddressFamily, + uint16_t aFlags, AddrInfo** aAddrInfo) +{ + MOZ_ASSERT(aHost); + MOZ_ASSERT(aAddrInfo); + + nsRefPtr dnsapi = nullptr; + { + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + dnsapi = gDnsapiInfo; + } + + if (!dnsapi) { + LOG_WARNING("GetAddrInfo has been shutdown or has not been initialized."); + return NS_ERROR_NOT_INITIALIZED; + } + + WORD dns_type; + if (aAddressFamily == PR_AF_INET) { + dns_type = DNS_TYPE_A; + } else if (aAddressFamily == PR_AF_INET6) { + dns_type = DNS_TYPE_AAAA; + } else { + LOG_WARNING("Unsupported address family %X.\n", aAddressFamily); + MOZ_ASSERT_UNREACHABLE("Unsupported address family."); + return NS_ERROR_INVALID_ARG; + } + + PDNS_RECORDA dnsData = nullptr; + DNS_STATUS status = dnsapi->mDnsQueryFunc(aHost, dns_type, + DNS_QUERY_STANDARD, nullptr, &dnsData, nullptr); + if (status == DNS_INFO_NO_RECORDS || status == DNS_ERROR_RCODE_NAME_ERROR + || !dnsData) { + LOG("No DNS records found for %s.\n", aHost); + return NS_ERROR_UNKNOWN_HOST; + } else if (status != NOERROR) { + LOG_WARNING("DnsQuery_A failed with status %X.\n", status); + return NS_ERROR_FAILURE; + } + +#ifdef PR_LOGGING + int numARecords = 0; + int numAaaaRecords = 0; + int numCnameRecords = 0; + int numUnknownRecords = 0; + #define INCREMENT_IF_LOGGING(counter) ++counter +#else + #define INCREMENT_IF_LOGGING(counter) +#endif + + // Everything we need is now in dnsData. We just need to pull it out and put + // it into an AddrInfo object. + nsAutoPtr ai(new AddrInfo(aHost, nullptr)); + PDNS_RECORDA curRecord = dnsData; + while (curRecord) { + if (curRecord->wType == DNS_TYPE_A) { + INCREMENT_IF_LOGGING(numARecords); + + NetAddr addr; + addr.inet.family = AF_INET; + addr.inet.ip = curRecord->Data.A.IpAddress; + + // Initialize port to 0 to be filled in later at socket connection time + addr.inet.port = 0; + + ai->AddAddress(new NetAddrElement(addr)); + } else if (curRecord->wType == DNS_TYPE_AAAA) { + INCREMENT_IF_LOGGING(numAaaaRecords); + + NetAddr addr; + addr.inet6.family = AF_INET6; + memcpy(&addr.inet6.ip, &curRecord->Data.AAAA.Ip6Address, sizeof(addr.inet6.ip.u8)); + + // Initialize port to 0 to be filled in later at socket connection time + addr.inet6.port = 0; + + ai->AddAddress(new NetAddrElement(addr)); + } else if (curRecord->wType == DNS_TYPE_CNAME) { + INCREMENT_IF_LOGGING(numCnameRecords); + + char* cname = curRecord->Data.CNAME.pNameHost; + LOG("Got 'CNAME' %s for %s.\n", cname, aHost); + + ai->SetCanonicalName(cname); + } else { + INCREMENT_IF_LOGGING(numUnknownRecords); + + LOG("Ignoring record for %s of type %X.\n", aHost, curRecord->wType); + } + + curRecord = curRecord->pNext; + } + +#ifdef PR_LOGGING + LOG("Got %d 'A' records, %d 'AAAA' records, %d 'CNAME' records, and %d " + "unknown records for host %s.\n", numARecords, numAaaaRecords, + numCnameRecords, numUnknownRecords, aHost); +#endif + + dnsapi->mDnsFreeFunc(dnsData, DNS_FREE_TYPE::DnsFreeRecordList); + + { + // dnsapi's destructor is not thread-safe, so we release explicitly here + OffTheBooksMutexAutoLock lock(*gDnsapiInfoLock); + dnsapi = nullptr; + } + + if (ai->mAddresses.isEmpty()) { + return NS_ERROR_UNKNOWN_HOST; + } + + *aAddrInfo = ai.forget(); + return NS_OK; +} +#elif DNS_API == DNS_API_PORTABLE +//////////////////////////////////// +// PORTABLE RUNTIME IMPLEMENTATION// +//////////////////////////////////// + +static MOZ_ALWAYS_INLINE nsresult +_GetAddrInfo_Portable(const char* aHost, uint16_t aAddressFamily, + uint16_t aFlags, AddrInfo** aAddrInfo) +{ + MOZ_ASSERT(aHost); + MOZ_ASSERT(aAddrInfo); + + // We accept the same aFlags that nsHostResolver::ResolveHost accepts, but we + // need to translate the aFlags into a form that PR_GetAddrInfoByName + // accepts. + int prFlags = PR_AI_ADDRCONFIG; + if (!(aFlags & nsHostResolver::RES_CANON_NAME)) { + prFlags |= PR_AI_NOCANONNAME; + } + + // We need to remove IPv4 records manually because PR_GetAddrInfoByName + // doesn't support PR_AF_INET6. + bool disableIPv4 = aAddressFamily == PR_AF_INET6; + if (disableIPv4) { + aAddressFamily = PR_AF_UNSPEC; + } + + PRAddrInfo* prai = PR_GetAddrInfoByName(aHost, aAddressFamily, prFlags); + + if (!prai) { + return NS_ERROR_UNKNOWN_HOST; + } + + const char* canonName = nullptr; + if (aFlags & nsHostResolver::RES_CANON_NAME) { + canonName = PR_GetCanonNameFromAddrInfo(prai); + } + + nsAutoPtr ai(new AddrInfo(aHost, prai, disableIPv4, canonName)); + PR_FreeAddrInfo(prai); + if (ai->mAddresses.isEmpty()) { + return NS_ERROR_UNKNOWN_HOST; + } + + *aAddrInfo = ai.forget(); + + return NS_OK; +} +#endif + +////////////////////////////////////// +// COMMON/PLATFORM INDEPENDENT CODE // +////////////////////////////////////// +nsresult +GetAddrInfoInit() { + LOG("Initializing GetAddrInfo.\n"); + +#if DNS_API == DNS_API_WINDOWS_DNS_QUERY + return _GetAddrInfoInit_Windows(); +#else + return NS_OK; +#endif +} + +nsresult +GetAddrInfoShutdown() { + LOG("Shutting down GetAddrInfo.\n"); + +#if DNS_API == DNS_API_WINDOWS_DNS_QUERY + return _GetAddrInfoShutdown_Windows(); +#else + return NS_OK; +#endif +} + +nsresult +GetAddrInfo(const char* aHost, uint16_t aAddressFamily, uint16_t aFlags, + AddrInfo** aAddrInfo) +{ + if (NS_WARN_IF(!aHost) || NS_WARN_IF(!aAddrInfo)) { + return NS_ERROR_NULL_POINTER; + } + + *aAddrInfo = nullptr; + +#if DNS_API == DNS_API_WINDOWS_DNS_QUERY + return _GetAddrInfo_Windows(aHost, aAddressFamily, aFlags, aAddrInfo); +#elif DNS_API == DNS_API_PORTABLE + return _GetAddrInfo_Portable(aHost, aAddressFamily, aFlags, aAddrInfo); +#else + // This is merely to prevent programmer error in the future (setting the + // platform ID to something invalid on accident). _GetAddrInfo_Portable is + // defaulted to in the header file. + #error Unknown or unspecified DNS_API. +#endif +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/dns/GetAddrInfo.h b/netwerk/dns/GetAddrInfo.h new file mode 100644 index 00000000000..c9f65a6dc63 --- /dev/null +++ b/netwerk/dns/GetAddrInfo.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 netwerk_dns_GetAddrInfo_h +#define netwerk_dns_GetAddrInfo_h + +#include "nsError.h" + +#define DNS_API_PORTABLE (0) // Portable: PR_GetAddrInfoByName() +#define DNS_API_WINDOWS_DNS_QUERY (1) // Windows: DnsQuery() + +#ifdef XP_WIN +#define DNS_API DNS_API_WINDOWS_DNS_QUERY +#else +#define DNS_API DNS_API_PORTABLE +#endif + +namespace mozilla { +namespace net { + +class AddrInfo; + +/** + * Look up a host by name. Mostly equivalent to getaddrinfo(host, NULL, ...) of + * RFC 3493. + * + * @param hostname[in] Character string defining the host name of interest + * @param aAf[in] May be AF_INET, AF_INET6, or AF_UNSPEC. Note that AF_UNSPEC + * is not supported if DNS_API is DNS_API_WINDOWS_DNS_QUERY. + * @param aFlags[in] May be either PR_AI_ADDRCONFIG or + * PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME. Include PR_AI_NOCANONNAME to + * suppress the determination of the canonical name corresponding to + * hostname. + * @param aAddrInfo[out] Will point to the results of the host lookup, or be + * null if the lookup failed. + */ +nsresult +GetAddrInfo(const char* aHost, uint16_t aAf, uint16_t aFlags, AddrInfo** aAddrInfo); + +/** + * Initialize the GetAddrInfo module. + * + * GetAddrInfoShutdown() should be called for every time this function is + * called. + */ +nsresult +GetAddrInfoInit(); + +/** + * Shutdown the GetAddrInfo module. + * + * This function should be called for every time GetAddrInfoInit() is called. + * An assertion may throw (but is not guarenteed) if this function is called + * too many times. + */ +nsresult +GetAddrInfoShutdown(); + +} // namespace net +} // namespace mozilla + +#endif // netwerk_dns_GetAddrInfo_h diff --git a/netwerk/dns/moz.build b/netwerk/dns/moz.build index 0b0717a5a8c..a106daebdef 100644 --- a/netwerk/dns/moz.build +++ b/netwerk/dns/moz.build @@ -25,6 +25,7 @@ EXPORTS.mozilla.net += [ ] SOURCES += [ + 'GetAddrInfo.cpp', # Excluded from UNIFIED_SOURCES due to NSPR forced logging. 'nsEffectiveTLDService.cpp', # Excluded from UNIFIED_SOURCES due to special build flags. 'nsHostResolver.cpp', # Excluded from UNIFIED_SOURCES due to NSPR forced logging. ] diff --git a/netwerk/dns/nsHostResolver.cpp b/netwerk/dns/nsHostResolver.cpp index 1808fd1e335..c26882addca 100644 --- a/netwerk/dns/nsHostResolver.cpp +++ b/netwerk/dns/nsHostResolver.cpp @@ -10,7 +10,7 @@ #if defined(HAVE_RES_NINIT) #include #include -#include +#include #include #include #define RES_RETRY_ON_FAILURE @@ -19,6 +19,7 @@ #include #include "nsHostResolver.h" #include "nsError.h" +#include "GetAddrInfo.h" #include "nsISupportsBase.h" #include "nsISupportsUtils.h" #include "nsAutoPtr.h" @@ -35,6 +36,7 @@ #include "mozilla/TimeStamp.h" #include "mozilla/Telemetry.h" #include "mozilla/VisualEventTracer.h" +#include "mozilla/DebugOnly.h" using namespace mozilla; using namespace mozilla::net; @@ -166,6 +168,11 @@ nsHostRecord::nsHostRecord(const nsHostKey *key) , onQueue(false) , usingAnyThread(false) , mDoomed(false) +#if DO_MERGE_FOR_AF_UNSPEC + , mInnerAF(nsHostRecord::UNSPECAF_NULL) + , mCloneOf(nullptr) + , mNumPending(0) +#endif { host = ((char *) this) + sizeof(nsHostRecord); memcpy((char *) host, key->host, strlen(key->host) + 1); @@ -195,6 +202,26 @@ nsHostRecord::Create(const nsHostKey *key, nsHostRecord **result) return NS_OK; } +#if DO_MERGE_FOR_AF_UNSPEC +nsresult +nsHostRecord::CloneForAFUnspec(nsHostRecord** aClonedRecord, uint16_t aInnerAF) +{ + nsHostRecord* cloned = nullptr; + nsresult rv = Create(static_cast(this), &cloned); + if (NS_FAILED(rv)) { + return rv; + } + + cloned->mInnerAF = aInnerAF; + cloned->mCloneOf = this; + NS_ADDREF_THIS(); + + *aClonedRecord = cloned; + + return NS_OK; +} +#endif + nsHostRecord::~nsHostRecord() { delete addr_info; @@ -444,6 +471,10 @@ nsHostResolver::~nsHostResolver() nsresult nsHostResolver::Init() { + if (NS_FAILED(GetAddrInfoInit())) { + return NS_ERROR_FAILURE; + } + PL_DHashTableInit(&mDB, &gHostDB_ops, nullptr, sizeof(nsHostDBEnt), 0); mShutdown = false; @@ -534,6 +565,9 @@ nsHostResolver::Shutdown() while (mThreadCount && PR_IntervalNow() < stopTime) PR_Sleep(delay); #endif + + mozilla::DebugOnly rv = GetAddrInfoShutdown(); + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to shutdown GetAddrInfo"); } void @@ -843,7 +877,42 @@ nsHostResolver::ConditionallyCreateThread(nsHostRecord *rec) } nsresult -nsHostResolver::IssueLookup(nsHostRecord *rec) +nsHostResolver::IssueLookup(nsHostRecord* rec) +{ +#if DO_MERGE_FOR_AF_UNSPEC + // Issue two lookups to fulfill AF_UNSPEC requests: one each for AF_INET + // and AF_INET6. + if (rec->af == PR_AF_UNSPEC) { + // Enqueue a lookup for the IPv4 addresses first + rec->mInnerAF = AF_INET; + nsresult rv = IssueLookupInternal(rec); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rec->mNumPending++; + + // Make a clone and issue a lookup for the IPv6 addresses + nsHostRecord* rec_clone; + rv = rec->CloneForAFUnspec(&rec_clone, AF_INET6); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = IssueLookupInternal(rec_clone); + NS_RELEASE(rec_clone); + if (NS_SUCCEEDED(rv)) { + rec->mNumPending++; + } + + return rv; + } +#endif + + return IssueLookupInternal(rec); +} + +nsresult +nsHostResolver::IssueLookupInternal(nsHostRecord* rec) { MOZ_EVENT_TRACER_WAIT(rec, "net::dns::resolve"); @@ -853,9 +922,9 @@ nsHostResolver::IssueLookup(nsHostRecord *rec) // Add rec to one of the pending queues, possibly removing it from mEvictionQ. // If rec is on mEvictionQ, then we can just move the owning // reference over to the new active queue. - if (rec->next == rec) + if (rec->next == rec) { NS_ADDREF(rec); - else { + } else { PR_REMOVE_LINK(rec); mEvictionQSize--; } @@ -978,7 +1047,7 @@ nsHostResolver::GetHostToLookup(nsHostRecord **result) } void -nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, AddrInfo *result) +nsHostResolver::OnLookupComplete(nsHostRecord* rec, nsresult status, AddrInfo* result) { // get the list of pending callbacks for this lookup, and notify // them that the lookup is complete. @@ -987,63 +1056,156 @@ nsHostResolver::OnLookupComplete(nsHostRecord *rec, nsresult status, AddrInfo *r { MutexAutoLock lock(mLock); - // grab list of callbacks to notify - MoveCList(rec->callbacks, cbs); +#if DO_MERGE_FOR_AF_UNSPEC + // If this was an unspec query, then this function will be called twice + // and we need to make sure to merge the second result with the first. + if (rec->af == PR_AF_UNSPEC) { + MOZ_ASSERT(rec->mInnerAF != nsHostRecord::UNSPECAF_NULL); - // update record fields. We might have a rec->addr_info already if a - // previous lookup result expired and we're reresolving it.. - AddrInfo *old_addr_info; - { - MutexAutoLock lock(rec->addr_info_lock); - old_addr_info = rec->addr_info; - rec->addr_info = result; - rec->addr_info_gencnt++; - } - delete old_addr_info; + LOG(("OnLookupComplete: %s for UNSPEC request %s host %s.", + PR_AF_INET == rec->mInnerAF ? "INET" : "INET6", + rec->mCloneOf ? "clone" : "original", + rec->host)); - rec->expiration = TimeStamp::NowLoRes(); - if (result) { - rec->expiration += mMaxCacheLifetime; - rec->negative = false; - } - else { - rec->expiration += TimeDuration::FromSeconds(60); /* one minute for negative cache */ - rec->negative = true; - } - rec->resolving = false; - - if (rec->usingAnyThread) { - mActiveAnyThreadCount--; - rec->usingAnyThread = false; - } + nsHostRecord* originalRecord = rec->mCloneOf ? rec->mCloneOf : rec; - if (!mShutdown) { - // add to mEvictionQ - PR_APPEND_LINK(rec, &mEvictionQ); - NS_ADDREF(rec); - if (mEvictionQSize < mMaxCacheEntries) - mEvictionQSize++; - else { - // remove first element on mEvictionQ - nsHostRecord *head = - static_cast(PR_LIST_HEAD(&mEvictionQ)); - PR_REMOVE_AND_INIT_LINK(head); - PL_DHashTableOperate(&mDB, (nsHostKey *) head, PL_DHASH_REMOVE); + { + MutexAutoLock lock(originalRecord->addr_info_lock); - if (!head->negative) { - // record the age of the entry upon eviction. - TimeDuration age = TimeStamp::NowLoRes() - - (head->expiration - mMaxCacheLifetime); - Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE, - static_cast(age.ToSeconds() / 60)); + // If we have addresses for this host already... + if (originalRecord->addr_info) { + LOG(("Merging AF_UNSPEC results into existing addr_info " + "for %s.\n", rec->host)); + + originalRecord->addr_info->MergeAndConsume(result, + rec->mInnerAF); + originalRecord->addr_info_gencnt++; + } else { + LOG(("Original has no addr_info, using new AF_UNSPEC " + "result for %s.\n", rec->host)); + + originalRecord->addr_info = result; + originalRecord->addr_info_gencnt++; + } + } + + // Release the cloned record if its lookup is complete. + if (rec != originalRecord) { + MOZ_ASSERT(rec->mCloneOf); + LOG(("Deleting cloned AF_UNSPEC record for %s.\n", rec->host)); + + if (rec->usingAnyThread) { + mActiveAnyThreadCount--; + rec->usingAnyThread = false; } - // release reference to rec owned by mEvictionQ - NS_RELEASE(head); + // The original record will be released at the end of this + // function, so we don't have to (and shouldn't) release it + // here. + rec->mCloneOf = nullptr; + + // We need to release the clone however because it won't be + // released otherwise. + NS_RELEASE(rec); + + // We're totally done with the clone now and can concern + // ourselves solely with the original record. + rec = originalRecord; + originalRecord = nullptr; + } + + MOZ_ASSERT(rec->mNumPending >= 0); + rec->mNumPending--; + } else { +#else // if !DO_MERGE_FOR_AF_UNSPEC + { +#endif + LOG(("Got result for %s.\n", rec->host)); + + // update record fields. We might have a rec->addr_info already if + // a previous lookup result expired and we're reresolving it.. + AddrInfo *old_addr_info; + { + MutexAutoLock lock(rec->addr_info_lock); + old_addr_info = rec->addr_info; + rec->addr_info = result; + rec->addr_info_gencnt++; + } + delete old_addr_info; + } + +#if DO_MERGE_FOR_AF_UNSPEC + // If we're merging for AF_UNSPEC, grab the callback list only if all + // the inner lookups are complete. + if (rec->mNumPending <= 0) { + MOZ_ASSERT(rec->mNumPending == 0); +#else + // Otherwise, go ahead and grab the list of callbacks to notify. + { +#endif + MoveCList(rec->callbacks, cbs); + + rec->expiration = TimeStamp::NowLoRes(); + if (result) { + rec->expiration += mMaxCacheLifetime; + rec->negative = false; + } + else { + // One minute for negative cache + rec->expiration += TimeDuration::FromSeconds(60); + rec->negative = true; + } + rec->resolving = false; + + if (rec->usingAnyThread) { + mActiveAnyThreadCount--; + rec->usingAnyThread = false; + } + + if (!mShutdown) { + // add to mEvictionQ + PR_APPEND_LINK(rec, &mEvictionQ); + NS_ADDREF(rec); + if (mEvictionQSize < mMaxCacheEntries) + mEvictionQSize++; + else { + // remove first element on mEvictionQ + nsHostRecord *head = + static_cast(PR_LIST_HEAD(&mEvictionQ)); + PR_REMOVE_AND_INIT_LINK(head); + PL_DHashTableOperate(&mDB, (nsHostKey *) head, PL_DHASH_REMOVE); + + if (!head->negative) { + // record the age of the entry upon eviction. + TimeDuration age = TimeStamp::NowLoRes() - + (head->expiration - mMaxCacheLifetime); + Telemetry::Accumulate(Telemetry::DNS_CLEANUP_AGE, + static_cast(age.ToSeconds() / 60)); + } + + // release reference to rec owned by mEvictionQ + NS_RELEASE(head); + } } } } +#if DO_MERGE_FOR_AF_UNSPEC + // We don't want to trigger the callbacks if the inner lookups haven't + // completed yet. + if (rec->mNumPending > 0) { + NS_RELEASE(rec); + return; + } + + MOZ_ASSERT(rec->mNumPending == 0); + + if (rec->af == PR_AF_UNSPEC && rec->addr_info) { + MutexAutoLock lock(rec->addr_info_lock); + status = rec->addr_info->mAddresses.isEmpty() ? status : NS_OK; + } +#endif + MOZ_EVENT_TRACER_DONE(rec, "net::dns::resolve"); if (!PR_CLIST_IS_EMPTY(&cbs)) { @@ -1142,62 +1304,48 @@ nsHostResolver::ThreadFunc(void *arg) #endif nsHostResolver *resolver = (nsHostResolver *)arg; nsHostRecord *rec; - PRAddrInfo *prai = nullptr; while (resolver->GetHostToLookup(&rec)) { - LOG(("DNS lookup thread - Calling getaddrinfo for host [%s].\n", + LOG(("DNS lookup thread - Getting address info for host [%s].\n", rec->host)); - int flags = PR_AI_ADDRCONFIG; - if (!(rec->flags & RES_CANON_NAME)) - flags |= PR_AI_NOCANONNAME; - TimeStamp startTime = TimeStamp::Now(); MOZ_EVENT_TRACER_EXEC(rec, "net::dns::resolve"); - // We need to remove IPv4 records manually - // because PR_GetAddrInfoByName doesn't support PR_AF_INET6. - bool disableIPv4 = rec->af == PR_AF_INET6; - uint16_t af = disableIPv4 ? PR_AF_UNSPEC : rec->af; - prai = PR_GetAddrInfoByName(rec->host, af, flags); + uint16_t af; +#if DO_MERGE_FOR_AF_UNSPEC + // In the case of an unspec request, we need to make sure to use the + // "real" address family when we call GetAddrInfo. + af = rec->af == PR_AF_UNSPEC ? rec->mInnerAF : rec->af; +#else + af = rec->af; +#endif + + AddrInfo* ai = nullptr; + nsresult rv = GetAddrInfo(rec->host, af, rec->flags, &ai); #if defined(RES_RETRY_ON_FAILURE) - if (!prai && rs.Reset()) - prai = PR_GetAddrInfoByName(rec->host, af, flags); + if (NS_FAILED(rv) && rs.Reset()) { + rv = GetAddrInfo(rec->host, af, rec->flags, &ai); + } #endif TimeDuration elapsed = TimeStamp::Now() - startTime; uint32_t millis = static_cast(elapsed.ToMilliseconds()); - // convert error code to nsresult - nsresult status; - AddrInfo *ai = nullptr; - if (prai) { - const char *cname = nullptr; - if (rec->flags & RES_CANON_NAME) - cname = PR_GetCanonNameFromAddrInfo(prai); - ai = new AddrInfo(rec->host, prai, disableIPv4, cname); - PR_FreeAddrInfo(prai); - if (ai->mAddresses.isEmpty()) { - delete ai; - ai = nullptr; - } - } - if (ai) { - status = NS_OK; - + if (NS_SUCCEEDED(rv)) { + MOZ_ASSERT(ai); Telemetry::Accumulate(!rec->addr_info_gencnt ? Telemetry::DNS_LOOKUP_TIME : Telemetry::DNS_RENEWAL_TIME, millis); - } - else { - status = NS_ERROR_UNKNOWN_HOST; + } else { Telemetry::Accumulate(Telemetry::DNS_FAILED_LOOKUP_TIME, millis); } // OnLookupComplete may release "rec", log before we lose it. LOG(("DNS lookup thread - lookup completed for host [%s]: %s.\n", - rec->host, ai ? "success" : "failure: unknown host")); - resolver->OnLookupComplete(rec, status, ai); + rec->host, + NS_SUCCEEDED(rv) ? "success" : "failure: unknown host")); + resolver->OnLookupComplete(rec, rv, ai); } NS_RELEASE(resolver); LOG(("DNS lookup thread - queue empty, thread finished.\n")); diff --git a/netwerk/dns/nsHostResolver.h b/netwerk/dns/nsHostResolver.h index 3c60152eab5..04b0dc018c6 100644 --- a/netwerk/dns/nsHostResolver.h +++ b/netwerk/dns/nsHostResolver.h @@ -16,6 +16,7 @@ #include "nsIDNSListener.h" #include "nsString.h" #include "nsTArray.h" +#include "nsAutoPtr.h" #include "mozilla/net/DNS.h" #include "mozilla/net/DashboardTypes.h" #include "mozilla/TimeStamp.h" @@ -31,6 +32,17 @@ class nsResolveHostCallback; #define MAX_RESOLVER_THREADS (MAX_RESOLVER_THREADS_FOR_ANY_PRIORITY + \ MAX_RESOLVER_THREADS_FOR_HIGH_PRIORITY) +#if XP_WIN +// If this is enabled, we will make two queries to our resolver for unspec +// queries. One for any AAAA records, and the other for A records. We will then +// merge the results ourselves. This is done for us by getaddrinfo, but because +// getaddrinfo doesn't give us the TTL we use other APIs when we can that may +// not do it for us (Window's DnsQuery function for example). +#define DO_MERGE_FOR_AF_UNSPEC 1 +#else +#define DO_MERGE_FOR_AF_UNSPEC 0 +#endif + struct nsHostKey { const char *host; @@ -69,7 +81,10 @@ public: * thread doesn't need to lock when reading |addr_info|. */ Mutex addr_info_lock; - int addr_info_gencnt; /* generation count of |addr_info| */ + /* generation count of |addr_info|. Must be incremented whenever addr_info + * is changed so any iterators going through the old linked list can be + * invalidated. */ + int addr_info_gencnt; mozilla::net::AddrInfo *addr_info; mozilla::net::NetAddr *addr; bool negative; /* True if this record is a cache of a failed lookup. @@ -101,6 +116,23 @@ private: bool usingAnyThread; /* true if off queue and contributing to mActiveAnyThreadCount */ bool mDoomed; /* explicitly expired */ +#if DO_MERGE_FOR_AF_UNSPEC + // If this->af is PR_AF_UNSPEC, this will contain the address family that + // should actually be passed to GetAddrInfo. + uint16_t mInnerAF; + static const uint16_t UNSPECAF_NULL = -1; + + // mCloneOf will point at the original host record if this record is a + // clone. Null otherwise. + nsHostRecord* mCloneOf; + + // This will be set to the number of unresolved host records out for the + // given host record key. 0 for non AF_UNSPEC records. + int mNumPending; + + nsresult CloneForAFUnspec(nsHostRecord** aNewRecord, uint16_t aUnspecAF); +#endif + // a list of addresses associated with this record that have been reported // as unusable. the list is kept as a set of strings to make it independent // of gencnt. @@ -244,13 +276,20 @@ private: ~nsHostResolver(); nsresult Init(); - nsresult IssueLookup(nsHostRecord *); bool GetHostToLookup(nsHostRecord **m); void OnLookupComplete(nsHostRecord *, nsresult, mozilla::net::AddrInfo *); void DeQueue(PRCList &aQ, nsHostRecord **aResult); void ClearPendingQueue(PRCList *aPendingQueue); nsresult ConditionallyCreateThread(nsHostRecord *rec); + // This will issue two lookups (using the internal version) if + // DO_MERGE_FOR_AF_UNSPEC is enabled and the passed in record is an + // AF_UNSPEC record. + nsresult IssueLookup(nsHostRecord *); + + // This actually issues a single lookup + nsresult IssueLookupInternal(nsHostRecord *); + /** * Starts a new lookup in the background for entries that are in the grace * period with a failed connect or all cached entries are negative. From bb06786cab049f3b1d4a93f8ed63f7034f58f5dc Mon Sep 17 00:00:00 2001 From: Steve Singer Date: Mon, 18 Aug 2014 14:11:54 -0700 Subject: [PATCH 27/86] Bug 1046452 - Fix big endian JS_ION issues. r=bhackett --- js/src/asmjs/AsmJSSignalHandlers.cpp | 4 ++++ js/src/jit/IonMacroAssembler.cpp | 12 +++++++----- js/src/jit/IonMacroAssembler.h | 12 ++++++++---- js/src/jit/none/MacroAssembler-none.h | 2 ++ 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/js/src/asmjs/AsmJSSignalHandlers.cpp b/js/src/asmjs/AsmJSSignalHandlers.cpp index ca99d921480..6886c3fca50 100644 --- a/js/src/asmjs/AsmJSSignalHandlers.cpp +++ b/js/src/asmjs/AsmJSSignalHandlers.cpp @@ -370,7 +370,11 @@ HandleSimulatorInterrupt(JSRuntime *rt, AsmJSActivation *activation, void *fault static uint8_t ** ContextToPC(CONTEXT *context) { +#ifdef JS_CODEGEN_NONE + MOZ_CRASH(); +#else return reinterpret_cast(&PC_sig(context)); +#endif } # if defined(JS_CODEGEN_X64) diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index b5ed0705d5b..58e9ec0b91b 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -1945,7 +1945,6 @@ MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch // perform an aligned 32-bit load and adjust the bitmask accordingly. JS_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0); JS_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2); - JS_STATIC_ASSERT(IS_LITTLE_ENDIAN); // Emit code for the following test: // @@ -1956,21 +1955,24 @@ MacroAssembler::branchIfNotInterpretedConstructor(Register fun, Register scratch // First, ensure it's a scripted function. load32(Address(fun, JSFunction::offsetOfNargs()), scratch); - branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::INTERPRETED << 16), label); + int32_t bits = IMM32_16ADJ(JSFunction::INTERPRETED); + branchTest32(Assembler::Zero, scratch, Imm32(bits), label); // Common case: if IS_FUN_PROTO, ARROW and SELF_HOSTED are not set, // the function is an interpreted constructor and we're done. Label done; - uint32_t bits = (JSFunction::IS_FUN_PROTO | JSFunction::ARROW | JSFunction::SELF_HOSTED) << 16; + bits = IMM32_16ADJ( (JSFunction::IS_FUN_PROTO | JSFunction::ARROW | JSFunction::SELF_HOSTED) ); branchTest32(Assembler::Zero, scratch, Imm32(bits), &done); { // The callee is either Function.prototype, an arrow function or // self-hosted. None of these are constructible, except self-hosted // constructors, so branch to |label| if SELF_HOSTED_CTOR is not set. - branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::SELF_HOSTED_CTOR << 16), label); + bits = IMM32_16ADJ(JSFunction::SELF_HOSTED_CTOR); + branchTest32(Assembler::Zero, scratch, Imm32(bits), label); #ifdef DEBUG - branchTest32(Assembler::Zero, scratch, Imm32(JSFunction::IS_FUN_PROTO << 16), &done); + bits = IMM32_16ADJ(JSFunction::IS_FUN_PROTO); + branchTest32(Assembler::Zero, scratch, Imm32(bits), &done); assumeUnreachable("Function.prototype should not have the SELF_HOSTED_CTOR flag"); #endif } diff --git a/js/src/jit/IonMacroAssembler.h b/js/src/jit/IonMacroAssembler.h index 874445131b4..c15118e1e87 100644 --- a/js/src/jit/IonMacroAssembler.h +++ b/js/src/jit/IonMacroAssembler.h @@ -28,6 +28,12 @@ #include "vm/ProxyObject.h" #include "vm/Shape.h" +#ifdef IS_LITTLE_ENDIAN +#define IMM32_16ADJ(X) X << 16 +#else +#define IMM32_16ADJ(X) X +#endif + namespace js { namespace jit { @@ -523,9 +529,8 @@ class MacroAssembler : public MacroAssemblerSpecific // perform an aligned 32-bit load and adjust the bitmask accordingly. JS_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0); JS_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2); - JS_STATIC_ASSERT(IS_LITTLE_ENDIAN); Address address(fun, JSFunction::offsetOfNargs()); - uint32_t bit = JSFunction::INTERPRETED << 16; + int32_t bit = IMM32_16ADJ(JSFunction::INTERPRETED); branchTest32(Assembler::Zero, address, Imm32(bit), label); } void branchIfInterpreted(Register fun, Label *label) { @@ -533,9 +538,8 @@ class MacroAssembler : public MacroAssemblerSpecific // perform an aligned 32-bit load and adjust the bitmask accordingly. JS_ASSERT(JSFunction::offsetOfNargs() % sizeof(uint32_t) == 0); JS_ASSERT(JSFunction::offsetOfFlags() == JSFunction::offsetOfNargs() + 2); - JS_STATIC_ASSERT(IS_LITTLE_ENDIAN); Address address(fun, JSFunction::offsetOfNargs()); - uint32_t bit = JSFunction::INTERPRETED << 16; + int32_t bit = IMM32_16ADJ(JSFunction::INTERPRETED); branchTest32(Assembler::NonZero, address, Imm32(bit), label); } diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index aa8ed95db88..b4819e336e5 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -14,6 +14,8 @@ namespace js { namespace jit { +class MDefinition; + static MOZ_CONSTEXPR_VAR Register StackPointer = { 0 }; static MOZ_CONSTEXPR_VAR Register FramePointer = { 0 }; static MOZ_CONSTEXPR_VAR Register ReturnReg = { 0 }; From 8997acdb2d4fe70a70b436dedd90b924986b3c1a Mon Sep 17 00:00:00 2001 From: Mihaela Velimiroviciu Date: Tue, 29 Jul 2014 17:18:15 +0300 Subject: [PATCH 28/86] Bug 1042769 - Add automated test for checking that the metainfo fields are displayed in password manager. r=paolo --- .../passwordmgr/test/browser/browser.ini | 1 + .../browser/browser_passwordmgr_fields.js | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 toolkit/components/passwordmgr/test/browser/browser_passwordmgr_fields.js diff --git a/toolkit/components/passwordmgr/test/browser/browser.ini b/toolkit/components/passwordmgr/test/browser/browser.ini index 9036e11630d..e4c39d27320 100644 --- a/toolkit/components/passwordmgr/test/browser/browser.ini +++ b/toolkit/components/passwordmgr/test/browser/browser.ini @@ -1,5 +1,6 @@ [DEFAULT] +[browser_passwordmgr_fields.js] [browser_passwordmgr_observers.js] [browser_passwordmgr_sort.js] [browser_passwordmgrcopypwd.js] diff --git a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_fields.js b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_fields.js new file mode 100644 index 00000000000..8a18fbaeb1a --- /dev/null +++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_fields.js @@ -0,0 +1,65 @@ +/* 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/. */ + +function test() { + waitForExplicitFinish(); + + let pwmgr = Cc["@mozilla.org/login-manager;1"]. + getService(Ci.nsILoginManager); + pwmgr.removeAllLogins(); + + // add login data + let nsLoginInfo = new Components.Constructor("@mozilla.org/login-manager/loginInfo;1", + Ci.nsILoginInfo, "init"); + let login = new nsLoginInfo("http://example.com/", "http://example.com/", null, + "user", "password", "u1", "p1"); + pwmgr.addLogin(login); + + // Open the password manager dialog + const PWMGR_DLG = "chrome://passwordmgr/content/passwordManager.xul"; + let pwmgrdlg = window.openDialog(PWMGR_DLG, "Toolkit:PasswordManager", ""); + SimpleTest.waitForFocus(doTest, pwmgrdlg); + + function doTest() { + let doc = pwmgrdlg.document; + + let signonsTree = doc.querySelector("#signonsTree"); + is(signonsTree.view.rowCount, 1, "One entry in the passwords list"); + + is(signonsTree.view.getCellText(0, signonsTree.columns.getNamedColumn("siteCol")), + "http://example.com/", + "Correct website saved"); + + is(signonsTree.view.getCellText(0, signonsTree.columns.getNamedColumn("userCol")), + "user", + "Correct user saved"); + + let timeCreatedCol = doc.getElementById("timeCreatedCol"); + is(timeCreatedCol.getAttribute("hidden"), "true", + "Time created column is not displayed"); + + + let timeLastUsedCol = doc.getElementById("timeLastUsedCol"); + is(timeLastUsedCol.getAttribute("hidden"), "", + "Last Used column is displayed"); + + let timePasswordChangedCol = doc.getElementById("timePasswordChangedCol"); + is(timePasswordChangedCol.getAttribute("hidden"), "", + "Last Changed column is displayed"); + + // cleanup + Services.ww.registerNotification(function (aSubject, aTopic, aData) { + if (aSubject.location == pwmgrdlg.location && aTopic == "domwindowclosed") { + // unregister ourself + Services.ww.unregisterNotification(arguments.callee); + + pwmgr.removeAllLogins(); + + finish(); + } + }); + + pwmgrdlg.close(); + } +} From 4dad8c56d459cd72faf4f956603c4998d1fad06d Mon Sep 17 00:00:00 2001 From: Ahmed Kachkach Date: Fri, 15 Aug 2014 15:42:00 -0400 Subject: [PATCH 29/86] Bug 1050855 - Remove --log-file and --file-level options. r=ahal --- testing/mochitest/mochitest_options.py | 19 ------------------- testing/mochitest/runtests.py | 5 +++++ testing/mochitest/runtestsremote.py | 1 + testing/testsuite-targets.mk | 10 +++++----- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/testing/mochitest/mochitest_options.py b/testing/mochitest/mochitest_options.py index aba020baaf8..16e40029111 100644 --- a/testing/mochitest/mochitest_options.py +++ b/testing/mochitest/mochitest_options.py @@ -61,14 +61,6 @@ class MochitestOptions(optparse.OptionParser): "help": "absolute path to directory containing certificate store to use testing profile", "default": os.path.join(build_obj.topsrcdir, 'build', 'pgo', 'certs') if build_obj is not None else None, }], - [["--log-file"], - { "action": "store", - "type": "string", - "dest": "logFile", - "metavar": "FILE", - "help": "file to which logging occurs", - "default": "", - }], [["--autorun"], { "action": "store_true", "dest": "autorun", @@ -121,17 +113,6 @@ class MochitestOptions(optparse.OptionParser): "logging" % LEVEL_STRING, "default": None, }], - [["--file-level"], - { "action": "store", - "type": "choice", - "dest": "fileLevel", - "choices": LOG_LEVELS, - "metavar": "LEVEL", - "help": "one of %s to determine the level of file " - "logging if a file has been specified, defaulting " - "to INFO" % LEVEL_STRING, - "default": "INFO", - }], [["--chrome"], { "action": "store_true", "dest": "chrome", diff --git a/testing/mochitest/runtests.py b/testing/mochitest/runtests.py index 21433736e74..098c0a50386 100644 --- a/testing/mochitest/runtests.py +++ b/testing/mochitest/runtests.py @@ -481,6 +481,11 @@ class MochitestUtilsMixin(object): repeat -- How many times to repeat the test, ie: repeat=1 will run the test twice. """ + if not hasattr(options, 'logFile'): + options.logFile = "" + if not hasattr(options, 'fileLevel'): + options.fileLevel = 'INFO' + # allow relative paths for logFile if options.logFile: options.logFile = self.getLogFilePath(options.logFile) diff --git a/testing/mochitest/runtestsremote.py b/testing/mochitest/runtestsremote.py index 4434ff883e9..6729240b651 100644 --- a/testing/mochitest/runtestsremote.py +++ b/testing/mochitest/runtestsremote.py @@ -370,6 +370,7 @@ class MochiRemote(Mochitest): def buildURLOptions(self, options, env): self.localLog = options.logFile options.logFile = self.remoteLog + options.fileLevel = 'INFO' options.profilePath = self.localProfile env["MOZ_HIDE_RESULTS_TABLE"] = "1" retVal = Mochitest.buildURLOptions(self, options, env) diff --git a/testing/testsuite-targets.mk b/testing/testsuite-targets.mk index 8afd3489124..ab7ec4ac69e 100644 --- a/testing/testsuite-targets.mk +++ b/testing/testsuite-targets.mk @@ -30,7 +30,7 @@ endif RUN_MOCHITEST_B2G_DESKTOP = \ rm -f ./$@.log && \ $(PYTHON) _tests/testing/mochitest/runtestsb2g.py --autorun --close-when-done \ - --console-level=INFO --log-file=./$@.log --file-level=INFO \ + --console-level=INFO --log-tbpl=./$@.log \ --desktop --profile ${GAIA_PROFILE_DIR} \ --failure-file=$(abspath _tests/testing/mochitest/makefailures.json) \ $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS) @@ -38,7 +38,7 @@ RUN_MOCHITEST_B2G_DESKTOP = \ RUN_MOCHITEST = \ rm -f ./$@.log && \ $(PYTHON) _tests/testing/mochitest/runtests.py --autorun --close-when-done \ - --console-level=INFO --log-file=./$@.log --file-level=INFO \ + --console-level=INFO --log-tbpl=./$@.log \ --failure-file=$(abspath _tests/testing/mochitest/makefailures.json) \ --testing-modules-dir=$(abspath _tests/modules) \ --extra-profile-file=$(DIST)/plugins \ @@ -47,7 +47,7 @@ RUN_MOCHITEST = \ RERUN_MOCHITEST = \ rm -f ./$@.log && \ $(PYTHON) _tests/testing/mochitest/runtests.py --autorun --close-when-done \ - --console-level=INFO --log-file=./$@.log --file-level=INFO \ + --console-level=INFO --log-tbpl=./$@.log \ --run-only-tests=makefailures.json \ --testing-modules-dir=$(abspath _tests/modules) \ --extra-profile-file=$(DIST)/plugins \ @@ -56,7 +56,7 @@ RERUN_MOCHITEST = \ RUN_MOCHITEST_REMOTE = \ rm -f ./$@.log && \ $(PYTHON) _tests/testing/mochitest/runtestsremote.py --autorun --close-when-done \ - --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \ + --console-level=INFO --log-tbpl=./$@.log $(DM_FLAGS) --dm_trans=$(DM_TRANS) \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ --testing-modules-dir=$(abspath _tests/modules) \ $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS) @@ -67,7 +67,7 @@ RUN_MOCHITEST_ROBOCOP = \ --robocop-apk=$(DEPTH)/build/mobile/robocop/robocop-debug.apk \ --robocop-ids=$(DEPTH)/mobile/android/base/fennec_ids.txt \ --robocop-ini=$(DEPTH)/build/mobile/robocop/robocop.ini \ - --console-level=INFO --log-file=./$@.log --file-level=INFO $(DM_FLAGS) --dm_trans=$(DM_TRANS) \ + --console-level=INFO --log-tbpl=./$@.log $(DM_FLAGS) --dm_trans=$(DM_TRANS) \ --app=$(TEST_PACKAGE_NAME) --deviceIP=${TEST_DEVICE} --xre-path=${MOZ_HOST_BIN} \ $(SYMBOLS_PATH) $(TEST_PATH_ARG) $(EXTRA_TEST_ARGS) From 4e5e817715d6294b1e11d6df2d795934e7fabb8a Mon Sep 17 00:00:00 2001 From: Martijn Wargers Date: Mon, 18 Aug 2014 18:21:08 +0200 Subject: [PATCH 30/86] Bug 1051783 - Fix test_pointerlock-api.html. r=Enn --- dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html b/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html index 0015d5d07ee..e4802f51658 100644 --- a/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html +++ b/dom/tests/mochitest/pointerlock/file_retargetMouseEvents.html @@ -143,7 +143,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=633602 parent.addEventListener("click", parentClickTest); child.addEventListener("click", childClickTest); SimpleTest.executeSoon(function () { - synthesizeMouseAtCenter(child, {type: "click"}, window); + synthesizeMouseAtCenter(child, {}, window); }); }; From 6cad9db1f36944992eb324c8708bdf4c3c91b900 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:38 -0700 Subject: [PATCH 31/86] Bug 1050340 - Access regexp guts generically. r=luke --- js/src/vm/StructuredClone.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index bc838cfbf23..7032ae395e5 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1011,10 +1011,12 @@ JSStructuredCloneWriter::startWrite(HandleValue v) if (backref) return true; - if (obj->is()) { - RegExpObject &reobj = obj->as(); - return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) && - writeString(SCTAG_STRING, reobj.getSource()); + if (ObjectClassIs(obj, ESClass_RegExp, context())) { + RegExpGuard re(context()); + if (!RegExpToShared(context(), obj, &re)) + return false; + return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) && + writeString(SCTAG_STRING, re->getSource()); } else if (obj->is()) { double d = js_DateGetMsecSinceEpoch(obj); return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d); From 62ec2984ecba524bffea0a783f157cf96024ed52 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:38 -0700 Subject: [PATCH 32/86] Bug 1050340 - Handle dates generically. r=luke --- js/src/jsdate.cpp | 6 +++++- js/src/vm/StructuredClone.cpp | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 3dbbb481e05..3d55a2f7102 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -32,6 +32,7 @@ #include "jsstr.h" #include "jstypes.h" #include "jsutil.h" +#include "jswrapper.h" #include "prmjtime.h" #include "js/Date.h" @@ -3130,5 +3131,8 @@ js_DateGetSeconds(JSObject *obj) JS_FRIEND_API(double) js_DateGetMsecSinceEpoch(JSObject *obj) { - return obj->is() ? obj->as().UTCTime().toNumber() : 0; + obj = CheckedUnwrap(obj); + if (!obj || !obj->is()) + return 0; + return obj->as().UTCTime().toNumber(); } diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 7032ae395e5..6a4a70577d5 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1017,7 +1017,7 @@ JSStructuredCloneWriter::startWrite(HandleValue v) return false; return out.writePair(SCTAG_REGEXP_OBJECT, re->getFlags()) && writeString(SCTAG_STRING, re->getSource()); - } else if (obj->is()) { + } else if (ObjectClassIs(obj, ESClass_Date, context())) { double d = js_DateGetMsecSinceEpoch(obj); return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d); } else if (obj->is()) { From bea169fd759df448f2b98f1302598e5a2c7dc053 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:39 -0700 Subject: [PATCH 33/86] Bug 1050340 - Handle ArrayBuffers and TypedArrays pseudo-generically. r=luke --- js/src/jsfriendapi.h | 11 ++++++ js/src/vm/ArrayBufferObject.cpp | 6 +++ js/src/vm/StructuredClone.cpp | 66 ++++++++++++++++----------------- 3 files changed, 49 insertions(+), 34 deletions(-) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index f49b0024cfe..3344839dd29 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1729,6 +1729,17 @@ JS_IsArrayBufferObject(JSObject *obj); extern JS_FRIEND_API(uint32_t) JS_GetArrayBufferByteLength(JSObject *obj); +/* + * Return true if the arrayBuffer contains any data. This will return false for + * ArrayBuffer.prototype and neutered ArrayBuffers. + * + * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known + * that it would pass such a test: it is an ArrayBuffer or a wrapper of an + * ArrayBuffer, and the unwrapping will succeed. + */ +extern JS_FRIEND_API(bool) +JS_ArrayBufferHasData(JSObject *obj); + /* * Check whether the obj is ArrayBufferObject and memory mapped. Note that this * may return false if a security wrapper is encountered that denies the diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 7ce9d9a7f2b..089808da45c 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -1147,6 +1147,12 @@ JS_IsArrayBufferObject(JSObject *obj) return obj ? obj->is() : false; } +JS_FRIEND_API(bool) +JS_ArrayBufferHasData(JSObject *obj) +{ + return CheckedUnwrap(obj)->as().hasData(); +} + JS_FRIEND_API(JSObject *) js::UnwrapArrayBuffer(JSObject *obj) { diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 6a4a70577d5..8ff41edccb7 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -856,7 +856,8 @@ JSStructuredCloneWriter::checkStack() bool JSStructuredCloneWriter::writeTypedArray(HandleObject obj) { - Rooted tarr(context(), &obj->as()); + Rooted tarr(context(), &CheckedUnwrap(obj)->as()); + JSAutoCompartment ac(context(), tarr); if (!TypedArrayObject::ensureHasBuffer(context(), tarr)) return false; @@ -878,7 +879,8 @@ JSStructuredCloneWriter::writeTypedArray(HandleObject obj) bool JSStructuredCloneWriter::writeArrayBuffer(HandleObject obj) { - ArrayBufferObject &buffer = obj->as(); + ArrayBufferObject &buffer = CheckedUnwrap(obj)->as(); + JSAutoCompartment ac(context(), &buffer); return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, buffer.byteLength()) && out.writeBytes(buffer.dataPointer(), buffer.byteLength()); @@ -1020,9 +1022,9 @@ JSStructuredCloneWriter::startWrite(HandleValue v) } else if (ObjectClassIs(obj, ESClass_Date, context())) { double d = js_DateGetMsecSinceEpoch(obj); return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d); - } else if (obj->is()) { + } else if (JS_IsTypedArrayObject(obj)) { return writeTypedArray(obj); - } else if (obj->is() && obj->as().hasData()) { + } else if (JS_IsArrayBufferObject(obj) && JS_ArrayBufferHasData(obj)) { return writeArrayBuffer(obj); } else if (obj->is() || obj->is()) { return traverseObject(obj); @@ -1108,29 +1110,34 @@ JSStructuredCloneWriter::transferOwnership() MOZ_ASSERT(ownership == JS::SCTAG_TMO_UNFILLED); #endif - if (obj->is()) { - bool isMapped = obj->as().isMappedArrayBuffer(); - size_t nbytes = obj->as().byteLength(); - content = JS_StealArrayBufferContents(context(), obj); - if (!content) - return false; // Destructor will clean up the already-transferred data - tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER; - if (isMapped) - ownership = JS::SCTAG_TMO_MAPPED_DATA; - else - ownership = JS::SCTAG_TMO_ALLOC_DATA; - extraData = nbytes; - } else if (obj->is()) { - SharedArrayRawBuffer *rawbuf = obj->as().rawBufferObject(); + if (ObjectClassIs(obj, ESClass_ArrayBuffer, context())) { + // The current setup of the array buffer inheritance hierarchy doesn't + // lend itself well to generic manipulation via proxies. + Rooted arrayBuffer(context(), &CheckedUnwrap(obj)->as()); + if (arrayBuffer->isSharedArrayBuffer()) { + SharedArrayRawBuffer *rawbuf = arrayBuffer->as().rawBufferObject(); - // Avoids a race condition where the parent thread frees the buffer - // before the child has accepted the transferable. - rawbuf->addReference(); + // Avoids a race condition where the parent thread frees the buffer + // before the child has accepted the transferable. + rawbuf->addReference(); - tag = SCTAG_TRANSFER_MAP_SHARED_BUFFER; - ownership = JS::SCTAG_TMO_SHARED_BUFFER; - content = rawbuf; - extraData = 0; + tag = SCTAG_TRANSFER_MAP_SHARED_BUFFER; + ownership = JS::SCTAG_TMO_SHARED_BUFFER; + content = rawbuf; + extraData = 0; + } else { + bool isMapped = arrayBuffer->isMappedArrayBuffer(); + size_t nbytes = arrayBuffer->byteLength(); + content = JS_StealArrayBufferContents(context(), arrayBuffer); + if (!content) + return false; // Destructor will clean up the already-transferred data + tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER; + if (isMapped) + ownership = JS::SCTAG_TMO_MAPPED_DATA; + else + ownership = JS::SCTAG_TMO_ALLOC_DATA; + extraData = nbytes; + } } else { if (!callbacks || !callbacks->writeTransfer) return reportErrorTransferable(); @@ -2010,14 +2017,5 @@ JS_WriteTypedArray(JSStructuredCloneWriter *w, HandleValue v) JS_ASSERT(v.isObject()); assertSameCompartment(w->context(), v); RootedObject obj(w->context(), &v.toObject()); - - // If the object is a security wrapper, see if we're allowed to unwrap it. - // If we aren't, throw. - if (obj->is()) - obj = CheckedUnwrap(obj); - if (!obj) { - JS_ReportErrorNumber(w->context(), js_GetErrorMessage, nullptr, JSMSG_UNWRAP_DENIED); - return false; - } return w->writeTypedArray(obj); } From 93348157b7468a7391fcab678699f2eea92c3121 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:39 -0700 Subject: [PATCH 34/86] Bug 1050340 - Handle boxed values with a new proxy trap. r=luke --- js/public/Class.h | 4 ++++ js/src/jsobjinlines.h | 18 ++++++++++++++++++ js/src/jsproxy.cpp | 21 +++++++++++++++++++++ js/src/jsproxy.h | 3 +++ js/src/jswrapper.cpp | 17 +++++++++++++++++ js/src/jswrapper.h | 2 ++ js/src/vm/StructuredClone.cpp | 22 +++++++++++++++------- 7 files changed, 80 insertions(+), 7 deletions(-) diff --git a/js/public/Class.h b/js/public/Class.h index 82339d4d4bc..dbedc4eddf8 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -535,6 +535,10 @@ ObjectClassIs(JSObject &obj, ESClassValue classValue, JSContext *cx); inline bool IsObjectWithClass(const JS::Value &v, ESClassValue classValue, JSContext *cx); +/* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ +inline bool +Unbox(JSContext *cx, JS::HandleObject obj, JS::MutableHandleValue vp); + } /* namespace js */ #endif /* js_Class_h */ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 8758514a845..f8bfc171be0 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1046,6 +1046,24 @@ IsObjectWithClass(const Value &v, ESClassValue classValue, JSContext *cx) return ObjectClassIs(obj, classValue, cx); } +inline bool +Unbox(JSContext *cx, HandleObject obj, MutableHandleValue vp) +{ + if (MOZ_UNLIKELY(obj->is())) + return Proxy::boxedValue_unbox(cx, obj, vp); + + if (obj->is()) + vp.setBoolean(obj->as().unbox()); + else if (obj->is()) + vp.setNumber(obj->as().unbox()); + else if (obj->is()) + vp.setString(obj->as().unbox()); + else + vp.setUndefined(); + + return true; +} + static MOZ_ALWAYS_INLINE bool NewObjectMetadata(ExclusiveContext *cxArg, JSObject **pmetadata) { diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 360a9daea05..ae6429fd7be 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -329,6 +329,13 @@ BaseProxyHandler::regexp_toShared(JSContext *cx, HandleObject proxy, MOZ_CRASH("This should have been a wrapped regexp"); } +bool +BaseProxyHandler::boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const +{ + vp.setUndefined(); + return true; +} + bool BaseProxyHandler::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp) const @@ -558,6 +565,13 @@ DirectProxyHandler::regexp_toShared(JSContext *cx, HandleObject proxy, return RegExpToShared(cx, target, g); } +bool +DirectProxyHandler::boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const +{ + RootedObject target(cx, proxy->as().target()); + return Unbox(cx, target, vp); +} + JSObject * DirectProxyHandler::weakmapKeyDelegate(JSObject *proxy) const { @@ -2609,6 +2623,13 @@ Proxy::regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) return proxy->as().handler()->regexp_toShared(cx, proxy, g); } +bool +Proxy::boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) +{ + JS_CHECK_RECURSION(cx, return false); + return proxy->as().handler()->boxedValue_unbox(cx, proxy, vp); +} + bool Proxy::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHandleValue vp) { diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index 37730ea483b..dda92b6b555 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -206,6 +206,7 @@ class JS_FRIEND_API(BaseProxyHandler) virtual const char *className(JSContext *cx, HandleObject proxy) const; virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const; virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const; + virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const; virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp) const; virtual void finalize(JSFreeOp *fop, JSObject *proxy) const; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const; @@ -289,6 +290,7 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler unsigned indent) const MOZ_OVERRIDE; virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE; + virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const; virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const MOZ_OVERRIDE; }; @@ -338,6 +340,7 @@ class Proxy static const char *className(JSContext *cx, HandleObject proxy); static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent); static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g); + static bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp); static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp); static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp); diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 59fc41680da..3750043d467 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -569,6 +569,15 @@ CrossCompartmentWrapper::regexp_toShared(JSContext *cx, HandleObject wrapper, Re return cx->compartment()->regExps.get(cx, re->getSource(), re->getFlags(), g); } +bool +CrossCompartmentWrapper::boxedValue_unbox(JSContext *cx, HandleObject wrapper, MutableHandleValue vp) const +{ + PIERCE(cx, wrapper, + NOTHING, + Wrapper::boxedValue_unbox(cx, wrapper, vp), + cx->compartment()->wrap(cx, vp)); +} + bool CrossCompartmentWrapper::defaultValue(JSContext *cx, HandleObject wrapper, JSType hint, MutableHandleValue vp) const @@ -689,6 +698,14 @@ SecurityWrapper::regexp_toShared(JSContext *cx, HandleObject obj, RegExpGu return Base::regexp_toShared(cx, obj, g); } +template +bool +SecurityWrapper::boxedValue_unbox(JSContext *cx, HandleObject obj, MutableHandleValue vp) const +{ + vp.setUndefined(); + return true; +} + template bool SecurityWrapper::defineProperty(JSContext *cx, HandleObject wrapper, diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 1cc0ff2789d..8f3676a48bc 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -144,6 +144,7 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper virtual JSString *fun_toString(JSContext *cx, HandleObject wrapper, unsigned indent) const MOZ_OVERRIDE; virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE; + virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint, MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, @@ -181,6 +182,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) const MOZ_OVERRIDE; virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE; + virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const MOZ_OVERRIDE; virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc) const MOZ_OVERRIDE; diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 8ff41edccb7..b5dadd709b3 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1028,13 +1028,21 @@ JSStructuredCloneWriter::startWrite(HandleValue v) return writeArrayBuffer(obj); } else if (obj->is() || obj->is()) { return traverseObject(obj); - } else if (obj->is()) { - return out.writePair(SCTAG_BOOLEAN_OBJECT, obj->as().unbox()); - } else if (obj->is()) { - return out.writePair(SCTAG_NUMBER_OBJECT, 0) && - out.writeDouble(obj->as().unbox()); - } else if (obj->is()) { - return writeString(SCTAG_STRING_OBJECT, obj->as().unbox()); + } else if (ObjectClassIs(obj, ESClass_Boolean, context())) { + RootedValue unboxed(context()); + if (!Unbox(context(), obj, &unboxed)) + return false; + return out.writePair(SCTAG_BOOLEAN_OBJECT, unboxed.toBoolean()); + } else if (ObjectClassIs(obj, ESClass_Number, context())) { + RootedValue unboxed(context()); + if (!Unbox(context(), obj, &unboxed)) + return false; + return out.writePair(SCTAG_NUMBER_OBJECT, 0) && out.writeDouble(unboxed.toNumber()); + } else if (ObjectClassIs(obj, ESClass_String, context())) { + RootedValue unboxed(context()); + if (!Unbox(context(), obj, &unboxed)) + return false; + return writeString(SCTAG_STRING_OBJECT, unboxed.toString()); } else if (obj->is()) { return traverseMap(obj); } else if (obj->is()) { From 601fef2922508aea64c16fb5c925854c9fdeec28 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:39 -0700 Subject: [PATCH 35/86] Bug 1050340 - Handle maps and sets. r=luke --- js/public/Class.h | 3 ++- js/src/jscompartment.h | 8 ++++++++ js/src/jsobjinlines.h | 3 +++ js/src/vm/StructuredClone.cpp | 24 ++++++++++++++++++++---- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/js/public/Class.h b/js/public/Class.h index dbedc4eddf8..99503d56d74 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -519,7 +519,8 @@ Valueify(const JSClass *c) */ enum ESClassValue { ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean, - ESClass_RegExp, ESClass_ArrayBuffer, ESClass_Date + ESClass_RegExp, ESClass_ArrayBuffer, ESClass_Date, ESClass_Set, + ESClass_Map }; /* diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 0c1a9675029..10443a65b67 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -325,6 +325,14 @@ struct JSCompartment bool wrap(JSContext *cx, JS::MutableHandle desc); bool wrap(JSContext *cx, JS::MutableHandle desc); + template bool wrap(JSContext *cx, JS::AutoVectorRooter &vec) { + for (size_t i = 0; i < vec.length(); ++i) { + if (!wrap(cx, vec[i])) + return false; + } + return true; + }; + bool putWrapper(JSContext *cx, const js::CrossCompartmentKey& wrapped, const js::Value& wrapper); js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) { diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index f8bfc171be0..02e054c4dc0 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -9,6 +9,7 @@ #include "jsobj.h" +#include "builtin/MapObject.h" #include "builtin/TypedObject.h" #include "vm/ArrayObject.h" #include "vm/DateObject.h" @@ -1033,6 +1034,8 @@ ObjectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) case ESClass_ArrayBuffer: return obj->is() || obj->is(); case ESClass_Date: return obj->is(); + case ESClass_Set: return obj->is(); + case ESClass_Map: return obj->is(); } MOZ_CRASH("bad classValue"); } diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index b5dadd709b3..17d319867ee 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -937,7 +937,15 @@ bool JSStructuredCloneWriter::traverseMap(HandleObject obj) { AutoValueVector newEntries(context()); - if (!MapObject::entries(context(), obj, &newEntries)) + { + // If there is no wrapper, the compartment munging is a no-op. + RootedObject unwrapped(context(), CheckedUnwrap(obj)); + MOZ_ASSERT(unwrapped); + JSAutoCompartment ac(context(), unwrapped); + if (!MapObject::entries(context(), unwrapped, &newEntries)) + return false; + } + if (!context()->compartment()->wrap(context(), newEntries)) return false; for (size_t i = newEntries.length(); i > 0; --i) { @@ -959,7 +967,15 @@ bool JSStructuredCloneWriter::traverseSet(HandleObject obj) { AutoValueVector keys(context()); - if (!SetObject::keys(context(), obj, &keys)) + { + // If there is no wrapper, the compartment munging is a no-op. + RootedObject unwrapped(context(), CheckedUnwrap(obj)); + MOZ_ASSERT(unwrapped); + JSAutoCompartment ac(context(), unwrapped); + if (!SetObject::keys(context(), obj, &keys)) + return false; + } + if (!context()->compartment()->wrap(context(), keys)) return false; for (size_t i = keys.length(); i > 0; --i) { @@ -1043,9 +1059,9 @@ JSStructuredCloneWriter::startWrite(HandleValue v) if (!Unbox(context(), obj, &unboxed)) return false; return writeString(SCTAG_STRING_OBJECT, unboxed.toString()); - } else if (obj->is()) { + } else if (ObjectClassIs(obj, ESClass_Map, context())) { return traverseMap(obj); - } else if (obj->is()) { + } else if (ObjectClassIs(obj, ESClass_Set, context())) { return traverseSet(obj); } From 1fdb7585c84f79e992f385dad968b5a918129b38 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:39 -0700 Subject: [PATCH 36/86] Bug 1050340 - Handle object and array. r=luke --- js/public/Class.h | 6 +++--- js/src/jsobjinlines.h | 1 + js/src/vm/StructuredClone.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/js/public/Class.h b/js/public/Class.h index 99503d56d74..bf96371a63e 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -518,9 +518,9 @@ Valueify(const JSClass *c) * value of objects. */ enum ESClassValue { - ESClass_Array, ESClass_Number, ESClass_String, ESClass_Boolean, - ESClass_RegExp, ESClass_ArrayBuffer, ESClass_Date, ESClass_Set, - ESClass_Map + ESClass_Object, ESClass_Array, ESClass_Number, ESClass_String, + ESClass_Boolean, ESClass_RegExp, ESClass_ArrayBuffer, ESClass_Date, + ESClass_Set, ESClass_Map }; /* diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 02e054c4dc0..0d0dbfb8775 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -1026,6 +1026,7 @@ ObjectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx) return Proxy::objectClassIs(obj, classValue, cx); switch (classValue) { + case ESClass_Object: return obj->is(); case ESClass_Array: return obj->is(); case ESClass_Number: return obj->is(); case ESClass_String: return obj->is(); diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 17d319867ee..d5f53540af3 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -930,7 +930,7 @@ JSStructuredCloneWriter::traverseObject(HandleObject obj) checkStack(); /* Write the header for obj. */ - return out.writePair(obj->is() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0); + return out.writePair(ObjectClassIs(obj, ESClass_Array, context()) ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0); } bool @@ -1042,7 +1042,9 @@ JSStructuredCloneWriter::startWrite(HandleValue v) return writeTypedArray(obj); } else if (JS_IsArrayBufferObject(obj) && JS_ArrayBufferHasData(obj)) { return writeArrayBuffer(obj); - } else if (obj->is() || obj->is()) { + } else if (ObjectClassIs(obj, ESClass_Object, context())) { + return traverseObject(obj); + } else if (ObjectClassIs(obj, ESClass_Array, context())) { return traverseObject(obj); } else if (ObjectClassIs(obj, ESClass_Boolean, context())) { RootedValue unboxed(context()); From 650a9f4c18c6f333d3632e893a9f4503b4d48945 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:39 -0700 Subject: [PATCH 37/86] Bug 1050340 - Do a CheckedUnwrap in xpc::IsReflector. r=gabor This matches the behavior of UnwrapReflectorToISupports, and makes all of the structured clone callbacks scattered throughout Gecko compatible with wrappers that have not already had CheckedUnwrap invoked on them. --- js/xpconnect/src/ExportHelpers.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/js/xpconnect/src/ExportHelpers.cpp b/js/xpconnect/src/ExportHelpers.cpp index b1e208390f8..2ea1675929b 100644 --- a/js/xpconnect/src/ExportHelpers.cpp +++ b/js/xpconnect/src/ExportHelpers.cpp @@ -26,6 +26,9 @@ namespace xpc { bool IsReflector(JSObject *obj) { + obj = CheckedUnwrap(obj, /* stopAtOuter = */ false); + if (!obj) + return false; return IS_WN_REFLECTOR(obj) || dom::IsDOMObject(obj); } @@ -117,15 +120,11 @@ bool IsBlobOrFileList(JSObject *obj) static bool StackScopedCloneWrite(JSContext *cx, JSStructuredCloneWriter *writer, - Handle objArg, void *closure) + Handle obj, void *closure) { MOZ_ASSERT(closure, "Null pointer!"); StackScopedCloneData *cloneData = static_cast(closure); - // The SpiderMonkey structured clone machinery does a CheckedUnwrap, but - // doesn't strip off outer windows. Do that to avoid confusing the reflector - // detection. - RootedObject obj(cx, JS_ObjectToInnerObject(cx, objArg)); if ((cloneData->mOptions->wrapReflectors && IsReflector(obj)) || IsBlobOrFileList(obj)) { From 94a6e2c07227419363e2149f02348d53bbf0bae6 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:40 -0700 Subject: [PATCH 38/86] Bug 1050340 - Fix up content search test framework. r=adw --- browser/modules/test/contentSearch.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/browser/modules/test/contentSearch.js b/browser/modules/test/contentSearch.js index 3b7cc8a2288..c6bcd17d4cc 100644 --- a/browser/modules/test/contentSearch.js +++ b/browser/modules/test/contentSearch.js @@ -8,7 +8,12 @@ const CLIENT_EVENT_TYPE = "ContentSearchClient"; // Forward events from the in-content service to the test. content.addEventListener(SERVICE_EVENT_TYPE, event => { - sendAsyncMessage(TEST_MSG, event.detail); + // The event dispatch code in content.js clones the event detail into the + // content scope. That's generally the right thing, but causes us to end + // up with an XrayWrapper to it here, which will screw us up when trying to + // serialize the object in sendAsyncMessage. Waive Xrays for the benefit of + // the test machinery. + sendAsyncMessage(TEST_MSG, Components.utils.waiveXrays(event.detail)); }); // Forward messages from the test to the in-content service. From ba6f24c9d01414ea362df5d6f99c71a993be7865 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Mon, 18 Aug 2014 14:18:40 -0700 Subject: [PATCH 39/86] Bug 1050340 - Fix up cloning test. r=gabor This test currently assume that cloning a COW will fail. Once we always go over security wrappers, this isn't true anymore, because COWs silently deny disallowed property gets. So it makes sense to rewrite the test so that we can see what actually makes it through the structured clones. Promises galore. We also take out the buggy Blob/FileList stuff and replace it with ImageData, which does a bonafide clone in NS_DOMWriteStructuredClone instead of the weird pointer swapping we do in nsGlobalWindow.cpp (baku is in the process of cleaning that up, but it's not done yet). --- .../mochitest/chrome/test_clonewrapper.xul | 82 +++++++++---------- .../mochitest/general/file_clonewrapper.html | 19 +++-- 2 files changed, 54 insertions(+), 47 deletions(-) diff --git a/dom/tests/mochitest/chrome/test_clonewrapper.xul b/dom/tests/mochitest/chrome/test_clonewrapper.xul index e2d2b005e6b..ec4beec2861 100644 --- a/dom/tests/mochitest/chrome/test_clonewrapper.xul +++ b/dom/tests/mochitest/chrome/test_clonewrapper.xul @@ -13,6 +13,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=667388 -
diff --git a/editor/libeditor/html/tests/test_bug607584.html b/editor/libeditor/tests/test_bug607584.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug607584.html
rename to editor/libeditor/tests/test_bug607584.html
diff --git a/editor/libeditor/html/tests/test_bug607584.xul b/editor/libeditor/tests/test_bug607584.xul
similarity index 100%
rename from editor/libeditor/html/tests/test_bug607584.xul
rename to editor/libeditor/tests/test_bug607584.xul
diff --git a/editor/libeditor/html/tests/test_bug611182.html b/editor/libeditor/tests/test_bug611182.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug611182.html
rename to editor/libeditor/tests/test_bug611182.html
diff --git a/editor/libeditor/html/tests/test_bug612128.html b/editor/libeditor/tests/test_bug612128.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug612128.html
rename to editor/libeditor/tests/test_bug612128.html
diff --git a/editor/libeditor/html/tests/test_bug612447.html b/editor/libeditor/tests/test_bug612447.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug612447.html
rename to editor/libeditor/tests/test_bug612447.html
diff --git a/editor/libeditor/html/tests/test_bug616590.xul b/editor/libeditor/tests/test_bug616590.xul
similarity index 100%
rename from editor/libeditor/html/tests/test_bug616590.xul
rename to editor/libeditor/tests/test_bug616590.xul
diff --git a/editor/libeditor/html/tests/test_bug620906.html b/editor/libeditor/tests/test_bug620906.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug620906.html
rename to editor/libeditor/tests/test_bug620906.html
diff --git a/editor/libeditor/html/tests/test_bug622371.html b/editor/libeditor/tests/test_bug622371.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug622371.html
rename to editor/libeditor/tests/test_bug622371.html
diff --git a/editor/libeditor/html/tests/test_bug629845.html b/editor/libeditor/tests/test_bug629845.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug629845.html
rename to editor/libeditor/tests/test_bug629845.html
diff --git a/editor/libeditor/html/tests/test_bug635636.html b/editor/libeditor/tests/test_bug635636.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug635636.html
rename to editor/libeditor/tests/test_bug635636.html
diff --git a/editor/libeditor/html/tests/test_bug640321.html b/editor/libeditor/tests/test_bug640321.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug640321.html
rename to editor/libeditor/tests/test_bug640321.html
diff --git a/editor/libeditor/html/tests/test_bug668599.html b/editor/libeditor/tests/test_bug668599.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug668599.html
rename to editor/libeditor/tests/test_bug668599.html
diff --git a/editor/libeditor/html/tests/test_bug674770-1.html b/editor/libeditor/tests/test_bug674770-1.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug674770-1.html
rename to editor/libeditor/tests/test_bug674770-1.html
diff --git a/editor/libeditor/html/tests/test_bug674770-2.html b/editor/libeditor/tests/test_bug674770-2.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug674770-2.html
rename to editor/libeditor/tests/test_bug674770-2.html
diff --git a/editor/libeditor/html/tests/test_bug674861.html b/editor/libeditor/tests/test_bug674861.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug674861.html
rename to editor/libeditor/tests/test_bug674861.html
diff --git a/editor/libeditor/html/tests/test_bug676401.html b/editor/libeditor/tests/test_bug676401.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug676401.html
rename to editor/libeditor/tests/test_bug676401.html
diff --git a/editor/libeditor/html/tests/test_bug677752.html b/editor/libeditor/tests/test_bug677752.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug677752.html
rename to editor/libeditor/tests/test_bug677752.html
diff --git a/editor/libeditor/html/tests/test_bug686203.html b/editor/libeditor/tests/test_bug686203.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug686203.html
rename to editor/libeditor/tests/test_bug686203.html
diff --git a/editor/libeditor/html/tests/test_bug697842.html b/editor/libeditor/tests/test_bug697842.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug697842.html
rename to editor/libeditor/tests/test_bug697842.html
diff --git a/editor/libeditor/html/tests/test_bug725069.html b/editor/libeditor/tests/test_bug725069.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug725069.html
rename to editor/libeditor/tests/test_bug725069.html
diff --git a/editor/libeditor/html/tests/test_bug735059.html b/editor/libeditor/tests/test_bug735059.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug735059.html
rename to editor/libeditor/tests/test_bug735059.html
diff --git a/editor/libeditor/html/tests/test_bug738366.html b/editor/libeditor/tests/test_bug738366.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug738366.html
rename to editor/libeditor/tests/test_bug738366.html
diff --git a/editor/libeditor/html/tests/test_bug757371.html b/editor/libeditor/tests/test_bug757371.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug757371.html
rename to editor/libeditor/tests/test_bug757371.html
diff --git a/editor/libeditor/html/tests/test_bug767684.html b/editor/libeditor/tests/test_bug767684.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug767684.html
rename to editor/libeditor/tests/test_bug767684.html
diff --git a/editor/libeditor/html/tests/test_bug780035.html b/editor/libeditor/tests/test_bug780035.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug780035.html
rename to editor/libeditor/tests/test_bug780035.html
diff --git a/editor/libeditor/html/tests/test_bug780908.xul b/editor/libeditor/tests/test_bug780908.xul
similarity index 100%
rename from editor/libeditor/html/tests/test_bug780908.xul
rename to editor/libeditor/tests/test_bug780908.xul
diff --git a/editor/libeditor/html/tests/test_bug787432.html b/editor/libeditor/tests/test_bug787432.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug787432.html
rename to editor/libeditor/tests/test_bug787432.html
diff --git a/editor/libeditor/html/tests/test_bug790475.html b/editor/libeditor/tests/test_bug790475.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug790475.html
rename to editor/libeditor/tests/test_bug790475.html
diff --git a/editor/libeditor/html/tests/test_bug796839.html b/editor/libeditor/tests/test_bug796839.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug796839.html
rename to editor/libeditor/tests/test_bug796839.html
diff --git a/editor/libeditor/html/tests/test_bug832025.html b/editor/libeditor/tests/test_bug832025.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug832025.html
rename to editor/libeditor/tests/test_bug832025.html
diff --git a/editor/libeditor/html/tests/test_bug857487.html b/editor/libeditor/tests/test_bug857487.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug857487.html
rename to editor/libeditor/tests/test_bug857487.html
diff --git a/editor/libeditor/html/tests/test_bug966155.html b/editor/libeditor/tests/test_bug966155.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug966155.html
rename to editor/libeditor/tests/test_bug966155.html
diff --git a/editor/libeditor/html/tests/test_bug966552.html b/editor/libeditor/tests/test_bug966552.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug966552.html
rename to editor/libeditor/tests/test_bug966552.html
diff --git a/editor/libeditor/html/tests/test_bug998188.html b/editor/libeditor/tests/test_bug998188.html
similarity index 100%
rename from editor/libeditor/html/tests/test_bug998188.html
rename to editor/libeditor/tests/test_bug998188.html
diff --git a/editor/libeditor/html/tests/test_contenteditable_focus.html b/editor/libeditor/tests/test_contenteditable_focus.html
similarity index 100%
rename from editor/libeditor/html/tests/test_contenteditable_focus.html
rename to editor/libeditor/tests/test_contenteditable_focus.html
diff --git a/editor/libeditor/html/tests/test_contenteditable_text_input_handling.html b/editor/libeditor/tests/test_contenteditable_text_input_handling.html
similarity index 100%
rename from editor/libeditor/html/tests/test_contenteditable_text_input_handling.html
rename to editor/libeditor/tests/test_contenteditable_text_input_handling.html
diff --git a/editor/libeditor/html/tests/test_dom_input_event_on_htmleditor.html b/editor/libeditor/tests/test_dom_input_event_on_htmleditor.html
similarity index 100%
rename from editor/libeditor/html/tests/test_dom_input_event_on_htmleditor.html
rename to editor/libeditor/tests/test_dom_input_event_on_htmleditor.html
diff --git a/editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html b/editor/libeditor/tests/test_htmleditor_keyevent_handling.html
similarity index 100%
rename from editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
rename to editor/libeditor/tests/test_htmleditor_keyevent_handling.html
diff --git a/editor/libeditor/html/tests/test_keypress_untrusted_event.html b/editor/libeditor/tests/test_keypress_untrusted_event.html
similarity index 100%
rename from editor/libeditor/html/tests/test_keypress_untrusted_event.html
rename to editor/libeditor/tests/test_keypress_untrusted_event.html
diff --git a/editor/libeditor/html/tests/test_root_element_replacement.html b/editor/libeditor/tests/test_root_element_replacement.html
similarity index 100%
rename from editor/libeditor/html/tests/test_root_element_replacement.html
rename to editor/libeditor/tests/test_root_element_replacement.html
diff --git a/editor/libeditor/html/tests/test_select_all_without_body.html b/editor/libeditor/tests/test_select_all_without_body.html
similarity index 100%
rename from editor/libeditor/html/tests/test_select_all_without_body.html
rename to editor/libeditor/tests/test_select_all_without_body.html
diff --git a/editor/libeditor/html/tests/test_spellcheck_pref.html b/editor/libeditor/tests/test_spellcheck_pref.html
similarity index 100%
rename from editor/libeditor/html/tests/test_spellcheck_pref.html
rename to editor/libeditor/tests/test_spellcheck_pref.html
diff --git a/editor/libeditor/text/nsPlaintextEditor.cpp b/editor/libeditor/text/nsPlaintextEditor.cpp
index 2e73b99bdd7..3749c95e20a 100644
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -351,7 +351,7 @@ nsPlaintextEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
 {
   // NOTE: When you change this method, you should also change:
   //   * editor/libeditor/text/tests/test_texteditor_keyevent_handling.html
-  //   * editor/libeditor/html/tests/test_htmleditor_keyevent_handling.html
+  //   * editor/libeditor/tests/test_htmleditor_keyevent_handling.html
   //
   // And also when you add new key handling, you need to change the subclass's
   // HandleKeyPressEvent()'s switch statement.
diff --git a/layout/build/moz.build b/layout/build/moz.build
index 02b73404fd5..2c7e1e10289 100644
--- a/layout/build/moz.build
+++ b/layout/build/moz.build
@@ -66,7 +66,6 @@ LOCAL_INCLUDES += [
     '/dom/xslt/xslt',
     '/editor/composer',
     '/editor/libeditor',
-    '/editor/libeditor/html',
     '/editor/libeditor/text',
     '/editor/txmgr',
     '/editor/txtsvc',
diff --git a/parser/htmlparser/public/nsHTMLTagList.h b/parser/htmlparser/public/nsHTMLTagList.h
index 5b634744951..88be0453126 100644
--- a/parser/htmlparser/public/nsHTMLTagList.h
+++ b/parser/htmlparser/public/nsHTMLTagList.h
@@ -30,7 +30,7 @@
 
   Entries *must* use only lowercase characters.
 
-  Don't forget to update /editor/libeditor/html/nsHTMLEditUtils.cpp as well.
+  Don't forget to update /editor/libeditor/nsHTMLEditUtils.cpp as well.
 
   ** Break these invariants and bad things will happen. **
 

From 42c1c4e220393a0f3213ed7ab9ff17a83f140078 Mon Sep 17 00:00:00 2001
From: Chris Manchester 
Date: Thu, 10 Jul 2014 09:33:39 -0400
Subject: [PATCH 44/86] Bug 1034272 - Convert cppunittests to structured
 logging.;r=ted

---
 testing/mach_commands.py      | 14 ++++---
 testing/remotecppunittests.py | 30 +++++++++-----
 testing/runcppunittests.py    | 75 ++++++++++++++++++++++++-----------
 3 files changed, 80 insertions(+), 39 deletions(-)

diff --git a/testing/mach_commands.py b/testing/mach_commands.py
index 8dfb275e95e..5776ca2a045 100644
--- a/testing/mach_commands.py
+++ b/testing/mach_commands.py
@@ -253,8 +253,12 @@ class MachCommands(MachCommandBase):
             'executed.')
 
     def run_cppunit_test(self, **params):
+        from mozlog.structured import commandline
         import runcppunittests as cppunittests
-        import logging
+
+        log = commandline.setup_logging("cppunittest",
+                                        {},
+                                        {"tbpl": sys.stdout})
 
         if len(params['test_files']) == 0:
             testdir = os.path.join(self.distdir, 'cppunittests')
@@ -269,11 +273,9 @@ class MachCommands(MachCommandBase):
 
         tester = cppunittests.CPPUnitTests()
         try:
-            result = tester.run_tests(progs, self.bindir, symbols_path)
-        except Exception, e:
-            self.log(logging.ERROR, 'cppunittests',
-                {'exception': str(e)},
-                'Caught exception running cpp unit tests: {exception}')
+            result = tester.run_tests(progs, self.bindir, symbols_path, interactive=True)
+        except Exception as e:
+            log.error("Caught exception running cpp unit tests: %s" % str(e))
             result = False
 
         return 0 if result else 1
diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
index 607bf839d9a..ce45d239d4e 100644
--- a/testing/remotecppunittests.py
+++ b/testing/remotecppunittests.py
@@ -9,11 +9,12 @@ import subprocess
 import tempfile
 from zipfile import ZipFile
 import runcppunittests as cppunittests
-import mozcrash, mozlog
+import mozcrash
 import mozfile
 import StringIO
 import posixpath
 from mozdevice import devicemanager, devicemanagerADB, devicemanagerSUT
+from mozlog import structured
 
 try:
     from mozbuild.base import MozbuildObject
@@ -21,8 +22,6 @@ try:
 except ImportError:
     build_obj = None
 
-log = mozlog.getLogger('remotecppunittests')
-
 class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
     def __init__(self, devmgr, options, progs):
         cppunittests.CPPUnitTests.__init__(self)
@@ -110,11 +109,11 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
                 elif len(envdef_parts) == 1:
                     env[envdef_parts[0]] = ""
                 else:
-                    print >> sys.stderr, "warning: invalid --addEnv option skipped: "+envdef
+                    self.log.warning("invalid --addEnv option skipped: %s" % envdef)
 
         return env
 
-    def run_one_test(self, prog, env, symbols_path=None):
+    def run_one_test(self, prog, env, symbols_path=None, interactive=False):
         """
         Run a single C++ unit test program remotely.
 
@@ -128,21 +127,25 @@ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
         """
         basename = os.path.basename(prog)
         remote_bin = posixpath.join(self.remote_bin_dir, basename)
-        log.info("Running test %s", basename)
+        self.log.test_start(basename)
         buf = StringIO.StringIO()
         returncode = self.device.shell([remote_bin], buf, env=env, cwd=self.remote_home_dir,
                                        timeout=cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT)
-        print >> sys.stdout, buf.getvalue()
+        self.log.process_output(basename, "\n%s" % buf.getvalue(),
+                                command=[remote_bin])
         with mozfile.TemporaryDirectory() as tempdir:
             self.device.getDirectory(self.remote_home_dir, tempdir)
             if mozcrash.check_for_crashes(tempdir, symbols_path,
                                           test_name=basename):
-                log.testFail("%s | test crashed", basename)
+                self.log.test_end(basename, status='CRASH', expected='PASS')
                 return False
         result = returncode == 0
         if not result:
-            log.testFail("%s | test failed with return code %s",
-                         basename, returncode)
+            self.log.test_end(basename, status='FAIL', expected='PASS',
+                              message=("test failed with return code %d" %
+                                       returncode))
+        else:
+            self.log.test_end(basename, status='PASS', expected='PASS')
         return result
 
 class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
@@ -204,6 +207,7 @@ class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
 
 def main():
     parser = RemoteCPPUnittestOptions()
+    structured.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
     if not args:
         print >>sys.stderr, """Usage: %s  [...]""" % sys.argv[0]
@@ -243,6 +247,12 @@ def main():
         if not options.device_ip:
             print "Error: you must provide a device IP to connect to via the --deviceIP option"
             sys.exit(1)
+
+    log = structured.commandline.setup_logging("remotecppunittests",
+                                               options,
+                                               {"tbpl": sys.stdout})
+
+
     options.xre_path = os.path.abspath(options.xre_path)
     progs = cppunittests.extract_unittests_from_args(args, options.manifest_file)
     tester = RemoteCPPUnitTests(dm, options, progs)
diff --git a/testing/runcppunittests.py b/testing/runcppunittests.py
index a27cf761b6e..def44a31895 100644
--- a/testing/runcppunittests.py
+++ b/testing/runcppunittests.py
@@ -7,10 +7,13 @@
 from __future__ import with_statement
 import sys, os, tempfile, shutil
 from optparse import OptionParser
-import mozprocess, mozinfo, mozlog, mozcrash, mozfile
+import mozprocess
+import mozinfo
+import mozcrash
+import mozfile
 from contextlib import contextmanager
-
-log = mozlog.getLogger('cppunittests')
+from mozlog import structured
+from subprocess import PIPE
 
 class CPPUnitTests(object):
     # Time (seconds) to wait for test process to complete
@@ -18,7 +21,7 @@ class CPPUnitTests(object):
     # Time (seconds) in which process will be killed if it produces no output.
     TEST_PROC_NO_OUTPUT_TIMEOUT = 300
 
-    def run_one_test(self, prog, env, symbols_path=None):
+    def run_one_test(self, prog, env, symbols_path=None, interactive=False):
         """
         Run a single C++ unit test program.
 
@@ -31,28 +34,44 @@ class CPPUnitTests(object):
         Return True if the program exits with a zero status, False otherwise.
         """
         basename = os.path.basename(prog)
-        log.info("Running test %s", basename)
+        self.log.test_start(basename)
         with mozfile.TemporaryDirectory() as tempdir:
-            proc = mozprocess.ProcessHandler([prog],
-                                             cwd=tempdir,
-                                             env=env)
+            if interactive:
+                # For tests run locally, via mach, print output directly
+                proc = mozprocess.ProcessHandler([prog],
+                                                 cwd=tempdir,
+                                                 env=env,
+                                                 storeOutput=False)
+            else:
+                proc = mozprocess.ProcessHandler([prog],
+                                                 cwd=tempdir,
+                                                 env=env,
+                                                 storeOutput=True,
+                                                 processOutputLine=lambda _: None)
             #TODO: After bug 811320 is fixed, don't let .run() kill the process,
             # instead use a timeout in .wait() and then kill to get a stack.
             proc.run(timeout=CPPUnitTests.TEST_PROC_TIMEOUT,
                      outputTimeout=CPPUnitTests.TEST_PROC_NO_OUTPUT_TIMEOUT)
             proc.wait()
+            if proc.output:
+                output = "\n%s" % "\n".join(proc.output)
+                self.log.process_output(proc.pid, output, command=[prog])
             if proc.timedOut:
-                log.testFail("%s | timed out after %d seconds",
-                             basename, CPPUnitTests.TEST_PROC_TIMEOUT)
+                message = "timed out after %d seconds" % CPPUnitTests.TEST_PROC_TIMEOUT
+                self.log.test_end(basename, status='TIMEOUT', expected='PASS',
+                                  message=message)
                 return False
             if mozcrash.check_for_crashes(tempdir, symbols_path,
                                           test_name=basename):
-                log.testFail("%s | test crashed", basename)
+                self.log.test_end(basename, status='CRASH', expected='PASS')
                 return False
             result = proc.proc.returncode == 0
             if not result:
-                log.testFail("%s | test failed with return code %d",
-                             basename, proc.proc.returncode)
+                self.log.test_end(basename, status='FAIL', expected='PASS',
+                                  message=("test failed with return code %d" %
+                                           proc.proc.returncode))
+            else:
+                self.log.test_end(basename, status='PASS', expected='PASS')
             return result
 
     def build_core_environment(self, env = {}):
@@ -94,13 +113,13 @@ class CPPUnitTests(object):
         llvmsym = os.path.join(self.xre_path, "llvm-symbolizer")
         if os.path.isfile(llvmsym):
             env["ASAN_SYMBOLIZER_PATH"] = llvmsym
-            log.info("ASan using symbolizer at %s", llvmsym)
+            self.log.info("ASan using symbolizer at %s" % llvmsym)
         else:
-            log.info("Failed to find ASan symbolizer at %s", llvmsym)
+            self.log.info("Failed to find ASan symbolizer at %s" % llvmsym)
 
         return env
 
-    def run_tests(self, programs, xre_path, symbols_path=None):
+    def run_tests(self, programs, xre_path, symbols_path=None, interactive=False):
         """
         Run a set of C++ unit test programs.
 
@@ -114,19 +133,23 @@ class CPPUnitTests(object):
         otherwise.
         """
         self.xre_path = xre_path
+        self.log = structured.structuredlog.get_default_logger()
+        self.log.suite_start(programs)
         env = self.build_environment()
         pass_count = 0
         fail_count = 0
         for prog in programs:
-            single_result = self.run_one_test(prog, env, symbols_path)
+            single_result = self.run_one_test(prog, env, symbols_path, interactive)
             if single_result:
                 pass_count += 1
             else:
                 fail_count += 1
+        self.log.suite_end()
 
-        log.info("Result summary:")
-        log.info("Passed: %d" % pass_count)
-        log.info("Failed: %d" % fail_count)
+        # Mozharness-parseable summary formatting.
+        self.log.info("Result summary:")
+        self.log.info("cppunittests INFO | Passed: %d" % pass_count)
+        self.log.info("cppunittests INFO | Failed: %d" % fail_count)
         return fail_count == 0
 
 class CPPUnittestOptions(OptionParser):
@@ -171,6 +194,7 @@ def extract_unittests_from_args(args, manifest_file):
 
 def main():
     parser = CPPUnittestOptions()
+    structured.commandline.add_logging_group(parser)
     options, args = parser.parse_args()
     if not args:
         print >>sys.stderr, """Usage: %s  [...]""" % sys.argv[0]
@@ -178,17 +202,22 @@ def main():
     if not options.xre_path:
         print >>sys.stderr, """Error: --xre-path is required"""
         sys.exit(1)
-        
+
+    log = structured.commandline.setup_logging("cppunittests",
+                                               options,
+                                               {"tbpl": sys.stdout})
+
     progs = extract_unittests_from_args(args, options.manifest_file)
     options.xre_path = os.path.abspath(options.xre_path)
     tester = CPPUnitTests()
+
     try:
         result = tester.run_tests(progs, options.xre_path, options.symbols_path)
-    except Exception, e:
+    except Exception as e:
         log.error(str(e))
         result = False
+
     sys.exit(0 if result else 1)
 
 if __name__ == '__main__':
     main()
-

From 068850377e88aec08dddb67035882d37a347536b Mon Sep 17 00:00:00 2001
From: Nicholas Hurley 
Date: Mon, 18 Aug 2014 14:59:32 -0700
Subject: [PATCH 45/86] Bug 1054173 - Do not fail connections when receiving
 request headers. r=mcmanus

---
 netwerk/protocol/http/Http2Compression.cpp | 24 ++++++++++++----------
 netwerk/protocol/http/Http2Compression.h   |  3 ++-
 netwerk/protocol/http/Http2Session.cpp     |  2 +-
 netwerk/protocol/http/Http2Stream.cpp      |  4 ++--
 4 files changed, 18 insertions(+), 15 deletions(-)

diff --git a/netwerk/protocol/http/Http2Compression.cpp b/netwerk/protocol/http/Http2Compression.cpp
index d768a280544..ca988f1961f 100644
--- a/netwerk/protocol/http/Http2Compression.cpp
+++ b/netwerk/protocol/http/Http2Compression.cpp
@@ -243,7 +243,7 @@ Http2BaseCompressor::DumpState()
 
 nsresult
 Http2Decompressor::DecodeHeaderBlock(const uint8_t *data, uint32_t datalen,
-                                     nsACString &output)
+                                     nsACString &output, bool isPush)
 {
   mOffset = 0;
   mData = data;
@@ -256,6 +256,7 @@ Http2Decompressor::DecodeHeaderBlock(const uint8_t *data, uint32_t datalen,
   mHeaderPath.Truncate();
   mHeaderMethod.Truncate();
   mSeenNonColonHeader = false;
+  mIsPush = isPush;
 
   nsresult rv = NS_OK;
   while (NS_SUCCEEDED(rv) && (mOffset < datalen)) {
@@ -336,18 +337,19 @@ nsresult
 Http2Decompressor::OutputHeader(const nsACString &name, const nsACString &value)
 {
     // exclusions
-  if (name.EqualsLiteral("connection") ||
-      name.EqualsLiteral("host") ||
-      name.EqualsLiteral("keep-alive") ||
-      name.EqualsLiteral("proxy-connection") ||
-      name.EqualsLiteral("te") ||
-      name.EqualsLiteral("transfer-encoding") ||
-      name.EqualsLiteral("upgrade") ||
-      name.Equals(("accept-encoding"))) {
+  if (!mIsPush &&
+      (name.EqualsLiteral("connection") ||
+       name.EqualsLiteral("host") ||
+       name.EqualsLiteral("keep-alive") ||
+       name.EqualsLiteral("proxy-connection") ||
+       name.EqualsLiteral("te") ||
+       name.EqualsLiteral("transfer-encoding") ||
+       name.EqualsLiteral("upgrade") ||
+       name.Equals(("accept-encoding")))) {
     nsCString toLog(name);
-    LOG(("HTTP Decompressor illegal response header found : %s",
+    LOG(("HTTP Decompressor illegal response header found, not gatewaying: %s",
          toLog.get()));
-    return NS_ERROR_ILLEGAL_VALUE;
+    return NS_OK;
   }
 
   // Look for upper case characters in the name.
diff --git a/netwerk/protocol/http/Http2Compression.h b/netwerk/protocol/http/Http2Compression.h
index 6bc5f7d9a98..df104c04c70 100644
--- a/netwerk/protocol/http/Http2Compression.h
+++ b/netwerk/protocol/http/Http2Compression.h
@@ -84,7 +84,7 @@ public:
 
   // NS_OK: Produces the working set of HTTP/1 formatted headers
   nsresult DecodeHeaderBlock(const uint8_t *data, uint32_t datalen,
-                             nsACString &output);
+                             nsACString &output, bool isPush);
 
   void GetStatus(nsACString &hdr) { hdr = mHeaderStatus; }
   void GetHost(nsACString &hdr) { hdr = mHeaderHost; }
@@ -127,6 +127,7 @@ private:
   const uint8_t *mData;
   uint32_t mDataLen;
   bool mSeenNonColonHeader;
+  bool mIsPush;
 };
 
 
diff --git a/netwerk/protocol/http/Http2Session.cpp b/netwerk/protocol/http/Http2Session.cpp
index 030d92e4b44..6bc5e694bf6 100644
--- a/netwerk/protocol/http/Http2Session.cpp
+++ b/netwerk/protocol/http/Http2Session.cpp
@@ -661,7 +661,7 @@ Http2Session::UncompressAndDiscard()
   nsAutoCString trash;
 
   rv = mDecompressor.DecodeHeaderBlock(reinterpret_cast(mDecompressBuffer.BeginReading()),
-                                       mDecompressBuffer.Length(), trash);
+                                       mDecompressBuffer.Length(), trash, false);
   mDecompressBuffer.Truncate();
   if (NS_FAILED(rv)) {
     LOG3(("Http2Session::UncompressAndDiscard %p Compression Error\n",
diff --git a/netwerk/protocol/http/Http2Stream.cpp b/netwerk/protocol/http/Http2Stream.cpp
index b4295b13290..b078bef3540 100644
--- a/netwerk/protocol/http/Http2Stream.cpp
+++ b/netwerk/protocol/http/Http2Stream.cpp
@@ -848,7 +848,7 @@ Http2Stream::ConvertResponseHeaders(Http2Decompressor *decompressor,
   nsresult rv =
     decompressor->DecodeHeaderBlock(reinterpret_cast(aHeadersIn.BeginReading()),
                                     aHeadersIn.Length(),
-                                    aHeadersOut);
+                                    aHeadersOut, false);
   if (NS_FAILED(rv)) {
     LOG3(("Http2Stream::ConvertHeaders %p decode Error\n", this));
     return NS_ERROR_ILLEGAL_VALUE;
@@ -902,7 +902,7 @@ Http2Stream::ConvertPushHeaders(Http2Decompressor *decompressor,
   nsresult rv =
     decompressor->DecodeHeaderBlock(reinterpret_cast(aHeadersIn.BeginReading()),
                                     aHeadersIn.Length(),
-                                    aHeadersOut);
+                                    aHeadersOut, true);
   if (NS_FAILED(rv)) {
     LOG3(("Http2Stream::ConvertPushHeaders %p Error\n", this));
     return NS_ERROR_ILLEGAL_VALUE;

From ed9323def171c276e5249707b11c4c02b52a288a Mon Sep 17 00:00:00 2001
From: Chris Peterson 
Date: Sat, 9 Aug 2014 14:25:24 -0700
Subject: [PATCH 46/86] Bug 1052033 - Fix warnings in security/sandbox and mark
 as FAIL_ON_WARNINGS. r=smichaud

---
 security/sandbox/mac/Sandbox.mm | 6 +++---
 security/sandbox/mac/moz.build  | 2 ++
 security/sandbox/moz.build      | 9 +++++++++
 3 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/security/sandbox/mac/Sandbox.mm b/security/sandbox/mac/Sandbox.mm
index a3c90f3ef4e..331cc118f0c 100644
--- a/security/sandbox/mac/Sandbox.mm
+++ b/security/sandbox/mac/Sandbox.mm
@@ -16,7 +16,7 @@ extern "C" void sandbox_free_error(char *errorbuf);
 
 namespace mozilla {
 
-static const char *rules =
+static const char rules[] =
   "(version 1)\n"
   "(deny default)\n"
   "(allow signal (target self))\n"
@@ -39,7 +39,7 @@ static const char *rules =
 
 bool StartMacSandbox(MacSandboxInfo aInfo, nsCString &aErrorMessage)
 {
-  if (!aInfo.type == MacSandboxType_Plugin) {
+  if (aInfo.type != MacSandboxType_Plugin) {
     aErrorMessage.AppendPrintf("Unexpected sandbox type %u", aInfo.type);
     return false;
   }
@@ -60,7 +60,7 @@ bool StartMacSandbox(MacSandboxInfo aInfo, nsCString &aErrorMessage)
     if (errorbuf) {
       aErrorMessage.AppendPrintf("sandbox_init() failed with error \"%s\"",
                                  errorbuf);
-      printf(profile.get());
+      printf("profile: %s\n", profile.get());
       sandbox_free_error(errorbuf);
     }
     return false;
diff --git a/security/sandbox/mac/moz.build b/security/sandbox/mac/moz.build
index 87f70cc1a58..2b0c7d917e1 100644
--- a/security/sandbox/mac/moz.build
+++ b/security/sandbox/mac/moz.build
@@ -13,3 +13,5 @@ SOURCES += [
 ]
 
 FINAL_LIBRARY = 'xul'
+
+FAIL_ON_WARNINGS = True
diff --git a/security/sandbox/moz.build b/security/sandbox/moz.build
index f472a1759e6..cced08b51e9 100644
--- a/security/sandbox/moz.build
+++ b/security/sandbox/moz.build
@@ -140,3 +140,12 @@ elif CONFIG['OS_ARCH'] == 'WINNT':
     LOCAL_INCLUDES += ['/nsprpub']
 
     DISABLE_STL_WRAPPING = True
+
+    # Suppress warnings in third-party code.
+    if CONFIG['_MSC_VER']:
+        CXXFLAGS += [
+            '-wd4275', # non dll-interface class exception used as base for dll-interface class
+            '-wd4717', # recursive on all control paths, function will cause runtime stack overflow
+        ]
+
+FAIL_ON_WARNINGS = True

From 56216d903467e0346a3227e361774cb33e201a25 Mon Sep 17 00:00:00 2001
From: Chris Peterson 
Date: Tue, 18 Sep 2012 00:56:14 -0700
Subject: [PATCH 47/86] Bug 793978 - Alphabetize navigator.plugins and
 navigator.mimeTypes arrays to reduce fingerprintable entropy. r=bsmedberg

---
 dom/base/nsPluginArray.cpp | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/dom/base/nsPluginArray.cpp b/dom/base/nsPluginArray.cpp
index 3096c99f05d..15e73868b8b 100644
--- a/dom/base/nsPluginArray.cpp
+++ b/dom/base/nsPluginArray.cpp
@@ -81,6 +81,13 @@ GetPluginMimeTypes(const nsTArray >& aPlugins,
   }
 }
 
+static bool
+operator<(const nsRefPtr& lhs, const nsRefPtr& rhs)
+{
+  // Sort MIME types alphabetically by type name.
+  return lhs->Type() < rhs->Type();
+}
+
 void
 nsPluginArray::GetMimeTypes(nsTArray >& aMimeTypes,
                             nsTArray >& aHiddenMimeTypes)
@@ -96,6 +103,10 @@ nsPluginArray::GetMimeTypes(nsTArray >& aMimeTypes,
 
   GetPluginMimeTypes(mPlugins, aMimeTypes);
   GetPluginMimeTypes(mHiddenPlugins, aHiddenMimeTypes);
+
+  // Alphabetize the enumeration order of non-hidden MIME types to reduce
+  // fingerprintable entropy based on plugins' installation file times.
+  aMimeTypes.Sort();
 }
 
 nsPluginElement*
@@ -297,6 +308,14 @@ IsPluginEnumerable(const nsTArray& enumerableNames,
   return false; // hide plugin!
 }
 
+static bool
+operator<(const nsRefPtr& lhs,
+          const nsRefPtr& rhs)
+{
+  // Sort plugins alphabetically by name.
+  return lhs->PluginTag()->mName < rhs->PluginTag()->mName;
+}
+
 void
 nsPluginArray::EnsurePlugins()
 {
@@ -345,6 +364,10 @@ nsPluginArray::EnsurePlugins()
 
     pluginArray.AppendElement(new nsPluginElement(mWindow, pluginTag));
   }
+
+  // Alphabetize the enumeration order of non-hidden plugins to reduce
+  // fingerprintable entropy based on plugins' installation file times.
+  mPlugins.Sort();
 }
 
 // nsPluginElement implementation.

From d3551f8f02454425dff14e2a95fb0cf78458b3e2 Mon Sep 17 00:00:00 2001
From: Margaret Leibovic 
Date: Mon, 18 Aug 2014 13:41:31 -0700
Subject: [PATCH 48/86] Bug 1052563 - Don't capture clicks to dismiss search
 bar. r=eedens

---
 .../java/org/mozilla/search/MainActivity.java | 21 +++++-------
 .../autocomplete/ClearableEditText.java       | 11 ++++++-
 .../autocomplete/SuggestionsFragment.java     | 33 +++++++++++--------
 .../res/layout/search_activity_main.xml       | 17 +++-------
 .../search/res/layout/search_sugestions.xml   |  5 +--
 5 files changed, 45 insertions(+), 42 deletions(-)

diff --git a/mobile/android/search/java/org/mozilla/search/MainActivity.java b/mobile/android/search/java/org/mozilla/search/MainActivity.java
index f665375acb1..0b4076cc498 100644
--- a/mobile/android/search/java/org/mozilla/search/MainActivity.java
+++ b/mobile/android/search/java/org/mozilla/search/MainActivity.java
@@ -59,7 +59,7 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
     private View preSearch;
     private View postSearch;
 
-    private View suggestionsContainer;
+    private View suggestions;
     private SuggestionsFragment suggestionsFragment;
 
     private static final int SUGGESTION_TRANSITION_DURATION = 300;
@@ -109,22 +109,19 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
                     onSearch(trimmedQuery);
                 }
             }
+
+            @Override
+            public void onFocusChange(boolean hasFocus) {
+                setEditState(hasFocus ? EditState.EDITING : EditState.WAITING);
+            }
         });
 
         preSearch = findViewById(R.id.presearch);
         postSearch = findViewById(R.id.postsearch);
 
-        suggestionsContainer = findViewById(R.id.suggestions_container);
+        suggestions = findViewById(R.id.suggestions);
         suggestionsFragment = (SuggestionsFragment) getSupportFragmentManager().findFragmentById(R.id.suggestions);
 
-        // Dismiss edit mode when the user taps outside of the suggestions.
-        findViewById(R.id.suggestions_container).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                setEditState(EditState.WAITING);
-            }
-        });
-
         animationText = (TextView) findViewById(R.id.animation_text);
         animationCard = findViewById(R.id.animation_card);
 
@@ -159,7 +156,7 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
         preSearch = null;
         postSearch = null;
         suggestionsFragment = null;
-        suggestionsContainer = null;
+        suggestions = null;
         animationText = null;
         animationCard = null;
     }
@@ -299,7 +296,7 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
         this.editState = editState;
 
         editText.setActive(editState == EditState.EDITING);
-        suggestionsContainer.setVisibility(editState == EditState.EDITING ? View.VISIBLE : View.INVISIBLE);
+        suggestions.setVisibility(editState == EditState.EDITING ? View.VISIBLE : View.INVISIBLE);
     }
 
     private void setSearchState(SearchState searchState) {
diff --git a/mobile/android/search/java/org/mozilla/search/autocomplete/ClearableEditText.java b/mobile/android/search/java/org/mozilla/search/autocomplete/ClearableEditText.java
index 0ca8790d725..d234aee6e50 100644
--- a/mobile/android/search/java/org/mozilla/search/autocomplete/ClearableEditText.java
+++ b/mobile/android/search/java/org/mozilla/search/autocomplete/ClearableEditText.java
@@ -36,6 +36,7 @@ public class ClearableEditText extends FrameLayout {
     public interface TextListener {
         public void onChange(String text);
         public void onSubmit(String text);
+        public void onFocusChange(boolean hasFocus);
     }
 
     public ClearableEditText(Context context, AttributeSet attrs) {
@@ -65,7 +66,6 @@ public class ClearableEditText extends FrameLayout {
         editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
             @Override
             public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-
                 if (listener != null && actionId == EditorInfo.IME_ACTION_SEARCH) {
                     // The user searched without using search engine suggestions.
                     Telemetry.sendUIEvent(TelemetryContract.Event.SEARCH, TelemetryContract.Method.ACTIONBAR, "text");
@@ -76,6 +76,15 @@ public class ClearableEditText extends FrameLayout {
             }
         });
 
+        editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                if (listener != null) {
+                    listener.onFocusChange(hasFocus);
+                }
+            }
+        });
+
         clearButton = (ImageButton) findViewById(R.id.clear_button);
         clearButton.setOnClickListener(new View.OnClickListener(){
             @Override
diff --git a/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java b/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java
index f7ce0a948f3..4517cbd086b 100644
--- a/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java
+++ b/mobile/android/search/java/org/mozilla/search/autocomplete/SuggestionsFragment.java
@@ -63,7 +63,8 @@ public class SuggestionsFragment extends Fragment implements SearchEngineManager
 
     private AutoCompleteAdapter autoCompleteAdapter;
 
-    private ListView suggestionDropdown;
+    // Holds the list of search suggestions.
+    private ListView suggestionsList;
 
     public SuggestionsFragment() {
         // Required empty public constructor
@@ -110,14 +111,14 @@ public class SuggestionsFragment extends Fragment implements SearchEngineManager
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
-        suggestionDropdown = (ListView) inflater.inflate(R.layout.search_sugestions, container, false);
-        suggestionDropdown.setAdapter(autoCompleteAdapter);
+        suggestionsList = (ListView) inflater.inflate(R.layout.search_sugestions, container, false);
+        suggestionsList.setAdapter(autoCompleteAdapter);
 
         // Attach listener for tapping on a suggestion.
-        suggestionDropdown.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+        suggestionsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
             @Override
             public void onItemClick(AdapterView parent, View view, int position, long id) {
-                final Suggestion suggestion = (Suggestion) suggestionDropdown.getItemAtPosition(position);
+                final Suggestion suggestion = (Suggestion) suggestionsList.getItemAtPosition(position);
 
                 final Rect startBounds = new Rect();
                 view.getGlobalVisibleRect(startBounds);
@@ -134,17 +135,17 @@ public class SuggestionsFragment extends Fragment implements SearchEngineManager
             }
         });
 
-        return suggestionDropdown;
+        return suggestionsList;
     }
 
     @Override
     public void onDestroyView() {
         super.onDestroyView();
 
-        if (null != suggestionDropdown) {
-            suggestionDropdown.setOnItemClickListener(null);
-            suggestionDropdown.setAdapter(null);
-            suggestionDropdown = null;
+        if (null != suggestionsList) {
+            suggestionsList.setOnItemClickListener(null);
+            suggestionsList.setAdapter(null);
+            suggestionsList = null;
         }
     }
 
@@ -204,13 +205,17 @@ public class SuggestionsFragment extends Fragment implements SearchEngineManager
 
         @Override
         public void onLoadFinished(Loader> loader, List suggestions) {
-            autoCompleteAdapter.update(suggestions);
+            // Only show the ListView if there are suggestions in it.
+            if (suggestions.size() > 0) {
+                autoCompleteAdapter.update(suggestions);
+                suggestionsList.setVisibility(View.VISIBLE);
+            } else {
+                suggestionsList.setVisibility(View.INVISIBLE);
+            }
         }
 
         @Override
-        public void onLoaderReset(Loader> loader) {
-            autoCompleteAdapter.update(null);
-        }
+        public void onLoaderReset(Loader> loader) { }
     }
 
     private static class SuggestionAsyncLoader extends AsyncTaskLoader> {
diff --git a/mobile/android/search/res/layout/search_activity_main.xml b/mobile/android/search/res/layout/search_activity_main.xml
index 638e638bc85..6572b1aa78e 100644
--- a/mobile/android/search/res/layout/search_activity_main.xml
+++ b/mobile/android/search/res/layout/search_activity_main.xml
@@ -34,22 +34,13 @@
         android:layout_marginTop="@dimen/search_bar_height"
         android:layout_gravity="top"/>
 
-    
-
-        
-
-    
+        android:layout_gravity="top"/>
 
     
+    android:listSelector="@android:color/transparent"
+    android:visibility="invisible"/>

From 2cb26ed54daa25c5a3288bc8195dc173d0d844bb Mon Sep 17 00:00:00 2001
From: Mihaela Velimiroviciu 
Date: Fri, 1 Aug 2014 15:32:01 +0300
Subject: [PATCH 49/86] Bug 983636 - Update tests to support testing of adding
 duplicate properties. r=jryans

---
 .../test/browser_manifest_editor.js           | 27 ++++++++++++-------
 .../devtools/app-manager/test/manifest.webapp |  3 +++
 2 files changed, 21 insertions(+), 9 deletions(-)

diff --git a/browser/devtools/app-manager/test/browser_manifest_editor.js b/browser/devtools/app-manager/test/browser_manifest_editor.js
index 434b5ab7d35..676eff6f108 100644
--- a/browser/devtools/app-manager/test/browser_manifest_editor.js
+++ b/browser/devtools/app-manager/test/browser_manifest_editor.js
@@ -23,6 +23,13 @@ function test() {
     yield changeManifestValue("name", "the best app");
     yield changeManifestValueBad("name", "the worst app");
     yield addNewManifestProperty("developer", "foo", "bar");
+
+    // add duplicate property in the same parent doesn't create duplicates
+    yield addNewManifestProperty("developer", "foo", "bar2");
+
+    // add propery with same key in other parent is allowed
+    yield addNewManifestProperty("tester", "foo", "new");
+
     yield addNewManifestPropertyBad("developer", "blob", "bob");
     yield removeManifestProperty("developer", "foo");
     gManifestWindow = null;
@@ -94,15 +101,14 @@ function changeManifestValueBad(key, value) {
 }
 
 function addNewManifestProperty(parent, key, value) {
+  info("Adding new property - parent: " + parent + "; key: " + key + "; value: " + value + "\n\n");
   return Task.spawn(function() {
     let parentElem = gManifestWindow.document
                      .querySelector("[id ^= '" + parent + "']");
-    ok(parentElem,
-      "Found parent element");
-    let addPropertyElem = parentElem
-                          .querySelector(".variables-view-add-property");
-    ok(addPropertyElem,
-      "Found add-property button");
+    ok(parentElem, "Found parent element: " + parentElem.id);
+
+    let addPropertyElem = parentElem.querySelector(".variables-view-add-property");
+    ok(addPropertyElem, "Found add-property button");
 
     EventUtils.sendMouseEvent({ type: "mousedown" }, addPropertyElem, gManifestWindow);
 
@@ -116,10 +122,13 @@ function addNewManifestProperty(parent, key, value) {
 
     yield waitForUpdate();
 
-    let newElem = gManifestWindow.document.querySelector("[id ^= '" + key + "']");
+    parentElem = gManifestWindow.document.querySelector("[id ^= '" + parent + "']");
+    let elems = parentElem.querySelectorAll("[id ^= '" + key + "']");
+    is(elems.length, 1, "No duplicate property is added");
+
+    let newElem = elems[0];
     let nameElem = newElem.querySelector(".name");
-    is(nameElem.value, key,
-       "Key doesn't match expected Key");
+    is(nameElem.value, key, "Key doesn't match expected Key");
 
     ok(key in gManifestEditor.manifest[parent],
        "Manifest doesn't contain expected key");
diff --git a/browser/devtools/app-manager/test/manifest.webapp b/browser/devtools/app-manager/test/manifest.webapp
index 44702852c00..caa670bf470 100644
--- a/browser/devtools/app-manager/test/manifest.webapp
+++ b/browser/devtools/app-manager/test/manifest.webapp
@@ -2,5 +2,8 @@
   "name": "My packaged app",
   "developer": {
     "name": "Foo Bar"
+  },
+  "tester" : {
+    "who": "qa"
   }
 }

From c5a0983c40e9e76dac28107dd8e916ef6b12ee09 Mon Sep 17 00:00:00 2001
From: Rob Campbell 
Date: Mon, 18 Aug 2014 10:02:00 -0400
Subject: [PATCH 50/86] Bug 1003153 - Make it easier to close the sidebar. r=vp

---
 .../devtools/netmonitor/netmonitor-view.js    | 37 ++++++++++++++++++-
 .../test/browser_net_accessibility-02.js      | 17 ++++++++-
 .../devtools/shared/widgets/ViewHelpers.jsm   | 15 +++++++-
 3 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/browser/devtools/netmonitor/netmonitor-view.js b/browser/devtools/netmonitor/netmonitor-view.js
index ea48c9e56e0..aed3a335b46 100644
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -75,6 +75,7 @@ let NetMonitorView = {
     this.RequestsMenu.initialize();
     this.NetworkDetails.initialize();
     this.CustomRequest.initialize();
+    this.arrowClosed = false;
   },
 
   /**
@@ -308,12 +309,16 @@ ToolbarView.prototype = {
     let requestsMenu = NetMonitorView.RequestsMenu;
     let selectedIndex = requestsMenu.selectedIndex;
 
+    // Allow opening the sidebar if it was previously closed with an arrow key.
+    requestsMenu.arrowClosed = false;
+
     // Make sure there's a selection if the button is pressed, to avoid
     // showing an empty network details pane.
+    // If there is a selection, toggle the sidebar.
     if (selectedIndex == -1 && requestsMenu.itemCount) {
       requestsMenu.selectedIndex = 0;
     } else {
-      requestsMenu.selectedIndex = -1;
+      NetMonitorView.Sidebar.toggle(NetMonitorView.detailsPaneHidden);
     }
   },
 
@@ -385,6 +390,9 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
     $("#request-menu-context-copy-url").addEventListener("command", this._onContextCopyUrlCommand, false);
     $("#request-menu-context-copy-image-as-data-uri").addEventListener("command", this._onContextCopyImageAsDataUriCommand, false);
 
+    this.ignoreLeftRight = true;
+    this.widget.on("keyPress", this._handleKeyPress.bind(this));
+
     window.once("connected", this._onConnect.bind(this));
   },
 
@@ -733,6 +741,29 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
     }
   },
 
+  /**
+   * Handler to allow keyboard controls to close the Sidebar.
+   * Left|Return: open
+   * Right: close
+   *
+   * @param string aName
+   *        Name of the Event
+   * @param nsIDOMEvent aEvent
+   */
+  _handleKeyPress: function(aName, aEvent) {
+    switch (aEvent.keyCode) {
+      case aEvent.DOM_VK_RETURN:
+      case aEvent.DOM_VK_LEFT:
+        NetMonitorView.Sidebar.toggle(true);
+        this.arrowClosed = false;
+        return;
+      case aEvent.DOM_VK_RIGHT:
+        NetMonitorView.Sidebar.toggle(false);
+        this.arrowClosed = true;
+        return;
+    }
+  },
+
   /**
    * Returns a predicate that can be used to test if a request matches any of
    * the active filters.
@@ -1546,6 +1577,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
    * The selection listener for this container.
    */
   _onSelect: function({ detail: item }) {
+    if (this.arrowClosed) {
+      return;
+    }
+
     if (item) {
       NetMonitorView.Sidebar.populate(item.attachment);
       NetMonitorView.Sidebar.toggle(true);
diff --git a/browser/devtools/netmonitor/test/browser_net_accessibility-02.js b/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
index 0ec5490a274..5a0ad781237 100644
--- a/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
@@ -25,6 +25,11 @@ function test() {
       EventUtils.sendKey("UP", window);
       check(0, true);
 
+      EventUtils.sendKey("RIGHT", window);
+      check(0, false);
+      EventUtils.sendKey("LEFT", window);
+      check(0, true);
+
       EventUtils.sendKey("PAGE_DOWN", window);
       check(1, true);
       EventUtils.sendKey("PAGE_UP", window);
@@ -52,16 +57,24 @@ function test() {
       check(4, true);
       EventUtils.sendKey("PAGE_DOWN", window);
       check(8, true);
+      EventUtils.sendKey("RIGHT", window);
+      check(8, false);
       EventUtils.sendKey("PAGE_UP", window);
+      check(4, false);
+      EventUtils.sendKey("LEFT", window);
       check(4, true);
       EventUtils.sendKey("PAGE_UP", window);
       check(0, true);
 
       EventUtils.sendKey("HOME", window);
       check(0, true);
+      EventUtils.sendKey("RIGHT", window);
+      check(0, false);
       EventUtils.sendKey("HOME", window);
-      check(0, true);
+      check(0, false);
       EventUtils.sendKey("PAGE_UP", window);
+      check(0, false);
+      EventUtils.sendKey("RETURN", window);
       check(0, true);
       EventUtils.sendKey("HOME", window);
       check(0, true);
@@ -102,7 +115,7 @@ function test() {
       check(19, true);
 
       EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
-      check(-1, false);
+      check(19, false);
 
       EventUtils.sendMouseEvent({ type: "mousedown" }, $(".side-menu-widget-item"));
       check(0, true);
diff --git a/browser/devtools/shared/widgets/ViewHelpers.jsm b/browser/devtools/shared/widgets/ViewHelpers.jsm
index 68b4be71259..af2f24a86ef 100644
--- a/browser/devtools/shared/widgets/ViewHelpers.jsm
+++ b/browser/devtools/shared/widgets/ViewHelpers.jsm
@@ -1181,6 +1181,13 @@ this.WidgetMethods = {
    */
   autoFocusOnInput: true,
 
+  /**
+   * Ignore Left and Right keypresses.
+   *
+   * If this flag is set to true, Widgets should implement their own handler.
+   */
+  ignoreLeftRight: false,
+
   /**
    * When focusing on input, allow right clicks?
    * @see WidgetMethods.autoFocusOnInput
@@ -1634,13 +1641,17 @@ this.WidgetMethods = {
 
     switch (aEvent.keyCode) {
       case aEvent.DOM_VK_UP:
-      case aEvent.DOM_VK_LEFT:
         this.focusPrevItem();
         return;
       case aEvent.DOM_VK_DOWN:
-      case aEvent.DOM_VK_RIGHT:
         this.focusNextItem();
         return;
+      case aEvent.DOM_VK_LEFT:
+        if (!this.ignoreLeftRight) this.focusPrevItem();
+        return;
+      case aEvent.DOM_VK_RIGHT:
+        if (!this.ignoreLeftRight) this.focusNextItem();
+        return;
       case aEvent.DOM_VK_PAGE_UP:
         this.focusItemAtDelta(-(this.pageSize || (this.itemCount / PAGE_SIZE_ITEM_COUNT_RATIO)));
         return;

From e606415606ee079ab30d56e3ce24a9de5c81f55a Mon Sep 17 00:00:00 2001
From: Jan Keromnes 
Date: Mon, 18 Aug 2014 06:14:00 -0400
Subject: [PATCH 51/86] Bug 1049835 - Don't require actor clients to have a
 detach method. r=ochameau

---
 browser/devtools/webide/content/monitor.js           |  1 -
 toolkit/devtools/client/dbg-client.jsm               | 12 ++++++------
 .../devtools/server/tests/unit/test_monitor_actor.js |  1 -
 3 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/browser/devtools/webide/content/monitor.js b/browser/devtools/webide/content/monitor.js
index b2ee9884949..8c6562899fa 100644
--- a/browser/devtools/webide/content/monitor.js
+++ b/browser/devtools/webide/content/monitor.js
@@ -295,7 +295,6 @@ function MonitorClient(client, form) {
 MonitorClient.prototype.destroy = function () {
   this.client.unregisterClient(this);
 }
-MonitorClient.prototype.detach = function () {}
 MonitorClient.prototype.start = function () {
   this.client.request({
     to: this.actor,
diff --git a/toolkit/devtools/client/dbg-client.jsm b/toolkit/devtools/client/dbg-client.jsm
index a5ec414fa17..1b31d302084 100644
--- a/toolkit/devtools/client/dbg-client.jsm
+++ b/toolkit/devtools/client/dbg-client.jsm
@@ -420,7 +420,11 @@ DebuggerClient.prototype = {
         this._transport = null;
         return;
       }
-      client.detach(detachClients);
+      if (client.detach) {
+        client.detach(detachClients);
+        return;
+      }
+      detachClients();
     };
     detachClients();
   },
@@ -1008,13 +1012,9 @@ DebuggerClient.prototype = {
     }
     if (client.events.length > 0 && typeof(client.emit) != "function") {
       throw new Error("DebuggerServer.registerClient expects " +
-                      "client instances with non-empty `events` array to" +
+                      "a client instance with non-empty `events` array to" +
                       "have an `emit` function.");
     }
-    if (typeof(client.detach) != "function") {
-      throw new Error("DebuggerServer.registerClient expects " +
-                      "a client instance with a `detach` function.");
-    }
     if (this._clients.has(actorID)) {
       throw new Error("DebuggerServer.registerClient already registered " +
                       "a client for this actor.");
diff --git a/toolkit/devtools/server/tests/unit/test_monitor_actor.js b/toolkit/devtools/server/tests/unit/test_monitor_actor.js
index f15aa31f66d..817bcd58658 100644
--- a/toolkit/devtools/server/tests/unit/test_monitor_actor.js
+++ b/toolkit/devtools/server/tests/unit/test_monitor_actor.js
@@ -27,7 +27,6 @@ function run_test()
   MonitorClient.prototype.destroy = function () {
     client.unregisterClient(this);
   }
-  MonitorClient.prototype.detach = function () {}
   MonitorClient.prototype.start = function (callback) {
     this.client.request({
       to: this.actor,

From 998635ec5321ed088e572e5bd72eedc054d75b64 Mon Sep 17 00:00:00 2001
From: "J. Ryan Stinnett" 
Date: Fri, 15 Aug 2014 15:33:00 -0400
Subject: [PATCH 52/86] Bug 1054006 - Set chrome prefs in Browser Toolbox.
 r=bgrins

---
 browser/devtools/framework/toolbox-process-window.js | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/browser/devtools/framework/toolbox-process-window.js b/browser/devtools/framework/toolbox-process-window.js
index 460ecc973d1..c53a79c110c 100644
--- a/browser/devtools/framework/toolbox-process-window.js
+++ b/browser/devtools/framework/toolbox-process-window.js
@@ -49,9 +49,16 @@ function connect() {
   });
 }
 
+// Certain options should be toggled since we can assume chrome debugging here
+function setPrefDefaults() {
+  Services.prefs.setBoolPref("devtools.inspector.showUserAgentStyles", true);
+  Services.prefs.setBoolPref("devtools.profiler.ui.show-platform-data", true);
+}
+
 window.addEventListener("load", function() {
   let cmdClose = document.getElementById("toolbox-cmd-close");
   cmdClose.addEventListener("command", onCloseCommand);
+  setPrefDefaults();
   connect();
 });
 

From c78ed659932f5e9e59cc5349cf6424541c59ed81 Mon Sep 17 00:00:00 2001
From: Matthew Noorenberghe 
Date: Mon, 18 Aug 2014 14:32:34 -0700
Subject: [PATCH 53/86] Bug 1047130 - Implement desktop backend to login to FxA
 via OAuth for Loop. r=vladikoff,ckarlof,mikedeboer

This implements the OAuth authorization phase.
---
 browser/components/loop/MozLoopService.jsm    | 109 +++++++++++++++++-
 browser/components/loop/moz.build             |   5 +-
 .../loop/test/mochitest/browser.ini           |   3 +
 .../loop/test/mochitest/browser_fxa_login.js  |  92 +++++++++++++++
 .../components/loop/test/mochitest/head.js    |   2 +-
 .../loop/test/mochitest/loop_fxa.sjs          |  16 ++-
 services/fxaccounts/FxAccountsOAuthClient.jsm |  26 +++--
 7 files changed, 241 insertions(+), 12 deletions(-)
 create mode 100644 browser/components/loop/test/mochitest/browser_fxa_login.js

diff --git a/browser/components/loop/MozLoopService.jsm b/browser/components/loop/MozLoopService.jsm
index 7f1c611f863..4c2325dd76e 100644
--- a/browser/components/loop/MozLoopService.jsm
+++ b/browser/components/loop/MozLoopService.jsm
@@ -14,6 +14,8 @@ Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/osfile.jsm", this);
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/FxAccountsOAuthClient.jsm");
 
 this.EXPORTED_SYMBOLS = ["MozLoopService"];
 
@@ -56,6 +58,8 @@ let gHawkClient = null;
 let gRegisteredLoopServer = false;
 let gLocalizedStrings =  null;
 let gInitializeTimer = null;
+let gFxAOAuthClientPromise = null;
+let gFxAOAuthClient = null;
 
 /**
  * Internal helper methods and state
@@ -449,7 +453,86 @@ let MozLoopServiceInternal = {
     };
 
     Chat.open(contentWindow, origin, title, url, undefined, undefined, callback);
-  }
+  },
+
+  /**
+   * Fetch Firefox Accounts (FxA) OAuth parameters from the Loop Server.
+   *
+   * @return {Promise} resolved with the body of the hawk request for OAuth parameters.
+   */
+  promiseFxAOAuthParameters: function() {
+    return this.hawkRequest("/fxa-oauth/params", "POST").then(response => {
+      return JSON.parse(response.body);
+    });
+  },
+
+  /**
+   * Get the OAuth client constructed with Loop OAauth parameters.
+   *
+   * @return {Promise}
+   */
+  promiseFxAOAuthClient: Task.async(function* () {
+    // We must make sure to have only a single client otherwise they will have different states and
+    // multiple channels. This would happen if the user clicks the Login button more than once.
+    if (gFxAOAuthClientPromise) {
+      return gFxAOAuthClientPromise;
+    }
+
+    gFxAOAuthClientPromise = this.promiseFxAOAuthParameters().then(
+      parameters => {
+        try {
+          gFxAOAuthClient = new FxAccountsOAuthClient({
+            parameters: parameters,
+          });
+        } catch (ex) {
+          gFxAOAuthClientPromise = null;
+          throw ex;
+        }
+        return gFxAOAuthClient;
+      },
+      error => {
+        gFxAOAuthClientPromise = null;
+        return error;
+      }
+    );
+
+    return gFxAOAuthClientPromise;
+  }),
+
+  /**
+   * Params => web flow => code
+   */
+  promiseFxAOAuthAuthorization: function() {
+    let deferred = Promise.defer();
+    this.promiseFxAOAuthClient().then(
+      client => {
+        client.onComplete = this._fxAOAuthComplete.bind(this, deferred);
+        client.launchWebFlow();
+      },
+      error => {
+        Cu.reportError(error);
+        deferred.reject(error);
+      }
+    );
+    return deferred.promise;
+  },
+
+  /**
+   * Called once gFxAOAuthClient fires onComplete.
+   *
+   * @param {Deferred} deferred used to resolve or reject the gFxAOAuthClientPromise
+   * @param {Object} result (with code and state)
+   */
+  _fxAOAuthComplete: function(deferred, result) {
+    gFxAOAuthClientPromise = null;
+
+    // Note: The state was already verified in FxAccountsOAuthClient.
+    if (result) {
+      deferred.resolve(result);
+    } else {
+      deferred.reject("Invalid token data");
+    }
+  },
 };
 Object.freeze(MozLoopServiceInternal);
 
@@ -469,6 +552,17 @@ let gInitializeTimerFunc = () => {
  * Public API
  */
 this.MozLoopService = {
+#ifdef DEBUG
+  // Test-only helpers
+  get internal() {
+    return MozLoopServiceInternal;
+  },
+
+  resetFxA: function() {
+    gFxAOAuthClientPromise = null;
+  },
+#endif
+
   set initializeTimerFunc(value) {
     gInitializeTimerFunc = value;
   },
@@ -636,6 +730,19 @@ this.MozLoopService = {
     }
   },
 
+  /**
+   * Start the FxA login flow using the OAuth client and params from the Loop server.
+   *
+   * The caller should be prepared to handle rejections related to network, server or login errors.
+   *
+   * @return {Promise} that resolves when the FxA login flow is complete.
+   */
+  logInToFxA: function() {
+    return MozLoopServiceInternal.promiseFxAOAuthAuthorization().then(response => {
+      return MozLoopServiceInternal.promiseFxAOAuthToken(response.code, response.state);
+    });
+  },
+
   /**
    * Performs a hawk based request to the loop server.
    *
diff --git a/browser/components/loop/moz.build b/browser/components/loop/moz.build
index a03b8a94581..b1beaecd09e 100644
--- a/browser/components/loop/moz.build
+++ b/browser/components/loop/moz.build
@@ -15,6 +15,9 @@ BROWSER_CHROME_MANIFESTS += [
 EXTRA_JS_MODULES.loop += [
     'MozLoopAPI.jsm',
     'MozLoopPushHandler.jsm',
-    'MozLoopService.jsm',
     'MozLoopWorker.js',
 ]
+
+EXTRA_PP_JS_MODULES.loop += [
+    'MozLoopService.jsm',
+]
diff --git a/browser/components/loop/test/mochitest/browser.ini b/browser/components/loop/test/mochitest/browser.ini
index 4623fc6aa50..fb7377a5a00 100644
--- a/browser/components/loop/test/mochitest/browser.ini
+++ b/browser/components/loop/test/mochitest/browser.ini
@@ -2,7 +2,10 @@
 support-files =
     head.js
     loop_fxa.sjs
+    ../../../../base/content/test/general/browser_fxa_oauth.html
 
+[browser_fxa_login.js]
+skip-if = !debug
 [browser_loop_fxa_server.js]
 [browser_mozLoop_appVersionInfo.js]
 [browser_mozLoop_prefs.js]
diff --git a/browser/components/loop/test/mochitest/browser_fxa_login.js b/browser/components/loop/test/mochitest/browser_fxa_login.js
new file mode 100644
index 00000000000..35640976ea2
--- /dev/null
+++ b/browser/components/loop/test/mochitest/browser_fxa_login.js
@@ -0,0 +1,92 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test FxA logins with Loop.
+ */
+
+"use strict";
+
+const BASE_URL = "http://mochi.test:8888/browser/browser/components/loop/test/mochitest/loop_fxa.sjs?";
+
+add_task(function* setup() {
+  Services.prefs.setCharPref("loop.server", BASE_URL);
+  Services.prefs.setCharPref("services.push.serverURL", "ws://localhost/");
+  registerCleanupFunction(function* () {
+    info("cleanup time");
+    yield promiseDeletedOAuthParams(BASE_URL);
+    Services.prefs.clearUserPref("loop.server");
+    Services.prefs.clearUserPref("services.push.serverURL");
+  });
+});
+
+add_task(function* checkOAuthParams() {
+  let params = {
+    client_id: "client_id",
+    content_uri: BASE_URL + "/content",
+    oauth_uri: BASE_URL + "/oauth",
+    profile_uri: BASE_URL + "/profile",
+    state: "state",
+  };
+  yield promiseOAuthParamsSetup(BASE_URL, params);
+  let client = yield MozLoopService.internal.promiseFxAOAuthClient();
+  for (let key of Object.keys(params)) {
+    ise(client.parameters[key], params[key], "Check " + key + " was passed to the OAuth client");
+  }
+});
+
+add_task(function* basicAuthorization() {
+  let result = yield MozLoopService.internal.promiseFxAOAuthAuthorization();
+  is(result.code, "code1", "Check code");
+  is(result.state, "state", "Check state");
+});
+
+add_task(function* sameOAuthClientForTwoCalls() {
+  MozLoopService.resetFxA();
+  let client1 = yield MozLoopService.internal.promiseFxAOAuthClient();
+  let client2 = yield MozLoopService.internal.promiseFxAOAuthClient();
+  ise(client1, client2, "The same client should be returned");
+});
+
+add_task(function* paramsInvalid() {
+  MozLoopService.resetFxA();
+  // Delete the params so an empty object is returned.
+  yield promiseDeletedOAuthParams(BASE_URL);
+  let result = null;
+  let loginPromise = MozLoopService.logInToFxA();
+  let caught = false;
+  yield loginPromise.catch(() => {
+    ok(true, "The login promise should be rejected due to invalid params");
+    caught = true;
+  });
+  ok(caught, "Should have caught the rejection");
+  is(result, null, "No token data should be returned");
+});
+
+add_task(function* params_nonJSON() {
+  MozLoopService.resetFxA();
+  Services.prefs.setCharPref("loop.server", "https://loop.invalid");
+  let result = null;
+  let loginPromise = MozLoopService.logInToFxA();
+  yield loginPromise.catch(() => {
+    ok(true, "The login promise should be rejected due to non-JSON params");
+  });
+  is(result, null, "No token data should be returned");
+  Services.prefs.setCharPref("loop.server", BASE_URL);
+});
+
+add_task(function* invalidState() {
+  MozLoopService.resetFxA();
+  let params = {
+    client_id: "client_id",
+    content_uri: BASE_URL + "/content",
+    oauth_uri: BASE_URL + "/oauth",
+    profile_uri: BASE_URL + "/profile",
+    state: "invalid_state",
+  };
+  yield promiseOAuthParamsSetup(BASE_URL, params);
+  let loginPromise = MozLoopService.logInToFxA();
+  yield loginPromise.catch((error) => {
+    ok(error, "The login promise should be rejected due to invalid state");
+  });
+});
diff --git a/browser/components/loop/test/mochitest/head.js b/browser/components/loop/test/mochitest/head.js
index 934125fe7b1..993753a5959 100644
--- a/browser/components/loop/test/mochitest/head.js
+++ b/browser/components/loop/test/mochitest/head.js
@@ -89,7 +89,7 @@ function promiseDeletedOAuthParams(baseURL) {
               createInstance(Ci.nsIXMLHttpRequest);
   xhr.open("DELETE", baseURL + "/setup_params", true);
   xhr.addEventListener("load", () => deferred.resolve(xhr));
-  xhr.addEventListener("error", error => deferred.reject(error));
+  xhr.addEventListener("error", deferred.reject);
   xhr.send();
 
   return deferred.promise;
diff --git a/browser/components/loop/test/mochitest/loop_fxa.sjs b/browser/components/loop/test/mochitest/loop_fxa.sjs
index d2e72a81d33..72a239d8d1c 100644
--- a/browser/components/loop/test/mochitest/loop_fxa.sjs
+++ b/browser/components/loop/test/mochitest/loop_fxa.sjs
@@ -15,13 +15,17 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm");
  * Entry point for HTTP requests.
  */
 function handleRequest(request, response) {
-  switch (request.queryString) {
+  // Look at the query string but ignore past the encoded ? when deciding on the handler.
+  switch (request.queryString.replace(/%3F.*/,"")) {
     case "/setup_params":
       setup_params(request, response);
       return;
     case "/fxa-oauth/params":
       params(request, response);
       return;
+    case encodeURIComponent("/oauth/authorization"):
+      oauth_authorization(request, response);
+      return;
     case "/fxa-oauth/token":
       token(request, response);
       return;
@@ -89,6 +93,16 @@ function params(request, response) {
   response.write(JSON.stringify(params, null, 2));
 }
 
+/**
+ * GET /oauth/authorization endpoint for the test params.
+ *
+ * Redirect to a test page that uses WebChannel to complete the web flow.
+ */
+function oauth_authorization(request, response) {
+  response.setStatusLine(request.httpVersion, 302, "Found");
+  response.setHeader("Location", "browser_fxa_oauth.html");
+}
+
 /**
  * POST /fxa-oauth/token
  *
diff --git a/services/fxaccounts/FxAccountsOAuthClient.jsm b/services/fxaccounts/FxAccountsOAuthClient.jsm
index f6d03e27e88..c59c84cdc0f 100644
--- a/services/fxaccounts/FxAccountsOAuthClient.jsm
+++ b/services/fxaccounts/FxAccountsOAuthClient.jsm
@@ -64,7 +64,9 @@ this.FxAccountsOAuthClient = function(options) {
 
 this.FxAccountsOAuthClient.prototype = {
   /**
-   * Function that gets called once the OAuth flow is successfully complete.
+   * Function that gets called once the OAuth flow is complete.
+   * The callback will receive null as it's argument if there is a state mismatch or an object with
+   * code and state properties otherwise.
    */
   onComplete: null,
   /**
@@ -115,6 +117,7 @@ this.FxAccountsOAuthClient.prototype = {
     this.onComplete = null;
     this._complete = true;
     this._channel.stopListening();
+    this._channel = null;
   },
 
   /**
@@ -157,17 +160,24 @@ this.FxAccountsOAuthClient.prototype = {
         switch (command) {
           case "oauth_complete":
             // validate the state parameter and call onComplete
-            if (this.onComplete && data.code && this.parameters.state === data.state) {
-              log.debug("OAuth flow completed.");
-              this.onComplete({
+            let result = null;
+            if (this.parameters.state === data.state) {
+              result = {
                 code: data.code,
                 state: data.state
-              });
-              // onComplete will be called for this client only once
-              // calling onComplete again will result in a failure of the OAuth flow
-              this.tearDown();
+              };
+              log.debug("OAuth flow completed.");
+            } else {
+              log.debug("OAuth flow failed. State doesn't match");
             }
 
+            if (this.onComplete) {
+              this.onComplete(result);
+            }
+            // onComplete will be called for this client only once
+            // calling onComplete again will result in a failure of the OAuth flow
+            this.tearDown();
+
             // if the message asked to close the tab
             if (data.closeWindow && target && target.contentWindow) {
               target.contentWindow.close();

From d82d593ecaea98c01cef5a92cde3bf14b7cf14c4 Mon Sep 17 00:00:00 2001
From: "Bernardo P. Rittmeyer" 
Date: Mon, 18 Aug 2014 14:42:00 -0700
Subject: [PATCH 54/86] Bug 1052174 - Applied -moz-resolution fragment to
 favicons to enable support for high resolution throughout the UI. r=MattN

---
 browser/base/content/browser.js               |  1 +
 .../customizableui/CustomizableWidgets.jsm    |  7 +++--
 browser/components/places/PlacesUIUtils.jsm   | 27 -------------------
 .../places/content/browserPlacesViews.js      |  8 +++---
 browser/components/places/content/treeView.js |  6 ++++-
 .../RecentlyClosedTabsAndWindowsMenuUtils.jsm | 10 ++++---
 browser/components/tabview/favicons.js        |  8 +++++-
 toolkit/components/places/PlacesUtils.jsm     | 27 +++++++++++++++++++
 toolkit/content/widgets/autocomplete.xml      | 18 ++++++++++++-
 9 files changed, 72 insertions(+), 40 deletions(-)

diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index abc1229333e..1217d0309da 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3319,6 +3319,7 @@ function FillHistoryMenu(aParent) {
       PlacesUtils.favicons.getFaviconURLForPage(entry.URI, function (aURI) {
         if (aURI) {
           let iconURL = PlacesUtils.favicons.getFaviconLinkForIcon(aURI).spec;
+          iconURL = PlacesUtils.getImageURLForResolution(window, iconURL);
           item.style.listStyleImage = "url(" + iconURL + ")";
         }
       });
diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm
index b6924a61d29..9695d5e8a58 100644
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -159,6 +159,7 @@ const CustomizableWidgets = [{
       // Populate our list of history
       const kMaxResults = 15;
       let doc = aEvent.detail.ownerDocument;
+      let win = doc.defaultView;
 
       let options = PlacesUtils.history.getNewQueryOptions();
       options.excludeQueries = true;
@@ -201,8 +202,10 @@ const CustomizableWidgets = [{
               item.addEventListener("click", function (aEvent) {
                 onHistoryVisit(uri, aEvent, item);
               });
-              if (icon)
-                item.setAttribute("image", "moz-anno:favicon:" + icon);
+              if (icon) {
+                let iconURL = PlacesUtils.getImageURLForResolution(win, "moz-anno:favicon:" + icon);
+                item.setAttribute("image", iconURL);
+              }
               fragment.appendChild(item);
             } catch (e) {
               ERROR("Error while showing history subview: " + e);
diff --git a/browser/components/places/PlacesUIUtils.jsm b/browser/components/places/PlacesUIUtils.jsm
index bcf5cd691bf..3bcdd7a6c8c 100644
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -1014,33 +1014,6 @@ this.PlacesUIUtils = {
            Weave.Service.engineManager.get("tabs") &&
            Weave.Service.engineManager.get("tabs").enabled;
   },
-
-  /**
-   * Returns the passed URL with a #moz-resolution fragment
-   * for the specified dimensions and devicePixelRatio.
-   *
-   * @param aWindow
-   *        A window from where we want to get the device
-   *        pixel Ratio
-   *
-   * @param aURL
-   *        The URL where we should add the fragment
-   *
-   * @param aWidth
-   *        The target image width
-   *
-   * @param aHeight
-   *        The target image height
-   *
-   * @return The URL with the fragment at the end
-   */
-  getImageURLForResolution:
-  function PUIU_getImageURLForResolution(aWindow, aURL, aWidth = 16, aHeight = 16) {
-    let width  = Math.round(aWidth * aWindow.devicePixelRatio);
-    let height = Math.round(aHeight * aWindow.devicePixelRatio);
-    return aURL + (aURL.contains("#") ? "&" : "#") +
-           "-moz-resolution=" + width + "," + height;
-  },
 };
 
 XPCOMUtils.defineLazyServiceGetter(PlacesUIUtils, "RDF",
diff --git a/browser/components/places/content/browserPlacesViews.js b/browser/components/places/content/browserPlacesViews.js
index ef02a7e0e43..b265ee48061 100644
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -363,7 +363,7 @@ PlacesViewBase.prototype = {
       let icon = aPlacesNode.icon;
       if (icon)
         element.setAttribute("image",
-                             PlacesUIUtils.getImageURLForResolution(window, icon));
+                             PlacesUtils.getImageURLForResolution(window, icon));
     }
 
     element._placesNode = aPlacesNode;
@@ -502,7 +502,7 @@ PlacesViewBase.prototype = {
       elt.removeAttribute("image");
     else if (icon != elt.getAttribute("image"))
       elt.setAttribute("image",
-                       PlacesUIUtils.getImageURLForResolution(window, icon));
+                       PlacesUtils.getImageURLForResolution(window, icon));
   },
 
   nodeAnnotationChanged:
@@ -1019,7 +1019,7 @@ PlacesToolbar.prototype = {
       let icon = aChild.icon;
       if (icon)
         button.setAttribute("image",
-                            PlacesUIUtils.getImageURLForResolution(window, icon));
+                            PlacesUtils.getImageURLForResolution(window, icon));
 
       if (PlacesUtils.containerTypes.indexOf(type) != -1) {
         button.setAttribute("type", "menu");
@@ -1844,7 +1844,7 @@ PlacesPanelMenuView.prototype = {
       let icon = aChild.icon;
       if (icon)
         button.setAttribute("image",
-                            PlacesUIUtils.getImageURLForResolution(window, icon));
+                            PlacesUtils.getImageURLForResolution(window, icon));
 
       if (PlacesUtils.containerTypes.indexOf(type) != -1) {
         button.setAttribute("container", "true");
diff --git a/browser/components/places/content/treeView.js b/browser/components/places/content/treeView.js
index 68b389cdfd4..942eba03e3d 100644
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -1396,7 +1396,11 @@ PlacesTreeView.prototype = {
     if (this._getColumnType(aColumn) != this.COLUMN_TYPE_TITLE)
       return "";
 
-    return this._getNodeForRow(aRow).icon;
+    let node = this._getNodeForRow(aRow);
+    if (PlacesUtils.nodeIsURI(node) && node.icon)
+      return PlacesUtils.getImageURLForResolution(window, node.icon);
+
+    return node.icon;
   },
 
   getProgressMode: function(aRow, aColumn) { },
diff --git a/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm b/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm
index 7ed73fc8a76..5b87aa2cf03 100644
--- a/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm
+++ b/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm
@@ -13,6 +13,7 @@ var Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/PlacesUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
@@ -45,7 +46,7 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
         let element = doc.createElementNS(kNSXUL, aTagName);
         element.setAttribute("label", closedTabs[i].title);
         if (closedTabs[i].image) {
-          setImage(closedTabs[i], element);
+          setImage(aWindow, closedTabs[i], element);
         }
         element.setAttribute("value", i);
         if (aTagName == "menuitem") {
@@ -117,7 +118,7 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
         item.setAttribute("label", menuLabel);
         let selectedTab = undoItem.tabs[undoItem.selected - 1];
         if (selectedTab.image) {
-          setImage(selectedTab, item);
+          setImage(aWindow, selectedTab, item);
         }
         if (aTagName == "menuitem") {
           item.setAttribute("class", "menuitem-iconic bookmark-item menuitem-with-favicon");
@@ -167,10 +168,11 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = {
   },
 };
 
-function setImage(aItem, aElement) {
-  let iconURL = aItem.image;
+function setImage(aWindow, aItem, aElement) {
+  let iconURL = PlacesUtils.getImageURLForResolution(aWindow, aItem.image);
   // don't initiate a connection just to fetch a favicon (see bug 467828)
   if (/^https?:/.test(iconURL))
     iconURL = "moz-anno:favicon:" + iconURL;
+
   aElement.setAttribute("image", iconURL);
 }
diff --git a/browser/components/tabview/favicons.js b/browser/components/tabview/favicons.js
index c20ff29fdce..7ec26d4e84f 100644
--- a/browser/components/tabview/favicons.js
+++ b/browser/components/tabview/favicons.js
@@ -2,6 +2,8 @@
  * 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/. */
 
+Components.utils.import('resource://gre/modules/PlacesUtils.jsm');
+
 let FavIcons = {
   // Pref that controls whether to display site icons.
   PREF_CHROME_SITE_ICONS: "browser.chrome.site_icons",
@@ -87,6 +89,8 @@ let FavIcons = {
       tabImage = this._favIconService.getFaviconLinkForIcon(tabImageURI).spec;
     }
 
+    tabImage = PlacesUtils.getImageURLForResolution(window, tabImage);
+
     callback(tabImage);
   },
 
@@ -99,7 +103,9 @@ let FavIcons = {
     let {currentURI} = tab.linkedBrowser;
     this._favIconService.getFaviconURLForPage(currentURI, function (uri) {
       if (uri) {
-        callback(this._favIconService.getFaviconLinkForIcon(uri).spec);
+        let icon = PlacesUtils.getImageURLForResolution(window,
+                     this._favIconService.getFaviconLinkForIcon(uri).spec);
+        callback(icon);
       } else {
         callback(this.defaultFavicon);
       }
diff --git a/toolkit/components/places/PlacesUtils.jsm b/toolkit/components/places/PlacesUtils.jsm
index bbb9cb6acee..df3bb80b97d 100644
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -1519,6 +1519,33 @@ this.PlacesUtils = {
     return deferred.promise;
   },
 
+  /**
+   * Returns the passed URL with a #-moz-resolution fragment
+   * for the specified dimensions and devicePixelRatio.
+   *
+   * @param aWindow
+   *        A window from where we want to get the device
+   *        pixel Ratio
+   *
+   * @param aURL
+   *        The URL where we should add the fragment
+   *
+   * @param aWidth
+   *        The target image width
+   *
+   * @param aHeight
+   *        The target image height
+   *
+   * @return The URL with the fragment at the end
+   */
+  getImageURLForResolution:
+  function PU_getImageURLForResolution(aWindow, aURL, aWidth = 16, aHeight = 16) {
+    let width  = Math.round(aWidth * aWindow.devicePixelRatio);
+    let height = Math.round(aHeight * aWindow.devicePixelRatio);
+    return aURL + (aURL.contains("#") ? "&" : "#") +
+           "-moz-resolution=" + width + "," + height;
+  },
+
   /**
    * Get the unique id for an item (a bookmark, a folder or a separator) given
    * its item id.
diff --git a/toolkit/content/widgets/autocomplete.xml b/toolkit/content/widgets/autocomplete.xml
index cb83860817c..86a9d626509 100644
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -1080,6 +1080,21 @@ extends="chrome://global/content/bindings/popup.xml#popup">
         
       
 
+      
+        
+        
+        
+        
+        
+          
+        
+      
+
       
         
           
 
             // set these attributes before we set the class
             // so that we can use them from the constructor
-            item.setAttribute("image", controller.getImageAt(this._currentIndex));
+            let iconURI = this._getImageURLForResolution(window, controller.getImageAt(this._currentIndex), 16, 16);
+            item.setAttribute("image", iconURI);
             item.setAttribute("url", url);
             item.setAttribute("title", controller.getCommentAt(this._currentIndex));
             item.setAttribute("type", controller.getStyleAt(this._currentIndex));

From 52ff11105bb7940aeae7eaa921445091fb4fa852 Mon Sep 17 00:00:00 2001
From: "Bernardo P. Rittmeyer" 
Date: Mon, 18 Aug 2014 14:33:00 -0700
Subject: [PATCH 55/86] Bug 1054712 - Remove duplicate logic from tabbrowser
 and search bar by using the getImageURLForResolution helper function in
 PlacesUtils. r=MattN

---
 browser/base/content/tabbrowser.xml          | 7 ++++---
 browser/components/search/content/search.xml | 7 ++++---
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml
index 92b45da8209..3f750b78425 100644
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -85,6 +85,9 @@
          Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"]
                    .getService(Components.interfaces.mozIPlacesAutoComplete);
       
+      
+        (Components.utils.import("resource://gre/modules/PlacesUtils.jsm", {})).PlacesUtils;
+      
       
         document.getAnonymousElementByAttribute(this, "anonid", "tabbox");
       
@@ -840,9 +843,7 @@
 
             let sizedIconUrl = browser.mIconURL || "";
             if (sizedIconUrl) {
-              let size = Math.round(16 * window.devicePixelRatio);
-              sizedIconUrl += (sizedIconUrl.contains("#") ? "&" : "#") +
-                              "-moz-resolution=" + size + "," + size;
+              sizedIconUrl = this.PlacesUtils.getImageURLForResolution(window, sizedIconUrl);
             }
             if (sizedIconUrl != aTab.getAttribute("image")) {
               if (sizedIconUrl)
diff --git a/browser/components/search/content/search.xml b/browser/components/search/content/search.xml
index cad9fa1e6f9..02db53ffe71 100644
--- a/browser/components/search/content/search.xml
+++ b/browser/components/search/content/search.xml
@@ -125,6 +125,9 @@
       
         (Components.utils.import("resource://gre/modules/FormHistory.jsm", {})).FormHistory;
       
+      
+        (Components.utils.import("resource://gre/modules/PlacesUtils.jsm", {})).PlacesUtils;
+      
 
       
         
         

From d7d04c3fe12f1f82b6598f0b932cc65deea40919 Mon Sep 17 00:00:00 2001
From: Mark Finkle 
Date: Mon, 18 Aug 2014 17:46:10 -0400
Subject: [PATCH 56/86] Bug 1042252 - Add some tests for NativeWindow APIs
 r=wesj

---
 mobile/android/base/tests/robocop.ini         |   1 +
 .../tests/roboextender/testNativeWindow.html  | 113 +++++++++++++++
 .../android/base/tests/testNativeWindow.java  | 130 ++++++++++++++++++
 3 files changed, 244 insertions(+)
 create mode 100644 mobile/android/base/tests/roboextender/testNativeWindow.html
 create mode 100644 mobile/android/base/tests/testNativeWindow.java

diff --git a/mobile/android/base/tests/robocop.ini b/mobile/android/base/tests/robocop.ini
index 59866d8e759..dc14ea181fa 100644
--- a/mobile/android/base/tests/robocop.ini
+++ b/mobile/android/base/tests/robocop.ini
@@ -102,6 +102,7 @@ skip-if = android_version == "10"
 [testDeviceSearchEngine]
 [testJNI]
 # [testMozPay] # see bug 945675
+[testNativeWindow]
 [testOrderedBroadcast]
 [testResourceSubstitutions]
 [testSharedPreferences]
diff --git a/mobile/android/base/tests/roboextender/testNativeWindow.html b/mobile/android/base/tests/roboextender/testNativeWindow.html
new file mode 100644
index 00000000000..02daef278e0
--- /dev/null
+++ b/mobile/android/base/tests/roboextender/testNativeWindow.html
@@ -0,0 +1,113 @@
+
+  
+    NativeWindow test page
+    
+    
+    
+  
+  
+  
+
diff --git a/mobile/android/base/tests/testNativeWindow.java b/mobile/android/base/tests/testNativeWindow.java
new file mode 100644
index 00000000000..d0ca15c1313
--- /dev/null
+++ b/mobile/android/base/tests/testNativeWindow.java
@@ -0,0 +1,130 @@
+package org.mozilla.gecko.tests;
+
+import org.mozilla.gecko.Actions;
+
+import android.widget.CheckBox;
+
+import java.util.ArrayList;
+
+public class testNativeWindow extends BaseTest {
+
+    private static final String TEST_URL = "chrome://roboextender/content/testNativeWindow.html";
+    private static final String TOAST_TEXT = "TOAST!";
+    private static final String MENU_TEXT1 = "MENU-A";
+    private static final String MENU_TEXT2 = "MENU-B";
+    private static final String DOORHANGER_TEXT = "DOORHANGER";
+    private static final String DOORHANGER_BUTTON1 = "BUTTON1";
+    private static final String DOORHANGER_BUTTON2 = "BUTTON2";
+    private static final String DOORHANGER_CHECK = "CHECKBOX";
+
+    public void testNativeWindow() {
+        blockForGeckoReady();
+
+        // NOTE: These test methods depend on being run in this order.
+        addToastTest();
+
+        prepNextTest();
+        addMenuTest();
+
+        prepNextTest();
+        updateMenuTest();
+
+        prepNextTest();
+        removeMenuTest();
+
+        prepNextTest();
+        addDoorhangerTest();
+    }
+
+    /**
+     * Load about:blank between each test to ensure we reset state.
+     */
+    private void prepNextTest() {
+        loadUrl("about:blank");
+        mAsserter.ok(waitForText("about:blank"), "Loaded blank page", "page title match");
+    }
+
+    /**
+     * Shows a toast, verifies that it appears when it should.
+     */
+    private void addToastTest() {
+        Actions.EventExpecter eventExpecter = mActions.expectGeckoEvent("TestNativeWindow:ShowToast");
+        loadUrl(TEST_URL + "#showToast");
+        eventExpecter.blockForEvent();
+
+        // Verify that the toast is visible with the correct text.
+        mAsserter.ok(waitForText(TOAST_TEXT), "Waiting for the toast", "Toast has been displayed");
+    }
+
+    /**
+     * Adds a menu and verifies the callback fires when clicked.
+     */
+    private void addMenuTest() {
+        Actions.EventExpecter eventExpecter = mActions.expectGeckoEvent("TestNativeWindow:AddMenu");
+        loadUrl(TEST_URL + "#addMenu");
+        eventExpecter.blockForEvent();
+
+        // Press the menu and wait for the callback to send a message
+        Actions.EventExpecter menuExpecter = mActions.expectGeckoEvent("TestNativeWindow:FireMenu");
+        selectMenuItem(MENU_TEXT1);
+        menuExpecter.blockForEvent();
+    }
+
+    /**
+     * Updates a menu and verifies the callback fires when clicked.
+     */
+    private void updateMenuTest() {
+        // Load about:home and make sure the onshown handler is called.
+        Actions.EventExpecter eventExpecter = mActions.expectGeckoEvent("TestNativeWindow:UpdateMenu");
+        loadUrl(TEST_URL + "#updateMenu");
+        eventExpecter.blockForEvent();
+
+        // Press the menu and wait for the callback to send a message
+        Actions.EventExpecter menuExpecter = mActions.expectGeckoEvent("TestNativeWindow:FireMenu");
+        selectMenuItem(MENU_TEXT2);
+        menuExpecter.blockForEvent();
+    }
+
+    /**
+     * Removes a menu and verifies the menu is not found.
+     */
+    private void removeMenuTest() {
+        Actions.EventExpecter eventExpecter = mActions.expectGeckoEvent("TestNativeWindow:RemoveMenu");
+        loadUrl(TEST_URL + "#removeMenu");
+        eventExpecter.blockForEvent();
+
+        // Do a simple search for the menu text on the main menu
+        mActions.sendSpecialKey(Actions.SpecialKey.MENU);
+        waitForText("^New Tab$");
+        mAsserter.ok(mSolo.searchText("^" + MENU_TEXT2 + "$") == false, "Checking for menu", "Menu has been removed");
+
+        // Close the menu, if it's still open
+        if (mSolo.searchText("^New Tab$")) {
+            mActions.sendSpecialKey(Actions.SpecialKey.BACK);
+        }
+    }
+
+    /**
+     * Adds a doorhanger and verifies the callback fires when clicked.
+     */
+    private void addDoorhangerTest() {
+        Actions.EventExpecter eventExpecter = mActions.expectGeckoEvent("TestNativeWindow:AddDoorhanger");
+        loadUrl(TEST_URL + "#addDoorhanger");
+        eventExpecter.blockForEvent();
+
+        // Press the doorhanger button and wait for the callback to send a message
+        Actions.EventExpecter menuExpecter = mActions.expectGeckoEvent("TestNativeWindow:FireDoorhanger");
+        waitForText(DOORHANGER_TEXT);
+
+        // Uncheck the checkbox
+        ArrayList checkBoxes = mSolo.getCurrentViews(CheckBox.class);
+        mAsserter.ok(checkBoxes.size() == 1, "checkbox count", "only one checkbox visible");
+        mAsserter.ok(mSolo.isCheckBoxChecked(0), "checkbox checked", "checkbox is checked");
+        mSolo.clickOnCheckBox(0);
+        mAsserter.ok(!mSolo.isCheckBoxChecked(0), "checkbox not checked", "checkbox is not checked");
+
+        mSolo.clickOnText(DOORHANGER_BUTTON1);
+
+        menuExpecter.blockForEvent();
+    }
+}

From 6edce0acfd49aba9238cf4ac2401337423fc999b Mon Sep 17 00:00:00 2001
From: Wes Kocher 
Date: Mon, 18 Aug 2014 15:24:53 -0700
Subject: [PATCH 57/86] Backed out changeset 7ee849f1c0c4 (bug 1003153) for
 devtools bustage on a CLOSED TREE

---
 .../devtools/netmonitor/netmonitor-view.js    | 37 +------------------
 .../test/browser_net_accessibility-02.js      | 17 +--------
 .../devtools/shared/widgets/ViewHelpers.jsm   | 15 +-------
 3 files changed, 5 insertions(+), 64 deletions(-)

diff --git a/browser/devtools/netmonitor/netmonitor-view.js b/browser/devtools/netmonitor/netmonitor-view.js
index aed3a335b46..ea48c9e56e0 100644
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -75,7 +75,6 @@ let NetMonitorView = {
     this.RequestsMenu.initialize();
     this.NetworkDetails.initialize();
     this.CustomRequest.initialize();
-    this.arrowClosed = false;
   },
 
   /**
@@ -309,16 +308,12 @@ ToolbarView.prototype = {
     let requestsMenu = NetMonitorView.RequestsMenu;
     let selectedIndex = requestsMenu.selectedIndex;
 
-    // Allow opening the sidebar if it was previously closed with an arrow key.
-    requestsMenu.arrowClosed = false;
-
     // Make sure there's a selection if the button is pressed, to avoid
     // showing an empty network details pane.
-    // If there is a selection, toggle the sidebar.
     if (selectedIndex == -1 && requestsMenu.itemCount) {
       requestsMenu.selectedIndex = 0;
     } else {
-      NetMonitorView.Sidebar.toggle(NetMonitorView.detailsPaneHidden);
+      requestsMenu.selectedIndex = -1;
     }
   },
 
@@ -390,9 +385,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
     $("#request-menu-context-copy-url").addEventListener("command", this._onContextCopyUrlCommand, false);
     $("#request-menu-context-copy-image-as-data-uri").addEventListener("command", this._onContextCopyImageAsDataUriCommand, false);
 
-    this.ignoreLeftRight = true;
-    this.widget.on("keyPress", this._handleKeyPress.bind(this));
-
     window.once("connected", this._onConnect.bind(this));
   },
 
@@ -741,29 +733,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
     }
   },
 
-  /**
-   * Handler to allow keyboard controls to close the Sidebar.
-   * Left|Return: open
-   * Right: close
-   *
-   * @param string aName
-   *        Name of the Event
-   * @param nsIDOMEvent aEvent
-   */
-  _handleKeyPress: function(aName, aEvent) {
-    switch (aEvent.keyCode) {
-      case aEvent.DOM_VK_RETURN:
-      case aEvent.DOM_VK_LEFT:
-        NetMonitorView.Sidebar.toggle(true);
-        this.arrowClosed = false;
-        return;
-      case aEvent.DOM_VK_RIGHT:
-        NetMonitorView.Sidebar.toggle(false);
-        this.arrowClosed = true;
-        return;
-    }
-  },
-
   /**
    * Returns a predicate that can be used to test if a request matches any of
    * the active filters.
@@ -1577,10 +1546,6 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
    * The selection listener for this container.
    */
   _onSelect: function({ detail: item }) {
-    if (this.arrowClosed) {
-      return;
-    }
-
     if (item) {
       NetMonitorView.Sidebar.populate(item.attachment);
       NetMonitorView.Sidebar.toggle(true);
diff --git a/browser/devtools/netmonitor/test/browser_net_accessibility-02.js b/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
index 5a0ad781237..0ec5490a274 100644
--- a/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
+++ b/browser/devtools/netmonitor/test/browser_net_accessibility-02.js
@@ -25,11 +25,6 @@ function test() {
       EventUtils.sendKey("UP", window);
       check(0, true);
 
-      EventUtils.sendKey("RIGHT", window);
-      check(0, false);
-      EventUtils.sendKey("LEFT", window);
-      check(0, true);
-
       EventUtils.sendKey("PAGE_DOWN", window);
       check(1, true);
       EventUtils.sendKey("PAGE_UP", window);
@@ -57,24 +52,16 @@ function test() {
       check(4, true);
       EventUtils.sendKey("PAGE_DOWN", window);
       check(8, true);
-      EventUtils.sendKey("RIGHT", window);
-      check(8, false);
       EventUtils.sendKey("PAGE_UP", window);
-      check(4, false);
-      EventUtils.sendKey("LEFT", window);
       check(4, true);
       EventUtils.sendKey("PAGE_UP", window);
       check(0, true);
 
       EventUtils.sendKey("HOME", window);
       check(0, true);
-      EventUtils.sendKey("RIGHT", window);
-      check(0, false);
       EventUtils.sendKey("HOME", window);
-      check(0, false);
+      check(0, true);
       EventUtils.sendKey("PAGE_UP", window);
-      check(0, false);
-      EventUtils.sendKey("RETURN", window);
       check(0, true);
       EventUtils.sendKey("HOME", window);
       check(0, true);
@@ -115,7 +102,7 @@ function test() {
       check(19, true);
 
       EventUtils.sendMouseEvent({ type: "mousedown" }, $("#details-pane-toggle"));
-      check(19, false);
+      check(-1, false);
 
       EventUtils.sendMouseEvent({ type: "mousedown" }, $(".side-menu-widget-item"));
       check(0, true);
diff --git a/browser/devtools/shared/widgets/ViewHelpers.jsm b/browser/devtools/shared/widgets/ViewHelpers.jsm
index af2f24a86ef..68b4be71259 100644
--- a/browser/devtools/shared/widgets/ViewHelpers.jsm
+++ b/browser/devtools/shared/widgets/ViewHelpers.jsm
@@ -1181,13 +1181,6 @@ this.WidgetMethods = {
    */
   autoFocusOnInput: true,
 
-  /**
-   * Ignore Left and Right keypresses.
-   *
-   * If this flag is set to true, Widgets should implement their own handler.
-   */
-  ignoreLeftRight: false,
-
   /**
    * When focusing on input, allow right clicks?
    * @see WidgetMethods.autoFocusOnInput
@@ -1641,16 +1634,12 @@ this.WidgetMethods = {
 
     switch (aEvent.keyCode) {
       case aEvent.DOM_VK_UP:
+      case aEvent.DOM_VK_LEFT:
         this.focusPrevItem();
         return;
       case aEvent.DOM_VK_DOWN:
-        this.focusNextItem();
-        return;
-      case aEvent.DOM_VK_LEFT:
-        if (!this.ignoreLeftRight) this.focusPrevItem();
-        return;
       case aEvent.DOM_VK_RIGHT:
-        if (!this.ignoreLeftRight) this.focusNextItem();
+        this.focusNextItem();
         return;
       case aEvent.DOM_VK_PAGE_UP:
         this.focusItemAtDelta(-(this.pageSize || (this.itemCount / PAGE_SIZE_ITEM_COUNT_RATIO)));

From 52cf7ad1eb7237f87b76382fa346c597d3c77cc2 Mon Sep 17 00:00:00 2001
From: Mark Hammond 
Date: Tue, 19 Aug 2014 08:47:37 +1000
Subject: [PATCH 58/86] Bug 1053948 - declare AccountState in fxAccounts.
 r=gavin

---
 services/fxaccounts/FxAccounts.jsm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/services/fxaccounts/FxAccounts.jsm b/services/fxaccounts/FxAccounts.jsm
index a4f9a72124a..4cad40eb381 100644
--- a/services/fxaccounts/FxAccounts.jsm
+++ b/services/fxaccounts/FxAccounts.jsm
@@ -61,7 +61,7 @@ let publicProperties = [
 // }
 // If the state has changed between the function being called and the promise
 // being resolved, the .resolve() call will actually be rejected.
-AccountState = function(fxaInternal) {
+let AccountState = function(fxaInternal) {
   this.fxaInternal = fxaInternal;
 };
 

From 68aec498ce46beffc4a28aa766722b0e381a1e8c Mon Sep 17 00:00:00 2001
From: Andrei Oprea 
Date: Mon, 18 Aug 2014 16:24:14 -0700
Subject: [PATCH 59/86] Bug 976116 - Implement end to end call in one browser
 window, r=dmose

---
 browser/components/loop/content/js/panel.js   |   8 +-
 browser/components/loop/content/js/panel.jsx  |   8 +-
 .../loop/content/shared/js/views.js           |   3 +-
 .../loop/content/shared/js/views.jsx          |   3 +-
 .../loop/standalone/content/js/webapp.js      |   1 -
 .../loop/standalone/content/js/webapp.jsx     |   1 -
 .../components/loop/test/functional/config.py |  20 +++
 .../loop/test/functional/manifest.ini         |   2 +-
 .../loop/test/functional/serversetup.py       |  70 ++++++++
 .../test/functional/test_1_browser_call.py    | 161 ++++++++++++++++++
 .../loop/test/functional/test_get_url.py      | 145 ----------------
 11 files changed, 270 insertions(+), 152 deletions(-)
 create mode 100644 browser/components/loop/test/functional/config.py
 create mode 100644 browser/components/loop/test/functional/serversetup.py
 create mode 100644 browser/components/loop/test/functional/test_1_browser_call.py
 delete mode 100644 browser/components/loop/test/functional/test_get_url.py

diff --git a/browser/components/loop/content/js/panel.js b/browser/components/loop/content/js/panel.js
index a08a1798ce6..bef8bea73d1 100644
--- a/browser/components/loop/content/js/panel.js
+++ b/browser/components/loop/content/js/panel.js
@@ -234,11 +234,17 @@ loop.panel = (function(_, mozL10n) {
       // readOnly attr will suppress a warning regarding this issue
       // from the react lib.
       var cx = React.addons.classSet;
+      var inputCSSClass = cx({
+        "pending": this.state.pending,
+        // Used in functional testing, signals that
+        // call url was received from loop server
+         "callUrl": !this.state.pending
+      });
       return (
         PanelLayout({summary: __("share_link_header_text")}, 
           React.DOM.div({className: "invite"}, 
             React.DOM.input({type: "url", value: this.state.callUrl, readOnly: "true", 
-                   className: cx({pending: this.state.pending})}), 
+                   className: inputCSSClass}), 
             React.DOM.p({className: "button-group url-actions"}, 
               React.DOM.button({className: "btn btn-email", disabled: !this.state.callUrl, 
                 onClick: this.handleEmailButtonClick, 
diff --git a/browser/components/loop/content/js/panel.jsx b/browser/components/loop/content/js/panel.jsx
index 37e919c060b..6dd29759fc2 100644
--- a/browser/components/loop/content/js/panel.jsx
+++ b/browser/components/loop/content/js/panel.jsx
@@ -234,11 +234,17 @@ loop.panel = (function(_, mozL10n) {
       // readOnly attr will suppress a warning regarding this issue
       // from the react lib.
       var cx = React.addons.classSet;
+      var inputCSSClass = cx({
+        "pending": this.state.pending,
+        // Used in functional testing, signals that
+        // call url was received from loop server
+         "callUrl": !this.state.pending
+      });
       return (
         
           
+ className={inputCSSClass} />

  • Date: Mon, 18 Aug 2014 17:27:33 -0700 Subject: [PATCH 60/86] Bug 1054776: Ctrl+K should focus the search bar if it is in the toolbar. r=adw --- browser/base/content/browser.js | 20 ++++++++-------- .../content/test/general/browser_aboutHome.js | 24 +++++++++++++++++-- .../test/newtab/browser_newtab_search.js | 13 ++++++++-- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 1217d0309da..de7685e242d 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3097,16 +3097,16 @@ const BrowserSearch = { } #endif let openSearchPageIfFieldIsNotActive = function(aSearchBar) { - let doc = gBrowser.selectedBrowser.contentDocument; - let url = doc.documentURI.toLowerCase(); - let mm = gBrowser.selectedBrowser.messageManager; - - if (url === "about:home") { - AboutHome.focusInput(mm); - } else if (url === "about:newtab") { - ContentSearch.focusInput(mm); - } else if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) { - openUILinkIn("about:home", "current"); + if (!aSearchBar || document.activeElement != aSearchBar.textbox.inputField) { + let url = gBrowser.currentURI.spec.toLowerCase(); + let mm = gBrowser.selectedBrowser.messageManager; + if (url === "about:home") { + AboutHome.focusInput(mm); + } else if (url === "about:newtab") { + ContentSearch.focusInput(mm); + } else { + openUILinkIn("about:home", "current"); + } } }; diff --git a/browser/base/content/test/general/browser_aboutHome.js b/browser/base/content/test/general/browser_aboutHome.js index 9b51e0fa22b..c5a889bcf04 100644 --- a/browser/base/content/test/general/browser_aboutHome.js +++ b/browser/base/content/test/general/browser_aboutHome.js @@ -420,8 +420,11 @@ let gTests = [ } }, { - desc: "Cmd+k should focus the search bar element", - setup: function () {}, + desc: "Cmd+k should focus the search box in the page when the search box in the toolbar is absent", + setup: function () { + // Remove the search bar from toolbar + CustomizableUI.removeWidgetFromArea("search-container"); + }, run: Task.async(function* () { let doc = gBrowser.selectedTab.linkedBrowser.contentDocument; let logo = doc.getElementById("brandLogo"); @@ -433,8 +436,25 @@ let gTests = [ EventUtils.synthesizeKey("k", { accelKey: true }); yield promiseWaitForCondition(() => doc.activeElement === searchInput); is(searchInput, doc.activeElement, "Search input should be the active element."); + CustomizableUI.reset(); }) }, +{ + desc: "Cmd+k should focus the search box in the toolbar when it's present", + setup: function () {}, + run: Task.async(function* () { + let logo = gBrowser.selectedTab.linkedBrowser.contentDocument.getElementById("brandLogo"); + let doc = window.document; + let searchInput = doc.getElementById("searchbar").textbox.inputField; + + EventUtils.synthesizeMouseAtCenter(logo, {}); + isnot(searchInput, doc.activeElement, "Search bar should not be the active element."); + + EventUtils.synthesizeKey("k", { accelKey: true }); + yield promiseWaitForCondition(() => doc.activeElement === searchInput); + is(searchInput, doc.activeElement, "Search bar should be the active element."); + }) +} ]; diff --git a/browser/base/content/test/newtab/browser_newtab_search.js b/browser/base/content/test/newtab/browser_newtab_search.js index de652e813ab..70d69fb769f 100644 --- a/browser/base/content/test/newtab/browser_newtab_search.js +++ b/browser/base/content/test/newtab/browser_newtab_search.js @@ -186,15 +186,24 @@ function runTests() { EventUtils.synthesizeKey("VK_DELETE", {}); ok(table.hidden, "Search suggestion table hidden"); - // Focus a different element than the search input. + // Remove the search bar from toolbar + CustomizableUI.removeWidgetFromArea("search-container"); + // Focus a different element than the search input from the page. let btn = getContentDocument().getElementById("newtab-customize-button"); yield promiseClick(btn).then(TestRunner.next); isnot(input, getContentDocument().activeElement, "Search input should not be focused"); - // Test that Ctrl/Cmd + K will focus the input field. + // Test that Ctrl/Cmd + K will focus the input field from the page. EventUtils.synthesizeKey("k", { accelKey: true }); yield promiseSearchEvents(["FocusInput"]).then(TestRunner.next); is(input, getContentDocument().activeElement, "Search input should be focused"); + // Reset changes made to toolbar + CustomizableUI.reset(); + + // Test that Ctrl/Cmd + K will focus the search bar from toolbar. + let searchBar = gWindow.document.getElementById("searchbar"); + EventUtils.synthesizeKey("k", { accelKey: true }); + is(searchBar.textbox.inputField, gWindow.document.activeElement, "Toolbar's search bar should be focused"); // Done. Revert the current engine and remove the new engines. Services.search.currentEngine = oldCurrentEngine; From 34158c2cc2199944ec3fe56963ee1ff0f10cfe41 Mon Sep 17 00:00:00 2001 From: Alex Bardas Date: Mon, 18 Aug 2014 17:27:35 -0700 Subject: [PATCH 61/86] Bug 1054600 - Refactor AboutHomeListener & browser.js document URI checks. r=adw --- browser/base/content/content.js | 72 +++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/browser/base/content/content.js b/browser/base/content/content.js index d4461de6ef6..32661fa12bc 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -29,7 +29,7 @@ addMessageListener("Browser:HideSessionRestoreButton", function (message) { let doc = content.document; let container; if (doc.documentURI.toLowerCase() == "about:home" && - (container = doc.getElementById("sessionRestoreContainer"))){ + (container = doc.getElementById("sessionRestoreContainer"))) { container.hidden = true; } }); @@ -90,18 +90,37 @@ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) { let AboutHomeListener = { init: function(chromeGlobal) { - chromeGlobal.addEventListener('AboutHomeLoad', () => this.onPageLoad(), false, true); + chromeGlobal.addEventListener('AboutHomeLoad', this, false, true); + }, + + get isAboutHome() { + return content.document.documentURI.toLowerCase() == "about:home"; }, handleEvent: function(aEvent) { + if (!this.isAboutHome) { + return; + } switch (aEvent.type) { case "AboutHomeLoad": this.onPageLoad(); break; + case "AboutHomeSearchEvent": + this.onSearch(aEvent); + break; + case "click": + this.onClick(aEvent); + break; + case "pagehide": + this.onPageHide(aEvent); + break; } }, receiveMessage: function(aMessage) { + if (!this.isAboutHome) { + return; + } switch (aMessage.name) { case "AboutHome:Update": this.onUpdate(aMessage.data); @@ -114,9 +133,6 @@ let AboutHomeListener = { onUpdate: function(aData) { let doc = content.document; - if (doc.documentURI.toLowerCase() != "about:home") - return; - if (aData.showRestoreLastSession && !PrivateBrowsingUtils.isWindowPrivate(content)) doc.getElementById("launcher").setAttribute("session", "true"); @@ -133,25 +149,15 @@ let AboutHomeListener = { onPageLoad: function() { let doc = content.document; - if (doc.documentURI.toLowerCase() != "about:home" || - doc.documentElement.hasAttribute("hasBrowserHandlers")) { + if (doc.documentElement.hasAttribute("hasBrowserHandlers")) { return; } doc.documentElement.setAttribute("hasBrowserHandlers", "true"); - let self = this; - addMessageListener("AboutHome:Update", self); - addMessageListener("AboutHome:FocusInput", self); - addEventListener("click", this.onClick, true); - addEventListener("pagehide", function onPageHide(event) { - if (event.target.defaultView.frameElement) - return; - removeMessageListener("AboutHome:Update", self); - removeEventListener("click", self.onClick, true); - removeEventListener("pagehide", onPageHide, true); - if (event.target.documentElement) - event.target.documentElement.removeAttribute("hasBrowserHandlers"); - }, true); + addMessageListener("AboutHome:Update", this); + addMessageListener("AboutHome:FocusInput", this); + addEventListener("click", this, true); + addEventListener("pagehide", this, true); // XXX bug 738646 - when Marketplace is launched, remove this statement and // the hidden attribute set on the apps button in aboutHome.xhtml @@ -160,10 +166,7 @@ let AboutHomeListener = { doc.getElementById("apps").removeAttribute("hidden"); sendAsyncMessage("AboutHome:RequestUpdate"); - - doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) { - sendAsyncMessage("AboutHome:Search", { searchData: e.detail }); - }, true, true); + doc.addEventListener("AboutHomeSearchEvent", this, true, true); }, onClick: function(aEvent) { @@ -217,8 +220,27 @@ let AboutHomeListener = { } }, + onPageHide: function(aEvent) { + if (event.target.defaultView.frameElement) { + return; + } + removeMessageListener("AboutHome:Update", this); + removeEventListener("click", this, true); + removeEventListener("pagehide", this, true); + if (event.target.documentElement) { + event.target.documentElement.removeAttribute("hasBrowserHandlers"); + } + }, + + onSearch: function(aEvent) { + sendAsyncMessage("AboutHome:Search", { searchData: aEvent.detail }); + }, + onFocusInput: function () { - content.document.getElementById("searchText").focus(); + let searchInput = content.document.getElementById("searchText"); + if (searchInput) { + searchInput.focus(); + } }, }; AboutHomeListener.init(this); From 04231d7e7ae6184f67dea361aa910d93d1f590cc Mon Sep 17 00:00:00 2001 From: Ed Lee Date: Mon, 18 Aug 2014 20:36:04 -0700 Subject: [PATCH 62/86] Bug 1055261 - Reduce new tab performance impact by only attempting to show 5 columns (from 8) [r=adw] --- browser/app/profile/firefox.js | 2 +- browser/base/content/test/newtab/browser_newtab_bug752841.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index e98c208d7dd..a15e38aeaa5 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1522,7 +1522,7 @@ pref("browser.newtabpage.enhanced", false); pref("browser.newtabpage.rows", 3); // number of columns of newtab grid -pref("browser.newtabpage.columns", 8); +pref("browser.newtabpage.columns", 5); // directory tiles download URL pref("browser.newtabpage.directory.source", "chrome://global/content/directoryLinks.json"); diff --git a/browser/base/content/test/newtab/browser_newtab_bug752841.js b/browser/base/content/test/newtab/browser_newtab_bug752841.js index c19272417ca..5b0555d16cd 100644 --- a/browser/base/content/test/newtab/browser_newtab_bug752841.js +++ b/browser/base/content/test/newtab/browser_newtab_bug752841.js @@ -17,8 +17,8 @@ function runTests() { // Expected length of grid let expectedValues = [1, 1, 1, 1, 8, 10]; - // Values before setting new pref values (24 is the default value -> 8 x 3) - let previousValues = [24, 1, 1, 1, 1, 8]; + // Values before setting new pref values (15 is the default value -> 5 x 3) + let previousValues = [15, 1, 1, 1, 1, 8]; let existingTab, existingTabGridLength, newTab, newTabGridLength; yield addNewTabPageTab(); From ba0e8ba23dc437ef5b1cc79698b0a3eb94b435ce Mon Sep 17 00:00:00 2001 From: Kumar Ayush Date: Mon, 18 Aug 2014 20:36:05 -0700 Subject: [PATCH 63/86] Bug 1045751 - Shrink tile (pin/block/gear) button sizes by a little bit [r=adw] pin/block to 24px, gear to 28px as per UX info; --- browser/themes/shared/newtab/newTab.inc.css | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/browser/themes/shared/newtab/newTab.inc.css b/browser/themes/shared/newtab/newTab.inc.css index 201207c6f52..c71f30e9ab6 100644 --- a/browser/themes/shared/newtab/newTab.inc.css +++ b/browser/themes/shared/newtab/newTab.inc.css @@ -65,9 +65,10 @@ #newtab-customize-button { background-color: transparent; background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 32, 32, 0); + background-size: 28px; border: none; - height: 32px; - width: 32px; + height: 28px; + width: 28px; } #newtab-customize-button:-moz-any(:hover, :active, [active]) { @@ -166,9 +167,10 @@ /* CONTROLS */ .newtab-control { background-color: transparent; + background-size: 24px; border: none; - height: 32px; - width: 32px; + height: 24px; + width: 24px; } .newtab-control-pin, @@ -199,10 +201,9 @@ } .newtab-control-sponsored { - width: 24px; - height: 24px; background-image: url(chrome://browser/skin/newtab/controls.png); background-position: -249px -1px; + background-size: auto; } @media (min-resolution: 2dppx) { From 6e42778210aa046d536ffa1aa62ac5e5802403ce Mon Sep 17 00:00:00 2001 From: Nick Alexander Date: Mon, 18 Aug 2014 21:23:20 -0700 Subject: [PATCH 64/86] Bug 1046020 - Follow-up: Revert added initializers. r=trivial --- mobile/android/base/browserid/MockMyIDTokenFactory.java | 2 +- .../fxa/authenticator/FxAccountAuthenticatorService.java | 2 +- mobile/android/base/fxa/sync/FxAccountSyncAdapter.java | 2 +- mobile/android/base/fxa/sync/FxAccountSyncService.java | 2 +- mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java | 4 ++-- mobile/android/base/fxa/tasks/FxAccountSetupTask.java | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/mobile/android/base/browserid/MockMyIDTokenFactory.java b/mobile/android/base/browserid/MockMyIDTokenFactory.java index ee4933ec3b2..c807d4cbbd3 100644 --- a/mobile/android/base/browserid/MockMyIDTokenFactory.java +++ b/mobile/android/base/browserid/MockMyIDTokenFactory.java @@ -21,7 +21,7 @@ public class MockMyIDTokenFactory { public static final BigInteger MOCKMYID_g = new BigInteger("c52a4a0ff3b7e61fdf1867ce84138369a6154f4afa92966e3c827e25cfa6cf508b90e5de419e1337e07a2e9e2a3cd5dea704d175f8ebf6af397d69e110b96afb17c7a03259329e4829b0d03bbc7896b15b4ade53e130858cc34d96269aa89041f409136c7242a38895c9d5bccad4f389af1d7a4bd1398bd072dffa896233397a", 16); // Computed lazily by static getMockMyIDPrivateKey. - protected static SigningPrivateKey cachedMockMyIDPrivateKey = null; + protected static SigningPrivateKey cachedMockMyIDPrivateKey; public static SigningPrivateKey getMockMyIDPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException { if (cachedMockMyIDPrivateKey == null) { diff --git a/mobile/android/base/fxa/authenticator/FxAccountAuthenticatorService.java b/mobile/android/base/fxa/authenticator/FxAccountAuthenticatorService.java index d66163a8161..d138e6c45a2 100644 --- a/mobile/android/base/fxa/authenticator/FxAccountAuthenticatorService.java +++ b/mobile/android/base/fxa/authenticator/FxAccountAuthenticatorService.java @@ -14,7 +14,7 @@ public class FxAccountAuthenticatorService extends Service { public static final String LOG_TAG = FxAccountAuthenticatorService.class.getSimpleName(); // Lazily initialized by getAuthenticator. - protected FxAccountAuthenticator accountAuthenticator = null; + protected FxAccountAuthenticator accountAuthenticator; protected synchronized FxAccountAuthenticator getAuthenticator() { if (accountAuthenticator == null) { diff --git a/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java b/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java index 903c10d328c..b13cd0c26a6 100644 --- a/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java +++ b/mobile/android/base/fxa/sync/FxAccountSyncAdapter.java @@ -74,7 +74,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter { // Used to do cheap in-memory rate limiting. Don't sync again if we // successfully synced within this duration. private static final int MINIMUM_SYNC_DELAY_MILLIS = 15 * 1000; // 15 seconds. - private volatile long lastSyncRealtimeMillis = 0L; + private volatile long lastSyncRealtimeMillis; protected final ExecutorService executor; protected final FxAccountNotificationManager notificationManager; diff --git a/mobile/android/base/fxa/sync/FxAccountSyncService.java b/mobile/android/base/fxa/sync/FxAccountSyncService.java index 0d271e8615d..59c06ca9760 100644 --- a/mobile/android/base/fxa/sync/FxAccountSyncService.java +++ b/mobile/android/base/fxa/sync/FxAccountSyncService.java @@ -10,7 +10,7 @@ import android.os.IBinder; public class FxAccountSyncService extends Service { private static final Object syncAdapterLock = new Object(); - private static FxAccountSyncAdapter syncAdapter = null; + private static FxAccountSyncAdapter syncAdapter; @Override public void onCreate() { diff --git a/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java b/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java index fad35584a95..fc4b33f866c 100644 --- a/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java +++ b/mobile/android/base/fxa/sync/FxAccountSyncStatusHelper.java @@ -23,7 +23,7 @@ public class FxAccountSyncStatusHelper implements SyncStatusObserver { @SuppressWarnings("unused") private static final String LOG_TAG = FxAccountSyncStatusHelper.class.getSimpleName(); - protected static FxAccountSyncStatusHelper sInstance = null; + protected static FxAccountSyncStatusHelper sInstance; public synchronized static FxAccountSyncStatusHelper getInstance() { if (sInstance == null) { @@ -33,7 +33,7 @@ public class FxAccountSyncStatusHelper implements SyncStatusObserver { } // Used to unregister this as a listener. - protected Object handle = null; + protected Object handle; // Maps delegates to whether their underlying Android account was syncing the // last time we observed a status change. diff --git a/mobile/android/base/fxa/tasks/FxAccountSetupTask.java b/mobile/android/base/fxa/tasks/FxAccountSetupTask.java index 4ef71de6072..aa2b5324dab 100644 --- a/mobile/android/base/fxa/tasks/FxAccountSetupTask.java +++ b/mobile/android/base/fxa/tasks/FxAccountSetupTask.java @@ -85,9 +85,9 @@ public abstract class FxAccountSetupTask extends AsyncTask implements RequestDelegate { protected final CountDownLatch latch; - public T response = null; - public Exception exception = null; - public FxAccountClientRemoteException failure = null; + public T response; + public Exception exception; + public FxAccountClientRemoteException failure; protected InnerRequestDelegate(CountDownLatch latch) { this.latch = latch; From 5ce2034be17d699601ce80a174b52bc752644f96 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Mon, 18 Aug 2014 11:38:24 +0200 Subject: [PATCH 65/86] Bug 1054815 - Fix browser_tabview_bug712203.js to not connect to google.com r=smacleod --- browser/components/tabview/test/browser_tabview_bug712203.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/components/tabview/test/browser_tabview_bug712203.js b/browser/components/tabview/test/browser_tabview_bug712203.js index 279471e22f6..c82aadc78d4 100644 --- a/browser/components/tabview/test/browser_tabview_bug712203.js +++ b/browser/components/tabview/test/browser_tabview_bug712203.js @@ -9,13 +9,13 @@ function test() { let newState = { windows: [{ tabs: [{ - entries: [{ url: "http://www.google.com" }], + entries: [{ url: "about:mozilla" }], hidden: true, attributes: {}, extData: { "tabview-tab": '{"bounds":{"left":21,"top":29,"width":204,"height":153},' + - '"userSize":null,"url":"http://www.google.com","groupID":1,' + + '"userSize":null,"url":"about:mozilla","groupID":1,' + '"imageData":null,"title":null}' } },{ From 5f28cdacf99e9edf516eb11c05abe9e4ca411994 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Mon, 18 Aug 2014 15:20:02 -0700 Subject: [PATCH 66/86] (no bug) Fix incorrect indentation in nsComputedDOMStyle::DoGetMixBlendMode. whitespace-only, DONTBUILD --- layout/style/nsComputedDOMStyle.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index cfdd62b95a9..31f34a15f87 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -4155,10 +4155,10 @@ nsComputedDOMStyle::DoGetMinWidth() CSSValue* nsComputedDOMStyle::DoGetMixBlendMode() { - nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; - val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mMixBlendMode, - nsCSSProps::kBlendModeKTable)); - return val; + nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue; + val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mMixBlendMode, + nsCSSProps::kBlendModeKTable)); + return val; } CSSValue* From 9a452a126c53a5c9d4ff8e50c5e9d3f4011bbf86 Mon Sep 17 00:00:00 2001 From: Rafael Kourdis Date: Mon, 18 Aug 2014 18:42:14 -0400 Subject: [PATCH 67/86] Bug 1030487 - Don't report main-thread I/O to Telemetry unless it lasts more than 50ms; r=vladan --- toolkit/components/telemetry/Telemetry.cpp | 9 ++++++++- xpcom/build/IOInterposer.cpp | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index c34e255c1ce..f1b6f4a5bc0 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -410,7 +410,10 @@ void TelemetryIOInterposeObserver::AddPath(const nsAString& aPath, { mSafeDirs.AppendElement(SafeDir(aPath, aSubstName)); } - + +// Threshold for reporting slow main-thread I/O (50 milliseconds). +const TimeDuration kTelemetryReportThreshold = TimeDuration::FromMilliseconds(50); + void TelemetryIOInterposeObserver::Observe(Observation& aOb) { // We only report main-thread I/O @@ -424,6 +427,10 @@ void TelemetryIOInterposeObserver::Observe(Observation& aOb) return; } + if (aOb.Duration() < kTelemetryReportThreshold) { + return; + } + // Get the filename const char16_t* filename = aOb.Filename(); diff --git a/xpcom/build/IOInterposer.cpp b/xpcom/build/IOInterposer.cpp index 91d859f1cac..aa1e3aae032 100644 --- a/xpcom/build/IOInterposer.cpp +++ b/xpcom/build/IOInterposer.cpp @@ -350,6 +350,7 @@ public: "IOInterposer", false) { mStart = TimeStamp::Now(); + mEnd = mStart; } }; From 692b3ada1dd373bf3192eee5f36eba45a516b8a4 Mon Sep 17 00:00:00 2001 From: Georgios Kontaxis Date: Mon, 18 Aug 2014 14:58:33 -0700 Subject: [PATCH 68/86] Bug 1055180: cleanup functions in test_classified_annotations and test_allowlisted_annotations. Making sure the nsChannelClassifier::ShouldEnableTrackingProtection does not abort on chrome URIs. (r=mmc) --- .../mochitest/classifiedAnnotatedFrame.html | 2 ++ .../test_allowlisted_annotations.html | 11 ++++------- .../mochitest/test_classified_annotations.html | 18 +++++++++++------- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedFrame.html b/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedFrame.html index 83e8841ee06..3793a38cee3 100644 --- a/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedFrame.html +++ b/toolkit/components/url-classifier/tests/mochitest/classifiedAnnotatedFrame.html @@ -81,6 +81,8 @@ function checkLoads() { window.parent.is(allNodeMatch, true, "All tracking nodes are expected to be annotated as such"); + // Unset prefs, etc. + window.parent.cleanup(); // End (parent) test. window.parent.SimpleTest.finish(); } diff --git a/toolkit/components/url-classifier/tests/mochitest/test_allowlisted_annotations.html b/toolkit/components/url-classifier/tests/mochitest/test_allowlisted_annotations.html index 9bdb11bfd60..c3015df853d 100644 --- a/toolkit/components/url-classifier/tests/mochitest/test_allowlisted_annotations.html +++ b/toolkit/components/url-classifier/tests/mochitest/test_allowlisted_annotations.html @@ -40,6 +40,8 @@ function clearPermissions() { ok(!SpecialPowers.testPermission("trackingprotection", Ci.nsIPermissionManager.ALLOW_ACTION, { url: "https://allowlisted.example.com" })); + SpecialPowers.clearUserPref("privacy.trackingprotection.enabled"); + SpecialPowers.clearUserPref("channelclassifier.allowlist_example"); } function doUpdate(update) { @@ -60,13 +62,8 @@ function doUpdate(update) { SimpleTest.finish(); }, updateSuccess: function(requestedTimeout) { - SpecialPowers.pushPrefEnv( - {"set" : [["privacy.trackingprotection.enabled", true]]}, - function loadTestFrame() { - document.getElementById("testFrame").src = - "allowlistAnnotatedFrame.html"; - } - ); + SpecialPowers.setBoolPref("privacy.trackingprotection.enabled", true); + document.getElementById("testFrame").src = "allowlistAnnotatedFrame.html"; } }; diff --git a/toolkit/components/url-classifier/tests/mochitest/test_classified_annotations.html b/toolkit/components/url-classifier/tests/mochitest/test_classified_annotations.html index beb9e155bbd..d29c8eea876 100644 --- a/toolkit/components/url-classifier/tests/mochitest/test_classified_annotations.html +++ b/toolkit/components/url-classifier/tests/mochitest/test_classified_annotations.html @@ -24,6 +24,11 @@ var testUpdate = "a:524:32:" + testData.length + "\n" + testData; +function cleanup() { + SpecialPowers.clearUserPref("privacy.trackingprotection.enabled"); + SpecialPowers.clearUserPref("channelclassifier.allowlist_example"); +} + var dbService = Cc["@mozilla.org/url-classifier/dbservice;1"] .getService(Ci.nsIUrlClassifierDBService); @@ -45,13 +50,12 @@ function doUpdate(update) { SimpleTest.finish(); }, updateSuccess: function(requestedTimeout) { - SpecialPowers.pushPrefEnv( - {"set" : [["privacy.trackingprotection.enabled", true]]}, - function loadTestFrame() { - document.getElementById("testFrame").src = - "classifiedAnnotatedFrame.html"; - } - ); + SpecialPowers.setBoolPref("privacy.trackingprotection.enabled", true); + // Make sure chrome:// URIs are processed. This does not white-list + // any URIs unless 'https://allowlisted.example.com' is added in the + // permission manager (see test_allowlisted_annotations.html) + SpecialPowers.setBoolPref("channelclassifier.allowlist_example", true); + document.getElementById("testFrame").src = "classifiedAnnotatedFrame.html"; } }; From f56038f9c1aa9bd964d12a9b72c5ddec177a88c8 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Mon, 18 Aug 2014 16:01:20 -0700 Subject: [PATCH 69/86] Bug 1054394 - Avoid clang internal compiler error in Zone.h. r=jfkthame --- js/src/gc/Zone.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 1749052518d..2e3a624a005 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -421,7 +421,7 @@ class CompartmentsIterT void next() { JS_ASSERT(!done()); - JS_ASSERT(!comp->done()); + JS_ASSERT(!comp.ref().done()); comp->next(); if (comp->done()) { comp.reset(); From ea9adfa2eaaecd898d17a80bfd05fabcac65e510 Mon Sep 17 00:00:00 2001 From: David Burns Date: Tue, 19 Aug 2014 00:07:56 +0100 Subject: [PATCH 70/86] Bug 1055088: Update Marionette HtmlElement documentation for is_enabled; r=jgriffin --- testing/marionette/client/marionette/marionette.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index e91d301ebcf..d73756ad203 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -127,7 +127,11 @@ class HTMLElement(object): def is_enabled(self): ''' - Returns True if the element is enabled. + This command will return False if all the following criteria are met otherwise return True: + + * A form control is disabled. + * A HtmlElement has a disabled boolean attribute. + ''' return self.marionette._send_message('isElementEnabled', 'value', id=self.id) From d1f1a22b91b445d35364d9228860fbb4b4a4c5fb Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 18 Aug 2014 16:18:28 -0700 Subject: [PATCH 71/86] Bug 1045826 - Add missing null check in popup blocking (r=felipe) --- toolkit/content/widgets/browser.xml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index 10c1378f0bb..0a104edcdcc 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -845,13 +845,15 @@ switch (aMessage.name) { case "PopupBlocking:UpdateBlockedPopups": { this.blockedPopups = data.blockedPopups; - for (let i = 0; i < this.blockedPopups.length; i++) { - let scope = Components.utils.import("resource://gre/modules/BrowserUtils.jsm", {}); - let uri = scope.BrowserUtils.makeURI(this.blockedPopups[i].popupWindowURI); - this.blockedPopups[i].popupWindowURI = uri; - } - if (data.freshPopup) { - this.blockedPopups.reported = false; + if (this.blockedPopups) { + for (let i = 0; i < this.blockedPopups.length; i++) { + let scope = Components.utils.import("resource://gre/modules/BrowserUtils.jsm", {}); + let uri = scope.BrowserUtils.makeURI(this.blockedPopups[i].popupWindowURI); + this.blockedPopups[i].popupWindowURI = uri; + } + if (data.freshPopup) { + this.blockedPopups.reported = false; + } } this.updateBlockedPopups(); break; From 71d866e73e97adde4a04ca0cc3ba84ba87e947e2 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 18 Aug 2014 20:12:50 -0400 Subject: [PATCH 72/86] Bug 1007778 - Add a devtools API to make some Web Audio nodes pass through their inputs; r=roc,smaug --- content/media/AudioNodeStream.cpp | 29 +++++++++- content/media/AudioNodeStream.h | 6 +- content/media/webaudio/AudioNode.cpp | 18 ++++++ content/media/webaudio/AudioNode.h | 6 ++ content/media/webaudio/test/mochitest.ini | 8 +++ .../test/test_analyserNodeOutput.html | 43 +++++++++++++++ .../test/test_analyserNodePassThrough.html | 47 ++++++++++++++++ .../test_biquadFilterNodePassThrough.html | 47 ++++++++++++++++ .../test/test_convolverNodePassThrough.html | 48 ++++++++++++++++ .../test/test_delayNodePassThrough.html | 53 ++++++++++++++++++ ...est_dynamicsCompressorNodePassThrough.html | 47 ++++++++++++++++ .../test/test_gainNodePassThrough.html | 49 +++++++++++++++++ .../test/test_pannerNodePassThrough.html | 53 ++++++++++++++++++ .../test/test_waveShaperPassThrough.html | 55 +++++++++++++++++++ dom/webidl/AnalyserNode.webidl | 3 + dom/webidl/AudioNode.webidl | 5 ++ dom/webidl/BiquadFilterNode.webidl | 3 + dom/webidl/ConvolverNode.webidl | 3 + dom/webidl/DelayNode.webidl | 3 + dom/webidl/DynamicsCompressorNode.webidl | 3 + dom/webidl/GainNode.webidl | 3 + dom/webidl/PannerNode.webidl | 3 + dom/webidl/ScriptProcessorNode.webidl | 3 + dom/webidl/WaveShaperNode.webidl | 3 + 24 files changed, 537 insertions(+), 4 deletions(-) create mode 100644 content/media/webaudio/test/test_analyserNodeOutput.html create mode 100644 content/media/webaudio/test/test_analyserNodePassThrough.html create mode 100644 content/media/webaudio/test/test_biquadFilterNodePassThrough.html create mode 100644 content/media/webaudio/test/test_convolverNodePassThrough.html create mode 100644 content/media/webaudio/test/test_delayNodePassThrough.html create mode 100644 content/media/webaudio/test/test_dynamicsCompressorNodePassThrough.html create mode 100644 content/media/webaudio/test/test_gainNodePassThrough.html create mode 100644 content/media/webaudio/test/test_pannerNodePassThrough.html create mode 100644 content/media/webaudio/test/test_waveShaperPassThrough.html diff --git a/content/media/AudioNodeStream.cpp b/content/media/AudioNodeStream.cpp index 82cf083aa01..0903e048af2 100644 --- a/content/media/AudioNodeStream.cpp +++ b/content/media/AudioNodeStream.cpp @@ -261,6 +261,24 @@ AudioNodeStream::SetChannelMixingParameters(uint32_t aNumberOfChannels, aChannelInterpretation)); } +void +AudioNodeStream::SetPassThrough(bool aPassThrough) +{ + class Message : public ControlMessage { + public: + Message(AudioNodeStream* aStream, bool aPassThrough) + : ControlMessage(aStream), mPassThrough(aPassThrough) {} + virtual void Run() + { + static_cast(mStream)->mPassThrough = mPassThrough; + } + bool mPassThrough; + }; + + MOZ_ASSERT(this); + GraphImpl()->AppendMessage(new Message(this, aPassThrough)); +} + void AudioNodeStream::SetChannelMixingParametersImpl(uint32_t aNumberOfChannels, ChannelCountMode aChannelCountMode, @@ -453,10 +471,15 @@ AudioNodeStream::ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) ObtainInputBlock(inputChunks[i], i); } bool finished = false; - if (maxInputs <= 1 && mEngine->OutputCount() <= 1) { - mEngine->ProcessBlock(this, inputChunks[0], &mLastChunks[0], &finished); + if (mPassThrough) { + MOZ_ASSERT(outputCount == 1, "For now, we only support nodes that have one output port"); + mLastChunks[0] = inputChunks[0]; } else { - mEngine->ProcessBlocksOnPorts(this, inputChunks, mLastChunks, &finished); + if (maxInputs <= 1 && mEngine->OutputCount() <= 1) { + mEngine->ProcessBlock(this, inputChunks[0], &mLastChunks[0], &finished); + } else { + mEngine->ProcessBlocksOnPorts(this, inputChunks, mLastChunks, &finished); + } } for (uint16_t i = 0; i < outputCount; ++i) { NS_ASSERTION(mLastChunks[i].GetDuration() == WEBAUDIO_BLOCK_SIZE, diff --git a/content/media/AudioNodeStream.h b/content/media/AudioNodeStream.h index ad20b4aaeca..b76a28c309b 100644 --- a/content/media/AudioNodeStream.h +++ b/content/media/AudioNodeStream.h @@ -54,7 +54,8 @@ public: mKind(aKind), mNumberOfInputChannels(2), mMarkAsFinishedAfterThisBlock(false), - mAudioParamStream(false) + mAudioParamStream(false), + mPassThrough(false) { MOZ_ASSERT(NS_IsMainThread()); mChannelCountMode = ChannelCountMode::Max; @@ -85,6 +86,7 @@ public: void SetChannelMixingParameters(uint32_t aNumberOfChannels, ChannelCountMode aChannelCountMoe, ChannelInterpretation aChannelInterpretation); + void SetPassThrough(bool aPassThrough); ChannelInterpretation GetChannelInterpretation() { return mChannelInterpretation; @@ -192,6 +194,8 @@ protected: bool mMarkAsFinishedAfterThisBlock; // Whether the stream is an AudioParamHelper stream. bool mAudioParamStream; + // Whether the stream just passes its input through. + bool mPassThrough; }; } diff --git a/content/media/webaudio/AudioNode.cpp b/content/media/webaudio/AudioNode.cpp index 0dc5a28a4d2..1eb3a19eed2 100644 --- a/content/media/webaudio/AudioNode.cpp +++ b/content/media/webaudio/AudioNode.cpp @@ -65,6 +65,7 @@ AudioNode::AudioNode(AudioContext* aContext, , mChannelCountMode(aChannelCountMode) , mChannelInterpretation(aChannelInterpretation) , mId(gId++) + , mPassThrough(false) #ifdef DEBUG , mDemiseNotified(false) #endif @@ -416,5 +417,22 @@ AudioNode::RemoveOutputParam(AudioParam* aParam) mOutputParams.RemoveElement(aParam); } +bool +AudioNode::PassThrough() const +{ + MOZ_ASSERT(NumberOfInputs() == 1 && NumberOfOutputs() == 1); + return mPassThrough; +} + +void +AudioNode::SetPassThrough(bool aPassThrough) +{ + MOZ_ASSERT(NumberOfInputs() == 1 && NumberOfOutputs() == 1); + mPassThrough = aPassThrough; + AudioNodeStream* ns = static_cast(mStream.get()); + MOZ_ASSERT(ns, "How come we don't have a stream here?"); + ns->SetPassThrough(mPassThrough); +} + } } diff --git a/content/media/webaudio/AudioNode.h b/content/media/webaudio/AudioNode.h index cd86e658e74..04263ba918a 100644 --- a/content/media/webaudio/AudioNode.h +++ b/content/media/webaudio/AudioNode.h @@ -133,6 +133,9 @@ public: uint32_t Id() const { return mId; } + bool PassThrough() const; + void SetPassThrough(bool aPassThrough); + uint32_t ChannelCount() const { return mChannelCount; } virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) { @@ -267,6 +270,9 @@ private: ChannelCountMode mChannelCountMode; ChannelInterpretation mChannelInterpretation; const uint32_t mId; + // Whether the node just passes through its input. This is a devtools API that + // only works for some node types. + bool mPassThrough; #ifdef DEBUG // In debug builds, check to make sure that the node demise notification has // been properly sent before the node is destroyed. diff --git a/content/media/webaudio/test/mochitest.ini b/content/media/webaudio/test/mochitest.ini index 3b4bb6900e3..9d38a0af82c 100644 --- a/content/media/webaudio/test/mochitest.ini +++ b/content/media/webaudio/test/mochitest.ini @@ -24,6 +24,8 @@ support-files = webaudio.js [test_analyserNode.html] +[test_analyserNodeOutput.html] +[test_analyserNodePassThrough.html] [test_AudioBuffer.html] [test_audioBufferSourceNode.html] [test_audioBufferSourceNodeEnded.html] @@ -49,6 +51,7 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752 [test_audioParamTimelineDestinationOffset.html] [test_badConnect.html] [test_biquadFilterNode.html] +[test_biquadFilterNodePassThrough.html] [test_biquadFilterNodeWithGain.html] [test_bug808374.html] [test_bug827541.html] @@ -74,6 +77,7 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752 [test_convolverNode.html] [test_convolverNode_mono_mono.html] [test_convolverNodeChannelCount.html] +[test_convolverNodePassThrough.html] [test_convolverNodeWithGain.html] [test_currentTime.html] [test_decodeMultichannel.html] @@ -81,6 +85,7 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752 [test_delayNodeAtMax.html] [test_delayNodeChannelChanges.html] [test_delayNodeCycles.html] +[test_delayNodePassThrough.html] [test_delayNodeSmallMaxDelay.html] [test_delayNodeTailIncrease.html] [test_delayNodeTailWithDisconnect.html] @@ -88,8 +93,10 @@ skip-if = (toolkit == 'gonk' && !debug) || (toolkit == 'android') #bug 906752 [test_delayNodeTailWithReconnect.html] [test_delayNodeWithGain.html] [test_dynamicsCompressorNode.html] +[test_dynamicsCompressorNodePassThrough.html] [test_gainNode.html] [test_gainNodeInLoop.html] +[test_gainNodePassThrough.html] [test_maxChannelCount.html] [test_mediaDecoding.html] [test_mediaElementAudioSourceNode.html] @@ -125,4 +132,5 @@ skip-if = (toolkit == 'gonk' && !debug) [test_waveDecoder.html] [test_waveShaper.html] [test_waveShaperNoCurve.html] +[test_waveShaperPassThrough.html] [test_waveShaperZeroLengthCurve.html] diff --git a/content/media/webaudio/test/test_analyserNodeOutput.html b/content/media/webaudio/test/test_analyserNodeOutput.html new file mode 100644 index 00000000000..e6255fee006 --- /dev/null +++ b/content/media/webaudio/test/test_analyserNodeOutput.html @@ -0,0 +1,43 @@ + + + + Test AnalyserNode + + + + + +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_analyserNodePassThrough.html b/content/media/webaudio/test/test_analyserNodePassThrough.html new file mode 100644 index 00000000000..37d1db51031 --- /dev/null +++ b/content/media/webaudio/test/test_analyserNodePassThrough.html @@ -0,0 +1,47 @@ + + + + Test AnalyserNode with passthrough + + + + + +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_biquadFilterNodePassThrough.html b/content/media/webaudio/test/test_biquadFilterNodePassThrough.html new file mode 100644 index 00000000000..59fc8ab4f5b --- /dev/null +++ b/content/media/webaudio/test/test_biquadFilterNodePassThrough.html @@ -0,0 +1,47 @@ + + + + Test BiquadFilterNode with passthrough + + + + + +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_convolverNodePassThrough.html b/content/media/webaudio/test/test_convolverNodePassThrough.html new file mode 100644 index 00000000000..d5f9ef8ab5e --- /dev/null +++ b/content/media/webaudio/test/test_convolverNodePassThrough.html @@ -0,0 +1,48 @@ + + + + Test ConvolverNode with passthrough + + + + + +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_delayNodePassThrough.html b/content/media/webaudio/test/test_delayNodePassThrough.html new file mode 100644 index 00000000000..4945ee95c7b --- /dev/null +++ b/content/media/webaudio/test/test_delayNodePassThrough.html @@ -0,0 +1,53 @@ + + + + Test DelayNode + + + + +
    +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_dynamicsCompressorNodePassThrough.html b/content/media/webaudio/test/test_dynamicsCompressorNodePassThrough.html new file mode 100644 index 00000000000..1be838a4ebb --- /dev/null +++ b/content/media/webaudio/test/test_dynamicsCompressorNodePassThrough.html @@ -0,0 +1,47 @@ + + + + Test DynamicsCompressorNode with passthrough + + + + + +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_gainNodePassThrough.html b/content/media/webaudio/test/test_gainNodePassThrough.html new file mode 100644 index 00000000000..2a7cd6bf4ce --- /dev/null +++ b/content/media/webaudio/test/test_gainNodePassThrough.html @@ -0,0 +1,49 @@ + + + + Test GainNode with passthrough + + + + + +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_pannerNodePassThrough.html b/content/media/webaudio/test/test_pannerNodePassThrough.html new file mode 100644 index 00000000000..e44368e9636 --- /dev/null +++ b/content/media/webaudio/test/test_pannerNodePassThrough.html @@ -0,0 +1,53 @@ + + + + Test PannerNode with passthrough + + + + + +
    +
    +
    + + diff --git a/content/media/webaudio/test/test_waveShaperPassThrough.html b/content/media/webaudio/test/test_waveShaperPassThrough.html new file mode 100644 index 00000000000..52c70d3c2f9 --- /dev/null +++ b/content/media/webaudio/test/test_waveShaperPassThrough.html @@ -0,0 +1,55 @@ + + + + Test WaveShaperNode with passthrough + + + + + +
    +
    +
    + + diff --git a/dom/webidl/AnalyserNode.webidl b/dom/webidl/AnalyserNode.webidl index e6afdc58ab2..aaed3f09c39 100644 --- a/dom/webidl/AnalyserNode.webidl +++ b/dom/webidl/AnalyserNode.webidl @@ -35,3 +35,6 @@ interface AnalyserNode : AudioNode { }; +// Mozilla extension +AnalyserNode implements AudioNodePassThrough; + diff --git a/dom/webidl/AudioNode.webidl b/dom/webidl/AudioNode.webidl index ed077f953df..3bb8f4f41b4 100644 --- a/dom/webidl/AudioNode.webidl +++ b/dom/webidl/AudioNode.webidl @@ -48,4 +48,9 @@ partial interface AudioNode { [ChromeOnly] readonly attribute unsigned long id; }; +[NoInterfaceObject] +interface AudioNodePassThrough { + [ChromeOnly] + attribute boolean passThrough; +}; diff --git a/dom/webidl/BiquadFilterNode.webidl b/dom/webidl/BiquadFilterNode.webidl index 7103c4f6daf..daa35ffb0bb 100644 --- a/dom/webidl/BiquadFilterNode.webidl +++ b/dom/webidl/BiquadFilterNode.webidl @@ -35,3 +35,6 @@ interface BiquadFilterNode : AudioNode { }; +// Mozilla extension +BiquadFilterNode implements AudioNodePassThrough; + diff --git a/dom/webidl/ConvolverNode.webidl b/dom/webidl/ConvolverNode.webidl index a94329799cc..fcdebe1eef6 100644 --- a/dom/webidl/ConvolverNode.webidl +++ b/dom/webidl/ConvolverNode.webidl @@ -18,3 +18,6 @@ interface ConvolverNode : AudioNode { }; +// Mozilla extension +ConvolverNode implements AudioNodePassThrough; + diff --git a/dom/webidl/DelayNode.webidl b/dom/webidl/DelayNode.webidl index 301f7660e40..631ffad4e5a 100644 --- a/dom/webidl/DelayNode.webidl +++ b/dom/webidl/DelayNode.webidl @@ -16,3 +16,6 @@ interface DelayNode : AudioNode { }; +// Mozilla extension +DelayNode implements AudioNodePassThrough; + diff --git a/dom/webidl/DynamicsCompressorNode.webidl b/dom/webidl/DynamicsCompressorNode.webidl index 428ae3326c0..5e7021cdc28 100644 --- a/dom/webidl/DynamicsCompressorNode.webidl +++ b/dom/webidl/DynamicsCompressorNode.webidl @@ -21,3 +21,6 @@ interface DynamicsCompressorNode : AudioNode { }; +// Mozilla extension +DynamicsCompressorNode implements AudioNodePassThrough; + diff --git a/dom/webidl/GainNode.webidl b/dom/webidl/GainNode.webidl index f09f745348f..56ba0bda056 100644 --- a/dom/webidl/GainNode.webidl +++ b/dom/webidl/GainNode.webidl @@ -16,3 +16,6 @@ interface GainNode : AudioNode { }; +// Mozilla extension +GainNode implements AudioNodePassThrough; + diff --git a/dom/webidl/PannerNode.webidl b/dom/webidl/PannerNode.webidl index 5f5fa3e3cbd..e8e497b5d27 100644 --- a/dom/webidl/PannerNode.webidl +++ b/dom/webidl/PannerNode.webidl @@ -44,3 +44,6 @@ interface PannerNode : AudioNode { }; +// Mozilla extension +PannerNode implements AudioNodePassThrough; + diff --git a/dom/webidl/ScriptProcessorNode.webidl b/dom/webidl/ScriptProcessorNode.webidl index 8015a992c66..4d299c8dc98 100644 --- a/dom/webidl/ScriptProcessorNode.webidl +++ b/dom/webidl/ScriptProcessorNode.webidl @@ -18,3 +18,6 @@ interface ScriptProcessorNode : AudioNode { }; +// Mozilla extension +ScriptProcessorNode implements AudioNodePassThrough; + diff --git a/dom/webidl/WaveShaperNode.webidl b/dom/webidl/WaveShaperNode.webidl index 91487879b7b..e22d9c59a0e 100644 --- a/dom/webidl/WaveShaperNode.webidl +++ b/dom/webidl/WaveShaperNode.webidl @@ -23,3 +23,6 @@ interface WaveShaperNode : AudioNode { }; +// Mozilla extension +WaveShaperNode implements AudioNodePassThrough; + From 237f3ed1dbcd7bf9c54e6015614e0ececa5e19d6 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Mon, 18 Aug 2014 17:19:26 -0700 Subject: [PATCH 73/86] Backed out changeset c69cc7b3c21d (bug 1016467) for B2G Windows bustage --- testing/mozbase/mozversion/tests/test_apk.py | 32 -------------------- 1 file changed, 32 deletions(-) delete mode 100644 testing/mozbase/mozversion/tests/test_apk.py diff --git a/testing/mozbase/mozversion/tests/test_apk.py b/testing/mozbase/mozversion/tests/test_apk.py deleted file mode 100644 index 8e58ffff734..00000000000 --- a/testing/mozbase/mozversion/tests/test_apk.py +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env python - -# 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/. - -import tempfile -import unittest -import zipfile -from mozversion import get_version - - -class ApkTest(unittest.TestCase): - """test getting version information from an android .apk""" - - application_changeset = 'a'*40 - platform_changeset = 'b'*40 - - def test_basic(self): - with tempfile.NamedTemporaryFile() as f: - with zipfile.ZipFile(f.name, 'w') as z: - z.writestr('application.ini', - """[App]\nSourceStamp=%s\n""" % self.application_changeset) - z.writestr('platform.ini', - """[Build]\nSourceStamp=%s\n""" % self.platform_changeset) - z.writestr('AndroidManifest.xml', '') - v = get_version(f.name) - self.assertEqual(v.get('application_changeset'), self.application_changeset) - self.assertEqual(v.get('platform_changeset'), self.platform_changeset) - -if __name__ == '__main__': - unittest.main() From 22b151eb6bbfdc5717704853ed39d23fe997c940 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Mon, 18 Aug 2014 20:59:37 -0400 Subject: [PATCH 74/86] Bug 1055286 - Flatten editor/libeditor/text to editor/libeditor; r=poiru --HG-- rename : editor/libeditor/text/crashtests/403965-1.xhtml => editor/libeditor/crashtests/403965-1.xhtml rename : editor/libeditor/text/crashtests/580151-1.xhtml => editor/libeditor/crashtests/580151-1.xhtml rename : editor/libeditor/text/nsInternetCiter.cpp => editor/libeditor/nsInternetCiter.cpp rename : editor/libeditor/text/nsInternetCiter.h => editor/libeditor/nsInternetCiter.h rename : editor/libeditor/text/nsPlaintextDataTransfer.cpp => editor/libeditor/nsPlaintextDataTransfer.cpp rename : editor/libeditor/text/nsPlaintextEditor.cpp => editor/libeditor/nsPlaintextEditor.cpp rename : editor/libeditor/text/nsPlaintextEditor.h => editor/libeditor/nsPlaintextEditor.h rename : editor/libeditor/text/nsTextEditRules.cpp => editor/libeditor/nsTextEditRules.cpp rename : editor/libeditor/text/nsTextEditRules.h => editor/libeditor/nsTextEditRules.h rename : editor/libeditor/text/nsTextEditRulesBidi.cpp => editor/libeditor/nsTextEditRulesBidi.cpp rename : editor/libeditor/text/nsTextEditUtils.cpp => editor/libeditor/nsTextEditUtils.cpp rename : editor/libeditor/text/nsTextEditUtils.h => editor/libeditor/nsTextEditUtils.h rename : editor/libeditor/text/tests/test_bug1026397.html => editor/libeditor/tests/test_bug1026397.html rename : editor/libeditor/text/tests/test_bug318065.html => editor/libeditor/tests/test_bug318065.html rename : editor/libeditor/text/tests/test_bug471319.html => editor/libeditor/tests/test_bug471319.html rename : editor/libeditor/text/tests/test_bug471722.html => editor/libeditor/tests/test_bug471722.html rename : editor/libeditor/text/tests/test_bug483651.html => editor/libeditor/tests/test_bug483651.html rename : editor/libeditor/text/tests/test_bug527935.html => editor/libeditor/tests/test_bug527935.html rename : editor/libeditor/text/tests/test_bug569988.html => editor/libeditor/tests/test_bug569988.html rename : editor/libeditor/text/tests/test_bug590554.html => editor/libeditor/tests/test_bug590554.html rename : editor/libeditor/text/tests/test_bug596001.html => editor/libeditor/tests/test_bug596001.html rename : editor/libeditor/text/tests/test_bug596333.html => editor/libeditor/tests/test_bug596333.html rename : editor/libeditor/text/tests/test_bug596506.html => editor/libeditor/tests/test_bug596506.html rename : editor/libeditor/text/tests/test_bug597331.html => editor/libeditor/tests/test_bug597331.html rename : editor/libeditor/text/tests/test_bug600570.html => editor/libeditor/tests/test_bug600570.html rename : editor/libeditor/text/tests/test_bug602130.html => editor/libeditor/tests/test_bug602130.html rename : editor/libeditor/text/tests/test_bug603556.html => editor/libeditor/tests/test_bug603556.html rename : editor/libeditor/text/tests/test_bug604532.html => editor/libeditor/tests/test_bug604532.html rename : editor/libeditor/text/tests/test_bug625452.html => editor/libeditor/tests/test_bug625452.html rename : editor/libeditor/text/tests/test_bug629172.html => editor/libeditor/tests/test_bug629172.html rename : editor/libeditor/text/tests/test_bug636465.xul => editor/libeditor/tests/test_bug636465.xul rename : editor/libeditor/text/tests/test_bug638596.html => editor/libeditor/tests/test_bug638596.html rename : editor/libeditor/text/tests/test_bug641466.html => editor/libeditor/tests/test_bug641466.html rename : editor/libeditor/text/tests/test_bug645914.html => editor/libeditor/tests/test_bug645914.html rename : editor/libeditor/text/tests/test_bug681229.html => editor/libeditor/tests/test_bug681229.html rename : editor/libeditor/text/tests/test_bug692520.html => editor/libeditor/tests/test_bug692520.html rename : editor/libeditor/text/tests/test_bug740784.html => editor/libeditor/tests/test_bug740784.html rename : editor/libeditor/text/tests/test_bug757771.html => editor/libeditor/tests/test_bug757771.html rename : editor/libeditor/text/tests/test_bug830600.html => editor/libeditor/tests/test_bug830600.html rename : editor/libeditor/text/tests/test_dom_input_event_on_texteditor.html => editor/libeditor/tests/test_dom_input_event_on_texteditor.html rename : editor/libeditor/text/tests/test_texteditor_keyevent_handling.html => editor/libeditor/tests/test_texteditor_keyevent_handling.html --- content/html/content/src/moz.build | 1 - editor/crashtests.list | 1 - .../{text => }/crashtests/403965-1.xhtml | 0 .../{text => }/crashtests/580151-1.xhtml | 0 editor/libeditor/crashtests/crashtests.list | 2 ++ editor/libeditor/moz.build | 9 +++-- editor/libeditor/nsEditor.cpp | 2 +- .../libeditor/{text => }/nsInternetCiter.cpp | 2 +- editor/libeditor/{text => }/nsInternetCiter.h | 0 .../{text => }/nsPlaintextDataTransfer.cpp | 0 .../{text => }/nsPlaintextEditor.cpp | 2 +- .../libeditor/{text => }/nsPlaintextEditor.h | 0 .../libeditor/{text => }/nsTextEditRules.cpp | 0 editor/libeditor/{text => }/nsTextEditRules.h | 0 .../{text => }/nsTextEditRulesBidi.cpp | 0 .../libeditor/{text => }/nsTextEditUtils.cpp | 0 editor/libeditor/{text => }/nsTextEditUtils.h | 0 editor/libeditor/tests/chrome.ini | 10 ++++++ editor/libeditor/tests/mochitest.ini | 30 +++++++++++++++++ .../{text => }/tests/test_bug1026397.html | 0 .../{text => }/tests/test_bug318065.html | 0 .../{text => }/tests/test_bug471319.html | 0 .../{text => }/tests/test_bug471722.html | 0 .../{text => }/tests/test_bug483651.html | 0 .../{text => }/tests/test_bug527935.html | 0 .../{text => }/tests/test_bug569988.html | 0 .../{text => }/tests/test_bug590554.html | 0 .../{text => }/tests/test_bug596001.html | 0 .../{text => }/tests/test_bug596333.html | 0 .../{text => }/tests/test_bug596506.html | 0 .../{text => }/tests/test_bug597331.html | 0 .../{text => }/tests/test_bug600570.html | 0 .../{text => }/tests/test_bug602130.html | 0 .../{text => }/tests/test_bug603556.html | 0 .../{text => }/tests/test_bug604532.html | 0 .../{text => }/tests/test_bug625452.html | 0 .../{text => }/tests/test_bug629172.html | 0 .../{text => }/tests/test_bug636465.xul | 0 .../{text => }/tests/test_bug638596.html | 0 .../{text => }/tests/test_bug641466.html | 0 .../{text => }/tests/test_bug645914.html | 0 .../{text => }/tests/test_bug681229.html | 0 .../{text => }/tests/test_bug692520.html | 0 .../{text => }/tests/test_bug740784.html | 0 .../{text => }/tests/test_bug757771.html | 0 .../{text => }/tests/test_bug830600.html | 0 .../test_dom_input_event_on_texteditor.html | 0 .../test_texteditor_keyevent_handling.html | 0 .../libeditor/text/crashtests/crashtests.list | 2 -- editor/libeditor/text/moz.build | 28 ---------------- editor/libeditor/text/tests/chrome.ini | 10 ------ editor/libeditor/text/tests/mochitest.ini | 33 ------------------- layout/build/moz.build | 1 - layout/forms/moz.build | 1 - testing/mochitest/androidx86.json | 4 +-- 55 files changed, 53 insertions(+), 85 deletions(-) rename editor/libeditor/{text => }/crashtests/403965-1.xhtml (100%) rename editor/libeditor/{text => }/crashtests/580151-1.xhtml (100%) rename editor/libeditor/{text => }/nsInternetCiter.cpp (99%) rename editor/libeditor/{text => }/nsInternetCiter.h (100%) rename editor/libeditor/{text => }/nsPlaintextDataTransfer.cpp (100%) rename editor/libeditor/{text => }/nsPlaintextEditor.cpp (99%) rename editor/libeditor/{text => }/nsPlaintextEditor.h (100%) rename editor/libeditor/{text => }/nsTextEditRules.cpp (100%) rename editor/libeditor/{text => }/nsTextEditRules.h (100%) rename editor/libeditor/{text => }/nsTextEditRulesBidi.cpp (100%) rename editor/libeditor/{text => }/nsTextEditUtils.cpp (100%) rename editor/libeditor/{text => }/nsTextEditUtils.h (100%) rename editor/libeditor/{text => }/tests/test_bug1026397.html (100%) rename editor/libeditor/{text => }/tests/test_bug318065.html (100%) rename editor/libeditor/{text => }/tests/test_bug471319.html (100%) rename editor/libeditor/{text => }/tests/test_bug471722.html (100%) rename editor/libeditor/{text => }/tests/test_bug483651.html (100%) rename editor/libeditor/{text => }/tests/test_bug527935.html (100%) rename editor/libeditor/{text => }/tests/test_bug569988.html (100%) rename editor/libeditor/{text => }/tests/test_bug590554.html (100%) rename editor/libeditor/{text => }/tests/test_bug596001.html (100%) rename editor/libeditor/{text => }/tests/test_bug596333.html (100%) rename editor/libeditor/{text => }/tests/test_bug596506.html (100%) rename editor/libeditor/{text => }/tests/test_bug597331.html (100%) rename editor/libeditor/{text => }/tests/test_bug600570.html (100%) rename editor/libeditor/{text => }/tests/test_bug602130.html (100%) rename editor/libeditor/{text => }/tests/test_bug603556.html (100%) rename editor/libeditor/{text => }/tests/test_bug604532.html (100%) rename editor/libeditor/{text => }/tests/test_bug625452.html (100%) rename editor/libeditor/{text => }/tests/test_bug629172.html (100%) rename editor/libeditor/{text => }/tests/test_bug636465.xul (100%) rename editor/libeditor/{text => }/tests/test_bug638596.html (100%) rename editor/libeditor/{text => }/tests/test_bug641466.html (100%) rename editor/libeditor/{text => }/tests/test_bug645914.html (100%) rename editor/libeditor/{text => }/tests/test_bug681229.html (100%) rename editor/libeditor/{text => }/tests/test_bug692520.html (100%) rename editor/libeditor/{text => }/tests/test_bug740784.html (100%) rename editor/libeditor/{text => }/tests/test_bug757771.html (100%) rename editor/libeditor/{text => }/tests/test_bug830600.html (100%) rename editor/libeditor/{text => }/tests/test_dom_input_event_on_texteditor.html (100%) rename editor/libeditor/{text => }/tests/test_texteditor_keyevent_handling.html (100%) delete mode 100644 editor/libeditor/text/crashtests/crashtests.list delete mode 100644 editor/libeditor/text/moz.build delete mode 100644 editor/libeditor/text/tests/chrome.ini delete mode 100644 editor/libeditor/text/tests/mochitest.ini diff --git a/content/html/content/src/moz.build b/content/html/content/src/moz.build index 9421e0978b8..e23a8fa5ec9 100644 --- a/content/html/content/src/moz.build +++ b/content/html/content/src/moz.build @@ -179,7 +179,6 @@ LOCAL_INCLUDES += [ '/dom/canvas', '/dom/xbl', '/editor/libeditor', - '/editor/libeditor/text', '/editor/txmgr', '/layout/forms', '/layout/generic', diff --git a/editor/crashtests.list b/editor/crashtests.list index f6eed56966f..5c8a04b68aa 100644 --- a/editor/crashtests.list +++ b/editor/crashtests.list @@ -3,6 +3,5 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. include libeditor/crashtests/crashtests.list -include libeditor/text/crashtests/crashtests.list include composer/crashtests/crashtests.list include txmgr/tests/crashtests/crashtests.list diff --git a/editor/libeditor/text/crashtests/403965-1.xhtml b/editor/libeditor/crashtests/403965-1.xhtml similarity index 100% rename from editor/libeditor/text/crashtests/403965-1.xhtml rename to editor/libeditor/crashtests/403965-1.xhtml diff --git a/editor/libeditor/text/crashtests/580151-1.xhtml b/editor/libeditor/crashtests/580151-1.xhtml similarity index 100% rename from editor/libeditor/text/crashtests/580151-1.xhtml rename to editor/libeditor/crashtests/580151-1.xhtml diff --git a/editor/libeditor/crashtests/crashtests.list b/editor/libeditor/crashtests/crashtests.list index c743ac1b1fb..be753fdc175 100644 --- a/editor/libeditor/crashtests/crashtests.list +++ b/editor/libeditor/crashtests/crashtests.list @@ -3,6 +3,7 @@ load 336104.html load 382527-1.html load 382778-1.html load 402172-1.html +load 403965-1.xhtml load 407074-1.html load 407079-1.html load 407256-1.html @@ -26,6 +27,7 @@ load 503709-1.xhtml load 513375-1.xhtml load 535632-1.xhtml load 574558-1.xhtml +load 580151-1.xhtml load 582138-1.xhtml load 612565-1.html asserts(0-6) load 615015-1.html # Bug 439258 diff --git a/editor/libeditor/moz.build b/editor/libeditor/moz.build index ec6d5a6aac7..bb58db18995 100644 --- a/editor/libeditor/moz.build +++ b/editor/libeditor/moz.build @@ -4,8 +4,6 @@ # 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/. -DIRS += ['text'] - TEST_DIRS += ['tests'] UNIFIED_SOURCES += [ @@ -39,9 +37,15 @@ UNIFIED_SOURCES += [ 'nsHTMLInlineTableEditor.cpp', 'nsHTMLObjectResizer.cpp', 'nsHTMLURIRefObject.cpp', + 'nsInternetCiter.cpp', + 'nsPlaintextDataTransfer.cpp', + 'nsPlaintextEditor.cpp', 'nsSelectionState.cpp', 'nsStyleSheetTxns.cpp', 'nsTableEditor.cpp', + 'nsTextEditRules.cpp', + 'nsTextEditRulesBidi.cpp', + 'nsTextEditUtils.cpp', 'nsWSRunObject.cpp', 'PlaceholderTxn.cpp', 'SetDocTitleTxn.cpp', @@ -60,7 +64,6 @@ LOCAL_INCLUDES += [ '/layout/style', '/layout/tables', '/layout/xul', - 'text', ] FINAL_LIBRARY = 'xul' diff --git a/editor/libeditor/nsEditor.cpp b/editor/libeditor/nsEditor.cpp index 2ed84418761..d3261d0e91f 100644 --- a/editor/libeditor/nsEditor.cpp +++ b/editor/libeditor/nsEditor.cpp @@ -4755,7 +4755,7 @@ nsresult nsEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent) { // NOTE: When you change this method, you should also change: - // * editor/libeditor/text/tests/test_texteditor_keyevent_handling.html + // * editor/libeditor/tests/test_texteditor_keyevent_handling.html // * editor/libeditor/tests/test_htmleditor_keyevent_handling.html // // And also when you add new key handling, you need to change the subclass's diff --git a/editor/libeditor/text/nsInternetCiter.cpp b/editor/libeditor/nsInternetCiter.cpp similarity index 99% rename from editor/libeditor/text/nsInternetCiter.cpp rename to editor/libeditor/nsInternetCiter.cpp index 4cd658aa343..1ab040fc8b4 100644 --- a/editor/libeditor/text/nsInternetCiter.cpp +++ b/editor/libeditor/nsInternetCiter.cpp @@ -19,7 +19,6 @@ const char16_t gt ('>'); const char16_t space (' '); -const char16_t nbsp (0xa0); const char16_t nl ('\n'); const char16_t cr('\r'); @@ -142,6 +141,7 @@ BreakLine(nsAString& aOutString, uint32_t& outStringCol, static inline bool IsSpace(char16_t c) { + const char16_t nbsp (0xa0); return (nsCRT::IsAsciiSpace(c) || (c == nl) || (c == cr) || (c == nbsp)); } diff --git a/editor/libeditor/text/nsInternetCiter.h b/editor/libeditor/nsInternetCiter.h similarity index 100% rename from editor/libeditor/text/nsInternetCiter.h rename to editor/libeditor/nsInternetCiter.h diff --git a/editor/libeditor/text/nsPlaintextDataTransfer.cpp b/editor/libeditor/nsPlaintextDataTransfer.cpp similarity index 100% rename from editor/libeditor/text/nsPlaintextDataTransfer.cpp rename to editor/libeditor/nsPlaintextDataTransfer.cpp diff --git a/editor/libeditor/text/nsPlaintextEditor.cpp b/editor/libeditor/nsPlaintextEditor.cpp similarity index 99% rename from editor/libeditor/text/nsPlaintextEditor.cpp rename to editor/libeditor/nsPlaintextEditor.cpp index 3749c95e20a..2bc42a2087f 100644 --- a/editor/libeditor/text/nsPlaintextEditor.cpp +++ b/editor/libeditor/nsPlaintextEditor.cpp @@ -350,7 +350,7 @@ nsresult nsPlaintextEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent) { // NOTE: When you change this method, you should also change: - // * editor/libeditor/text/tests/test_texteditor_keyevent_handling.html + // * editor/libeditor/tests/test_texteditor_keyevent_handling.html // * editor/libeditor/tests/test_htmleditor_keyevent_handling.html // // And also when you add new key handling, you need to change the subclass's diff --git a/editor/libeditor/text/nsPlaintextEditor.h b/editor/libeditor/nsPlaintextEditor.h similarity index 100% rename from editor/libeditor/text/nsPlaintextEditor.h rename to editor/libeditor/nsPlaintextEditor.h diff --git a/editor/libeditor/text/nsTextEditRules.cpp b/editor/libeditor/nsTextEditRules.cpp similarity index 100% rename from editor/libeditor/text/nsTextEditRules.cpp rename to editor/libeditor/nsTextEditRules.cpp diff --git a/editor/libeditor/text/nsTextEditRules.h b/editor/libeditor/nsTextEditRules.h similarity index 100% rename from editor/libeditor/text/nsTextEditRules.h rename to editor/libeditor/nsTextEditRules.h diff --git a/editor/libeditor/text/nsTextEditRulesBidi.cpp b/editor/libeditor/nsTextEditRulesBidi.cpp similarity index 100% rename from editor/libeditor/text/nsTextEditRulesBidi.cpp rename to editor/libeditor/nsTextEditRulesBidi.cpp diff --git a/editor/libeditor/text/nsTextEditUtils.cpp b/editor/libeditor/nsTextEditUtils.cpp similarity index 100% rename from editor/libeditor/text/nsTextEditUtils.cpp rename to editor/libeditor/nsTextEditUtils.cpp diff --git a/editor/libeditor/text/nsTextEditUtils.h b/editor/libeditor/nsTextEditUtils.h similarity index 100% rename from editor/libeditor/text/nsTextEditUtils.h rename to editor/libeditor/nsTextEditUtils.h diff --git a/editor/libeditor/tests/chrome.ini b/editor/libeditor/tests/chrome.ini index 95d676ee83b..69bebc6a319 100644 --- a/editor/libeditor/tests/chrome.ini +++ b/editor/libeditor/tests/chrome.ini @@ -3,18 +3,28 @@ support-files = green.png [test_bug46555.html] [test_bug366682.html] +[test_bug471319.html] +[test_bug483651.html] [test_bug489202.xul] [test_bug490879.xul] +[test_bug569988.html] +skip-if = buildapp == 'mulet' [test_bug599983.xul] skip-if = buildapp == 'mulet' [test_bug607584.xul] [test_bug616590.xul] [test_bug635636.html] +[test_bug636465.xul] [test_bug646194.xul] [test_bug780908.xul] +[test_bug830600.html] [test_composition_event_created_in_chrome.html] [test_contenteditable_text_input_handling.html] [test_dragdrop.html] skip-if = buildapp == 'mulet' [test_htmleditor_keyevent_handling.html] [test_selection_move_commands.xul] +[test_texteditor_keyevent_handling.html] +# disables the key handling test on gtk because gtk overrides some key events +# on our editor, and the combinations depend on the system. +skip-if = toolkit == "gtk2" || toolkit == "gtk3" diff --git a/editor/libeditor/tests/mochitest.ini b/editor/libeditor/tests/mochitest.ini index 6fb718c014f..40091d25de1 100644 --- a/editor/libeditor/tests/mochitest.ini +++ b/editor/libeditor/tests/mochitest.ini @@ -18,6 +18,7 @@ skip-if = os != "mac" [test_bug290026.html] [test_bug291780.html] [test_bug316447.html] +[test_bug318065.html] [test_bug332636.html] support-files = test_bug332636.html^headers^ [test_bug372345.html] @@ -38,6 +39,7 @@ skip-if = toolkit == 'android' || e10s [test_bug456244.html] [test_bug460740.html] [test_bug468353.html] +[test_bug471722.html] [test_bug478725.html] skip-if = toolkit == 'android' || e10s [test_bug480647.html] @@ -52,6 +54,8 @@ skip-if = toolkit == 'android' || e10s skip-if = toolkit == 'android' || e10s [test_bug525389.html] skip-if = toolkit == 'android' || e10s +[test_bug527935.html] +skip-if = toolkit == 'android' || e10s [test_bug537046.html] [test_bug549262.html] skip-if = toolkit == 'android' || e10s @@ -64,11 +68,24 @@ skip-if = toolkit == 'android' || e10s [test_bug586662.html] skip-if = toolkit == 'android' || e10s [test_bug587461.html] +[test_bug590554.html] [test_bug592592.html] +[test_bug596001.html] +[test_bug596333.html] +skip-if = toolkit == 'android' || e10s +[test_bug596506.html] +[test_bug597331.html] +skip-if = buildapp == 'mulet' [test_bug597784.html] [test_bug599322.html] skip-if = toolkit == 'android' || e10s [test_bug599983.html] +[test_bug600570.html] +skip-if = toolkit == 'android' +[test_bug602130.html] +[test_bug603556.html] +[test_bug604532.html] +skip-if = toolkit == 'android' [test_bug607584.html] [test_bug611182.html] skip-if = toolkit == 'android' @@ -78,9 +95,15 @@ skip-if = toolkit == 'android' skip-if = toolkit == 'android' #TIMED_OUT [test_bug622371.html] skip-if = toolkit == 'android' #bug 957797 +[test_bug625452.html] +[test_bug629172.html] +skip-if = toolkit == 'android' || e10s [test_bug629845.html] +[test_bug638596.html] [test_bug640321.html] skip-if = e10s +[test_bug641466.html] +[test_bug645914.html] [test_bug668599.html] [test_bug674770-1.html] skip-if = toolkit == 'android' || e10s @@ -89,13 +112,17 @@ skip-if = toolkit == 'android' || e10s [test_bug674861.html] [test_bug676401.html] [test_bug677752.html] +[test_bug681229.html] [test_bug686203.html] +[test_bug692520.html] [test_bug697842.html] [test_bug725069.html] [test_bug735059.html] [test_bug738366.html] +[test_bug740784.html] [test_bug742261.html] [test_bug757371.html] +[test_bug757771.html] [test_bug767684.html] [test_bug773262.html] [test_bug780035.html] @@ -110,10 +137,13 @@ skip-if = os != "win" [test_bug966552.html] skip-if = os != "win" [test_bug998188.html] +[test_bug1026397.html] +skip-if = e10s [test_CF_HTML_clipboard.html] [test_contenteditable_focus.html] [test_dom_input_event_on_htmleditor.html] skip-if = toolkit == 'android' # bug 1054087 +[test_dom_input_event_on_texteditor.html] [test_keypress_untrusted_event.html] [test_root_element_replacement.html] [test_select_all_without_body.html] diff --git a/editor/libeditor/text/tests/test_bug1026397.html b/editor/libeditor/tests/test_bug1026397.html similarity index 100% rename from editor/libeditor/text/tests/test_bug1026397.html rename to editor/libeditor/tests/test_bug1026397.html diff --git a/editor/libeditor/text/tests/test_bug318065.html b/editor/libeditor/tests/test_bug318065.html similarity index 100% rename from editor/libeditor/text/tests/test_bug318065.html rename to editor/libeditor/tests/test_bug318065.html diff --git a/editor/libeditor/text/tests/test_bug471319.html b/editor/libeditor/tests/test_bug471319.html similarity index 100% rename from editor/libeditor/text/tests/test_bug471319.html rename to editor/libeditor/tests/test_bug471319.html diff --git a/editor/libeditor/text/tests/test_bug471722.html b/editor/libeditor/tests/test_bug471722.html similarity index 100% rename from editor/libeditor/text/tests/test_bug471722.html rename to editor/libeditor/tests/test_bug471722.html diff --git a/editor/libeditor/text/tests/test_bug483651.html b/editor/libeditor/tests/test_bug483651.html similarity index 100% rename from editor/libeditor/text/tests/test_bug483651.html rename to editor/libeditor/tests/test_bug483651.html diff --git a/editor/libeditor/text/tests/test_bug527935.html b/editor/libeditor/tests/test_bug527935.html similarity index 100% rename from editor/libeditor/text/tests/test_bug527935.html rename to editor/libeditor/tests/test_bug527935.html diff --git a/editor/libeditor/text/tests/test_bug569988.html b/editor/libeditor/tests/test_bug569988.html similarity index 100% rename from editor/libeditor/text/tests/test_bug569988.html rename to editor/libeditor/tests/test_bug569988.html diff --git a/editor/libeditor/text/tests/test_bug590554.html b/editor/libeditor/tests/test_bug590554.html similarity index 100% rename from editor/libeditor/text/tests/test_bug590554.html rename to editor/libeditor/tests/test_bug590554.html diff --git a/editor/libeditor/text/tests/test_bug596001.html b/editor/libeditor/tests/test_bug596001.html similarity index 100% rename from editor/libeditor/text/tests/test_bug596001.html rename to editor/libeditor/tests/test_bug596001.html diff --git a/editor/libeditor/text/tests/test_bug596333.html b/editor/libeditor/tests/test_bug596333.html similarity index 100% rename from editor/libeditor/text/tests/test_bug596333.html rename to editor/libeditor/tests/test_bug596333.html diff --git a/editor/libeditor/text/tests/test_bug596506.html b/editor/libeditor/tests/test_bug596506.html similarity index 100% rename from editor/libeditor/text/tests/test_bug596506.html rename to editor/libeditor/tests/test_bug596506.html diff --git a/editor/libeditor/text/tests/test_bug597331.html b/editor/libeditor/tests/test_bug597331.html similarity index 100% rename from editor/libeditor/text/tests/test_bug597331.html rename to editor/libeditor/tests/test_bug597331.html diff --git a/editor/libeditor/text/tests/test_bug600570.html b/editor/libeditor/tests/test_bug600570.html similarity index 100% rename from editor/libeditor/text/tests/test_bug600570.html rename to editor/libeditor/tests/test_bug600570.html diff --git a/editor/libeditor/text/tests/test_bug602130.html b/editor/libeditor/tests/test_bug602130.html similarity index 100% rename from editor/libeditor/text/tests/test_bug602130.html rename to editor/libeditor/tests/test_bug602130.html diff --git a/editor/libeditor/text/tests/test_bug603556.html b/editor/libeditor/tests/test_bug603556.html similarity index 100% rename from editor/libeditor/text/tests/test_bug603556.html rename to editor/libeditor/tests/test_bug603556.html diff --git a/editor/libeditor/text/tests/test_bug604532.html b/editor/libeditor/tests/test_bug604532.html similarity index 100% rename from editor/libeditor/text/tests/test_bug604532.html rename to editor/libeditor/tests/test_bug604532.html diff --git a/editor/libeditor/text/tests/test_bug625452.html b/editor/libeditor/tests/test_bug625452.html similarity index 100% rename from editor/libeditor/text/tests/test_bug625452.html rename to editor/libeditor/tests/test_bug625452.html diff --git a/editor/libeditor/text/tests/test_bug629172.html b/editor/libeditor/tests/test_bug629172.html similarity index 100% rename from editor/libeditor/text/tests/test_bug629172.html rename to editor/libeditor/tests/test_bug629172.html diff --git a/editor/libeditor/text/tests/test_bug636465.xul b/editor/libeditor/tests/test_bug636465.xul similarity index 100% rename from editor/libeditor/text/tests/test_bug636465.xul rename to editor/libeditor/tests/test_bug636465.xul diff --git a/editor/libeditor/text/tests/test_bug638596.html b/editor/libeditor/tests/test_bug638596.html similarity index 100% rename from editor/libeditor/text/tests/test_bug638596.html rename to editor/libeditor/tests/test_bug638596.html diff --git a/editor/libeditor/text/tests/test_bug641466.html b/editor/libeditor/tests/test_bug641466.html similarity index 100% rename from editor/libeditor/text/tests/test_bug641466.html rename to editor/libeditor/tests/test_bug641466.html diff --git a/editor/libeditor/text/tests/test_bug645914.html b/editor/libeditor/tests/test_bug645914.html similarity index 100% rename from editor/libeditor/text/tests/test_bug645914.html rename to editor/libeditor/tests/test_bug645914.html diff --git a/editor/libeditor/text/tests/test_bug681229.html b/editor/libeditor/tests/test_bug681229.html similarity index 100% rename from editor/libeditor/text/tests/test_bug681229.html rename to editor/libeditor/tests/test_bug681229.html diff --git a/editor/libeditor/text/tests/test_bug692520.html b/editor/libeditor/tests/test_bug692520.html similarity index 100% rename from editor/libeditor/text/tests/test_bug692520.html rename to editor/libeditor/tests/test_bug692520.html diff --git a/editor/libeditor/text/tests/test_bug740784.html b/editor/libeditor/tests/test_bug740784.html similarity index 100% rename from editor/libeditor/text/tests/test_bug740784.html rename to editor/libeditor/tests/test_bug740784.html diff --git a/editor/libeditor/text/tests/test_bug757771.html b/editor/libeditor/tests/test_bug757771.html similarity index 100% rename from editor/libeditor/text/tests/test_bug757771.html rename to editor/libeditor/tests/test_bug757771.html diff --git a/editor/libeditor/text/tests/test_bug830600.html b/editor/libeditor/tests/test_bug830600.html similarity index 100% rename from editor/libeditor/text/tests/test_bug830600.html rename to editor/libeditor/tests/test_bug830600.html diff --git a/editor/libeditor/text/tests/test_dom_input_event_on_texteditor.html b/editor/libeditor/tests/test_dom_input_event_on_texteditor.html similarity index 100% rename from editor/libeditor/text/tests/test_dom_input_event_on_texteditor.html rename to editor/libeditor/tests/test_dom_input_event_on_texteditor.html diff --git a/editor/libeditor/text/tests/test_texteditor_keyevent_handling.html b/editor/libeditor/tests/test_texteditor_keyevent_handling.html similarity index 100% rename from editor/libeditor/text/tests/test_texteditor_keyevent_handling.html rename to editor/libeditor/tests/test_texteditor_keyevent_handling.html diff --git a/editor/libeditor/text/crashtests/crashtests.list b/editor/libeditor/text/crashtests/crashtests.list deleted file mode 100644 index 77fa4db9d93..00000000000 --- a/editor/libeditor/text/crashtests/crashtests.list +++ /dev/null @@ -1,2 +0,0 @@ -load 403965-1.xhtml -load 580151-1.xhtml diff --git a/editor/libeditor/text/moz.build b/editor/libeditor/text/moz.build deleted file mode 100644 index 99eb178d1ae..00000000000 --- a/editor/libeditor/text/moz.build +++ /dev/null @@ -1,28 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -UNIFIED_SOURCES += [ - 'nsInternetCiter.cpp', - 'nsPlaintextDataTransfer.cpp', - 'nsPlaintextEditor.cpp', - 'nsTextEditRules.cpp', - 'nsTextEditRulesBidi.cpp', - 'nsTextEditUtils.cpp', -] - -FAIL_ON_WARNINGS = True - -LOCAL_INCLUDES += [ - '..', - '/content/base/src', - '/editor/txmgr', -] - -FINAL_LIBRARY = 'xul' - -MOCHITEST_MANIFESTS += ['tests/mochitest.ini'] - -MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini'] diff --git a/editor/libeditor/text/tests/chrome.ini b/editor/libeditor/text/tests/chrome.ini deleted file mode 100644 index 699c1f0fe38..00000000000 --- a/editor/libeditor/text/tests/chrome.ini +++ /dev/null @@ -1,10 +0,0 @@ -[test_bug471319.html] -[test_bug483651.html] -[test_bug569988.html] -skip-if = buildapp == 'mulet' -[test_bug636465.xul] -[test_bug830600.html] -[test_texteditor_keyevent_handling.html] -# disables the key handling test on gtk because gtk overrides some key events -# on our editor, and the combinations depend on the system. -skip-if = toolkit == "gtk2" || toolkit == "gtk3" diff --git a/editor/libeditor/text/tests/mochitest.ini b/editor/libeditor/text/tests/mochitest.ini deleted file mode 100644 index 8be1128fd8a..00000000000 --- a/editor/libeditor/text/tests/mochitest.ini +++ /dev/null @@ -1,33 +0,0 @@ -[DEFAULT] -skip-if = buildapp == 'b2g' - -[test_bug318065.html] -[test_bug471722.html] -[test_bug527935.html] -skip-if = toolkit == 'android' || e10s -[test_bug590554.html] -[test_bug596001.html] -[test_bug596333.html] -skip-if = toolkit == 'android' || e10s -[test_bug596506.html] -[test_bug597331.html] -skip-if = buildapp == 'mulet' -[test_bug600570.html] -skip-if = toolkit == 'android' -[test_bug602130.html] -[test_bug603556.html] -[test_bug604532.html] -skip-if = toolkit == 'android' -[test_bug625452.html] -[test_bug629172.html] -skip-if = toolkit == 'android' || e10s -[test_bug638596.html] -[test_bug641466.html] -[test_bug645914.html] -[test_bug681229.html] -[test_bug692520.html] -[test_bug740784.html] -[test_bug757771.html] -[test_bug1026397.html] -skip-if = e10s -[test_dom_input_event_on_texteditor.html] diff --git a/layout/build/moz.build b/layout/build/moz.build index 2c7e1e10289..a934fac5bf3 100644 --- a/layout/build/moz.build +++ b/layout/build/moz.build @@ -66,7 +66,6 @@ LOCAL_INCLUDES += [ '/dom/xslt/xslt', '/editor/composer', '/editor/libeditor', - '/editor/libeditor/text', '/editor/txmgr', '/editor/txtsvc', '/extensions/cookie', diff --git a/layout/forms/moz.build b/layout/forms/moz.build index a2130dab62f..9cdea8e416d 100644 --- a/layout/forms/moz.build +++ b/layout/forms/moz.build @@ -46,7 +46,6 @@ LOCAL_INCLUDES += [ '../../content/base/src', '../../content/html/content/src', '../../editor/libeditor', - '../../editor/libeditor/text', '../../editor/txmgr', '../base', '../generic', diff --git a/testing/mochitest/androidx86.json b/testing/mochitest/androidx86.json index 035045d580d..4c73680a796 100644 --- a/testing/mochitest/androidx86.json +++ b/testing/mochitest/androidx86.json @@ -91,8 +91,8 @@ "dom/imptests/html/webgl": "WebGL", "dom/inputmethod": "Not supported on Android", "dom/tests/mochitest/geolocation/test_timeoutWatch.html": "TIMED_OUT", - "editor/libeditor/text/tests/test_bug569988.html": "TIMED_OUT", - "editor/libeditor/text/tests/test_texteditor_keyevent_handling.html": "", + "editor/libeditor/tests/test_bug569988.html": "TIMED_OUT", + "editor/libeditor/tests/test_texteditor_keyevent_handling.html": "", "Harness_sanity/test_sanityWindowSnapshot.html": "x86 only", "image/test/mochitest/test_bug671906.html": "x86 only", "image/test/mochitest/test_bug89419-2.html": "x86 only", From 36bc8530441822e3df6d925e22a7aab14067edb2 Mon Sep 17 00:00:00 2001 From: Lynn Tran Date: Mon, 18 Aug 2014 21:13:14 -0400 Subject: [PATCH 75/86] Bug 1041335 - Add a mozilla::services getter for nsIServiceWorkerManager; r=ehsan --- content/base/src/nsDocument.cpp | 5 ++-- dom/workers/ServiceWorkerContainer.cpp | 34 ++++++++++++-------------- dom/workers/ServiceWorkerManager.cpp | 3 +-- xpcom/build/ServiceList.h | 2 ++ xpcom/build/Services.cpp | 1 + 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 65eb4a1baaf..0a78f8236f5 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -39,6 +39,7 @@ #include "nsIDocShellTreeItem.h" #include "nsCOMArray.h" #include "nsDOMClassInfo.h" +#include "mozilla/Services.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/BasicEvents.h" @@ -4494,7 +4495,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) return; } - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); if (swm) { swm->MaybeStartControlling(this); mMaybeServiceWorkerControlled = true; @@ -8526,7 +8527,7 @@ nsDocument::Destroy() mRegistry = nullptr; - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); if (swm) { swm->MaybeStopControlling(this); } diff --git a/dom/workers/ServiceWorkerContainer.cpp b/dom/workers/ServiceWorkerContainer.cpp index 2abe7b9dc50..4c49e0f7596 100644 --- a/dom/workers/ServiceWorkerContainer.cpp +++ b/dom/workers/ServiceWorkerContainer.cpp @@ -9,6 +9,7 @@ #include "nsIDocument.h" #include "nsIServiceWorkerManager.h" #include "nsPIDOMWindow.h" +#include "mozilla/Services.h" #include "nsCycleCollectionParticipant.h" #include "nsServiceManagerUtils.h" @@ -60,10 +61,9 @@ ServiceWorkerContainer::Register(const nsAString& aScriptURL, { nsCOMPtr promise; - nsresult rv; - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(rv); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); + if (!swm) { + aRv.Throw(NS_ERROR_FAILURE); return nullptr; } @@ -83,10 +83,9 @@ ServiceWorkerContainer::Unregister(const nsAString& aScope, { nsCOMPtr promise; - nsresult rv; - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(rv); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); + if (!swm) { + aRv.Throw(NS_ERROR_FAILURE); return nullptr; } @@ -138,8 +137,8 @@ ServiceWorkerContainer::GetController() { if (!mControllerWorker) { nsresult rv; - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); + if (!swm) { return nullptr; } @@ -177,7 +176,7 @@ ServiceWorkerContainer::GetReady(ErrorResult& aRv) void ServiceWorkerContainer::StartListeningForEvents() { - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); if (swm) { swm->AddContainerEventListener(mWindow->GetDocumentURI(), this); } @@ -186,7 +185,7 @@ ServiceWorkerContainer::StartListeningForEvents() void ServiceWorkerContainer::StopListeningForEvents() { - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); if (swm) { swm->RemoveContainerEventListener(mWindow->GetDocumentURI(), this); } @@ -212,8 +211,8 @@ already_AddRefed ServiceWorkerContainer::GetWorkerReference(WhichServiceWorker aWhichOne) { nsresult rv; - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); + if (!swm) { return nullptr; } @@ -254,10 +253,9 @@ ServiceWorkerContainer::GetScopeForUrl(const nsAString& aUrl, nsString& aScope, ErrorResult& aRv) { - nsresult rv; - nsCOMPtr swm = do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - aRv.Throw(rv); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); + if (!swm) { + aRv.Throw(NS_ERROR_FAILURE); return; } diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index 97282f4982a..f049d4f3b31 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -607,8 +607,7 @@ ServiceWorkerManager::Unregister(nsIDOMWindow* aWindow, const nsAString& aScope, already_AddRefed ServiceWorkerManager::GetInstance() { - nsCOMPtr swm = - do_GetService(SERVICEWORKERMANAGER_CONTRACTID); + nsCOMPtr swm = mozilla::services::GetServiceWorkerManager(); nsRefPtr concrete = do_QueryObject(swm); return concrete.forget(); } diff --git a/xpcom/build/ServiceList.h b/xpcom/build/ServiceList.h index c624c0e25ec..8c39830d0eb 100644 --- a/xpcom/build/ServiceList.h +++ b/xpcom/build/ServiceList.h @@ -27,6 +27,8 @@ MOZ_SERVICE(InDOMUtils, inIDOMUtils, "@mozilla.org/inspector/dom-utils;1") MOZ_SERVICE(PermissionManager, nsIPermissionManager, "@mozilla.org/permissionmanager;1"); +MOZ_SERVICE(ServiceWorkerManager, nsIServiceWorkerManager, + "@mozilla.org/serviceworkers/manager;1"); #ifdef MOZ_USE_NAMESPACE namespace mozilla { diff --git a/xpcom/build/Services.cpp b/xpcom/build/Services.cpp index 0d1f8ca0d01..a7d4e6d631e 100644 --- a/xpcom/build/Services.cpp +++ b/xpcom/build/Services.cpp @@ -23,6 +23,7 @@ #include "nsIXPConnect.h" #include "inIDOMUtils.h" #include "nsIPermissionManager.h" +#include "nsIServiceWorkerManager.h" using namespace mozilla; using namespace mozilla::services; From dfffe06cbd1768efcc152252ec196472ede6274a Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Tue, 19 Aug 2014 14:13:55 +1200 Subject: [PATCH 76/86] Bug 1049133 - Calculate eviction offset for MP4 instead of guessing; r=kinetik,edwin --- content/media/MediaDecoderReader.h | 1 + content/media/fmp4/MP4Reader.cpp | 30 +++-- content/media/fmp4/MP4Reader.h | 4 +- .../media/mediasource/SubBufferDecoder.cpp | 7 +- media/libstagefright/binding/Index.cpp | 109 ++++++++++++------ .../binding/include/mp4_demuxer/Index.h | 2 + .../binding/include/mp4_demuxer/Interval.h | 10 +- .../binding/include/mp4_demuxer/mp4_demuxer.h | 6 +- media/libstagefright/binding/mp4_demuxer.cpp | 23 ++++ 9 files changed, 135 insertions(+), 57 deletions(-) diff --git a/content/media/MediaDecoderReader.h b/content/media/MediaDecoderReader.h index 713c275ef46..d2bea4387a4 100644 --- a/content/media/MediaDecoderReader.h +++ b/content/media/MediaDecoderReader.h @@ -159,6 +159,7 @@ public: // Only used by WebMReader and MediaOmxReader for now, so stub here rather // than in every reader than inherits from MediaDecoderReader. virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) {} + virtual int64_t GetEvictionOffset(double aTime) { return -1; } virtual MediaQueue& AudioQueue() { return mAudioQueue; } virtual MediaQueue& VideoQueue() { return mVideoQueue; } diff --git a/content/media/fmp4/MP4Reader.cpp b/content/media/fmp4/MP4Reader.cpp index 7341564fccf..157bb59ab6e 100644 --- a/content/media/fmp4/MP4Reader.cpp +++ b/content/media/fmp4/MP4Reader.cpp @@ -109,7 +109,6 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder) , mVideo("MP4 video decoder data", Preferences::GetUint("media.mp4-video-decode-ahead", 2)) , mLastReportedNumDecodedFrames(0) , mLayersBackendType(layers::LayersBackend::LAYERS_NONE) - , mTimeRangesMonitor("MP4Reader::TimeRanges") , mDemuxerInitialized(false) , mIsEncrypted(false) { @@ -774,29 +773,36 @@ MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, void MP4Reader::UpdateIndex() { - nsTArray ranges; - nsTArray> timeRanges; - MediaResource* resource = mDecoder->GetResource(); resource->Pin(); + nsTArray ranges; if (NS_SUCCEEDED(resource->GetCachedRanges(ranges))) { - mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges); + mDemuxer->UpdateIndex(ranges); } resource->Unpin(); - - MonitorAutoLock mon(mTimeRangesMonitor); - mTimeRanges = timeRanges; } +int64_t +MP4Reader::GetEvictionOffset(double aTime) +{ + return mDemuxer->GetEvictionOffset(aTime * 1000000.0); +} nsresult MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) { - MonitorAutoLock mon(mTimeRangesMonitor); - for (size_t i = 0; i < mTimeRanges.Length(); i++) { - aBuffered->Add((mTimeRanges[i].start - aStartTime) / 1000000.0, - (mTimeRanges[i].end - aStartTime) / 1000000.0); + MediaResource* resource = mDecoder->GetResource(); + resource->Pin(); + nsTArray ranges; + if (NS_SUCCEEDED(resource->GetCachedRanges(ranges))) { + nsTArray> timeRanges; + mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges); + for (size_t i = 0; i < timeRanges.Length(); i++) { + aBuffered->Add((timeRanges[i].start - aStartTime) / 1000000.0, + (timeRanges[i].end - aStartTime) / 1000000.0); + } } + resource->Unpin(); return NS_OK; } diff --git a/content/media/fmp4/MP4Reader.h b/content/media/fmp4/MP4Reader.h index 6fa9cbe2278..06016238a95 100644 --- a/content/media/fmp4/MP4Reader.h +++ b/content/media/fmp4/MP4Reader.h @@ -55,6 +55,8 @@ public: virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) MOZ_OVERRIDE; + virtual int64_t GetEvictionOffset(double aTime) MOZ_OVERRIDE; + virtual nsresult GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) MOZ_OVERRIDE; @@ -181,8 +183,6 @@ private: layers::LayersBackend mLayersBackendType; nsTArray> mInitDataEncountered; - Monitor mTimeRangesMonitor; - nsTArray> mTimeRanges; // True if we've read the streams' metadata. bool mDemuxerInitialized; diff --git a/content/media/mediasource/SubBufferDecoder.cpp b/content/media/mediasource/SubBufferDecoder.cpp index 9456dc40ae1..195997451cf 100644 --- a/content/media/mediasource/SubBufferDecoder.cpp +++ b/content/media/mediasource/SubBufferDecoder.cpp @@ -112,11 +112,16 @@ SubBufferDecoder::GetBuffered(dom::TimeRanges* aBuffered) int64_t SubBufferDecoder::ConvertToByteOffset(double aTime) { + int64_t readerOffset = mReader->GetEvictionOffset(aTime); + if (readerOffset >= 0) { + return readerOffset; + } + // Uses a conversion based on (aTime/duration) * length. For the // purposes of eviction this should be adequate since we have the // byte threshold as well to ensure data actually gets evicted and // we ensure we don't evict before the current playable point. - if (mMediaDuration == -1) { + if (mMediaDuration <= 0) { return -1; } int64_t length = GetResource()->GetLength(); diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index eaed3b2c16f..65bc97408d0 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -8,6 +8,9 @@ #include "media/stagefright/MediaSource.h" #include "MediaResource.h" +#include +#include + using namespace stagefright; using namespace mozilla; @@ -85,67 +88,101 @@ Index::Index(const stagefright::Vector& aIndex, Index::~Index() {} +void +Index::UpdateMoofIndex(const nsTArray& aByteRanges) +{ + if (!mMoofParser) { + return; + } + + MonitorAutoLock mon(mMonitor); + mMoofParser->RebuildFragmentedIndex(aByteRanges); +} + void Index::ConvertByteRangesToTimeRanges( const nsTArray& aByteRanges, nsTArray>* aTimeRanges) { + MonitorAutoLock mon(mMonitor); + RangeFinder rangeFinder(aByteRanges); nsTArray> timeRanges; - nsTArray moofIndex; - nsTArray* index; + nsTArray*> indexes; if (mMoofParser) { - { - MonitorAutoLock mon(mMonitor); - mMoofParser->RebuildFragmentedIndex(aByteRanges); + // We take the index out of the moof parser and move it into a local + // variable so we don't get concurrency issues. It gets freed when we + // exit this function. + for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) { + Moof& moof = mMoofParser->mMoofs[i]; - // We take the index out of the moof parser and move it into a local - // variable so we don't get concurrency issues. It gets freed when we - // exit this function. - for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) { - Moof& moof = mMoofParser->mMoofs[i]; - if (rangeFinder.Contains(moof.mRange) && - rangeFinder.Contains(moof.mMdatRange)) { + // We need the entire moof in order to play anything + if (rangeFinder.Contains(moof.mRange)) { + if (rangeFinder.Contains(moof.mMdatRange)) { timeRanges.AppendElements(moof.mTimeRanges); } else { - moofIndex.AppendElements(mMoofParser->mMoofs[i].mIndex); + indexes.AppendElement(&moof.mIndex); } } } - index = &moofIndex; } else { - index = &mIndex; + indexes.AppendElement(&mIndex); } bool hasSync = false; - for (size_t i = 0; i < index->Length(); i++) { - const MediaSource::Indice& indice = (*index)[i]; - if (!rangeFinder.Contains(MediaByteRange(indice.start_offset, - indice.end_offset))) { - // We process the index in decode order so we clear hasSync when we hit - // a range that isn't buffered. - hasSync = false; - continue; - } + for (size_t i = 0; i < indexes.Length(); i++) { + nsTArray* index = indexes[i]; + for (size_t j = 0; j < index->Length(); j++) { + const MediaSource::Indice& indice = (*index)[j]; + if (!rangeFinder.Contains( + MediaByteRange(indice.start_offset, indice.end_offset))) { + // We process the index in decode order so we clear hasSync when we hit + // a range that isn't buffered. + hasSync = false; + continue; + } - hasSync |= indice.sync; - if (!hasSync) { - continue; - } + hasSync |= indice.sync; + if (!hasSync) { + continue; + } - // This is an optimisation for when the file is decoded in composition - // order. It means that Normalise() below doesn't need to do a sort. - size_t s = timeRanges.Length(); - if (s && timeRanges[s - 1].end == indice.start_composition) { - timeRanges[s - 1].end = indice.end_composition; - } else { - timeRanges.AppendElement(Interval(indice.start_composition, - indice.end_composition)); + Interval::SemiNormalAppend( + timeRanges, Interval(indice.start_composition, + indice.end_composition)); } } // This fixes up when the compositon order differs from the byte range order Interval::Normalize(timeRanges, aTimeRanges); } + +uint64_t +Index::GetEvictionOffset(Microseconds aTime) +{ + uint64_t offset = std::numeric_limits::max(); + if (mMoofParser) { + // We need to keep the whole moof if we're keeping any of it because the + // parser doesn't keep parsed moofs. + for (int i = 0; i < mMoofParser->mMoofs.Length(); i++) { + Moof& moof = mMoofParser->mMoofs[i]; + + if (!moof.mTimeRanges.IsEmpty() && moof.mTimeRanges[0].end > aTime) { + offset = std::min(offset, uint64_t(std::min(moof.mRange.mStart, + moof.mMdatRange.mStart))); + } + } + } else { + // We've already parsed and stored the moov so we don't need to keep it. + // All we need to keep is the sample data itself. + for (size_t i = 0; i < mIndex.Length(); i++) { + const MediaSource::Indice& indice = mIndex[i]; + if (aTime >= indice.start_composition) { + offset = std::min(offset, indice.start_offset); + } + } + } + return offset; +} } diff --git a/media/libstagefright/binding/include/mp4_demuxer/Index.h b/media/libstagefright/binding/include/mp4_demuxer/Index.h index 618a905d4c7..eaeccfbba2b 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Index.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h @@ -22,9 +22,11 @@ public: Stream* aSource, uint32_t aTrackId); ~Index(); + void UpdateMoofIndex(const nsTArray& aByteRanges); void ConvertByteRangesToTimeRanges( const nsTArray& aByteRanges, nsTArray>* aTimeRanges); + uint64_t GetEvictionOffset(Microseconds aTime); private: mozilla::Monitor mMonitor; diff --git a/media/libstagefright/binding/include/mp4_demuxer/Interval.h b/media/libstagefright/binding/include/mp4_demuxer/Interval.h index 61268acdb8a..77f5f01fd02 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Interval.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Interval.h @@ -61,7 +61,7 @@ struct Interval } MOZ_ASSERT(aNormalized->IsEmpty()); - nsTArray > sorted; + nsTArray> sorted; sorted = aIntervals; sorted.Sort(Compare()); @@ -81,9 +81,9 @@ struct Interval aNormalized->AppendElement(current); } - static void Intersection(const nsTArray >& a0, - const nsTArray >& a1, - nsTArray >* aIntersection) + static void Intersection(const nsTArray>& a0, + const nsTArray>& a1, + nsTArray>* aIntersection) { MOZ_ASSERT(IsNormalized(a0)); MOZ_ASSERT(IsNormalized(a1)); @@ -106,7 +106,7 @@ struct Interval } } - static bool IsNormalized(const nsTArray >& aIntervals) + static bool IsNormalized(const nsTArray>& aIntervals) { for (size_t i = 1; i < aIntervals.Length(); i++) { if (aIntervals[i - 1].end >= aIntervals[i].start) { diff --git a/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h b/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h index 72fa4c6690c..0105b9c97b3 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h +++ b/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h @@ -59,9 +59,13 @@ public: const AudioDecoderConfig& AudioConfig() { return mAudioConfig; } const VideoDecoderConfig& VideoConfig() { return mVideoConfig; } + void UpdateIndex(const nsTArray& aByteRanges); + void ConvertByteRangesToTime( const nsTArray& aByteRanges, - nsTArray >* aIntervals); + nsTArray>* aIntervals); + + int64_t GetEvictionOffset(Microseconds aTime); private: AudioDecoderConfig mAudioConfig; diff --git a/media/libstagefright/binding/mp4_demuxer.cpp b/media/libstagefright/binding/mp4_demuxer.cpp index c7200909441..29f32cdfffd 100644 --- a/media/libstagefright/binding/mp4_demuxer.cpp +++ b/media/libstagefright/binding/mp4_demuxer.cpp @@ -13,6 +13,7 @@ #include #include +#include using namespace stagefright; @@ -197,6 +198,14 @@ MP4Demuxer::DemuxVideoSample() return sample.forget(); } +void +MP4Demuxer::UpdateIndex(const nsTArray& aByteRanges) +{ + for (int i = 0; i < mPrivate->mIndexes.Length(); i++) { + mPrivate->mIndexes[i]->UpdateMoofIndex(aByteRanges); + } +} + void MP4Demuxer::ConvertByteRangesToTime( const nsTArray& aByteRanges, @@ -218,4 +227,18 @@ MP4Demuxer::ConvertByteRangesToTime( } } +int64_t +MP4Demuxer::GetEvictionOffset(Microseconds aTime) +{ + if (mPrivate->mIndexes.IsEmpty()) { + return 0; + } + + uint64_t offset = std::numeric_limits::max(); + for (int i = 0; i < mPrivate->mIndexes.Length(); i++) { + offset = std::min(offset, mPrivate->mIndexes[i]->GetEvictionOffset(aTime)); + } + return offset; +} + } // namespace mp4_demuxer From cc7b452600e97e26728a1aad333c23497ab164d5 Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Tue, 19 Aug 2014 14:13:56 +1200 Subject: [PATCH 77/86] Bug 1054153 - Fix MP4 demuxer is init vs buffered range race; r=edwin --- content/media/fmp4/MP4Reader.cpp | 32 +++++++++++++++++-- content/media/fmp4/MP4Reader.h | 3 ++ media/libstagefright/binding/Index.cpp | 4 --- .../binding/include/mp4_demuxer/Index.h | 1 - 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/content/media/fmp4/MP4Reader.cpp b/content/media/fmp4/MP4Reader.cpp index 157bb59ab6e..1d60fd90f45 100644 --- a/content/media/fmp4/MP4Reader.cpp +++ b/content/media/fmp4/MP4Reader.cpp @@ -111,6 +111,8 @@ MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder) , mLayersBackendType(layers::LayersBackend::LAYERS_NONE) , mDemuxerInitialized(false) , mIsEncrypted(false) + , mIndexReady(false) + , mIndexMonitor("MP4 index") { MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); MOZ_COUNT_CTOR(MP4Reader); @@ -303,6 +305,11 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo, bool ok = mDemuxer->Init(); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); + { + MonitorAutoLock mon(mIndexMonitor); + mIndexReady = true; + } + mInfo.mVideo.mHasVideo = mVideo.mActive = mDemuxer->HasValidVideo(); const VideoDecoderConfig& video = mDemuxer->VideoConfig(); // If we have video, we *only* allow H.264 to be decoded. @@ -416,6 +423,8 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo, *aInfo = mInfo; *aTags = nullptr; + UpdateIndex(); + return NS_OK; } @@ -773,6 +782,11 @@ MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength, void MP4Reader::UpdateIndex() { + MonitorAutoLock mon(mIndexMonitor); + if (!mIndexReady) { + return; + } + MediaResource* resource = mDecoder->GetResource(); resource->Pin(); nsTArray ranges; @@ -785,16 +799,29 @@ MP4Reader::UpdateIndex() int64_t MP4Reader::GetEvictionOffset(double aTime) { + MonitorAutoLock mon(mIndexMonitor); + if (!mIndexReady) { + return 0; + } + return mDemuxer->GetEvictionOffset(aTime * 1000000.0); } nsresult MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) { + MonitorAutoLock mon(mIndexMonitor); + if (!mIndexReady) { + return NS_OK; + } + MediaResource* resource = mDecoder->GetResource(); - resource->Pin(); nsTArray ranges; - if (NS_SUCCEEDED(resource->GetCachedRanges(ranges))) { + resource->Pin(); + nsresult rv = resource->GetCachedRanges(ranges); + resource->Unpin(); + + if (NS_SUCCEEDED(rv)) { nsTArray> timeRanges; mDemuxer->ConvertByteRangesToTime(ranges, &timeRanges); for (size_t i = 0; i < timeRanges.Length(); i++) { @@ -802,7 +829,6 @@ MP4Reader::GetBuffered(dom::TimeRanges* aBuffered, int64_t aStartTime) (timeRanges[i].end - aStartTime) / 1000000.0); } } - resource->Unpin(); return NS_OK; } diff --git a/content/media/fmp4/MP4Reader.h b/content/media/fmp4/MP4Reader.h index 06016238a95..3d9c56128ac 100644 --- a/content/media/fmp4/MP4Reader.h +++ b/content/media/fmp4/MP4Reader.h @@ -189,6 +189,9 @@ private: // Synchronized by decoder monitor. bool mIsEncrypted; + + bool mIndexReady; + Monitor mIndexMonitor; }; } // namespace mozilla diff --git a/media/libstagefright/binding/Index.cpp b/media/libstagefright/binding/Index.cpp index 65bc97408d0..565a91c3e18 100644 --- a/media/libstagefright/binding/Index.cpp +++ b/media/libstagefright/binding/Index.cpp @@ -77,7 +77,6 @@ RangeFinder::Contains(MediaByteRange aByteRange) Index::Index(const stagefright::Vector& aIndex, Stream* aSource, uint32_t aTrackId) - : mMonitor("mp4_demuxer::Index") { if (aIndex.isEmpty()) { mMoofParser = new MoofParser(aSource, aTrackId); @@ -95,7 +94,6 @@ Index::UpdateMoofIndex(const nsTArray& aByteRanges) return; } - MonitorAutoLock mon(mMonitor); mMoofParser->RebuildFragmentedIndex(aByteRanges); } @@ -104,8 +102,6 @@ Index::ConvertByteRangesToTimeRanges( const nsTArray& aByteRanges, nsTArray>* aTimeRanges) { - MonitorAutoLock mon(mMonitor); - RangeFinder rangeFinder(aByteRanges); nsTArray> timeRanges; diff --git a/media/libstagefright/binding/include/mp4_demuxer/Index.h b/media/libstagefright/binding/include/mp4_demuxer/Index.h index eaeccfbba2b..7e95fd0a516 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/Index.h +++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h @@ -29,7 +29,6 @@ public: uint64_t GetEvictionOffset(Microseconds aTime); private: - mozilla::Monitor mMonitor; nsTArray mIndex; nsAutoPtr mMoofParser; }; From f574bb0e2ebb4f1cf3cc097b75ae922d8d5d3bcc Mon Sep 17 00:00:00 2001 From: Anthony Jones Date: Tue, 19 Aug 2014 14:13:58 +1200 Subject: [PATCH 78/86] Bug 1050814 - Fix duration reporting in MP4; r=edwin --- media/libstagefright/binding/include/mp4_demuxer/DecoderData.h | 1 - 1 file changed, 1 deletion(-) diff --git a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h index 23e32467d09..24d4b9f6388 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h +++ b/media/libstagefright/binding/include/mp4_demuxer/DecoderData.h @@ -92,7 +92,6 @@ public: { } - int64_t duration; uint32_t channel_count; uint32_t bits_per_sample; uint32_t samples_per_second; From 7c13ca416baf7c8cc1eb58796f8d750165a56d0b Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Tue, 19 Aug 2014 15:58:17 +1200 Subject: [PATCH 79/86] Bug 781701 - Interpolate rotate3d rotation angles numerically when we can instead of using matrix decompositon. r=dbaron --- layout/style/StyleAnimationValue.cpp | 28 +++++++++++++++++++++- layout/style/nsStyleTransformMatrix.cpp | 32 +++++++++++-------------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index f0c18b2641b..39a346f4761 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -1813,10 +1813,36 @@ AddTransformLists(double aCoeff1, const nsCSSValueList* aList1, break; } + case eCSSKeyword_rotate3d: { + gfxPoint3D vector1(a1->Item(1).GetFloatValue(), + a1->Item(2).GetFloatValue(), + a1->Item(3).GetFloatValue()); + vector1.Normalize(); + gfxPoint3D vector2(a2->Item(1).GetFloatValue(), + a2->Item(2).GetFloatValue(), + a2->Item(3).GetFloatValue()); + vector2.Normalize(); + + // Handle rotate3d with matched (normalized) vectors, + // otherwise fallthrough to the next switch statement + // and do matrix decomposition. + if (vector1 == vector2) { + // We skipped appending a transform function above for rotate3d, + // so do it now. + arr = StyleAnimationValue::AppendTransformFunction(tfunc, resultTail); + arr->Item(1).SetFloatValue(vector1.x, eCSSUnit_Number); + arr->Item(2).SetFloatValue(vector1.y, eCSSUnit_Number); + arr->Item(3).SetFloatValue(vector1.z, eCSSUnit_Number); + + AddCSSValueAngle(aCoeff1, a1->Item(4), aCoeff2, a2->Item(4), + arr->Item(4)); + break; + } + // FALL THROUGH + } case eCSSKeyword_matrix: case eCSSKeyword_matrix3d: case eCSSKeyword_interpolatematrix: - case eCSSKeyword_rotate3d: case eCSSKeyword_perspective: { // FIXME: If the matrix contains only numbers then we could decompose // here. diff --git a/layout/style/nsStyleTransformMatrix.cpp b/layout/style/nsStyleTransformMatrix.cpp index ca92e48a258..a55e95dc43c 100644 --- a/layout/style/nsStyleTransformMatrix.cpp +++ b/layout/style/nsStyleTransformMatrix.cpp @@ -437,33 +437,29 @@ ProcessRotate3D(gfx3DMatrix& aMatrix, const nsCSSValue::Array* aData) float cosTheta = FlushToZero(cos(theta)); float sinTheta = FlushToZero(sin(theta)); - float x = aData->Item(1).GetFloatValue(); - float y = aData->Item(2).GetFloatValue(); - float z = aData->Item(3).GetFloatValue(); + gfxPoint3D vector(aData->Item(1).GetFloatValue(), + aData->Item(2).GetFloatValue(), + aData->Item(3).GetFloatValue()); - /* Normalize [x,y,z] */ - float length = sqrt(x*x + y*y + z*z); - if (length == 0.0) { + if (!vector.Length()) { return; } - x /= length; - y /= length; - z /= length; + vector.Normalize(); gfx3DMatrix temp; /* Create our matrix */ - temp._11 = 1 + (1 - cosTheta) * (x * x - 1); - temp._12 = -z * sinTheta + (1 - cosTheta) * x * y; - temp._13 = y * sinTheta + (1 - cosTheta) * x * z; + temp._11 = 1 + (1 - cosTheta) * (vector.x * vector.x - 1); + temp._12 = -vector.z * sinTheta + (1 - cosTheta) * vector.x * vector.y; + temp._13 = vector.y * sinTheta + (1 - cosTheta) * vector.x * vector.z; temp._14 = 0.0f; - temp._21 = z * sinTheta + (1 - cosTheta) * x * y; - temp._22 = 1 + (1 - cosTheta) * (y * y - 1); - temp._23 = -x * sinTheta + (1 - cosTheta) * y * z; + temp._21 = vector.z * sinTheta + (1 - cosTheta) * vector.x * vector.y; + temp._22 = 1 + (1 - cosTheta) * (vector.y * vector.y - 1); + temp._23 = -vector.x * sinTheta + (1 - cosTheta) * vector.y * vector.z; temp._24 = 0.0f; - temp._31 = -y * sinTheta + (1 - cosTheta) * x * z; - temp._32 = x * sinTheta + (1 - cosTheta) * y * z; - temp._33 = 1 + (1 - cosTheta) * (z * z - 1); + temp._31 = -vector.y * sinTheta + (1 - cosTheta) * vector.x * vector.z; + temp._32 = vector.x * sinTheta + (1 - cosTheta) * vector.y * vector.z; + temp._33 = 1 + (1 - cosTheta) * (vector.z * vector.z - 1); temp._34 = 0.0f; temp._41 = 0.0f; temp._42 = 0.0f; From 25f90a04b3ab424d9519ec56429d0cedfd7831ed Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Tue, 19 Aug 2014 17:03:04 +1200 Subject: [PATCH 80/86] Bug 1034368 - Add storage capabilities to GMPs. r=jesup --- content/media/gmp/GMPChild.cpp | 26 ++ content/media/gmp/GMPChild.h | 6 + content/media/gmp/GMPParent.cpp | 33 ++- content/media/gmp/GMPParent.h | 6 + content/media/gmp/GMPPlatform.cpp | 27 ++- content/media/gmp/GMPStorageChild.cpp | 282 ++++++++++++++++++++++ content/media/gmp/GMPStorageChild.h | 95 ++++++++ content/media/gmp/GMPStorageParent.cpp | 287 +++++++++++++++++++++++ content/media/gmp/GMPStorageParent.h | 45 ++++ content/media/gmp/PGMP.ipdl | 3 + content/media/gmp/PGMPStorage.ipdl | 34 +++ content/media/gmp/gmp-api/gmp-platform.h | 2 + content/media/gmp/gmp-api/gmp-storage.h | 34 ++- content/media/gmp/moz.build | 5 + 14 files changed, 874 insertions(+), 11 deletions(-) create mode 100644 content/media/gmp/GMPStorageChild.cpp create mode 100644 content/media/gmp/GMPStorageChild.h create mode 100644 content/media/gmp/GMPStorageParent.cpp create mode 100644 content/media/gmp/GMPStorageParent.h create mode 100644 content/media/gmp/PGMPStorage.ipdl diff --git a/content/media/gmp/GMPChild.cpp b/content/media/gmp/GMPChild.cpp index 0f4c1b9966d..f93ef31bdaf 100644 --- a/content/media/gmp/GMPChild.cpp +++ b/content/media/gmp/GMPChild.cpp @@ -399,6 +399,32 @@ GMPChild::GetGMPTimers() return mTimerChild; } +PGMPStorageChild* +GMPChild::AllocPGMPStorageChild() +{ + return new GMPStorageChild(this); +} + +bool +GMPChild::DeallocPGMPStorageChild(PGMPStorageChild* aActor) +{ + mStorage = nullptr; + return true; +} + +GMPStorageChild* +GMPChild::GetGMPStorage() +{ + if (!mStorage) { + PGMPStorageChild* sc = SendPGMPStorageConstructor(); + if (!sc) { + return nullptr; + } + mStorage = static_cast(sc); + } + return mStorage; +} + bool GMPChild::RecvCrashPluginNow() { diff --git a/content/media/gmp/GMPChild.h b/content/media/gmp/GMPChild.h index 120dc5f8f55..2475b75cdd5 100644 --- a/content/media/gmp/GMPChild.h +++ b/content/media/gmp/GMPChild.h @@ -9,6 +9,7 @@ #include "mozilla/gmp/PGMPChild.h" #include "GMPSharedMemManager.h" #include "GMPTimerChild.h" +#include "GMPStorageChild.h" #include "gmp-async-shutdown.h" #include "gmp-entrypoints.h" #include "prlink.h" @@ -37,6 +38,7 @@ public: // Main thread only. GMPTimerChild* GetGMPTimers(); + GMPStorageChild* GetGMPStorage(); // GMPSharedMem virtual void CheckThread() MOZ_OVERRIDE; @@ -67,6 +69,9 @@ private: virtual PGMPTimerChild* AllocPGMPTimerChild() MOZ_OVERRIDE; virtual bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) MOZ_OVERRIDE; + virtual PGMPStorageChild* AllocPGMPStorageChild() MOZ_OVERRIDE; + virtual bool DeallocPGMPStorageChild(PGMPStorageChild* aActor) MOZ_OVERRIDE; + virtual bool RecvCrashPluginNow() MOZ_OVERRIDE; virtual bool RecvBeginAsyncShutdown() MOZ_OVERRIDE; @@ -75,6 +80,7 @@ private: GMPAsyncShutdown* mAsyncShutdown; nsRefPtr mTimerChild; + nsRefPtr mStorage; PRLibrary* mLib; GMPGetAPIFunc mGetAPIFunc; diff --git a/content/media/gmp/GMPParent.cpp b/content/media/gmp/GMPParent.cpp index 46408d123dc..6dffeaa0d5c 100644 --- a/content/media/gmp/GMPParent.cpp +++ b/content/media/gmp/GMPParent.cpp @@ -171,6 +171,10 @@ GMPParent::CloseIfUnused() } } } else { + // Any async shutdown must be complete. Shutdown GMPStorage. + for (size_t i = mStorage.Length(); i > 0; i--) { + mStorage[i - 1]->Shutdown(); + } Shutdown(); } } @@ -218,17 +222,14 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) mVideoDecoders[i - 1]->Shutdown(); } - // Invalidate and remove any remaining API objects. for (uint32_t i = mVideoEncoders.Length(); i > 0; i--) { mVideoEncoders[i - 1]->Shutdown(); } - // Invalidate and remove any remaining API objects. for (uint32_t i = mDecryptors.Length(); i > 0; i--) { mDecryptors[i - 1]->Shutdown(); } - // Invalidate and remove any remaining API objects. for (uint32_t i = mAudioDecoders.Length(); i > 0; i--) { mAudioDecoders[i - 1]->Shutdown(); } @@ -237,6 +238,9 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) mTimers[i - 1]->Shutdown(); } + // Note: We don't shutdown storage API objects here, as they need to + // work during async shutdown of GMPs. + // Note: the shutdown of the codecs is async! don't kill // the plugin-container until they're all safely shut down via // CloseIfUnused(); @@ -658,6 +662,29 @@ GMPParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) return true; } +PGMPStorageParent* +GMPParent::AllocPGMPStorageParent() +{ + GMPStorageParent* p = new GMPStorageParent(mOrigin, this); + mStorage.AppendElement(p); // Addrefs, released in DeallocPGMPStorageParent. + return p; +} + +bool +GMPParent::DeallocPGMPStorageParent(PGMPStorageParent* aActor) +{ + GMPStorageParent* p = static_cast(aActor); + p->Shutdown(); + mStorage.RemoveElement(p); + return true; +} + +bool +GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* actor) +{ + return true; +} + bool GMPParent::RecvPGMPTimerConstructor(PGMPTimerParent* actor) { diff --git a/content/media/gmp/GMPParent.h b/content/media/gmp/GMPParent.h index 28eca5ec451..2fe794324c8 100644 --- a/content/media/gmp/GMPParent.h +++ b/content/media/gmp/GMPParent.h @@ -13,6 +13,7 @@ #include "GMPVideoDecoderParent.h" #include "GMPVideoEncoderParent.h" #include "GMPTimerParent.h" +#include "GMPStorageParent.h" #include "mozilla/gmp/PGMPParent.h" #include "nsCOMPtr.h" #include "nscore.h" @@ -154,6 +155,10 @@ private: virtual PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() MOZ_OVERRIDE; virtual bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) MOZ_OVERRIDE; + virtual bool RecvPGMPStorageConstructor(PGMPStorageParent* actor) MOZ_OVERRIDE; + virtual PGMPStorageParent* AllocPGMPStorageParent() MOZ_OVERRIDE; + virtual bool DeallocPGMPStorageParent(PGMPStorageParent* aActor) MOZ_OVERRIDE; + virtual bool RecvPGMPTimerConstructor(PGMPTimerParent* actor) MOZ_OVERRIDE; virtual PGMPTimerParent* AllocPGMPTimerParent() MOZ_OVERRIDE; virtual bool DeallocPGMPTimerParent(PGMPTimerParent* aActor) MOZ_OVERRIDE; @@ -177,6 +182,7 @@ private: nsTArray> mDecryptors; nsTArray> mAudioDecoders; nsTArray> mTimers; + nsTArray> mStorage; nsCOMPtr mGMPThread; // Origin the plugin is assigned to, or empty if the the plugin is not // assigned to an origin. diff --git a/content/media/gmp/GMPPlatform.cpp b/content/media/gmp/GMPPlatform.cpp index 8964640fa50..347d2dbb666 100644 --- a/content/media/gmp/GMPPlatform.cpp +++ b/content/media/gmp/GMPPlatform.cpp @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "GMPPlatform.h" +#include "GMPStorageChild.h" #include "GMPTimerChild.h" #include "mozilla/Monitor.h" #include "nsAutoPtr.h" @@ -151,6 +152,30 @@ CreateMutex(GMPMutex** aMutex) return GMPNoErr; } +GMPErr +CreateRecord(const char* aRecordName, + uint32_t aRecordNameSize, + GMPRecord** aOutRecord, + GMPRecordClient* aClient) +{ + if (sMainLoop != MessageLoop::current()) { + NS_WARNING("GMP called CreateRecord() on non-main thread!"); + return GMPGenericErr; + } + if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE) { + NS_WARNING("GMP tried to CreateRecord with too long record name"); + return GMPGenericErr; + } + GMPStorageChild* storage = sChild->GetGMPStorage(); + if (!storage) { + return GMPGenericErr; + } + MOZ_ASSERT(storage); + return storage->CreateRecord(nsDependentCString(aRecordName, aRecordNameSize), + aOutRecord, + aClient); +} + GMPErr SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) { @@ -184,7 +209,7 @@ InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild) aPlatformAPI.runonmainthread = &RunOnMainThread; aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread; aPlatformAPI.createmutex = &CreateMutex; - aPlatformAPI.createrecord = nullptr; + aPlatformAPI.createrecord = &CreateRecord; aPlatformAPI.settimer = &SetTimerOnMainThread; aPlatformAPI.getcurrenttime = &GetClock; } diff --git a/content/media/gmp/GMPStorageChild.cpp b/content/media/gmp/GMPStorageChild.cpp new file mode 100644 index 00000000000..e5b7eb35525 --- /dev/null +++ b/content/media/gmp/GMPStorageChild.cpp @@ -0,0 +1,282 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "GMPStorageChild.h" +#include "GMPChild.h" +#include "gmp-storage.h" + +namespace mozilla { +namespace gmp { + +GMPRecordImpl::GMPRecordImpl(GMPStorageChild* aOwner, + const nsCString& aName, + GMPRecordClient* aClient) + : mName(aName) + , mClient(aClient) + , mOwner(aOwner) + , mIsClosed(true) +{ +} + +GMPErr +GMPRecordImpl::Open() +{ + if (!mIsClosed) { + return GMPRecordInUse; + } + return mOwner->Open(this); +} + +void +GMPRecordImpl::OpenComplete(GMPErr aStatus) +{ + mIsClosed = false; + mClient->OpenComplete(aStatus); +} + +GMPErr +GMPRecordImpl::Read() +{ + if (mIsClosed) { + return GMPClosedErr; + } + return mOwner->Read(this); +} + +void +GMPRecordImpl::ReadComplete(GMPErr aStatus, + const uint8_t* aBytes, + uint32_t aLength) +{ + mClient->ReadComplete(aStatus, aBytes, aLength); +} + +GMPErr +GMPRecordImpl::Write(const uint8_t* aData, uint32_t aDataSize) +{ + if (mIsClosed) { + return GMPClosedErr; + } + return mOwner->Write(this, aData, aDataSize); +} + +void +GMPRecordImpl::WriteComplete(GMPErr aStatus) +{ + mClient->WriteComplete(aStatus); +} + +GMPErr +GMPRecordImpl::Close() +{ + nsRefPtr kungfuDeathGrip(this); + + if (!mIsClosed) { + // Delete the storage child's reference to us. + mOwner->Close(this); + // Owner should callback MarkClosed(). + MOZ_ASSERT(mIsClosed); + } + + // Delete our self reference. + Release(); + + return GMPNoErr; +} + +void +GMPRecordImpl::MarkClosed() +{ + mIsClosed = true; +} + +GMPStorageChild::GMPStorageChild(GMPChild* aPlugin) + : mPlugin(aPlugin) + , mShutdown(false) +{ + MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current()); +} + +GMPErr +GMPStorageChild::CreateRecord(const nsCString& aRecordName, + GMPRecord** aOutRecord, + GMPRecordClient* aClient) +{ + if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { + NS_WARNING("GMP used GMPStorage on non-main thread."); + return GMPGenericErr; + } + if (mShutdown) { + NS_WARNING("GMPStorage used after it's been shutdown!"); + return GMPClosedErr; + } + MOZ_ASSERT(aRecordName.Length() && aOutRecord); + nsRefPtr record(new GMPRecordImpl(this, aRecordName, aClient)); + mRecords.Put(aRecordName, record); // Addrefs + + // The GMPRecord holds a self reference until the GMP calls Close() on + // it. This means the object is always valid (even if neutered) while + // the GMP expects it to be. + record.forget(aOutRecord); + + return GMPNoErr; +} + +GMPErr +GMPStorageChild::Open(GMPRecordImpl* aRecord) +{ + if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { + NS_WARNING("GMP used GMPStorage on non-main thread."); + return GMPGenericErr; + } + if (mShutdown) { + NS_WARNING("GMPStorage used after it's been shutdown!"); + return GMPClosedErr; + } + if (!SendOpen(aRecord->Name())) { + Close(aRecord); + return GMPClosedErr; + } + return GMPNoErr; +} + +GMPErr +GMPStorageChild::Read(GMPRecordImpl* aRecord) +{ + if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { + NS_WARNING("GMP used GMPStorage on non-main thread."); + return GMPGenericErr; + } + if (mShutdown) { + NS_WARNING("GMPStorage used after it's been shutdown!"); + return GMPClosedErr; + } + if (!SendRead(aRecord->Name())) { + Close(aRecord); + return GMPClosedErr; + } + return GMPNoErr; +} + +GMPErr +GMPStorageChild::Write(GMPRecordImpl* aRecord, + const uint8_t* aData, + uint32_t aDataSize) +{ + if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { + NS_WARNING("GMP used GMPStorage on non-main thread."); + return GMPGenericErr; + } + if (mShutdown) { + NS_WARNING("GMPStorage used after it's been shutdown!"); + return GMPClosedErr; + } + if (aDataSize > GMP_MAX_RECORD_SIZE) { + return GMPQuotaExceededErr; + } + nsTArray data; + data.AppendElements(aData, aDataSize); + if (!SendWrite(aRecord->Name(), data)) { + Close(aRecord); + return GMPClosedErr; + } + return GMPNoErr; +} + +GMPErr +GMPStorageChild::Close(GMPRecordImpl* aRecord) +{ + if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { + NS_WARNING("GMP used GMPStorage on non-main thread."); + return GMPGenericErr; + } + if (!mRecords.Contains(aRecord->Name())) { + // Already closed. + return GMPClosedErr; + } + + GMPErr rv = GMPNoErr; + if (!mShutdown && !SendClose(aRecord->Name())) { + rv = GMPGenericErr; + } + + aRecord->MarkClosed(); + mRecords.Remove(aRecord->Name()); + + return rv; +} + +bool +GMPStorageChild::RecvOpenComplete(const nsCString& aRecordName, + const GMPErr& aStatus) +{ + if (mShutdown) { + return true; + } + nsRefPtr record; + if (!mRecords.Get(aRecordName, getter_AddRefs(record)) || !record) { + // Not fatal. + return true; + } + record->OpenComplete(aStatus); + if (GMP_FAILED(aStatus)) { + Close(record); + } + return true; +} + +bool +GMPStorageChild::RecvReadComplete(const nsCString& aRecordName, + const GMPErr& aStatus, + const InfallibleTArray& aBytes) +{ + if (mShutdown) { + return true; + } + nsRefPtr record; + if (!mRecords.Get(aRecordName, getter_AddRefs(record)) || !record) { + // Not fatal. + return true; + } + record->ReadComplete(aStatus, + aBytes.Elements(), + aBytes.Length()); + if (GMP_FAILED(aStatus)) { + Close(record); + } + return true; +} + +bool +GMPStorageChild::RecvWriteComplete(const nsCString& aRecordName, + const GMPErr& aStatus) +{ + if (mShutdown) { + return true; + } + nsRefPtr record; + if (!mRecords.Get(aRecordName, getter_AddRefs(record)) || !record) { + // Not fatal. + return true; + } + record->WriteComplete(aStatus); + if (GMP_FAILED(aStatus)) { + Close(record); + } + return true; +} + +bool +GMPStorageChild::RecvShutdown() +{ + // Block any new storage requests, and thus any messages back to the + // parent. We don't delete any objects here, as that may invalidate + // GMPRecord pointers held by the GMP. + mShutdown = true; + return true; +} + +} // namespace gmp +} // namespace mozilla diff --git a/content/media/gmp/GMPStorageChild.h b/content/media/gmp/GMPStorageChild.h new file mode 100644 index 00000000000..e4248ee1f30 --- /dev/null +++ b/content/media/gmp/GMPStorageChild.h @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 2; 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 GMPStorageChild_h_ +#define GMPStorageChild_h_ + +#include "mozilla/gmp/PGMPStorageChild.h" +#include "gmp-storage.h" +#include "nsTHashtable.h" +#include "nsRefPtrHashtable.h" + +namespace mozilla { +namespace gmp { + +class GMPChild; +class GMPStorageChild; + +class GMPRecordImpl : public GMPRecord +{ +public: + NS_INLINE_DECL_REFCOUNTING(GMPRecordImpl) + + GMPRecordImpl(GMPStorageChild* aOwner, + const nsCString& aName, + GMPRecordClient* aClient); + + // GMPRecord. + virtual GMPErr Open() MOZ_OVERRIDE; + virtual GMPErr Read() MOZ_OVERRIDE; + virtual GMPErr Write(const uint8_t* aData, + uint32_t aDataSize) MOZ_OVERRIDE; + virtual GMPErr Close() MOZ_OVERRIDE; + + const nsCString& Name() const { return mName; } + + void OpenComplete(GMPErr aStatus); + void ReadComplete(GMPErr aStatus, const uint8_t* aBytes, uint32_t aLength); + void WriteComplete(GMPErr aStatus); + + void MarkClosed(); + +private: + ~GMPRecordImpl() {} + const nsCString mName; + GMPRecordClient* const mClient; + GMPStorageChild* const mOwner; + bool mIsClosed; +}; + +class GMPStorageChild : public PGMPStorageChild +{ +public: + NS_INLINE_DECL_REFCOUNTING(GMPStorageChild) + + GMPStorageChild(GMPChild* aPlugin); + + GMPErr CreateRecord(const nsCString& aRecordName, + GMPRecord** aOutRecord, + GMPRecordClient* aClient); + + GMPErr Open(GMPRecordImpl* aRecord); + + GMPErr Read(GMPRecordImpl* aRecord); + + GMPErr Write(GMPRecordImpl* aRecord, + const uint8_t* aData, + uint32_t aDataSize); + + GMPErr Close(GMPRecordImpl* aRecord); + +protected: + ~GMPStorageChild() {} + + // PGMPStorageChild + virtual bool RecvOpenComplete(const nsCString& aRecordName, + const GMPErr& aStatus) MOZ_OVERRIDE; + virtual bool RecvReadComplete(const nsCString& aRecordName, + const GMPErr& aStatus, + const InfallibleTArray& aBytes) MOZ_OVERRIDE; + virtual bool RecvWriteComplete(const nsCString& aRecordName, + const GMPErr& aStatus) MOZ_OVERRIDE; + virtual bool RecvShutdown() MOZ_OVERRIDE; + +private: + nsRefPtrHashtable mRecords; + GMPChild* mPlugin; + bool mShutdown; +}; + +} // namespace gmp +} // namespace mozilla + +#endif // GMPStorageChild_h_ diff --git a/content/media/gmp/GMPStorageParent.cpp b/content/media/gmp/GMPStorageParent.cpp new file mode 100644 index 00000000000..9ec343febaf --- /dev/null +++ b/content/media/gmp/GMPStorageParent.cpp @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +#include "GMPStorageParent.h" +#include "mozilla/SyncRunnable.h" +#include "plhash.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "GMPParent.h" +#include "gmp-storage.h" +#include "mozilla/unused.h" + +namespace mozilla { + +#ifdef LOG +#undef LOG +#endif + +#ifdef PR_LOGGING +extern PRLogModuleInfo* GetGMPLog(); + +#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg) +#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg) +#else +#define LOGD(msg) +#define LOG(level, msg) +#endif + +#ifdef __CLASS__ +#undef __CLASS__ +#endif +#define __CLASS__ "GMPParent" + +namespace gmp { + +class GetTempDirTask : public nsRunnable +{ +public: + NS_IMETHOD Run() { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr tmpFile; + nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + tmpFile->GetPath(mPath); + return NS_OK; + } + + nsString mPath; +}; + +// We store the records in files in the system temp dir. +static nsresult +GetGMPStorageDir(nsIFile** aTempDir, const nsString& aOrigin) +{ + if (NS_WARN_IF(!aTempDir)) { + return NS_ERROR_INVALID_ARG; + } + + // Directory service is main thread only... + nsRefPtr task = new GetTempDirTask(); + nsCOMPtr mainThread = do_GetMainThread(); + mozilla::SyncRunnable::DispatchToThread(mainThread, task); + + nsCOMPtr tmpFile; + nsresult rv = NS_NewLocalFile(task->mPath, false, getter_AddRefs(tmpFile)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->AppendNative(nsDependentCString("mozilla-gmp-storage")); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // TODO: When aOrigin is the same node-id as the GMP sees in the child + // process (a UUID or somesuch), we can just append it un-hashed here. + // This should reduce the chance of hash collsions exposing data. + nsAutoString nodeIdHash; + nodeIdHash.AppendInt(HashString(aOrigin.get())); + rv = tmpFile->Append(nodeIdHash); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + tmpFile.forget(aTempDir); + + return NS_OK; +} + +GMPStorageParent::GMPStorageParent(const nsString& aOrigin, + GMPParent* aPlugin) + : mOrigin(aOrigin) + , mPlugin(aPlugin) + , mShutdown(false) +{ +} + +enum OpenFileMode { ReadWrite, Truncate }; + +nsresult +OpenStorageFile(const nsCString& aRecordName, + const nsString& aNodeId, + const OpenFileMode aMode, + PRFileDesc** aOutFD) +{ + MOZ_ASSERT(aOutFD); + + nsCOMPtr f; + nsresult rv = GetGMPStorageDir(getter_AddRefs(f), aNodeId); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsAutoString recordNameHash; + recordNameHash.AppendInt(HashString(aRecordName.get())); + f->Append(recordNameHash); + + auto mode = PR_RDWR | PR_CREATE_FILE; + if (aMode == Truncate) { + mode |= PR_TRUNCATE; + } + + return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD); +} + +bool +GMPStorageParent::RecvOpen(const nsCString& aRecordName) +{ + if (mShutdown) { + return true; + } + + if (mOrigin.EqualsASCII("null")) { + // Refuse to open storage if the page is the "null" origin; if the page + // is opened from disk. + NS_WARNING("Refusing to open storage for null origin"); + unused << SendOpenComplete(aRecordName, GMPGenericErr); + return true; + } + + if (aRecordName.IsEmpty() || mFiles.Contains(aRecordName)) { + unused << SendOpenComplete(aRecordName, GMPRecordInUse); + return true; + } + + PRFileDesc* fd = nullptr; + nsresult rv = OpenStorageFile(aRecordName, mOrigin, ReadWrite, &fd); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to open storage file."); + unused << SendOpenComplete(aRecordName, GMPGenericErr); + return true; + } + + mFiles.Put(aRecordName, fd); + unused << SendOpenComplete(aRecordName, GMPNoErr); + + return true; +} + +bool +GMPStorageParent::RecvRead(const nsCString& aRecordName) +{ + LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get())); + + if (mShutdown) { + return true; + } + + PRFileDesc* fd = mFiles.Get(aRecordName); + nsTArray data; + if (!fd) { + unused << SendReadComplete(aRecordName, GMPClosedErr, data); + return true; + } + + int32_t len = PR_Seek(fd, 0, PR_SEEK_END); + PR_Seek(fd, 0, PR_SEEK_SET); + + if (len > GMP_MAX_RECORD_SIZE) { + // Refuse to read big records. + unused << SendReadComplete(aRecordName, GMPQuotaExceededErr, data); + return true; + } + data.SetLength(len); + auto bytesRead = PR_Read(fd, data.Elements(), len); + auto res = (bytesRead == len) ? GMPNoErr : GMPGenericErr; + unused << SendReadComplete(aRecordName, res, data); + + return true; +} + +bool +GMPStorageParent::RecvWrite(const nsCString& aRecordName, + const InfallibleTArray& aBytes) +{ + LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get())); + + if (mShutdown) { + return true; + } + if (aBytes.Length() > GMP_MAX_RECORD_SIZE) { + unused << SendWriteComplete(aRecordName, GMPQuotaExceededErr); + return true; + } + + PRFileDesc* fd = mFiles.Get(aRecordName); + if (!fd) { + unused << SendWriteComplete(aRecordName, GMPGenericErr); + return true; + } + + // Write operations overwrite the entire record. So re-open the file + // in truncate mode, to clear its contents. + PR_Close(fd); + mFiles.Remove(aRecordName); + if (NS_FAILED(OpenStorageFile(aRecordName, mOrigin, Truncate, &fd))) { + unused << SendWriteComplete(aRecordName, GMPGenericErr); + return true; + } + mFiles.Put(aRecordName, fd); + + int32_t bytesWritten = PR_Write(fd, aBytes.Elements(), aBytes.Length()); + auto res = (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr; + unused << SendWriteComplete(aRecordName, res); + return true; +} + +bool +GMPStorageParent::RecvClose(const nsCString& aRecordName) +{ + LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get())); + + if (mShutdown) { + return true; + } + + PRFileDesc* fd = mFiles.Get(aRecordName); + if (!fd) { + return true; + } + PR_Close(fd); + mFiles.Remove(aRecordName); + return true; +} + +void +GMPStorageParent::ActorDestroy(ActorDestroyReason aWhy) +{ + LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this)); + Shutdown(); +} + +PLDHashOperator +CloseFile(const nsACString& key, PRFileDesc*& entry, void* cx) +{ + PR_Close(entry); + return PL_DHASH_REMOVE; +} + +void +GMPStorageParent::Shutdown() +{ + LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this)); + + if (mShutdown) { + return; + } + mShutdown = true; + unused << SendShutdown(); + + mFiles.Enumerate(CloseFile, nullptr); + MOZ_ASSERT(!mFiles.Count()); +} + +} // namespace gmp +} // namespace mozilla diff --git a/content/media/gmp/GMPStorageParent.h b/content/media/gmp/GMPStorageParent.h new file mode 100644 index 00000000000..57583d0ead9 --- /dev/null +++ b/content/media/gmp/GMPStorageParent.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 2; 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 GMPStorageParent_h_ +#define GMPStorageParent_h_ + +#include "mozilla/gmp/PGMPStorageParent.h" +#include "gmp-storage.h" +#include "nsTHashtable.h" +#include "nsDataHashtable.h" +#include "prio.h" + +namespace mozilla { +namespace gmp { + +class GMPParent; + +class GMPStorageParent : public PGMPStorageParent { +public: + NS_INLINE_DECL_REFCOUNTING(GMPStorageParent) + GMPStorageParent(const nsString& aOrigin, GMPParent* aPlugin); + + void Shutdown(); + +protected: + virtual bool RecvOpen(const nsCString& aRecordName) MOZ_OVERRIDE; + virtual bool RecvRead(const nsCString& aRecordName) MOZ_OVERRIDE; + virtual bool RecvWrite(const nsCString& aRecordName, + const InfallibleTArray& aBytes) MOZ_OVERRIDE; + virtual bool RecvClose(const nsCString& aRecordName) MOZ_OVERRIDE; + virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; + +private: + nsDataHashtable mFiles; + const nsString mOrigin; + nsRefPtr mPlugin; + bool mShutdown; +}; + +} // namespace gmp +} // namespace mozilla + +#endif // GMPStorageParent_h_ diff --git a/content/media/gmp/PGMP.ipdl b/content/media/gmp/PGMP.ipdl index 9daa4784a34..be50bc9704f 100644 --- a/content/media/gmp/PGMP.ipdl +++ b/content/media/gmp/PGMP.ipdl @@ -9,6 +9,7 @@ include protocol PCrashReporter; include protocol PGMPDecryptor; include protocol PGMPAudioDecoder; include protocol PGMPTimer; +include protocol PGMPStorage; using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h"; @@ -23,10 +24,12 @@ intr protocol PGMP manages PGMPVideoEncoder; manages PCrashReporter; manages PGMPTimer; + manages PGMPStorage; parent: async PCrashReporter(NativeThreadId tid); async PGMPTimer(); + async PGMPStorage(); async AsyncShutdownComplete(); async AsyncShutdownRequired(); diff --git a/content/media/gmp/PGMPStorage.ipdl b/content/media/gmp/PGMPStorage.ipdl new file mode 100644 index 00000000000..c67a8bea2dc --- /dev/null +++ b/content/media/gmp/PGMPStorage.ipdl @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 2; 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/. */ + +include protocol PGMP; +include GMPTypes; + +using GMPErr from "gmp-errors.h"; + +namespace mozilla { +namespace gmp { + +async protocol PGMPStorage +{ + manager PGMP; + +child: + OpenComplete(nsCString aRecordName, GMPErr aStatus); + ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes); + WriteComplete(nsCString aRecordName, GMPErr aStatus); + Shutdown(); + +parent: + Open(nsCString aRecordName); + Read(nsCString aRecordName); + Write(nsCString aRecordName, uint8_t[] aBytes); + Close(nsCString aRecordName); + __delete__(); + +}; + +} // namespace gmp +} // namespace mozilla diff --git a/content/media/gmp/gmp-api/gmp-platform.h b/content/media/gmp/gmp-api/gmp-platform.h index feffe0133da..48b21f5702c 100644 --- a/content/media/gmp/gmp-api/gmp-platform.h +++ b/content/media/gmp/gmp-api/gmp-platform.h @@ -69,6 +69,8 @@ typedef GMPErr (*GMPCreateThreadPtr)(GMPThread** aThread); typedef GMPErr (*GMPRunOnMainThreadPtr)(GMPTask* aTask); typedef GMPErr (*GMPSyncRunOnMainThreadPtr)(GMPTask* aTask); typedef GMPErr (*GMPCreateMutexPtr)(GMPMutex** aMutex); + +// Call on main thread only. typedef GMPErr (*GMPCreateRecordPtr)(const char* aRecordName, uint32_t aRecordNameSize, GMPRecord** aOutRecord, diff --git a/content/media/gmp/gmp-api/gmp-storage.h b/content/media/gmp/gmp-api/gmp-storage.h index 6ca8872cab9..59f8175f52f 100644 --- a/content/media/gmp/gmp-api/gmp-storage.h +++ b/content/media/gmp/gmp-api/gmp-storage.h @@ -20,16 +20,31 @@ #include "gmp-errors.h" #include +// Maximum size of a record, in bytes. +#define GMP_MAX_RECORD_SIZE (1024 * 1024 * 1024) + +// Maximum length of a record name. +#define GMP_MAX_RECORD_NAME_SIZE 200 + // Provides basic per-origin storage for CDMs. GMPRecord instances can be // retrieved by calling GMPPlatformAPI->openstorage. Multiple GMPRecords // with different names can be open at once, but a single record can only // be opened by one client at a time. This interface is asynchronous, with // results being returned via callbacks to the GMPRecordClient pointer // provided to the GMPPlatformAPI->openstorage call, on the main thread. +// +// Lifecycle: Once opened, the GMPRecord object remains allocated until +// GMPRecord::Close() is called. If any GMPRecord function, either +// synchronously or asynchronously through a GMPRecordClient callback, +// returns an error, the GMP is responsible for calling Close() on the +// GMPRecord to delete the GMPRecord object's memory. If your GMP does not +// call Close(), the GMPRecord's memory will leak. class GMPRecord { public: // Opens the record. Calls OpenComplete() once the record is open. + // Note: Only work when GMP is loading content from a webserver. + // Does not work for web pages on loaded from disk. // Note: OpenComplete() is only called if this returns GMPNoErr. virtual GMPErr Open() = 0; @@ -39,13 +54,15 @@ public: virtual GMPErr Read() = 0; // Writes aDataSize bytes of aData into the record, overwriting the - // contents of the record. Overwriting with 0 bytes "deletes" the file. + // contents of the record, truncating it to aDataSize length. + // Overwriting with 0 bytes "deletes" the record. // Note: WriteComplete is only called if this returns GMPNoErr. virtual GMPErr Write(const uint8_t* aData, uint32_t aDataSize) = 0; - // Closes a record. GMPRecord object must not be used after this is - // called, request a new one with GMPPlatformAPI->openstorage to re-open - // this record. Cancels all callbacks. + // Closes a record, deletes the GMPRecord object. The GMPRecord object + // must not be used after this is called, request a new one with + // GMPPlatformAPI->openstorage to re-open this record. Cancels all + // callbacks. virtual GMPErr Close() = 0; virtual ~GMPRecord() {} @@ -61,7 +78,8 @@ class GMPRecordClient { // - GMPNoErr - Record opened successfully. Record may be empty. // - GMPRecordInUse - This record is in use by another client. // - GMPGenericErr - Unspecified error. - // Do not use the GMPRecord if aStatus is not GMPNoErr. + // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must + // call Close() on the GMPRecord to dispose of it. virtual void OpenComplete(GMPErr aStatus) = 0; // Response to a GMPRecord::Read() call, where aData is the record contents, @@ -74,7 +92,8 @@ class GMPRecordClient { // - GMPRecordInUse - There are other operations or clients in use on // this record. // - GMPGenericErr - Unspecified error. - // Do not continue to use the GMPRecord if aStatus is not GMPNoErr. + // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must + // call Close() on the GMPRecord to dispose of it. virtual void ReadComplete(GMPErr aStatus, const uint8_t* aData, uint32_t aDataSize) = 0; @@ -84,7 +103,8 @@ class GMPRecordClient { // - GMPRecordInUse - There are other operations or clients in use on // this record. // - GMPGenericErr - Unspecified error. - // Do not continue to use the GMPRecord if aStatus is not GMPNoErr. + // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must + // call Close() on the GMPRecord to dispose of it. virtual void WriteComplete(GMPErr aStatus) = 0; virtual ~GMPRecordClient() {} diff --git a/content/media/gmp/moz.build b/content/media/gmp/moz.build index 2bf2083d1ee..cd302051886 100644 --- a/content/media/gmp/moz.build +++ b/content/media/gmp/moz.build @@ -46,6 +46,8 @@ EXPORTS += [ 'GMPProcessParent.h', 'GMPService.h', 'GMPSharedMemManager.h', + 'GMPStorageChild.h', + 'GMPStorageParent.h', 'GMPTimerChild.h', 'GMPTimerParent.h', 'GMPVideoDecoderChild.h', @@ -74,6 +76,8 @@ UNIFIED_SOURCES += [ 'GMPProcessParent.cpp', 'GMPService.cpp', 'GMPSharedMemManager.cpp', + 'GMPStorageChild.cpp', + 'GMPStorageParent.cpp', 'GMPTimerChild.cpp', 'GMPTimerParent.cpp', 'GMPVideoDecoderChild.cpp', @@ -91,6 +95,7 @@ IPDL_SOURCES += [ 'PGMP.ipdl', 'PGMPAudioDecoder.ipdl', 'PGMPDecryptor.ipdl', + 'PGMPStorage.ipdl', 'PGMPTimer.ipdl', 'PGMPVideoDecoder.ipdl', 'PGMPVideoEncoder.ipdl', From 8526e8d3092c941a94a2634a106b0697c191035f Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Tue, 19 Aug 2014 17:03:11 +1200 Subject: [PATCH 81/86] Bug 1055408 - Kill GMP timers when entering shutdown. r=jesup --- content/media/gmp/GMPParent.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/content/media/gmp/GMPParent.cpp b/content/media/gmp/GMPParent.cpp index 6dffeaa0d5c..70970bd90e3 100644 --- a/content/media/gmp/GMPParent.cpp +++ b/content/media/gmp/GMPParent.cpp @@ -161,6 +161,12 @@ GMPParent::CloseIfUnused() mVideoEncoders.IsEmpty() && mDecryptors.IsEmpty() && mAudioDecoders.IsEmpty()) { + + // Ensure all timers are killed. + for (uint32_t i = mTimers.Length(); i > 0; i--) { + mTimers[i - 1]->Shutdown(); + } + if (mAsyncShutdownRequired) { if (!mAsyncShutdownInProgress) { LOGD(("%s::%s: %p sending async shutdown notification", __CLASS__, @@ -234,9 +240,8 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) mAudioDecoders[i - 1]->Shutdown(); } - for (uint32_t i = mTimers.Length(); i > 0; i--) { - mTimers[i - 1]->Shutdown(); - } + // Note: we don't shutdown timers here, we do that in CloseIfUnused(), + // as there are multiple entry points to CloseIfUnused(). // Note: We don't shutdown storage API objects here, as they need to // work during async shutdown of GMPs. From e8960b0a355e3011b8a3d1f8941ec2740d73ace9 Mon Sep 17 00:00:00 2001 From: Yuki Sekiguchi Date: Mon, 18 Aug 2014 22:33:45 -0700 Subject: [PATCH 82/86] Bug 1042885 - Part 1: A rp element should not auto close a rtc element. r=wchen --- parser/html/javasrc/ElementName.java | 16 ++++++++-------- parser/html/javasrc/TreeBuilder.java | 24 ++++++++++++------------ parser/html/nsHtml5ElementName.cpp | 8 ++++---- parser/html/nsHtml5TreeBuilder.cpp | 20 ++++++++++---------- parser/html/nsHtml5TreeBuilder.h | 4 ++-- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/parser/html/javasrc/ElementName.java b/parser/html/javasrc/ElementName.java index f693b3eb5c0..40dcd1c6ba9 100644 --- a/parser/html/javasrc/ElementName.java +++ b/parser/html/javasrc/ElementName.java @@ -356,10 +356,10 @@ public final class ElementName // return "ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY"; // case TreeBuilder.RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR: // return "RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR"; -// case TreeBuilder.RB_OR_RP_OR_RTC: -// return "RB_OR_RP_OR_RTC"; -// case TreeBuilder.RT: -// return "RT"; +// case TreeBuilder.RB_OR_RTC: +// return "RB_OR_RTC"; +// case TreeBuilder.RT_OR_RP: +// return "RT_OR_RP"; // case TreeBuilder.PARAM_OR_SOURCE_OR_TRACK: // return "PARAM_OR_SOURCE_OR_TRACK"; // case TreeBuilder.MGLYPH_OR_MALIGNMARK: @@ -447,9 +447,9 @@ public final class ElementName public static final ElementName OL = new ElementName("ol", "ol", TreeBuilder.UL_OR_OL_OR_DL | SPECIAL); public static final ElementName OR = new ElementName("or", "or", TreeBuilder.OTHER); public static final ElementName PI = new ElementName("pi", "pi", TreeBuilder.OTHER); - public static final ElementName RB = new ElementName("rb", "rb", TreeBuilder.RB_OR_RP_OR_RTC | OPTIONAL_END_TAG); - public static final ElementName RP = new ElementName("rp", "rp", TreeBuilder.RB_OR_RP_OR_RTC | OPTIONAL_END_TAG); - public static final ElementName RT = new ElementName("rt", "rt", TreeBuilder.RT | OPTIONAL_END_TAG); + public static final ElementName RB = new ElementName("rb", "rb", TreeBuilder.RB_OR_RTC | OPTIONAL_END_TAG); + public static final ElementName RP = new ElementName("rp", "rp", TreeBuilder.RT_OR_RP | OPTIONAL_END_TAG); + public static final ElementName RT = new ElementName("rt", "rt", TreeBuilder.RT_OR_RP | OPTIONAL_END_TAG); public static final ElementName TD = new ElementName("td", "td", TreeBuilder.TD_OR_TH | SPECIAL | SCOPING | OPTIONAL_END_TAG); public static final ElementName TH = new ElementName("th", "th", TreeBuilder.TD_OR_TH | SPECIAL | SCOPING | OPTIONAL_END_TAG); public static final ElementName TR = new ElementName("tr", "tr", TreeBuilder.TR | SPECIAL | FOSTER_PARENTING | OPTIONAL_END_TAG); @@ -487,7 +487,7 @@ public final class ElementName public static final ElementName NOT = new ElementName("not", "not", TreeBuilder.OTHER); public static final ElementName NAV = new ElementName("nav", "nav", TreeBuilder.ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY | SPECIAL); public static final ElementName PRE = new ElementName("pre", "pre", TreeBuilder.PRE_OR_LISTING | SPECIAL); - public static final ElementName RTC = new ElementName("rtc", "rtc", TreeBuilder.RB_OR_RP_OR_RTC | OPTIONAL_END_TAG); + public static final ElementName RTC = new ElementName("rtc", "rtc", TreeBuilder.RB_OR_RTC | OPTIONAL_END_TAG); public static final ElementName REM = new ElementName("rem", "rem", TreeBuilder.OTHER); public static final ElementName SUB = new ElementName("sub", "sub", TreeBuilder.RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR); public static final ElementName SEC = new ElementName("sec", "sec", TreeBuilder.OTHER); diff --git a/parser/html/javasrc/TreeBuilder.java b/parser/html/javasrc/TreeBuilder.java index 7acced0d1c8..3a3662ae712 100644 --- a/parser/html/javasrc/TreeBuilder.java +++ b/parser/html/javasrc/TreeBuilder.java @@ -173,7 +173,7 @@ public abstract class TreeBuilder implements TokenHandler, final static int RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR = 52; - final static int RB_OR_RP_OR_RTC = 53; + final static int RB_OR_RTC = 53; final static int PARAM_OR_SOURCE_OR_TRACK = 55; @@ -203,7 +203,7 @@ public abstract class TreeBuilder implements TokenHandler, final static int IMG = 68; - final static int RT = 69; + final static int RT_OR_RP = 69; // start insertion modes @@ -2410,7 +2410,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes); attributes = null; // CPP break starttagloop; - case RB_OR_RP_OR_RTC: + case RB_OR_RTC: eltPos = findLastInScope("ruby"); if (eltPos != NOT_FOUND_ON_STACK) { generateImpliedEndTags(); @@ -2427,7 +2427,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes); attributes = null; // CPP break starttagloop; - case RT: + case RT_OR_RP: eltPos = findLastInScope("ruby"); if (eltPos != NOT_FOUND_ON_STACK) { generateImpliedEndTagsExceptFor("rtc"); @@ -3550,8 +3550,8 @@ public abstract class TreeBuilder implements TokenHandler, case OPTGROUP: case OPTION: // is this possible? case P: - case RB_OR_RP_OR_RTC: - case RT: + case RB_OR_RTC: + case RT_OR_RP: case TD_OR_TH: case TBODY_OR_THEAD_OR_TFOOT: break; @@ -3575,8 +3575,8 @@ public abstract class TreeBuilder implements TokenHandler, case DD_OR_DT: case LI: case P: - case RB_OR_RP_OR_RTC: - case RT: + case RB_OR_RTC: + case RT_OR_RP: case TBODY_OR_THEAD_OR_TFOOT: case TD_OR_TH: case BODY: @@ -4194,8 +4194,8 @@ public abstract class TreeBuilder implements TokenHandler, case DD_OR_DT: case OPTION: case OPTGROUP: - case RB_OR_RP_OR_RTC: - case RT: + case RB_OR_RTC: + case RT_OR_RP: if (node.ns == "http://www.w3.org/1999/xhtml" && node.name == name) { return; } @@ -4215,8 +4215,8 @@ public abstract class TreeBuilder implements TokenHandler, case DD_OR_DT: case OPTION: case OPTGROUP: - case RB_OR_RP_OR_RTC: - case RT: + case RB_OR_RTC: + case RT_OR_RP: pop(); continue; default: diff --git a/parser/html/nsHtml5ElementName.cpp b/parser/html/nsHtml5ElementName.cpp index 88166964587..bc397052644 100644 --- a/parser/html/nsHtml5ElementName.cpp +++ b/parser/html/nsHtml5ElementName.cpp @@ -575,9 +575,9 @@ nsHtml5ElementName::initializeStatics() ELT_OL = new nsHtml5ElementName(nsHtml5Atoms::ol, nsHtml5Atoms::ol, NS_HTML5TREE_BUILDER_UL_OR_OL_OR_DL | NS_HTML5ELEMENT_NAME_SPECIAL); ELT_OR = new nsHtml5ElementName(nsHtml5Atoms::or_, nsHtml5Atoms::or_, NS_HTML5TREE_BUILDER_OTHER); ELT_PI = new nsHtml5ElementName(nsHtml5Atoms::pi, nsHtml5Atoms::pi, NS_HTML5TREE_BUILDER_OTHER); - ELT_RB = new nsHtml5ElementName(nsHtml5Atoms::rb, nsHtml5Atoms::rb, NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); - ELT_RP = new nsHtml5ElementName(nsHtml5Atoms::rp, nsHtml5Atoms::rp, NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); - ELT_RT = new nsHtml5ElementName(nsHtml5Atoms::rt, nsHtml5Atoms::rt, NS_HTML5TREE_BUILDER_RT | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); + ELT_RB = new nsHtml5ElementName(nsHtml5Atoms::rb, nsHtml5Atoms::rb, NS_HTML5TREE_BUILDER_RB_OR_RTC | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); + ELT_RP = new nsHtml5ElementName(nsHtml5Atoms::rp, nsHtml5Atoms::rp, NS_HTML5TREE_BUILDER_RT_OR_RP | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); + ELT_RT = new nsHtml5ElementName(nsHtml5Atoms::rt, nsHtml5Atoms::rt, NS_HTML5TREE_BUILDER_RT_OR_RP | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); ELT_TD = new nsHtml5ElementName(nsHtml5Atoms::td, nsHtml5Atoms::td, NS_HTML5TREE_BUILDER_TD_OR_TH | NS_HTML5ELEMENT_NAME_SPECIAL | NS_HTML5ELEMENT_NAME_SCOPING | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); ELT_TH = new nsHtml5ElementName(nsHtml5Atoms::th, nsHtml5Atoms::th, NS_HTML5TREE_BUILDER_TD_OR_TH | NS_HTML5ELEMENT_NAME_SPECIAL | NS_HTML5ELEMENT_NAME_SCOPING | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); ELT_TR = new nsHtml5ElementName(nsHtml5Atoms::tr, nsHtml5Atoms::tr, NS_HTML5TREE_BUILDER_TR | NS_HTML5ELEMENT_NAME_SPECIAL | NS_HTML5ELEMENT_NAME_FOSTER_PARENTING | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); @@ -615,7 +615,7 @@ nsHtml5ElementName::initializeStatics() ELT_NOT = new nsHtml5ElementName(nsHtml5Atoms::not_, nsHtml5Atoms::not_, NS_HTML5TREE_BUILDER_OTHER); ELT_NAV = new nsHtml5ElementName(nsHtml5Atoms::nav, nsHtml5Atoms::nav, NS_HTML5TREE_BUILDER_ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY | NS_HTML5ELEMENT_NAME_SPECIAL); ELT_PRE = new nsHtml5ElementName(nsHtml5Atoms::pre, nsHtml5Atoms::pre, NS_HTML5TREE_BUILDER_PRE_OR_LISTING | NS_HTML5ELEMENT_NAME_SPECIAL); - ELT_RTC = new nsHtml5ElementName(nsHtml5Atoms::rtc, nsHtml5Atoms::rtc, NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); + ELT_RTC = new nsHtml5ElementName(nsHtml5Atoms::rtc, nsHtml5Atoms::rtc, NS_HTML5TREE_BUILDER_RB_OR_RTC | NS_HTML5ELEMENT_NAME_OPTIONAL_END_TAG); ELT_REM = new nsHtml5ElementName(nsHtml5Atoms::rem, nsHtml5Atoms::rem, NS_HTML5TREE_BUILDER_OTHER); ELT_SUB = new nsHtml5ElementName(nsHtml5Atoms::sub, nsHtml5Atoms::sub, NS_HTML5TREE_BUILDER_RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR); ELT_SEC = new nsHtml5ElementName(nsHtml5Atoms::sec, nsHtml5Atoms::sec, NS_HTML5TREE_BUILDER_OTHER); diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp index 22c82b5031b..a21af986791 100644 --- a/parser/html/nsHtml5TreeBuilder.cpp +++ b/parser/html/nsHtml5TreeBuilder.cpp @@ -1322,7 +1322,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu attributes = nullptr; NS_HTML5_BREAK(starttagloop); } - case NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC: { + case NS_HTML5TREE_BUILDER_RB_OR_RTC: { eltPos = findLastInScope(nsHtml5Atoms::ruby); if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { generateImpliedEndTags(); @@ -1338,7 +1338,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu attributes = nullptr; NS_HTML5_BREAK(starttagloop); } - case NS_HTML5TREE_BUILDER_RT: { + case NS_HTML5TREE_BUILDER_RT_OR_RP: { eltPos = findLastInScope(nsHtml5Atoms::ruby); if (eltPos != NS_HTML5TREE_BUILDER_NOT_FOUND_ON_STACK) { generateImpliedEndTagsExceptFor(nsHtml5Atoms::rtc); @@ -2466,8 +2466,8 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) case NS_HTML5TREE_BUILDER_OPTGROUP: case NS_HTML5TREE_BUILDER_OPTION: case NS_HTML5TREE_BUILDER_P: - case NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC: - case NS_HTML5TREE_BUILDER_RT: + case NS_HTML5TREE_BUILDER_RB_OR_RTC: + case NS_HTML5TREE_BUILDER_RT_OR_RP: case NS_HTML5TREE_BUILDER_TD_OR_TH: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: { break; @@ -2495,8 +2495,8 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) case NS_HTML5TREE_BUILDER_DD_OR_DT: case NS_HTML5TREE_BUILDER_LI: case NS_HTML5TREE_BUILDER_P: - case NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC: - case NS_HTML5TREE_BUILDER_RT: + case NS_HTML5TREE_BUILDER_RB_OR_RTC: + case NS_HTML5TREE_BUILDER_RT_OR_RP: case NS_HTML5TREE_BUILDER_TBODY_OR_THEAD_OR_TFOOT: case NS_HTML5TREE_BUILDER_TD_OR_TH: case NS_HTML5TREE_BUILDER_BODY: @@ -3136,8 +3136,8 @@ nsHtml5TreeBuilder::generateImpliedEndTagsExceptFor(nsIAtom* name) case NS_HTML5TREE_BUILDER_DD_OR_DT: case NS_HTML5TREE_BUILDER_OPTION: case NS_HTML5TREE_BUILDER_OPTGROUP: - case NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC: - case NS_HTML5TREE_BUILDER_RT: { + case NS_HTML5TREE_BUILDER_RB_OR_RTC: + case NS_HTML5TREE_BUILDER_RT_OR_RP: { if (node->ns == kNameSpaceID_XHTML && node->name == name) { return; } @@ -3161,8 +3161,8 @@ nsHtml5TreeBuilder::generateImpliedEndTags() case NS_HTML5TREE_BUILDER_DD_OR_DT: case NS_HTML5TREE_BUILDER_OPTION: case NS_HTML5TREE_BUILDER_OPTGROUP: - case NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC: - case NS_HTML5TREE_BUILDER_RT: { + case NS_HTML5TREE_BUILDER_RB_OR_RTC: + case NS_HTML5TREE_BUILDER_RT_OR_RP: { pop(); continue; } diff --git a/parser/html/nsHtml5TreeBuilder.h b/parser/html/nsHtml5TreeBuilder.h index b856d6de0de..502c069dee8 100644 --- a/parser/html/nsHtml5TreeBuilder.h +++ b/parser/html/nsHtml5TreeBuilder.h @@ -323,7 +323,7 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState #define NS_HTML5TREE_BUILDER_DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU 50 #define NS_HTML5TREE_BUILDER_ADDRESS_OR_ARTICLE_OR_ASIDE_OR_DETAILS_OR_DIR_OR_FIGCAPTION_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_HGROUP_OR_MAIN_OR_NAV_OR_SECTION_OR_SUMMARY 51 #define NS_HTML5TREE_BUILDER_RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR 52 -#define NS_HTML5TREE_BUILDER_RB_OR_RP_OR_RTC 53 +#define NS_HTML5TREE_BUILDER_RB_OR_RTC 53 #define NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE_OR_TRACK 55 #define NS_HTML5TREE_BUILDER_MGLYPH_OR_MALIGNMARK 56 #define NS_HTML5TREE_BUILDER_MI_MO_MN_MS_MTEXT 57 @@ -338,7 +338,7 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState #define NS_HTML5TREE_BUILDER_MENUITEM 66 #define NS_HTML5TREE_BUILDER_TEMPLATE 67 #define NS_HTML5TREE_BUILDER_IMG 68 -#define NS_HTML5TREE_BUILDER_RT 69 +#define NS_HTML5TREE_BUILDER_RT_OR_RP 69 #define NS_HTML5TREE_BUILDER_IN_ROW 0 #define NS_HTML5TREE_BUILDER_IN_TABLE_BODY 1 #define NS_HTML5TREE_BUILDER_IN_TABLE 2 From 3156f7446fbe0c8d036bf50b8f3fd606c0ec0b8c Mon Sep 17 00:00:00 2001 From: Yuki Sekiguchi Date: Mon, 18 Aug 2014 22:33:45 -0700 Subject: [PATCH 83/86] Bug 1042885 - Part 2: Fix test case for a rp element should not auto close a rtc element. r=wchen --- .../tests/mochitest/html5lib_tree_construction/ruby.dat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat index 80d0c53313c..1ca8016cf13 100644 --- a/parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat +++ b/parser/htmlparser/tests/mochitest/html5lib_tree_construction/ruby.dat @@ -195,7 +195,7 @@ | "a" | | "b" -| +| #data ab From ec1c45c5c46d0b0cfa74c8b3b4b15de929a4290c Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Tue, 19 Aug 2014 12:06:42 +0530 Subject: [PATCH 84/86] Backed out changeset 3b0d1e17cad0 (bug 1055408) for bustage --- content/media/gmp/GMPParent.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/content/media/gmp/GMPParent.cpp b/content/media/gmp/GMPParent.cpp index 70970bd90e3..6dffeaa0d5c 100644 --- a/content/media/gmp/GMPParent.cpp +++ b/content/media/gmp/GMPParent.cpp @@ -161,12 +161,6 @@ GMPParent::CloseIfUnused() mVideoEncoders.IsEmpty() && mDecryptors.IsEmpty() && mAudioDecoders.IsEmpty()) { - - // Ensure all timers are killed. - for (uint32_t i = mTimers.Length(); i > 0; i--) { - mTimers[i - 1]->Shutdown(); - } - if (mAsyncShutdownRequired) { if (!mAsyncShutdownInProgress) { LOGD(("%s::%s: %p sending async shutdown notification", __CLASS__, @@ -240,8 +234,9 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) mAudioDecoders[i - 1]->Shutdown(); } - // Note: we don't shutdown timers here, we do that in CloseIfUnused(), - // as there are multiple entry points to CloseIfUnused(). + for (uint32_t i = mTimers.Length(); i > 0; i--) { + mTimers[i - 1]->Shutdown(); + } // Note: We don't shutdown storage API objects here, as they need to // work during async shutdown of GMPs. From 0ad13193ff6a2fa92d75925c71bbf9199e5df87c Mon Sep 17 00:00:00 2001 From: Nigel Babu Date: Tue, 19 Aug 2014 12:07:01 +0530 Subject: [PATCH 85/86] Backed out changeset 55ea2c2fb857 (bug 1034368) for bustage --- content/media/gmp/GMPChild.cpp | 26 -- content/media/gmp/GMPChild.h | 6 - content/media/gmp/GMPParent.cpp | 33 +-- content/media/gmp/GMPParent.h | 6 - content/media/gmp/GMPPlatform.cpp | 27 +-- content/media/gmp/GMPStorageChild.cpp | 282 ---------------------- content/media/gmp/GMPStorageChild.h | 95 -------- content/media/gmp/GMPStorageParent.cpp | 287 ----------------------- content/media/gmp/GMPStorageParent.h | 45 ---- content/media/gmp/PGMP.ipdl | 3 - content/media/gmp/PGMPStorage.ipdl | 34 --- content/media/gmp/gmp-api/gmp-platform.h | 2 - content/media/gmp/gmp-api/gmp-storage.h | 34 +-- content/media/gmp/moz.build | 5 - 14 files changed, 11 insertions(+), 874 deletions(-) delete mode 100644 content/media/gmp/GMPStorageChild.cpp delete mode 100644 content/media/gmp/GMPStorageChild.h delete mode 100644 content/media/gmp/GMPStorageParent.cpp delete mode 100644 content/media/gmp/GMPStorageParent.h delete mode 100644 content/media/gmp/PGMPStorage.ipdl diff --git a/content/media/gmp/GMPChild.cpp b/content/media/gmp/GMPChild.cpp index f93ef31bdaf..0f4c1b9966d 100644 --- a/content/media/gmp/GMPChild.cpp +++ b/content/media/gmp/GMPChild.cpp @@ -399,32 +399,6 @@ GMPChild::GetGMPTimers() return mTimerChild; } -PGMPStorageChild* -GMPChild::AllocPGMPStorageChild() -{ - return new GMPStorageChild(this); -} - -bool -GMPChild::DeallocPGMPStorageChild(PGMPStorageChild* aActor) -{ - mStorage = nullptr; - return true; -} - -GMPStorageChild* -GMPChild::GetGMPStorage() -{ - if (!mStorage) { - PGMPStorageChild* sc = SendPGMPStorageConstructor(); - if (!sc) { - return nullptr; - } - mStorage = static_cast(sc); - } - return mStorage; -} - bool GMPChild::RecvCrashPluginNow() { diff --git a/content/media/gmp/GMPChild.h b/content/media/gmp/GMPChild.h index 2475b75cdd5..120dc5f8f55 100644 --- a/content/media/gmp/GMPChild.h +++ b/content/media/gmp/GMPChild.h @@ -9,7 +9,6 @@ #include "mozilla/gmp/PGMPChild.h" #include "GMPSharedMemManager.h" #include "GMPTimerChild.h" -#include "GMPStorageChild.h" #include "gmp-async-shutdown.h" #include "gmp-entrypoints.h" #include "prlink.h" @@ -38,7 +37,6 @@ public: // Main thread only. GMPTimerChild* GetGMPTimers(); - GMPStorageChild* GetGMPStorage(); // GMPSharedMem virtual void CheckThread() MOZ_OVERRIDE; @@ -69,9 +67,6 @@ private: virtual PGMPTimerChild* AllocPGMPTimerChild() MOZ_OVERRIDE; virtual bool DeallocPGMPTimerChild(PGMPTimerChild* aActor) MOZ_OVERRIDE; - virtual PGMPStorageChild* AllocPGMPStorageChild() MOZ_OVERRIDE; - virtual bool DeallocPGMPStorageChild(PGMPStorageChild* aActor) MOZ_OVERRIDE; - virtual bool RecvCrashPluginNow() MOZ_OVERRIDE; virtual bool RecvBeginAsyncShutdown() MOZ_OVERRIDE; @@ -80,7 +75,6 @@ private: GMPAsyncShutdown* mAsyncShutdown; nsRefPtr mTimerChild; - nsRefPtr mStorage; PRLibrary* mLib; GMPGetAPIFunc mGetAPIFunc; diff --git a/content/media/gmp/GMPParent.cpp b/content/media/gmp/GMPParent.cpp index 6dffeaa0d5c..46408d123dc 100644 --- a/content/media/gmp/GMPParent.cpp +++ b/content/media/gmp/GMPParent.cpp @@ -171,10 +171,6 @@ GMPParent::CloseIfUnused() } } } else { - // Any async shutdown must be complete. Shutdown GMPStorage. - for (size_t i = mStorage.Length(); i > 0; i--) { - mStorage[i - 1]->Shutdown(); - } Shutdown(); } } @@ -222,14 +218,17 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) mVideoDecoders[i - 1]->Shutdown(); } + // Invalidate and remove any remaining API objects. for (uint32_t i = mVideoEncoders.Length(); i > 0; i--) { mVideoEncoders[i - 1]->Shutdown(); } + // Invalidate and remove any remaining API objects. for (uint32_t i = mDecryptors.Length(); i > 0; i--) { mDecryptors[i - 1]->Shutdown(); } + // Invalidate and remove any remaining API objects. for (uint32_t i = mAudioDecoders.Length(); i > 0; i--) { mAudioDecoders[i - 1]->Shutdown(); } @@ -238,9 +237,6 @@ GMPParent::CloseActive(bool aDieWhenUnloaded) mTimers[i - 1]->Shutdown(); } - // Note: We don't shutdown storage API objects here, as they need to - // work during async shutdown of GMPs. - // Note: the shutdown of the codecs is async! don't kill // the plugin-container until they're all safely shut down via // CloseIfUnused(); @@ -662,29 +658,6 @@ GMPParent::DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) return true; } -PGMPStorageParent* -GMPParent::AllocPGMPStorageParent() -{ - GMPStorageParent* p = new GMPStorageParent(mOrigin, this); - mStorage.AppendElement(p); // Addrefs, released in DeallocPGMPStorageParent. - return p; -} - -bool -GMPParent::DeallocPGMPStorageParent(PGMPStorageParent* aActor) -{ - GMPStorageParent* p = static_cast(aActor); - p->Shutdown(); - mStorage.RemoveElement(p); - return true; -} - -bool -GMPParent::RecvPGMPStorageConstructor(PGMPStorageParent* actor) -{ - return true; -} - bool GMPParent::RecvPGMPTimerConstructor(PGMPTimerParent* actor) { diff --git a/content/media/gmp/GMPParent.h b/content/media/gmp/GMPParent.h index 2fe794324c8..28eca5ec451 100644 --- a/content/media/gmp/GMPParent.h +++ b/content/media/gmp/GMPParent.h @@ -13,7 +13,6 @@ #include "GMPVideoDecoderParent.h" #include "GMPVideoEncoderParent.h" #include "GMPTimerParent.h" -#include "GMPStorageParent.h" #include "mozilla/gmp/PGMPParent.h" #include "nsCOMPtr.h" #include "nscore.h" @@ -155,10 +154,6 @@ private: virtual PGMPAudioDecoderParent* AllocPGMPAudioDecoderParent() MOZ_OVERRIDE; virtual bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) MOZ_OVERRIDE; - virtual bool RecvPGMPStorageConstructor(PGMPStorageParent* actor) MOZ_OVERRIDE; - virtual PGMPStorageParent* AllocPGMPStorageParent() MOZ_OVERRIDE; - virtual bool DeallocPGMPStorageParent(PGMPStorageParent* aActor) MOZ_OVERRIDE; - virtual bool RecvPGMPTimerConstructor(PGMPTimerParent* actor) MOZ_OVERRIDE; virtual PGMPTimerParent* AllocPGMPTimerParent() MOZ_OVERRIDE; virtual bool DeallocPGMPTimerParent(PGMPTimerParent* aActor) MOZ_OVERRIDE; @@ -182,7 +177,6 @@ private: nsTArray> mDecryptors; nsTArray> mAudioDecoders; nsTArray> mTimers; - nsTArray> mStorage; nsCOMPtr mGMPThread; // Origin the plugin is assigned to, or empty if the the plugin is not // assigned to an origin. diff --git a/content/media/gmp/GMPPlatform.cpp b/content/media/gmp/GMPPlatform.cpp index 347d2dbb666..8964640fa50 100644 --- a/content/media/gmp/GMPPlatform.cpp +++ b/content/media/gmp/GMPPlatform.cpp @@ -4,7 +4,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "GMPPlatform.h" -#include "GMPStorageChild.h" #include "GMPTimerChild.h" #include "mozilla/Monitor.h" #include "nsAutoPtr.h" @@ -152,30 +151,6 @@ CreateMutex(GMPMutex** aMutex) return GMPNoErr; } -GMPErr -CreateRecord(const char* aRecordName, - uint32_t aRecordNameSize, - GMPRecord** aOutRecord, - GMPRecordClient* aClient) -{ - if (sMainLoop != MessageLoop::current()) { - NS_WARNING("GMP called CreateRecord() on non-main thread!"); - return GMPGenericErr; - } - if (aRecordNameSize > GMP_MAX_RECORD_NAME_SIZE) { - NS_WARNING("GMP tried to CreateRecord with too long record name"); - return GMPGenericErr; - } - GMPStorageChild* storage = sChild->GetGMPStorage(); - if (!storage) { - return GMPGenericErr; - } - MOZ_ASSERT(storage); - return storage->CreateRecord(nsDependentCString(aRecordName, aRecordNameSize), - aOutRecord, - aClient); -} - GMPErr SetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) { @@ -209,7 +184,7 @@ InitPlatformAPI(GMPPlatformAPI& aPlatformAPI, GMPChild* aChild) aPlatformAPI.runonmainthread = &RunOnMainThread; aPlatformAPI.syncrunonmainthread = &SyncRunOnMainThread; aPlatformAPI.createmutex = &CreateMutex; - aPlatformAPI.createrecord = &CreateRecord; + aPlatformAPI.createrecord = nullptr; aPlatformAPI.settimer = &SetTimerOnMainThread; aPlatformAPI.getcurrenttime = &GetClock; } diff --git a/content/media/gmp/GMPStorageChild.cpp b/content/media/gmp/GMPStorageChild.cpp deleted file mode 100644 index e5b7eb35525..00000000000 --- a/content/media/gmp/GMPStorageChild.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; 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/. */ - -#include "GMPStorageChild.h" -#include "GMPChild.h" -#include "gmp-storage.h" - -namespace mozilla { -namespace gmp { - -GMPRecordImpl::GMPRecordImpl(GMPStorageChild* aOwner, - const nsCString& aName, - GMPRecordClient* aClient) - : mName(aName) - , mClient(aClient) - , mOwner(aOwner) - , mIsClosed(true) -{ -} - -GMPErr -GMPRecordImpl::Open() -{ - if (!mIsClosed) { - return GMPRecordInUse; - } - return mOwner->Open(this); -} - -void -GMPRecordImpl::OpenComplete(GMPErr aStatus) -{ - mIsClosed = false; - mClient->OpenComplete(aStatus); -} - -GMPErr -GMPRecordImpl::Read() -{ - if (mIsClosed) { - return GMPClosedErr; - } - return mOwner->Read(this); -} - -void -GMPRecordImpl::ReadComplete(GMPErr aStatus, - const uint8_t* aBytes, - uint32_t aLength) -{ - mClient->ReadComplete(aStatus, aBytes, aLength); -} - -GMPErr -GMPRecordImpl::Write(const uint8_t* aData, uint32_t aDataSize) -{ - if (mIsClosed) { - return GMPClosedErr; - } - return mOwner->Write(this, aData, aDataSize); -} - -void -GMPRecordImpl::WriteComplete(GMPErr aStatus) -{ - mClient->WriteComplete(aStatus); -} - -GMPErr -GMPRecordImpl::Close() -{ - nsRefPtr kungfuDeathGrip(this); - - if (!mIsClosed) { - // Delete the storage child's reference to us. - mOwner->Close(this); - // Owner should callback MarkClosed(). - MOZ_ASSERT(mIsClosed); - } - - // Delete our self reference. - Release(); - - return GMPNoErr; -} - -void -GMPRecordImpl::MarkClosed() -{ - mIsClosed = true; -} - -GMPStorageChild::GMPStorageChild(GMPChild* aPlugin) - : mPlugin(aPlugin) - , mShutdown(false) -{ - MOZ_ASSERT(mPlugin->GMPMessageLoop() == MessageLoop::current()); -} - -GMPErr -GMPStorageChild::CreateRecord(const nsCString& aRecordName, - GMPRecord** aOutRecord, - GMPRecordClient* aClient) -{ - if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { - NS_WARNING("GMP used GMPStorage on non-main thread."); - return GMPGenericErr; - } - if (mShutdown) { - NS_WARNING("GMPStorage used after it's been shutdown!"); - return GMPClosedErr; - } - MOZ_ASSERT(aRecordName.Length() && aOutRecord); - nsRefPtr record(new GMPRecordImpl(this, aRecordName, aClient)); - mRecords.Put(aRecordName, record); // Addrefs - - // The GMPRecord holds a self reference until the GMP calls Close() on - // it. This means the object is always valid (even if neutered) while - // the GMP expects it to be. - record.forget(aOutRecord); - - return GMPNoErr; -} - -GMPErr -GMPStorageChild::Open(GMPRecordImpl* aRecord) -{ - if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { - NS_WARNING("GMP used GMPStorage on non-main thread."); - return GMPGenericErr; - } - if (mShutdown) { - NS_WARNING("GMPStorage used after it's been shutdown!"); - return GMPClosedErr; - } - if (!SendOpen(aRecord->Name())) { - Close(aRecord); - return GMPClosedErr; - } - return GMPNoErr; -} - -GMPErr -GMPStorageChild::Read(GMPRecordImpl* aRecord) -{ - if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { - NS_WARNING("GMP used GMPStorage on non-main thread."); - return GMPGenericErr; - } - if (mShutdown) { - NS_WARNING("GMPStorage used after it's been shutdown!"); - return GMPClosedErr; - } - if (!SendRead(aRecord->Name())) { - Close(aRecord); - return GMPClosedErr; - } - return GMPNoErr; -} - -GMPErr -GMPStorageChild::Write(GMPRecordImpl* aRecord, - const uint8_t* aData, - uint32_t aDataSize) -{ - if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { - NS_WARNING("GMP used GMPStorage on non-main thread."); - return GMPGenericErr; - } - if (mShutdown) { - NS_WARNING("GMPStorage used after it's been shutdown!"); - return GMPClosedErr; - } - if (aDataSize > GMP_MAX_RECORD_SIZE) { - return GMPQuotaExceededErr; - } - nsTArray data; - data.AppendElements(aData, aDataSize); - if (!SendWrite(aRecord->Name(), data)) { - Close(aRecord); - return GMPClosedErr; - } - return GMPNoErr; -} - -GMPErr -GMPStorageChild::Close(GMPRecordImpl* aRecord) -{ - if (mPlugin->GMPMessageLoop() != MessageLoop::current()) { - NS_WARNING("GMP used GMPStorage on non-main thread."); - return GMPGenericErr; - } - if (!mRecords.Contains(aRecord->Name())) { - // Already closed. - return GMPClosedErr; - } - - GMPErr rv = GMPNoErr; - if (!mShutdown && !SendClose(aRecord->Name())) { - rv = GMPGenericErr; - } - - aRecord->MarkClosed(); - mRecords.Remove(aRecord->Name()); - - return rv; -} - -bool -GMPStorageChild::RecvOpenComplete(const nsCString& aRecordName, - const GMPErr& aStatus) -{ - if (mShutdown) { - return true; - } - nsRefPtr record; - if (!mRecords.Get(aRecordName, getter_AddRefs(record)) || !record) { - // Not fatal. - return true; - } - record->OpenComplete(aStatus); - if (GMP_FAILED(aStatus)) { - Close(record); - } - return true; -} - -bool -GMPStorageChild::RecvReadComplete(const nsCString& aRecordName, - const GMPErr& aStatus, - const InfallibleTArray& aBytes) -{ - if (mShutdown) { - return true; - } - nsRefPtr record; - if (!mRecords.Get(aRecordName, getter_AddRefs(record)) || !record) { - // Not fatal. - return true; - } - record->ReadComplete(aStatus, - aBytes.Elements(), - aBytes.Length()); - if (GMP_FAILED(aStatus)) { - Close(record); - } - return true; -} - -bool -GMPStorageChild::RecvWriteComplete(const nsCString& aRecordName, - const GMPErr& aStatus) -{ - if (mShutdown) { - return true; - } - nsRefPtr record; - if (!mRecords.Get(aRecordName, getter_AddRefs(record)) || !record) { - // Not fatal. - return true; - } - record->WriteComplete(aStatus); - if (GMP_FAILED(aStatus)) { - Close(record); - } - return true; -} - -bool -GMPStorageChild::RecvShutdown() -{ - // Block any new storage requests, and thus any messages back to the - // parent. We don't delete any objects here, as that may invalidate - // GMPRecord pointers held by the GMP. - mShutdown = true; - return true; -} - -} // namespace gmp -} // namespace mozilla diff --git a/content/media/gmp/GMPStorageChild.h b/content/media/gmp/GMPStorageChild.h deleted file mode 100644 index e4248ee1f30..00000000000 --- a/content/media/gmp/GMPStorageChild.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; 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 GMPStorageChild_h_ -#define GMPStorageChild_h_ - -#include "mozilla/gmp/PGMPStorageChild.h" -#include "gmp-storage.h" -#include "nsTHashtable.h" -#include "nsRefPtrHashtable.h" - -namespace mozilla { -namespace gmp { - -class GMPChild; -class GMPStorageChild; - -class GMPRecordImpl : public GMPRecord -{ -public: - NS_INLINE_DECL_REFCOUNTING(GMPRecordImpl) - - GMPRecordImpl(GMPStorageChild* aOwner, - const nsCString& aName, - GMPRecordClient* aClient); - - // GMPRecord. - virtual GMPErr Open() MOZ_OVERRIDE; - virtual GMPErr Read() MOZ_OVERRIDE; - virtual GMPErr Write(const uint8_t* aData, - uint32_t aDataSize) MOZ_OVERRIDE; - virtual GMPErr Close() MOZ_OVERRIDE; - - const nsCString& Name() const { return mName; } - - void OpenComplete(GMPErr aStatus); - void ReadComplete(GMPErr aStatus, const uint8_t* aBytes, uint32_t aLength); - void WriteComplete(GMPErr aStatus); - - void MarkClosed(); - -private: - ~GMPRecordImpl() {} - const nsCString mName; - GMPRecordClient* const mClient; - GMPStorageChild* const mOwner; - bool mIsClosed; -}; - -class GMPStorageChild : public PGMPStorageChild -{ -public: - NS_INLINE_DECL_REFCOUNTING(GMPStorageChild) - - GMPStorageChild(GMPChild* aPlugin); - - GMPErr CreateRecord(const nsCString& aRecordName, - GMPRecord** aOutRecord, - GMPRecordClient* aClient); - - GMPErr Open(GMPRecordImpl* aRecord); - - GMPErr Read(GMPRecordImpl* aRecord); - - GMPErr Write(GMPRecordImpl* aRecord, - const uint8_t* aData, - uint32_t aDataSize); - - GMPErr Close(GMPRecordImpl* aRecord); - -protected: - ~GMPStorageChild() {} - - // PGMPStorageChild - virtual bool RecvOpenComplete(const nsCString& aRecordName, - const GMPErr& aStatus) MOZ_OVERRIDE; - virtual bool RecvReadComplete(const nsCString& aRecordName, - const GMPErr& aStatus, - const InfallibleTArray& aBytes) MOZ_OVERRIDE; - virtual bool RecvWriteComplete(const nsCString& aRecordName, - const GMPErr& aStatus) MOZ_OVERRIDE; - virtual bool RecvShutdown() MOZ_OVERRIDE; - -private: - nsRefPtrHashtable mRecords; - GMPChild* mPlugin; - bool mShutdown; -}; - -} // namespace gmp -} // namespace mozilla - -#endif // GMPStorageChild_h_ diff --git a/content/media/gmp/GMPStorageParent.cpp b/content/media/gmp/GMPStorageParent.cpp deleted file mode 100644 index 9ec343febaf..00000000000 --- a/content/media/gmp/GMPStorageParent.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; 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/. */ - -#include "GMPStorageParent.h" -#include "mozilla/SyncRunnable.h" -#include "plhash.h" -#include "nsDirectoryServiceUtils.h" -#include "nsDirectoryServiceDefs.h" -#include "GMPParent.h" -#include "gmp-storage.h" -#include "mozilla/unused.h" - -namespace mozilla { - -#ifdef LOG -#undef LOG -#endif - -#ifdef PR_LOGGING -extern PRLogModuleInfo* GetGMPLog(); - -#define LOGD(msg) PR_LOG(GetGMPLog(), PR_LOG_DEBUG, msg) -#define LOG(level, msg) PR_LOG(GetGMPLog(), (level), msg) -#else -#define LOGD(msg) -#define LOG(level, msg) -#endif - -#ifdef __CLASS__ -#undef __CLASS__ -#endif -#define __CLASS__ "GMPParent" - -namespace gmp { - -class GetTempDirTask : public nsRunnable -{ -public: - NS_IMETHOD Run() { - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr tmpFile; - nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - tmpFile->GetPath(mPath); - return NS_OK; - } - - nsString mPath; -}; - -// We store the records in files in the system temp dir. -static nsresult -GetGMPStorageDir(nsIFile** aTempDir, const nsString& aOrigin) -{ - if (NS_WARN_IF(!aTempDir)) { - return NS_ERROR_INVALID_ARG; - } - - // Directory service is main thread only... - nsRefPtr task = new GetTempDirTask(); - nsCOMPtr mainThread = do_GetMainThread(); - mozilla::SyncRunnable::DispatchToThread(mainThread, task); - - nsCOMPtr tmpFile; - nsresult rv = NS_NewLocalFile(task->mPath, false, getter_AddRefs(tmpFile)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->AppendNative(nsDependentCString("mozilla-gmp-storage")); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - // TODO: When aOrigin is the same node-id as the GMP sees in the child - // process (a UUID or somesuch), we can just append it un-hashed here. - // This should reduce the chance of hash collsions exposing data. - nsAutoString nodeIdHash; - nodeIdHash.AppendInt(HashString(aOrigin.get())); - rv = tmpFile->Append(nodeIdHash); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); - if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - tmpFile.forget(aTempDir); - - return NS_OK; -} - -GMPStorageParent::GMPStorageParent(const nsString& aOrigin, - GMPParent* aPlugin) - : mOrigin(aOrigin) - , mPlugin(aPlugin) - , mShutdown(false) -{ -} - -enum OpenFileMode { ReadWrite, Truncate }; - -nsresult -OpenStorageFile(const nsCString& aRecordName, - const nsString& aNodeId, - const OpenFileMode aMode, - PRFileDesc** aOutFD) -{ - MOZ_ASSERT(aOutFD); - - nsCOMPtr f; - nsresult rv = GetGMPStorageDir(getter_AddRefs(f), aNodeId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - nsAutoString recordNameHash; - recordNameHash.AppendInt(HashString(aRecordName.get())); - f->Append(recordNameHash); - - auto mode = PR_RDWR | PR_CREATE_FILE; - if (aMode == Truncate) { - mode |= PR_TRUNCATE; - } - - return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD); -} - -bool -GMPStorageParent::RecvOpen(const nsCString& aRecordName) -{ - if (mShutdown) { - return true; - } - - if (mOrigin.EqualsASCII("null")) { - // Refuse to open storage if the page is the "null" origin; if the page - // is opened from disk. - NS_WARNING("Refusing to open storage for null origin"); - unused << SendOpenComplete(aRecordName, GMPGenericErr); - return true; - } - - if (aRecordName.IsEmpty() || mFiles.Contains(aRecordName)) { - unused << SendOpenComplete(aRecordName, GMPRecordInUse); - return true; - } - - PRFileDesc* fd = nullptr; - nsresult rv = OpenStorageFile(aRecordName, mOrigin, ReadWrite, &fd); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to open storage file."); - unused << SendOpenComplete(aRecordName, GMPGenericErr); - return true; - } - - mFiles.Put(aRecordName, fd); - unused << SendOpenComplete(aRecordName, GMPNoErr); - - return true; -} - -bool -GMPStorageParent::RecvRead(const nsCString& aRecordName) -{ - LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get())); - - if (mShutdown) { - return true; - } - - PRFileDesc* fd = mFiles.Get(aRecordName); - nsTArray data; - if (!fd) { - unused << SendReadComplete(aRecordName, GMPClosedErr, data); - return true; - } - - int32_t len = PR_Seek(fd, 0, PR_SEEK_END); - PR_Seek(fd, 0, PR_SEEK_SET); - - if (len > GMP_MAX_RECORD_SIZE) { - // Refuse to read big records. - unused << SendReadComplete(aRecordName, GMPQuotaExceededErr, data); - return true; - } - data.SetLength(len); - auto bytesRead = PR_Read(fd, data.Elements(), len); - auto res = (bytesRead == len) ? GMPNoErr : GMPGenericErr; - unused << SendReadComplete(aRecordName, res, data); - - return true; -} - -bool -GMPStorageParent::RecvWrite(const nsCString& aRecordName, - const InfallibleTArray& aBytes) -{ - LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get())); - - if (mShutdown) { - return true; - } - if (aBytes.Length() > GMP_MAX_RECORD_SIZE) { - unused << SendWriteComplete(aRecordName, GMPQuotaExceededErr); - return true; - } - - PRFileDesc* fd = mFiles.Get(aRecordName); - if (!fd) { - unused << SendWriteComplete(aRecordName, GMPGenericErr); - return true; - } - - // Write operations overwrite the entire record. So re-open the file - // in truncate mode, to clear its contents. - PR_Close(fd); - mFiles.Remove(aRecordName); - if (NS_FAILED(OpenStorageFile(aRecordName, mOrigin, Truncate, &fd))) { - unused << SendWriteComplete(aRecordName, GMPGenericErr); - return true; - } - mFiles.Put(aRecordName, fd); - - int32_t bytesWritten = PR_Write(fd, aBytes.Elements(), aBytes.Length()); - auto res = (bytesWritten == (int32_t)aBytes.Length()) ? GMPNoErr : GMPGenericErr; - unused << SendWriteComplete(aRecordName, res); - return true; -} - -bool -GMPStorageParent::RecvClose(const nsCString& aRecordName) -{ - LOGD(("%s::%s: %p record=%s", __CLASS__, __FUNCTION__, this, aRecordName.get())); - - if (mShutdown) { - return true; - } - - PRFileDesc* fd = mFiles.Get(aRecordName); - if (!fd) { - return true; - } - PR_Close(fd); - mFiles.Remove(aRecordName); - return true; -} - -void -GMPStorageParent::ActorDestroy(ActorDestroyReason aWhy) -{ - LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this)); - Shutdown(); -} - -PLDHashOperator -CloseFile(const nsACString& key, PRFileDesc*& entry, void* cx) -{ - PR_Close(entry); - return PL_DHASH_REMOVE; -} - -void -GMPStorageParent::Shutdown() -{ - LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this)); - - if (mShutdown) { - return; - } - mShutdown = true; - unused << SendShutdown(); - - mFiles.Enumerate(CloseFile, nullptr); - MOZ_ASSERT(!mFiles.Count()); -} - -} // namespace gmp -} // namespace mozilla diff --git a/content/media/gmp/GMPStorageParent.h b/content/media/gmp/GMPStorageParent.h deleted file mode 100644 index 57583d0ead9..00000000000 --- a/content/media/gmp/GMPStorageParent.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; 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 GMPStorageParent_h_ -#define GMPStorageParent_h_ - -#include "mozilla/gmp/PGMPStorageParent.h" -#include "gmp-storage.h" -#include "nsTHashtable.h" -#include "nsDataHashtable.h" -#include "prio.h" - -namespace mozilla { -namespace gmp { - -class GMPParent; - -class GMPStorageParent : public PGMPStorageParent { -public: - NS_INLINE_DECL_REFCOUNTING(GMPStorageParent) - GMPStorageParent(const nsString& aOrigin, GMPParent* aPlugin); - - void Shutdown(); - -protected: - virtual bool RecvOpen(const nsCString& aRecordName) MOZ_OVERRIDE; - virtual bool RecvRead(const nsCString& aRecordName) MOZ_OVERRIDE; - virtual bool RecvWrite(const nsCString& aRecordName, - const InfallibleTArray& aBytes) MOZ_OVERRIDE; - virtual bool RecvClose(const nsCString& aRecordName) MOZ_OVERRIDE; - virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE; - -private: - nsDataHashtable mFiles; - const nsString mOrigin; - nsRefPtr mPlugin; - bool mShutdown; -}; - -} // namespace gmp -} // namespace mozilla - -#endif // GMPStorageParent_h_ diff --git a/content/media/gmp/PGMP.ipdl b/content/media/gmp/PGMP.ipdl index be50bc9704f..9daa4784a34 100644 --- a/content/media/gmp/PGMP.ipdl +++ b/content/media/gmp/PGMP.ipdl @@ -9,7 +9,6 @@ include protocol PCrashReporter; include protocol PGMPDecryptor; include protocol PGMPAudioDecoder; include protocol PGMPTimer; -include protocol PGMPStorage; using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h"; @@ -24,12 +23,10 @@ intr protocol PGMP manages PGMPVideoEncoder; manages PCrashReporter; manages PGMPTimer; - manages PGMPStorage; parent: async PCrashReporter(NativeThreadId tid); async PGMPTimer(); - async PGMPStorage(); async AsyncShutdownComplete(); async AsyncShutdownRequired(); diff --git a/content/media/gmp/PGMPStorage.ipdl b/content/media/gmp/PGMPStorage.ipdl deleted file mode 100644 index c67a8bea2dc..00000000000 --- a/content/media/gmp/PGMPStorage.ipdl +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; 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/. */ - -include protocol PGMP; -include GMPTypes; - -using GMPErr from "gmp-errors.h"; - -namespace mozilla { -namespace gmp { - -async protocol PGMPStorage -{ - manager PGMP; - -child: - OpenComplete(nsCString aRecordName, GMPErr aStatus); - ReadComplete(nsCString aRecordName, GMPErr aStatus, uint8_t[] aBytes); - WriteComplete(nsCString aRecordName, GMPErr aStatus); - Shutdown(); - -parent: - Open(nsCString aRecordName); - Read(nsCString aRecordName); - Write(nsCString aRecordName, uint8_t[] aBytes); - Close(nsCString aRecordName); - __delete__(); - -}; - -} // namespace gmp -} // namespace mozilla diff --git a/content/media/gmp/gmp-api/gmp-platform.h b/content/media/gmp/gmp-api/gmp-platform.h index 48b21f5702c..feffe0133da 100644 --- a/content/media/gmp/gmp-api/gmp-platform.h +++ b/content/media/gmp/gmp-api/gmp-platform.h @@ -69,8 +69,6 @@ typedef GMPErr (*GMPCreateThreadPtr)(GMPThread** aThread); typedef GMPErr (*GMPRunOnMainThreadPtr)(GMPTask* aTask); typedef GMPErr (*GMPSyncRunOnMainThreadPtr)(GMPTask* aTask); typedef GMPErr (*GMPCreateMutexPtr)(GMPMutex** aMutex); - -// Call on main thread only. typedef GMPErr (*GMPCreateRecordPtr)(const char* aRecordName, uint32_t aRecordNameSize, GMPRecord** aOutRecord, diff --git a/content/media/gmp/gmp-api/gmp-storage.h b/content/media/gmp/gmp-api/gmp-storage.h index 59f8175f52f..6ca8872cab9 100644 --- a/content/media/gmp/gmp-api/gmp-storage.h +++ b/content/media/gmp/gmp-api/gmp-storage.h @@ -20,31 +20,16 @@ #include "gmp-errors.h" #include -// Maximum size of a record, in bytes. -#define GMP_MAX_RECORD_SIZE (1024 * 1024 * 1024) - -// Maximum length of a record name. -#define GMP_MAX_RECORD_NAME_SIZE 200 - // Provides basic per-origin storage for CDMs. GMPRecord instances can be // retrieved by calling GMPPlatformAPI->openstorage. Multiple GMPRecords // with different names can be open at once, but a single record can only // be opened by one client at a time. This interface is asynchronous, with // results being returned via callbacks to the GMPRecordClient pointer // provided to the GMPPlatformAPI->openstorage call, on the main thread. -// -// Lifecycle: Once opened, the GMPRecord object remains allocated until -// GMPRecord::Close() is called. If any GMPRecord function, either -// synchronously or asynchronously through a GMPRecordClient callback, -// returns an error, the GMP is responsible for calling Close() on the -// GMPRecord to delete the GMPRecord object's memory. If your GMP does not -// call Close(), the GMPRecord's memory will leak. class GMPRecord { public: // Opens the record. Calls OpenComplete() once the record is open. - // Note: Only work when GMP is loading content from a webserver. - // Does not work for web pages on loaded from disk. // Note: OpenComplete() is only called if this returns GMPNoErr. virtual GMPErr Open() = 0; @@ -54,15 +39,13 @@ public: virtual GMPErr Read() = 0; // Writes aDataSize bytes of aData into the record, overwriting the - // contents of the record, truncating it to aDataSize length. - // Overwriting with 0 bytes "deletes" the record. + // contents of the record. Overwriting with 0 bytes "deletes" the file. // Note: WriteComplete is only called if this returns GMPNoErr. virtual GMPErr Write(const uint8_t* aData, uint32_t aDataSize) = 0; - // Closes a record, deletes the GMPRecord object. The GMPRecord object - // must not be used after this is called, request a new one with - // GMPPlatformAPI->openstorage to re-open this record. Cancels all - // callbacks. + // Closes a record. GMPRecord object must not be used after this is + // called, request a new one with GMPPlatformAPI->openstorage to re-open + // this record. Cancels all callbacks. virtual GMPErr Close() = 0; virtual ~GMPRecord() {} @@ -78,8 +61,7 @@ class GMPRecordClient { // - GMPNoErr - Record opened successfully. Record may be empty. // - GMPRecordInUse - This record is in use by another client. // - GMPGenericErr - Unspecified error. - // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must - // call Close() on the GMPRecord to dispose of it. + // Do not use the GMPRecord if aStatus is not GMPNoErr. virtual void OpenComplete(GMPErr aStatus) = 0; // Response to a GMPRecord::Read() call, where aData is the record contents, @@ -92,8 +74,7 @@ class GMPRecordClient { // - GMPRecordInUse - There are other operations or clients in use on // this record. // - GMPGenericErr - Unspecified error. - // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must - // call Close() on the GMPRecord to dispose of it. + // Do not continue to use the GMPRecord if aStatus is not GMPNoErr. virtual void ReadComplete(GMPErr aStatus, const uint8_t* aData, uint32_t aDataSize) = 0; @@ -103,8 +84,7 @@ class GMPRecordClient { // - GMPRecordInUse - There are other operations or clients in use on // this record. // - GMPGenericErr - Unspecified error. - // If aStatus is not GMPNoErr, the GMPRecord is unusable, and you must - // call Close() on the GMPRecord to dispose of it. + // Do not continue to use the GMPRecord if aStatus is not GMPNoErr. virtual void WriteComplete(GMPErr aStatus) = 0; virtual ~GMPRecordClient() {} diff --git a/content/media/gmp/moz.build b/content/media/gmp/moz.build index cd302051886..2bf2083d1ee 100644 --- a/content/media/gmp/moz.build +++ b/content/media/gmp/moz.build @@ -46,8 +46,6 @@ EXPORTS += [ 'GMPProcessParent.h', 'GMPService.h', 'GMPSharedMemManager.h', - 'GMPStorageChild.h', - 'GMPStorageParent.h', 'GMPTimerChild.h', 'GMPTimerParent.h', 'GMPVideoDecoderChild.h', @@ -76,8 +74,6 @@ UNIFIED_SOURCES += [ 'GMPProcessParent.cpp', 'GMPService.cpp', 'GMPSharedMemManager.cpp', - 'GMPStorageChild.cpp', - 'GMPStorageParent.cpp', 'GMPTimerChild.cpp', 'GMPTimerParent.cpp', 'GMPVideoDecoderChild.cpp', @@ -95,7 +91,6 @@ IPDL_SOURCES += [ 'PGMP.ipdl', 'PGMPAudioDecoder.ipdl', 'PGMPDecryptor.ipdl', - 'PGMPStorage.ipdl', 'PGMPTimer.ipdl', 'PGMPVideoDecoder.ipdl', 'PGMPVideoEncoder.ipdl', From 9396350e7958ddd415914cd0df668b147258be96 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Tue, 19 Aug 2014 08:19:28 +0200 Subject: [PATCH 86/86] Bug 1055060 - Non-array delete for scalars - CID 1122166 & 1122167 r=jesup --- .../webrtc/signaling/src/peerconnection/PeerConnectionImpl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index 26edb09b572..5c61066f312 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -432,7 +432,7 @@ public: char *tmp; GetLocalDescription(&tmp); aSDP.AssignASCII(tmp); - delete tmp; + delete[] tmp; } NS_IMETHODIMP GetRemoteDescription(char** aSDP); @@ -442,7 +442,7 @@ public: char *tmp; GetRemoteDescription(&tmp); aSDP.AssignASCII(tmp); - delete tmp; + delete[] tmp; } NS_IMETHODIMP SignalingState(mozilla::dom::PCImplSignalingState* aState);