From 5184cb9b304e4d3d5a3d18b09d66835a85b63149 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 15 Sep 2014 11:40:48 -0700 Subject: [PATCH 01/32] Bug 1066733: Fix JS Debugger test to add debuggees as intended. f=tromey r=sfink --- js/src/jit-test/tests/debug/Debugger-debuggees-20.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/src/jit-test/tests/debug/Debugger-debuggees-20.js b/js/src/jit-test/tests/debug/Debugger-debuggees-20.js index 16319f8a2ca9..121698ab4080 100644 --- a/js/src/jit-test/tests/debug/Debugger-debuggees-20.js +++ b/js/src/jit-test/tests/debug/Debugger-debuggees-20.js @@ -9,14 +9,17 @@ var g3 = newGlobal(); // Created after the Debugger; debuggee. var g4 = newGlobal(); // Created after the Debugger; not debuggee. var g1w = dbg.addDebuggee(g1); +var g3w = dbg.addDebuggee(g3); assertEq(dbg.addAllGlobalsAsDebuggees(), undefined); // Get Debugger.Objects viewing the globals from their own compartments; // this is the sort that findAllGlobals and addDebuggee return. -var g1w = g1w.makeDebuggeeValue(g1).unwrap(); +assertEq(g1w, g3w.makeDebuggeeValue(g1).unwrap()); +assertEq(g3w, g1w.makeDebuggeeValue(g3).unwrap()); + var g2w = g1w.makeDebuggeeValue(g2).unwrap(); -var g3w = g1w.makeDebuggeeValue(g3).unwrap(); var g4w = g1w.makeDebuggeeValue(g4).unwrap(); + var thisw = g1w.makeDebuggeeValue(this).unwrap(); // Check that they're all there. From 4993106c02cb8362272776334f024d938846f601 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 15 Sep 2014 11:54:02 -0700 Subject: [PATCH 02/32] Bug 1058083 - IonMonkey: Re-enable the integer-divide-by-constant optimization when the register allocator is not LSRA r=jandem --- js/src/jit/shared/Lowering-x86-shared.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/js/src/jit/shared/Lowering-x86-shared.cpp b/js/src/jit/shared/Lowering-x86-shared.cpp index ada867b25a65..1c5465cca9a9 100644 --- a/js/src/jit/shared/Lowering-x86-shared.cpp +++ b/js/src/jit/shared/Lowering-x86-shared.cpp @@ -155,6 +155,14 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *div) if (div->fallible() && !assignSnapshot(lir, Bailout_DoubleOutput)) return false; return defineReuseInput(lir, div, 0); + } else if (rhs != 0 && + gen->optimizationInfo().registerAllocator() != RegisterAllocator_LSRA) + { + LDivOrModConstantI *lir; + lir = new(alloc()) LDivOrModConstantI(useRegister(div->lhs()), rhs, tempFixed(eax)); + if (div->fallible() && !assignSnapshot(lir, Bailout_DoubleOutput)) + return false; + return defineFixed(lir, div, LAllocation(AnyRegister(edx))); } } @@ -179,6 +187,14 @@ LIRGeneratorX86Shared::lowerModI(MMod *mod) if (mod->fallible() && !assignSnapshot(lir, Bailout_DoubleOutput)) return false; return defineReuseInput(lir, mod, 0); + } else if (rhs != 0 && + gen->optimizationInfo().registerAllocator() != RegisterAllocator_LSRA) + { + LDivOrModConstantI *lir; + lir = new(alloc()) LDivOrModConstantI(useRegister(mod->lhs()), rhs, tempFixed(edx)); + if (mod->fallible() && !assignSnapshot(lir, Bailout_DoubleOutput)) + return false; + return defineFixed(lir, mod, LAllocation(AnyRegister(eax))); } } From 4113b4b4661deb2ca353b2140d581c6752c52b91 Mon Sep 17 00:00:00 2001 From: David Keeler Date: Mon, 15 Sep 2014 12:31:43 -0700 Subject: [PATCH 03/32] bug 973048 - replace nsNSSCleaner with Scoped types r=rbarnes --- security/manager/ssl/src/moz.build | 1 - security/manager/ssl/src/nsNSSCertificate.cpp | 18 ++- security/manager/ssl/src/nsNSSCleaner.cpp | 25 ----- security/manager/ssl/src/nsNSSCleaner.h | 105 ------------------ security/manager/ssl/src/nsNSSIOLayer.cpp | 12 +- 5 files changed, 11 insertions(+), 150 deletions(-) delete mode 100644 security/manager/ssl/src/nsNSSCleaner.cpp delete mode 100644 security/manager/ssl/src/nsNSSCleaner.h diff --git a/security/manager/ssl/src/moz.build b/security/manager/ssl/src/moz.build index 25968ece080c..eebafbe3d37b 100644 --- a/security/manager/ssl/src/moz.build +++ b/security/manager/ssl/src/moz.build @@ -36,7 +36,6 @@ UNIFIED_SOURCES += [ 'nsNSSCertificateFakeTransport.cpp', 'nsNSSCertTrust.cpp', 'nsNSSCertValidity.cpp', - 'nsNSSCleaner.cpp', 'nsNSSErrors.cpp', 'nsNSSIOLayer.cpp', 'nsNSSModule.cpp', diff --git a/security/manager/ssl/src/nsNSSCertificate.cpp b/security/manager/ssl/src/nsNSSCertificate.cpp index 34321fbb046a..a0f01e7a94d1 100644 --- a/security/manager/ssl/src/nsNSSCertificate.cpp +++ b/security/manager/ssl/src/nsNSSCertificate.cpp @@ -14,7 +14,6 @@ #include "pkix/pkixtypes.h" #include "pkix/ScopedPtr.h" #include "nsNSSComponent.h" // for PIPNSS string bundle calls. -#include "nsNSSCleaner.h" #include "nsCOMPtr.h" #include "nsIMutableArray.h" #include "nsNSSCertValidity.h" @@ -59,8 +58,6 @@ using namespace mozilla::psm; extern PRLogModuleInfo* gPIPNSSLog; #endif -NSSCleanupAutoPtrClass_WithParam(PLArenaPool, PORT_FreeArena, FalseParam, false) - // This is being stored in an uint32_t that can otherwise // only take values from nsIX509Cert's list of cert types. // As nsIX509Cert is frozen, we choose a value not contained @@ -1155,14 +1152,6 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode, return NS_ERROR_INVALID_ARG; }; - PLArenaPool* arena = PORT_NewArena(1024); - PLArenaPoolCleanerFalseParam arenaCleaner(arena); - if (!arena) { - PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, - ("nsNSSCertificate::ExportAsCMS - out of memory\n")); - return NS_ERROR_OUT_OF_MEMORY; - } - ScopedNSSCMSMessage cmsg(NSS_CMSMessage_Create(nullptr)); if (!cmsg) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, @@ -1231,6 +1220,13 @@ nsNSSCertificate::ExportAsCMS(uint32_t chainMode, return NS_ERROR_FAILURE; } + ScopedPLArenaPool arena(PORT_NewArena(1024)); + if (!arena) { + PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, + ("nsNSSCertificate::ExportAsCMS - out of memory\n")); + return NS_ERROR_OUT_OF_MEMORY; + } + SECItem certP7 = { siBuffer, nullptr, 0 }; NSSCMSEncoderContext* ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr, &certP7, arena, nullptr, diff --git a/security/manager/ssl/src/nsNSSCleaner.cpp b/security/manager/ssl/src/nsNSSCleaner.cpp deleted file mode 100644 index 60cbffa1d5ac..000000000000 --- a/security/manager/ssl/src/nsNSSCleaner.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* 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 "nsNSSCleaner.h" -#include "cert.h" - -CERTVerifyLogContentsCleaner::CERTVerifyLogContentsCleaner(CERTVerifyLog *&cvl) -:m_cvl(cvl) -{ -} - -CERTVerifyLogContentsCleaner::~CERTVerifyLogContentsCleaner() -{ - if (!m_cvl) - return; - - CERTVerifyLogNode *i_node; - for (i_node = m_cvl->head; i_node; i_node = i_node->next) - { - if (i_node->cert) - CERT_DestroyCertificate(i_node->cert); - } -} - diff --git a/security/manager/ssl/src/nsNSSCleaner.h b/security/manager/ssl/src/nsNSSCleaner.h deleted file mode 100644 index 0b395d8cd09a..000000000000 --- a/security/manager/ssl/src/nsNSSCleaner.h +++ /dev/null @@ -1,105 +0,0 @@ -/* 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 _INC_NSSCleaner_H -#define _INC_NSSCleaner_H - -/* - NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate) - - will produce: - - class CERTCertificateCleaner - { - private: - CERTCertificateCleaner(const CERTCertificateCleaner&); - CERTCertificateCleaner(); - void operator=(const CERTCertificateCleaner&); - CERTCertificate *&object; - public: - CERTCertificateCleaner(CERTCertificate *&a_object) - :object(a_object) {} - ~CERTCertificateCleaner() { - if (object) { - CERT_DestroyCertificate(object); - object = nullptr; - } - } - }; - - By making default and copy constructor, and assignment operator - private, we will make sure nobody will be able to use it. - Not defining bodies for them is an additional safeguard. - - This class is not designed to allow being passed around. - It's just for automatic cleanup of a local variable. - - - By storing a reference to the underlying pointer, - we will zero out the given pointer variable, - making sure it will not be used after it has been freed. - - Even better, in case the underlying pointer variable gets - assigned another value, this will be recognized, and - the latest value stored in the pointer will be freed. - - - In order to not require everybody to have all the NSS - includes in their implementation files, - we don't declare the classes here. - -*/ - -#define NSSCleanupAutoPtrClass(nsstype, cleanfunc) \ -class nsstype##Cleaner \ -{ \ -private: \ - nsstype##Cleaner(const nsstype##Cleaner&); \ - nsstype##Cleaner(); \ - void operator=(const nsstype##Cleaner&); \ - nsstype *&object; \ -public: \ - explicit nsstype##Cleaner(nsstype *&a_object) \ - :object(a_object) {} \ - ~nsstype##Cleaner() { \ - if (object) { \ - cleanfunc(object); \ - object = nullptr; \ - } \ - } \ - void detach() {object=nullptr;} \ -}; - -#define NSSCleanupAutoPtrClass_WithParam(nsstype, cleanfunc, namesuffix, paramvalue) \ -class nsstype##Cleaner##namesuffix \ -{ \ -private: \ - nsstype##Cleaner##namesuffix(const nsstype##Cleaner##namesuffix &); \ - nsstype##Cleaner##namesuffix(); \ - void operator=(const nsstype##Cleaner##namesuffix &); \ - nsstype *&object; \ -public: \ - explicit nsstype##Cleaner##namesuffix(nsstype *&a_object) \ - :object(a_object) {} \ - ~nsstype##Cleaner##namesuffix() { \ - if (object) { \ - cleanfunc(object, paramvalue); \ - object = nullptr; \ - } \ - } \ - void detach() {object=nullptr;} \ -}; - -#include "certt.h" - -class CERTVerifyLogContentsCleaner -{ -public: - explicit CERTVerifyLogContentsCleaner(CERTVerifyLog *&cvl); - ~CERTVerifyLogContentsCleaner(); -private: - CERTVerifyLog *&m_cvl; -}; - -#endif diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index 5d73577f5470..b8f733099ad2 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -24,7 +24,6 @@ #include "nsPrintfCString.h" #include "SSLServerCertVerification.h" #include "nsNSSCertHelper.h" -#include "nsNSSCleaner.h" #ifndef MOZ_NO_EV_CERTS #include "nsIDocShell.h" @@ -66,8 +65,6 @@ using namespace mozilla::psm; namespace { -NSSCleanupAutoPtrClass(void, PR_FREEIF) - void getSiteKey(const nsACString& hostName, uint16_t port, /*out*/ nsCSubstring& key) @@ -2164,16 +2161,15 @@ ClientAuthDataRunnable::RunOnTargetThread() NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts"); // Get CN and O of the subject and O of the issuer - char* ccn = CERT_GetCommonName(&mServerCert->subject); - void* v = ccn; - voidCleaner ccnCleaner(v); - NS_ConvertUTF8toUTF16 cn(ccn); + mozilla::pkix::ScopedPtr ccn( + CERT_GetCommonName(&mServerCert->subject)); + NS_ConvertUTF8toUTF16 cn(ccn.get()); int32_t port; mSocketInfo->GetPort(&port); nsString cn_host_port; - if (ccn && strcmp(ccn, hostname) == 0) { + if (ccn && strcmp(ccn.get(), hostname) == 0) { cn_host_port.Append(cn); cn_host_port.Append(':'); cn_host_port.AppendInt(port); From 1a71ceec1468e1bf4cb9388b99edae82a0aada0d Mon Sep 17 00:00:00 2001 From: Steven Michaud Date: Mon, 15 Sep 2014 14:48:42 -0500 Subject: [PATCH 04/32] Bug 1056251 - Changing to a Firefox window in a different workspace does not focus automatically. r=masayuki --- widget/cocoa/nsChildView.mm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 48cedd08436b..1bd8777a3c44 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -5686,6 +5686,18 @@ static int32_t RoundUp(double aDouble) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK; + // Weird things can happen on keyboard input if the key window isn't in the + // current space. For example see bug 1056251. To get around this, always + // make sure that, if our window is key, it's also made frontmost. Doing + // this automatically switches to whatever space our window is in. Safari + // does something similar. Our window should normally always be key -- + // otherwise why is the OS sending us a key down event? But it's just + // possible we're in Gecko's hidden window, so we check first. + NSWindow *viewWindow = [self window]; + if (viewWindow && [viewWindow isKeyWindow]) { + [viewWindow orderWindow:NSWindowAbove relativeTo:0]; + } + #if !defined(RELEASE_BUILD) || defined(DEBUG) if (mGeckoChild && mTextInputHandler && mTextInputHandler->IsFocused()) { #ifdef MOZ_CRASHREPORTER From c6dc096f07ddaca26f2ffe765edac646687fc641 Mon Sep 17 00:00:00 2001 From: David Keeler Date: Mon, 15 Sep 2014 13:02:47 -0700 Subject: [PATCH 05/32] bug 973048 - follow-up to add #include for ScopedPtr r=bustage on a CLOSED TREE --- security/manager/ssl/src/nsNSSIOLayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index b8f733099ad2..a13eab63a0f8 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -6,6 +6,7 @@ #include "nsNSSIOLayer.h" +#include "pkix/ScopedPtr.h" #include "pkix/pkixtypes.h" #include "nsNSSComponent.h" #include "mozilla/Casting.h" From dce41c469b040a12f8e623dbb48619618690b4ae Mon Sep 17 00:00:00 2001 From: David Keeler Date: Mon, 15 Sep 2014 13:50:18 -0700 Subject: [PATCH 06/32] bug 973048 - follow-up to add another missed #include r=bustage on a CLOSED TREE --- security/manager/ssl/src/nsNSSIOLayer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/security/manager/ssl/src/nsNSSIOLayer.cpp b/security/manager/ssl/src/nsNSSIOLayer.cpp index a13eab63a0f8..5e628bde718d 100644 --- a/security/manager/ssl/src/nsNSSIOLayer.cpp +++ b/security/manager/ssl/src/nsNSSIOLayer.cpp @@ -40,6 +40,7 @@ #include "SharedSSLState.h" #include "mozilla/Preferences.h" #include "nsContentUtils.h" +#include "NSSCertDBTrustDomain.h" #include "NSSErrorsService.h" #include "ssl.h" From 7b34db1b6702b6cb427b0793a1216febd16a6f40 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Thu, 11 Sep 2014 13:25:56 -0700 Subject: [PATCH 07/32] Bug 1065774 - Be more precise in PromiseFlatString docs about why assigning PromiseFlatString(...) to a reference is safe. r=froydnj --HG-- extra : rebase_source : aad06aa3b0a803abb678000f559b4a9d4736813c --- xpcom/string/nsTPromiseFlatString.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/xpcom/string/nsTPromiseFlatString.h b/xpcom/string/nsTPromiseFlatString.h index 763b2dfdf752..11b8d926a1d4 100644 --- a/xpcom/string/nsTPromiseFlatString.h +++ b/xpcom/string/nsTPromiseFlatString.h @@ -38,11 +38,17 @@ * The only way to make one is with the function |PromiseFlat[C]String|, * which produce a |const| instance. ``What if I need to keep a promise * around for a little while?'' you might ask. In that case, you can keep a - * reference, like so + * reference, like so: * * const nsCString& flat = PromiseFlatString(aCSubstring); - * // this reference holds the anonymous temporary alive, but remember, - * // it must _still_ have a lifetime shorter than that of |aCSubstring| + * // Temporaries usually die after the full expression containing the + * // expression that created the temporary is evaluated. But when a + * // temporary is assigned to a local reference, the temporary's lifetime + * // is extended to the reference's lifetime (C++11 [class.temporary]p5). + * // + * // This reference holds the anonymous temporary alive. But remember: it + * // must _still_ have a lifetime shorter than that of |aCSubstring|, and + * // |aCSubstring| must not be changed while the PromiseFlatString lives. * * SomeOSFunction(flat.get()); * SomeOtherOSFunction(flat.get()); From 054b1c458514710aad896aa82b15677235dff7a5 Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Tue, 9 Sep 2014 19:08:14 +0900 Subject: [PATCH 08/32] Bug 1041426 - Make error message for unexpected token more clear. r=jwalden --HG-- extra : rebase_source : 1785f67732a81aa29dd81c8be765cf497a9b74c8 --- .../test/browser_dbg_watch-expressions-02.js | 6 +- ...owser_scratchpad_display_outputs_errors.js | 4 +- dom/tests/mochitest/bugs/test_bug531176.html | 4 +- js/src/frontend/Parser.cpp | 79 ++++++++++++++----- js/src/frontend/TokenKind.h | 2 +- js/src/frontend/TokenStream.cpp | 18 +++++ js/src/frontend/TokenStream.h | 3 + .../basic/syntax-error-function-body-eof.js | 9 +++ .../tests/basic/syntax-error-primary.js | 69 ++++++++++++++++ .../tests/basic/syntax-error-throw.js | 39 +++++++++ .../tests/basic/syntax-error-toplevel-eof.js | 9 +++ js/src/js.msg | 5 +- .../tests/ecma_3/LexicalConventions/7.9.1.js | 4 +- js/src/tests/ecma_3/extensions/7.9.1.js | 2 +- js/src/vm/Xdr.h | 2 +- 15 files changed, 221 insertions(+), 34 deletions(-) create mode 100644 js/src/jit-test/tests/basic/syntax-error-function-body-eof.js create mode 100644 js/src/jit-test/tests/basic/syntax-error-primary.js create mode 100644 js/src/jit-test/tests/basic/syntax-error-throw.js create mode 100644 js/src/jit-test/tests/basic/syntax-error-toplevel-eof.js diff --git a/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js b/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js index 151fc83c6ef1..7c0a8be6378a 100644 --- a/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js +++ b/browser/devtools/debugger/test/browser_dbg_watch-expressions-02.js @@ -312,7 +312,7 @@ function test() { is(w2.value, "a", "The second value is correct."); is(w3.value, "a\"\"", "The third value is correct."); is(w4.value, "a''", "The fourth value is correct."); - is(w5.value, "SyntaxError: syntax error", "The fifth value is correct."); + is(w5.value, "SyntaxError: expected expression, got '?'", "The fifth value is correct."); if (typeof expected_a == "object") { is(w6.value.type, expected_a.type, "The sixth value type is correct."); @@ -361,8 +361,8 @@ function test() { is(w19.value.type, "undefined", "The 19th value type is correct."); is(w19.value.class, undefined, "The 19th value class is correct."); - is(w20.value, "SyntaxError: syntax error", "The 20th value is correct."); - is(w21.value, "SyntaxError: syntax error", "The 21th value is correct."); + is(w20.value, "SyntaxError: expected expression, got '.'", "The 20th value is correct."); + is(w21.value, "SyntaxError: expected expression, got '.'", "The 21th value is correct."); is(w22.value, "TypeError: (intermediate value).foo is not a function", "The 22th value is correct."); is(w23.value, "RangeError: invalid array length", "The 23th value is correct."); is(w24.value, "RangeError: precision -4 out of range", "The 24th value is correct."); diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js b/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js index 6a5b9cc0cd91..ea35d1435327 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_display_outputs_errors.js @@ -43,7 +43,7 @@ function runTests() { method: "display", code: syntaxError, - result: syntaxError + openComment + "Exception: syntax error\n@" + + result: syntaxError + openComment + "Exception: expected expression, got end of script\n@" + scratchpad.uniqueName + ":1" + closeComment, label: "syntaxError display output", }, @@ -63,7 +63,7 @@ function runTests() { method: "run", code: syntaxError, - result: syntaxError + openComment + "Exception: syntax error\n@" + + result: syntaxError + openComment + "Exception: expected expression, got end of script\n@" + scratchpad.uniqueName + ":1" + closeComment, label: "syntaxError run output", }]; diff --git a/dom/tests/mochitest/bugs/test_bug531176.html b/dom/tests/mochitest/bugs/test_bug531176.html index 4109afd4e76f..63ca296ac79c 100644 --- a/dom/tests/mochitest/bugs/test_bug531176.html +++ b/dom/tests/mochitest/bugs/test_bug531176.html @@ -21,7 +21,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=531176 var errorCount = 0; function errorHandler(msg, filename, linenr) { - is(msg, "SyntaxError: syntax error", "Wrong error!"); + is(msg, "SyntaxError: expected expression, got ';'", "Wrong error!"); is(filename, window.location, "Wrong filename!"); is(linenr, 1, "Wrong linenr!"); ++errorCount; @@ -34,7 +34,7 @@ document.body.onclick; is(errorCount, 1, "Error handler should have been called! (1)"); function recursiveHandler(msg, filename, linenr) { - is(msg, "SyntaxError: syntax error", "Wrong error!"); + is(msg, "SyntaxError: expected expression, got ';'", "Wrong error!"); is(filename, window.location, "Wrong filename!"); is(linenr, 1, "Wrong linenr!"); ++errorCount; diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 46bb0536c8cf..317283399f53 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -633,7 +633,8 @@ Parser::parse(JSObject *chain) Node pn = statements(); if (pn) { if (!tokenStream.matchToken(TOK_EOF)) { - report(ParseError, false, null(), JSMSG_SYNTAX_ERROR); + report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, + "script", TokenKindToDesc(tokenStream.peekToken())); return null(); } if (foldConstants) { @@ -751,7 +752,8 @@ Parser::standaloneFunctionBody(HandleFunction fun, const AutoN return null(); if (!tokenStream.matchToken(TOK_EOF)) { - report(ParseError, false, null(), JSMSG_SYNTAX_ERROR); + report(ParseError, false, null(), JSMSG_GARBAGE_AFTER_INPUT, + "function body", TokenKindToDesc(tokenStream.peekToken())); return null(); } @@ -5005,8 +5007,12 @@ Parser::throwStatement() TokenKind tt = tokenStream.peekTokenSameLine(TokenStream::Operand); if (tt == TOK_ERROR) return null(); - if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) { - report(ParseError, false, null(), JSMSG_SYNTAX_ERROR); + if (tt == TOK_EOF || tt == TOK_SEMI || tt == TOK_RC) { + report(ParseError, false, null(), JSMSG_MISSING_EXPR_AFTER_THROW); + return null(); + } + if (tt == TOK_EOL) { + report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_THROW); return null(); } @@ -7432,10 +7438,14 @@ Parser::primaryExpr(TokenKind tt) case TOK_NULL: return handler.newNullLiteral(pos()); - case TOK_RP: + case TOK_RP: { + TokenKind next = tokenStream.peekToken(); + if (next == TOK_ERROR) + return null(); + // Not valid expression syntax, but this is valid in an arrow function // with no params: `() => body`. - if (tokenStream.peekToken() == TOK_ARROW) { + if (next == TOK_ARROW) { tokenStream.ungetToken(); // put back right paren // Now just return something that will allow parsing to continue. @@ -7443,30 +7453,57 @@ Parser::primaryExpr(TokenKind tt) // reparse the whole arrow function. See Parser::assignExpr. return handler.newNullLiteral(pos()); } - report(ParseError, false, null(), JSMSG_SYNTAX_ERROR); - return null(); + goto unexpected_token; + } - case TOK_TRIPLEDOT: - // Not valid expression syntax, but this is valid in an arrow function - // with a rest param: `(a, b, ...rest) => body`. - if (tokenStream.matchToken(TOK_NAME) && - tokenStream.matchToken(TOK_RP) && - tokenStream.peekToken() == TOK_ARROW) - { - tokenStream.ungetToken(); // put back right paren + case TOK_TRIPLEDOT: { + TokenKind next; - // Return an arbitrary expression node. See case TOK_RP above. - return handler.newNullLiteral(pos()); + // This isn't valid expression syntax, but it's valid in an arrow + // function as a trailing rest param: `(a, b, ...rest) => body`. Check + // for a name, closing parenthesis, and arrow, and allow it only if all + // are present. + next = tokenStream.getToken(); + if (next == TOK_ERROR) + return null(); + if (next != TOK_NAME) { + report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + "rest argument name", TokenKindToDesc(next)); + return null(); } - report(ParseError, false, null(), JSMSG_SYNTAX_ERROR); - return null(); + + next = tokenStream.getToken(); + if (next == TOK_ERROR) + return null(); + if (next != TOK_RP) { + report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + "closing parenthesis", TokenKindToDesc(next)); + return null(); + } + + next = tokenStream.peekToken(); + if (next == TOK_ERROR) + return null(); + if (next != TOK_ARROW) { + report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + "'=>' after argument list", TokenKindToDesc(next)); + return null(); + } + + tokenStream.ungetToken(); // put back right paren + + // Return an arbitrary expression node. See case TOK_RP above. + return handler.newNullLiteral(pos()); + } case TOK_ERROR: /* The scanner or one of its subroutines reported the error. */ return null(); default: - report(ParseError, false, null(), JSMSG_SYNTAX_ERROR); + unexpected_token: + report(ParseError, false, null(), JSMSG_UNEXPECTED_TOKEN, + "expression", TokenKindToDesc(tt)); return null(); } } diff --git a/js/src/frontend/TokenKind.h b/js/src/frontend/TokenKind.h index 5d2e6dc254c6..4bf51d2389e4 100644 --- a/js/src/frontend/TokenKind.h +++ b/js/src/frontend/TokenKind.h @@ -51,7 +51,7 @@ * Note that this list does not contain ERROR and LIMIT. */ #define FOR_EACH_TOKEN_KIND_WITH_RANGE(macro, range) \ - macro(EOF, "end of file") \ + macro(EOF, "end of script") \ \ /* only returned by peekTokenSameLine() */ \ macro(EOL, "line terminator") \ diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp index 40e8620c2849..b2c751e4856a 100644 --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -1810,6 +1810,24 @@ js_fgets(char *buf, int size, FILE *file) return i; } +const char * +frontend::TokenKindToDesc(TokenKind tt) +{ + switch (tt) { +#define EMIT_CASE(name, desc) case TOK_##name: return desc; + FOR_EACH_TOKEN_KIND(EMIT_CASE) +#undef EMIT_CASE + case TOK_ERROR: + MOZ_ASSERT_UNREACHABLE("TOK_ERROR should not be passed."); + break; + case TOK_LIMIT: + MOZ_ASSERT_UNREACHABLE("TOK_LIMIT should not be passed."); + break; + } + + return ""; +} + #ifdef DEBUG const char * TokenKindToString(TokenKind tt) diff --git a/js/src/frontend/TokenStream.h b/js/src/frontend/TokenStream.h index 771e86d02f41..b4f51a063b0b 100644 --- a/js/src/frontend/TokenStream.h +++ b/js/src/frontend/TokenStream.h @@ -782,6 +782,9 @@ class MOZ_STACK_CLASS TokenStream // message have const char16_t* type, not const char*. #define JSREPORT_UC 0x100 +extern const char * +TokenKindToDesc(TokenKind tt); + } // namespace frontend } // namespace js diff --git a/js/src/jit-test/tests/basic/syntax-error-function-body-eof.js b/js/src/jit-test/tests/basic/syntax-error-function-body-eof.js new file mode 100644 index 000000000000..7015f83b1094 --- /dev/null +++ b/js/src/jit-test/tests/basic/syntax-error-function-body-eof.js @@ -0,0 +1,9 @@ +var caught = false; +try { + new Function("switch (x) {} }"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("unexpected garbage after function body, starting with '}'") == -1, false); + caught = true; +} +assertEq(caught, true); diff --git a/js/src/jit-test/tests/basic/syntax-error-primary.js b/js/src/jit-test/tests/basic/syntax-error-primary.js new file mode 100644 index 000000000000..6be66ee0c17e --- /dev/null +++ b/js/src/jit-test/tests/basic/syntax-error-primary.js @@ -0,0 +1,69 @@ +var caught = false; +try { + new Function(")"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("expected expression, got ')'") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("...;"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("expected rest argument name, got ';'") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("...a;"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("expected closing parenthesis, got ';'") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("...a);"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("expected '=>' after argument list, got ';'") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("...a) @"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("expected '=>' after argument list, got '@'") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("(if)"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("expected expression, got keyword 'if'") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("("); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("expected expression, got end of script") == -1, false); + caught = true; +} +assertEq(caught, true); diff --git a/js/src/jit-test/tests/basic/syntax-error-throw.js b/js/src/jit-test/tests/basic/syntax-error-throw.js new file mode 100644 index 000000000000..c82c56cf8b10 --- /dev/null +++ b/js/src/jit-test/tests/basic/syntax-error-throw.js @@ -0,0 +1,39 @@ +var caught = false; +try { + new Function("throw;"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("throw statement is missing an expression") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("throw\n1;"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("no line break is allowed between 'throw' and its expression") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("throw}"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("throw statement is missing an expression") == -1, false); + caught = true; +} +assertEq(caught, true); + +caught = false; +try { + new Function("throw"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("throw statement is missing an expression") == -1, false); + caught = true; +} +assertEq(caught, true); diff --git a/js/src/jit-test/tests/basic/syntax-error-toplevel-eof.js b/js/src/jit-test/tests/basic/syntax-error-toplevel-eof.js new file mode 100644 index 000000000000..15aaaf780165 --- /dev/null +++ b/js/src/jit-test/tests/basic/syntax-error-toplevel-eof.js @@ -0,0 +1,9 @@ +var caught = false; +try { + Reflect.parse("}"); +} catch (e) { + assertEq(e instanceof SyntaxError, true); + assertEq(e.message.startsWith("unexpected garbage after script, starting with '}'") == -1, false); + caught = true; +} +assertEq(caught, true); diff --git a/js/src/js.msg b/js/src/js.msg index 3a1cbc16f7f1..cde551aee552 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -233,6 +233,7 @@ MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 0, JSEXN_SYNTAXERR, "test for equality (= 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") +MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}") MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal") MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character") MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level") @@ -242,9 +243,11 @@ MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found") MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable") MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 0, JSEXN_SYNTAXERR, "let declaration not directly within block") +MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression") MSG_DEF(JSMSG_MALFORMED_ESCAPE, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence") MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'") MSG_DEF(JSMSG_MISSING_EXPONENT, 0, JSEXN_SYNTAXERR, "missing exponent") +MSG_DEF(JSMSG_MISSING_EXPR_AFTER_THROW,0, JSEXN_SYNTAXERR, "throw statement is missing an expression") MSG_DEF(JSMSG_MISSING_FORMAL, 0, JSEXN_SYNTAXERR, "missing formal parameter") MSG_DEF(JSMSG_MISSING_HEXDIGITS, 0, JSEXN_SYNTAXERR, "missing hexadecimal digits after '0x'") MSG_DEF(JSMSG_MISSING_OCTAL_DIGITS, 0, JSEXN_SYNTAXERR, "missing octal digits after '0o'") @@ -289,7 +292,6 @@ MSG_DEF(JSMSG_SOURCE_TOO_LONG, 0, JSEXN_RANGEERR, "source is too long") MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements") MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements") MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function") -MSG_DEF(JSMSG_SYNTAX_ERROR, 0, JSEXN_SYNTAXERR, "syntax error") MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string") MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 0, JSEXN_TYPEERR, "value isn't a SIMD value object") MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases") @@ -299,6 +301,7 @@ MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 0, JSEXN_SYNTAXERR, "more than one switch MSG_DEF(JSMSG_TOO_MANY_FUN_ARGS, 0, JSEXN_SYNTAXERR, "too many function arguments") MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local variables") MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch") +MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}") MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name") MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment") MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal") diff --git a/js/src/tests/ecma_3/LexicalConventions/7.9.1.js b/js/src/tests/ecma_3/LexicalConventions/7.9.1.js index 6bc4ae53a67c..7e11692cf52c 100644 --- a/js/src/tests/ecma_3/LexicalConventions/7.9.1.js +++ b/js/src/tests/ecma_3/LexicalConventions/7.9.1.js @@ -42,7 +42,7 @@ function test() code = 'expr\n++'; expr = 0; - expect = 'SyntaxError: syntax error'; + expect = 'SyntaxError: expected expression, got end of script'; try { @@ -74,7 +74,7 @@ function test() code = 'expr\n--'; expr = 0; - expect = 'SyntaxError: syntax error'; + expect = 'SyntaxError: expected expression, got end of script'; try { diff --git a/js/src/tests/ecma_3/extensions/7.9.1.js b/js/src/tests/ecma_3/extensions/7.9.1.js index 13d4360eef80..e6aa6f7fd081 100644 --- a/js/src/tests/ecma_3/extensions/7.9.1.js +++ b/js/src/tests/ecma_3/extensions/7.9.1.js @@ -37,7 +37,7 @@ function test() print('see bug 256617'); code = '(function() { throw \n x++; })'; // expect = '(function() { throw ; x++; })'; - expect = 'SyntaxError: syntax error'; + expect = 'SyntaxError: no line break is allowed between \'throw\' and its expression'; try { uneval(eval(code)); } catch(ex) { actual = ex + ''; }; // compareSource(expect, actual, summary + ': ' + code); reportCompare(expect, actual, summary + ': ' + code); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 16a5dfe31725..d789be6d515a 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -28,7 +28,7 @@ namespace js { * * https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode */ -static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 182); +static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 183); class XDRBuffer { public: From 69bfa032a3141a95d82009693adf342009c8d930 Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Fri, 12 Sep 2014 17:46:05 -0400 Subject: [PATCH 09/32] Bug 1066259 - Fix operators for multiplying/dividing a Coord by a Scale. r=kats --HG-- extra : rebase_source : e6efebeac8b6628b24e1596fb5dc78187c64e325 --- layout/base/Units.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layout/base/Units.h b/layout/base/Units.h index ed727f32b302..9c57c5e138d1 100644 --- a/layout/base/Units.h +++ b/layout/base/Units.h @@ -298,12 +298,12 @@ struct ScreenPixel { // Operators to apply ScaleFactors directly to Coords, Points, Rects, Sizes and Margins template -gfx::CoordTyped operator*(gfx::CoordTyped& aCoord, const gfx::ScaleFactor& aScale) { +gfx::CoordTyped operator*(const gfx::CoordTyped& aCoord, const gfx::ScaleFactor& aScale) { return gfx::CoordTyped(aCoord.value * aScale.scale); } template -gfx::CoordTyped operator/(gfx::CoordTyped& aCoord, const gfx::ScaleFactor& aScale) { +gfx::CoordTyped operator/(const gfx::CoordTyped& aCoord, const gfx::ScaleFactor& aScale) { return gfx::CoordTyped(aCoord.value / aScale.scale); } From 37e83036c0672c0a855ebb1e7bd6a7b64ad9950b Mon Sep 17 00:00:00 2001 From: Botond Ballo Date: Fri, 12 Sep 2014 17:46:31 -0400 Subject: [PATCH 10/32] Bug 1066259 - Change Axis to operate in Screen pixels where possible. r=kats --HG-- extra : rebase_source : c31c5a16e46eb79c64fd6e6d42c1d84f4718c2fe --- gfx/layers/apz/src/AsyncPanZoomController.cpp | 75 +++++------- gfx/layers/apz/src/AsyncPanZoomController.h | 2 +- gfx/layers/apz/src/Axis.cpp | 113 +++++++++--------- gfx/layers/apz/src/Axis.h | 91 ++++++-------- 4 files changed, 121 insertions(+), 160 deletions(-) diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 3dc3f1e81c50..dff3f1e70a6b 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -528,20 +528,16 @@ public: ScreenPoint offset = velocity * aDelta.ToMilliseconds(); - // Inversely scale the offset by the resolution (when you're zoomed further in, - // the same swipe should move you a shorter distance). - CSSPoint cssOffset = offset / aFrameMetrics.GetZoom(); - // Ordinarily we might need to do a ScheduleComposite if either of // the following AdjustDisplacement calls returns true, but this // is already running as part of a FlingAnimation, so we'll be compositing // per frame of animation anyway. - CSSPoint overscroll; - CSSPoint adjustedOffset; - mApzc.mX.AdjustDisplacement(cssOffset.x, adjustedOffset.x, overscroll.x); - mApzc.mY.AdjustDisplacement(cssOffset.y, adjustedOffset.y, overscroll.y); + ScreenPoint overscroll; + ScreenPoint adjustedOffset; + mApzc.mX.AdjustDisplacement(offset.x, adjustedOffset.x, overscroll.x); + mApzc.mY.AdjustDisplacement(offset.y, adjustedOffset.y, overscroll.y); - aFrameMetrics.ScrollBy(adjustedOffset); + aFrameMetrics.ScrollBy(adjustedOffset / aFrameMetrics.GetZoom()); // The fling may have caused us to reach the end of our scroll range. if (!IsZero(overscroll)) { @@ -750,18 +746,17 @@ public: } else { mApzc.mY.SetVelocity(velocity.y); } - // If we overscroll, hand off to a fling animation that will complete the // spring back. - float displacement_x = position.x - mApzc.mX.GetOrigin(); - float displacement_y = position.y - mApzc.mY.GetOrigin(); + CSSToScreenScale zoom = aFrameMetrics.GetZoom(); + ScreenPoint displacement = (position - aFrameMetrics.GetScrollOffset()) * zoom; - CSSPoint overscroll; - CSSPoint adjustedOffset; - mApzc.mX.AdjustDisplacement(displacement_x, adjustedOffset.x, overscroll.x); - mApzc.mY.AdjustDisplacement(displacement_y, adjustedOffset.y, overscroll.y); + ScreenPoint overscroll; + ScreenPoint adjustedOffset; + mApzc.mX.AdjustDisplacement(displacement.x, adjustedOffset.x, overscroll.x); + mApzc.mY.AdjustDisplacement(displacement.y, adjustedOffset.y, overscroll.y); - aFrameMetrics.ScrollBy(adjustedOffset); + aFrameMetrics.ScrollBy(adjustedOffset / zoom); // The smooth scroll may have caused us to reach the end of our scroll range. // This can happen if either the layout.css.scroll-behavior.damping-ratio @@ -1394,17 +1389,13 @@ nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) { CSSToParentLayerScale userZoom = mFrameMetrics.GetZoomToParent(); ParentLayerPoint focusPoint = ToParentLayerCoords(aEvent.mFocusPoint) - mFrameMetrics.mCompositionBounds.TopLeft(); - CSSPoint cssFocusPoint = focusPoint / userZoom; + CSSPoint cssFocusPoint = focusPoint / mFrameMetrics.GetZoomToParent(); CSSPoint focusChange = (mLastZoomFocus - focusPoint) / userZoom; // If displacing by the change in focus point will take us off page bounds, // then reduce the displacement such that it doesn't. - if (mX.DisplacementWillOverscroll(focusChange.x) != Axis::OVERSCROLL_NONE) { - focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x); - } - if (mY.DisplacementWillOverscroll(focusChange.y) != Axis::OVERSCROLL_NONE) { - focusChange.y -= mY.DisplacementWillOverscrollAmount(focusChange.y); - } + focusChange.x -= mX.DisplacementWillOverscrollAmount(focusChange.x); + focusChange.y -= mY.DisplacementWillOverscrollAmount(focusChange.y); ScrollBy(focusChange); // When we zoom in with focus, we can zoom too much towards the boundaries @@ -1927,27 +1918,18 @@ bool AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint, ScreenPoint displacement = aStartPoint - aEndPoint; ScreenPoint overscroll; // will be used outside monitor block - CSSPoint cssOverscroll; // ditto { ReentrantMonitorAutoEnter lock(mMonitor); - CSSToScreenScale zoom = mFrameMetrics.GetZoom(); - - // Inversely scale the offset by the resolution (when you're zoomed further in, - // the same swipe should move you a shorter distance). - CSSPoint cssDisplacement = displacement / zoom; - - CSSPoint adjustedDisplacement; - bool xChanged = mX.AdjustDisplacement(cssDisplacement.x, adjustedDisplacement.x, cssOverscroll.x); - bool yChanged = mY.AdjustDisplacement(cssDisplacement.y, adjustedDisplacement.y, cssOverscroll.y); + ScreenPoint adjustedDisplacement; + bool xChanged = mX.AdjustDisplacement(displacement.x, adjustedDisplacement.x, overscroll.x); + bool yChanged = mY.AdjustDisplacement(displacement.y, adjustedDisplacement.y, overscroll.y); if (xChanged || yChanged) { ScheduleComposite(); } - overscroll = cssOverscroll * zoom; - if (!IsZero(adjustedDisplacement)) { - ScrollBy(adjustedDisplacement); + ScrollBy(adjustedDisplacement / mFrameMetrics.GetZoom()); ScheduleCompositeAndMaybeRepaint(); UpdateSharedCompositorFrameMetrics(); } @@ -1972,10 +1954,10 @@ bool AsyncPanZoomController::AttemptScroll(const ScreenPoint& aStartPoint, // overscroll, try to accept it ourselves. We only accept it if we // are pannable. APZC_LOG("%p taking overscroll during panning\n", this); - return OverscrollBy(cssOverscroll); + return OverscrollBy(overscroll); } -bool AsyncPanZoomController::OverscrollBy(const CSSPoint& aOverscroll) { +bool AsyncPanZoomController::OverscrollBy(const ScreenPoint& aOverscroll) { if (!gfxPrefs::APZOverscrollEnabled()) { return false; } @@ -2438,7 +2420,7 @@ void AsyncPanZoomController::GetOverscrollTransform(Matrix4x4* aTransform) const // Compute the amount of the stretch along each axis. The stretch is // proportional to the amount by which we are overscrolled along that axis. - CSSSize compositionSize(mX.GetCompositionLength(), mY.GetCompositionLength()); + ScreenSize compositionSize(mX.GetCompositionLength(), mY.GetCompositionLength()); float scaleX = 1 + kStretchFactor * fabsf(mX.GetOverscroll()) / mX.GetCompositionLength(); float scaleY = 1 + kStretchFactor * fabsf(mY.GetOverscroll()) / mY.GetCompositionLength(); @@ -2447,24 +2429,23 @@ void AsyncPanZoomController::GetOverscrollTransform(Matrix4x4* aTransform) const // are overscrolling at the top or on the left, but if we are overscrolling // at the bottom or on the right, we want the bottom or right edge of the // content to stay in place instead, so we add a translation to compensate. - CSSPoint translation; + ScreenPoint translation; if (mX.IsOverscrolled() && mX.GetOverscroll() > 0) { // Overscrolled on the right. - CSSCoord overscrolledCompositionWidth = scaleX * compositionSize.width; - CSSCoord extraCompositionWidth = overscrolledCompositionWidth - compositionSize.width; + ScreenCoord overscrolledCompositionWidth = scaleX * compositionSize.width; + ScreenCoord extraCompositionWidth = overscrolledCompositionWidth - compositionSize.width; translation.x = -extraCompositionWidth; } if (mY.IsOverscrolled() && mY.GetOverscroll() > 0) { // Overscrolled at the bottomn. - CSSCoord overscrolledCompositionHeight = scaleY * compositionSize.height; - CSSCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height; + ScreenCoord overscrolledCompositionHeight = scaleY * compositionSize.height; + ScreenCoord extraCompositionHeight = overscrolledCompositionHeight - compositionSize.height; translation.y = -extraCompositionHeight; } // Combine the transformations into a matrix. - ScreenPoint screenTranslation = translation * mFrameMetrics.GetZoom(); *aTransform = Matrix4x4().Scale(scaleX, scaleY, 1) - .PostTranslate(screenTranslation.x, screenTranslation.y, 0); + .PostTranslate(translation.x, translation.y, 0); } bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime) diff --git a/gfx/layers/apz/src/AsyncPanZoomController.h b/gfx/layers/apz/src/AsyncPanZoomController.h index 5d2e1b91a3f8..2b4fea243931 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.h +++ b/gfx/layers/apz/src/AsyncPanZoomController.h @@ -1022,7 +1022,7 @@ private: * and the function returns true. * Otherwise, nothing happens and the function return false. */ - bool OverscrollBy(const CSSPoint& aOverscroll); + bool OverscrollBy(const ScreenPoint& aOverscroll); /** * Build the chain of APZCs along which scroll will be handed off when diff --git a/gfx/layers/apz/src/Axis.cpp b/gfx/layers/apz/src/Axis.cpp index 84f66f3c8cd6..eb93a53b697d 100644 --- a/gfx/layers/apz/src/Axis.cpp +++ b/gfx/layers/apz/src/Axis.cpp @@ -72,9 +72,9 @@ void Axis::StartTouch(ScreenCoord aPos, uint32_t aTimestampMs) { mAxisLocked = false; } -bool Axis::AdjustDisplacement(CSSCoord aDisplacement, - /* CSSCoord */ float& aDisplacementOut, - /* CSSCoord */ float& aOverscrollAmountOut) +bool Axis::AdjustDisplacement(ScreenCoord aDisplacement, + /* ScreenCoord */ float& aDisplacementOut, + /* ScreenCoord */ float& aOverscrollAmountOut) { if (mAxisLocked) { aOverscrollAmountOut = 0; @@ -82,10 +82,10 @@ bool Axis::AdjustDisplacement(CSSCoord aDisplacement, return false; } - CSSCoord displacement = aDisplacement; + ScreenCoord displacement = aDisplacement; // First consume any overscroll in the opposite direction along this axis. - CSSCoord consumedOverscroll = 0; + ScreenCoord consumedOverscroll = 0; if (mOverscroll > 0 && aDisplacement < 0) { consumedOverscroll = std::min(mOverscroll, -aDisplacement); } else if (mOverscroll < 0 && aDisplacement > 0) { @@ -96,18 +96,18 @@ bool Axis::AdjustDisplacement(CSSCoord aDisplacement, // Split the requested displacement into an allowed displacement that does // not overscroll, and an overscroll amount. - if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) { + aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement); + if (aOverscrollAmountOut != 0.0f) { // No need to have a velocity along this axis anymore; it won't take us // anywhere, so we're just spinning needlessly. mVelocity = 0.0f; - aOverscrollAmountOut = DisplacementWillOverscrollAmount(displacement); displacement -= aOverscrollAmountOut; } aDisplacementOut = displacement; return fabsf(consumedOverscroll) > EPSILON; } -CSSCoord Axis::ApplyResistance(CSSCoord aRequestedOverscroll) const { +ScreenCoord Axis::ApplyResistance(ScreenCoord aRequestedOverscroll) const { // 'resistanceFactor' is a value between 0 and 1, which: // - tends to 1 as the existing overscroll tends to 0 // - tends to 0 as the existing overscroll tends to the composition length @@ -115,10 +115,10 @@ CSSCoord Axis::ApplyResistance(CSSCoord aRequestedOverscroll) const { // factor; this should prevent overscrolling by more than the composition // length. float resistanceFactor = 1 - fabsf(mOverscroll) / GetCompositionLength(); - return resistanceFactor < 0 ? CSSCoord(0) : aRequestedOverscroll * resistanceFactor; + return resistanceFactor < 0 ? ScreenCoord(0) : aRequestedOverscroll * resistanceFactor; } -void Axis::OverscrollBy(CSSCoord aOverscroll) { +void Axis::OverscrollBy(ScreenCoord aOverscroll) { MOZ_ASSERT(CanScroll()); aOverscroll = ApplyResistance(aOverscroll); if (aOverscroll > 0) { @@ -145,7 +145,7 @@ void Axis::OverscrollBy(CSSCoord aOverscroll) { mOverscroll += aOverscroll; } -CSSCoord Axis::GetOverscroll() const { +ScreenCoord Axis::GetOverscroll() const { return mOverscroll; } @@ -170,14 +170,13 @@ bool Axis::SampleSnapBack(const TimeDuration& aDelta) { float force = -1 * kSpringStiffness * mOverscroll - kSpringFriction * mVelocity; float acceleration = force / kMass; mVelocity += acceleration * aDelta.ToMilliseconds(); - float screenDisplacement = mVelocity * aDelta.ToMilliseconds(); - float cssDisplacement = screenDisplacement / GetFrameMetrics().GetZoom().scale; + float displacement = mVelocity * aDelta.ToMilliseconds(); if (mOverscroll > 0) { - if (cssDisplacement > 0) { + if (displacement > 0) { NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!"); return false; } - mOverscroll = std::max(mOverscroll + cssDisplacement, 0.0f); + mOverscroll = std::max(mOverscroll + displacement, 0.0f); // Overscroll relieved, do not continue animation. if (mOverscroll == 0.f) { mVelocity = 0; @@ -185,11 +184,11 @@ bool Axis::SampleSnapBack(const TimeDuration& aDelta) { } return true; } else if (mOverscroll < 0) { - if (cssDisplacement < 0) { + if (displacement < 0) { NS_WARNING("Overscroll snap-back animation is moving in the wrong direction!"); return false; } - mOverscroll = std::min(mOverscroll + cssDisplacement, 0.0f); + mOverscroll = std::min(mOverscroll + displacement, 0.0f); // Overscroll relieved, do not continue animation. if (mOverscroll == 0.f) { mVelocity = 0; @@ -273,37 +272,35 @@ bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta, return true; } -Axis::Overscroll Axis::DisplacementWillOverscroll(CSSCoord aDisplacement) { +ScreenCoord Axis::DisplacementWillOverscrollAmount(ScreenCoord aDisplacement) const { + ScreenCoord newOrigin = GetOrigin() + aDisplacement; + ScreenCoord newCompositionEnd = GetCompositionEnd() + aDisplacement; // If the current pan plus a displacement takes the window to the left of or // above the current page rect. - bool minus = GetOrigin() + aDisplacement < GetPageStart(); + bool minus = newOrigin < GetPageStart(); // If the current pan plus a displacement takes the window to the right of or // below the current page rect. - bool plus = GetCompositionEnd() + aDisplacement > GetPageEnd(); + bool plus = newCompositionEnd > GetPageEnd(); if (minus && plus) { - return OVERSCROLL_BOTH; + // Don't handle overscrolled in both directions; a displacement can't cause + // this, it must have already been zoomed out too far. + return 0; } if (minus) { - return OVERSCROLL_MINUS; + return newOrigin - GetPageStart(); } if (plus) { - return OVERSCROLL_PLUS; + return newCompositionEnd - GetPageEnd(); } - return OVERSCROLL_NONE; + return 0; } -CSSCoord Axis::DisplacementWillOverscrollAmount(CSSCoord aDisplacement) { - switch (DisplacementWillOverscroll(aDisplacement)) { - case OVERSCROLL_MINUS: return (GetOrigin() + aDisplacement) - GetPageStart(); - case OVERSCROLL_PLUS: return (GetCompositionEnd() + aDisplacement) - GetPageEnd(); - // Don't handle overscrolled in both directions; a displacement can't cause - // this, it must have already been zoomed out too far. - default: return 0; - } -} - -CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) { - CSSCoord originAfterScale = (GetOrigin() + aFocus) - (aFocus / aScale); +CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const { + // Internally, do computations in Screen coordinates *before* the scale is + // applied. + CSSToScreenScale zoom = GetFrameMetrics().GetZoom(); + ScreenCoord focus = aFocus * zoom; + ScreenCoord originAfterScale = (GetOrigin() + focus) - (focus / aScale); bool both = ScaleWillOverscrollBothSides(aScale); bool minus = GetPageStart() - originAfterScale > COORDINATE_EPSILON; @@ -315,10 +312,10 @@ CSSCoord Axis::ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) { return 0; } if (minus) { - return originAfterScale - GetPageStart(); + return (originAfterScale - GetPageStart()) / zoom; } if (plus) { - return originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd(); + return (originAfterScale + (GetCompositionLength() / aScale) - GetPageEnd()) / zoom; } return 0; } @@ -331,40 +328,40 @@ void Axis::SetVelocity(float aVelocity) { mVelocity = aVelocity; } -CSSCoord Axis::GetCompositionEnd() const { +ScreenCoord Axis::GetCompositionEnd() const { return GetOrigin() + GetCompositionLength(); } -CSSCoord Axis::GetPageEnd() const { +ScreenCoord Axis::GetPageEnd() const { return GetPageStart() + GetPageLength(); } -CSSCoord Axis::GetOrigin() const { - CSSPoint origin = GetFrameMetrics().GetScrollOffset(); +ScreenCoord Axis::GetOrigin() const { + ScreenPoint origin = GetFrameMetrics().GetScrollOffset() * GetFrameMetrics().GetZoom(); return GetPointOffset(origin); } -CSSCoord Axis::GetCompositionLength() const { - return GetRectLength(GetFrameMetrics().CalculateCompositedRectInCssPixels()); +ScreenCoord Axis::GetCompositionLength() const { + return GetRectLength(GetFrameMetrics().mCompositionBounds / GetFrameMetrics().mTransformScale); } -CSSCoord Axis::GetPageStart() const { - CSSRect pageRect = GetFrameMetrics().GetExpandedScrollableRect(); +ScreenCoord Axis::GetPageStart() const { + ScreenRect pageRect = GetFrameMetrics().GetExpandedScrollableRect() * GetFrameMetrics().GetZoom(); return GetRectOffset(pageRect); } -CSSCoord Axis::GetPageLength() const { - CSSRect pageRect = GetFrameMetrics().GetExpandedScrollableRect(); +ScreenCoord Axis::GetPageLength() const { + ScreenRect pageRect = GetFrameMetrics().GetExpandedScrollableRect() * GetFrameMetrics().GetZoom(); return GetRectLength(pageRect); } -bool Axis::ScaleWillOverscrollBothSides(float aScale) { +bool Axis::ScaleWillOverscrollBothSides(float aScale) const { const FrameMetrics& metrics = GetFrameMetrics(); - CSSToParentLayerScale scale(metrics.GetZoomToParent().scale * aScale); - CSSRect cssCompositionBounds = metrics.mCompositionBounds / scale; + ScreenToParentLayerScale scale(metrics.mTransformScale.scale * aScale); + ScreenRect screenCompositionBounds = metrics.mCompositionBounds / scale; - return GetRectLength(cssCompositionBounds) - GetRectLength(metrics.GetExpandedScrollableRect()) > COORDINATE_EPSILON; + return GetRectLength(screenCompositionBounds) - GetPageLength() > COORDINATE_EPSILON; } const FrameMetrics& Axis::GetFrameMetrics() const { @@ -378,17 +375,17 @@ AxisX::AxisX(AsyncPanZoomController* aAsyncPanZoomController) } -CSSCoord AxisX::GetPointOffset(const CSSPoint& aPoint) const +ScreenCoord AxisX::GetPointOffset(const ScreenPoint& aPoint) const { return aPoint.x; } -CSSCoord AxisX::GetRectLength(const CSSRect& aRect) const +ScreenCoord AxisX::GetRectLength(const ScreenRect& aRect) const { return aRect.width; } -CSSCoord AxisX::GetRectOffset(const CSSRect& aRect) const +ScreenCoord AxisX::GetRectOffset(const ScreenRect& aRect) const { return aRect.x; } @@ -404,17 +401,17 @@ AxisY::AxisY(AsyncPanZoomController* aAsyncPanZoomController) } -CSSCoord AxisY::GetPointOffset(const CSSPoint& aPoint) const +ScreenCoord AxisY::GetPointOffset(const ScreenPoint& aPoint) const { return aPoint.y; } -CSSCoord AxisY::GetRectLength(const CSSRect& aRect) const +ScreenCoord AxisY::GetRectLength(const ScreenRect& aRect) const { return aRect.height; } -CSSCoord AxisY::GetRectOffset(const CSSRect& aRect) const +ScreenCoord AxisY::GetRectOffset(const ScreenRect& aRect) const { return aRect.y; } diff --git a/gfx/layers/apz/src/Axis.h b/gfx/layers/apz/src/Axis.h index d4800cf4a20a..62053507b2c7 100644 --- a/gfx/layers/apz/src/Axis.h +++ b/gfx/layers/apz/src/Axis.h @@ -8,7 +8,7 @@ #define mozilla_layers_Axis_h #include // for int32_t -#include "Units.h" // for CSSRect, CSSPoint +#include "Units.h" #include "mozilla/TimeStamp.h" // for TimeDuration #include "nsTArray.h" // for nsTArray @@ -37,20 +37,6 @@ class Axis { public: explicit Axis(AsyncPanZoomController* aAsyncPanZoomController); - enum Overscroll { - // Overscroll is not happening at all. - OVERSCROLL_NONE = 0, - // Overscroll is happening in the negative direction. This means either to - // the left or to the top depending on the axis. - OVERSCROLL_MINUS, - // Overscroll is happening in the positive direction. This means either to - // the right or to the bottom depending on the axis. - OVERSCROLL_PLUS, - // Overscroll is happening both ways. This only means something when the - // page is scaled out to a smaller size than the viewport. - OVERSCROLL_BOTH - }; - /** * Notify this Axis that a new touch has been received, including a timestamp * for when the touch was received. This triggers a recalculation of velocity. @@ -87,20 +73,20 @@ public: * displacement, and the function returns true iff internal overscroll amounts * were changed. */ - bool AdjustDisplacement(CSSCoord aDisplacement, - /* CSSCoord */ float& aDisplacementOut, - /* CSSCoord */ float& aOverscrollAmountOut); + bool AdjustDisplacement(ScreenCoord aDisplacement, + /* ScreenCoord */ float& aDisplacementOut, + /* ScreenCoord */ float& aOverscrollAmountOut); /** * Overscrolls this axis by the requested amount in the requested direction. * The axis must be at the end of its scroll range in this direction. */ - void OverscrollBy(CSSCoord aOverscroll); + void OverscrollBy(ScreenCoord aOverscroll); /** - * Return the amount of overscroll on this axis, in CSS pixels. + * Return the amount of overscroll on this axis, in Screen pixels. */ - CSSCoord GetOverscroll() const; + ScreenCoord GetOverscroll() const; /** * Sample the snap-back animation to relieve overscroll. @@ -177,28 +163,25 @@ public: */ void SetVelocity(float aVelocity); - /** - * Gets the overscroll state of the axis given an additional displacement. - * That is to say, if the given displacement is applied, this will tell you - * whether or not it will overscroll, and in what direction. - */ - Overscroll DisplacementWillOverscroll(CSSCoord aDisplacement); - /** * If a displacement will overscroll the axis, this returns the amount and in - * what direction. Similar to GetExcess() but takes a displacement to apply. + * what direction. */ - CSSCoord DisplacementWillOverscrollAmount(CSSCoord aDisplacement); + ScreenCoord DisplacementWillOverscrollAmount(ScreenCoord aDisplacement) const; /** * If a scale will overscroll the axis, this returns the amount and in what - * direction. Similar to GetExcess() but takes a displacement to apply. + * direction. * * |aFocus| is the point at which the scale is focused at. We will offset the * scroll offset in such a way that it remains in the same place on the page * relative. + * + * Note: Unlike most other functions in Axis, this functions operates in + * CSS coordinates so there is no confusion as to whether the Screen + * coordinates it operates in are before or after the scale is applied. */ - CSSCoord ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus); + CSSCoord ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const; /** * Checks if an axis will overscroll in both directions by computing the @@ -207,20 +190,20 @@ public: * * This gets called by ScaleWillOverscroll(). */ - bool ScaleWillOverscrollBothSides(float aScale); + bool ScaleWillOverscrollBothSides(float aScale) const; - CSSCoord GetOrigin() const; - CSSCoord GetCompositionLength() const; - CSSCoord GetPageStart() const; - CSSCoord GetPageLength() const; - CSSCoord GetCompositionEnd() const; - CSSCoord GetPageEnd() const; + ScreenCoord GetOrigin() const; + ScreenCoord GetCompositionLength() const; + ScreenCoord GetPageStart() const; + ScreenCoord GetPageLength() const; + ScreenCoord GetCompositionEnd() const; + ScreenCoord GetPageEnd() const; ScreenCoord GetPos() const { return mPos; } - virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const = 0; - virtual CSSCoord GetRectLength(const CSSRect& aRect) const = 0; - virtual CSSCoord GetRectOffset(const CSSRect& aRect) const = 0; + virtual ScreenCoord GetPointOffset(const ScreenPoint& aPoint) const = 0; + virtual ScreenCoord GetRectLength(const ScreenRect& aRect) const = 0; + virtual ScreenCoord GetRectOffset(const ScreenRect& aRect) const = 0; virtual ScreenPoint MakePoint(ScreenCoord aCoord) const = 0; @@ -228,16 +211,16 @@ protected: ScreenCoord mPos; uint32_t mPosTimeMs; ScreenCoord mStartPos; - float mVelocity; + float mVelocity; // Units: ScreenCoords per millisecond bool mAxisLocked; // Whether movement on this axis is locked. AsyncPanZoomController* mAsyncPanZoomController; - // The amount by which this axis is in overscroll, in CSS coordinates. + // The amount by which this axis is in overscroll, in Screen coordinates. // If this amount is nonzero, the relevant component of // mAsyncPanZoomController->mFrameMetrics.mScrollOffset must be at its // extreme allowed value in the relevant direction (that is, it must be at // its maximum value if mOverscroll is positive, and at its minimum value // if mOverscroll is negative). - CSSCoord mOverscroll; + ScreenCoord mOverscroll; // A queue of (timestamp, velocity) pairs; these are the historical // velocities at the given timestamps. Timestamps are in milliseconds, // velocities are in screen pixels per ms. This member can only be @@ -248,25 +231,25 @@ protected: // Adjust a requested overscroll amount for resistance, yielding a smaller // actual overscroll amount. - CSSCoord ApplyResistance(CSSCoord aOverscroll) const; + ScreenCoord ApplyResistance(ScreenCoord aOverscroll) const; }; class AxisX : public Axis { public: explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController); - virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const; - virtual CSSCoord GetRectLength(const CSSRect& aRect) const; - virtual CSSCoord GetRectOffset(const CSSRect& aRect) const; - virtual ScreenPoint MakePoint(ScreenCoord aCoord) const; + virtual ScreenCoord GetPointOffset(const ScreenPoint& aPoint) const MOZ_OVERRIDE; + virtual ScreenCoord GetRectLength(const ScreenRect& aRect) const MOZ_OVERRIDE; + virtual ScreenCoord GetRectOffset(const ScreenRect& aRect) const MOZ_OVERRIDE; + virtual ScreenPoint MakePoint(ScreenCoord aCoord) const MOZ_OVERRIDE; }; class AxisY : public Axis { public: explicit AxisY(AsyncPanZoomController* mAsyncPanZoomController); - virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const; - virtual CSSCoord GetRectLength(const CSSRect& aRect) const; - virtual CSSCoord GetRectOffset(const CSSRect& aRect) const; - virtual ScreenPoint MakePoint(ScreenCoord aCoord) const; + virtual ScreenCoord GetPointOffset(const ScreenPoint& aPoint) const MOZ_OVERRIDE; + virtual ScreenCoord GetRectLength(const ScreenRect& aRect) const MOZ_OVERRIDE; + virtual ScreenCoord GetRectOffset(const ScreenRect& aRect) const MOZ_OVERRIDE; + virtual ScreenPoint MakePoint(ScreenCoord aCoord) const MOZ_OVERRIDE; }; } From a097c4dda88e955bec8f9012d25cf7d6a99bbae5 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Fri, 12 Sep 2014 16:34:38 +1200 Subject: [PATCH 11/32] Factor out more MSE test setup to the helper function. No bug. DONTBUILD --- content/media/mediasource/test/mediasource.js | 30 ++++++++++++++----- .../mediasource/test/test_BufferedSeek.html | 10 +------ .../mediasource/test/test_FrameSelection.html | 10 +------ .../mediasource/test/test_SplitAppend.html | 10 +------ .../test/test_SplitAppendDelay.html | 10 +------ 5 files changed, 26 insertions(+), 44 deletions(-) diff --git a/content/media/mediasource/test/mediasource.js b/content/media/mediasource/test/mediasource.js index bca2fd2b5286..921adbef9d0a 100644 --- a/content/media/mediasource/test/mediasource.js +++ b/content/media/mediasource/test/mediasource.js @@ -1,20 +1,34 @@ // Helpers for Media Source Extensions tests function runWithMSE(testFunction) { - addLoadEvent(() => SpecialPowers.pushPrefEnv({"set": [[ "media.mediasource.enabled", true ]]}, testFunction)); + function bootstrapTest() { + var ms = new MediaSource(); + + var el = document.createElement("video"); + el.src = URL.createObjectURL(ms); + el.preload = "auto"; + + document.body.appendChild(el); + SimpleTest.registerCleanupFunction(function () { + el.parentNode.removeChild(el); + }); + + testFunction(ms, el); + } + + addLoadEvent(function () { + SpecialPowers.pushPrefEnv({"set": [[ "media.mediasource.enabled", true ]]}, + bootstrapTest); + }); } function fetchWithXHR(uri, onLoadFunction) { var xhr = new XMLHttpRequest(); xhr.open("GET", uri, true); - xhr.responseType = "blob"; - xhr.addEventListener("load", function (e) { + xhr.responseType = "arraybuffer"; + xhr.addEventListener("load", function () { is(xhr.status, 200, "fetchWithXHR load uri='" + uri + "' status=" + xhr.status); - var rdr = new FileReader(); - rdr.addEventListener("load", function (e) { - onLoadFunction(e.target.result); - }); - rdr.readAsArrayBuffer(e.target.response); + onLoadFunction(xhr.response); }); xhr.send(); }; diff --git a/content/media/mediasource/test/test_BufferedSeek.html b/content/media/mediasource/test/test_BufferedSeek.html index bb87efb56773..4f1cd1025cdc 100644 --- a/content/media/mediasource/test/test_BufferedSeek.html +++ b/content/media/mediasource/test/test_BufferedSeek.html @@ -12,14 +12,7 @@ SimpleTest.waitForExplicitFinish(); -runWithMSE(function () { - var ms = new MediaSource(); - - var v = document.createElement("video"); - v.preload = "auto"; - v.src = URL.createObjectURL(ms); - document.body.appendChild(v); - +runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); @@ -51,7 +44,6 @@ runWithMSE(function () { v.addEventListener("seeked", function () { ok(wasSeeking, "Received expected seeking and seeked events"); is(v.currentTime, target, "Video currentTime not at target"); - v.parentNode.removeChild(v); SimpleTest.finish(); }); }); diff --git a/content/media/mediasource/test/test_FrameSelection.html b/content/media/mediasource/test/test_FrameSelection.html index d441a044973a..dab987bc3b59 100644 --- a/content/media/mediasource/test/test_FrameSelection.html +++ b/content/media/mediasource/test/test_FrameSelection.html @@ -12,14 +12,7 @@ SimpleTest.waitForExplicitFinish(); -runWithMSE(function () { - var ms = new MediaSource(); - - var v = document.createElement("video"); - v.preload = "auto"; - v.src = URL.createObjectURL(ms); - document.body.appendChild(v); - +runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); @@ -66,7 +59,6 @@ runWithMSE(function () { if (target) { v.currentTime = target.currentTime; } else { - v.parentNode.removeChild(v); SimpleTest.finish(); } }); diff --git a/content/media/mediasource/test/test_SplitAppend.html b/content/media/mediasource/test/test_SplitAppend.html index 353ac50fe2e6..34070c456e8b 100644 --- a/content/media/mediasource/test/test_SplitAppend.html +++ b/content/media/mediasource/test/test_SplitAppend.html @@ -12,14 +12,7 @@ SimpleTest.waitForExplicitFinish(); -runWithMSE(function () { - var ms = new MediaSource(); - - var v = document.createElement("video"); - v.preload = "auto"; - v.src = URL.createObjectURL(ms); - document.body.appendChild(v); - +runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); @@ -41,7 +34,6 @@ runWithMSE(function () { v.addEventListener("ended", function () { is(v.duration, 4, "Video has correct duration"); is(v.currentTime, 4, "Video has played to end"); - v.parentNode.removeChild(v); SimpleTest.finish(); }); }); diff --git a/content/media/mediasource/test/test_SplitAppendDelay.html b/content/media/mediasource/test/test_SplitAppendDelay.html index 8602ee656e66..9bf26e6dc6be 100644 --- a/content/media/mediasource/test/test_SplitAppendDelay.html +++ b/content/media/mediasource/test/test_SplitAppendDelay.html @@ -12,14 +12,7 @@ SimpleTest.waitForExplicitFinish(); -runWithMSE(function () { - var ms = new MediaSource(); - - var v = document.createElement("video"); - v.preload = "auto"; - v.src = URL.createObjectURL(ms); - document.body.appendChild(v); - +runWithMSE(function (ms, v) { ms.addEventListener("sourceopen", function () { var sb = ms.addSourceBuffer("video/webm"); @@ -43,7 +36,6 @@ runWithMSE(function () { v.addEventListener("ended", function () { is(v.duration, 4, "Video has correct duration"); is(v.currentTime, 4, "Video has played to end"); - v.parentNode.removeChild(v); SimpleTest.finish(); }); }); From aba8fc1912efc5f5524020d4298677d295dd025e Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Wed, 10 Sep 2014 13:26:22 +1200 Subject: [PATCH 12/32] Bug 1062657 - Tweak SourceBuffer::AppendData overlap algorithm and switch internal SourceBuffer timestamp handling from double/seconds to int64_t/microseconds. r=karlt --- content/media/mediasource/SourceBuffer.cpp | 61 +++++++++++++++------- content/media/mediasource/TrackBuffer.cpp | 10 ++-- content/media/mediasource/TrackBuffer.h | 10 ++-- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/content/media/mediasource/SourceBuffer.cpp b/content/media/mediasource/SourceBuffer.cpp index fdf7917d902b..31bbc3214892 100644 --- a/content/media/mediasource/SourceBuffer.cpp +++ b/content/media/mediasource/SourceBuffer.cpp @@ -47,6 +47,9 @@ class ContainerParser { public: virtual ~ContainerParser() {} + // Return true if aData starts with an initialization segment. + // The base implementation exists only for debug logging and is expected + // to be called first from the overriding implementation. virtual bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength) { MSE_DEBUG("ContainerParser(%p)::IsInitSegmentPresent aLength=%u [%x%x%x%x]", @@ -58,6 +61,9 @@ public: return false; } + // Return true if aData starts with a media segment. + // The base implementation exists only for debug logging and is expected + // to be called first from the overriding implementation. virtual bool IsMediaSegmentPresent(const uint8_t* aData, uint32_t aLength) { MSE_DEBUG("ContainerParser(%p)::IsMediaSegmentPresent aLength=%u [%x%x%x%x]", @@ -69,12 +75,24 @@ public: return false; } + // Parse aData to extract the start and end frame times from the media + // segment. aData may not start on a parser sync boundary. Return true + // if aStart and aEnd have been updated. virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength, - double& aStart, double& aEnd) + int64_t& aStart, int64_t& aEnd) { return false; } + // Compare aLhs and rHs, considering any error that may exist in the + // timestamps from the format's base representation. Return true if aLhs + // == aRhs within the error epsilon. + virtual bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs) + { + NS_WARNING("Using default ContainerParser::TimestampFuzzyEquals implementation"); + return aLhs == aRhs; + } + virtual const nsTArray& InitData() { MOZ_ASSERT(mInitData.Length() > 0); @@ -93,6 +111,8 @@ public: : mParser(0), mOffset(0) {} + static const unsigned NS_PER_USEC = 1000; + bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength) { ContainerParser::IsInitSegmentPresent(aData, aLength); @@ -133,8 +153,8 @@ public: return false; } - virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength, - double& aStart, double& aEnd) + bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength, + int64_t& aStart, int64_t& aEnd) { bool initSegment = IsInitSegmentPresent(aData, aLength); if (initSegment) { @@ -181,12 +201,11 @@ public: return false; } - static const double NS_PER_S = 1e9; - aStart = mapping[0].mTimecode / NS_PER_S; - aEnd = mapping[endIdx].mTimecode / NS_PER_S; - aEnd += (mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode) / NS_PER_S; + uint64_t frameDuration = mapping[endIdx].mTimecode - mapping[endIdx - 1].mTimecode; + aStart = mapping[0].mTimecode / NS_PER_USEC; + aEnd = (mapping[endIdx].mTimecode + frameDuration) / NS_PER_USEC; - MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: [%f, %f] [fso=%lld, leo=%lld, l=%u endIdx=%u]", + MSE_DEBUG("WebMContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld] [fso=%lld, leo=%lld, l=%u endIdx=%u]", this, aStart, aEnd, mapping[0].mSyncOffset, mapping[endIdx].mEndOffset, mapping.Length(), endIdx); mapping.RemoveElementsAt(0, endIdx + 1); @@ -195,6 +214,12 @@ public: return true; } + bool TimestampsFuzzyEqual(int64_t aLhs, int64_t aRhs) + { + int64_t error = mParser.GetTimecodeScale() / NS_PER_USEC; + return llabs(aLhs - aRhs) <= error * 2; + } + private: WebMBufferedParser mParser; nsTArray mOverlappedMapping; @@ -232,8 +257,8 @@ public: aData[7] == 'p'; } - virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength, - double& aStart, double& aEnd) + bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength, + int64_t& aStart, int64_t& aEnd) { bool initSegment = IsInitSegmentPresent(aData, aLength); if (initSegment) { @@ -266,9 +291,9 @@ public: if (compositionRange.IsNull()) { return false; } - aStart = static_cast(compositionRange.start) / USECS_PER_S; - aEnd = static_cast(compositionRange.end) / USECS_PER_S; - MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: [%f, %f]", + aStart = compositionRange.start; + aEnd = compositionRange.end; + MSE_DEBUG("MP4ContainerParser(%p)::ParseStartAndEndTimestamps: [%lld, %lld]", this, aStart, aEnd); return true; } @@ -591,13 +616,13 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR aRv.Throw(NS_ERROR_FAILURE); return; } - double start, end; + int64_t start, end; if (mParser->ParseStartAndEndTimestamps(aData, aLength, start, end)) { - double lastStart, lastEnd; + int64_t lastStart, lastEnd; mTrackBuffer->LastTimestamp(lastStart, lastEnd); if (mParser->IsMediaSegmentPresent(aData, aLength) && - (start < lastEnd || start - lastEnd > 0.1)) { - MSE_DEBUG("SourceBuffer(%p)::AppendData: Data last=[%f, %f] overlaps [%f, %f]", + !mParser->TimestampsFuzzyEqual(start, lastEnd)) { + MSE_DEBUG("SourceBuffer(%p)::AppendData: Data last=[%lld, %lld] overlaps [%lld, %lld]", this, lastStart, lastEnd, start, end); // This data is earlier in the timeline than data we have already @@ -616,7 +641,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR mTrackBuffer->SetLastStartTimestamp(start); } mTrackBuffer->SetLastEndTimestamp(end); - MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment last=[%f, %f] [%f, %f]", + MSE_DEBUG("SourceBuffer(%p)::AppendData: Segment last=[%lld, %lld] [%lld, %lld]", this, lastStart, lastEnd, start, end); } if (!mTrackBuffer->AppendData(aData, aLength)) { diff --git a/content/media/mediasource/TrackBuffer.cpp b/content/media/mediasource/TrackBuffer.cpp index 0b59526e00f1..231ca4c8a4ab 100644 --- a/content/media/mediasource/TrackBuffer.cpp +++ b/content/media/mediasource/TrackBuffer.cpp @@ -47,7 +47,7 @@ TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& a : mParentDecoder(aParentDecoder) , mType(aType) , mLastStartTimestamp(0) - , mLastEndTimestamp(UnspecifiedNaN()) + , mLastEndTimestamp(0) , mHasInit(false) , mHasAudio(false) , mHasVideo(false) @@ -177,7 +177,7 @@ TrackBuffer::NewDecoder() mDecoders.AppendElement(decoder); mLastStartTimestamp = 0; - mLastEndTimestamp = UnspecifiedNaN(); + mLastEndTimestamp = 0; mHasInit = true; return QueueInitializeDecoder(decoder); @@ -292,7 +292,7 @@ TrackBuffer::IsReady() } void -TrackBuffer::LastTimestamp(double& aStart, double& aEnd) +TrackBuffer::LastTimestamp(int64_t& aStart, int64_t& aEnd) { MOZ_ASSERT(NS_IsMainThread()); aStart = mLastStartTimestamp; @@ -300,14 +300,14 @@ TrackBuffer::LastTimestamp(double& aStart, double& aEnd) } void -TrackBuffer::SetLastStartTimestamp(double aStart) +TrackBuffer::SetLastStartTimestamp(int64_t aStart) { MOZ_ASSERT(NS_IsMainThread()); mLastStartTimestamp = aStart; } void -TrackBuffer::SetLastEndTimestamp(double aEnd) +TrackBuffer::SetLastEndTimestamp(int64_t aEnd) { MOZ_ASSERT(NS_IsMainThread()); mLastEndTimestamp = aEnd; diff --git a/content/media/mediasource/TrackBuffer.h b/content/media/mediasource/TrackBuffer.h index 0e379ea61382..a09ce4d6ad4b 100644 --- a/content/media/mediasource/TrackBuffer.h +++ b/content/media/mediasource/TrackBuffer.h @@ -64,9 +64,9 @@ public: bool IsReady(); // Query and update mLast{Start,End}Timestamp. - void LastTimestamp(double& aStart, double& aEnd); - void SetLastStartTimestamp(double aStart); - void SetLastEndTimestamp(double aEnd); + void LastTimestamp(int64_t& aStart, int64_t& aEnd); + void SetLastStartTimestamp(int64_t aStart); + void SetLastEndTimestamp(int64_t aEnd); // Returns true if any of the decoders managed by this track buffer // contain aTime in their buffered ranges. @@ -122,8 +122,8 @@ private: // The last start and end timestamps added to the TrackBuffer via // AppendData. Accessed on the main thread only. - double mLastStartTimestamp; - double mLastEndTimestamp; + int64_t mLastStartTimestamp; + int64_t mLastEndTimestamp; // Set when the initialization segment is first seen and cached (implied // by new decoder creation). Protected by mParentDecoder's monitor. From dd0bc2fbdeb6710e13411b0e4258601b583b2e10 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Wed, 10 Sep 2014 14:27:51 +1200 Subject: [PATCH 13/32] Bug 1065218 - Convert MediaSourceReader timestamp handling to int64_t/microseconds. r=karlt --- .../media/mediasource/MediaSourceReader.cpp | 39 +++++++++---------- content/media/mediasource/MediaSourceReader.h | 10 ++--- .../media/mediasource/SourceBufferDecoder.cpp | 12 ------ .../media/mediasource/SourceBufferDecoder.h | 3 -- content/media/mediasource/TrackBuffer.cpp | 4 +- content/media/mediasource/TrackBuffer.h | 2 +- 6 files changed, 26 insertions(+), 44 deletions(-) diff --git a/content/media/mediasource/MediaSourceReader.cpp b/content/media/mediasource/MediaSourceReader.cpp index 72e868d2a05c..7a4614000778 100644 --- a/content/media/mediasource/MediaSourceReader.cpp +++ b/content/media/mediasource/MediaSourceReader.cpp @@ -85,7 +85,7 @@ MediaSourceReader::RequestAudioData() return; } mAudioIsSeeking = false; - SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S); + SwitchAudioReader(mLastAudioTime); mAudioReader->RequestAudioData(); } @@ -119,7 +119,7 @@ MediaSourceReader::OnAudioEOS() { MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p (decoders=%u)", this, mAudioReader.get(), mAudioTrack->Decoders().Length()); - if (SwitchAudioReader(double(mLastAudioTime) / USECS_PER_S)) { + if (SwitchAudioReader(mLastAudioTime)) { // Success! Resume decoding with next audio decoder. RequestAudioData(); } else if (IsEnded()) { @@ -146,7 +146,7 @@ MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThres mDropVideoBeforeThreshold = true; } mVideoIsSeeking = false; - SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S); + SwitchVideoReader(mLastVideoTime); mVideoReader->RequestVideoData(aSkipToNextKeyframe, aTimeThreshold); } @@ -181,7 +181,7 @@ MediaSourceReader::OnVideoEOS() // End of stream. See if we can switch to another video decoder. MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p (decoders=%u)", this, mVideoReader.get(), mVideoTrack->Decoders().Length()); - if (SwitchVideoReader(double(mLastVideoTime) / USECS_PER_S)) { + if (SwitchVideoReader(mLastVideoTime)) { // Success! Resume decoding with next video decoder. RequestVideoData(false, 0); } else if (IsEnded()) { @@ -263,7 +263,7 @@ MediaSourceReader::CanSelectVideoReader(MediaDecoderReader* aNewReader) } already_AddRefed -MediaSourceReader::SelectReader(double aTarget, +MediaSourceReader::SelectReader(int64_t aTarget, bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*), const nsTArray>& aTrackDecoders) { @@ -283,8 +283,8 @@ MediaSourceReader::SelectReader(double aTarget, nsRefPtr ranges = new dom::TimeRanges(); aTrackDecoders[i]->GetBuffered(ranges); - if (ranges->Find(aTarget) == dom::TimeRanges::NoIndex) { - MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%f) newReader=%p target not in ranges=%s", + if (ranges->Find(double(aTarget) / USECS_PER_S) == dom::TimeRanges::NoIndex) { + MSE_DEBUGV("MediaSourceReader(%p)::SelectReader(%lld) newReader=%p target not in ranges=%s", this, aTarget, newReader.get(), DumpTimeRanges(ranges).get()); continue; } @@ -296,7 +296,7 @@ MediaSourceReader::SelectReader(double aTarget, } bool -MediaSourceReader::SwitchAudioReader(double aTarget) +MediaSourceReader::SwitchAudioReader(int64_t aTarget) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); // XXX: Can't handle adding an audio track after ReadMetadata. @@ -316,7 +316,7 @@ MediaSourceReader::SwitchAudioReader(double aTarget) } bool -MediaSourceReader::SwitchVideoReader(double aTarget) +MediaSourceReader::SwitchVideoReader(int64_t aTarget) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); // XXX: Can't handle adding a video track after ReadMetadata. @@ -439,22 +439,22 @@ private: }; void -MediaSourceReader::WaitForTimeRange(double aTime) +MediaSourceReader::WaitForTimeRange(int64_t aTime) { - MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%f)", this, aTime); + MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%lld)", this, aTime); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); // Loop until we have the requested time range in the active TrackBuffers. // Ideally, this wait loop would use an async request and callback // instead. Bug 1056441 covers that change. while (!TrackBuffersContainTime(aTime) && !IsShutdown() && !IsEnded()) { - MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%f) waiting", this, aTime); + MSE_DEBUG("MediaSourceReader(%p)::WaitForTimeRange(%lld) waiting", this, aTime); mon.Wait(); } } bool -MediaSourceReader::TrackBuffersContainTime(double aTime) +MediaSourceReader::TrackBuffersContainTime(int64_t aTime) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); if (mAudioTrack && !mAudioTrack->ContainsTime(aTime)) { @@ -482,13 +482,12 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, mLastAudioTime = aTime; mLastVideoTime = aTime; - double target = static_cast(aTime) / USECS_PER_S; - if (!TrackBuffersContainTime(target)) { - MSE_DEBUG("MediaSourceReader(%p)::Seek no active buffer contains target=%f", this, target); + if (!TrackBuffersContainTime(aTime)) { + MSE_DEBUG("MediaSourceReader(%p)::Seek no active buffer contains target=%lld", this, aTime); NS_DispatchToMainThread(new ChangeToHaveMetadata(mDecoder)); } - WaitForTimeRange(target); + WaitForTimeRange(aTime); if (IsShutdown()) { return NS_ERROR_FAILURE; @@ -496,8 +495,7 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, if (mAudioTrack) { mAudioIsSeeking = true; - SwitchAudioReader(target); - MOZ_ASSERT(static_cast(mAudioReader->GetDecoder())->ContainsTime(target)); + SwitchAudioReader(aTime); nsresult rv = mAudioReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime); MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p rv=%x", this, mAudioReader.get(), rv); if (NS_FAILED(rv)) { @@ -506,8 +504,7 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, } if (mVideoTrack) { mVideoIsSeeking = true; - SwitchVideoReader(target); - MOZ_ASSERT(static_cast(mVideoReader->GetDecoder())->ContainsTime(target)); + SwitchVideoReader(aTime); nsresult rv = mVideoReader->Seek(aTime, aStartTime, aEndTime, aCurrentTime); MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p rv=%x", this, mVideoReader.get(), rv); if (NS_FAILED(rv)) { diff --git a/content/media/mediasource/MediaSourceReader.h b/content/media/mediasource/MediaSourceReader.h index a2cf3d7f0fdd..7983debb01e5 100644 --- a/content/media/mediasource/MediaSourceReader.h +++ b/content/media/mediasource/MediaSourceReader.h @@ -93,7 +93,7 @@ public: } // Return true if all of the active tracks contain data for the specified time. - bool TrackBuffersContainTime(double aTime); + bool TrackBuffersContainTime(int64_t aTime); // Mark the reader to indicate that EndOfStream has been called on our MediaSource void Ended(); @@ -102,15 +102,15 @@ public: bool IsEnded(); private: - bool SwitchAudioReader(double aTarget); - bool SwitchVideoReader(double aTarget); + bool SwitchAudioReader(int64_t aTarget); + bool SwitchVideoReader(int64_t aTarget); // Return a reader from the set available in aTrackDecoders that is considered // usable by the aCanUserReader callback and has data available in the range // requested by aTarget. // aCanSelectReader is passed each reader available in aTrackDecoders and is // expected to return true if the reader is considerable selectable. - already_AddRefed SelectReader(double aTarget, + already_AddRefed SelectReader(int64_t aTarget, bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*), const nsTArray>& aTrackDecoders); @@ -124,7 +124,7 @@ private: // Waits on the decoder monitor for aTime to become available in the active // TrackBuffers. Used to block a Seek call until the necessary data has been // provided to the relevant SourceBuffers. - void WaitForTimeRange(double aTime); + void WaitForTimeRange(int64_t aTime); nsRefPtr mAudioReader; nsRefPtr mVideoReader; diff --git a/content/media/mediasource/SourceBufferDecoder.cpp b/content/media/mediasource/SourceBufferDecoder.cpp index a72465e5be4f..386d31c0e51e 100644 --- a/content/media/mediasource/SourceBufferDecoder.cpp +++ b/content/media/mediasource/SourceBufferDecoder.cpp @@ -236,16 +236,4 @@ SourceBufferDecoder::ConvertToByteOffset(double aTime) return offset; } -bool -SourceBufferDecoder::ContainsTime(double aTime) -{ - ErrorResult dummy; - nsRefPtr ranges = new dom::TimeRanges(); - nsresult rv = GetBuffered(ranges); - if (NS_FAILED(rv) || ranges->Length() == 0) { - return false; - } - return ranges->Find(aTime) != dom::TimeRanges::NoIndex; -} - } // namespace mozilla diff --git a/content/media/mediasource/SourceBufferDecoder.h b/content/media/mediasource/SourceBufferDecoder.h index b9eeba5018ad..c02336dffa4b 100644 --- a/content/media/mediasource/SourceBufferDecoder.h +++ b/content/media/mediasource/SourceBufferDecoder.h @@ -85,9 +85,6 @@ public: // cached data. Returns -1 if no such value is computable. int64_t ConvertToByteOffset(double aTime); - // Returns true if the data buffered by this decoder contains the given time. - bool ContainsTime(double aTime); - private: virtual ~SourceBufferDecoder(); diff --git a/content/media/mediasource/TrackBuffer.cpp b/content/media/mediasource/TrackBuffer.cpp index 231ca4c8a4ab..3f08ece73d19 100644 --- a/content/media/mediasource/TrackBuffer.cpp +++ b/content/media/mediasource/TrackBuffer.cpp @@ -314,13 +314,13 @@ TrackBuffer::SetLastEndTimestamp(int64_t aEnd) } bool -TrackBuffer::ContainsTime(double aTime) +TrackBuffer::ContainsTime(int64_t aTime) { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); for (uint32_t i = 0; i < mInitializedDecoders.Length(); ++i) { nsRefPtr r = new dom::TimeRanges(); mInitializedDecoders[i]->GetBuffered(r); - if (r->Find(aTime) != dom::TimeRanges::NoIndex) { + if (r->Find(double(aTime) / USECS_PER_S) != dom::TimeRanges::NoIndex) { return true; } } diff --git a/content/media/mediasource/TrackBuffer.h b/content/media/mediasource/TrackBuffer.h index a09ce4d6ad4b..47168571e541 100644 --- a/content/media/mediasource/TrackBuffer.h +++ b/content/media/mediasource/TrackBuffer.h @@ -70,7 +70,7 @@ public: // Returns true if any of the decoders managed by this track buffer // contain aTime in their buffered ranges. - bool ContainsTime(double aTime); + bool ContainsTime(int64_t aTime); void BreakCycles(); From 6393ec70b5e9bbb30cd198439834d5375d563311 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Wed, 10 Sep 2014 14:21:17 +1200 Subject: [PATCH 14/32] Bug 1065219 - Move track format rejection from switch to init time. r=cajbir --- .../media/mediasource/MediaSourceReader.cpp | 51 +--------------- content/media/mediasource/MediaSourceReader.h | 15 +---- content/media/mediasource/TrackBuffer.cpp | 60 ++++++++++++++----- content/media/mediasource/TrackBuffer.h | 18 ++++-- 4 files changed, 63 insertions(+), 81 deletions(-) diff --git a/content/media/mediasource/MediaSourceReader.cpp b/content/media/mediasource/MediaSourceReader.cpp index 7a4614000778..41daa2988477 100644 --- a/content/media/mediasource/MediaSourceReader.cpp +++ b/content/media/mediasource/MediaSourceReader.cpp @@ -227,44 +227,8 @@ MediaSourceReader::BreakCycles() mTrackBuffers.Clear(); } -bool -MediaSourceReader::CanSelectAudioReader(MediaDecoderReader* aNewReader) -{ - AudioInfo currentInfo = mAudioReader->GetMediaInfo().mAudio; - AudioInfo newInfo = aNewReader->GetMediaInfo().mAudio; - - // TODO: We can't handle switching audio formats yet. - if (currentInfo.mRate != newInfo.mRate || - currentInfo.mChannels != newInfo.mChannels) { - MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to format mismatch", - this, aNewReader); - return false; - } - - if (aNewReader->AudioQueue().AtEndOfStream()) { - MSE_DEBUGV("MediaSourceReader(%p)::CanSelectAudioReader(%p) skip reader due to queue EOS", - this, aNewReader); - return false; - } - - return true; -} - -bool -MediaSourceReader::CanSelectVideoReader(MediaDecoderReader* aNewReader) -{ - if (aNewReader->VideoQueue().AtEndOfStream()) { - MSE_DEBUGV("MediaSourceReader(%p)::CanSelectVideoReader(%p) skip reader due to queue EOS", - this, aNewReader); - return false; - } - - return true; -} - already_AddRefed MediaSourceReader::SelectReader(int64_t aTarget, - bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*), const nsTArray>& aTrackDecoders) { mDecoder->GetReentrantMonitor().AssertCurrentThreadIn(); @@ -274,13 +238,6 @@ MediaSourceReader::SelectReader(int64_t aTarget, for (int32_t i = aTrackDecoders.Length() - 1; i >= 0; --i) { nsRefPtr newReader = aTrackDecoders[i]->GetReader(); - // Check the track-type-specific aspects first, as it's assumed these - // are cheaper than a buffered range comparison, which seems worthwhile - // to avoid on any reader we'd subsequently reject. - if (!(this->*aCanSelectReader)(newReader)) { - continue; - } - nsRefPtr ranges = new dom::TimeRanges(); aTrackDecoders[i]->GetBuffered(ranges); if (ranges->Find(double(aTarget) / USECS_PER_S) == dom::TimeRanges::NoIndex) { @@ -303,9 +260,7 @@ MediaSourceReader::SwitchAudioReader(int64_t aTarget) if (!mAudioTrack) { return false; } - nsRefPtr newReader = SelectReader(aTarget, - &MediaSourceReader::CanSelectAudioReader, - mAudioTrack->Decoders()); + nsRefPtr newReader = SelectReader(aTarget, mAudioTrack->Decoders()); if (newReader && newReader != mAudioReader) { mAudioReader->SetIdle(); mAudioReader = newReader; @@ -323,9 +278,7 @@ MediaSourceReader::SwitchVideoReader(int64_t aTarget) if (!mVideoTrack) { return false; } - nsRefPtr newReader = SelectReader(aTarget, - &MediaSourceReader::CanSelectVideoReader, - mVideoTrack->Decoders()); + nsRefPtr newReader = SelectReader(aTarget, mVideoTrack->Decoders()); if (newReader && newReader != mVideoReader) { mVideoReader->SetIdle(); mVideoReader = newReader; diff --git a/content/media/mediasource/MediaSourceReader.h b/content/media/mediasource/MediaSourceReader.h index 7983debb01e5..f7ca11f842a8 100644 --- a/content/media/mediasource/MediaSourceReader.h +++ b/content/media/mediasource/MediaSourceReader.h @@ -105,22 +105,11 @@ private: bool SwitchAudioReader(int64_t aTarget); bool SwitchVideoReader(int64_t aTarget); - // Return a reader from the set available in aTrackDecoders that is considered - // usable by the aCanUserReader callback and has data available in the range - // requested by aTarget. - // aCanSelectReader is passed each reader available in aTrackDecoders and is - // expected to return true if the reader is considerable selectable. + // Return a reader from the set available in aTrackDecoders that has data + // available in the range requested by aTarget. already_AddRefed SelectReader(int64_t aTarget, - bool (MediaSourceReader::*aCanSelectReader)(MediaDecoderReader*), const nsTArray>& aTrackDecoders); - // Passed to SelectReader to enforce any track format specific requirements. - // In the case of CanSelectAudioReader, verifies that aNewReader has a - // matching audio format to the existing reader, as format switching is not - // yet supported. - bool CanSelectAudioReader(MediaDecoderReader* aNewReader); - bool CanSelectVideoReader(MediaDecoderReader* aNewReader); - // Waits on the decoder monitor for aTime to become available in the active // TrackBuffers. Used to block a Seek call until the necessary data has been // provided to the relevant SourceBuffers. diff --git a/content/media/mediasource/TrackBuffer.cpp b/content/media/mediasource/TrackBuffer.cpp index 3f08ece73d19..98cbac42837c 100644 --- a/content/media/mediasource/TrackBuffer.cpp +++ b/content/media/mediasource/TrackBuffer.cpp @@ -49,8 +49,6 @@ TrackBuffer::TrackBuffer(MediaSourceDecoder* aParentDecoder, const nsACString& a , mLastStartTimestamp(0) , mLastEndTimestamp(0) , mHasInit(false) - , mHasAudio(false) - , mHasVideo(false) { MOZ_COUNT_CTOR(TrackBuffer); mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool()); @@ -218,11 +216,7 @@ TrackBuffer::InitializeDecoder(nsRefPtr aDecoder) MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d", this, reader, rv, mi.HasAudio(), mi.HasVideo()); aDecoder->SetTaskQueue(nullptr); - { - ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - mDecoders.RemoveElement(aDecoder); - } - NS_DispatchToMainThread(new ReleaseDecoderTask(aDecoder)); + RemoveDecoder(aDecoder); return; } @@ -235,11 +229,36 @@ TrackBuffer::InitializeDecoder(nsRefPtr aDecoder) this, reader, mi.mAudio.mRate, mi.mAudio.mChannels); } + if (!RegisterDecoder(aDecoder)) { + // XXX: Need to signal error back to owning SourceBuffer. + MSE_DEBUG("TrackBuffer(%p): Reader %p not activated", this, reader); + RemoveDecoder(aDecoder); + return; + } MSE_DEBUG("TrackBuffer(%p): Reader %p activated", this, reader); - RegisterDecoder(aDecoder); } -void +bool +TrackBuffer::ValidateTrackFormats(const MediaInfo& aInfo) +{ + if (mInfo.HasAudio() != aInfo.HasAudio() || + mInfo.HasVideo() != aInfo.HasVideo()) { + MSE_DEBUG("TrackBuffer(%p)::ValidateTrackFormats audio/video track mismatch", this); + return false; + } + + // TODO: Support dynamic audio format changes. + if (mInfo.HasAudio() && + (mInfo.mAudio.mRate != aInfo.mAudio.mRate || + mInfo.mAudio.mChannels != aInfo.mAudio.mChannels)) { + MSE_DEBUG("TrackBuffer(%p)::ValidateTrackFormats audio format mismatch", this); + return false; + } + + return true; +} + +bool TrackBuffer::RegisterDecoder(nsRefPtr aDecoder) { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); @@ -247,14 +266,16 @@ TrackBuffer::RegisterDecoder(nsRefPtr aDecoder) const MediaInfo& info = aDecoder->GetReader()->GetMediaInfo(); // Initialize the track info since this is the first decoder. if (mInitializedDecoders.IsEmpty()) { - mHasAudio = info.HasAudio(); - mHasVideo = info.HasVideo(); - mParentDecoder->OnTrackBufferConfigured(this, info); - } else if ((info.HasAudio() && !mHasAudio) || (info.HasVideo() && !mHasVideo)) { + mInfo = info; + mParentDecoder->OnTrackBufferConfigured(this, mInfo); + } + if (!ValidateTrackFormats(info)) { MSE_DEBUG("TrackBuffer(%p)::RegisterDecoder with mismatched audio/video tracks", this); + return false; } mInitializedDecoders.AppendElement(aDecoder); mParentDecoder->NotifyTimeRangesChanged(); + return true; } void @@ -287,8 +308,8 @@ bool TrackBuffer::IsReady() { ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); - MOZ_ASSERT((mHasAudio || mHasVideo) || mInitializedDecoders.IsEmpty()); - return HasInitSegment() && (mHasAudio || mHasVideo); + MOZ_ASSERT((mInfo.HasAudio() || mInfo.HasVideo()) || mInitializedDecoders.IsEmpty()); + return HasInitSegment() && (mInfo.HasAudio() || mInfo.HasVideo()); } void @@ -373,4 +394,13 @@ TrackBuffer::Dump(const char* aPath) } #endif +void +TrackBuffer::RemoveDecoder(nsRefPtr aDecoder) +{ + ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor()); + MOZ_ASSERT(!mInitializedDecoders.Contains(aDecoder)); + mDecoders.RemoveElement(aDecoder); + NS_DispatchToMainThread(new ReleaseDecoderTask(aDecoder)); +} + } // namespace mozilla diff --git a/content/media/mediasource/TrackBuffer.h b/content/media/mediasource/TrackBuffer.h index 47168571e541..cce638bc5f01 100644 --- a/content/media/mediasource/TrackBuffer.h +++ b/content/media/mediasource/TrackBuffer.h @@ -98,8 +98,19 @@ private: // Adds a successfully initialized decoder to mDecoders and (if it's the // first decoder initialized), initializes mHasAudio/mHasVideo. Called - // from the decode thread pool. - void RegisterDecoder(nsRefPtr aDecoder); + // from the decode thread pool. Return true if the decoder was + // successfully registered. + bool RegisterDecoder(nsRefPtr aDecoder); + + // Returns true if aInfo is considered a supported or the same format as + // the TrackBuffer was initialized as. + bool ValidateTrackFormats(const MediaInfo& aInfo); + + // Remove aDecoder from mDecoders and dispatch an event to the main thread + // to clean up the decoder. If aDecoder was added to + // mInitializedDecoders, it must have been removed before calling this + // function. + void RemoveDecoder(nsRefPtr aDecoder); // A task queue using the shared media thread pool. Used exclusively to // initialize (i.e. call ReadMetadata on) decoders as they are created via @@ -131,8 +142,7 @@ private: // Set when the first decoder used by this TrackBuffer is initialized. // Protected by mParentDecoder's monitor. - bool mHasAudio; - bool mHasVideo; + MediaInfo mInfo; }; } // namespace mozilla From ba4e7fa834609cb61664c492473bfdb6b1394255 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Wed, 10 Sep 2014 10:51:28 +1200 Subject: [PATCH 15/32] Bug 1064705 - Don't treat EOS as fatal when reading optional block subelements in nestegg_read_packet. r=cajbir --- .../mediasource/test/test_MediaSource.html | 5 +- .../mediasource/test/test_SplitAppend.html | 5 +- .../test/test_SplitAppendDelay.html | 5 +- media/libnestegg/README_MOZILLA | 2 +- media/libnestegg/include/nestegg.h | 14 ++ media/libnestegg/src/nestegg.c | 228 ++++++++++++++++-- 6 files changed, 238 insertions(+), 21 deletions(-) diff --git a/content/media/mediasource/test/test_MediaSource.html b/content/media/mediasource/test/test_MediaSource.html index 20d563906048..4e4e4dd77b9d 100644 --- a/content/media/mediasource/test/test_MediaSource.html +++ b/content/media/mediasource/test/test_MediaSource.html @@ -72,8 +72,9 @@ runWithMSE(function () { }); v.addEventListener("ended", function () { - is(v.duration, 4, "Video has correct duration"); - is(v.currentTime, 4, "Video has played to end"); + // XXX: Duration should be exactly 4.0, see bug 1065207. + is(v.duration, 4.001, "Video has correct duration"); + is(v.currentTime, 4.001, "Video has played to end"); v.parentNode.removeChild(v); SimpleTest.finish(); }); diff --git a/content/media/mediasource/test/test_SplitAppend.html b/content/media/mediasource/test/test_SplitAppend.html index 34070c456e8b..dac91e21fcc9 100644 --- a/content/media/mediasource/test/test_SplitAppend.html +++ b/content/media/mediasource/test/test_SplitAppend.html @@ -32,8 +32,9 @@ runWithMSE(function (ms, v) { }); v.addEventListener("ended", function () { - is(v.duration, 4, "Video has correct duration"); - is(v.currentTime, 4, "Video has played to end"); + // XXX: Duration should be exactly 4.0, see bug 1065207. + is(v.duration, 4.001, "Video has correct duration"); + is(v.currentTime, 4.001, "Video has played to end"); SimpleTest.finish(); }); }); diff --git a/content/media/mediasource/test/test_SplitAppendDelay.html b/content/media/mediasource/test/test_SplitAppendDelay.html index 9bf26e6dc6be..971c321b93e4 100644 --- a/content/media/mediasource/test/test_SplitAppendDelay.html +++ b/content/media/mediasource/test/test_SplitAppendDelay.html @@ -34,8 +34,9 @@ runWithMSE(function (ms, v) { }); v.addEventListener("ended", function () { - is(v.duration, 4, "Video has correct duration"); - is(v.currentTime, 4, "Video has played to end"); + // XXX: Duration should be exactly 4.0, see bug 1065207. + is(v.duration, 4.001, "Video has correct duration"); + is(v.currentTime, 4.001, "Video has played to end"); SimpleTest.finish(); }); }); diff --git a/media/libnestegg/README_MOZILLA b/media/libnestegg/README_MOZILLA index 7fe4676a3215..c7857bbdbe88 100644 --- a/media/libnestegg/README_MOZILLA +++ b/media/libnestegg/README_MOZILLA @@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system. The nestegg git repository is: git://github.com/kinetiknz/nestegg.git -The git commit ID used was 276ccd80e723b0edaf0ef42dbacb5a3a42e02d5c. +The git commit ID used was 46ab96bcc8b099704cc8a15993f80fe0269a5284. diff --git a/media/libnestegg/include/nestegg.h b/media/libnestegg/include/nestegg.h index ca588d05bc84..06f9c83b8772 100644 --- a/media/libnestegg/include/nestegg.h +++ b/media/libnestegg/include/nestegg.h @@ -133,6 +133,7 @@ typedef struct { unsigned int crop_top; /**< Pixels to crop from the top of the frame. */ unsigned int crop_left; /**< Pixels to crop from the left of the frame. */ unsigned int crop_right; /**< Pixels to crop from the right of the frame. */ + unsigned int alpha_mode; /**< 1 if an additional opacity stream is available, otherwise 0. */ } nestegg_video_params; /** Parameters specific to an audio track. */ @@ -340,6 +341,19 @@ int nestegg_packet_count(nestegg_packet * packet, unsigned int * count); int nestegg_packet_data(nestegg_packet * packet, unsigned int item, unsigned char ** data, size_t * length); +/** Get a pointer to additional data with identifier @a id of additional packet + data. If @a id isn't present in the packet, returns -1. + @param packet Packet initialized by #nestegg_read_packet. + @param id Codec specific identifer. For VP8, use 1 to get a VP8 encoded + frame containing an alpha channel in its Y plane. + @param data Storage for the queried data pointer. + The data is owned by the #nestegg_packet packet. + @param length Storage for the queried data size. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_packet_additional_data(nestegg_packet * packet, unsigned int id, + unsigned char ** data, size_t * length); + /** Returns discard_padding for given packet @param packet Packet initialized by #nestegg_read_packet. @param discard_padding pointer to store discard padding in. diff --git a/media/libnestegg/src/nestegg.c b/media/libnestegg/src/nestegg.c index 8813cf2941cd..f74ba04bc870 100644 --- a/media/libnestegg/src/nestegg.c +++ b/media/libnestegg/src/nestegg.c @@ -47,10 +47,18 @@ /* BlockGroup Elements */ #define ID_BLOCK 0xa1 +#define ID_BLOCK_ADDITIONS 0x75a1 #define ID_BLOCK_DURATION 0x9b #define ID_REFERENCE_BLOCK 0xfb #define ID_DISCARD_PADDING 0x75a2 +/* BlockAdditions Elements */ +#define ID_BLOCK_MORE 0xa6 + +/* BlockMore Elements */ +#define ID_BLOCK_ADD_ID 0xee +#define ID_BLOCK_ADDITIONAL 0xa5 + /* Tracks Elements */ #define ID_TRACKS 0x1654ae6b #define ID_TRACK_ENTRY 0xae @@ -71,6 +79,7 @@ /* Video Elements */ #define ID_VIDEO 0xe0 #define ID_STEREO_MODE 0x53b8 +#define ID_ALPHA_MODE 0x53c0 #define ID_PIXEL_WIDTH 0xb0 #define ID_PIXEL_HEIGHT 0xba #define ID_PIXEL_CROP_BOTTOM 0x54aa @@ -195,7 +204,17 @@ struct info { struct ebml_type duration; }; +struct block_more { + struct ebml_type block_add_id; + struct ebml_type block_additional; +}; + +struct block_additions { + struct ebml_list block_more; +}; + struct block_group { + struct ebml_type block_additions; struct ebml_type duration; struct ebml_type reference_block; struct ebml_type discard_padding; @@ -208,6 +227,7 @@ struct cluster { struct video { struct ebml_type stereo_mode; + struct ebml_type alpha_mode; struct ebml_type pixel_width; struct ebml_type pixel_height; struct ebml_type pixel_crop_bottom; @@ -294,6 +314,13 @@ struct frame { struct frame * next; }; +struct block_additional { + unsigned int id; + unsigned char * data; + size_t length; + struct block_additional * next; +}; + /* Public (opaque) Structures */ struct nestegg { nestegg_io * io; @@ -314,6 +341,7 @@ struct nestegg_packet { uint64_t timecode; uint64_t duration; struct frame * frame; + struct block_additional * block_additional; int64_t discard_padding; }; @@ -374,11 +402,23 @@ static struct ebml_element_desc ne_info_elements[] = { E_LAST }; +static struct ebml_element_desc ne_block_more_elements[] = { + E_FIELD(ID_BLOCK_ADD_ID, TYPE_UINT, struct block_more, block_add_id), + E_FIELD(ID_BLOCK_ADDITIONAL, TYPE_BINARY, struct block_more, block_additional), + E_LAST +}; + +static struct ebml_element_desc ne_block_additions_elements[] = { + E_MASTER(ID_BLOCK_MORE, TYPE_MASTER, struct block_additions, block_more), + E_LAST +}; + static struct ebml_element_desc ne_block_group_elements[] = { E_SUSPEND(ID_BLOCK, TYPE_BINARY), E_FIELD(ID_BLOCK_DURATION, TYPE_UINT, struct block_group, duration), E_FIELD(ID_REFERENCE_BLOCK, TYPE_INT, struct block_group, reference_block), E_FIELD(ID_DISCARD_PADDING, TYPE_INT, struct block_group, discard_padding), + E_SINGLE_MASTER(ID_BLOCK_ADDITIONS, TYPE_MASTER, struct block_group, block_additions), E_LAST }; @@ -391,6 +431,7 @@ static struct ebml_element_desc ne_cluster_elements[] = { static struct ebml_element_desc ne_video_elements[] = { E_FIELD(ID_STEREO_MODE, TYPE_UINT, struct video, stereo_mode), + E_FIELD(ID_ALPHA_MODE, TYPE_UINT, struct video, alpha_mode), E_FIELD(ID_PIXEL_WIDTH, TYPE_UINT, struct video, pixel_width), E_FIELD(ID_PIXEL_HEIGHT, TYPE_UINT, struct video, pixel_height), E_FIELD(ID_PIXEL_CROP_BOTTOM, TYPE_UINT, struct video, pixel_crop_bottom), @@ -689,14 +730,16 @@ ne_read_string(nestegg * ctx, char ** val, uint64_t length) char * str; int r; - if (length == 0 || length > LIMIT_STRING) + if (length > LIMIT_STRING) return -1; str = ne_pool_alloc(length + 1, ctx->alloc_pool); if (!str) return -1; - r = ne_io_read(ctx->io, (unsigned char *) str, length); - if (r != 1) - return r; + if (length) { + r = ne_io_read(ctx->io, (unsigned char *) str, length); + if (r != 1) + return r; + } str[length] = '\0'; *val = str; return 1; @@ -1420,6 +1463,7 @@ ne_read_block_duration(nestegg * ctx, nestegg_packet * pkt) r = ne_read_simple(ctx, element, size); if (r != 1) return r; + storage = (struct ebml_type *) (ctx->ancestor->data + element->offset); pkt->duration = storage->v.i * ne_get_timecode_scale(ctx); @@ -1448,12 +1492,123 @@ ne_read_discard_padding(nestegg * ctx, nestegg_packet * pkt) r = ne_read_simple(ctx, element, size); if (r != 1) return r; + storage = (struct ebml_type *) (ctx->ancestor->data + element->offset); pkt->discard_padding = storage->v.i; return 1; } +static int +ne_read_block_additions(nestegg * ctx, nestegg_packet * pkt) +{ + int r; + uint64_t id, size, data_size; + int64_t block_additions_end, block_more_end; + void * data; + int has_data; + struct block_additional * block_additional; + uint64_t add_id; + + assert(pkt != NULL); + assert(pkt->block_additional == NULL); + + r = ne_peek_element(ctx, &id, &size); + if (r != 1) + return r; + + if (id != ID_BLOCK_ADDITIONS) + return 1; + + /* This makes ne_read_element read the next element instead of returning + information about the already "peeked" one. */ + ctx->last_valid = 0; + + block_additions_end = ne_io_tell(ctx->io) + size; + + while (ne_io_tell(ctx->io) < block_additions_end) { + add_id = 1; + data = NULL; + has_data = 0; + r = ne_read_element(ctx, &id, &size); + if (r != 1) + return -1; + + if (id != ID_BLOCK_MORE) { + /* We don't know what this element is, so skip over it */ + if (id != ID_VOID && id != ID_CRC32) + ctx->log(ctx, NESTEGG_LOG_DEBUG, + "unknown element %llx in BlockAdditions", id); + ne_io_read_skip(ctx->io, size); + continue; + } + + block_more_end = ne_io_tell(ctx->io) + size; + + while (ne_io_tell(ctx->io) < block_more_end) { + r = ne_read_element(ctx, &id, &size); + if (r != 1) { + free(data); + return r; + } + + if (id == ID_BLOCK_ADD_ID) { + r = ne_read_uint(ctx->io, &add_id, size); + if (r != 1) { + free(data); + return r; + } + + if (add_id == 0) { + ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed BlockAddId 0 used"); + free(data); + return -1; + } + } else if (id == ID_BLOCK_ADDITIONAL) { + if (has_data) { + /* BlockAdditional is supposed to only occur once in a + BlockMore. */ + ctx->log(ctx, NESTEGG_LOG_ERROR, + "Multiple BlockAdditional elements in a BlockMore"); + free(data); + return -1; + } + + has_data = 1; + data_size = size; + if (size != 0) { + data = ne_alloc(size); + r = ne_io_read(ctx->io, data, size); + if (r != 1) { + free(data); + return r; + } + } + } else { + /* We don't know what this element is, so skip over it */ + if (id != ID_VOID && id != ID_CRC32) + ctx->log(ctx, NESTEGG_LOG_DEBUG, + "unknown element %llx in BlockMore", id); + ne_io_read_skip(ctx->io, size); + } + } + + if (has_data == 0) { + ctx->log(ctx, NESTEGG_LOG_ERROR, + "No BlockAdditional element in a BlockMore"); + return -1; + } + + block_additional = ne_alloc(sizeof(*block_additional)); + block_additional->next = pkt->block_additional; + block_additional->id = add_id; + block_additional->data = data; + block_additional->length = data_size; + pkt->block_additional = block_additional; + } + + return 1; +} static uint64_t ne_buf_read_id(unsigned char const * p, size_t length) @@ -1727,8 +1882,8 @@ ne_match_webm(nestegg_io io, int64_t max_offset) ne_ctx_push(ctx, ne_top_level_elements, ctx); /* we don't check the return value of ne_parse, that might fail because - * max_offset is not on a valid element end point. We only want to check - * the EBML ID and that the doctype is "webm". */ + max_offset is not on a valid element end point. We only want to check + the EBML ID and that the doctype is "webm". */ ne_parse(ctx, NULL, max_offset); if (ne_get_string(ctx->ebml.doctype, &doctype) != 0 || @@ -2168,6 +2323,10 @@ nestegg_track_video_params(nestegg * ctx, unsigned int track, value == NESTEGG_VIDEO_STEREO_RIGHT_LEFT) params->stereo_mode = value; + value = 0; + ne_get_uint(entry->video.alpha_mode, &value); + params->alpha_mode = value; + if (ne_get_uint(entry->video.pixel_width, &value) != 0) return -1; params->width = value; @@ -2262,7 +2421,7 @@ nestegg_track_default_duration(nestegg * ctx, unsigned int track, int nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) { - int r; + int r, read_block = 0; uint64_t id, size; *pkt = NULL; @@ -2284,15 +2443,27 @@ nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) if (r != 1) return r; - r = ne_read_block_duration(ctx, *pkt); - if (r != 1) - return r; + read_block = 1; - r = ne_read_discard_padding(ctx, *pkt); - if (r != 1) - return r; + /* These are not valid elements of a SimpleBlock, only a full-blown + Block. */ + if (id != ID_SIMPLE_BLOCK) { + r = ne_read_block_duration(ctx, *pkt); + if (r < 0) + return r; - return r; + r = ne_read_discard_padding(ctx, *pkt); + if (r < 0) + return r; + + r = ne_read_block_additions(ctx, *pkt); + if (r < 0) + return r; + } + + /* If we have read a block and hit EOS when reading optional block + subelements, don't report EOS until the next call. */ + return read_block; } r = ne_parse(ctx, NULL, -1); @@ -2307,6 +2478,7 @@ void nestegg_free_packet(nestegg_packet * pkt) { struct frame * frame; + struct block_additional * block_additional; while (pkt->frame) { frame = pkt->frame; @@ -2315,6 +2487,13 @@ nestegg_free_packet(nestegg_packet * pkt) free(frame); } + while (pkt->block_additional) { + block_additional = pkt->block_additional; + pkt->block_additional = block_additional->next; + free(block_additional->data); + free(block_additional); + } + free(pkt); } @@ -2384,6 +2563,27 @@ nestegg_packet_data(nestegg_packet * pkt, unsigned int item, return -1; } +int +nestegg_packet_additional_data(nestegg_packet * pkt, unsigned int id, + unsigned char ** data, size_t * length) +{ + struct block_additional * a = pkt->block_additional; + + *data = NULL; + *length = 0; + + while (a) { + if (a->id == id) { + *data = a->data; + *length = a->length; + return 0; + } + a = a->next; + } + + return -1; +} + int nestegg_has_cues(nestegg * ctx) { From d7d1af4ae190ea1721552a75ddb5c64eebb0e75c Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 15 Sep 2014 16:30:45 -0700 Subject: [PATCH 16/32] Bug 1001090 - Part 1: Implement let temporal dead zone in the frontend and interpreter. (r=Waldo) --- js/public/Value.h | 2 + js/src/frontend/BytecodeCompiler.cpp | 22 +- js/src/frontend/BytecodeEmitter.cpp | 376 +++++++++++----- js/src/frontend/BytecodeEmitter.h | 10 +- js/src/frontend/FullParseHandler.h | 23 +- js/src/frontend/ParseNode.cpp | 3 +- js/src/frontend/ParseNode.h | 5 +- js/src/frontend/Parser.cpp | 413 ++++++++++++++---- js/src/frontend/Parser.h | 37 +- js/src/frontend/SharedContext.h | 3 + js/src/frontend/SyntaxParseHandler.h | 3 + .../tests/arguments/alias-function-closed.js | 2 +- .../arguments/alias-function-not-closed.js | 2 +- js/src/jit-test/tests/basic/bug1001090-1.js | 2 + js/src/jit-test/tests/basic/bug1001090-2.js | 5 + js/src/jit-test/tests/basic/bug1001090-3.js | 27 ++ js/src/jit-test/tests/basic/bug1001090-4.js | 30 ++ js/src/jit-test/tests/basic/bug1001090-5.js | 6 + js/src/jit-test/tests/basic/bug1001090-6.js | 7 + .../tests/basic/letLegacyForOfOrInScope.js | 5 + .../tests/basic/letTDZAfterInitializer.js | 19 + .../basic/testFunctionStatementAliasLocals.js | 10 - js/src/jit-test/tests/basic/testLet.js | 84 ++-- .../tests/debug/Environment-variables.js | 2 - js/src/jit-test/tests/debug/Frame-eval-21.js | 3 + js/src/jit-test/tests/jaeger/bug583672.js | 4 +- js/src/jit-test/tests/parallel/write-array.js | 2 +- js/src/jit-test/tests/parallel/write-obj.js | 2 +- js/src/jit/BaselineFrame.cpp | 14 +- js/src/jit/BaselineIC.cpp | 3 +- js/src/jit/CompileInfo.h | 20 +- js/src/jit/IonCaches.cpp | 3 +- js/src/js.msg | 1 + js/src/jsinferinlines.h | 5 +- js/src/jsobj.cpp | 27 +- js/src/jsobj.h | 7 +- js/src/jsopcode.cpp | 2 +- js/src/jsscript.cpp | 99 +++-- js/src/jsscript.h | 88 +++- .../tests/js1_7/block/order-of-operation.js | 3 +- js/src/tests/js1_7/block/regress-411279.js | 56 --- .../js1_8_1/extensions/regress-353214-02.js | 4 +- .../js1_8_1/regress/regress-452498-103.js | 31 -- js/src/vm/CommonPropertyNames.h | 1 + js/src/vm/Debugger.cpp | 16 +- js/src/vm/Debugger.h | 4 + js/src/vm/Interpreter-inl.h | 73 ++++ js/src/vm/Interpreter.cpp | 200 +++++++-- js/src/vm/Interpreter.h | 9 + js/src/vm/Opcodes.h | 54 ++- js/src/vm/ScopeObject-inl.h | 9 + js/src/vm/ScopeObject.cpp | 9 +- js/src/vm/ScopeObject.h | 2 + js/src/vm/Stack-inl.h | 17 +- js/src/vm/Stack.cpp | 8 +- js/src/vm/Stack.h | 9 +- 56 files changed, 1384 insertions(+), 499 deletions(-) create mode 100644 js/src/jit-test/tests/basic/bug1001090-1.js create mode 100644 js/src/jit-test/tests/basic/bug1001090-2.js create mode 100644 js/src/jit-test/tests/basic/bug1001090-3.js create mode 100644 js/src/jit-test/tests/basic/bug1001090-4.js create mode 100644 js/src/jit-test/tests/basic/bug1001090-5.js create mode 100644 js/src/jit-test/tests/basic/bug1001090-6.js create mode 100644 js/src/jit-test/tests/basic/letLegacyForOfOrInScope.js create mode 100644 js/src/jit-test/tests/basic/letTDZAfterInitializer.js delete mode 100644 js/src/tests/js1_7/block/regress-411279.js delete mode 100644 js/src/tests/js1_8_1/regress/regress-452498-103.js diff --git a/js/public/Value.h b/js/public/Value.h index cff31d3f3c45..05acd7a55e7f 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -242,6 +242,8 @@ typedef enum JSWhyMagic JS_ION_ERROR, /* error while running Ion code */ JS_ION_BAILOUT, /* missing recover instruction result */ JS_OPTIMIZED_OUT, /* optimized out slot */ + JS_UNINITIALIZED_LEXICAL, /* uninitialized lexical bindings that produce ReferenceError + * on touch. */ JS_GENERIC_MAGIC /* for local use */ } JSWhyMagic; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index 642619a0b71e..452a36e49d0c 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -291,7 +291,8 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco BytecodeEmitter::EmitterMode emitterMode = options.selfHostingMode ? BytecodeEmitter::SelfHosting : BytecodeEmitter::Normal; - BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script, options.forEval, + BytecodeEmitter bce(/* parent = */ nullptr, &parser, &globalsc, script, + /* lazyScript = */ js::NullPtr(), options.forEval, evalCaller, !!globalScope, options.lineno, emitterMode); if (!bce.init()) return nullptr; @@ -436,9 +437,11 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco // locals, however, which are allocated to the fixed part of the stack // frame. InternalHandle bindings(script, &script->bindings); - if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, nullptr, - pc->blockScopeDepth)) + if (!Bindings::initWithTemporaryStorage(cx, bindings, 0, 0, 0, + pc->blockScopeDepth, nullptr)) + { return nullptr; + } if (!JSScript::fullyInitFromEmitter(cx, script, &bce)) return nullptr; @@ -509,15 +512,13 @@ frontend::CompileLazyFunction(JSContext *cx, Handle lazy, const cha if (lazy->hasBeenCloned()) script->setHasBeenCloned(); - BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, options.forEval, - /* evalCaller = */ NullPtr(), /* hasGlobalScope = */ true, - options.lineno, BytecodeEmitter::LazyFunction); + BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy, + options.forEval, /* evalCaller = */ js::NullPtr(), + /* hasGlobalScope = */ true, options.lineno, + BytecodeEmitter::LazyFunction); if (!bce.init()) return false; - if (lazy->treatAsRunOnce()) - bce.lazyRunOnceLambda = true; - return EmitFunctionScript(cx, &bce, pn->pn_body); } @@ -632,7 +633,8 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp * instead is cloned immediately onto the right scope chain. */ BytecodeEmitter funbce(/* parent = */ nullptr, &parser, fn->pn_funbox, script, - /* insideEval = */ false, /* evalCaller = */ js::NullPtr(), + /* lazyScript = */ js::NullPtr(), /* insideEval = */ false, + /* evalCaller = */ js::NullPtr(), fun->environment() && fun->environment()->is(), options.lineno); if (!funbce.init()) diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp index 39e39946f385..deab2d22fc54 100644 --- a/js/src/frontend/BytecodeEmitter.cpp +++ b/js/src/frontend/BytecodeEmitter.cpp @@ -31,6 +31,7 @@ #include "frontend/Parser.h" #include "frontend/TokenStream.h" #include "vm/Debugger.h" +#include "vm/Stack.h" #include "jsatominlines.h" #include "jsobjinlines.h" @@ -110,11 +111,13 @@ struct LoopStmtInfo : public StmtInfoBCE BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, SharedContext *sc, - HandleScript script, bool insideEval, HandleScript evalCaller, + HandleScript script, Handle lazyScript, + bool insideEval, HandleScript evalCaller, bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode) : sc(sc), parent(parent), script(sc->context, script), + lazyScript(sc->context, lazyScript), prolog(sc->context, lineNum), main(sc->context, lineNum), current(&main), @@ -135,12 +138,12 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter *parent, hasSingletons(false), emittingForInit(false), emittingRunOnceLambda(false), - lazyRunOnceLambda(false), insideEval(insideEval), hasGlobalScope(hasGlobalScope), emitterMode(emitterMode) { JS_ASSERT_IF(evalCaller, insideEval); + JS_ASSERT_IF(emitterMode == LazyFunction, lazyScript); } bool @@ -223,7 +226,7 @@ frontend::Emit2(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode ptrdiff_t frontend::Emit3(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, jsbytecode op1, - jsbytecode op2) + jsbytecode op2) { /* These should filter through EmitVarOp. */ JS_ASSERT(!IsArgOp(op)); @@ -799,8 +802,8 @@ EmitInternedObjectOp(ExclusiveContext *cx, uint32_t index, JSOp op, BytecodeEmit static void ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, Handle blockObj) { - unsigned nfixedvars = bce->sc->isFunctionBox() ? bce->script->bindings.numVars() : 0; - unsigned localOffset = nfixedvars; + unsigned nbodyfixed = bce->sc->isFunctionBox() ? bce->script->bindings.numBodyLevelLocals() : 0; + unsigned localOffset = nbodyfixed; if (bce->staticScope) { Rooted outer(cx, bce->staticScope); @@ -814,7 +817,7 @@ ComputeLocalOffset(ExclusiveContext *cx, BytecodeEmitter *bce, HandlenumVariables() - <= nfixedvars + bce->script->bindings.numBlockScoped()); + <= nbodyfixed + bce->script->bindings.numBlockScoped()); blockObj->setLocalOffset(localOffset); } @@ -1061,17 +1064,33 @@ EmitRegExp(ExclusiveContext *cx, uint32_t index, BytecodeEmitter *bce) * used as a non-asserting version of EMIT_UINT16_IMM_OP. */ static bool -EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, BytecodeEmitter *bce) +EmitLocalOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, uint32_t slot) +{ + JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD); + JS_ASSERT(IsLocalOp(op)); + + ptrdiff_t off = EmitN(cx, bce, op, LOCALNO_LEN); + if (off < 0) + return false; + + SET_LOCALNO(bce->code(off), slot); + return true; +} + +static bool +EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, MaybeCheckLexical checkLexical, + BytecodeEmitter *bce) { JS_ASSERT(JOF_OPTYPE(op) != JOF_SCOPECOORD); if (IsLocalOp(op)) { - ptrdiff_t off = EmitN(cx, bce, op, LOCALNO_LEN); - if (off < 0) - return false; + if (checkLexical) { + MOZ_ASSERT(op != JSOP_INITLEXICAL); + if (!EmitLocalOp(cx, bce, JSOP_CHECKLEXICAL, slot)) + return false; + } - SET_LOCALNO(bce->code(off), slot); - return true; + return EmitLocalOp(cx, bce, op, slot); } JS_ASSERT(IsArgOp(op)); @@ -1084,7 +1103,7 @@ EmitUnaliasedVarOp(ExclusiveContext *cx, JSOp op, uint32_t slot, BytecodeEmitter } static bool -EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmitter *bce) +EmitScopeCoordOp(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, ScopeCoordinate sc) { JS_ASSERT(JOF_OPTYPE(op) == JOF_SCOPECOORD); @@ -1104,6 +1123,19 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, BytecodeEmit return true; } +static bool +EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ScopeCoordinate sc, MaybeCheckLexical checkLexical, + BytecodeEmitter *bce) +{ + if (checkLexical) { + MOZ_ASSERT(op != JSOP_INITALIASEDLEXICAL); + if (!EmitScopeCoordOp(cx, bce, JSOP_CHECKALIASEDLEXICAL, sc)) + return false; + } + + return EmitScopeCoordOp(cx, bce, op, sc); +} + // Compute the number of nested scope objects that will actually be on the scope // chain at runtime, given the BCE's current staticScope. static unsigned @@ -1119,30 +1151,60 @@ DynamicNestedScopeDepth(BytecodeEmitter *bce) } static bool -LookupAliasedName(HandleScript script, PropertyName *name, uint32_t *pslot) +LookupAliasedName(BytecodeEmitter *bce, HandleScript script, PropertyName *name, uint32_t *pslot, + ParseNode *pn = nullptr) { + LazyScript::FreeVariable *freeVariables = nullptr; + uint32_t lexicalBegin = 0; + uint32_t numFreeVariables = 0; + if (bce->emitterMode == BytecodeEmitter::LazyFunction) { + freeVariables = bce->lazyScript->freeVariables(); + lexicalBegin = script->bindings.lexicalBegin(); + numFreeVariables = bce->lazyScript->numFreeVariables(); + } + /* * Beware: BindingIter may contain more than one Binding for a given name * (in the case of |function f(x,x) {}|) but only one will be aliased. */ + uint32_t bindingIndex = 0; uint32_t slot = CallObject::RESERVED_SLOTS; for (BindingIter bi(script); !bi.done(); bi++) { if (bi->aliased()) { if (bi->name() == name) { + // Check if the free variable from a lazy script was marked as + // a possible hoisted use and is a lexical binding. If so, + // mark it as such so we emit a dead zone check. + if (freeVariables) { + for (uint32_t i = 0; i < numFreeVariables; i++) { + if (freeVariables[i].atom() == name) { + if (freeVariables[i].isHoistedUse() && bindingIndex >= lexicalBegin) { + MOZ_ASSERT(pn); + MOZ_ASSERT(pn->isUsed()); + pn->pn_dflags |= PND_LET; + } + + break; + } + } + } + *pslot = slot; return true; } slot++; } + bindingIndex++; } return false; } static bool -LookupAliasedNameSlot(HandleScript script, PropertyName *name, ScopeCoordinate *sc) +LookupAliasedNameSlot(BytecodeEmitter *bce, HandleScript script, PropertyName *name, + ScopeCoordinate *sc) { uint32_t slot; - if (!LookupAliasedName(script, name, &slot)) + if (!LookupAliasedName(bce, script, name, &slot)) return false; sc->setSlot(slot); @@ -1165,6 +1227,12 @@ AssignHops(BytecodeEmitter *bce, ParseNode *pn, unsigned src, ScopeCoordinate *d return true; } +static inline MaybeCheckLexical +NodeNeedsCheckLexical(ParseNode *pn) +{ + return pn->isHoistedLetUse() ? CheckLexical : DontCheckLexical; +} + static bool EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter *bce) { @@ -1211,14 +1279,14 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter * if (IsArgOp(pn->getOp())) { if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc)) return false; - JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc)); + JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc)); } else { JS_ASSERT(IsLocalOp(pn->getOp()) || pn->isKind(PNK_FUNCTION)); uint32_t local = pn->pn_cookie.slot(); - if (local < bceOfDef->script->bindings.numVars()) { + if (local < bceOfDef->script->bindings.numBodyLevelLocals()) { if (!AssignHops(bce, pn, skippedScopes + DynamicNestedScopeDepth(bceOfDef), &sc)) return false; - JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef->script, pn->name(), &sc)); + JS_ALWAYS_TRUE(LookupAliasedNameSlot(bceOfDef, bceOfDef->script, pn->name(), &sc)); } else { JS_ASSERT_IF(bce->sc->isFunctionBox(), local <= bceOfDef->script->bindings.numLocals()); JS_ASSERT(bceOfDef->staticScope->is()); @@ -1234,7 +1302,7 @@ EmitAliasedVarOp(ExclusiveContext *cx, JSOp op, ParseNode *pn, BytecodeEmitter * } } - return EmitAliasedVarOp(cx, op, sc, bce); + return EmitAliasedVarOp(cx, op, sc, NodeNeedsCheckLexical(pn), bce); } static bool @@ -1247,7 +1315,7 @@ EmitVarOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) ScopeCoordinate sc; sc.setHops(pn->pn_cookie.level()); sc.setSlot(pn->pn_cookie.slot()); - return EmitAliasedVarOp(cx, op, sc, bce); + return EmitAliasedVarOp(cx, op, sc, NodeNeedsCheckLexical(pn), bce); } JS_ASSERT_IF(pn->isKind(PNK_NAME), IsArgOp(op) || IsLocalOp(op)); @@ -1256,12 +1324,13 @@ EmitVarOp(ExclusiveContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce) JS_ASSERT(pn->isUsed() || pn->isDefn()); JS_ASSERT_IF(pn->isUsed(), pn->pn_cookie.level() == 0); JS_ASSERT_IF(pn->isDefn(), pn->pn_cookie.level() == bce->script->staticLevel()); - return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), bce); + return EmitUnaliasedVarOp(cx, op, pn->pn_cookie.slot(), NodeNeedsCheckLexical(pn), bce); } switch (op) { case JSOP_GETARG: case JSOP_GETLOCAL: op = JSOP_GETALIASEDVAR; break; case JSOP_SETARG: case JSOP_SETLOCAL: op = JSOP_SETALIASEDVAR; break; + case JSOP_INITLEXICAL: op = JSOP_INITALIASEDLEXICAL; break; default: MOZ_CRASH("unexpected var op"); } @@ -1435,13 +1504,14 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn) return false; if (ssi.hasDynamicScopeObject()) { uint32_t slot; - if (LookupAliasedName(script, pn->pn_atom->asPropertyName(), &slot)) { + if (LookupAliasedName(bce, script, pn->pn_atom->asPropertyName(), &slot, pn)) { JSOp op; switch (pn->getOp()) { - case JSOP_NAME: op = JSOP_GETALIASEDVAR; break; - case JSOP_SETNAME: op = JSOP_SETALIASEDVAR; break; + case JSOP_NAME: op = JSOP_GETALIASEDVAR; break; + case JSOP_SETNAME: op = JSOP_SETALIASEDVAR; break; default: return false; } + pn->setOp(op); JS_ALWAYS_TRUE(pn->pn_cookie.set(bce->parser->tokenStream, hops, slot)); return true; @@ -2464,10 +2534,11 @@ SetJumpOffsetAt(BytecodeEmitter *bce, ptrdiff_t off) } static bool -PushUndefinedValues(ExclusiveContext *cx, BytecodeEmitter *bce, unsigned n) +PushInitialConstants(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp op, unsigned n) { + MOZ_ASSERT(op == JSOP_UNDEFINED || op == JSOP_UNINITIALIZED); for (unsigned i = 0; i < n; ++i) { - if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) + if (Emit1(cx, bce, op) < 0) return false; } return true; @@ -2482,11 +2553,11 @@ InitializeBlockScopedLocalsFromStack(ExclusiveContext *cx, BytecodeEmitter *bce, ScopeCoordinate sc; sc.setHops(0); sc.setSlot(BlockObject::RESERVED_SLOTS + i - 1); - if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce)) + if (!EmitAliasedVarOp(cx, JSOP_INITALIASEDLEXICAL, sc, DontCheckLexical, bce)) return false; } else { unsigned local = blockObj->blockIndexToLocalIndex(i - 1); - if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, local, bce)) + if (!EmitUnaliasedVarOp(cx, JSOP_INITLEXICAL, local, DontCheckLexical, bce)) return false; } if (Emit1(cx, bce, JSOP_POP) < 0) @@ -2497,11 +2568,14 @@ InitializeBlockScopedLocalsFromStack(ExclusiveContext *cx, BytecodeEmitter *bce, static bool EnterBlockScope(ExclusiveContext *cx, BytecodeEmitter *bce, StmtInfoBCE *stmtInfo, - ObjectBox *objbox, unsigned alreadyPushed = 0) + ObjectBox *objbox, JSOp initialValueOp, unsigned alreadyPushed = 0) { - // Initial values for block-scoped locals. + // Initial values for block-scoped locals. Whether it is undefined or the + // JS_UNINITIALIZED_LEXICAL magic value depends on the context. The + // current way we emit for-in and for-of heads means its let bindings will + // always be initialized, so we can initialize them to undefined. Rooted blockObj(cx, &objbox->object->as()); - if (!PushUndefinedValues(cx, bce, blockObj->numVariables() - alreadyPushed)) + if (!PushInitialConstants(cx, bce, initialValueOp, blockObj->numVariables() - alreadyPushed)) return false; if (!EnterNestedScope(cx, bce, stmtInfo, objbox, STMT_BLOCK)) @@ -2544,7 +2618,7 @@ EmitSwitch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) StmtInfoBCE stmtInfo(cx); if (pn2->isKind(PNK_LEXICALSCOPE)) { - if (!EnterBlockScope(cx, bce, &stmtInfo, pn2->pn_objbox, 0)) + if (!EnterBlockScope(cx, bce, &stmtInfo, pn2->pn_objbox, JSOP_UNINITIALIZED, 0)) return false; stmtInfo.type = STMT_SWITCH; @@ -2847,8 +2921,11 @@ BytecodeEmitter::isRunOnceLambda() // at properties of the function itself before deciding to emit a function // as a run once lambda. - if (!(parent && parent->emittingRunOnceLambda) && !lazyRunOnceLambda) + if (!(parent && parent->emittingRunOnceLambda) && + (emitterMode != LazyFunction || !lazyScript->treatAsRunOnce())) + { return false; + } FunctionBox *funbox = sc->asFunctionBox(); return !funbox->argumentsHasLocalBinding() && @@ -2877,11 +2954,11 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo if (bce->script->varIsAliased(varIndex)) { ScopeCoordinate sc; sc.setHops(0); - JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce->script, cx->names().arguments, &sc)); - if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, bce)) + JS_ALWAYS_TRUE(LookupAliasedNameSlot(bce, bce->script, cx->names().arguments, &sc)); + if (!EmitAliasedVarOp(cx, JSOP_SETALIASEDVAR, sc, DontCheckLexical, bce)) return false; } else { - if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, bce)) + if (!EmitUnaliasedVarOp(cx, JSOP_SETLOCAL, varIndex, DontCheckLexical, bce)) return false; } if (Emit1(cx, bce, JSOP_POP) < 0) @@ -3007,20 +3084,10 @@ enum VarEmitOption typedef bool (*DestructuringDeclEmitter)(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn); +template static bool -EmitDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn) -{ - JS_ASSERT(pn->isKind(PNK_NAME)); - if (!BindNameToSlot(cx, bce, pn)) - return false; - - JS_ASSERT(!pn->isOp(JSOP_CALLEE)); - return MaybeEmitVarDecl(cx, bce, prologOp, pn, nullptr); -} - -static bool -EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, - ParseNode *pattern) +EmitDestructuringDeclsWithEmitter(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, + ParseNode *pattern) { if (pattern->isKind(PNK_ARRAY)) { for (ParseNode *element = pattern->pn_head; element; element = element->pn_next) { @@ -3031,10 +3098,13 @@ EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp JS_ASSERT(element->pn_kid->isKind(PNK_NAME)); target = element->pn_kid; } - DestructuringDeclEmitter emitter = - target->isKind(PNK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls; - if (!emitter(cx, bce, prologOp, target)) - return false; + if (target->isKind(PNK_NAME)) { + if (!EmitName(cx, bce, prologOp, target)) + return false; + } else { + if (!EmitDestructuringDeclsWithEmitter(cx, bce, prologOp, target)) + return false; + } } return true; } @@ -3046,14 +3116,55 @@ EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp member->isKind(PNK_SHORTHAND)); ParseNode *target = member->isKind(PNK_MUTATEPROTO) ? member->pn_kid : member->pn_right; - DestructuringDeclEmitter emitter = - target->isKind(PNK_NAME) ? EmitDestructuringDecl : EmitDestructuringDecls; - if (!emitter(cx, bce, prologOp, target)) - return false; + + if (target->isKind(PNK_NAME)) { + if (!EmitName(cx, bce, prologOp, target)) + return false; + } else { + if (!EmitDestructuringDeclsWithEmitter(cx, bce, prologOp, target)) + return false; + } } return true; } +bool +EmitDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn) +{ + JS_ASSERT(pn->isKind(PNK_NAME)); + if (!BindNameToSlot(cx, bce, pn)) + return false; + + JS_ASSERT(!pn->isOp(JSOP_CALLEE)); + return MaybeEmitVarDecl(cx, bce, prologOp, pn, nullptr); +} + +static inline bool +EmitDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, + ParseNode *pattern) +{ + return EmitDestructuringDeclsWithEmitter(cx, bce, prologOp, pattern); +} + +bool +EmitInitializeDestructuringDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, + ParseNode *pn) +{ + MOZ_ASSERT(pn->isKind(PNK_NAME)); + MOZ_ASSERT(pn->isBound()); + return EmitVarOp(cx, pn, pn->getOp(), bce); +} + +// Emit code to initialize all destructured names to the value on the top of +// the stack. +static inline bool +EmitInitializeDestructuringDecls(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, + ParseNode *pattern) +{ + return EmitDestructuringDeclsWithEmitter(cx, bce, + prologOp, pattern); +} + static bool EmitDestructuringOpsHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pattern, VarEmitOption emitOption); @@ -3093,7 +3204,7 @@ EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, } else if (emitOption == PushInitialValues) { // The lhs is a simple name so the to-be-destructured value is // its initial value and there is nothing to do. - JS_ASSERT(pn->getOp() == JSOP_SETLOCAL); + JS_ASSERT(pn->getOp() == JSOP_SETLOCAL || pn->getOp() == JSOP_INITLEXICAL); JS_ASSERT(pn->pn_dflags & PND_BOUND); } else { switch (pn->getKind()) { @@ -3138,6 +3249,7 @@ EmitDestructuringLHS(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, case JSOP_SETLOCAL: case JSOP_SETARG: + case JSOP_INITLEXICAL: if (!EmitVarOp(cx, pn, pn->getOp(), bce)) return false; break; @@ -3534,10 +3646,10 @@ EmitTemplateString(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) static bool EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmitOption emitOption, - bool isLet = false) + bool isLetExpr = false) { JS_ASSERT(pn->isArity(PN_LIST)); - JS_ASSERT(isLet == (emitOption == PushInitialValues)); + JS_ASSERT(isLetExpr == (emitOption == PushInitialValues)); ParseNode *next; for (ParseNode *pn2 = pn->pn_head; ; pn2 = next) { @@ -3548,18 +3660,35 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit ParseNode *pn3; if (!pn2->isKind(PNK_NAME)) { if (pn2->isKind(PNK_ARRAY) || pn2->isKind(PNK_OBJECT)) { - /* - * Emit variable binding ops, but not destructuring ops. The - * parser (see Parser::variables) has ensured that our caller - * will be the PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree, and - * that case will emit the destructuring code only after - * emitting an enumerating opcode and a branch that tests - * whether the enumeration ended. - */ - JS_ASSERT(emitOption == DefineVars); + // If the emit option is DefineVars, emit variable binding + // ops, but not destructuring ops. The parser (see + // Parser::variables) has ensured that our caller will be the + // PNK_FOR/PNK_FORIN/PNK_FOROF case in EmitTree (we don't have + // to worry about this being a variable declaration, as + // destructuring declarations without initializers, e.g., |var + // [x]|, are not legal syntax), and that case will emit the + // destructuring code only after emitting an enumerating + // opcode and a branch that tests whether the enumeration + // ended. Thus, each iteration's assignment is responsible for + // initializing, and nothing needs to be done here. + // + // Otherwise this is emitting destructuring let binding + // initialization for a legacy comprehension expression. See + // EmitForInOrOfVariables. JS_ASSERT(pn->pn_count == 1); - if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2)) - return false; + if (emitOption == DefineVars) { + if (!EmitDestructuringDecls(cx, bce, pn->getOp(), pn2)) + return false; + } else { + // Lexical bindings cannot be used before they are + // initialized. Similar to the JSOP_INITLEXICAL case below. + MOZ_ASSERT(emitOption != DefineVars); + MOZ_ASSERT_IF(emitOption == InitializeVars, pn->pn_xflags & PNX_POPVAR); + if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) + return false; + if (!EmitInitializeDestructuringDecls(cx, bce, pn->getOp(), pn2)) + return false; + } break; } @@ -3591,7 +3720,7 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit if (!EmitTree(cx, bce, pn2->pn_right)) return false; - if (!EmitDestructuringOps(cx, bce, pn3, isLet)) + if (!EmitDestructuringOps(cx, bce, pn3, isLetExpr)) return false; /* If we are not initializing, nothing to pop. */ @@ -3645,13 +3774,17 @@ EmitVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, VarEmit if (!EmitTree(cx, bce, pn3)) return false; bce->emittingForInit = oldEmittingForInit; - } else if (isLet) { - /* JSOP_ENTERLETx expects at least 1 slot to have been pushed. */ + } else if (op == JSOP_INITLEXICAL || isLetExpr) { + // 'let' bindings cannot be used before they are + // initialized. JSOP_INITLEXICAL distinguishes the binding site. + MOZ_ASSERT(emitOption != DefineVars); + MOZ_ASSERT_IF(emitOption == InitializeVars, pn->pn_xflags & PNX_POPVAR); if (Emit1(cx, bce, JSOP_UNDEFINED) < 0) return false; } - /* If we are not initializing, nothing to pop. */ + // If we are not initializing, nothing to pop. If we are initializing + // lets, we must emit the pops. if (emitOption != InitializeVars) { if (next) continue; @@ -4109,7 +4242,7 @@ EmitCatch(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) case PNK_NAME: /* Inline and specialize BindNameToSlot for pn2. */ JS_ASSERT(!pn2->pn_cookie.isFree()); - if (!EmitVarOp(cx, pn2, JSOP_SETLOCAL, bce)) + if (!EmitVarOp(cx, pn2, JSOP_INITLEXICAL, bce)) return false; if (Emit1(cx, bce, JSOP_POP) < 0) return false; @@ -4463,9 +4596,9 @@ EmitLet(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pnLet) return false; /* Push storage for hoisted let decls (e.g. 'let (x) { let y }'). */ - uint32_t alreadyPushed = bce->stackDepth - letHeadDepth; + uint32_t valuesPushed = bce->stackDepth - letHeadDepth; StmtInfoBCE stmtInfo(cx); - if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, alreadyPushed)) + if (!EnterBlockScope(cx, bce, &stmtInfo, letBody->pn_objbox, JSOP_UNINITIALIZED, valuesPushed)) return false; if (!EmitTree(cx, bce, letBody->pn_expr)) @@ -4487,7 +4620,7 @@ EmitLexicalScope(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) JS_ASSERT(pn->isKind(PNK_LEXICALSCOPE)); StmtInfoBCE stmtInfo(cx); - if (!EnterBlockScope(cx, bce, &stmtInfo, pn->pn_objbox, 0)) + if (!EnterBlockScope(cx, bce, &stmtInfo, pn->pn_objbox, JSOP_UNINITIALIZED, 0)) return false; if (!EmitTree(cx, bce, pn->pn_expr)) @@ -4534,6 +4667,39 @@ EmitIterator(ExclusiveContext *cx, BytecodeEmitter *bce) return true; } +static bool +EmitForInOrOfVariables(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, bool *letDecl) +{ + *letDecl = pn->isKind(PNK_LEXICALSCOPE); + MOZ_ASSERT_IF(*letDecl, pn->isLet()); + + // If the left part is 'var x', emit code to define x if necessary using a + // prolog opcode, but do not emit a pop. If it is 'let x', EnterBlockScope + // will initialize let bindings in EmitForOf and EmitForIn with + // undefineds. + // + // Due to the horror of legacy comprehensions, there is a third case where + // we have PNK_LET without a lexical scope, because those expressions are + // parsed with single lexical scope for the entire comprehension. In this + // case we must initialize the lets to not trigger dead zone checks via + // InitializeVars. + if (!*letDecl) { + bce->emittingForInit = true; + if (pn->isKind(PNK_VAR)) { + if (!EmitVariables(cx, bce, pn, DefineVars)) + return false; + } else { + MOZ_ASSERT(pn->isKind(PNK_LET)); + if (!EmitVariables(cx, bce, pn, InitializeVars)) + return false; + } + bce->emittingForInit = false; + } + + return true; +} + + /** * If type is STMT_FOR_OF_LOOP, it emits bytecode for for-of loop. * pn should be PNK_FOR, and pn->pn_left should be PNK_FOROF. @@ -4554,19 +4720,9 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode * ParseNode *forBody = pn ? pn->pn_right : nullptr; ParseNode *pn1 = forHead ? forHead->pn_kid1 : nullptr; - bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE); - JS_ASSERT_IF(letDecl, pn1->isLet()); - - // If the left part is 'var x', emit code to define x if necessary using a - // prolog opcode, but do not emit a pop. - if (pn1) { - ParseNode *decl = letDecl ? pn1->pn_expr : pn1; - JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET)); - bce->emittingForInit = true; - if (!EmitVariables(cx, bce, decl, DefineVars)) - return false; - bce->emittingForInit = false; - } + bool letDecl = false; + if (pn1 && !EmitForInOrOfVariables(cx, bce, pn1, &letDecl)) + return false; if (type == STMT_FOR_OF_LOOP) { // For-of loops run with two values on the stack: the iterator and the @@ -4584,9 +4740,11 @@ EmitForOf(ExclusiveContext *cx, BytecodeEmitter *bce, StmtType type, ParseNode * } // Enter the block before the loop body, after evaluating the obj. + // Initialize let bindings with undefined when entering, as the name + // assigned to is a plain assignment. StmtInfoBCE letStmt(cx); if (letDecl) { - if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 0)) + if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0)) return false; } @@ -4708,23 +4866,9 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t ParseNode *forBody = pn->pn_right; ParseNode *pn1 = forHead->pn_kid1; - bool letDecl = pn1 && pn1->isKind(PNK_LEXICALSCOPE); - JS_ASSERT_IF(letDecl, pn1->isLet()); - - /* - * If the left part is 'var x', emit code to define x if necessary - * using a prolog opcode, but do not emit a pop. If the left part was - * originally 'var x = i', the parser will have rewritten it; see - * Parser::forStatement. 'for (let x = i in o)' is mercifully banned. - */ - if (pn1) { - ParseNode *decl = letDecl ? pn1->pn_expr : pn1; - JS_ASSERT(decl->isKind(PNK_VAR) || decl->isKind(PNK_LET)); - bce->emittingForInit = true; - if (!EmitVariables(cx, bce, decl, DefineVars)) - return false; - bce->emittingForInit = false; - } + bool letDecl = false; + if (pn1 && !EmitForInOrOfVariables(cx, bce, pn1, &letDecl)) + return false; /* Compile the object expression to the right of 'in'. */ if (!EmitTree(cx, bce, forHead->pn_kid3)) @@ -4739,10 +4883,12 @@ EmitForIn(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrdiff_t t if (Emit2(cx, bce, JSOP_ITER, (uint8_t) pn->pn_iflags) < 0) return false; - /* Enter the block before the loop body, after evaluating the obj. */ + // Enter the block before the loop body, after evaluating the obj. + // Initialize let bindings with undefined when entering, as the name + // assigned to is a plain assignment. StmtInfoBCE letStmt(cx); if (letDecl) { - if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, 0)) + if (!EnterBlockScope(cx, bce, &letStmt, pn1->pn_objbox, JSOP_UNDEFINED, 0)) return false; } @@ -5042,8 +5188,8 @@ EmitFunc(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn) script->bindings = funbox->bindings; uint32_t lineNum = bce->parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin); - BytecodeEmitter bce2(bce, bce->parser, funbox, script, bce->insideEval, - bce->evalCaller, bce->hasGlobalScope, lineNum, + BytecodeEmitter bce2(bce, bce->parser, funbox, script, /* lazyScript = */ js::NullPtr(), + bce->insideEval, bce->evalCaller, bce->hasGlobalScope, lineNum, bce->emitterMode); if (!bce2.init()) return false; diff --git a/js/src/frontend/BytecodeEmitter.h b/js/src/frontend/BytecodeEmitter.h index c20cceaa578f..aabe7bec97c3 100644 --- a/js/src/frontend/BytecodeEmitter.h +++ b/js/src/frontend/BytecodeEmitter.h @@ -86,6 +86,9 @@ struct BytecodeEmitter Rooted script; /* the JSScript we're ultimately producing */ + Rooted lazyScript; /* the lazy script if mode is LazyFunction, + nullptr otherwise. */ + struct EmitSection { BytecodeVector code; /* bytecode */ SrcNotesVector notes; /* source notes, see below */ @@ -136,8 +139,6 @@ struct BytecodeEmitter bool emittingRunOnceLambda:1; /* true while emitting a lambda which is only expected to run once. */ - bool lazyRunOnceLambda:1; /* true while lazily emitting a script for - * a lambda which is only expected to run once. */ bool isRunOnceLambda(); @@ -173,8 +174,9 @@ struct BytecodeEmitter * destruction. */ BytecodeEmitter(BytecodeEmitter *parent, Parser *parser, SharedContext *sc, - HandleScript script, bool insideEval, HandleScript evalCaller, - bool hasGlobalScope, uint32_t lineNum, EmitterMode emitterMode = Normal); + HandleScript script, Handle lazyScript, + bool insideEval, HandleScript evalCaller, bool hasGlobalScope, + uint32_t lineNum, EmitterMode emitterMode = Normal); bool init(); bool isAliasedName(ParseNode *pn); diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index f8579b4dea94..dc6fb91a02b0 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -597,6 +597,9 @@ class FullParseHandler static Definition::Kind getDefinitionKind(Definition *dn) { return dn->kind(); } + static bool isPlaceholderDefinition(Definition *dn) { + return dn->isPlaceholder(); + } void linkUseToDef(ParseNode *pn, Definition *dn) { JS_ASSERT(!pn->isUsed()); @@ -624,6 +627,13 @@ class FullParseHandler bool dependencyCovered(ParseNode *pn, unsigned blockid, bool functionScope) { return pn->pn_blockid >= blockid; } + void markMaybeUninitializedLexicalUseInSwitch(ParseNode *pn, Definition *dn, + uint16_t firstDominatingLexicalSlot) + { + MOZ_ASSERT(pn->isUsed()); + if (dn->isLet() && dn->pn_cookie.slot() < firstDominatingLexicalSlot) + pn->pn_dflags |= PND_LET; + } static uintptr_t definitionToBits(Definition *dn) { return uintptr_t(dn); @@ -711,11 +721,14 @@ FullParseHandler::finishInitializerAssignment(ParseNode *pn, ParseNode *init, JS pn->pn_expr = init; } - pn->setOp((pn->pn_dflags & PND_BOUND) - ? JSOP_SETLOCAL - : (op == JSOP_DEFCONST) - ? JSOP_SETCONST - : JSOP_SETNAME); + if (op == JSOP_INITLEXICAL) + pn->setOp(op); + else if (pn->pn_dflags & PND_BOUND) + pn->setOp(JSOP_SETLOCAL); + else if (op == JSOP_DEFCONST) + pn->setOp(JSOP_SETCONST); + else + pn->setOp(JSOP_SETNAME); pn->markAsAssigned(); diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp index 1bc53fb0433e..d75b3fad8416 100644 --- a/js/src/frontend/ParseNode.cpp +++ b/js/src/frontend/ParseNode.cpp @@ -407,6 +407,7 @@ Parser::cloneParseTree(ParseNode *opn) Definition *dn = pn->pn_lexdef; pn->pn_link = dn->dn_uses; + pn->pn_dflags = opn->pn_dflags; dn->dn_uses = pn; } else if (opn->pn_expr) { NULLCHECK(pn->pn_expr = cloneParseTree(opn->pn_expr)); @@ -513,7 +514,7 @@ Parser::cloneLeftHandSide(ParseNode *opn) if (opn->isDefn()) { /* We copied some definition-specific state into pn. Clear it out. */ pn->pn_cookie.makeFree(); - pn->pn_dflags &= ~PND_BOUND; + pn->pn_dflags &= ~(PND_LET | PND_BOUND); pn->setDefn(false); handler.linkUseToDef(pn, (Definition *) opn); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index a3d21f43f594..7c0a255d47a3 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -664,7 +664,7 @@ class ParseNode Definition *resolve(); /* PN_CODE and PN_NAME pn_dflags bits. */ -#define PND_LET 0x01 /* let (block-scoped) binding */ +#define PND_LET 0x01 /* let (block-scoped) binding or use of a hoisted let */ #define PND_CONST 0x02 /* const binding (orthogonal to let) */ #define PND_ASSIGNED 0x04 /* set if ever LHS of assignment */ #define PND_PLACEHOLDER 0x08 /* placeholder definition for lexdep */ @@ -746,7 +746,7 @@ class ParseNode inline bool test(unsigned flag) const; - bool isLet() const { return test(PND_LET); } + bool isLet() const { return test(PND_LET) && !isUsed(); } bool isConst() const { return test(PND_CONST); } bool isPlaceholder() const { return test(PND_PLACEHOLDER); } bool isDeoptimized() const { return test(PND_DEOPTIMIZED); } @@ -754,6 +754,7 @@ class ParseNode bool isClosed() const { return test(PND_CLOSED); } bool isBound() const { return test(PND_BOUND); } bool isImplicitArguments() const { return test(PND_IMPLICITARGUMENTS); } + bool isHoistedLetUse() const { return test(PND_LET) && isUsed(); } /* True if pn is a parsenode representing a literal constant. */ bool isLiteral() const { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index 317283399f53..91233bb9c5f5 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -96,6 +96,65 @@ PushStatementPC(ParseContext *pc, StmtInfoPC *stmt, StmtType type) PushStatement(pc, stmt, type); } +template <> +bool +ParseContext::checkLocalsOverflow(TokenStream &ts) +{ + if (vars_.length() + bodyLevelLexicals_.length() >= LOCALNO_LIMIT) { + ts.reportError(JSMSG_TOO_MANY_LOCALS); + return false; + } + return true; +} + +static void +MarkUsesAsHoistedLexical(ParseNode *pn) +{ + MOZ_ASSERT(pn->isDefn()); + + Definition *dn = (Definition *)pn; + ParseNode **pnup = &dn->dn_uses; + ParseNode *pnu; + unsigned start = pn->pn_blockid; + + // In ES6, lexical bindings cannot be accessed until initialized. + // Distinguish hoisted uses as a different JSOp for easier compilation. + while ((pnu = *pnup) != nullptr && pnu->pn_blockid >= start) { + MOZ_ASSERT(pnu->isUsed()); + + // JavaScript is parsed in dominator order. This condition says to + // mark uses which either: + // + // 1) Is at the same dominator level. + // + // This covers the case where the right hand side of declarations + // cannot refer to the binding itself. e.g, |let x = x| is a + // ReferenceError. Note that the use of 'x' follows the definition + // node 'let x' in the program text. + // + // 2) Precedes the definition in the program text. + // + // This covers all hoisted uses. + // + // The uses that are not covered by these two conditions are uses of + // the binding as free variables in function definitions on the right + // hand side of the binding node. e.g., + // + // let x = function () { x(); } + // + // does not mark the upvar use of 'x' inside the lambda as needing a + // TDZ check. + // + // N.B. This function expects to be called at the point of defining + // the lexical binding, and should not be called afterwards, as it + // would erroneously unmark hoisted function definitions and needing + // TDZ checks, which is currently handled in leaveFunction. + if (pnu->pn_blockid == start || pnu->pn_pos < pn->pn_pos) + pnu->pn_dflags |= PND_LET; + pnup = &pnu->pn_link; + } +} + // See comment on member function declaration. template <> bool @@ -150,6 +209,7 @@ ParseContext::define(TokenStream &ts, case Definition::ARG: JS_ASSERT(sc->isFunctionBox()); dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETARG : JSOP_GETARG); + dn->pn_blockid = bodyid; dn->pn_dflags |= PND_BOUND; if (!dn->pn_cookie.set(ts, staticLevel, args_.length())) return false; @@ -169,24 +229,35 @@ ParseContext::define(TokenStream &ts, case Definition::VAR: if (sc->isFunctionBox()) { dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL); + dn->pn_blockid = bodyid; dn->pn_dflags |= PND_BOUND; if (!dn->pn_cookie.set(ts, staticLevel, vars_.length())) return false; if (!vars_.append(dn)) return false; - if (vars_.length() >= LOCALNO_LIMIT) { - ts.reportError(JSMSG_TOO_MANY_LOCALS); + if (!checkLocalsOverflow(ts)) return false; - } } if (!decls_.addUnique(name, dn)) return false; break; case Definition::LET: - dn->setOp((js_CodeSpec[dn->getOp()].format & JOF_SET) ? JSOP_SETLOCAL : JSOP_GETLOCAL); + dn->setOp(JSOP_INITLEXICAL); dn->pn_dflags |= (PND_LET | PND_BOUND); JS_ASSERT(dn->pn_cookie.level() == staticLevel); /* see bindLet */ + if (atBodyLevel()) { + if (!bodyLevelLexicals_.append(dn)) + return false; + if (!checkLocalsOverflow(ts)) + return false; + } + + // In ES6, lexical bindings cannot be accessed until initialized. If + // the definition has existing uses, they need to be marked so that we + // emit dead zone checks. + MarkUsesAsHoistedLexical(pn); + if (!decls_.addShadow(name, dn)) return false; break; @@ -198,6 +269,13 @@ ParseContext::define(TokenStream &ts, return true; } +template <> +bool +ParseContext::checkLocalsOverflow(TokenStream &ts) +{ + return true; +} + template <> bool ParseContext::define(TokenStream &ts, HandlePropertyName name, Node pn, @@ -278,6 +356,11 @@ AppendPackedBindings(const ParseContext *pc, const DeclVector &vec Binding::Kind kind; switch (dn->kind()) { + case Definition::LET: + // Treat body-level let declarations as var bindings by falling + // through. The fact that the binding is in fact a let declaration + // is reflected in the slot. All body-level lets go after the + // vars. case Definition::VAR: kind = Binding::VARIABLE; break; @@ -313,16 +396,24 @@ ParseContext::generateFunctionBindings(ExclusiveContext *cx, Token { JS_ASSERT(sc->isFunctionBox()); JS_ASSERT(args_.length() < ARGNO_LIMIT); - JS_ASSERT(vars_.length() < LOCALNO_LIMIT); + JS_ASSERT(vars_.length() + bodyLevelLexicals_.length() < LOCALNO_LIMIT); /* * Avoid pathological edge cases by explicitly limiting the total number of * bindings to what will fit in a uint32_t. */ - if (UINT32_MAX - args_.length() <= vars_.length()) + if (UINT32_MAX - args_.length() <= vars_.length() + bodyLevelLexicals_.length()) return ts.reportError(JSMSG_TOO_MANY_LOCALS); - uint32_t count = args_.length() + vars_.length(); + // Fix up the slots of body-level lets to come after the vars now that we + // know how many vars there are. + for (size_t i = 0; i < bodyLevelLexicals_.length(); i++) { + Definition *dn = bodyLevelLexicals_[i]; + if (!dn->pn_cookie.set(ts, dn->pn_cookie.level(), vars_.length() + i)) + return false; + } + + uint32_t count = args_.length() + vars_.length() + bodyLevelLexicals_.length(); Binding *packedBindings = alloc.newArrayUninitialized(count); if (!packedBindings) { js_ReportOutOfMemory(cx); @@ -331,9 +422,12 @@ ParseContext::generateFunctionBindings(ExclusiveContext *cx, Token AppendPackedBindings(this, args_, packedBindings); AppendPackedBindings(this, vars_, packedBindings + args_.length()); + AppendPackedBindings(this, bodyLevelLexicals_, + packedBindings + args_.length() + vars_.length()); return Bindings::initWithTemporaryStorage(cx, bindings, args_.length(), vars_.length(), - packedBindings, blockScopeDepth); + bodyLevelLexicals_.length(), blockScopeDepth, + packedBindings); } template @@ -813,7 +907,10 @@ Parser::checkFunctionArguments() */ Definition *maybeArgDef = pc->decls().lookupFirst(arguments); bool argumentsHasBinding = !!maybeArgDef; - bool argumentsHasLocalBinding = maybeArgDef && maybeArgDef->kind() != Definition::ARG; + // ES6 9.2.13.17 says that a lexical binding of 'arguments' shadows the + // arguments object. + bool argumentsHasLocalBinding = maybeArgDef && (maybeArgDef->kind() != Definition::ARG && + maybeArgDef->kind() != Definition::LET); bool hasRest = pc->sc->asFunctionBox()->function()->hasRest(); if (hasRest && argumentsHasLocalBinding) { report(ParseError, false, nullptr, JSMSG_ARGUMENTS_AND_REST); @@ -977,8 +1074,12 @@ Parser::functionBody(FunctionSyntaxKind kind, FunctionBodyType typ /* See comment for use in Parser::functionDef. */ template <> bool -Parser::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom) +Parser::makeDefIntoUse(Definition *dn, ParseNode *pn, JSAtom *atom, + bool *pbodyLevelHoistedUse) { + // See comment in addFreeVariablesFromLazyFunction. + *pbodyLevelHoistedUse = !!dn->dn_uses; + /* Turn pn into a definition. */ pc->updateDecl(atom, pn); @@ -1074,12 +1175,12 @@ struct BindData unsigned overflow; } let; - void initLet(VarContext varContext, StaticBlockObject &blockObj, unsigned overflow) { + void initLet(VarContext varContext, StaticBlockObject *blockObj, unsigned overflow) { this->pn = ParseHandler::null(); - this->op = JSOP_NOP; + this->op = JSOP_INITLEXICAL; this->binder = Parser::bindLet; this->let.varContext = varContext; - this->let.blockObj = &blockObj; + this->let.blockObj = blockObj; this->let.overflow = overflow; } @@ -1191,7 +1292,7 @@ ConvertDefinitionToNamedLambdaUse(TokenStream &ts, ParseContext bool Parser::leaveFunction(ParseNode *fn, ParseContext *outerpc, - FunctionSyntaxKind kind) + bool bodyLevelHoistedUse, FunctionSyntaxKind kind) { outerpc->blockidGen = pc->blockidGen; @@ -1263,6 +1364,29 @@ Parser::leaveFunction(ParseNode *fn, ParseContextdn_uses) { + // In ES6, lexical bindings cannot be accessed until + // initialized. If we are parsing a function with a + // hoisted body-level use, all free variables that get + // linked to an outer 'let' binding need to be marked as + // needing dead zone checks. e.g., + // + // function outer() { + // inner(); + // function inner() { use(x); } + // let x; + // } + // + // The use of 'x' inside 'inner' needs to be marked. + if (bodyLevelHoistedUse && outer_dn->isLet()) { + while (true) { + pnu->pn_dflags |= PND_LET; + if (!pnu->pn_link) + break; + pnu = pnu->pn_link; + } + pnu = dn->dn_uses; + } + while (true) { pnu->pn_lexdef = outer_dn; if (!pnu->pn_link) @@ -1290,12 +1414,12 @@ Parser::leaveFunction(ParseNode *fn, ParseContext bool Parser::leaveFunction(Node fn, ParseContext *outerpc, - FunctionSyntaxKind kind) + bool bodyLevelHoistedUse, FunctionSyntaxKind kind) { outerpc->blockidGen = pc->blockidGen; FunctionBox *funbox = pc->sc->asFunctionBox(); - return addFreeVariablesFromLazyFunction(funbox->function(), outerpc); + return addFreeVariablesFromLazyFunction(funbox->function(), outerpc, bodyLevelHoistedUse); } /* @@ -1566,10 +1690,12 @@ template <> bool Parser::checkFunctionDefinition(HandlePropertyName funName, ParseNode **pn_, FunctionSyntaxKind kind, - bool *pbodyProcessed) + bool *pbodyProcessed, + bool *pbodyLevelHoistedUse) { ParseNode *&pn = *pn_; *pbodyProcessed = false; + *pbodyLevelHoistedUse = false; /* Function statements add a binding to the enclosing scope. */ bool bodyLevel = pc->atBodyLevel(); @@ -1583,11 +1709,13 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, JS_ASSERT(!dn->isUsed()); JS_ASSERT(dn->isDefn()); - if (options().extraWarningsOption || dn->kind() == Definition::CONST) { + bool throwRedeclarationError = dn->kind() == Definition::CONST || + dn->kind() == Definition::LET; + if (options().extraWarningsOption || throwRedeclarationError) { JSAutoByteString name; - ParseReportKind reporter = (dn->kind() != Definition::CONST) - ? ParseExtraWarning - : ParseError; + ParseReportKind reporter = throwRedeclarationError + ? ParseError + : ParseExtraWarning; if (!AtomToPrintableString(context, funName, &name) || !report(reporter, false, nullptr, JSMSG_REDECLARED_VAR, Definition::kindString(dn->kind()), name.ptr())) @@ -1616,7 +1744,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, pn->pn_dflags |= PND_BOUND; dn->markAsAssigned(); } else { - if (!makeDefIntoUse(dn, pn, funName)) + if (!makeDefIntoUse(dn, pn, funName, pbodyLevelHoistedUse)) return false; } } @@ -1639,6 +1767,8 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, pc->lexdeps->remove(funName); handler.freeTree(pn); pn = fn; + + *pbodyLevelHoistedUse = true; } if (!pc->define(tokenStream, funName, pn, Definition::VAR)) @@ -1707,7 +1837,7 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, if (!funbox) return false; - if (!addFreeVariablesFromLazyFunction(fun, pc)) + if (!addFreeVariablesFromLazyFunction(fun, pc, *pbodyLevelHoistedUse)) return false; // The position passed to tokenStream.advance() is relative to @@ -1738,15 +1868,18 @@ PropagateTransitiveParseFlags(const T *inner, U *outer) template bool Parser::addFreeVariablesFromLazyFunction(JSFunction *fun, - ParseContext *pc) + ParseContext *pc, + bool bodyLevelHoistedUse) { + MOZ_ASSERT_IF(bodyLevelHoistedUse, fun->displayAtom() && pc->atBodyLevel()); + // Update any definition nodes in this context according to free variables // in a lazily parsed inner function. LazyScript *lazy = fun->lazyScript(); - HeapPtrAtom *freeVariables = lazy->freeVariables(); + LazyScript::FreeVariable *freeVariables = lazy->freeVariables(); for (size_t i = 0; i < lazy->numFreeVariables(); i++) { - JSAtom *atom = freeVariables[i]; + JSAtom *atom = freeVariables[i].atom(); // 'arguments' will be implicitly bound within the inner function. if (atom == context->names().arguments) @@ -1760,6 +1893,17 @@ Parser::addFreeVariablesFromLazyFunction(JSFunction *fun, return false; } + // In ES6, lexical bindings are unaccessible before initialization. If + // the inner function closes over a placeholder definition, we need to + // mark the variable as maybe needing a dead zone check when we emit + // bytecode. + // + // Note that body-level function declaration statements are always + // hoisted to the top, so all accesses to free let variables need the + // dead zone check. + if (handler.isPlaceholderDefinition(dn) || bodyLevelHoistedUse) + freeVariables[i].setIsHoistedUse(); + /* Mark the outer dn as escaping. */ handler.setFlag(handler.getDefinitionNode(dn), PND_CLOSED); } @@ -1772,9 +1916,11 @@ template <> bool Parser::checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind, - bool *pbodyProcessed) + bool *pbodyProcessed, + bool *pbodyLevelHoistedUse) { *pbodyProcessed = false; + *pbodyLevelHoistedUse = false; /* Function statements add a binding to the enclosing scope. */ bool bodyLevel = pc->atBodyLevel(); @@ -1795,8 +1941,10 @@ Parser::checkFunctionDefinition(HandlePropertyName funName, } } } else if (bodyLevel) { - if (pc->lexdeps.lookupDefn(funName)) + if (pc->lexdeps.lookupDefn(funName)) { + *pbodyLevelHoistedUse = true; pc->lexdeps->remove(funName); + } if (!pc->define(tokenStream, funName, *pn, Definition::VAR)) return false; @@ -1895,7 +2043,8 @@ Parser::functionDef(HandlePropertyName funName, const TokenStream: return null(); bool bodyProcessed; - if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed)) + bool bodyLevelHoistedUse; + if (!checkFunctionDefinition(funName, &pn, kind, &bodyProcessed, &bodyLevelHoistedUse)) return null(); if (bodyProcessed) @@ -1923,7 +2072,8 @@ Parser::functionDef(HandlePropertyName funName, const TokenStream: Directives newDirectives = directives; while (true) { - if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives)) + if (functionArgsAndBody(pn, fun, type, kind, generatorKind, directives, &newDirectives, + bodyLevelHoistedUse)) break; if (tokenStream.hadError() || directives == newDirectives) return null(); @@ -2014,10 +2164,10 @@ Parser::finishFunctionDefinition(Node pn, FunctionBox *funbo if (!lazy) return false; - HeapPtrAtom *freeVariables = lazy->freeVariables(); + LazyScript::FreeVariable *freeVariables = lazy->freeVariables(); size_t i = 0; for (AtomDefnRange r = pc->lexdeps->all(); !r.empty(); r.popFront()) - freeVariables[i++].init(r.front().key()); + freeVariables[i++] = LazyScript::FreeVariable(r.front().key()); JS_ASSERT(i == numFreeVariables); HeapPtrFunction *innerFunctions = lazy->innerFunctions(); @@ -2041,7 +2191,8 @@ Parser::functionArgsAndBody(ParseNode *pn, HandleFunction fun, FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind, Directives inheritedDirectives, - Directives *newDirectives) + Directives *newDirectives, + bool bodyLevelHoistedUse) { ParseContext *outerpc = pc; @@ -2065,8 +2216,7 @@ Parser::functionArgsAndBody(ParseNode *pn, HandleFunction fun, ParseContext funpc(parser, outerpc, SyntaxParseHandler::null(), funbox, newDirectives, outerpc->staticLevel + 1, - outerpc->blockidGen, - /* blockScopeDepth = */ 0); + outerpc->blockidGen, /* blockScopeDepth = */ 0); if (!funpc.init(tokenStream)) return false; @@ -2092,7 +2242,7 @@ Parser::functionArgsAndBody(ParseNode *pn, HandleFunction fun, pn->pn_pos.end = tokenStream.currentToken().pos.end; } - if (!addFreeVariablesFromLazyFunction(fun, pc)) + if (!addFreeVariablesFromLazyFunction(fun, pc, bodyLevelHoistedUse)) return false; pn->pn_blockid = outerpc->blockid(); @@ -2110,7 +2260,7 @@ Parser::functionArgsAndBody(ParseNode *pn, HandleFunction fun, if (!functionArgsAndBodyGeneric(pn, fun, type, kind)) return false; - if (!leaveFunction(pn, outerpc, kind)) + if (!leaveFunction(pn, outerpc, bodyLevelHoistedUse, kind)) return false; pn->pn_blockid = outerpc->blockid(); @@ -2131,7 +2281,8 @@ Parser::functionArgsAndBody(Node pn, HandleFunction fun, FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind, Directives inheritedDirectives, - Directives *newDirectives) + Directives *newDirectives, + bool bodyLevelHoistedUse) { ParseContext *outerpc = pc; @@ -2150,7 +2301,7 @@ Parser::functionArgsAndBody(Node pn, HandleFunction fun, if (!functionArgsAndBodyGeneric(pn, fun, type, kind)) return false; - if (!leaveFunction(pn, outerpc, kind)) + if (!leaveFunction(pn, outerpc, bodyLevelHoistedUse, kind)) return false; // This is a lazy function inner to another lazy function. Remember the @@ -2661,21 +2812,32 @@ Parser::bindLet(BindData *data, return false; ExclusiveContext *cx = parser->context; - Rooted blockObj(cx, data->let.blockObj); - unsigned index = blockObj->numVariables(); - if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) { - parser->report(ParseError, false, pn, data->let.overflow); - return false; + + unsigned index; + if (blockObj) { + index = blockObj->numVariables(); + if (index >= StaticBlockObject::LOCAL_INDEX_LIMIT) { + parser->report(ParseError, false, pn, data->let.overflow); + return false; + } + } else { + // If we don't have a block object, we are parsing a body-level let, + // in which case we use a bogus index. See comment block below in + // setting the pn_cookie for explanation on how it gets adjusted. + index = 0; } - /* - * Assign block-local index to pn->pn_cookie right away, encoding it as an - * upvar cookie whose skip tells the current static level. The emitter will - * adjust the node's slot based on its stack depth model -- and, for global - * and eval code, js::frontend::CompileScript will adjust the slot - * again to include script->nfixed. - */ + // For block-level lets, assign block-local index to pn->pn_cookie right + // away, encoding it as an upvar cookie whose skip tells the current + // static level. The emitter will adjust the node's slot based on its + // stack depth model -- and, for global and eval code, + // js::frontend::CompileScript will adjust the slot again to include + // script->nfixed and body-level lets. + // + // For body-level lets, the index is bogus at this point and is adjusted + // when creating Bindings. See ParseContext::generateFunctionBindings and + // AppendPackedBindings. if (!pn->pn_cookie.set(parser->tokenStream, pc->staticLevel, index)) return false; @@ -2684,7 +2846,6 @@ Parser::bindLet(BindData *data, * define() right now. Otherwise, delay define until PushLetScope. */ if (data->let.varContext == HoistVars) { - JS_ASSERT(!pc->atBodyLevel()); Definition *dn = pc->decls().lookupFirst(name); if (dn && dn->pn_blockid == pc->blockid()) return parser->reportRedeclaration(pn, dn->isConst(), name); @@ -2692,17 +2853,25 @@ Parser::bindLet(BindData *data, return false; } - bool redeclared; - RootedId id(cx, NameToId(name)); - RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, index, &redeclared)); - if (!shape) { - if (redeclared) - parser->reportRedeclaration(pn, false, name); - return false; + if (blockObj) { + bool redeclared; + RootedId id(cx, NameToId(name)); + RootedShape shape(cx, StaticBlockObject::addVar(cx, blockObj, id, index, &redeclared)); + if (!shape) { + if (redeclared) + parser->reportRedeclaration(pn, false, name); + return false; + } + + /* Store pn in the static block object. */ + blockObj->setDefinitionParseNode(index, reinterpret_cast(pn)); + } else { + // Body-level lets are hoisted and need to have been defined via + // pc->define above. + MOZ_ASSERT(data->let.varContext == HoistVars); + MOZ_ASSERT(pc->decls().lookupFirst(name)); } - /* Store pn in the static block object. */ - blockObj->setDefinitionParseNode(index, reinterpret_cast(pn)); return true; } @@ -2998,8 +3167,17 @@ Parser::noteNameUse(HandlePropertyName name, Node pn) handler.linkUseToDef(pn, dn); - if (stmt && stmt->type == STMT_WITH) - handler.setFlag(pn, PND_DEOPTIMIZED); + if (stmt) { + if (stmt->type == STMT_WITH) { + handler.setFlag(pn, PND_DEOPTIMIZED); + } else if (stmt->type == STMT_SWITCH && stmt->isBlockScope) { + // See comments above StmtInfoPC and switchStatement for how + // firstDominatingLetInCase is computed. + MOZ_ASSERT(stmt->firstDominatingLexicalInCase <= stmt->staticBlock().numVariables()); + handler.markMaybeUninitializedLexicalUseInSwitch(pn, dn, + stmt->firstDominatingLexicalInCase); + } + } return true; } @@ -3020,7 +3198,9 @@ Parser::bindDestructuringVar(BindData *data, * Select the appropriate name-setting opcode, respecting eager selection * done by the data->binder function. */ - if (pn->pn_dflags & PND_BOUND) + if (data->op == JSOP_INITLEXICAL) + pn->setOp(JSOP_INITLEXICAL); + else if (pn->pn_dflags & PND_BOUND) pn->setOp(JSOP_SETLOCAL); else if (data->op == JSOP_DEFCONST) pn->setOp(JSOP_SETCONST); @@ -3439,7 +3619,7 @@ Parser::variables(ParseNodeKind kind, bool *psimple, */ JS_ASSERT_IF(psimple, *psimple); - JSOp op = blockObj ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST; + JSOp op = kind == PNK_LET ? JSOP_NOP : kind == PNK_VAR ? JSOP_DEFVAR : JSOP_DEFCONST; Node pn = handler.newList(kind, null(), op); if (!pn) @@ -3451,8 +3631,8 @@ Parser::variables(ParseNodeKind kind, bool *psimple, * this code will change soon. */ BindData data(context); - if (blockObj) - data.initLet(varContext, *blockObj, JSMSG_TOO_MANY_LOCALS); + if (kind == PNK_LET) + data.initLet(varContext, blockObj, JSMSG_TOO_MANY_LOCALS); else data.initVarOrConst(op); @@ -3474,10 +3654,16 @@ Parser::variables(ParseNodeKind kind, bool *psimple, if (!pn2) return null(); - if (!checkDestructuring(&data, pn2)) - return null(); bool ignored; - if (pc->parsingForInit && matchInOrOf(&ignored)) { + bool parsingForInOrOfInit = pc->parsingForInit && matchInOrOf(&ignored); + + // See comment below for bindBeforeInitializer in the code that + // handles the non-destructuring case. + bool bindBeforeInitializer = kind != PNK_LET || parsingForInOrOfInit; + if (bindBeforeInitializer && !checkDestructuring(&data, pn2)) + return null(); + + if (parsingForInOrOfInit) { tokenStream.ungetToken(); handler.addList(pn, pn2); continue; @@ -3489,6 +3675,9 @@ Parser::variables(ParseNodeKind kind, bool *psimple, if (!init) return null(); + if (!bindBeforeInitializer && !checkDestructuring(&data, pn2)) + return null(); + pn2 = handler.newBinaryOrAppend(PNK_ASSIGN, pn2, init, pc); if (!pn2) return null(); @@ -3514,21 +3703,40 @@ Parser::variables(ParseNodeKind kind, bool *psimple, if (data.op == JSOP_DEFCONST) handler.setFlag(pn2, PND_CONST); data.pn = pn2; - if (!data.binder(&data, name, this)) - return null(); + handler.addList(pn, pn2); if (tokenStream.matchToken(TOK_ASSIGN)) { if (psimple) *psimple = false; + // In ES6, lexical bindings may not be accessed until + // initialized. So a declaration of the form |let x = x| results + // in a ReferenceError, as the 'x' on the RHS is accessing the let + // binding before it is initialized. + // + // If we are not parsing a let declaration, bind the name + // now. Otherwise we must wait until after parsing the initializing + // assignment. + bool bindBeforeInitializer = kind != PNK_LET; + if (bindBeforeInitializer && !data.binder(&data, name, this)) + return null(); + Node init = assignExpr(); if (!init) return null(); + if (!bindBeforeInitializer && !data.binder(&data, name, this)) + return null(); + if (!handler.finishInitializerAssignment(pn2, init, data.op)) return null(); + } else { + if (!data.binder(&data, name, this)) + return null(); } + + } while (tokenStream.matchToken(TOK_COMMA)); return pn; @@ -3575,19 +3783,27 @@ Parser::letDeclaration() * conflicting slots. Forbid top-level let declarations to * prevent such conflicts from ever occurring. */ - if (options().selfHostingMode && - !pc->sc->isFunctionBox() && - stmt == pc->topScopeStmt) - { + bool globalLet = !pc->sc->isFunctionBox() && stmt == pc->topScopeStmt; + if (options().selfHostingMode && globalLet) { report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LET); return null(); } /* - * ES4 specifies that let at top level and at body-block scope - * does not shadow var, so convert back to var. + * Parse body-level lets without a new block object. ES6 specs + * that an execution environment's initial lexical environment + * is the VariableEnvironment, i.e., body-level lets are in + * the same environment record as vars. + * + * However, they cannot be parsed exactly as vars, as ES6 + * requires that uninitialized lets throw ReferenceError on use. + * + * See 8.1.1.1.6 and the note in 13.2.1. + * + * FIXME global-level lets are still considered vars until + * other bugs are fixed. */ - pn = variables(PNK_VAR); + pn = variables(globalLet ? PNK_VAR : PNK_LET); if (!pn) return null(); pn->pn_xflags |= PNX_POPVAR; @@ -4625,6 +4841,19 @@ Parser::switchStatement() handler.addList(body, stmt); } + // In ES6, lexical bindings canot be accessed until initialized. If + // there was a 'let' declaration in the case we just parsed, remember + // the slot starting at which new lexical bindings will be + // assigned. Since lexical bindings from previous cases will not + // dominate uses in the current case, any such uses will require a + // dead zone check. + // + // Currently this is overly conservative; we could do better, but + // declaring lexical bindings within switch cases without introducing + // a new block is poor form and should be avoided. + if (stmtInfo.isBlockScope) + stmtInfo.firstDominatingLexicalInCase = stmtInfo.staticBlock().numVariables(); + Node casepn = handler.newCaseOrDefault(caseBegin, caseExpr, body); if (!casepn) return null(); @@ -5102,7 +5331,7 @@ Parser::tryStatement() * scoped, not a property of a new Object instance. This is * an intentional change that anticipates ECMA Ed. 4. */ - data.initLet(HoistVars, pc->staticScope->template as(), + data.initLet(HoistVars, &pc->staticScope->template as(), JSMSG_TOO_MANY_CATCH_VARS); JS_ASSERT(data.let.blockObj); @@ -6156,7 +6385,7 @@ Parser::legacyComprehensionTail(ParseNode *bodyStmt, unsigned return null(); JS_ASSERT(pc->staticScope && pc->staticScope == pn->pn_objbox->object); - data.initLet(HoistVars, pc->staticScope->as(), JSMSG_ARRAY_INIT_TOO_BIG); + data.initLet(HoistVars, &pc->staticScope->as(), JSMSG_ARRAY_INIT_TOO_BIG); do { /* @@ -6272,21 +6501,25 @@ Parser::legacyComprehensionTail(ParseNode *bodyStmt, unsigned /* * Synthesize a declaration. Every definition must appear in the parse * tree in order for ComprehensionTranslator to work. + * + * These are lets to tell the bytecode emitter to emit initialization + * code for the temporal dead zone. */ - ParseNode *vars = ListNode::create(PNK_VAR, &handler); - if (!vars) + ParseNode *lets = ListNode::create(PNK_LET, &handler); + if (!lets) return null(); - vars->setOp(JSOP_NOP); - vars->pn_pos = pn3->pn_pos; - vars->makeEmpty(); - vars->append(pn3); + lets->setOp(JSOP_NOP); + lets->pn_pos = pn3->pn_pos; + lets->makeEmpty(); + lets->append(pn3); + lets->pn_xflags |= PNX_POPVAR; /* Definitions can't be passed directly to EmitAssignment as lhs. */ pn3 = cloneLeftHandSide(pn3); if (!pn3) return null(); - pn2->pn_left = handler.newTernary(headKind, vars, pn3, pn4); + pn2->pn_left = handler.newTernary(headKind, lets, pn3, pn4); if (!pn2->pn_left) return null(); *pnp = pn2; @@ -6452,7 +6685,7 @@ Parser::generatorComprehensionLambda(GeneratorKind comprehensionKi PropagateTransitiveParseFlags(genFunbox, outerpc->sc); - if (!leaveFunction(genfn, outerpc)) + if (!leaveFunction(genfn, outerpc, /* bodyLevelHoistedUse = */ false)) return null(); return genfn; @@ -6558,7 +6791,7 @@ Parser::comprehensionFor(GeneratorKind comprehensionKind) RootedStaticBlockObject blockObj(context, StaticBlockObject::create(context)); if (!blockObj) return null(); - data.initLet(DontHoistVars, *blockObj, JSMSG_TOO_MANY_LOCALS); + data.initLet(DontHoistVars, blockObj, JSMSG_TOO_MANY_LOCALS); Node lhs = newName(name); if (!lhs) return null(); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 4cb51fa56c95..3cde705915c2 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -30,7 +30,19 @@ struct StmtInfoPC : public StmtInfoBase { uint32_t blockid; /* for simplified dominance computation */ uint32_t innerBlockScopeDepth; /* maximum depth of nested block scopes, in slots */ - explicit StmtInfoPC(ExclusiveContext *cx) : StmtInfoBase(cx), innerBlockScopeDepth(0) {} + // Lexical declarations inside switches are tricky because the block id + // doesn't convey dominance information. Record what index the current + // case's lexical declarations start at so we may generate dead zone + // checks for other cases' declarations. + // + // Only valid if type is STMT_SWITCH. + uint16_t firstDominatingLexicalInCase; + + explicit StmtInfoPC(ExclusiveContext *cx) + : StmtInfoBase(cx), + innerBlockScopeDepth(0), + firstDominatingLexicalInCase(0) + {} }; typedef HashSet, LifoAllocPolicy> FuncStmtSet; @@ -126,10 +138,14 @@ struct ParseContext : public GenericParseContext uint32_t blockScopeDepth; /* maximum depth of nested block scopes, in slots */ Node blockNode; /* parse node for a block with let declarations (block with its own lexical scope) */ + private: - AtomDecls decls_; /* function, const, and var declarations */ - DeclVector args_; /* argument definitions */ - DeclVector vars_; /* var/const definitions */ + AtomDecls decls_; /* function, const, and var declarations */ + DeclVector args_; /* argument definitions */ + DeclVector vars_; /* var/const definitions */ + DeclVector bodyLevelLexicals_; /* lexical definitions at body-level */ + + bool checkLocalsOverflow(TokenStream &ts); public: const AtomDecls &decls() const { @@ -259,6 +275,7 @@ struct ParseContext : public GenericParseContext decls_(prs->context, prs->alloc), args_(prs->context), vars_(prs->context), + bodyLevelLexicals_(prs->context), parserPC(&prs->pc), oldpc(prs->pc), lexdeps(prs->context), @@ -557,7 +574,8 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter bool functionArgsAndBody(Node pn, HandleFunction fun, FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind, - Directives inheritedDirectives, Directives *newDirectives); + Directives inheritedDirectives, Directives *newDirectives, + bool bodyLevelHoistedUse); Node unaryOpExpr(ParseNodeKind kind, JSOp op, uint32_t begin); @@ -606,11 +624,12 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter bool matchInOrOf(bool *isForOfp); bool checkFunctionArguments(); - bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom); + bool makeDefIntoUse(Definition *dn, Node pn, JSAtom *atom, bool *pbodyLevelHoistedUse); bool checkFunctionDefinition(HandlePropertyName funName, Node *pn, FunctionSyntaxKind kind, - bool *pbodyProcessed); + bool *pbodyProcessed, bool *pbodyLevelHoistedUse); bool finishFunctionDefinition(Node pn, FunctionBox *funbox, Node prelude, Node body); - bool addFreeVariablesFromLazyFunction(JSFunction *fun, ParseContext *pc); + bool addFreeVariablesFromLazyFunction(JSFunction *fun, ParseContext *pc, + bool bodyLevelHoistedUse); bool isValidForStatementLHS(Node pn1, JSVersion version, bool forDecl, bool forEach, ParseNodeKind headKind); @@ -661,7 +680,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter DefinitionNode getOrCreateLexicalDependency(ParseContext *pc, JSAtom *atom); bool leaveFunction(Node fn, ParseContext *outerpc, - FunctionSyntaxKind kind = Expression); + bool bodyLevelHoistedUse, FunctionSyntaxKind kind = Expression); TokenPos pos() const { return tokenStream.currentToken().pos; } diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 3fa7809897c5..ff4b7ea480cc 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -427,6 +427,9 @@ struct StmtInfoBase { return isNestedScope; } + void setStaticScope() { + } + StaticBlockObject& staticBlock() const { JS_ASSERT(isNestedScope); JS_ASSERT(isBlockScope); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index 83161a5b879c..01b01001bf7e 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -249,6 +249,7 @@ class SyntaxParseHandler static Node getDefinitionNode(DefinitionNode dn) { return NodeGeneric; } static Definition::Kind getDefinitionKind(DefinitionNode dn) { return dn; } + static bool isPlaceholderDefinition(DefinitionNode dn) { return dn == Definition::PLACEHOLDER; } void linkUseToDef(Node pn, DefinitionNode dn) {} DefinitionNode resolve(DefinitionNode dn) { return dn; } void deoptimizeUsesWithin(DefinitionNode dn, const TokenPos &pos) {} @@ -258,6 +259,8 @@ class SyntaxParseHandler // dependency location with blockid. return functionScope; } + void markMaybeUninitializedLexicalUseInSwitch(Node pn, DefinitionNode dn, + uint16_t firstDominatingLexicalSlot) {} static uintptr_t definitionToBits(DefinitionNode dn) { // Use a shift, as DefinitionList tags the lower bit of its associated union. diff --git a/js/src/jit-test/tests/arguments/alias-function-closed.js b/js/src/jit-test/tests/arguments/alias-function-closed.js index 68579238564a..6b880b4b8164 100644 --- a/js/src/jit-test/tests/arguments/alias-function-closed.js +++ b/js/src/jit-test/tests/arguments/alias-function-closed.js @@ -122,7 +122,7 @@ function f5(a, b, c, d) { } var a, b = ()=>63; - let c, d = ()=>65; + var c, d = ()=>65; // after var declarations, before function declarations assertEq(a(), 52); diff --git a/js/src/jit-test/tests/arguments/alias-function-not-closed.js b/js/src/jit-test/tests/arguments/alias-function-not-closed.js index 90ddba10f836..a9ef12992567 100644 --- a/js/src/jit-test/tests/arguments/alias-function-not-closed.js +++ b/js/src/jit-test/tests/arguments/alias-function-not-closed.js @@ -59,7 +59,7 @@ function f3(a, b, c, d) { assertEq(d(), 55); var a, b = ()=>63; - let c, d = ()=>65; + var c, d = ()=>65; // after var declarations, before function declarations assertEq(a(), 52); diff --git a/js/src/jit-test/tests/basic/bug1001090-1.js b/js/src/jit-test/tests/basic/bug1001090-1.js new file mode 100644 index 000000000000..86970ffc46dd --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1001090-1.js @@ -0,0 +1,2 @@ +(function() { let arguments })(); +(() => { let arguments; })() diff --git a/js/src/jit-test/tests/basic/bug1001090-2.js b/js/src/jit-test/tests/basic/bug1001090-2.js new file mode 100644 index 000000000000..2a3be2722153 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1001090-2.js @@ -0,0 +1,5 @@ +// |jit-test| error: ReferenceError +(function() { + with(x); + let x +})() diff --git a/js/src/jit-test/tests/basic/bug1001090-3.js b/js/src/jit-test/tests/basic/bug1001090-3.js new file mode 100644 index 000000000000..ba3a88f1b2e4 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1001090-3.js @@ -0,0 +1,27 @@ +var output = []; +function g(s) { + L = s.length; + for (var i = 0; i < L; i++) { + a = s.charAt() + } +} +function h(f, inputs) { + results = []; + for (var j = 0; j < 99; ++j) { + for (var k = 0; k < 99; ++k) { + try { + results.push(f()) + } catch (e) {} + } + } + output.push(g(uneval(results))) +} +m = (function(x, y) {}); +h(m, []) +try { + output.push(x); + let x = s() +} catch (e) {} + +assertEq(output.length, 1); +assertEq(output[0], undefined); diff --git a/js/src/jit-test/tests/basic/bug1001090-4.js b/js/src/jit-test/tests/basic/bug1001090-4.js new file mode 100644 index 000000000000..0511eea2a1a7 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1001090-4.js @@ -0,0 +1,30 @@ +var output = []; +function g(s) { + for (var i = 0; i < s.length; i++) { + s.charAt() + } +} +function h(f, inputs) { + results = [] + for (var j = 0; j < 99; ++j) { + for (var k = 0; k < 99; ++k) { + try { + results.push(f()) + } catch (e) {} + } + } + g(uneval(results)) +} +try { + x() +} catch (e) {} +m = function(y) { + return y; +}; +h(m, []); +try { + output.push(b); + let b = ""; +} catch (e) {} + +assertEq(output.length, 0); diff --git a/js/src/jit-test/tests/basic/bug1001090-5.js b/js/src/jit-test/tests/basic/bug1001090-5.js new file mode 100644 index 000000000000..4636ca053f9f --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1001090-5.js @@ -0,0 +1,6 @@ +// |jit-test| error: ReferenceError +evalcx("\ + for(x = 0; x < 9; x++) {\ + let y = y.s()\ + }\ +", newGlobal()) diff --git a/js/src/jit-test/tests/basic/bug1001090-6.js b/js/src/jit-test/tests/basic/bug1001090-6.js new file mode 100644 index 000000000000..14d60e8043e9 --- /dev/null +++ b/js/src/jit-test/tests/basic/bug1001090-6.js @@ -0,0 +1,7 @@ +// |jit-test| error: ReferenceError +(function() { + ((function() { + p(y) + })()); + let y +})() diff --git a/js/src/jit-test/tests/basic/letLegacyForOfOrInScope.js b/js/src/jit-test/tests/basic/letLegacyForOfOrInScope.js new file mode 100644 index 000000000000..d1c0764dc5d2 --- /dev/null +++ b/js/src/jit-test/tests/basic/letLegacyForOfOrInScope.js @@ -0,0 +1,5 @@ +var x = "foobar"; +{ for (let x of x) assertEq(x.length, 1, "second x refers to outer x"); } + +var x = "foobar"; +{ for (let x in x) assertEq(x.length, 1, "second x refers to outer x"); } diff --git a/js/src/jit-test/tests/basic/letTDZAfterInitializer.js b/js/src/jit-test/tests/basic/letTDZAfterInitializer.js new file mode 100644 index 000000000000..575615c17627 --- /dev/null +++ b/js/src/jit-test/tests/basic/letTDZAfterInitializer.js @@ -0,0 +1,19 @@ +function throwSomething() { + throw "something"; +} + +try { + // Use eval to force BINDNAME. Should throw "something" instead of the TDZ + // ReferenceError. + eval("x = throwSomething()"); + let x; +} catch (e) { + assertEq(e, "something"); +} + +try { + eval("x = 42"); + let x; +} catch (e) { + assertEq(e instanceof ReferenceError, true); +} diff --git a/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js b/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js index e149591492c1..7be49b7f395a 100644 --- a/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js +++ b/js/src/jit-test/tests/basic/testFunctionStatementAliasLocals.js @@ -14,13 +14,3 @@ function f2(b, w) { } assertEq(typeof f2(true, 3), "function"); assertEq(f2(false, 3), 3); - -function f3(b) { - let (w = 3) { - if (b) - function w() {} - return w; - } -} -assertEq(f3(true, 3), 3); -assertEq(f3(false), 3); diff --git a/js/src/jit-test/tests/basic/testLet.js b/js/src/jit-test/tests/basic/testLet.js index d5d122433da8..7b27f5062fb0 100644 --- a/js/src/jit-test/tests/basic/testLet.js +++ b/js/src/jit-test/tests/basic/testLet.js @@ -32,13 +32,25 @@ function test(str, arg, result) } } -function isError(str) +function isParseError(str) { var caught = false; try { new Function(str); } catch(e) { - assertEq(String(e).indexOf('TypeError') == 0 || String(e).indexOf('SyntaxError') == 0, true); + assertEq(e instanceof TypeError || e instanceof SyntaxError, true); + caught = true; + } + assertEq(caught, true); +} + +function isReferenceError(str) +{ + var caught = false; + try { + (new Function(str))(); + } catch(e) { + assertEq(e instanceof ReferenceError, true); caught = true; } assertEq(caught, true); @@ -86,12 +98,12 @@ test('"use strict";return let (y = x) (eval("var y = 2"), y);'); test('this.y = x;return let (y = 1) this.eval("y");'); test('try {let (x = x) eval("throw x");} catch (e) {return e;}'); test('try {return let (x = eval("throw x")) x;} catch (e) {return e;}'); -isError('let (x = 1, x = 2) x'); -isError('let ([x, y] = a, {a:x} = b) x'); -isError('let ([x, y, x] = a) x'); -isError('let ([x, [y, [x]]] = a) x'); -isError('let (x = function() { return x}) x()return x;'); -isError('(let (x = function() { return x}) x())return x;'); +isParseError('let (x = 1, x = 2) x'); +isParseError('let ([x, y] = a, {a:x} = b) x'); +isParseError('let ([x, y, x] = a) x'); +isParseError('let ([x, [y, [x]]] = a) x'); +isParseError('let (x = function() { return x}) x()return x;'); +isParseError('(let (x = function() { return x}) x())return x;'); // let block test('let (y) {return x;}'); @@ -133,10 +145,10 @@ test('return eval("let (y = x) {y;}");'); test('let (y = x) {eval("var y = 2");return y;}', 'ponies', 2); test('"use strict";let (y = x) {eval("var y = 2");return y;}'); test('this.y = x;let (y = 1) {return this.eval("y");}'); -isError('let (x = 1, x = 2) {x}'); -isError('let ([x, y] = a, {a:x} = b) {x}'); -isError('let ([x, y, x] = a) {x}'); -isError('let ([x, [y, [x]]] = a) {x}'); +isParseError('let (x = 1, x = 2) {x}'); +isParseError('let ([x, y] = a, {a:x} = b) {x}'); +isParseError('let ([x, y, x] = a) {x}'); +isParseError('let ([x, [y, [x]]] = a) {x}'); // var declarations test('var y;return x;'); @@ -171,15 +183,10 @@ test('if (x) {var z = y;var [y] = x;z += y;}return z;', ['-'], 'undefined-'); test('if (x) {let y;return x;}'); test('if (x) {let x;return "" + x;}', 'unicorns', 'undefined'); test('if (x) {let y = x;return x;}'); -test('if (x) {y = x;let y = y;return y;}'); -test('if (x) {var z = y;let [y] = x;z += y;}return z;', ['-'], 'undefined-'); test('if (x) {let y = x;return x;}'); test('if (x) {let [] = x;return x;}'); test('if (x) {let [, ] = x;return x;}'); test('if (x) {let [, , , , ] = x;return x;}'); -test('if (x) {let x = x;return "" + x;}', 'unicorns', 'undefined'); -test('if (x) {let y = y;return "" + y;}', 'unicorns', 'undefined'); -test('if (x) {let x = eval("x");return "" + x;}', 'unicorns', 'undefined'); test('if (x) {let y = (let (x = x + 1) x) + 1;return y;}', 1, 3); test('if (x) {let y = (let (x = eval("x") + 1) eval("x")) + 1;return eval("y");}', 1, 3); test('if (x) {let X = x + 1, y = x;return y;}'); @@ -214,11 +221,11 @@ test('"use strict";if (x) {let y = x;eval("var y = 2");return y;}'); test('"use strict";if (x) {let y = x;eval("let y = 2");return y;}'); test('"use strict";if (x) {let y = 1;return eval("let y = x;y;");}'); test('this.y = x;if (x) {let y = 1;return this.eval("y");}'); -isError('if (x) {let (x = 1, x = 2) {x}}'); -isError('if (x) {let ([x, y] = a, {a:x} = b) {x}}'); -isError('if (x) {let ([x, y, x] = a) {x}}'); -isError('if (x) {let ([x, [y, [x]]] = a) {x}}'); -isError('let ([x, y] = x) {let x;}'); +isParseError('if (x) {let (x = 1, x = 2) {x}}'); +isParseError('if (x) {let ([x, y] = a, {a:x} = b) {x}}'); +isParseError('if (x) {let ([x, y, x] = a) {x}}'); +isParseError('if (x) {let ([x, [y, [x]]] = a) {x}}'); +isParseError('let ([x, y] = x) {let x;}'); // for(;;) test('for (;;) {return x;}'); @@ -253,10 +260,10 @@ test('for (let a = x;;) {let c = x, d = x;return c;}'); test('for (let [a, b] = x;;) {let c = x, d = x;return c;}'); test('for (let [a] = (1, [x]);;) {return a;}'); test('for (let [a] = (1, x, 1, x);;) {return a;}', ['ponies']); -isError('for (let x = 1, x = 2;;) {}'); -isError('for (let [x, y] = a, {a:x} = b;;) {}'); -isError('for (let [x, y, x] = a;;) {}'); -isError('for (let [x, [y, [x]]] = a;;) {}'); +isParseError('for (let x = 1, x = 2;;) {}'); +isParseError('for (let [x, y] = a, {a:x} = b;;) {}'); +isParseError('for (let [x, y, x] = a;;) {}'); +isParseError('for (let [x, [y, [x]]] = a;;) {}'); // for(in) test('for (let i in x) {return x;}'); @@ -283,9 +290,9 @@ test('a:for (let i in x) {for (let j in x) {break a;}}return eval("x");'); test('var j;for (let i in x) {j = i;break;}return j;', {ponies:true}); test('try {for (let x in eval("throw x")) {}} catch (e) {return e;}'); test('try {for each (let x in x) {eval("throw x");}} catch (e) {return e;}', ['ponies']); -isError('for (let [x, x] in o) {}'); -isError('for (let [x, y, x] in o) {}'); -isError('for (let [x, [y, [x]]] in o) {}'); +isParseError('for (let [x, x] in o) {}'); +isParseError('for (let [x, y, x] in o) {}'); +isParseError('for (let [x, [y, [x]]] in o) {}'); // genexps test('return (i for (i in x)).next();', {ponies:true}); @@ -302,6 +309,21 @@ test('try {return [eval("throw i") for (i in x)][0];} catch (e) {return e;}', {p // don't forget about switch craziness test('var y = 3;switch (function () {return eval("y");}()) {case 3:let y;return x;default:;}'); test('switch (x) {case 3:let y;return 3;case 4:let z;return 4;default:return x;}'); -test('switch (x) {case 3:let x;break;default:if (x === undefined) {return "ponies";}}'); test('switch (x) {case 3:default:let y;let (y = x) {return y;}}'); -isError('switch (x) {case 3:let y;return 3;case 4:let y;return 4;default:;}'); +isParseError('switch (x) {case 3:let y;return 3;case 4:let y;return 4;default:;}'); + +// TDZ checks +isReferenceError('x + 1; let x = 42;'); +isReferenceError('x = 42; let x;'); +isReferenceError('inner(); function inner() { x++; } let x;'); +isReferenceError('inner(); let x; function inner() { x++; }'); +isReferenceError('inner(); let x; function inner() { function innerer() { x++; } innerer(); }'); +isReferenceError('let x; var inner = function () { y++; }; inner(); let y;'); +isReferenceError('let x = x;'); +isReferenceError('let [x] = [x];'); +isReferenceError('let {x} = {x:x};'); +isReferenceError('switch (x) {case 3:let x;break;default:if (x === undefined) {return "ponies";}}'); +isReferenceError('let x = function() {} ? x() : function() {}'); + +// redecl with function statements +isParseError('let a; function a() {}'); diff --git a/js/src/jit-test/tests/debug/Environment-variables.js b/js/src/jit-test/tests/debug/Environment-variables.js index 1a074597d4f6..d20548d8d5f8 100644 --- a/js/src/jit-test/tests/debug/Environment-variables.js +++ b/js/src/jit-test/tests/debug/Environment-variables.js @@ -30,8 +30,6 @@ var cases = [ // bindings in functions "function f() { var x = VAL; @@ } f();", "function f() { let x = VAL; @@ } f();", - "function f([x]) { let x = VAL; @@ } f(['fail']);", - "function f(x) { { let x = VAL; @@ } } f('fail');", "function f() { function x() {} x = VAL; @@ } f();", // dynamic bindings diff --git a/js/src/jit-test/tests/debug/Frame-eval-21.js b/js/src/jit-test/tests/debug/Frame-eval-21.js index 097eb5078f5d..332c84f29299 100644 --- a/js/src/jit-test/tests/debug/Frame-eval-21.js +++ b/js/src/jit-test/tests/debug/Frame-eval-21.js @@ -1,5 +1,8 @@ // Eval-in-frame with different type on baseline frame with let-scoping +// FIXMEshu disabled until TDZ checks are implemented in the JITs. +quit(0); + load(libdir + "jitopts.js"); if (!jitTogglesMatch(Opts_BaselineEager)) diff --git a/js/src/jit-test/tests/jaeger/bug583672.js b/js/src/jit-test/tests/jaeger/bug583672.js index 79335ece3b41..6280fa470e30 100644 --- a/js/src/jit-test/tests/jaeger/bug583672.js +++ b/js/src/jit-test/tests/jaeger/bug583672.js @@ -9,7 +9,7 @@ { new f } - let w = {} + var w = {} })() /* Make sure that MICs don't have the same bug. */ @@ -25,6 +25,6 @@ x = Object(); { new f } - let w = {} + var w = {} })() /* Don't assert. */ diff --git a/js/src/jit-test/tests/parallel/write-array.js b/js/src/jit-test/tests/parallel/write-array.js index 8b917a62629f..25dcea99e0a8 100644 --- a/js/src/jit-test/tests/parallel/write-array.js +++ b/js/src/jit-test/tests/parallel/write-array.js @@ -3,7 +3,7 @@ load(libdir + "parallelarray-helpers.js"); function buildSimple() { assertParallelModesCommute(["seq", "par"], function(m) { return Array.buildPar(256, function(i) { - let obj = [i, 1, 2]; + var obj = [i, 1, 2]; obj[0] += 1; obj[1] += 1; obj[2] += 1; diff --git a/js/src/jit-test/tests/parallel/write-obj.js b/js/src/jit-test/tests/parallel/write-obj.js index fc6a67fb8867..ae9d411468bd 100644 --- a/js/src/jit-test/tests/parallel/write-obj.js +++ b/js/src/jit-test/tests/parallel/write-obj.js @@ -3,7 +3,7 @@ load(libdir + "parallelarray-helpers.js"); function buildSimple() { assertParallelModesCommute(["seq", "par"], function(m) { Array.buildPar(256, function(i) { - let obj = { x: i, y: i + 1, z: i + 2 }; + var obj = { x: i, y: i + 1, z: i + 2 }; obj.x += 1; obj.y += 1; obj.z += 1; diff --git a/js/src/jit/BaselineFrame.cpp b/js/src/jit/BaselineFrame.cpp index 785cdc1c4c82..958da8e97b46 100644 --- a/js/src/jit/BaselineFrame.cpp +++ b/js/src/jit/BaselineFrame.cpp @@ -57,7 +57,7 @@ BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator) // Mark locals and stack values. JSScript *script = this->script(); size_t nfixed = script->nfixed(); - size_t nlivefixed = script->nfixedvars(); + size_t nlivefixed = script->nbodyfixed(); if (nfixed != nlivefixed) { jsbytecode *pc; @@ -75,7 +75,7 @@ BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator) } JS_ASSERT(nlivefixed <= nfixed); - JS_ASSERT(nlivefixed >= script->nfixedvars()); + JS_ASSERT(nlivefixed >= script->nbodyfixed()); // NB: It is possible that numValueSlots() could be zero, even if nfixed is // nonzero. This is the case if the function has an early stack check. @@ -91,9 +91,13 @@ BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator) // Mark operand stack. MarkLocals(this, trc, nfixed, numValueSlots()); - // Clear dead locals. - while (nfixed > nlivefixed) - unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined(); + // Clear non-magic dead locals. Magic values such as + // JS_UNINITIALIZED_LET need to be left as is for correctness. + while (nfixed > nlivefixed) { + --nfixed; + if (!unaliasedLocal(nfixed, DONT_CHECK_ALIASING).isMagic()) + unaliasedLocal(nfixed, DONT_CHECK_ALIASING).setUndefined(); + } // Mark live locals. MarkLocals(this, trc, 0, nlivefixed); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index a5a4c2789874..83627cc498a0 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -5962,7 +5962,8 @@ DoBindNameFallback(JSContext *cx, BaselineFrame *frame, ICBindName_Fallback *stu RootedPropertyName name(cx, frame->script()->getName(pc)); RootedObject scope(cx); - if (!LookupNameUnqualified(cx, name, scopeChain, &scope)) + RootedShape shape(cx); + if (!LookupNameUnqualified(cx, name, scopeChain, &scope, &shape)) return false; res.setObject(*scope); diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index a9eea178eafc..20a2864c2f45 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -187,7 +187,7 @@ class CompileInfo nimplicit_ = StartArgSlot(script) /* scope chain and argument obj */ + (fun ? 1 : 0); /* this */ nargs_ = fun ? fun->nargs() : 0; - nfixedvars_ = script->nfixedvars(); + nbodyfixed_ = script->nbodyfixed(); nlocals_ = script->nfixed(); nstack_ = script->nslots() - script->nfixed(); nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; @@ -200,7 +200,7 @@ class CompileInfo { nimplicit_ = 0; nargs_ = 0; - nfixedvars_ = 0; + nbodyfixed_ = 0; nlocals_ = nlocals; nstack_ = 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */ nslots_ = nlocals_ + nstack_; @@ -291,10 +291,10 @@ class CompileInfo unsigned nargs() const { return nargs_; } - // Number of slots needed for "fixed vars". Note that this is only non-zero - // for function code. - unsigned nfixedvars() const { - return nfixedvars_; + // Number of slots needed for fixed body-level bindings. Note that this + // is only non-zero for function code. + unsigned nbodyfixed() const { + return nbodyfixed_; } // Number of slots needed for all local variables. This includes "fixed // vars" (see above) and also block-scoped locals. @@ -377,9 +377,9 @@ class CompileInfo uint32_t local = index - firstLocalSlot(); if (local < nlocals()) { - // First, check if this local is a var. - if (local < nfixedvars()) - return script()->varIsAliased(local); + // First, check if this local is body-level. + if (local < nbodyfixed()) + return script()->bodyLevelLocalIsAliased(local); // Otherwise, it might be part of a block scope. for (; staticScope; staticScope = staticScope->enclosingNestedScope()) { @@ -466,7 +466,7 @@ class CompileInfo private: unsigned nimplicit_; unsigned nargs_; - unsigned nfixedvars_; + unsigned nbodyfixed_; unsigned nlocals_; unsigned nstack_; unsigned nslots_; diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 98083b993573..8a630b569097 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -4207,7 +4207,8 @@ BindNameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain) if (scopeChain->is()) { holder = scopeChain; } else { - if (!LookupNameUnqualified(cx, name, scopeChain, &holder)) + RootedShape shape(cx); + if (!LookupNameUnqualified(cx, name, scopeChain, &holder, &shape)) return nullptr; } diff --git a/js/src/js.msg b/js/src/js.msg index cde551aee552..07bd1b153fc5 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -109,6 +109,7 @@ MSG_DEF(JSMSG_BAD_PROTOTYPE, 1, JSEXN_TYPEERR, "'prototype' property o 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") +MSG_DEF(JSMSG_UNINITIALIZED_LEXICAL, 1, JSEXN_REFERENCEERR, "can't access let declaration `{0}' before initialization") // Date MSG_DEF(JSMSG_INVALID_DATE, 0, JSEXN_RANGEERR, "invalid date") diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 420a50ca4f14..fa31816f32eb 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -139,8 +139,11 @@ GetValueType(const Value &val) inline Type GetMaybeOptimizedOutValueType(const Value &val) { - if (val.isMagic() && val.whyMagic() == JS_OPTIMIZED_OUT) + if (val.isMagic() && (val.whyMagic() == JS_OPTIMIZED_OUT || + val.whyMagic() == JS_UNINITIALIZED_LEXICAL)) + { return Type::UnknownType(); + } return GetValueType(val); } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index dcd9810bb9a6..ba348c52aa03 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -4765,18 +4765,17 @@ js::LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain, bool js::LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, - MutableHandleObject objp) + MutableHandleObject objp, MutableHandleShape propp) { RootedId id(cx, NameToId(name)); RootedObject pobj(cx); - RootedShape prop(cx); RootedObject scope(cx, scopeChain); for (; !scope->is(); scope = scope->enclosingScope()) { - if (!JSObject::lookupGeneric(cx, scope, id, &pobj, &prop)) + if (!JSObject::lookupGeneric(cx, scope, id, &pobj, propp)) return false; - if (prop) + if (propp) break; } @@ -4786,21 +4785,29 @@ js::LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleOb bool js::LookupNameUnqualified(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, - MutableHandleObject objp) + MutableHandleObject objp, MutableHandleShape propp) { RootedId id(cx, NameToId(name)); RootedObject pobj(cx); - RootedShape prop(cx); RootedObject scope(cx, scopeChain); for (; !scope->isUnqualifiedVarObj(); scope = scope->enclosingScope()) { - if (!JSObject::lookupGeneric(cx, scope, id, &pobj, &prop)) + if (!JSObject::lookupGeneric(cx, scope, id, &pobj, propp)) return false; - if (prop) + if (propp) break; } + // If the name was found not on the scope object itself, null out the + // shape, which is passed as an out pointer to determine uninitialized + // lexical slots. In the case when the name is not found on the scope + // object itself, it cannot be an uninitialized lexical slot. + // + // See the JSOP_BINDNAME case in the Interpreter. + if (pobj != scope) + propp.set(nullptr); + objp.set(scope); return true; } @@ -4890,8 +4897,8 @@ NativeGetInline(JSContext *cx, if (shape->hasSlot()) { vp.set(pobj->nativeGetSlot(shape->slot())); - JS_ASSERT(!vp.isMagic()); - JS_ASSERT_IF(!pobj->hasSingletonType() && + JS_ASSERT_IF(!vp.isMagic(JS_UNINITIALIZED_LEXICAL) && + !pobj->hasSingletonType() && !pobj->template is() && shape->hasDefaultGetter(), js::types::TypeHasProperty(cx, pobj->type(), shape->propid(), vp)); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 226c192061ee..c83af2519da8 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1468,18 +1468,17 @@ LookupNameNoGC(JSContext *cx, PropertyName *name, JSObject *scopeChain, */ extern bool LookupNameWithGlobalDefault(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, - MutableHandleObject objp); + MutableHandleObject objp, MutableHandleShape propp); /* * Like LookupName except returns the unqualified var object if 'name' is not found in * any preceding scope. Normally the unqualified var object is the global. * - * Additionally, pobjp and propp are not needed by callers so they are not - * returned. + * Additionally, pobjp is not needed by callers so it is not returned. */ extern bool LookupNameUnqualified(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, - MutableHandleObject objp); + MutableHandleObject objp, MutableHandleShape propp); } diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index ba22cca86b27..ecbca61a1ee9 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1635,7 +1635,7 @@ JSAtom * ExpressionDecompiler::getLocal(uint32_t local, jsbytecode *pc) { JS_ASSERT(local < script->nfixed()); - if (local < script->nfixedvars()) { + if (local < script->nbodyfixed()) { JS_ASSERT(fun); uint32_t slot = local + fun->nargs(); JS_ASSERT(slot < script->bindings.count()); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index b670870e309b..81c60d34b140 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -76,8 +76,9 @@ Bindings::argumentsVarIndex(ExclusiveContext *cx, InternalBindingsHandle binding bool Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self, - unsigned numArgs, uint32_t numVars, - Binding *bindingArray, uint32_t numBlockScoped) + uint32_t numArgs, uint32_t numVars, + uint32_t numBodyLevelLexicals, uint32_t numBlockScoped, + Binding *bindingArray) { JS_ASSERT(!self->callObjShape_); JS_ASSERT(self->bindingArrayAndFlag_ == TEMPORARY_STORAGE_BIT); @@ -85,12 +86,17 @@ Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle JS_ASSERT(numArgs <= ARGC_LIMIT); JS_ASSERT(numVars <= LOCALNO_LIMIT); JS_ASSERT(numBlockScoped <= LOCALNO_LIMIT); - JS_ASSERT(numVars <= LOCALNO_LIMIT - numBlockScoped); - JS_ASSERT(UINT32_MAX - numArgs >= numVars + numBlockScoped); + JS_ASSERT(numBodyLevelLexicals <= LOCALNO_LIMIT); + uint64_t totalSlots = uint64_t(numVars) + + uint64_t(numBodyLevelLexicals) + + uint64_t(numBlockScoped); + JS_ASSERT(totalSlots <= LOCALNO_LIMIT); + JS_ASSERT(UINT32_MAX - numArgs >= totalSlots); self->bindingArrayAndFlag_ = uintptr_t(bindingArray) | TEMPORARY_STORAGE_BIT; self->numArgs_ = numArgs; self->numVars_ = numVars; + self->numBodyLevelLexicals_ = numBodyLevelLexicals; self->numBlockScoped_ = numBlockScoped; // Get the initial shape to use when creating CallObjects for this script. @@ -108,10 +114,25 @@ Bindings::initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle // any time, such accesses are mediated by DebugScopeProxy (see // DebugScopeProxy::handleUnaliasedAccess). uint32_t nslots = CallObject::RESERVED_SLOTS; + uint32_t aliasedBodyLevelLexicalBegin = UINT16_MAX; for (BindingIter bi(self); bi; bi++) { - if (bi->aliased()) + if (bi->aliased()) { + // Per ES6, lexical bindings cannot be accessed until + // initialized. Remember the first aliased slot that is a + // body-level let, so that they may be initialized to sentinel + // magic values. + if (numBodyLevelLexicals > 0 && + nslots < aliasedBodyLevelLexicalBegin && + bi->kind() == Binding::VARIABLE && + bi.frameIndex() >= numVars) + { + aliasedBodyLevelLexicalBegin = nslots; + } + nslots++; + } } + self->aliasedBodyLevelLexicalBegin_ = aliasedBodyLevelLexicalBegin; // Put as many of nslots inline into the object header as possible. uint32_t nfixed = gc::GetGCKindSlots(gc::GetGCObjectKind(nslots)); @@ -194,9 +215,13 @@ Bindings::clone(JSContext *cx, InternalBindingsHandle self, * Since atoms are shareable throughout the runtime, we can simply copy * the source's bindingArray directly. */ - if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(), src.bindingArray(), - src.numBlockScoped())) + if (!initWithTemporaryStorage(cx, self, src.numArgs(), src.numVars(), + src.numBodyLevelLexicals(), src.numBlockScoped(), + src.bindingArray())) + { return false; + } + self->switchToScriptStorage(dstPackedBindings); return true; } @@ -209,8 +234,8 @@ GCMethods::initial() template static bool -XDRScriptBindings(XDRState *xdr, LifoAllocScope &las, unsigned numArgs, uint32_t numVars, - HandleScript script, unsigned numBlockScoped) +XDRScriptBindings(XDRState *xdr, LifoAllocScope &las, uint16_t numArgs, uint32_t numVars, + uint16_t numBodyLevelLexicals, uint16_t numBlockScoped, HandleScript script) { JSContext *cx = xdr->cx(); @@ -227,7 +252,7 @@ XDRScriptBindings(XDRState *xdr, LifoAllocScope &las, unsigned numArgs, ui return false; } } else { - uint32_t nameCount = numArgs + numVars; + uint32_t nameCount = numArgs + numVars + numBodyLevelLexicals; AutoValueVector atoms(cx); if (!atoms.resize(nameCount)) @@ -255,9 +280,12 @@ XDRScriptBindings(XDRState *xdr, LifoAllocScope &las, unsigned numArgs, ui } InternalBindingsHandle bindings(script, &script->bindings); - if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, bindingArray, - numBlockScoped)) + if (!Bindings::initWithTemporaryStorage(cx, bindings, numArgs, numVars, + numBodyLevelLexicals, numBlockScoped, + bindingArray)) + { return false; + } } return true; @@ -431,17 +459,25 @@ XDRLazyFreeVariables(XDRState *xdr, MutableHandle lazy) { JSContext *cx = xdr->cx(); RootedAtom atom(cx); - HeapPtrAtom *freeVariables = lazy->freeVariables(); + uint8_t isHoistedUse; + LazyScript::FreeVariable *freeVariables = lazy->freeVariables(); size_t numFreeVariables = lazy->numFreeVariables(); for (size_t i = 0; i < numFreeVariables; i++) { - if (mode == XDR_ENCODE) - atom = freeVariables[i]; + if (mode == XDR_ENCODE) { + atom = freeVariables[i].atom(); + isHoistedUse = freeVariables[i].isHoistedUse(); + } if (!XDRAtom(xdr, &atom)) return false; + if (!xdr->codeUint8(&isHoistedUse)) + return false; - if (mode == XDR_DECODE) - freeVariables[i] = atom; + if (mode == XDR_DECODE) { + freeVariables[i] = LazyScript::FreeVariable(atom); + if (isHoistedUse) + freeVariables[i].setIsHoistedUse(); + } } return true; @@ -562,6 +598,7 @@ js::XDRScript(XDRState *xdr, HandleObject enclosingScope, HandleScript enc /* XDR arguments and vars. */ uint16_t nargs = 0; uint16_t nblocklocals = 0; + uint16_t nbodylevellexicals = 0; uint32_t nvars = 0; if (mode == XDR_ENCODE) { script = scriptp.get(); @@ -569,12 +606,15 @@ js::XDRScript(XDRState *xdr, HandleObject enclosingScope, HandleScript enc nargs = script->bindings.numArgs(); nblocklocals = script->bindings.numBlockScoped(); + nbodylevellexicals = script->bindings.numBodyLevelLexicals(); nvars = script->bindings.numVars(); } if (!xdr->codeUint16(&nargs)) return false; if (!xdr->codeUint16(&nblocklocals)) return false; + if (!xdr->codeUint16(&nbodylevellexicals)) + return false; if (!xdr->codeUint32(&nvars)) return false; @@ -721,7 +761,7 @@ js::XDRScript(XDRState *xdr, HandleObject enclosingScope, HandleScript enc /* JSScript::partiallyInit assumes script->bindings is fully initialized. */ LifoAllocScope las(&cx->tempLifoAlloc()); - if (!XDRScriptBindings(xdr, las, nargs, nvars, script, nblocklocals)) + if (!XDRScriptBindings(xdr, las, nargs, nvars, nbodylevellexicals, nblocklocals, script)) return false; if (mode == XDR_DECODE) { @@ -3369,9 +3409,12 @@ LazyScript::markChildren(JSTracer *trc) if (script_) MarkScript(trc, &script_, "realScript"); - HeapPtrAtom *freeVariables = this->freeVariables(); - for (size_t i = 0; i < numFreeVariables(); i++) - MarkString(trc, &freeVariables[i], "lazyScriptFreeVariable"); + // We rely on the fact that atoms are always tenured. + FreeVariable *freeVariables = this->freeVariables(); + for (size_t i = 0; i < numFreeVariables(); i++) { + JSAtom *atom = freeVariables[i].atom(); + MarkStringUnbarriered(trc, &atom, "lazyScriptFreeVariable"); + } HeapPtrFunction *innerFunctions = this->innerFunctions(); for (size_t i = 0; i < numInnerFunctions(); i++) @@ -3564,7 +3607,13 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script) bool JSScript::varIsAliased(uint32_t varSlot) { - return bindings.bindingIsAliased(bindings.numArgs() + varSlot); + return bodyLevelLocalIsAliased(varSlot); +} + +bool +JSScript::bodyLevelLocalIsAliased(uint32_t localSlot) +{ + return bindings.bindingIsAliased(bindings.numArgs() + localSlot); } bool @@ -3641,7 +3690,7 @@ LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun, p.hasBeenCloned = false; p.treatAsRunOnce = false; - size_t bytes = (p.numFreeVariables * sizeof(HeapPtrAtom)) + size_t bytes = (p.numFreeVariables * sizeof(FreeVariable)) + (p.numInnerFunctions * sizeof(HeapPtrFunction)); ScopedJSFreePtr table(bytes ? fun->pod_malloc(bytes) : nullptr); @@ -3701,9 +3750,9 @@ LazyScript::Create(ExclusiveContext *cx, HandleFunction fun, // Fill with dummies, to be GC-safe after the initialization of the free // variables and inner functions. size_t i, num; - HeapPtrAtom *variables = res->freeVariables(); + FreeVariable *variables = res->freeVariables(); for (i = 0, num = res->numFreeVariables(); i < num; i++) - variables[i].init(dummyAtom); + variables[i] = FreeVariable(dummyAtom); HeapPtrFunction *functions = res->innerFunctions(); for (i = 0, num = res->numInnerFunctions(); i < num; i++) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 0f75ac4e8782..30e5ac47b79c 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -137,7 +137,8 @@ class Binding static const uintptr_t NAME_MASK = ~(KIND_MASK | ALIASED_BIT); public: - // A "binding" is a formal, 'var', or 'const' declaration. A function's + // A "binding" is a formal parameter, 'var' (also a stand in for + // body-level 'let' declarations), or 'const' declaration. A function's // lexical scope is composed of these three kinds of bindings. enum Kind { ARGUMENT, VARIABLE, CONSTANT }; @@ -183,8 +184,16 @@ class Bindings uintptr_t bindingArrayAndFlag_; uint16_t numArgs_; uint16_t numBlockScoped_; + uint16_t numBodyLevelLexicals_; + uint16_t aliasedBodyLevelLexicalBegin_; uint32_t numVars_; +#if JS_BITS_PER_WORD == 32 + // Bindings is allocated inline inside JSScript, which needs to be + // gc::Cell aligned. + uint32_t padding_; +#endif + /* * During parsing, bindings are allocated out of a temporary LifoAlloc. * After parsing, a JSScript object is created and the bindings are @@ -209,13 +218,15 @@ class Bindings /* * Initialize a Bindings with a pointer into temporary storage. - * bindingArray must have length numArgs+numVars. Before the temporary - * storage is release, switchToScriptStorage must be called, providing a - * pointer into the Binding array stored in script->data. + * bindingArray must have length numArgs + numVars + + * numBodyLevelLexicals. Before the temporary storage is release, + * switchToScriptStorage must be called, providing a pointer into the + * Binding array stored in script->data. */ static bool initWithTemporaryStorage(ExclusiveContext *cx, InternalBindingsHandle self, - unsigned numArgs, uint32_t numVars, - Binding *bindingArray, unsigned numBlockScoped); + uint32_t numArgs, uint32_t numVars, + uint32_t numBodyLevelLexicals, uint32_t numBlockScoped, + Binding *bindingArray); // CompileScript parses and compiles one statement at a time, but the result // is one Script object. There will be no vars or bindings, because those @@ -240,13 +251,17 @@ class Bindings static bool clone(JSContext *cx, InternalBindingsHandle self, uint8_t *dstScriptData, HandleScript srcScript); - unsigned numArgs() const { return numArgs_; } + uint32_t numArgs() const { return numArgs_; } uint32_t numVars() const { return numVars_; } - unsigned numBlockScoped() const { return numBlockScoped_; } - uint32_t numLocals() const { return numVars() + numBlockScoped(); } + uint32_t numBodyLevelLexicals() const { return numBodyLevelLexicals_; } + uint32_t numBlockScoped() const { return numBlockScoped_; } + uint32_t numBodyLevelLocals() const { return numVars_ + numBodyLevelLexicals_; } + uint32_t numLocals() const { return numVars() + numBodyLevelLexicals() + numBlockScoped(); } + uint32_t lexicalBegin() const { return numArgs() + numVars(); } + uint32_t aliasedBodyLevelLexicalBegin() const { return aliasedBodyLevelLexicalBegin_; } // Return the size of the bindingArray. - uint32_t count() const { return numArgs() + numVars(); } + uint32_t count() const { return numArgs() + numVars() + numBodyLevelLexicals(); } /* Return the initial shape of call objects created for this scope. */ Shape *callObjShape() const { return callObjShape_; } @@ -1033,11 +1048,28 @@ class JSScript : public js::gc::BarrieredCell return function_ ? bindings.numLocals() : bindings.numBlockScoped(); } - // Number of fixed slots reserved for vars. Only nonzero for function code. + // Number of fixed slots reserved for vars. Only nonzero for function + // code. size_t nfixedvars() const { return function_ ? bindings.numVars() : 0; } + // Number of fixed slots reserved for body-level lexicals and vars. This + // value minus nfixedvars() is the number of body-level lexicals. Only + // nonzero for function code. + size_t nbodyfixed() const { + return function_ ? bindings.numBodyLevelLocals() : 0; + } + + // Aliases for clarity when dealing with lexical slots. + size_t fixedLexicalBegin() const { + return nfixedvars(); + } + + size_t fixedLexicalEnd() const { + return nfixed(); + } + size_t nslots() const { return nslots_; } @@ -1563,6 +1595,7 @@ class JSScript : public js::gc::BarrieredCell } bool varIsAliased(uint32_t varSlot); + bool bodyLevelLocalIsAliased(uint32_t localSlot); bool formalIsAliased(unsigned argSlot); bool formalLivesInArgumentsObject(unsigned argSlot); @@ -1691,6 +1724,35 @@ class AliasedFormalIter // bytecode from its source. class LazyScript : public gc::BarrieredCell { + public: + class FreeVariable + { + // Free variable names are possible tagged JSAtom *s. + uintptr_t bits_; + + static const uintptr_t HOISTED_USE_BIT = 0x1; + static const uintptr_t MASK = ~HOISTED_USE_BIT; + + public: + explicit FreeVariable() + : bits_(0) + { } + + explicit FreeVariable(JSAtom *name) + : bits_(uintptr_t(name)) + { + // We rely on not requiring any write barriers so we can tag the + // pointer. This code needs to change if we start allocating + // JSAtoms inside the nursery. + MOZ_ASSERT(!IsInsideNursery(name)); + } + + JSAtom *atom() const { return (JSAtom *)(bits_ & MASK); } + void setIsHoistedUse() { bits_ |= HOISTED_USE_BIT; } + bool isHoistedUse() const { return bool(bits_ & HOISTED_USE_BIT); } + }; + + private: // If non-nullptr, the script has been compiled and this is a forwarding // pointer to the result. HeapPtrScript script_; @@ -1802,8 +1864,8 @@ class LazyScript : public gc::BarrieredCell uint32_t numFreeVariables() const { return p_.numFreeVariables; } - HeapPtrAtom *freeVariables() { - return (HeapPtrAtom *)table_; + FreeVariable *freeVariables() { + return (FreeVariable *)table_; } uint32_t numInnerFunctions() const { diff --git a/js/src/tests/js1_7/block/order-of-operation.js b/js/src/tests/js1_7/block/order-of-operation.js index 2a502e99faf2..3ea224669b4d 100644 --- a/js/src/tests/js1_7/block/order-of-operation.js +++ b/js/src/tests/js1_7/block/order-of-operation.js @@ -85,6 +85,7 @@ function f6() { try { +/* var rv = f1(5); if (!isNaN(rv)) throw "f1(5):\n" + @@ -96,7 +97,7 @@ try throw "f2(5):\n" + " expected: NaN\n" + " actual: " + rv; -/* + rv = f3(8); if (rv != 9) throw "f3(8):\n" + diff --git a/js/src/tests/js1_7/block/regress-411279.js b/js/src/tests/js1_7/block/regress-411279.js deleted file mode 100644 index 50c341cb6a52..000000000000 --- a/js/src/tests/js1_7/block/regress-411279.js +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 411279; -var summary = 'let declaration as direct child of switch body block'; -var actual = 'No Crash'; -var expect = 'No Crash'; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - - function f(x) - { - var value = ''; - - switch(x) - { - case 1: - value = "1 " + y; - break; - case 2: - let y = 42; - value = "2 " + y; - break; - default: - value = "default " + y; - } - - return value; - } - - expect = '1 undefined'; - actual = f(1); - reportCompare(expect, actual, summary + ': f(1)'); - - expect = '2 42'; - actual = f(2); - reportCompare(expect, actual, summary + ': f(2)'); - - expect = 'default undefined'; - actual = f(3); - reportCompare(expect, actual, summary + ': f(3)'); - - exitFunc ('test'); -} diff --git a/js/src/tests/js1_8_1/extensions/regress-353214-02.js b/js/src/tests/js1_8_1/extensions/regress-353214-02.js index 3879f11b8374..13a8f246d191 100644 --- a/js/src/tests/js1_8_1/extensions/regress-353214-02.js +++ b/js/src/tests/js1_8_1/extensions/regress-353214-02.js @@ -20,8 +20,8 @@ function test() printBugNumber(BUGNUMBER); printStatus (summary); - var f = function ([x]) { let x; } - expect = 'function ([x]) { let x; }'; + var f = function ([x]) { let y; } + expect = 'function ([x]) { let y; }'; actual = f + ''; compareSource(expect, actual, summary); diff --git a/js/src/tests/js1_8_1/regress/regress-452498-103.js b/js/src/tests/js1_8_1/regress/regress-452498-103.js deleted file mode 100644 index b3ac0ed2fb53..000000000000 --- a/js/src/tests/js1_8_1/regress/regress-452498-103.js +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 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/. */ - -//----------------------------------------------------------------------------- -var BUGNUMBER = 452498; -var summary = 'TM: upvar2 regression tests'; -var actual = ''; -var expect = ''; - - -//----------------------------------------------------------------------------- -test(); -//----------------------------------------------------------------------------- - -function test() -{ - enterFunc ('test'); - printBugNumber(BUGNUMBER); - printStatus (summary); - -// ------- Comment #103 From Jesse Ruderman - - (function(a) { v = 5; let [v] = [3]; (function(){ v; })(); })(); -// Assertion failure: !(pn->pn_dflags & flag), at ../jsparse.h:638 - - reportCompare(expect, actual, summary); - - exitFunc ('test'); -} diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index a59ac6f9c2d0..a5f3aaf97233 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -186,6 +186,7 @@ macro(true, true_, "true") \ macro(unescape, unescape, "unescape") \ macro(uneval, uneval, "uneval") \ + macro(uninitialized, uninitialized, "uninitialized") \ macro(uint8, uint8, "uint8") \ macro(uint8Clamped, uint8Clamped, "uint8Clamped") \ macro(uint16, uint16, "uint16") \ diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 82af690322ed..bd54e88ee63f 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -725,15 +725,17 @@ Debugger::wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp) if (!optObj) return false; - // We handle two sentinel values: missing arguments (overloading - // JS_OPTIMIZED_ARGUMENTS) and optimized out slots (JS_OPTIMIZED_OUT). + // We handle three sentinel values: missing arguments (overloading + // JS_OPTIMIZED_ARGUMENTS), optimized out slots (JS_OPTIMIZED_OUT), + // and uninitialized bindings (JS_UNINITIALIZED_LEXICAL). + // // Other magic values should not have escaped. PropertyName *name; - if (vp.whyMagic() == JS_OPTIMIZED_ARGUMENTS) { - name = cx->names().missingArguments; - } else { - MOZ_ASSERT(vp.whyMagic() == JS_OPTIMIZED_OUT); - name = cx->names().optimizedOut; + switch (vp.whyMagic()) { + case JS_OPTIMIZED_ARGUMENTS: name = cx->names().missingArguments; break; + case JS_OPTIMIZED_OUT: name = cx->names().optimizedOut; break; + case JS_UNINITIALIZED_LEXICAL: name = cx->names().uninitialized; break; + default: MOZ_CRASH("Unsupported magic value escaped to Debugger"); } RootedValue trueVal(cx, BooleanValue(true)); diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index b7fcba9e89ce..40b0bb0e8430 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -498,6 +498,10 @@ class Debugger : private mozilla::LinkedListElement * If *vp is a magic JS_OPTIMIZED_ARGUMENTS value signifying missing * arguments, this produces a plain object of the form { missingArguments: * true }. + * + * If *vp is a magic JS_UNINITIALIZED_LEXICAL value signifying an + * unaccessible uninitialized binding, this produces a plain object of the + * form { uninitialized: true }. */ bool wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp); diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index c3538c95b374..b71fc5677280 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -22,6 +22,7 @@ #include "jsinferinlines.h" #include "jsobjinlines.h" +#include "vm/ScopeObject-inl.h" #include "vm/Stack-inl.h" #include "vm/String-inl.h" @@ -106,6 +107,62 @@ GuardFunApplyArgumentsOptimization(JSContext *cx, AbstractFramePtr frame, Handle return true; } +/* + * Per ES6, lexical declarations may not be accessed in any fashion until they + * are initialized (i.e., until the actual declaring statement is + * executed). The various LEXICAL opcodes need to check if the slot is an + * uninitialized let declaration, represented by the magic value + * JS_UNINITIALIZED_LEXICAL. + */ +static inline bool +IsUninitializedLexical(const Value &val) +{ + // Use whyMagic here because JS_OPTIMIZED_ARGUMENTS could flow into here. + return val.isMagic() && val.whyMagic() == JS_UNINITIALIZED_LEXICAL; +} + +static inline bool +IsUninitializedLexicalSlot(HandleObject obj, HandleShape shape) +{ + if (obj->is()) + return false; + // We check for IsImplicitDenseOrTypedArrayElement even though the shape + // is always a non-indexed property because proxy hooks may return a + // "non-native property found" shape, which happens to be encoded in the + // same way as the "dense element" shape. See MarkNonNativePropertyFound. + if (!shape || + IsImplicitDenseOrTypedArrayElement(shape) || + !shape->hasSlot() || + !shape->hasDefaultGetter() || + !shape->hasDefaultSetter()) + { + return false; + } + MOZ_ASSERT(obj->nativeContainsPure(shape)); + return IsUninitializedLexical(obj->nativeGetSlot(shape->slot())); +} + +static inline bool +CheckUninitializedLexical(JSContext *cx, PropertyName *name_, HandleValue val) +{ + if (IsUninitializedLexical(val)) { + RootedPropertyName name(cx, name_); + ReportUninitializedLexical(cx, name); + return false; + } + return true; +} + +static inline bool +CheckUninitializedLexical(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue val) +{ + if (IsUninitializedLexical(val)) { + ReportUninitializedLexical(cx, script, pc); + return false; + } + return true; +} + /* * Return an object on which we should look for the properties of |value|. * This helps us implement the custom [[Get]] method that ES5's GetValue @@ -225,6 +282,22 @@ SetIntrinsicOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleVal return cx->global()->setIntrinsicValue(cx, name, val); } +inline void +SetAliasedVarOperation(JSContext *cx, JSScript *script, jsbytecode *pc, + ScopeObject &obj, ScopeCoordinate sc, const Value &val, + MaybeCheckLexical checkLexical) +{ + MOZ_ASSERT_IF(checkLexical, !IsUninitializedLexical(obj.aliasedVar(sc))); + + // Avoid computing the name if no type updates are needed, as this may be + // expensive on scopes with large numbers of variables. + PropertyName *name = obj.hasSingletonType() + ? ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc) + : nullptr; + + obj.setAliasedVar(cx, sc, name, val); +} + inline bool SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject scope, HandleValue val) diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 44e313a6bfe8..570a74356a18 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -286,7 +286,7 @@ NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandle JSObject *scope = nullptr, *pobj = nullptr; if (LookupNameNoGC(cx, name, obj, &scope, &pobj, &shape)) { if (FetchNameNoGC(pobj, shape, vp)) - return true; + return CheckUninitializedLexical(cx, name, vp); } RootedObject objRoot(cx, obj), scopeRoot(cx), pobjRoot(cx); @@ -298,9 +298,17 @@ NameOperation(JSContext *cx, InterpreterFrame *fp, jsbytecode *pc, MutableHandle /* Kludge to allow (typeof foo == "undefined") tests. */ JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]); - if (op2 == JSOP_TYPEOF) - return FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp); - return FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp); + if (op2 == JSOP_TYPEOF) { + if (!FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp)) + return false; + } else { + if (!FetchName(cx, scopeRoot, pobjRoot, nameRoot, shapeRoot, vp)) + return false; + } + + // NAME operations are the slow paths already, so unconditionally check + // for uninitialized lets. + return CheckUninitializedLexical(cx, nameRoot, vp); } static inline bool @@ -1014,7 +1022,24 @@ HandleError(JSContext *cx, InterpreterRegs ®s) for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) { JSTryNote *tn = *tni; - UnwindScope(cx, si, regs.fp()->script()->main() + tn->start); + // Unwind the scope to the beginning of the JSOP_TRY. We cannot + // unwind to *after* the JSOP_TRY, because that might be the first + // opcode of an inner scope. Consider the following: + // + // try { + // { let x; } + // } + // + // This would generate + // + // 0000: try + // 0001: undefined + // 0002: initlet 0 + // + // If we unwound to 0001, we would be unwinding to the inner + // scope, and not the scope of the try { }. + UnwindScope(cx, si, (regs.fp()->script()->main() + tn->start - + js_CodeSpec[JSOP_TRY].length)); /* * Set pc to the first bytecode after the the try note to point @@ -1095,6 +1120,7 @@ HandleError(JSContext *cx, InterpreterRegs ®s) #define PUSH_OBJECT(obj) do { REGS.sp++->setObject(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0) #define PUSH_OBJECT_OR_NULL(obj) do { REGS.sp++->setObjectOrNull(obj); assertSameCompartmentDebugOnly(cx, REGS.sp[-1]); } while (0) #define PUSH_HOLE() REGS.sp++->setMagic(JS_ELEMENTS_HOLE) +#define PUSH_UNINITIALIZED() REGS.sp++->setMagic(JS_UNINITIALIZED_LEXICAL) #define POP_COPY_TO(v) (v) = *--REGS.sp #define POP_RETURN_VALUE() REGS.fp()->setReturnValue(*--REGS.sp) @@ -1585,11 +1611,6 @@ CASE(JSOP_UNUSED107) CASE(JSOP_UNUSED124) CASE(JSOP_UNUSED125) CASE(JSOP_UNUSED126) -CASE(JSOP_UNUSED138) -CASE(JSOP_UNUSED139) -CASE(JSOP_UNUSED140) -CASE(JSOP_UNUSED141) -CASE(JSOP_UNUSED142) CASE(JSOP_UNUSED146) CASE(JSOP_UNUSED147) CASE(JSOP_UNUSED148) @@ -1995,10 +2016,19 @@ CASE(JSOP_BINDNAME) /* Assigning to an undeclared name adds a property to the global object. */ RootedObject &scope = rootObject1; - if (!LookupNameUnqualified(cx, name, scopeChain, &scope)) + RootedShape &shape = rootShape0; + if (!LookupNameUnqualified(cx, name, scopeChain, &scope, &shape)) goto error; - PUSH_OBJECT(*scope); + // ES6 lets cannot be accessed until initialized. NAME operations, being + // the slow paths already, unconditionally check for uninitialized + // lets. The error, however, is thrown after evaluating the RHS in + // assignments. Thus if the LHS resolves to an uninitialized let, return a + // nullptr scope. + if (IsUninitializedLexicalSlot(scope, shape)) + PUSH_NULL(); + else + PUSH_OBJECT(*scope); } END_CASE(JSOP_BINDNAME) @@ -2384,7 +2414,16 @@ CASE(JSOP_SETGNAME) CASE(JSOP_SETNAME) { RootedObject &scope = rootObject0; - scope = ®S.sp[-2].toObject(); + scope = REGS.sp[-2].toObjectOrNull(); + + // A nullptr scope is pushed if the name is an uninitialized let. See + // CASE(JSOP_BINDNAME). + if (!scope) { + RootedPropertyName &name = rootName0; + name = script->getName(REGS.pc); + ReportUninitializedLexical(cx, name); + goto error; + } HandleValue value = REGS.stackHandleAt(-1); @@ -2622,7 +2661,8 @@ CASE(JSOP_IMPLICITTHIS) scopeObj = REGS.fp()->scopeChain(); RootedObject &scope = rootObject1; - if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &scope)) + RootedShape &shape = rootShape0; + if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &scope, &shape)) goto error; RootedValue &v = rootValue0; @@ -2833,7 +2873,10 @@ END_CASE(JSOP_REST) CASE(JSOP_GETALIASEDVAR) { ScopeCoordinate sc = ScopeCoordinate(REGS.pc); - PUSH_COPY(REGS.fp()->aliasedVarScope(sc).aliasedVar(sc)); + RootedValue &val = rootValue0; + val = REGS.fp()->aliasedVarScope(sc).aliasedVar(sc); + MOZ_ASSERT(!IsUninitializedLexical(val)); + PUSH_COPY(val); TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]); } END_CASE(JSOP_GETALIASEDVAR) @@ -2842,17 +2885,49 @@ CASE(JSOP_SETALIASEDVAR) { ScopeCoordinate sc = ScopeCoordinate(REGS.pc); ScopeObject &obj = REGS.fp()->aliasedVarScope(sc); - - // Avoid computing the name if no type updates are needed, as this may be - // expensive on scopes with large numbers of variables. - PropertyName *name = obj.hasSingletonType() - ? ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, REGS.pc) - : nullptr; - - obj.setAliasedVar(cx, sc, name, REGS.sp[-1]); + SetAliasedVarOperation(cx, script, REGS.pc, obj, sc, REGS.sp[-1], CheckLexical); } END_CASE(JSOP_SETALIASEDVAR) +CASE(JSOP_CHECKLEXICAL) +{ + uint32_t i = GET_LOCALNO(REGS.pc); + RootedValue &val = rootValue0; + val = REGS.fp()->unaliasedLocal(i); + if (!CheckUninitializedLexical(cx, script, REGS.pc, val)) + goto error; +} +END_CASE(JSOP_CHECKLEXICAL) + +CASE(JSOP_INITLEXICAL) +{ + uint32_t i = GET_LOCALNO(REGS.pc); + REGS.fp()->unaliasedLocal(i) = REGS.sp[-1]; +} +END_CASE(JSOP_INITLEXICAL) + +CASE(JSOP_CHECKALIASEDLEXICAL) +{ + ScopeCoordinate sc = ScopeCoordinate(REGS.pc); + RootedValue &val = rootValue0; + val = REGS.fp()->aliasedVarScope(sc).aliasedVar(sc); + if (!CheckUninitializedLexical(cx, script, REGS.pc, val)) + goto error; +} +END_CASE(JSOP_CHECKALIASEDLEXICAL) + +CASE(JSOP_INITALIASEDLEXICAL) +{ + ScopeCoordinate sc = ScopeCoordinate(REGS.pc); + ScopeObject &obj = REGS.fp()->aliasedVarScope(sc); + SetAliasedVarOperation(cx, script, REGS.pc, obj, sc, REGS.sp[-1], DontCheckLexical); +} +END_CASE(JSOP_INITALIASEDLEXICAL) + +CASE(JSOP_UNINITIALIZED) + PUSH_UNINITIALIZED(); +END_CASE(JSOP_UNINITIALIZED) + CASE(JSOP_GETARG) { unsigned i = GET_ARGNO(REGS.pc); @@ -2877,6 +2952,7 @@ CASE(JSOP_GETLOCAL) { uint32_t i = GET_LOCALNO(REGS.pc); PUSH_COPY_SKIP_CHECK(REGS.fp()->unaliasedLocal(i)); + MOZ_ASSERT(!IsUninitializedLexical(REGS.sp[-1])); /* * Skip the same-compartment assertion if the local will be immediately @@ -2892,6 +2968,7 @@ END_CASE(JSOP_GETLOCAL) CASE(JSOP_SETLOCAL) { uint32_t i = GET_LOCALNO(REGS.pc); + MOZ_ASSERT(!IsUninitializedLexical(REGS.fp()->unaliasedLocal(i))); REGS.fp()->unaliasedLocal(i) = REGS.sp[-1]; } END_CASE(JSOP_SETLOCAL) @@ -3490,7 +3567,11 @@ js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name return false; } - return JSObject::getProperty(cx, obj, obj, name, vp); + if (!JSObject::getProperty(cx, obj, obj, name, vp)) + return false; + + // See note in NameOperation. + return CheckUninitializedLexical(cx, name, vp); } /* @@ -3511,7 +3592,11 @@ js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandleProperty return true; } - return JSObject::getProperty(cx, obj, obj, name, vp); + if (!JSObject::getProperty(cx, obj, obj, name, vp)) + return false; + + // See note in NameOperation. + return CheckUninitializedLexical(cx, name, vp); } JSObject * @@ -3808,7 +3893,8 @@ js::ImplicitThisOperation(JSContext *cx, HandleObject scopeObj, HandlePropertyNa MutableHandleValue res) { RootedObject obj(cx); - if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj)) + RootedShape shape(cx); + if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &obj, &shape)) return false; return ComputeImplicitThis(cx, obj, res); @@ -3940,3 +4026,65 @@ js::SpreadCallOperation(JSContext *cx, HandleScript script, jsbytecode *pc, Hand TypeScript::Monitor(cx, script, pc, res); return true; } + +void +js::ReportUninitializedLexical(JSContext *cx, HandlePropertyName name) +{ + JSAutoByteString printable; + if (AtomToPrintableString(cx, name, &printable)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_UNINITIALIZED_LEXICAL, + printable.ptr()); + } +} + +void +js::ReportUninitializedLexical(JSContext *cx, HandleScript script, jsbytecode *pc) +{ + RootedPropertyName name(cx); + + if (JSOp(*pc) == JSOP_CHECKLEXICAL) { + uint32_t slot = GET_LOCALNO(pc); + + // First search for a name among body-level lets. + for (BindingIter bi(script); bi; bi++) { + if (bi->kind() != Binding::ARGUMENT && bi.frameIndex() == slot) { + name = bi->name(); + break; + } + } + + // Failing that, it must be a block-local let. + if (!name) { + // Skip to the right scope. + Rooted scope(cx, script->getStaticScope(pc)); + MOZ_ASSERT(scope && scope->is()); + Rooted block(cx, &scope->as()); + while (slot < block->localOffset()) + block = &block->enclosingNestedScope()->as(); + + // Translate the frame slot to the block slot, then find the name + // of the slot. + uint32_t blockSlot = block->localIndexToSlot(slot); + RootedShape shape(cx, block->lastProperty()); + Shape::Range r(cx, shape); + while (r.front().slot() != blockSlot) + r.popFront(); + jsid id = r.front().propidRaw(); + MOZ_ASSERT(JSID_IS_ATOM(id)); + name = JSID_TO_ATOM(id)->asPropertyName(); + } + } else { + MOZ_ASSERT(JSOp(*pc) == JSOP_CHECKALIASEDLEXICAL); + name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc); + } + + ReportUninitializedLexical(cx, name); +} + +void +js::ReportUninitializedLexical(JSContext *cx, HandleScript script, jsbytecode *pc, ScopeCoordinate sc) +{ + RootedPropertyName name(cx, ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, + script, pc)); + ReportUninitializedLexical(cx, name); +} diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 91dcc2a2eef2..348be7178751 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -470,6 +470,15 @@ SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, H JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY); } +void +ReportUninitializedLexical(JSContext *cx, HandlePropertyName name); + +void +ReportUninitializedLexical(JSContext *cx, HandleScript script, jsbytecode *pc); + +void +ReportUninitializedLexical(JSContext *cx, HandleScript script, jsbytecode *pc, ScopeCoordinate sc); + } /* namespace js */ #endif /* vm_Interpreter_h */ diff --git a/js/src/vm/Opcodes.h b/js/src/vm/Opcodes.h index 3d86f4612bef..f0de8c52fc72 100644 --- a/js/src/vm/Opcodes.h +++ b/js/src/vm/Opcodes.h @@ -1260,14 +1260,54 @@ */ \ macro(JSOP_SETALIASEDVAR, 137,"setaliasedvar",NULL, 5, 1, 1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \ \ - macro(JSOP_UNUSED138, 138, "unused138", NULL, 1, 0, 0, JOF_BYTE) \ - macro(JSOP_UNUSED139, 139, "unused139", NULL, 1, 0, 0, JOF_BYTE) \ - macro(JSOP_UNUSED140, 140, "unused140", NULL, 1, 0, 0, JOF_BYTE) \ - macro(JSOP_UNUSED141, 141, "unused141", NULL, 1, 0, 0, JOF_BYTE) \ - macro(JSOP_UNUSED142, 142, "unused142", NULL, 1, 0, 0, JOF_BYTE) \ - \ /* - * Pushes the value of the intrinsic onto the stack. + * Checks if the value of the local variable is the + * JS_UNINITIALIZED_LEXICAL magic, throwing an error if so. + * Category: Variables and Scopes + * Type: Local Variables + * Operands: uint32_t localno + * Stack: => + */ \ + macro(JSOP_CHECKLEXICAL, 138, "checklexical", NULL, 4, 0, 0, JOF_LOCAL|JOF_NAME) \ + /* + * Initializes an uninitialized local lexical binding with the top of stack + * value. + * Category: Variables and Scopes + * Type: Local Variables + * Operands: uint32_t localno + * Stack: v => v + */ \ + macro(JSOP_INITLEXICAL, 139, "initlexical", NULL, 4, 1, 1, JOF_LOCAL|JOF_NAME|JOF_SET|JOF_DETECTING) \ + /* + * Checks if the value of the aliased variable is the + * JS_UNINITIALIZED_LEXICAL magic, throwing an error if so. + * Category: Variables and Scopes + * Type: Aliased Variables + * Operands: uint8_t hops, uint24_t slot + * Stack: => + */ \ + macro(JSOP_CHECKALIASEDLEXICAL, 140, "checkaliasedlexical", NULL, 5, 0, 0, JOF_SCOPECOORD|JOF_NAME) \ + /* + * Initializes an uninitialized aliased lexical binding with the top of + * stack value. + * Category: Variables and Scopes + * Type: Aliased Variables + * Operands: uint8_t hops, uint24_t slot + * Stack: v => v + */ \ + macro(JSOP_INITALIASEDLEXICAL, 141, "initaliasedlexical", NULL, 5, 1, 1, JOF_SCOPECOORD|JOF_NAME|JOF_SET|JOF_DETECTING) \ + /* + * Pushes a JS_UNINITIALIZED_LEXICAL value onto the stack, representing an + * uninitialized lexical binding. + * + * This opcode is used with the JSOP_INITLET opcode. + * Category: Literals + * Type: Constants + * Operands: + * Stack: => uninitialized + */ \ + macro(JSOP_UNINITIALIZED, 142, "uninitialized", NULL, 1, 0, 1, JOF_BYTE) \ + /* Pushes the value of the intrinsic onto the stack. * * Intrinsic names are emitted instead of JSOP_*NAME ops when the * 'CompileOptions' flag 'selfHostingMode' is set. diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index 576d8d79e1c4..e6d5e993b681 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -53,6 +53,15 @@ CallObject::setAliasedVarFromArguments(JSContext *cx, const Value &argsValue, js types::AddTypePropertyId(cx, this, id, v); } +inline void +CallObject::setAliasedLexicalsToThrowOnTouch(JSScript *script) +{ + uint32_t aliasedLexicalBegin = script->bindings.aliasedBodyLevelLexicalBegin(); + uint32_t aliasedLexicalEnd = numFixedSlots(); + for (uint32_t slot = aliasedLexicalBegin; slot < aliasedLexicalEnd; slot++) + initFixedSlot(slot, MagicValue(JS_UNINITIALIZED_LEXICAL)); +} + template inline bool StaticScopeIter::done() const diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index aaa0c55ff16f..6f555d3a7b3a 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -217,6 +217,7 @@ CallObject::create(JSContext *cx, HandleScript script, HandleObject enclosing, H callobj->as().setEnclosingScope(enclosing); callobj->initFixedSlot(CALLEE_SLOT, ObjectOrNullValue(callee)); + callobj->setAliasedLexicalsToThrowOnTouch(script); if (script->treatAsRunOnce()) { Rooted ncallobj(cx, callobj); @@ -1157,7 +1158,7 @@ class DebugScopeProxy : public BaseProxyHandler *accessResult = ACCESS_GENERIC; ScopeIterVal *maybeLiveScope = DebugScopes::hasLiveScope(*scope); - /* Handle unaliased formals, vars, and consts at function scope. */ + /* Handle unaliased formals, vars, lets, and consts at function scope. */ if (scope->is() && !scope->as().isForEval()) { CallObject &callobj = scope->as(); RootedScript script(cx, callobj.callee().nonLazyScript()); @@ -1173,15 +1174,15 @@ class DebugScopeProxy : public BaseProxyHandler if (bi->kind() == Binding::VARIABLE || bi->kind() == Binding::CONSTANT) { uint32_t i = bi.frameIndex(); - if (script->varIsAliased(i)) + if (script->bodyLevelLocalIsAliased(i)) return true; if (maybeLiveScope) { AbstractFramePtr frame = maybeLiveScope->frame(); if (action == GET) - vp.set(frame.unaliasedVar(i)); + vp.set(frame.unaliasedLocal(i)); else - frame.unaliasedVar(i) = vp; + frame.unaliasedLocal(i) = vp; } else if (JSObject *snapshot = debugScope->maybeSnapshot()) { if (action == GET) vp.set(snapshot->getDenseElement(bindings.numArgs() + i)); diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 2350e8690fbc..3ca6395993ab 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -233,6 +233,8 @@ class CallObject : public ScopeObject static CallObject * create(JSContext *cx, HandleScript script, HandleObject enclosing, HandleFunction callee); + inline void setAliasedLexicalsToThrowOnTouch(JSScript *script); + public: static const Class class_; diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 79693dd11881..ebeb4683b14f 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -88,13 +88,24 @@ InterpreterFrame::initCallFrame(JSContext *cx, InterpreterFrame *prev, jsbytecod prevpc_ = prevpc; prevsp_ = prevsp; - initVarsToUndefined(); + initLocals(); } inline void -InterpreterFrame::initVarsToUndefined() +InterpreterFrame::initLocals() { - SetValueRangeToUndefined(slots(), script()->nfixed()); + SetValueRangeToUndefined(slots(), script()->nfixedvars()); + + // Lexical bindings throw ReferenceErrors if they are used before + // initialization. See ES6 8.1.1.1.6. + // + // For completeness, lexical bindings are initialized in ES6 by calling + // InitializeBinding, after which touching the binding will no longer + // throw reference errors. See 13.1.11, 9.2.13, 13.6.3.4, 13.6.4.6, + // 13.6.4.8, 13.14.5, 15.1.8, and 15.2.0.15. + Value *lexicalEnd = slots() + script()->fixedLexicalEnd(); + for (Value *lexical = slots() + script()->fixedLexicalBegin(); lexical != lexicalEnd; ++lexical) + lexical->setMagic(JS_UNINITIALIZED_LEXICAL); } inline Value & diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 1e7038ab982b..0ea725b982a0 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -398,7 +398,7 @@ InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc) StaticBlockObject &blockObj = staticScope->as(); nlivefixed = blockObj.localOffset() + blockObj.numVariables(); } else { - nlivefixed = script()->nfixedvars(); + nlivefixed = script()->nbodyfixed(); } if (nfixed == nlivefixed) { @@ -408,9 +408,9 @@ InterpreterFrame::markValues(JSTracer *trc, Value *sp, jsbytecode *pc) // Mark operand stack. markValues(trc, nfixed, sp - slots()); - // Clear dead locals. + // Clear dead block-scoped locals. while (nfixed > nlivefixed) - unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setUndefined(); + unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setMagic(JS_UNINITIALIZED_LEXICAL); // Mark live locals. markValues(trc, 0, nlivefixed); @@ -495,7 +495,7 @@ InterpreterStack::pushExecuteFrame(JSContext *cx, HandleScript script, const Val InterpreterFrame *fp = reinterpret_cast(buffer + 2 * sizeof(Value)); fp->mark_ = mark; fp->initExecuteFrame(cx, script, evalInFrame, thisv, *scopeChain, type); - fp->initVarsToUndefined(); + fp->initLocals(); return fp; } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 81ff337d93db..47d1f402acec 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -66,6 +66,7 @@ class ScopeCoordinate; // InterpreterActivation) is a local var of js::Interpret. enum MaybeCheckAliasing { CHECK_ALIASING = true, DONT_CHECK_ALIASING = false }; +enum MaybeCheckLexical { CheckLexical = true, DontCheckLexical = false }; /*****************************************************************************/ @@ -423,8 +424,12 @@ class InterpreterFrame bool initFunctionScopeObjects(JSContext *cx); - /* Initialize local variables of newly-pushed frame. */ - void initVarsToUndefined(); + /* + * Initialize local variables of newly-pushed frame. 'var' bindings are + * initialized to undefined and lexical bindings are initialized to + * JS_UNINITIALIZED_LEXICAL. + */ + void initLocals(); /* * Stack frame type From 59162cc73ebf77a267d0dfd819c9adc36593d224 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 15 Sep 2014 16:30:45 -0700 Subject: [PATCH 17/32] Bug 1001090 - Part 2a: Compile new let opcodes in Baseline. (r=jandem) --- js/src/jit/BaselineCompiler.cpp | 122 ++++++++++++++++++++++++-------- js/src/jit/BaselineCompiler.h | 8 +++ js/src/jit/BaselineFrame.cpp | 10 +-- js/src/jit/BaselineFrameInfo.h | 10 ++- js/src/jit/BaselineIC.cpp | 9 +-- js/src/jit/VMFunctions.cpp | 9 +++ js/src/jit/VMFunctions.h | 2 + 7 files changed, 128 insertions(+), 42 deletions(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index ceeb66196282..1d07baa21a2f 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -265,6 +265,39 @@ BaselineCompiler::compile() return Method_Compiled; } +void +BaselineCompiler::emitInitializeLocals(size_t n, const Value &v) +{ + MOZ_ASSERT(frame.nlocals() > 0 && n <= frame.nlocals()); + + // Use R0 to minimize code size. If the number of locals to push is < + // LOOP_UNROLL_FACTOR, then the initialization pushes are emitted directly + // and inline. Otherwise, they're emitted in a partially unrolled loop. + static const size_t LOOP_UNROLL_FACTOR = 4; + size_t toPushExtra = n % LOOP_UNROLL_FACTOR; + + masm.moveValue(v, R0); + + // Handle any extra pushes left over by the optional unrolled loop below. + for (size_t i = 0; i < toPushExtra; i++) + masm.pushValue(R0); + + // Partially unrolled loop of pushes. + if (n >= LOOP_UNROLL_FACTOR) { + size_t toPush = n - toPushExtra; + JS_ASSERT(toPush % LOOP_UNROLL_FACTOR == 0); + JS_ASSERT(toPush >= LOOP_UNROLL_FACTOR); + masm.move32(Imm32(toPush), R1.scratchReg()); + // Emit unrolled loop with 4 pushes per iteration. + Label pushLoop; + masm.bind(&pushLoop); + for (size_t i = 0; i < LOOP_UNROLL_FACTOR; i++) + masm.pushValue(R0); + masm.branchSub32(Assembler::NonZero, + Imm32(LOOP_UNROLL_FACTOR), R1.scratchReg(), &pushLoop); + } +} + bool BaselineCompiler::emitPrologue() { @@ -321,35 +354,12 @@ BaselineCompiler::emitPrologue() &earlyStackCheckFailed); } - // Initialize locals to |undefined|. Use R0 to minimize code size. - // If the number of locals to push is < LOOP_UNROLL_FACTOR, then the - // initialization pushes are emitted directly and inline. Otherwise, - // they're emitted in a partially unrolled loop. - if (frame.nlocals() > 0) { - size_t LOOP_UNROLL_FACTOR = 4; - size_t toPushExtra = frame.nlocals() % LOOP_UNROLL_FACTOR; - - masm.moveValue(UndefinedValue(), R0); - - // Handle any extra pushes left over by the optional unrolled loop below. - for (size_t i = 0; i < toPushExtra; i++) - masm.pushValue(R0); - - // Partially unrolled loop of pushes. - if (frame.nlocals() >= LOOP_UNROLL_FACTOR) { - size_t toPush = frame.nlocals() - toPushExtra; - JS_ASSERT(toPush % LOOP_UNROLL_FACTOR == 0); - JS_ASSERT(toPush >= LOOP_UNROLL_FACTOR); - masm.move32(Imm32(toPush), R1.scratchReg()); - // Emit unrolled loop with 4 pushes per iteration. - Label pushLoop; - masm.bind(&pushLoop); - for (size_t i = 0; i < LOOP_UNROLL_FACTOR; i++) - masm.pushValue(R0); - masm.branchSub32(Assembler::NonZero, - Imm32(LOOP_UNROLL_FACTOR), R1.scratchReg(), &pushLoop); - } - } + // Initialize local vars to |undefined| and lexicals to a magic value that + // throws on touch. + if (frame.nvars() > 0) + emitInitializeLocals(frame.nvars(), UndefinedValue()); + if (frame.nlexicals() > 0) + emitInitializeLocals(frame.nlexicals(), MagicValue(JS_UNINITIALIZED_LEXICAL)); if (needsEarlyStackCheck()) masm.bind(&earlyStackCheckFailed); @@ -2543,6 +2553,60 @@ BaselineCompiler::emit_JSOP_SETARG() return emitFormalArgAccess(arg, /* get = */ false); } +typedef bool (*ThrowUninitializedLexicalFn)(JSContext *cx); +static const VMFunction ThrowUninitializedLexicalInfo = + FunctionInfo(jit::ThrowUninitializedLexical); + +bool +BaselineCompiler::emitUninitializedLexicalCheck(const ValueOperand &val) +{ + Label done; + masm.branchTestMagicValue(Assembler::NotEqual, val, JS_UNINITIALIZED_LEXICAL, &done); + + prepareVMCall(); + if (!callVM(ThrowUninitializedLexicalInfo)) + return false; + + masm.bind(&done); + return true; +} + + +bool +BaselineCompiler::emit_JSOP_CHECKLEXICAL() +{ + frame.syncStack(0); + masm.loadValue(frame.addressOfLocal(GET_LOCALNO(pc)), R0); + return emitUninitializedLexicalCheck(R0); +} + +bool +BaselineCompiler::emit_JSOP_INITLEXICAL() +{ + return emit_JSOP_SETLOCAL(); +} + +bool +BaselineCompiler::emit_JSOP_CHECKALIASEDLEXICAL() +{ + frame.syncStack(0); + masm.loadValue(getScopeCoordinateAddress(R0.scratchReg()), R0); + return emitUninitializedLexicalCheck(R0); +} + +bool +BaselineCompiler::emit_JSOP_INITALIASEDLEXICAL() +{ + return emit_JSOP_SETALIASEDVAR(); +} + +bool +BaselineCompiler::emit_JSOP_UNINITIALIZED() +{ + frame.push(MagicValue(JS_UNINITIALIZED_LEXICAL)); + return true; +} + bool BaselineCompiler::emitCall() { diff --git a/js/src/jit/BaselineCompiler.h b/js/src/jit/BaselineCompiler.h index 7b9e5c5510df..9e410ff5100c 100644 --- a/js/src/jit/BaselineCompiler.h +++ b/js/src/jit/BaselineCompiler.h @@ -135,6 +135,11 @@ namespace jit { _(JSOP_SETLOCAL) \ _(JSOP_GETARG) \ _(JSOP_SETARG) \ + _(JSOP_CHECKLEXICAL) \ + _(JSOP_INITLEXICAL) \ + _(JSOP_CHECKALIASEDLEXICAL) \ + _(JSOP_INITALIASEDLEXICAL) \ + _(JSOP_UNINITIALIZED) \ _(JSOP_CALL) \ _(JSOP_FUNCALL) \ _(JSOP_FUNAPPLY) \ @@ -214,6 +219,7 @@ class BaselineCompiler : public BaselineCompilerSpecific private: MethodStatus emitBody(); + void emitInitializeLocals(size_t n, const Value &v); bool emitPrologue(); bool emitEpilogue(); #ifdef JSGC_GENERATIONAL @@ -267,6 +273,8 @@ class BaselineCompiler : public BaselineCompilerSpecific bool emitFormalArgAccess(uint32_t arg, bool get); + bool emitUninitializedLexicalCheck(const ValueOperand &val); + bool addPCMappingEntry(bool addIndexEntry); void getScopeCoordinateObject(Register reg); diff --git a/js/src/jit/BaselineFrame.cpp b/js/src/jit/BaselineFrame.cpp index 958da8e97b46..0ad823ca244d 100644 --- a/js/src/jit/BaselineFrame.cpp +++ b/js/src/jit/BaselineFrame.cpp @@ -91,13 +91,9 @@ BaselineFrame::trace(JSTracer *trc, JitFrameIterator &frameIterator) // Mark operand stack. MarkLocals(this, trc, nfixed, numValueSlots()); - // Clear non-magic dead locals. Magic values such as - // JS_UNINITIALIZED_LET need to be left as is for correctness. - while (nfixed > nlivefixed) { - --nfixed; - if (!unaliasedLocal(nfixed, DONT_CHECK_ALIASING).isMagic()) - unaliasedLocal(nfixed, DONT_CHECK_ALIASING).setUndefined(); - } + // Clear dead block-scoped locals. + while (nfixed > nlivefixed) + unaliasedLocal(--nfixed, DONT_CHECK_ALIASING).setMagic(JS_UNINITIALIZED_LEXICAL); // Mark live locals. MarkLocals(this, trc, 0, nlivefixed); diff --git a/js/src/jit/BaselineFrameInfo.h b/js/src/jit/BaselineFrameInfo.h index b958f05bac59..d5c57ba2fc96 100644 --- a/js/src/jit/BaselineFrameInfo.h +++ b/js/src/jit/BaselineFrameInfo.h @@ -176,12 +176,18 @@ class FrameInfo bool init(TempAllocator &alloc); - uint32_t nlocals() const { + size_t nlocals() const { return script->nfixed(); } - uint32_t nargs() const { + size_t nargs() const { return script->functionNonDelazifying()->nargs(); } + size_t nvars() const { + return script->nfixedvars(); + } + size_t nlexicals() const { + return script->fixedLexicalEnd() - script->fixedLexicalBegin(); + } private: inline StackValue *rawPush() { diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 83627cc498a0..b98d9eee118c 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1521,7 +1521,7 @@ DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, H case ICStub::SetProp_NativeAdd: { JS_ASSERT(obj->isNative()); jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script); - if (*pc == JSOP_SETALIASEDVAR) + if (*pc == JSOP_SETALIASEDVAR || *pc == JSOP_INITALIASEDLEXICAL) id = NameToId(ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc)); else id = NameToId(script->getName(pc)); @@ -7626,10 +7626,11 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ op == JSOP_SETNAME || op == JSOP_SETGNAME || op == JSOP_INITPROP || - op == JSOP_SETALIASEDVAR); + op == JSOP_SETALIASEDVAR || + op == JSOP_INITALIASEDLEXICAL); RootedPropertyName name(cx); - if (op == JSOP_SETALIASEDVAR) + if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) name = ScopeCoordinateName(cx->runtime()->scopeCoordinateNameCache, script, pc); else name = script->getName(pc); @@ -7651,7 +7652,7 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_ } else if (op == JSOP_SETNAME || op == JSOP_SETGNAME) { if (!SetNameOperation(cx, script, pc, obj, rhs)) return false; - } else if (op == JSOP_SETALIASEDVAR) { + } else if (op == JSOP_SETALIASEDVAR || op == JSOP_INITALIASEDLEXICAL) { obj->as().setAliasedVar(cx, ScopeCoordinate(pc), name, rhs); } else { MOZ_ASSERT(op == JSOP_SETPROP); diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 3d7c64e4bff0..ff277543aee2 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -1235,5 +1235,14 @@ MarkTypeObjectFromIon(JSRuntime *rt, types::TypeObject **typep) gc::MarkTypeObjectUnbarriered(&rt->gc.marker, typep, "write barrier"); } +bool +ThrowUninitializedLet(JSContext *cx) +{ + ScriptFrameIter iter(cx); + RootedScript script(cx, iter.script()); + ReportUninitializedLet(cx, script, iter.pc()); + return false; +} + } // namespace jit } // namespace js diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 29adea59342c..971a314f616c 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -747,6 +747,8 @@ IonMarkFunction(MIRType type) bool ObjectIsCallable(JSObject *obj); +bool ThrowUninitializedLet(JSContext *cx); + } // namespace jit } // namespace js From 55e691aca468c27a022fd71fa39ecf7123f86f38 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 15 Sep 2014 16:30:46 -0700 Subject: [PATCH 18/32] Bug 1001090 - Part 2b: Fix unwinding all scopes to not use pc. (r=jimb) --- js/src/jit/IonFrames.cpp | 2 +- js/src/jit/VMFunctions.cpp | 2 +- js/src/vm/Interpreter.cpp | 87 +++++++++++++++++++++++--------------- js/src/vm/Interpreter.h | 9 ++++ 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index 515b7822de72..edca38935cd8 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -555,7 +555,7 @@ HandleExceptionBaseline(JSContext *cx, const JitFrameIterator &frame, ResumeFrom // Unwind scope chain (pop block objects). if (cx->isExceptionPending()) { - *unwoundScopeToPc = script->main() + tn->start; + *unwoundScopeToPc = UnwindScopeToTryPc(script, tn); UnwindScope(cx, si, *unwoundScopeToPc); } diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index ff277543aee2..9b42c6be0e83 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -809,8 +809,8 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok) { // Unwind scope chain to stack depth 0. ScopeIter si(frame, pc, cx); + UnwindAllScopes(cx, si); jsbytecode *unwindPc = frame->script()->main(); - UnwindScope(cx, si, unwindPc); frame->setUnwoundScopeOverridePc(unwindPc); // If ScriptDebugEpilogue returns |true| we have to return the frame's diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 570a74356a18..2216b6bdd566 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -866,6 +866,25 @@ js::EnterWithOperation(JSContext *cx, AbstractFramePtr frame, HandleValue val, return true; } +static void +PopScope(JSContext *cx, ScopeIter &si) +{ + switch (si.type()) { + case ScopeIter::Block: + if (cx->compartment()->debugMode()) + DebugScopes::onPopBlock(cx, si); + if (si.staticBlock().needsClone()) + si.frame().popBlock(cx); + break; + case ScopeIter::With: + si.frame().popWith(cx); + break; + case ScopeIter::Call: + case ScopeIter::StrictEvalScope: + break; + } +} + // Unwind scope chain and iterator to match the static scope corresponding to // the given bytecode position. void @@ -876,28 +895,42 @@ js::UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc) Rooted staticScope(cx, si.frame().script()->getStaticScope(pc)); - for (; si.staticScope() != staticScope; ++si) { - switch (si.type()) { - case ScopeIter::Block: - if (cx->compartment()->debugMode()) - DebugScopes::onPopBlock(cx, si); - if (si.staticBlock().needsClone()) - si.frame().popBlock(cx); - break; - case ScopeIter::With: - si.frame().popWith(cx); - break; - case ScopeIter::Call: - case ScopeIter::StrictEvalScope: - break; - } - } + for (; si.staticScope() != staticScope; ++si) + PopScope(cx, si); +} + +// Unwind all scopes. This is needed because block scopes may cover the +// first bytecode at a script's main(). e.g., +// +// function f() { { let i = 0; } } +// +// will have no pc location distinguishing the first block scope from the +// outermost function scope. +void +js::UnwindAllScopes(JSContext *cx, ScopeIter &si) +{ + for (; !si.done(); ++si) + PopScope(cx, si); +} + +// Compute the pc needed to unwind the scope to the beginning of a try +// block. We cannot unwind to *after* the JSOP_TRY, because that might be the +// first opcode of an inner scope, with the same problem as above. e.g., +// +// try { { let x; } } +// +// will have no pc location distinguishing the try block scope from the inner +// let block scope. +jsbytecode * +js::UnwindScopeToTryPc(JSScript *script, JSTryNote *tn) +{ + return script->main() + tn->start - js_CodeSpec[JSOP_TRY].length; } static void ForcedReturn(JSContext *cx, ScopeIter &si, InterpreterRegs ®s) { - UnwindScope(cx, si, regs.fp()->script()->main()); + UnwindAllScopes(cx, si); regs.setToEndOfScript(); } @@ -1022,24 +1055,8 @@ HandleError(JSContext *cx, InterpreterRegs ®s) for (TryNoteIter tni(cx, regs); !tni.done(); ++tni) { JSTryNote *tn = *tni; - // Unwind the scope to the beginning of the JSOP_TRY. We cannot - // unwind to *after* the JSOP_TRY, because that might be the first - // opcode of an inner scope. Consider the following: - // - // try { - // { let x; } - // } - // - // This would generate - // - // 0000: try - // 0001: undefined - // 0002: initlet 0 - // - // If we unwound to 0001, we would be unwinding to the inner - // scope, and not the scope of the try { }. - UnwindScope(cx, si, (regs.fp()->script()->main() + tn->start - - js_CodeSpec[JSOP_TRY].length)); + // Unwind the scope to the beginning of the JSOP_TRY. + UnwindScope(cx, si, UnwindScopeToTryPc(regs.fp()->script(), tn)); /* * Set pc to the first bytecode after the the try note to point diff --git a/js/src/vm/Interpreter.h b/js/src/vm/Interpreter.h index 348be7178751..96ea36007c27 100644 --- a/js/src/vm/Interpreter.h +++ b/js/src/vm/Interpreter.h @@ -325,6 +325,15 @@ HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp); extern void UnwindScope(JSContext *cx, ScopeIter &si, jsbytecode *pc); +// Unwind all scopes. +extern void +UnwindAllScopes(JSContext *cx, ScopeIter &si); + +// Compute the pc needed to unwind the scope to the beginning of the block +// pointed to by the try note. +extern jsbytecode * +UnwindScopeToTryPc(JSScript *script, JSTryNote *tn); + /* * Unwind for an uncatchable exception. This means not running finalizers, etc; * just preserving the basic engine stack invariants. From b0dbddedd0740cb8b6674c594565495017f14a68 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 15 Sep 2014 16:30:46 -0700 Subject: [PATCH 19/32] Bug 1001090 - Part 3: Compile new let opcodes in Ion. (r=jandem) --- js/src/jit-test/tests/debug/Frame-eval-21.js | 3 - js/src/jit/CodeGenerator.cpp | 24 +++ js/src/jit/CodeGenerator.h | 2 + js/src/jit/CompileInfo.h | 7 + js/src/jit/IonAnalysis.cpp | 6 +- js/src/jit/IonBuilder.cpp | 168 +++++++++++++++---- js/src/jit/IonBuilder.h | 20 ++- js/src/jit/IonTypes.h | 26 +-- js/src/jit/LIR-Common.h | 22 +++ js/src/jit/LOpcodes.h | 4 +- js/src/jit/Lowering.cpp | 17 ++ js/src/jit/Lowering.h | 2 + js/src/jit/MIR.cpp | 3 + js/src/jit/MIR.h | 51 ++++++ js/src/jit/MOpcodes.h | 4 +- js/src/jit/ParallelSafetyAnalysis.cpp | 2 + js/src/jit/VMFunctions.cpp | 4 +- js/src/jit/VMFunctions.h | 2 +- js/src/jit/shared/CodeGenerator-shared.cpp | 10 +- js/src/jsinfer.h | 8 +- js/src/jsinferinlines.h | 2 +- js/src/vm/ScopeObject.h | 4 + 22 files changed, 330 insertions(+), 61 deletions(-) diff --git a/js/src/jit-test/tests/debug/Frame-eval-21.js b/js/src/jit-test/tests/debug/Frame-eval-21.js index 332c84f29299..097eb5078f5d 100644 --- a/js/src/jit-test/tests/debug/Frame-eval-21.js +++ b/js/src/jit-test/tests/debug/Frame-eval-21.js @@ -1,8 +1,5 @@ // Eval-in-frame with different type on baseline frame with let-scoping -// FIXMEshu disabled until TDZ checks are implemented in the JITs. -quit(0); - load(libdir + "jitopts.js"); if (!jitTogglesMatch(Opts_BaselineEager)) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 07565e3897b6..20ae59291af6 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -9207,5 +9207,29 @@ CodeGenerator::visitRecompileCheck(LRecompileCheck *ins) return true; } +typedef bool (*ThrowUninitializedLexicalFn)(JSContext *); +static const VMFunction ThrowUninitializedLexicalInfo = + FunctionInfo(ThrowUninitializedLexical); + +bool +CodeGenerator::visitLexicalCheck(LLexicalCheck *ins) +{ + OutOfLineCode *ool = oolCallVM(ThrowUninitializedLexicalInfo, ins, (ArgList()), + StoreNothing()); + if (!ool) + return false; + ValueOperand inputValue = ToValue(ins, LLexicalCheck::Input); + masm.branchTestMagicValue(Assembler::Equal, inputValue, JS_UNINITIALIZED_LEXICAL, + ool->entry()); + masm.bind(ool->rejoin()); + return true; +} + +bool +CodeGenerator::visitThrowUninitializedLexical(LThrowUninitializedLexical *ins) +{ + return callVM(ThrowUninitializedLexicalInfo, ins); +} + } // namespace jit } // namespace js diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 637cdd6654b2..56e59f4b95fe 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -305,6 +305,8 @@ class CodeGenerator : public CodeGeneratorSpecific bool visitAsmJSParameter(LAsmJSParameter *lir); bool visitAsmJSReturn(LAsmJSReturn *ret); bool visitAsmJSVoidReturn(LAsmJSVoidReturn *ret); + bool visitLexicalCheck(LLexicalCheck *ins); + bool visitThrowUninitializedLexical(LThrowUninitializedLexical *ins); bool visitCheckOverRecursed(LCheckOverRecursed *lir); bool visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool); diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index 20a2864c2f45..3a9c890f87e1 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -189,6 +189,7 @@ class CompileInfo nargs_ = fun ? fun->nargs() : 0; nbodyfixed_ = script->nbodyfixed(); nlocals_ = script->nfixed(); + fixedLexicalBegin_ = script->fixedLexicalBegin(); nstack_ = script->nslots() - script->nfixed(); nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; } @@ -204,6 +205,7 @@ class CompileInfo nlocals_ = nlocals; nstack_ = 1; /* For FunctionCompiler::pushPhiInput/popPhiOutput */ nslots_ = nlocals_ + nstack_; + fixedLexicalBegin_ = nlocals; } JSScript *script() const { @@ -304,6 +306,10 @@ class CompileInfo unsigned ninvoke() const { return nslots_ - nstack_; } + // The slot number at which fixed lexicals begin. + unsigned fixedLexicalBegin() const { + return fixedLexicalBegin_; + } uint32_t scopeChainSlot() const { JS_ASSERT(script()); @@ -470,6 +476,7 @@ class CompileInfo unsigned nlocals_; unsigned nstack_; unsigned nslots_; + unsigned fixedLexicalBegin_; JSScript *script_; JSFunction *fun_; jsbytecode *osrPc_; diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 37d3867f2372..a524444d085d 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -1089,6 +1089,9 @@ TypeAnalyzer::replaceRedundantPhi(MPhi *phi) case MIRType_MagicOptimizedOut: v = MagicValue(JS_OPTIMIZED_OUT); break; + case MIRType_MagicUninitializedLexical: + v = MagicValue(JS_UNINITIALIZED_LEXICAL); + break; default: MOZ_CRASH("unexpected type"); } @@ -1112,7 +1115,8 @@ TypeAnalyzer::insertConversions() if (phi->type() == MIRType_Undefined || phi->type() == MIRType_Null || phi->type() == MIRType_MagicOptimizedArguments || - phi->type() == MIRType_MagicOptimizedOut) + phi->type() == MIRType_MagicOptimizedOut || + phi->type() == MIRType_MagicUninitializedLexical) { replaceRedundantPhi(*phi); phi = block->discardPhiAt(phi); diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 6bc34128b7c4..8ea41873be72 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -67,7 +67,7 @@ jit::NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame, Compil // during compilation could capture nursery pointers, so the values' types // are recorded instead. - inspector->thisType = types::GetMaybeOptimizedOutValueType(frame->thisValue()); + inspector->thisType = types::GetMaybeUntrackedValueType(frame->thisValue()); if (frame->scopeChain()->hasSingletonType()) inspector->singletonScopeChain = frame->scopeChain(); @@ -81,10 +81,10 @@ jit::NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame, Compil if (script->formalIsAliased(i)) { inspector->argTypes.infallibleAppend(types::Type::UndefinedType()); } else if (!script->argsObjAliasesFormals()) { - types::Type type = types::GetMaybeOptimizedOutValueType(frame->unaliasedFormal(i)); + types::Type type = types::GetMaybeUntrackedValueType(frame->unaliasedFormal(i)); inspector->argTypes.infallibleAppend(type); } else if (frame->hasArgsObj()) { - types::Type type = types::GetMaybeOptimizedOutValueType(frame->argsObj().arg(i)); + types::Type type = types::GetMaybeUntrackedValueType(frame->argsObj().arg(i)); inspector->argTypes.infallibleAppend(type); } else { inspector->argTypes.infallibleAppend(types::Type::UndefinedType()); @@ -98,7 +98,7 @@ jit::NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame, Compil if (info->isSlotAliasedAtOsr(i + info->firstLocalSlot())) { inspector->varTypes.infallibleAppend(types::Type::UndefinedType()); } else { - types::Type type = types::GetMaybeOptimizedOutValueType(frame->unaliasedLocal(i)); + types::Type type = types::GetMaybeUntrackedValueType(frame->unaliasedLocal(i)); inspector->varTypes.infallibleAppend(type); } } @@ -125,6 +125,7 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, typeArrayHint(0), bytecodeTypeMap(nullptr), loopDepth_(loopDepth), + lexicalCheck_(nullptr), callerResumePoint_(nullptr), callerBuilder_(nullptr), cfgStack_(*temp), @@ -668,13 +669,7 @@ IonBuilder::build() #endif initParameters(); - - // Initialize local variables. - for (uint32_t i = 0; i < info().nlocals(); i++) { - MConstant *undef = MConstant::New(alloc(), UndefinedValue()); - current->add(undef); - current->initSlot(info().localSlot(i), undef); - } + initLocals(); // Initialize something for the scope chain. We can bail out before the // start instruction, but the snapshot is encoded *at* the start @@ -887,14 +882,10 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi if (!initScopeChain(callInfo.fun())) return false; - JitSpew(JitSpew_Inlining, "Initializing %u local slots", info().nlocals()); + JitSpew(JitSpew_Inlining, "Initializing %u local slots; fixed lexicals begin at %u", + info().nlocals(), info().fixedLexicalBegin()); - // Initialize local variables. - for (uint32_t i = 0; i < info().nlocals(); i++) { - MConstant *undef = MConstant::New(alloc(), UndefinedValue()); - current->add(undef); - current->initSlot(info().localSlot(i), undef); - } + initLocals(); JitSpew(JitSpew_Inlining, "Inline entry block MResumePoint %p, %u operands", (void *) current->entryResumePoint(), current->entryResumePoint()->numOperands()); @@ -988,6 +979,31 @@ IonBuilder::initParameters() } } +void +IonBuilder::initLocals() +{ + if (info().nlocals() == 0) + return; + + MConstant *undef = nullptr; + if (info().fixedLexicalBegin() > 0) { + undef = MConstant::New(alloc(), UndefinedValue()); + current->add(undef); + } + + MConstant *uninitLexical = nullptr; + if (info().fixedLexicalBegin() < info().nlocals()) { + uninitLexical = MConstant::New(alloc(), MagicValue(JS_UNINITIALIZED_LEXICAL)); + current->add(uninitLexical); + } + + for (uint32_t i = 0; i < info().nlocals(); i++) { + current->initSlot(info().localSlot(i), (i < info().fixedLexicalBegin() + ? undef + : uninitLexical)); + } +} + bool IonBuilder::initScopeChain(MDefinition *callee) { @@ -1310,6 +1326,7 @@ IonBuilder::traverseBytecode() case JSOP_SWAP: case JSOP_SETARG: case JSOP_SETLOCAL: + case JSOP_INITLEXICAL: case JSOP_SETRVAL: case JSOP_VOID: // Don't require SSA uses for values popped by these ops. @@ -1535,6 +1552,22 @@ IonBuilder::inspectOpcode(JSOp op) current->setLocal(GET_LOCALNO(pc)); return true; + case JSOP_CHECKLEXICAL: + return jsop_checklexical(); + + case JSOP_INITLEXICAL: + current->setLocal(GET_LOCALNO(pc)); + return true; + + case JSOP_CHECKALIASEDLEXICAL: + return jsop_checkaliasedlet(ScopeCoordinate(pc)); + + case JSOP_INITALIASEDLEXICAL: + return jsop_setaliasedvar(ScopeCoordinate(pc)); + + case JSOP_UNINITIALIZED: + return pushConstant(MagicValue(JS_UNINITIALIZED_LEXICAL)); + case JSOP_POP: current->pop(); @@ -6732,7 +6765,8 @@ NumFixedSlots(JSObject *object) } bool -IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded) +IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded, + MDefinition *lexicalCheck) { jsid id = NameToId(name); @@ -6742,6 +6776,10 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc *psucceeded = true; if (staticObject->is()) { + // Known values on the global definitely don't need TDZ checks. + if (lexicalCheck) + lexicalCheck->setNotGuardUnchecked(); + // Optimize undefined, NaN, and Infinity. if (name == names().undefined) return pushConstant(UndefinedValue()); @@ -6751,6 +6789,14 @@ IonBuilder::getStaticName(JSObject *staticObject, PropertyName *name, bool *psuc return pushConstant(compartment->runtime()->positiveInfinityValue()); } + // When not loading a known value on the global with a lexical check, + // always emit the lexical check. This could be optimized, but is + // currently not for simplicity's sake. + if (lexicalCheck) { + *psucceeded = false; + return true; + } + types::TypeObjectKey *staticType = types::TypeObjectKey::get(staticObject); if (analysisContext) staticType->ensureTrackedProperty(analysisContext, NameToId(name)); @@ -10272,6 +10318,36 @@ IonBuilder::jsop_deffun(uint32_t index) return resumeAfter(deffun); } +bool +IonBuilder::jsop_checklexical() +{ + uint32_t slot = info().localSlot(GET_LOCALNO(pc)); + MDefinition *lexical = addLexicalCheck(current->getSlot(slot)); + if (!lexical) + return false; + current->setSlot(slot, lexical); + return true; +} + +bool +IonBuilder::jsop_checkaliasedlet(ScopeCoordinate sc) +{ + MDefinition *let = addLexicalCheck(getAliasedVar(sc)); + if (!let) + return false; + + jsbytecode *nextPc = pc + JSOP_CHECKALIASEDLEXICAL_LENGTH; + MOZ_ASSERT(JSOp(*nextPc) == JSOP_GETALIASEDVAR || JSOp(*nextPc) == JSOP_SETALIASEDVAR); + MOZ_ASSERT(sc == ScopeCoordinate(nextPc)); + + // If we are checking for a load, push the checked let so that the load + // can use it. + if (JSOp(*nextPc) == JSOP_GETALIASEDVAR) + setLexicalCheck(let); + + return true; +} + bool IonBuilder::jsop_this() { @@ -10492,19 +10568,9 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall) return true; } -bool -IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc) +MDefinition * +IonBuilder::getAliasedVar(ScopeCoordinate sc) { - JSObject *call = nullptr; - if (hasStaticScopeObject(sc, &call) && call) { - PropertyName *name = ScopeCoordinateName(scopeCoordinateNameCache, script(), pc); - bool succeeded; - if (!getStaticName(call, name, &succeeded)) - return false; - if (succeeded) - return true; - } - MDefinition *obj = walkScopeChain(sc.hops()); Shape *shape = ScopeCoordinateToStaticScopeShape(script(), pc); @@ -10520,6 +10586,26 @@ IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc) } current->add(load); + return load; +} + +bool +IonBuilder::jsop_getaliasedvar(ScopeCoordinate sc) +{ + JSObject *call = nullptr; + if (hasStaticScopeObject(sc, &call) && call) { + PropertyName *name = ScopeCoordinateName(scopeCoordinateNameCache, script(), pc); + bool succeeded; + if (!getStaticName(call, name, &succeeded, takeLexicalCheck())) + return false; + if (succeeded) + return true; + } + + // See jsop_checkaliasedlet. + MDefinition *load = takeLexicalCheck(); + if (!load) + load = getAliasedVar(sc); current->push(load); types::TemporaryTypeSet *types = bytecodeTypes(pc); @@ -10993,3 +11079,23 @@ IonBuilder::getCallee() return inlineCallInfo_->fun(); } + +MDefinition * +IonBuilder::addLexicalCheck(MDefinition *input) +{ + MOZ_ASSERT(JSOp(*pc) == JSOP_CHECKLEXICAL || JSOp(*pc) == JSOP_CHECKALIASEDLEXICAL); + + // If we're guaranteed to not be JS_UNINITIALIZED_LEXICAL, no need to check. + MInstruction *lexicalCheck; + if (input->type() == MIRType_MagicUninitializedLexical) + lexicalCheck = MThrowUninitializedLexical::New(alloc()); + else if (input->type() == MIRType_Value) + lexicalCheck = MLexicalCheck::New(alloc(), input); + else + return input; + + current->add(lexicalCheck); + if (!resumeAfter(lexicalCheck)) + return nullptr; + return lexicalCheck->isLexicalCheck() ? lexicalCheck : constant(UndefinedValue()); +} diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index c6eac92c344e..b09433765134 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -338,6 +338,7 @@ class IonBuilder void insertRecompileCheck(); void initParameters(); + void initLocals(); void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex); void rewriteParameters(); bool initScopeChain(MDefinition *callee = nullptr); @@ -573,6 +574,8 @@ class IonBuilder MDefinition *getCallee(); + MDefinition *getAliasedVar(ScopeCoordinate sc); + MDefinition *addLexicalCheck(MDefinition *input); bool jsop_add(MDefinition *left, MDefinition *right); bool jsop_bitnot(); @@ -585,6 +588,8 @@ class IonBuilder bool jsop_defvar(uint32_t index); bool jsop_deffun(uint32_t index); bool jsop_notearg(); + bool jsop_checklexical(); + bool jsop_checkaliasedlet(ScopeCoordinate sc); bool jsop_funcall(uint32_t argc); bool jsop_funapply(uint32_t argc); bool jsop_funapplyarguments(uint32_t argc); @@ -598,7 +603,8 @@ class IonBuilder bool jsop_dup2(); bool jsop_loophead(jsbytecode *pc); bool jsop_compare(JSOp op); - bool getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded); + bool getStaticName(JSObject *staticObject, PropertyName *name, bool *psucceeded, + MDefinition *lexicalCheck = nullptr); bool setStaticName(JSObject *staticObject, PropertyName *name); bool jsop_getgname(PropertyName *name); bool jsop_getname(PropertyName *name); @@ -893,6 +899,18 @@ class IonBuilder return BytecodeSite(info().inlineScriptTree(), pc); } + MDefinition *lexicalCheck_; + + void setLexicalCheck(MDefinition *lexical) { + MOZ_ASSERT(!lexicalCheck_); + lexicalCheck_ = lexical; + } + MDefinition *takeLexicalCheck() { + MDefinition *lexical = lexicalCheck_; + lexicalCheck_ = nullptr; + return lexical; + } + /* Information used for inline-call builders. */ MResumePoint *callerResumePoint_; jsbytecode *callerPC() { diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index 757c0bd04bef..a27a8dc7fa2d 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -352,18 +352,19 @@ enum MIRType MIRType_String, MIRType_Symbol, MIRType_Object, - MIRType_MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value. - MIRType_MagicOptimizedOut, // JS_OPTIMIZED_OUT magic value. - MIRType_MagicHole, // JS_ELEMENTS_HOLE magic value. - MIRType_MagicIsConstructing, // JS_IS_CONSTRUCTING magic value. + MIRType_MagicOptimizedArguments, // JS_OPTIMIZED_ARGUMENTS magic value. + MIRType_MagicOptimizedOut, // JS_OPTIMIZED_OUT magic value. + MIRType_MagicHole, // JS_ELEMENTS_HOLE magic value. + MIRType_MagicIsConstructing, // JS_IS_CONSTRUCTING magic value. + MIRType_MagicUninitializedLexical, // JS_UNINITIALIZED_LEXICAL magic value. MIRType_Value, - MIRType_None, // Invalid, used as a placeholder. - MIRType_Slots, // A slots vector - MIRType_Elements, // An elements vector - MIRType_Pointer, // An opaque pointer that receives no special treatment - MIRType_Shape, // A Shape pointer. - MIRType_TypeObject, // A TypeObject pointer. - MIRType_ForkJoinContext, // js::ForkJoinContext* + MIRType_None, // Invalid, used as a placeholder. + MIRType_Slots, // A slots vector + MIRType_Elements, // An elements vector + MIRType_Pointer, // An opaque pointer that receives no special treatment + MIRType_Shape, // A Shape pointer. + MIRType_TypeObject, // A TypeObject pointer. + MIRType_ForkJoinContext, // js::ForkJoinContext* MIRType_Last = MIRType_ForkJoinContext, MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT), MIRType_Int32x4 = MIRType_Int32 | (2 << VECTOR_SCALE_SHIFT), @@ -435,6 +436,7 @@ ValueTypeFromMIRType(MIRType type) case MIRType_MagicOptimizedOut: case MIRType_MagicHole: case MIRType_MagicIsConstructing: + case MIRType_MagicUninitializedLexical: return JSVAL_TYPE_MAGIC; default: JS_ASSERT(type == MIRType_Object); @@ -478,6 +480,8 @@ StringFromMIRType(MIRType type) return "MagicHole"; case MIRType_MagicIsConstructing: return "MagicIsConstructing"; + case MIRType_MagicUninitializedLexical: + return "MagicUninitializedLexical"; case MIRType_Value: return "Value"; case MIRType_None: diff --git a/js/src/jit/LIR-Common.h b/js/src/jit/LIR-Common.h index 87310fff569c..aa6f39fc84b0 100644 --- a/js/src/jit/LIR-Common.h +++ b/js/src/jit/LIR-Common.h @@ -6478,6 +6478,28 @@ class LRecompileCheck : public LInstructionHelper<0, 0, 1> } }; +class LLexicalCheck : public LInstructionHelper<0, BOX_PIECES, 0> +{ + public: + LIR_HEADER(LexicalCheck) + + MLexicalCheck *mir() { + return mir_->toLexicalCheck(); + } + + static const size_t Input = 0; +}; + +class LThrowUninitializedLexical : public LCallInstructionHelper<0, 0, 0> +{ + public: + LIR_HEADER(ThrowUninitializedLexical) + + MLexicalCheck *mir() { + return mir_->toLexicalCheck(); + } +}; + } // namespace jit } // namespace js diff --git a/js/src/jit/LOpcodes.h b/js/src/jit/LOpcodes.h index 726b3df53b24..2ed01aa774e7 100644 --- a/js/src/jit/LOpcodes.h +++ b/js/src/jit/LOpcodes.h @@ -318,7 +318,9 @@ _(AssertRangeI) \ _(AssertRangeD) \ _(AssertRangeF) \ - _(AssertRangeV) + _(AssertRangeV) \ + _(LexicalCheck) \ + _(ThrowUninitializedLexical) #if defined(JS_CODEGEN_X86) # include "jit/x86/LOpcodes-x86.h" diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 8d01fb5a8695..b087fc72ae44 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -3790,6 +3790,23 @@ LIRGenerator::visitSimdBinaryBitwise(MSimdBinaryBitwise *ins) return false; } +bool +LIRGenerator::visitLexicalCheck(MLexicalCheck *ins) +{ + MDefinition *input = ins->input(); + MOZ_ASSERT(input->type() == MIRType_Value); + LLexicalCheck *lir = new(alloc()) LLexicalCheck(); + return redefine(ins, input) && useBox(lir, LLexicalCheck::Input, input) && + add(lir, ins) && assignSafepoint(lir, ins); +} + +bool +LIRGenerator::visitThrowUninitializedLexical(MThrowUninitializedLexical *ins) +{ + LThrowUninitializedLexical *lir = new(alloc()) LThrowUninitializedLexical(); + return add(lir, ins) && assignSafepoint(lir, ins); +} + static void SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index dde4cb0aba43..6ab6e934efe8 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -279,6 +279,8 @@ class LIRGenerator : public LIRGeneratorSpecific bool visitObjectState(MObjectState *ins); bool visitArrayState(MArrayState *ins); bool visitUnknownValue(MUnknownValue *ins); + bool visitLexicalCheck(MLexicalCheck *ins); + bool visitThrowUninitializedLexical(MThrowUninitializedLexical *ins); }; } // namespace jit diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index dfbb75b65ab7..b1456b5ec2b2 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -647,6 +647,9 @@ MConstant::printOpcode(FILE *fp) const case MIRType_MagicOptimizedOut: fprintf(fp, "magic optimized-out"); break; + case MIRType_MagicUninitializedLexical: + fprintf(fp, "magic uninitialized-lexical"); + break; default: MOZ_CRASH("unexpected type"); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 1bca0bc35868..702ed650b0b9 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -49,6 +49,8 @@ MIRType MIRTypeFromValue(const js::Value &vp) return MIRType_MagicHole; case JS_IS_CONSTRUCTING: return MIRType_MagicIsConstructing; + case JS_UNINITIALIZED_LEXICAL: + return MIRType_MagicUninitializedLexical; default: MOZ_ASSERT(!"Unexpected magic constant"); } @@ -6207,6 +6209,55 @@ class MAsmJSInterruptCheck : public MNullaryInstruction } }; +// Checks if a value is JS_UNINITIALIZED_LEXICAL, throwing if so. +class MLexicalCheck + : public MUnaryInstruction, + public BoxPolicy<0> +{ + explicit MLexicalCheck(MDefinition *input) + : MUnaryInstruction(input) + { + setGuard(); + setResultType(MIRType_Value); + setResultTypeSet(input->resultTypeSet()); + } + + public: + INSTRUCTION_HEADER(LexicalCheck) + + static MLexicalCheck *New(TempAllocator &alloc, MDefinition *input) { + return new(alloc) MLexicalCheck(input); + } + + AliasSet getAliasSet() const { + return AliasSet::None(); + } + + MDefinition *input() const { + return getOperand(0); + } +}; + +// Unconditionally throw an uninitialized let error. +class MThrowUninitializedLexical : public MNullaryInstruction +{ + MThrowUninitializedLexical() { + setGuard(); + setResultType(MIRType_None); + } + + public: + INSTRUCTION_HEADER(ThrowUninitializedLexical) + + static MThrowUninitializedLexical *New(TempAllocator &alloc) { + return new(alloc) MThrowUninitializedLexical(); + } + + AliasSet getAliasSet() const { + return AliasSet::None(); + } +}; + // If not defined, set a global variable to |undefined|. class MDefVar : public MUnaryInstruction { diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index 361d1c784744..59de4bae434d 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -243,7 +243,9 @@ namespace jit { _(GuardThreadExclusive) \ _(InterruptCheckPar) \ _(RecompileCheck) \ - _(UnknownValue) + _(UnknownValue) \ + _(LexicalCheck) \ + _(ThrowUninitializedLexical) // Forward declarations of MIR types. #define FORWARD_DECLARE(op) class M##op; diff --git a/js/src/jit/ParallelSafetyAnalysis.cpp b/js/src/jit/ParallelSafetyAnalysis.cpp index 23bd281182a2..105fb6a5b824 100644 --- a/js/src/jit/ParallelSafetyAnalysis.cpp +++ b/js/src/jit/ParallelSafetyAnalysis.cpp @@ -342,6 +342,8 @@ class ParallelSafetyVisitor : public MDefinitionVisitor UNSAFE_OP(AsmJSCall) DROP_OP(RecompileCheck) UNSAFE_OP(UnknownValue) + UNSAFE_OP(LexicalCheck) + UNSAFE_OP(ThrowUninitializedLexical) // It looks like this could easily be made safe: UNSAFE_OP(ConvertElementsToDoubles) diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 9b42c6be0e83..62d5cdc0afae 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -1236,11 +1236,11 @@ MarkTypeObjectFromIon(JSRuntime *rt, types::TypeObject **typep) } bool -ThrowUninitializedLet(JSContext *cx) +ThrowUninitializedLexical(JSContext *cx) { ScriptFrameIter iter(cx); RootedScript script(cx, iter.script()); - ReportUninitializedLet(cx, script, iter.pc()); + ReportUninitializedLexical(cx, script, iter.pc()); return false; } diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 971a314f616c..06d74bd8a00c 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -747,7 +747,7 @@ IonMarkFunction(MIRType type) bool ObjectIsCallable(JSObject *obj); -bool ThrowUninitializedLet(JSContext *cx); +bool ThrowUninitializedLexical(JSContext *cx); } // namespace jit } // namespace js diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 7c07611bada6..6bd7ea8b8ec3 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -345,12 +345,14 @@ CodeGeneratorShared::encodeAllocation(LSnapshot *snapshot, MDefinition *mir, } case MIRType_MagicOptimizedArguments: case MIRType_MagicOptimizedOut: + case MIRType_MagicUninitializedLexical: { uint32_t index; - JSWhyMagic why = (type == MIRType_MagicOptimizedArguments - ? JS_OPTIMIZED_ARGUMENTS - : JS_OPTIMIZED_OUT); - Value v = MagicValue(why); + Value v = MagicValue(type == MIRType_MagicOptimizedArguments + ? JS_OPTIMIZED_ARGUMENTS + : (type == MIRType_MagicOptimizedOut + ? JS_OPTIMIZED_OUT + : JS_UNINITIALIZED_LEXICAL)); if (!graph.addConstantToPool(v, &index)) return false; alloc = RValueAllocation::ConstantPool(index); diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index e9ca2a65f47b..8457871e13ff 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -318,11 +318,11 @@ class Type inline Type GetValueType(const Value &val); /* - * Get the type of a possibly optimized out value. This generally only - * happens on unconditional type monitors on bailing out of Ion, such as - * for argument and local types. + * Get the type of a possibly optimized out or uninitialized let value. This + * generally only happens on unconditional type monitors on bailing out of + * Ion, such as for argument and local types. */ -inline Type GetMaybeOptimizedOutValueType(const Value &val); +inline Type GetMaybeUntrackedValueType(const Value &val); /* * Type inference memory management overview. diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index fa31816f32eb..14ffc2c4a8ab 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -137,7 +137,7 @@ GetValueType(const Value &val) } inline Type -GetMaybeOptimizedOutValueType(const Value &val) +GetMaybeUntrackedValueType(const Value &val) { if (val.isMagic() && (val.whyMagic() == JS_OPTIMIZED_OUT || val.whyMagic() == JS_UNINITIALIZED_LEXICAL)) diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 3ca6395993ab..6ffce7cb73c8 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -130,6 +130,10 @@ class ScopeCoordinate uint32_t hops() const { JS_ASSERT(hops_ < SCOPECOORD_HOPS_LIMIT); return hops_; } uint32_t slot() const { JS_ASSERT(slot_ < SCOPECOORD_SLOT_LIMIT); return slot_; } + + bool operator==(const ScopeCoordinate &rhs) const { + return hops() == rhs.hops() && slot() == rhs.slot(); + } }; /* From 15262d36a9957d84e40eb99861f928fb30c02f42 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 15 Sep 2014 16:30:46 -0700 Subject: [PATCH 20/32] Bug 1001090 - Part 4: Fix errors in chrome code. (r=zombie,gavin,fitzgen,dcamp,bgrins,fabrice,gwagner,margaret,mrbkap,mak,njn,vicamo) --- addon-sdk/source/lib/sdk/deprecated/symbiont.js | 1 - addon-sdk/source/lib/sdk/io/fs.js | 12 ++++++------ addon-sdk/source/lib/sdk/windows/fennec.js | 2 +- browser/base/content/aboutSocialError.xhtml | 2 +- browser/base/content/browser-plugins.js | 4 ++-- browser/base/content/nsContextMenu.js | 2 +- browser/base/content/webrtcIndicator.js | 2 +- browser/components/nsBrowserGlue.js | 4 ++-- browser/devtools/debugger/debugger-view.js | 2 +- browser/devtools/framework/toolbox-process-window.js | 2 +- browser/devtools/markupview/markup-view.js | 2 +- browser/devtools/shared/theme-switching.js | 1 - browser/devtools/shared/widgets/TableWidget.js | 2 +- dom/browser-element/BrowserElementPanning.js | 2 +- dom/contacts/ContactManager.js | 2 +- dom/contacts/fallback/ContactService.jsm | 3 ++- dom/mobilemessage/gonk/MobileMessageDB.jsm | 2 +- mobile/android/components/PromptService.js | 3 ++- services/cloudsync/CloudSyncBookmarks.jsm | 1 - services/crypto/modules/WeaveCrypto.js | 2 +- services/sync/modules/userapi.js | 4 ++-- testing/marionette/marionette-listener.js | 2 +- testing/marionette/marionette-server.js | 1 - testing/specialpowers/content/specialpowersAPI.js | 2 +- .../components/aboutmemory/content/aboutMemory.js | 2 +- toolkit/components/crashes/CrashManager.jsm | 2 +- .../components/passwordmgr/LoginManagerParent.jsm | 1 - toolkit/components/passwordmgr/storage-mozStorage.js | 2 +- toolkit/components/places/PlacesTransactions.jsm | 2 +- toolkit/devtools/LayoutHelpers.jsm | 2 +- toolkit/devtools/client/dbg-client.jsm | 2 +- toolkit/devtools/server/actors/script.js | 12 +++++++----- toolkit/devtools/server/main.js | 4 ---- .../mozapps/extensions/internal/AddonRepository.jsm | 3 +-- 34 files changed, 44 insertions(+), 50 deletions(-) diff --git a/addon-sdk/source/lib/sdk/deprecated/symbiont.js b/addon-sdk/source/lib/sdk/deprecated/symbiont.js index 89447ec4a587..f43daeae8b51 100644 --- a/addon-sdk/source/lib/sdk/deprecated/symbiont.js +++ b/addon-sdk/source/lib/sdk/deprecated/symbiont.js @@ -180,7 +180,6 @@ const Symbiont = Worker.resolve({ } let eventName = 'end' == this.contentScriptWhen ? 'load' : 'DOMContentLoaded'; - let self = this; this._loadEvent = eventName; frame.addEventListener(eventName, this._loadListener = function _onReady(event) { diff --git a/addon-sdk/source/lib/sdk/io/fs.js b/addon-sdk/source/lib/sdk/io/fs.js index 57878dbf658e..08fc1fb449be 100644 --- a/addon-sdk/source/lib/sdk/io/fs.js +++ b/addon-sdk/source/lib/sdk/io/fs.js @@ -648,25 +648,25 @@ exports.close = close; * Synchronous open(2). */ function openSync(path, flags, mode) { - let [ fd, flags, mode, file ] = + let [ fd, flags_, mode_, file ] = [ { path: path }, Flags(flags), Mode(mode), nsILocalFile(path) ]; nsIFile(fd, file); // If trying to open file for just read that does not exists // need to throw exception as node does. - if (!file.exists() && !isWritable(flags)) + if (!file.exists() && !isWritable(flags_)) throw FSError("open", "ENOENT", 34, path); // If we want to open file in read mode we initialize input stream. - if (isReadable(flags)) { - let input = FileInputStream(file, flags, mode, DEFER_OPEN); + if (isReadable(flags_)) { + let input = FileInputStream(file, flags_, mode_, DEFER_OPEN); nsIFileInputStream(fd, input); } // If we want to open file in write mode we initialize output stream for it. - if (isWritable(flags)) { - let output = FileOutputStream(file, flags, mode, DEFER_OPEN); + if (isWritable(flags_)) { + let output = FileOutputStream(file, flags_, mode_, DEFER_OPEN); nsIFileOutputStream(fd, output); } diff --git a/addon-sdk/source/lib/sdk/windows/fennec.js b/addon-sdk/source/lib/sdk/windows/fennec.js index 343d099ab7a6..25a0f35abd6c 100644 --- a/addon-sdk/source/lib/sdk/windows/fennec.js +++ b/addon-sdk/source/lib/sdk/windows/fennec.js @@ -64,7 +64,7 @@ function getBrowserWindow(options) { return window; // we don't have a BrowserWindow yet, so create one - var window = BrowserWindow(options); + window = BrowserWindow(options); addListItem(browserWindows, window); return window; } diff --git a/browser/base/content/aboutSocialError.xhtml b/browser/base/content/aboutSocialError.xhtml index eba803a915c8..896dd7ffc2fc 100644 --- a/browser/base/content/aboutSocialError.xhtml +++ b/browser/base/content/aboutSocialError.xhtml @@ -61,7 +61,7 @@ case "tryAgain": let urlMatch = queryString.match(/url=([^&]+)/); let encodedURL = urlMatch && urlMatch[1] ? urlMatch[1] : ""; - let url = decodeURIComponent(encodedURL); + url = decodeURIComponent(encodedURL); config.tryAgainCallback = loadQueryURL; config.queryURL = url; diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index cfb56dcfa28c..a300291ae9df 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -1310,8 +1310,8 @@ var gPluginHandler = { buttons.push(submitButton); #endif - let notification = notificationBox.appendNotification(messageString, "plugin-crashed", - iconURL, priority, buttons); + notification = notificationBox.appendNotification(messageString, "plugin-crashed", + iconURL, priority, buttons); // Add the "learn more" link. let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 660819c41ba6..75ae2364ea85 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -740,7 +740,7 @@ nsContextMenu.prototype = { // if the document is editable, show context menu like in text inputs if (!this.onEditableArea) { - var win = this.target.ownerDocument.defaultView; + win = this.target.ownerDocument.defaultView; if (win) { var isEditable = false; try { diff --git a/browser/base/content/webrtcIndicator.js b/browser/base/content/webrtcIndicator.js index acbf2d7bcbb0..a4109de16dc4 100644 --- a/browser/base/content/webrtcIndicator.js +++ b/browser/base/content/webrtcIndicator.js @@ -147,7 +147,7 @@ let PositionHandler = { }, setXPosition: function(desiredX) { // Ensure the indicator isn't moved outside the available area of the screen. - let desiredX = Math.max(desiredX, screen.availLeft); + desiredX = Math.max(desiredX, screen.availLeft); let maxX = screen.availLeft + screen.availWidth - document.documentElement.clientWidth; window.moveTo(Math.min(desiredX, maxX), screen.availTop); diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 12ffdb99d57c..53e3fe4957bd 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -2170,9 +2170,9 @@ let DefaultBrowserCheck = { let neverItem = doc.createElement("menuitem"); neverItem.id = "defaultBrowserNever"; - let label = bundle.getString("setDefaultBrowserNever.label"); + label = bundle.getString("setDefaultBrowserNever.label"); neverItem.setAttribute("label", label); - let accesskey = bundle.getString("setDefaultBrowserNever.accesskey"); + accesskey = bundle.getString("setDefaultBrowserNever.accesskey"); neverItem.setAttribute("accesskey", accesskey); popup.appendChild(neverItem); diff --git a/browser/devtools/debugger/debugger-view.js b/browser/devtools/debugger/debugger-view.js index 8141469a092e..c4fd7ebfcdcf 100644 --- a/browser/devtools/debugger/debugger-view.js +++ b/browser/devtools/debugger/debugger-view.js @@ -216,7 +216,7 @@ let DebuggerView = { extraKeys["Esc"] = false; function bindKey(func, key, modifiers = {}) { - let key = document.getElementById(key).getAttribute("key"); + key = document.getElementById(key).getAttribute("key"); let shortcut = Editor.accel(key, modifiers); extraKeys[shortcut] = () => DebuggerView.Filtering[func](); } diff --git a/browser/devtools/framework/toolbox-process-window.js b/browser/devtools/framework/toolbox-process-window.js index c53a79c110c8..556d5db574df 100644 --- a/browser/devtools/framework/toolbox-process-window.js +++ b/browser/devtools/framework/toolbox-process-window.js @@ -138,7 +138,7 @@ function quitApp() { } function getParameterByName (name) { - let name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); + name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); let regex = new RegExp("[\\?&]" + name + "=([^&#]*)"); let results = regex.exec(window.location.search); return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); diff --git a/browser/devtools/markupview/markup-view.js b/browser/devtools/markupview/markup-view.js index e9a72438ebbb..5dbb1ff1ad9d 100644 --- a/browser/devtools/markupview/markup-view.js +++ b/browser/devtools/markupview/markup-view.js @@ -1282,7 +1282,7 @@ MarkupView.prototype = { let bgSize = ~~width + "px " + ~~height + "px"; this._preview.setAttribute("style", "background-size:" + bgSize); - let height = ~~(win.innerHeight * ratio) + "px"; + height = ~~(win.innerHeight * ratio) + "px"; let top = ~~(win.scrollY * ratio) + "px"; this._viewbox.setAttribute("style", "height:" + height + ";transform: translateY(" + top + ")"); diff --git a/browser/devtools/shared/theme-switching.js b/browser/devtools/shared/theme-switching.js index e900cb6198a4..0407a42f886a 100644 --- a/browser/devtools/shared/theme-switching.js +++ b/browser/devtools/shared/theme-switching.js @@ -25,7 +25,6 @@ } let oldThemeDef = gDevTools.getThemeDefinition(oldTheme); - let newThemeDef = gDevTools.getThemeDefinition(newTheme); // Unload all theme stylesheets related to the old theme. if (oldThemeDef) { diff --git a/browser/devtools/shared/widgets/TableWidget.js b/browser/devtools/shared/widgets/TableWidget.js index cd189fdc3658..e3f6ea5493b1 100644 --- a/browser/devtools/shared/widgets/TableWidget.js +++ b/browser/devtools/shared/widgets/TableWidget.js @@ -206,7 +206,7 @@ TableWidget.prototype = { let checked = !!item.getAttribute("checked"); let id = item.getAttribute("data-id"); this.emit(EVENTS.HEADER_CONTEXT_MENU, id, checked); - let checked = this.menupopup.querySelectorAll("menuitem[checked]"); + checked = this.menupopup.querySelectorAll("menuitem[checked]"); let disabled = this.menupopup.querySelectorAll("menuitem[disabled]"); if (checked.length == 2) { checked[checked.length - 1].setAttribute("disabled", "true"); diff --git a/dom/browser-element/BrowserElementPanning.js b/dom/browser-element/BrowserElementPanning.js index 04e40648e1ca..828a430b1098 100644 --- a/dom/browser-element/BrowserElementPanning.js +++ b/dom/browser-element/BrowserElementPanning.js @@ -512,7 +512,7 @@ const ContentPanning = { }, _recvDoubleTap: function(data) { - let data = data.json; + data = data.json; // We haven't received a metrics update yet; don't do anything. if (this._viewport == null) { diff --git a/dom/contacts/ContactManager.js b/dom/contacts/ContactManager.js index bcf8c53cdee4..d9ffead66ea1 100644 --- a/dom/contacts/ContactManager.js +++ b/dom/contacts/ContactManager.js @@ -261,7 +261,7 @@ ContactManager.prototype = { } // Create an array with a single nsIContentPermissionType element. - let type = { + type = { type: "contacts", access: access, options: [], diff --git a/dom/contacts/fallback/ContactService.jsm b/dom/contacts/fallback/ContactService.jsm index 8040e7d8ddeb..9ddff341d4ca 100644 --- a/dom/contacts/fallback/ContactService.jsm +++ b/dom/contacts/fallback/ContactService.jsm @@ -102,6 +102,7 @@ let ContactService = this.ContactService = { if (DEBUG) debug("receiveMessage " + aMessage.name); let mm = aMessage.target; let msg = aMessage.data; + let cursorList; switch (aMessage.name) { case "Contacts:Find": @@ -125,7 +126,7 @@ let ContactService = this.ContactService = { if (!this.assertPermission(aMessage, "contacts-read")) { return null; } - let cursorList = this._cursors.get(mm); + cursorList = this._cursors.get(mm); if (!cursorList) { cursorList = []; this._cursors.set(mm, cursorList); diff --git a/dom/mobilemessage/gonk/MobileMessageDB.jsm b/dom/mobilemessage/gonk/MobileMessageDB.jsm index 2a437207f6e1..182d54cc248e 100644 --- a/dom/mobilemessage/gonk/MobileMessageDB.jsm +++ b/dom/mobilemessage/gonk/MobileMessageDB.jsm @@ -1111,7 +1111,7 @@ MobileMessageDB.prototype = { return; } - let threadRecord = { + threadRecord = { participantIds: participantIds, participantAddresses: threadParticipants, lastMessageId: messageRecord.id, diff --git a/mobile/android/components/PromptService.js b/mobile/android/components/PromptService.js index 3a86baccbf76..36a37142cb65 100644 --- a/mobile/android/components/PromptService.js +++ b/mobile/android/components/PromptService.js @@ -384,7 +384,8 @@ InternalPrompt.prototype = { nsIAuthPrompt_loginPrompt: function(aTitle, aPasswordRealm, aSavePassword, aUser, aPass) { let checkMsg = null; let check = { value: false }; - let [hostname, realm, aUser] = PromptUtils.getHostnameAndRealm(aPasswordRealm); + let hostname, realm; + [hostname, realm, aUser] = PromptUtils.getHostnameAndRealm(aPasswordRealm); let canSave = PromptUtils.canSaveLogin(hostname, aSavePassword); if (canSave) { diff --git a/services/cloudsync/CloudSyncBookmarks.jsm b/services/cloudsync/CloudSyncBookmarks.jsm index a204b59b5f75..27c1ed9e0591 100644 --- a/services/cloudsync/CloudSyncBookmarks.jsm +++ b/services/cloudsync/CloudSyncBookmarks.jsm @@ -560,7 +560,6 @@ let RootFolder = function (rootId, rootName) { let processNewFolders = function () { let newFolderGuids = Object.keys(newFolders); let newFolderRoots = []; - let promises = []; for each (let guid in newFolderGuids) { let item = newFolders[guid]; diff --git a/services/crypto/modules/WeaveCrypto.js b/services/crypto/modules/WeaveCrypto.js index 41fdb5522436..290efc822b37 100644 --- a/services/crypto/modules/WeaveCrypto.js +++ b/services/crypto/modules/WeaveCrypto.js @@ -709,7 +709,7 @@ WeaveCrypto.prototype = { // Callee picks if SEC_OID_UNKNOWN, but only SHA1 is supported. let prfAlg = this.nss.SEC_OID_HMAC_SHA1; - let keyLength = keyLength || 0; // 0 = Callee will pick. + keyLength = keyLength || 0; // 0 = Callee will pick. let iterations = KEY_DERIVATION_ITERATIONS; let algid, slot, symKey, keyData; diff --git a/services/sync/modules/userapi.js b/services/sync/modules/userapi.js index 6b9af146def0..ec77d63e27c6 100644 --- a/services/sync/modules/userapi.js +++ b/services/sync/modules/userapi.js @@ -165,7 +165,7 @@ UserAPI10Client.prototype = { return; } - let error = new Error("Sync node retrieval failed."); + error = new Error("Sync node retrieval failed."); switch (response.status) { case 400: error.denied = true; @@ -214,7 +214,7 @@ UserAPI10Client.prototype = { return; } - let error = new Error("Could not create user."); + error = new Error("Could not create user."); error.body = response.body; cb(error, null); diff --git a/testing/marionette/marionette-listener.js b/testing/marionette/marionette-listener.js index 0ba5b09b8454..42482d0dfbdb 100644 --- a/testing/marionette/marionette-listener.js +++ b/testing/marionette/marionette-listener.js @@ -113,7 +113,7 @@ function registerSelf() { } function emitTouchEventForIFrame(message) { - let message = message.json; + message = message.json; let frames = curFrame.document.getElementsByTagName("iframe"); let iframe = frames[message.index]; let identifier = nextTouchId; diff --git a/testing/marionette/marionette-server.js b/testing/marionette/marionette-server.js index a584c3117409..118089e58e25 100644 --- a/testing/marionette/marionette-server.js +++ b/testing/marionette/marionette-server.js @@ -966,7 +966,6 @@ MarionetteServerConnection.prototype = { let curWindow = this.getCurrentWindow(); let original_onerror = curWindow.onerror; - let that = this; that.timeout = timeout; let marionette = new Marionette(this, curWindow, "chrome", this.marionetteLog, diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index d7aa0c38503f..3066ac702945 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -1847,7 +1847,7 @@ SpecialPowersAPI.prototype = { this._quotaManagerCallbackInfos.push(callbackInfo) } else { callbackInfo.listener = function(msg) { - let msg = msg.data; + msg = msg.data; for (let index in this._quotaManagerCallbackInfos) { let callbackInfo = this._quotaManagerCallbackInfos[index]; if (callbackInfo.id == msg.id) { diff --git a/toolkit/components/aboutmemory/content/aboutMemory.js b/toolkit/components/aboutmemory/content/aboutMemory.js index ee1764b7aa56..90034771e7a1 100644 --- a/toolkit/components/aboutmemory/content/aboutMemory.js +++ b/toolkit/components/aboutmemory/content/aboutMemory.js @@ -1129,7 +1129,7 @@ TreeNode.prototype = { maxAbsDescendant: function() { if (!this._kids) { // No kids? Just return the absolute value of the amount. - return max = Math.abs(this._amount); + return Math.abs(this._amount); } if ('_maxAbsDescendant' in this) { diff --git a/toolkit/components/crashes/CrashManager.jsm b/toolkit/components/crashes/CrashManager.jsm index ca1ab77ee1a3..8975a25c128c 100644 --- a/toolkit/components/crashes/CrashManager.jsm +++ b/toolkit/components/crashes/CrashManager.jsm @@ -473,7 +473,7 @@ this.CrashManager.prototype = Object.freeze({ let decoder = new TextDecoder(); data = decoder.decode(data); - let type, time, payload; + let type, time; let start = 0; for (let i = 0; i < 2; i++) { let index = data.indexOf("\n", start); diff --git a/toolkit/components/passwordmgr/LoginManagerParent.jsm b/toolkit/components/passwordmgr/LoginManagerParent.jsm index 4721c25450cd..093a2be7490d 100644 --- a/toolkit/components/passwordmgr/LoginManagerParent.jsm +++ b/toolkit/components/passwordmgr/LoginManagerParent.jsm @@ -160,7 +160,6 @@ var LoginManagerParent = { // Note: previousResult is a regular object, not an // nsIAutoCompleteResult. var result; - var matchingLogins; let searchStringLower = searchString.toLowerCase(); let logins; diff --git a/toolkit/components/passwordmgr/storage-mozStorage.js b/toolkit/components/passwordmgr/storage-mozStorage.js index 9a05f04fa071..4078b08ce395 100644 --- a/toolkit/components/passwordmgr/storage-mozStorage.js +++ b/toolkit/components/passwordmgr/storage-mozStorage.js @@ -1116,7 +1116,7 @@ LoginManagerStorage_mozStorage.prototype = { // Get a list of IDs for existing logins let ids = []; - let query = "SELECT id FROM moz_logins WHERE guid isnull"; + query = "SELECT id FROM moz_logins WHERE guid isnull"; let stmt; try { stmt = this._dbCreateStatement(query); diff --git a/toolkit/components/places/PlacesTransactions.jsm b/toolkit/components/places/PlacesTransactions.jsm index f0c7469648ca..55bb9e4fadd5 100644 --- a/toolkit/components/places/PlacesTransactions.jsm +++ b/toolkit/components/places/PlacesTransactions.jsm @@ -1188,7 +1188,7 @@ PT.RemoveItem.prototype = { for (let item of itemsToRestoreOnUndo) { let parentId = yield PlacesUtils.promiseItemId(item.parentGUID); let index = "index" in item ? - index : PlacesUtils.bookmarks.DEFAULT_INDEX; + item.index : PlacesUtils.bookmarks.DEFAULT_INDEX; let itemId; if (item.itemType == bms.TYPE_SEPARATOR) { itemId = bms.insertSeparator(parentId, index, item.GUID); diff --git a/toolkit/devtools/LayoutHelpers.jsm b/toolkit/devtools/LayoutHelpers.jsm index f01f71f55735..8becefd7a10f 100644 --- a/toolkit/devtools/LayoutHelpers.jsm +++ b/toolkit/devtools/LayoutHelpers.jsm @@ -467,7 +467,7 @@ LayoutHelpers.prototype = { } // Also take scrolled containers into account - let el = node; + el = node; while (el && el.parentNode) { if (el.scrollTop) { offsetTop -= el.scrollTop; diff --git a/toolkit/devtools/client/dbg-client.jsm b/toolkit/devtools/client/dbg-client.jsm index 6812b4722549..cf9955807b20 100644 --- a/toolkit/devtools/client/dbg-client.jsm +++ b/toolkit/devtools/client/dbg-client.jsm @@ -790,7 +790,7 @@ DebuggerClient.prototype = { throw Error("'" + request.type + "' bulk packet has no length."); } - let request = new Request(request); + request = new Request(request); request.format = "bulk"; this._pendingRequests.push(request); diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index 4b4e1945d43b..9522020664be 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -1480,7 +1480,7 @@ ThreadActor.prototype = { */ // Find all innermost scripts matching the given location - let scripts = this.dbg.findScripts({ + scripts = this.dbg.findScripts({ url: aLocation.url, line: aLocation.line, innermost: true @@ -2466,14 +2466,15 @@ PauseScopedActor.prototype = { * resolved nsIURI */ function resolveURIToLocalPath(aURI) { + let resolved; switch (aURI.scheme) { case "jar": case "file": return aURI; case "chrome": - let resolved = Cc["@mozilla.org/chrome/chrome-registry;1"]. - getService(Ci.nsIChromeRegistry).convertChromeURL(aURI); + resolved = Cc["@mozilla.org/chrome/chrome-registry;1"]. + getService(Ci.nsIChromeRegistry).convertChromeURL(aURI); return resolveURIToLocalPath(resolved); case "resource": @@ -4620,9 +4621,10 @@ EnvironmentActor.prototype = { } let value = this.obj.getVariable(name); - // The slot is optimized out or arguments on a dead scope. + // The slot is optimized out, arguments on a dead scope, or an + // uninitialized binding. // FIXME: Need actual UI, bug 941287. - if (value && (value.optimizedOut || value.missingArguments)) { + if (value && (value.optimizedOut || value.missingArguments || value.uninitialized)) { continue; } diff --git a/toolkit/devtools/server/main.js b/toolkit/devtools/server/main.js index 8303d0986935..ab38e4d5a61c 100644 --- a/toolkit/devtools/server/main.js +++ b/toolkit/devtools/server/main.js @@ -17,13 +17,9 @@ let { DebuggerTransport, LocalDebuggerTransport, ChildDebuggerTransport } = require("devtools/toolkit/transport/transport"); let DevToolsUtils = require("devtools/toolkit/DevToolsUtils"); let { dumpn, dumpv, dbg_assert } = DevToolsUtils; -let Services = require("Services"); let EventEmitter = require("devtools/toolkit/event-emitter"); let Debugger = require("Debugger"); -// Until all Debugger server code is converted to SDK modules, -// imports Components.* alias from chrome module. -var { Ci, Cc, CC, Cu, Cr } = require("chrome"); // On B2G, `this` != Global scope, so `Ci` won't be binded on `this` // (i.e. this.Ci is undefined) Then later, when using loadSubScript, // Ci,... won't be defined for sub scripts. diff --git a/toolkit/mozapps/extensions/internal/AddonRepository.jsm b/toolkit/mozapps/extensions/internal/AddonRepository.jsm index f9dfcdbd6681..00f2c733be86 100644 --- a/toolkit/mozapps/extensions/internal/AddonRepository.jsm +++ b/toolkit/mozapps/extensions/internal/AddonRepository.jsm @@ -624,7 +624,7 @@ this.AddonRepository = { AddonManager.getAllAddons(resolve)); // Filter the hotfix out of our list of add-ons - let allAddons = [a for (a of allAddons) if (a.id != AddonManager.hotfixID)]; + allAddons = [a for (a of allAddons) if (a.id != AddonManager.hotfixID)]; // Completely remove cache if caching is not enabled if (!this.cacheEnabled) { @@ -1327,7 +1327,6 @@ this.AddonRepository = { } // Create an AddonInstall for each result - let self = this; results.forEach(function(aResult) { let addon = aResult.addon; let callback = function addonInstallCallback(aInstall) { From 59ccd2fecbeb2024b1e9a5ec77b25dcf057ca1f7 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 15 Sep 2014 16:30:47 -0700 Subject: [PATCH 21/32] Bug 1001090 - Part 5: Fix errors in tests throughout the tree. (r=robcee,gavin) --- .../browser_bug1003461-switchtab-override.js | 2 +- ...wser_urlbarSearchSingleWordNotification.js | 2 +- .../test/newtab/browser_newtab_enhanced.js | 6 +-- .../test/plugins/browser_pageInfo_plugins.js | 2 +- .../browser_884402_customize_from_overflow.js | 2 +- ...rowser_886323_buildArea_removable_nodes.js | 2 +- .../browser_888817_currentset_updating.js | 2 +- .../test/browser_901207_searchbar_in_panel.js | 2 +- .../browser_952963_areaType_getter_no_area.js | 2 +- .../browser_962884_opt_in_disable_hyphens.js | 6 +-- .../test/browser_987492_window_api.js | 2 +- .../test/browser_987640_charEncoding.js | 2 +- .../browser_bootstrapped_custom_toolbar.js | 4 +- .../test/mochitest/browser_CardDavImporter.js | 6 +-- .../test/mochitest/browser_LoopContacts.js | 4 +- .../places/tests/unit/test_421483.js | 2 +- .../tests/browser_chunk_permissions.js | 4 +- ..._privatebrowsing_DownloadLastDirWithCPS.js | 4 +- .../components/search/test/browser_426329.js | 2 +- .../sessionstore/test/browser_463205.js | 2 +- .../sessionstore/test/browser_662743.js | 2 +- .../sessionstore/test/browser_attributes.js | 4 +- .../sessionstore/test/browser_broadcast.js | 4 +- .../test/browser_dynamic_frames.js | 2 +- .../sessionstore/test/browser_formdata.js | 14 +++--- .../test/browser_label_and_icon.js | 2 +- .../sessionstore/test/browser_privatetabs.js | 6 +-- .../test/browser_sessionHistory.js | 14 +++--- .../test/browser_sessionStorage.js | 18 +++---- .../tabview/test/browser_tabview_bug631752.js | 2 +- .../test/unit/test_healthreport.js | 4 +- .../test/browser_canvas-actor-test-10.js | 2 +- .../browser_canvas-frontend-call-search.js | 2 +- .../test/browser_canvas-frontend-slider-02.js | 16 +++--- ...browser_canvas-frontend-snapshot-select.js | 2 +- .../test/browser_cmd_csscoverage_util.js | 2 +- .../test/browser_dbg_break-on-dom-04.js | 2 +- .../test/browser_dbg_break-on-dom-05.js | 6 +-- .../test/browser_dbg_break-on-dom-06.js | 2 +- .../debugger/test/browser_dbg_cmd-blackbox.js | 10 ++-- .../browser_dbg_controller-evaluate-01.js | 2 +- .../debugger/test/browser_dbg_file-reload.js | 2 +- .../test/browser_dbg_optimized-out-vars.js | 2 +- .../test/browser_dbg_paused-keybindings.js | 2 +- .../test/browser_dbg_pretty-print-05.js | 3 +- .../test/browser_dbg_pretty-print-06.js | 3 +- .../test/browser_dbg_variables-view-data.js | 2 +- .../browser_dbg_variables-view-override-01.js | 12 ++--- .../browser_dbg_variables-view-popup-10.js | 2 +- .../browser_dbg_variables-view-popup-11.js | 12 ++--- .../browser_dbg_variables-view-popup-12.js | 12 ++--- .../browser_toolbox_theme_registration.js | 4 +- ...r_inspector_breadcrumbs_highlight_hover.js | 6 +-- .../test/browser_inspector_highlighter-02.js | 2 +- .../browser_markupview_highlight_hover_03.js | 4 +- .../test/browser_markupview_tag_edit_03.js | 4 +- .../test/browser_net_post-data-03.js | 4 +- .../browser_profiler_data-massaging-01.js | 2 +- .../browser_profiler_jump-to-debugger-02.js | 2 +- .../browser_profiler_shared-connection-03.js | 2 +- .../test/browser_profiler_tree-abstract-01.js | 4 +- .../test/browser_profiler_tree-view-06.js | 2 +- .../browser_projecteditor_contextmenu_01.js | 6 +-- .../browser_projecteditor_editors_image.js | 4 +- .../browser_projecteditor_external_change.js | 4 +- .../test/browser_projecteditor_menubar_01.js | 6 +-- .../test/browser_responsiveui.js | 8 +-- .../test/browser_se_shaders-edit-02.js | 6 +-- .../test/browser_webgl-actor-test-07.js | 10 ++-- .../test/browser_webgl-actor-test-14.js | 6 +-- .../test/browser_webgl-actor-test-16.js | 18 +++---- .../test/browser_webgl-actor-test-18.js | 2 +- .../shared/test/browser_cubic-bezier-02.js | 32 ++++++------ .../shared/test/browser_cubic-bezier-03.js | 4 +- .../test/browser_layoutHelpers-getBoxQuads.js | 2 +- .../shared/test/browser_outputparser.js | 2 +- .../shared/test/browser_tableWidget_basic.js | 8 +-- ...rowser_tableWidget_keyboard_interaction.js | 10 ++-- .../browser_tableWidget_mouse_interaction.js | 50 +++++++++---------- ...browser_treeWidget_keyboard_interaction.js | 10 ++-- .../browser_treeWidget_mouse_interaction.js | 2 +- .../shared/test/unit/test_bezierCanvas.js | 8 +-- .../shared/test/unit/test_cubicBezier.js | 4 +- .../test/browser_styleeditor_cmd_edit.js | 2 +- .../test/browser_styleeditor_new.js | 2 +- .../browser_computedview_keybindings_02.js | 2 +- ...browser_ruleview_add-property-cancel_02.js | 6 +-- .../test/browser_ruleview_add-property_01.js | 2 +- ...leview_colorpicker-and-image-tooltip_01.js | 2 +- ...leview_colorpicker-and-image-tooltip_02.js | 4 +- .../test/browser_ruleview_edit-property_01.js | 2 +- .../test/browser_ruleview_edit-property_02.js | 6 +-- .../test/browser_ruleview_keybindings.js | 6 +-- .../test/browser_ruleview_pseudo-element.js | 2 +- ...ruleview_refresh-on-attribute-change_01.js | 2 +- ...rowser_ruleview_refresh-on-style-change.js | 2 +- ...rowser_ruleview_selector-highlighter_02.js | 4 +- .../test/browser_ruleview_urls-clickable.js | 2 +- .../browser_ruleview_user-agent-styles.js | 16 +++--- ...einspector_csslogic-content-stylesheets.js | 4 +- ...styleinspector_tooltip-background-image.js | 2 +- ...spector_tooltip-closes-on-new-selection.js | 2 +- ...leinspector_tooltip-longhand-fontfamily.js | 2 +- ...styleinspector_transform-highlighter-01.js | 6 +-- ...styleinspector_transform-highlighter-02.js | 10 ++-- ...styleinspector_transform-highlighter-03.js | 6 +-- ...styleinspector_transform-highlighter-04.js | 4 +- .../browser_audionode-actor-get-set-param.js | 6 +-- .../test/browser_wa_reset-01.js | 4 +- .../test/browser_wa_reset-02.js | 4 +- .../test/browser_wa_reset-03.js | 4 +- .../test/browser_wa_reset-04.js | 2 +- .../browser_webaudio-actor-connect-param.js | 2 +- .../browser_webaudio-actor-destroy-node.js | 2 +- .../test/browser_webaudio-actor-simple.js | 2 +- ...rowser_webconsole_bug_586388_select_all.js | 2 +- .../test/browser_webconsole_network_panel.js | 2 +- .../test/browser_webconsole_split.js | 6 +-- .../test/browser_webconsole_split_focus.js | 4 +- .../test/browser_webconsole_split_persist.js | 8 +-- browser/devtools/webconsole/test/head.js | 12 ++--- browser/devtools/webide/test/test_newapp.html | 2 +- .../test/xpcshell/test_activate.js | 4 +- browser/experiments/test/xpcshell/test_api.js | 4 +- browser/modules/test/browser_ContentSearch.js | 2 +- browser/modules/test/browser_UITour2.js | 2 +- caps/tests/mochitest/test_disableScript.xul | 2 +- .../marionette/test_cellbroadcast_gsm.js | 4 +- .../marionette/test_cellbroadcast_umts.js | 4 +- ...rror_events_abort_transactions_iframe.html | 18 +++---- .../test/exceptions_in_events_iframe.html | 14 +++--- dom/indexedDB/test/test_blob_simple.html | 8 +-- .../test/test_file_transaction_abort.html | 4 +- .../test/test_filehandle_store_snapshot.html | 2 +- dom/indexedDB/test/test_persistenceType.html | 2 +- .../test/unit/test_autoIncrement_indexes.js | 2 +- .../test/unit/test_complex_keyPaths.js | 2 +- .../test_create_index_with_integer_keys.js | 4 +- .../test/unit/test_create_objectStore.js | 1 - .../test/unit/test_deleteDatabase.js | 10 ++-- .../unit/test_deleteDatabase_interactions.js | 2 +- .../test/unit/test_index_empty_keyPath.js | 12 ++--- dom/indexedDB/test/unit/test_indexes.js | 4 +- dom/indexedDB/test/unit/test_multientry.js | 1 - dom/indexedDB/test/unit/test_names_sorted.js | 10 ++-- .../unit/test_objectStore_openKeyCursor.js | 4 +- .../test/unit/test_open_for_principal.js | 2 +- .../unit/test_overlapping_transactions.js | 2 +- .../test/unit/test_persistenceType.js | 2 +- .../test/unit/test_remove_objectStore.js | 12 ++--- .../test/unit/test_temporary_storage.js | 2 +- .../test/unit/test_transaction_error.js | 2 +- .../test/unit/test_transaction_ordering.js | 4 +- .../gonk/tests/test_ril_worker_sms_cdma.js | 2 +- dom/system/gonk/tests/test_ril_worker_stk.js | 2 +- .../tests/marionette/test_proximity_init.js | 2 +- .../mochitest/chrome/queryCaretRectUnix.html | 2 +- .../mochitest/chrome/queryCaretRectWin.html | 2 +- dom/tests/mochitest/chrome/selectAtPoint.html | 26 +++++----- .../postMessage_structured_clone_helper.js | 6 +-- dom/wappush/tests/test_si_pdu_helper.js | 12 ++--- dom/wappush/tests/test_sl_pdu_helper.js | 8 +-- .../test_multi_sharedWorker_lifetimes.html | 8 +-- dom/xbl/test/test_bug591198.html | 2 +- .../test/unit/test_cookies_async_failure.js | 2 +- .../cookie/test/unit/test_domain_eviction.js | 2 +- .../test/unit/test_schema_2_migration.js | 2 +- .../test/unit/test_schema_3_migration.js | 4 +- image/test/unit/test_moz_icon_uri.js | 2 +- .../tests/unit/test_sandbox_metadata.js | 2 +- mobile/android/base/tests/testHomeProvider.js | 2 +- mobile/android/base/tests/testMozPay.js | 2 +- modules/libpref/test/unit/test_libPrefs.js | 12 ++--- .../common/tests/unit/test_storage_server.js | 41 +++++++-------- .../tests/unit/test_storageservice_bso.js | 16 +++--- .../crypto/tests/unit/test_crypto_crypt.js | 2 +- .../crypto/tests/unit/test_utils_httpmac.js | 8 +-- .../tests/xpcshell/test_accounts.js | 6 +-- .../fxaccounts/tests/xpcshell/test_client.js | 4 +- .../tests/xpcshell/test_loginmgr_storage.js | 4 +- .../sync/tests/unit/test_addons_reconciler.js | 2 +- .../sync/tests/unit/test_bookmark_engine.js | 1 - .../sync/tests/unit/test_httpd_sync_server.js | 7 +-- services/sync/tests/unit/test_resource.js | 4 +- .../sync/tests/unit/test_syncengine_sync.js | 12 ++--- services/sync/tests/unit/test_tab_store.js | 16 +++--- storage/test/unit/test_cache_size.js | 2 +- storage/test/unit/test_storage_connection.js | 1 - .../tests/unit/test_contentPrefsCache.js | 2 +- .../tests/xpcshell/test_crash_store.js | 2 +- .../ctypes/tests/chrome/test_ctypes.xul | 2 +- .../ctypes/tests/unit/test_jsctypes.js | 10 ++-- .../test/unit/test_DownloadIntegration.js | 4 +- .../osfile/tests/xpcshell/test_unique.js | 4 +- .../passwordmgr/test/unit/test_storage.js | 2 +- .../test_1017502-bookmarks_foreign_count.js | 2 +- .../test_477583_json-backup-in-future.js | 2 +- .../places/tests/bookmarks/test_bookmarks.js | 16 +++--- .../places/tests/bookmarks/test_keywords.js | 4 +- .../places/tests/browser/browser_bug248970.js | 2 +- .../expiration/test_annos_expire_history.js | 6 +-- .../expiration/test_annos_expire_never.js | 4 +- .../tests/expiration/test_removeAllPages.js | 5 +- .../places/tests/unit/test_385397.js | 18 +++---- .../places/tests/unit/test_399266.js | 6 +-- .../test_PlacesSearchAutocompleteProvider.js | 2 +- .../tests/unit/test_async_transactions.js | 2 +- .../unit/test_broken_folderShortcut_result.js | 6 +-- .../tests/unit/test_preventive_maintenance.js | 2 +- .../prompts/test/test_modal_prompts.html | 4 +- .../satchel/test/unit/test_autocomplete.js | 2 +- .../test/browser/browser_SocialProvider.js | 2 +- .../content/tests/chrome/findbar_window.xul | 2 +- .../content/tests/chrome/test_bug557987.xul | 4 +- .../tests/mochitest/inspector-helpers.js | 4 +- .../test_highlighter-boxmodel_02.html | 2 +- .../test_inspector-mutations-childlist.html | 2 +- .../tests/mochitest/test_styles-applied.html | 4 -- .../tests/mochitest/test_styles-svg.html | 1 - .../server/tests/unit/test_breakpoint-15.js | 6 +-- toolkit/devtools/tests/unit/test_consoleID.js | 2 +- .../modules/tests/browser/browser_Geometry.js | 40 +++++++-------- toolkit/modules/tests/xpcshell/test_Log.js | 18 +++---- toolkit/modules/tests/xpcshell/test_sqlite.js | 2 +- .../test/browser/browser_cancelCompatCheck.js | 26 ++++++---- .../test/browser/browser_experiments.js | 2 +- .../test/browser/browser_openH264.js | 2 +- .../test/xpcshell/test_blocklistchange.js | 18 +++---- .../extensions/test/xpcshell/test_migrate1.js | 4 +- .../test/xpcshell/test_overrideblocklist.js | 4 +- .../unit_aus_update/uiOnlyAllowOneWindow.js | 2 +- .../tests/unit_aus_update/uiSilentPref.js | 2 +- toolkit/profile/test/test_create_profile.xul | 2 +- 233 files changed, 633 insertions(+), 631 deletions(-) diff --git a/browser/base/content/test/general/browser_bug1003461-switchtab-override.js b/browser/base/content/test/general/browser_bug1003461-switchtab-override.js index 4f77a28f40c0..0552afe8b611 100644 --- a/browser/base/content/test/general/browser_bug1003461-switchtab-override.js +++ b/browser/base/content/test/general/browser_bug1003461-switchtab-override.js @@ -42,7 +42,7 @@ add_task(function* test_switchtab_override() { ok(/moz-action:switchtab/.test(gURLBar.value), "switch to tab entry found"); info("Override switch-to-tab"); - let deferred = Promise.defer(); + deferred = Promise.defer(); // In case of failure this would switch tab. let onTabSelect = event => { deferred.reject(new Error("Should have overridden switch to tab")); diff --git a/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js b/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js index 94bb8df5b6e6..2309d4676c04 100644 --- a/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js +++ b/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js @@ -102,7 +102,7 @@ function get_test_function_for_localhost_with_hostname(hostName, isPrivate) { browser.removeTab(tab); // Now try again with the pref set. - let tab = browser.selectedTab = browser.addTab(); + tab = browser.selectedTab = browser.addTab(); // In a private window, the notification should appear again. yield* runURLBarSearchTest(hostName, isPrivate, isPrivate, win); browser.removeTab(tab); diff --git a/browser/base/content/test/newtab/browser_newtab_enhanced.js b/browser/base/content/test/newtab/browser_newtab_enhanced.js index 6380f570b38c..6e48a5772b57 100644 --- a/browser/base/content/test/newtab/browser_newtab_enhanced.js +++ b/browser/base/content/test/newtab/browser_newtab_enhanced.js @@ -49,7 +49,7 @@ function runTests() { // Test with enhanced = true NewTabUtils.allPages.enhanced = true; yield addNewTabPageTab(); - let {type, enhanced, title} = getData(0); + ({type, enhanced, title} = getData(0)); is(type, "organic", "directory link is still organic"); isnot(enhanced, "", "directory link still has enhanced image"); is(title, "title"); @@ -59,7 +59,7 @@ function runTests() { // Test with a pinned link setPinnedLinks("-1"); yield addNewTabPageTab(); - let {type, enhanced, title} = getData(0); + ({type, enhanced, title} = getData(0)); is(type, "enhanced", "pinned history link is enhanced"); isnot(enhanced, "", "pinned history link has enhanced image"); is(title, "title"); @@ -69,7 +69,7 @@ function runTests() { // Test pinned link with enhanced = false NewTabUtils.allPages.enhanced = false; yield addNewTabPageTab(); - let {type, enhanced, title} = getData(0); + ({type, enhanced, title} = getData(0)); isnot(type, "enhanced", "history link is not enhanced"); is(enhanced, "", "history link has no enhanced image"); is(title, "site#-1"); diff --git a/browser/base/content/test/plugins/browser_pageInfo_plugins.js b/browser/base/content/test/plugins/browser_pageInfo_plugins.js index 77a43bb04ee7..80ed7c1635c7 100644 --- a/browser/base/content/test/plugins/browser_pageInfo_plugins.js +++ b/browser/base/content/test/plugins/browser_pageInfo_plugins.js @@ -70,7 +70,7 @@ function testPart1a() { let objLoadingContent = test.QueryInterface(Ci.nsIObjectLoadingContent); ok(!objLoadingContent.activated, "part 1a: Test plugin should not be activated"); let secondtest = gTestBrowser.contentDocument.getElementById("secondtestA"); - let objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent); + objLoadingContent = secondtest.QueryInterface(Ci.nsIObjectLoadingContent); ok(objLoadingContent.activated, "part 1a: Second Test plugin should be activated"); doOnOpenPageInfo(testPart1b); diff --git a/browser/components/customizableui/test/browser_884402_customize_from_overflow.js b/browser/components/customizableui/test/browser_884402_customize_from_overflow.js index e77daa2d2cf6..371e1eb85f50 100644 --- a/browser/components/customizableui/test/browser_884402_customize_from_overflow.js +++ b/browser/components/customizableui/test/browser_884402_customize_from_overflow.js @@ -74,7 +74,7 @@ add_task(function() { yield waitForCondition(() => navbar.hasAttribute("overflowing")); ok(navbar.hasAttribute("overflowing"), "Should have an overflowing toolbar."); - let homeButtonPlacement = CustomizableUI.getPlacementOfWidget("home-button"); + homeButtonPlacement = CustomizableUI.getPlacementOfWidget("home-button"); ok(homeButtonPlacement, "Home button should still have a placement"); is(homeButtonPlacement && homeButtonPlacement.area, "nav-bar", "Home button should be back in the navbar now"); diff --git a/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js index 40dcfd879a3c..b75e04d1ac4e 100644 --- a/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js +++ b/browser/components/customizableui/test/browser_886323_buildArea_removable_nodes.js @@ -34,7 +34,7 @@ add_task(function() { assertAreaPlacements(kLazyAreaId, [], "Placements should no longer include widget."); is(btn.parentNode.id, gNavBar.customizationTarget.id, "Button shouldn't actually have moved as it's not removable"); - let btn = document.getElementById(kButtonId); + btn = document.getElementById(kButtonId); if (btn) btn.remove(); CustomizableUI.removeWidgetFromArea(kButtonId); CustomizableUI.unregisterArea(kLazyAreaId); diff --git a/browser/components/customizableui/test/browser_888817_currentset_updating.js b/browser/components/customizableui/test/browser_888817_currentset_updating.js index fec615145d8e..ef43761023ae 100644 --- a/browser/components/customizableui/test/browser_888817_currentset_updating.js +++ b/browser/components/customizableui/test/browser_888817_currentset_updating.js @@ -12,7 +12,7 @@ add_task(function() { ok(!CustomizableUI.inDefaultState, "Making the bookmarks toolbar visible takes it out of the default state"); let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); - let personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS); + personalbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS); let navbarCurrentset = navbar.getAttribute("currentset") || navbar.currentSet; let personalbarCurrentset = personalbar.getAttribute("currentset") || personalbar.currentSet; diff --git a/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js b/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js index c73c52617d4e..faf56348ad8d 100644 --- a/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js +++ b/browser/components/customizableui/test/browser_901207_searchbar_in_panel.js @@ -89,7 +89,7 @@ add_task(function() { let hiddenPanelPromise = promiseOverflowHidden(window); EventUtils.synthesizeKey("VK_ESCAPE", {}); yield hiddenPanelPromise; - let navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); + navbar = document.getElementById(CustomizableUI.AREA_NAVBAR); window.resizeTo(this.originalWindowWidth, window.outerHeight); yield waitForCondition(() => !navbar.hasAttribute("overflowing")); ok(!navbar.hasAttribute("overflowing"), "Should not have an overflowing toolbar."); diff --git a/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js b/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js index f8c62ca642a5..bf6788b2f9b0 100644 --- a/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js +++ b/browser/components/customizableui/test/browser_952963_areaType_getter_no_area.js @@ -35,7 +35,7 @@ add_task(function() { let spec = {id: kUnregisterAreaTestWidget, type: 'button', removable: true, label: "areaType test", tooltiptext: "areaType test"}; CustomizableUI.createWidget(spec); - let toolbarNode = createToolbarWithPlacements(kToolbarName, [kUnregisterAreaTestWidget]); + toolbarNode = createToolbarWithPlacements(kToolbarName, [kUnregisterAreaTestWidget]); CustomizableUI.unregisterArea(kToolbarName); toolbarNode.remove(); w = CustomizableUI.getWidget(spec.id); diff --git a/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js b/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js index 4be004b9827f..65787b39e942 100644 --- a/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js +++ b/browser/components/customizableui/test/browser_962884_opt_in_disable_hyphens.js @@ -31,7 +31,7 @@ add_task(function() { isnot(characterEncoding.getAttribute("auto-hyphens"), "off", "Hyphens should not be disabled if the ­ character is not present in the label"); multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text"); - let multilineTextCS = getComputedStyle(multilineText); + multilineTextCS = getComputedStyle(multilineText); is(multilineTextCS.MozHyphens, "auto", "-moz-hyphens should be set to auto by default.") hiddenPanelPromise = promisePanelHidden(window); @@ -48,8 +48,8 @@ add_task(function() { gCustomizeMode.addToPanel(characterEncoding); is(characterEncoding.getAttribute("auto-hyphens"), "off", "Hyphens should be disabled if the ­ character is present in the label in customization mode"); - let multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text"); - let multilineTextCS = getComputedStyle(multilineText); + multilineText = document.getAnonymousElementByAttribute(characterEncoding, "class", "toolbarbutton-multiline-text"); + multilineTextCS = getComputedStyle(multilineText); is(multilineTextCS.MozHyphens, "manual", "-moz-hyphens should be set to manual when the ­ character is present in customization mode.") yield endCustomizing(); diff --git a/browser/components/customizableui/test/browser_987492_window_api.js b/browser/components/customizableui/test/browser_987492_window_api.js index 3f6581416ac2..1718303e1468 100644 --- a/browser/components/customizableui/test/browser_987492_window_api.js +++ b/browser/components/customizableui/test/browser_987492_window_api.js @@ -45,7 +45,7 @@ add_task(function* testOpenCloseWindow() { is(newWindow, closedWindow, "Closed window should match previously opened window"); CustomizableUI.removeListener(closeListener); - let windows = []; + windows = []; for (let win of CustomizableUI.windows) windows.push(win); is(windows.length, 1, "Should have one customizable window"); diff --git a/browser/components/customizableui/test/browser_987640_charEncoding.js b/browser/components/customizableui/test/browser_987640_charEncoding.js index 9db0e08c21b2..5c78abfeb1fa 100644 --- a/browser/components/customizableui/test/browser_987640_charEncoding.js +++ b/browser/components/customizableui/test/browser_987640_charEncoding.js @@ -48,7 +48,7 @@ add_task(function() { yield tabLoadPromise; yield PanelUI.show(); charEncodingButton.click(); - let checkedButtons = characterEncodingView.querySelectorAll("toolbarbutton[checked='true']"); + checkedButtons = characterEncodingView.querySelectorAll("toolbarbutton[checked='true']"); is(checkedButtons[0].getAttribute("label"), "Unicode", "The encoding was reset to Unicode"); }); diff --git a/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js b/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js index b565ac6194e1..af4316b13439 100644 --- a/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js +++ b/browser/components/customizableui/test/browser_bootstrapped_custom_toolbar.js @@ -50,13 +50,13 @@ function checkRestoredPresence(aWidgetID, aLegacy) { CustomizableUI.unregisterArea(testBar.id); testBar.remove(); - let placement = CustomizableUI.getPlacementOfWidget(aWidgetID); + placement = CustomizableUI.getPlacementOfWidget(aWidgetID); is(placement, null, "Expected " + aWidgetID + " to be in the palette"); testBar = createTestBar(aLegacy); yield startCustomizing(); - let placement = CustomizableUI.getPlacementOfWidget(aWidgetID); + placement = CustomizableUI.getPlacementOfWidget(aWidgetID); is(placement.area, kTestBarID, "Expected " + aWidgetID + " to be in the test toolbar"); yield endCustomizing(); diff --git a/browser/components/loop/test/mochitest/browser_CardDavImporter.js b/browser/components/loop/test/mochitest/browser_CardDavImporter.js index 4913ecb27991..ac6b2cd77896 100644 --- a/browser/components/loop/test/mochitest/browser_CardDavImporter.js +++ b/browser/components/loop/test/mochitest/browser_CardDavImporter.js @@ -327,7 +327,7 @@ add_task(function* test_CardDavImport() { }); Assert.equal(error.message, "401 Auth Failure", "Auth error should propagate"); - let error = yield new Promise ((resolve, reject) => { + error = yield new Promise ((resolve, reject) => { info("Initiating import"); importer.startImport({ "host": "example.invalid", @@ -342,7 +342,7 @@ add_task(function* test_CardDavImport() { mockDb.getByServiceId = function(serviceId, callback) { callback(new Error("getByServiceId failed")); }; - let error = yield new Promise ((resolve, reject) => { + error = yield new Promise ((resolve, reject) => { info("Initiating import"); importer.startImport({ "host": "example.com", @@ -354,7 +354,7 @@ add_task(function* test_CardDavImport() { Assert.equal(error.message, "getByServiceId failed", "Database error should propagate"); mockDb.getByServiceId = tmp; - let error = yield new Promise ((resolve, reject) => { + error = yield new Promise ((resolve, reject) => { info("Initiating import"); importer.startImport({ "host": "example.com", diff --git a/browser/components/loop/test/mochitest/browser_LoopContacts.js b/browser/components/loop/test/mochitest/browser_LoopContacts.js index 07901a68ad13..7e52b80aeba8 100644 --- a/browser/components/loop/test/mochitest/browser_LoopContacts.js +++ b/browser/components/loop/test/mochitest/browser_LoopContacts.js @@ -193,7 +193,7 @@ add_task(function* () { yield deferred.promise; info("Get a single contact by id."); - let deferred = Promise.defer(); + deferred = Promise.defer(); LoopContacts.getByServiceId(2, (err, contact) => { Assert.ok(!err, "There shouldn't be an error"); compareContacts(contact, kContacts[1]); @@ -202,7 +202,7 @@ add_task(function* () { yield deferred.promise; info("Get a couple of contacts."); - let deferred = Promise.defer(); + deferred = Promise.defer(); let toRetrieve = [contacts[0], contacts[2], contacts[3]]; LoopContacts.getMany(toRetrieve.map(contact => contact._guid), (err, result) => { Assert.ok(!err, "There shouldn't be an error"); diff --git a/browser/components/places/tests/unit/test_421483.js b/browser/components/places/tests/unit/test_421483.js index ac0c733679c4..2f3a4e7b7a9b 100644 --- a/browser/components/places/tests/unit/test_421483.js +++ b/browser/components/places/tests/unit/test_421483.js @@ -46,7 +46,7 @@ add_task(function remove_smart_bookmark_and_restore() { PlacesUtils.bookmarks.removeItem(smartBookmarkItemIds[0]); Services.prefs.setIntPref("browser.places.smartBookmarksVersion", 0); gluesvc.ensurePlacesDefaultQueriesInitialized(); - let smartBookmarkItemIds = + smartBookmarkItemIds = PlacesUtils.annotations.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO); do_check_eq(smartBookmarkItemIds.length, smartBookmarksCount); do_log_info("check that pref has been bumped up"); diff --git a/browser/components/preferences/tests/browser_chunk_permissions.js b/browser/components/preferences/tests/browser_chunk_permissions.js index 4bd387229c51..cdc9deff557b 100644 --- a/browser/components/preferences/tests/browser_chunk_permissions.js +++ b/browser/components/preferences/tests/browser_chunk_permissions.js @@ -121,11 +121,11 @@ var tests = [ }, run: function() { let testSite1 = getSiteItem(TEST_URI_1.host); - ok(!testSite2, "test site 1 was not removed from sites list"); + ok(testSite1, "test site 1 was not removed from sites list"); let testSite2 = getSiteItem(TEST_URI_2.host); ok(!testSite2, "test site 2 was pre-removed from sites list"); let testSite3 = getSiteItem(TEST_URI_3.host); - ok(!testSite2, "test site 3 was not removed from sites list"); + ok(testSite3, "test site 3 was not removed from sites list"); runNextTest(); } diff --git a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js index 68be197a1b37..d1695e046e9a 100644 --- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js +++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_DownloadLastDirWithCPS.js @@ -238,8 +238,8 @@ function runTest() { // And give it time to close executeSoon(moveAlong); yield; - let pbWin = yield createWindow({private: true}); - let pbDownloadLastDir = new DownloadLastDir(pbWin); + pbWin = yield createWindow({private: true}); + pbDownloadLastDir = new DownloadLastDir(pbWin); is((yield checkDownloadLastDir(pbDownloadLastDir, dir1)).path, dir1.path, "uri1 should return the expected last directory"); diff --git a/browser/components/search/test/browser_426329.js b/browser/components/search/test/browser_426329.js index d73ac2c152b5..01e6470b6477 100644 --- a/browser/components/search/test/browser_426329.js +++ b/browser/components/search/test/browser_426329.js @@ -251,7 +251,7 @@ add_task(function testDropInternalText() { // were merged so that if testDropInternalText failed it wouldn't cause testDropLink // to fail unexplainably. yield prepareTest(); - let promisePreventPopup = promiseEvent(searchBar, "popupshowing", true); + promisePreventPopup = promiseEvent(searchBar, "popupshowing", true); ChromeUtils.synthesizeDrop(searchBar.searchButton, searchBar.searchButton, [[ {type: "text/uri-list", data: "http://www.mozilla.org" } ]], "copy", window); yield promisePreventPopup; is(searchBar.value, "More Text", "drop text/uri-list on searchbar shouldn't change anything"); diff --git a/browser/components/sessionstore/test/browser_463205.js b/browser/components/sessionstore/test/browser_463205.js index a2d6f791db1e..6ff193721e54 100644 --- a/browser/components/sessionstore/test/browser_463205.js +++ b/browser/components/sessionstore/test/browser_463205.js @@ -27,7 +27,7 @@ add_task(function test_check_urls_before_restoring() { ss.setTabState(tab, getState("http://example.com/")); yield promiseTabRestored(tab); - let value = yield getInputValue(browser, {id: "text"}); + value = yield getInputValue(browser, {id: "text"}); is(value, "", "value was not restored"); // Cleanup. diff --git a/browser/components/sessionstore/test/browser_662743.js b/browser/components/sessionstore/test/browser_662743.js index 849a931b7bed..9e34d6c2da35 100644 --- a/browser/components/sessionstore/test/browser_662743.js +++ b/browser/components/sessionstore/test/browser_662743.js @@ -89,7 +89,7 @@ function testTabRestoreData(aFormData, aExpectedValue, aCallback) { let restoredFormData = restoredTabState.formdata; let selectIdFormData = restoredFormData.id.select_id; - let value = restoredFormData.id.select_id.value; + value = restoredFormData.id.select_id.value; // test format ok("id" in restoredFormData || "xpath" in restoredFormData, diff --git a/browser/components/sessionstore/test/browser_attributes.js b/browser/components/sessionstore/test/browser_attributes.js index 2e8e9d01a86f..a87c869b4ad4 100644 --- a/browser/components/sessionstore/test/browser_attributes.js +++ b/browser/components/sessionstore/test/browser_attributes.js @@ -34,7 +34,7 @@ function runTests() { tab.setAttribute("custom", "foobar"); ss.persistTabAttribute("custom"); - let {attributes} = JSON.parse(ss.getTabState(tab)); + ({attributes} = JSON.parse(ss.getTabState(tab))); is(attributes.custom, "foobar", "'custom' attribute is correct"); // Make sure we're backwards compatible and restore old 'image' attributes. @@ -55,7 +55,7 @@ function runTests() { yield whenTabRestored(tab); // Ensure no 'image' or 'pending' attributes are stored. - let {attributes} = JSON.parse(ss.getTabState(tab)); + ({attributes} = JSON.parse(ss.getTabState(tab))); ok(!("image" in attributes), "'image' attribute not saved"); ok(!("pending" in attributes), "'pending' attribute not saved"); is(attributes.custom, "foobaz", "'custom' attribute is correct"); diff --git a/browser/components/sessionstore/test/browser_broadcast.js b/browser/components/sessionstore/test/browser_broadcast.js index f7a9e6975220..752982ecb8a9 100644 --- a/browser/components/sessionstore/test/browser_broadcast.js +++ b/browser/components/sessionstore/test/browser_broadcast.js @@ -59,8 +59,8 @@ add_task(function flush_on_duplicate() { "sessionStorage data has been flushed when duplicating tabs"); yield promiseTabRestored(tab2); - gBrowser.removeTab(tab2) - let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); + gBrowser.removeTab(tab2); + [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); is(storage["http://example.com"].test, "on-duplicate", "sessionStorage data has been flushed when duplicating tabs"); diff --git a/browser/components/sessionstore/test/browser_dynamic_frames.js b/browser/components/sessionstore/test/browser_dynamic_frames.js index 4029be3dd866..8bc42ecd07e5 100644 --- a/browser/components/sessionstore/test/browser_dynamic_frames.js +++ b/browser/components/sessionstore/test/browser_dynamic_frames.js @@ -77,7 +77,7 @@ add_task(function () { yield promiseBrowserLoaded(browser, false /* don't ignore subframes */); SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); // Check URLs. ok(entries[0].url.startsWith("data:text/html"), "correct 1st root url"); diff --git a/browser/components/sessionstore/test/browser_formdata.js b/browser/components/sessionstore/test/browser_formdata.js index f82324f47b9c..77f95aeda990 100644 --- a/browser/components/sessionstore/test/browser_formdata.js +++ b/browser/components/sessionstore/test/browser_formdata.js @@ -43,7 +43,7 @@ add_task(function test_formdata() { Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1); yield createAndRemoveTab(); - let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); + [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); is(formdata.id.txt, OUTER_VALUE, "outer value is correct"); ok(!formdata.children, "inner value was *not* stored"); @@ -51,7 +51,7 @@ add_task(function test_formdata() { Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2); yield createAndRemoveTab(); - let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); + [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); ok(!formdata, "form data has *not* been stored"); // Restore the default privacy level. @@ -176,13 +176,13 @@ add_task(function test_nested() { "formdata for iframe stored correctly"); // Restore the closed tab. - let tab = ss.undoCloseTab(window, 0); - let browser = tab.linkedBrowser; + tab = ss.undoCloseTab(window, 0); + browser = tab.linkedBrowser; yield promiseTabRestored(tab); // Check that the input field has the right value. SyncHandlers.get(browser).flush(); - let {formdata} = JSON.parse(ss.getTabState(tab)); + ({formdata} = JSON.parse(ss.getTabState(tab))); is(JSON.stringify(formdata), JSON.stringify(FORM_DATA), "formdata for iframe restored correctly"); @@ -224,8 +224,8 @@ add_task(function test_design_mode() { yield promiseTabRestored(tab); // Check that the innerHTML value was restored. - let html = yield getInnerHTML(browser); - let expected = "

Mmozilla

"; + html = yield getInnerHTML(browser); + expected = "

Mmozilla

"; is(html, expected, "editable document has been restored correctly"); // Cleanup. diff --git a/browser/components/sessionstore/test/browser_label_and_icon.js b/browser/components/sessionstore/test/browser_label_and_icon.js index e883c4bd1543..d65161dbf078 100644 --- a/browser/components/sessionstore/test/browser_label_and_icon.js +++ b/browser/components/sessionstore/test/browser_label_and_icon.js @@ -31,7 +31,7 @@ add_task(function test_label_and_icon() { browser = null; // Open a new tab to restore into. - let tab = gBrowser.addTab("about:blank"); + tab = gBrowser.addTab("about:blank"); ss.setTabState(tab, state); yield promiseTabRestoring(tab); diff --git a/browser/components/sessionstore/test/browser_privatetabs.js b/browser/components/sessionstore/test/browser_privatetabs.js index 63aaf7408599..d69b205f73cc 100644 --- a/browser/components/sessionstore/test/browser_privatetabs.js +++ b/browser/components/sessionstore/test/browser_privatetabs.js @@ -92,13 +92,13 @@ add_task(function () { is(ss.getClosedTabCount(win), 0, "no tabs to restore"); // Create a new tab in the new window that will load the frame script. - let tab = win.gBrowser.addTab("about:mozilla"); - let browser = tab.linkedBrowser; + tab = win.gBrowser.addTab("about:mozilla"); + browser = tab.linkedBrowser; yield promiseBrowserLoaded(browser); SyncHandlers.get(browser).flush(); // Check that we consider the tab as private. - let state = JSON.parse(ss.getTabState(tab)); + state = JSON.parse(ss.getTabState(tab)); ok(state.isPrivate, "tab considered private"); // Check that all private tabs are removed when the non-private diff --git a/browser/components/sessionstore/test/browser_sessionHistory.js b/browser/components/sessionstore/test/browser_sessionHistory.js index 17b92ec8b8e8..cc7ec9641c88 100644 --- a/browser/components/sessionstore/test/browser_sessionHistory.js +++ b/browser/components/sessionstore/test/browser_sessionHistory.js @@ -52,7 +52,7 @@ add_task(function test_purge() { // Check that we are left with a single shistory entry. SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); is(entries.length, 1, "there is one shistory entry"); // Cleanup. @@ -81,7 +81,7 @@ add_task(function test_hashchange() { // Check that we now have two shistory entries. SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there are two shistory entries"); // Cleanup. @@ -144,7 +144,7 @@ add_task(function test_subframes() { // Check shistory. SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there now are two shistory entries"); is(entries[1].children.length, 1, "the second entry has one child"); @@ -158,7 +158,7 @@ add_task(function test_subframes() { // Check shistory. SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there now are two shistory entries"); is(entries[1].children.length, 1, "the second entry has one child"); @@ -186,7 +186,7 @@ add_task(function test_about_page_navigate() { // Check that we have changed the history entry. SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); is(entries.length, 1, "there is one shistory entry"); is(entries[0].url, "about:robots", "url is correct"); @@ -215,7 +215,7 @@ add_task(function test_pushstate_replacestate() { // Check that we have added the history entry. SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there is another shistory entry"); is(entries[1].url, "http://example.com/test-entry/", "url is correct"); @@ -225,7 +225,7 @@ add_task(function test_pushstate_replacestate() { // Check that we have modified the history entry. SyncHandlers.get(browser).flush(); - let {entries} = JSON.parse(ss.getTabState(tab)); + ({entries} = JSON.parse(ss.getTabState(tab))); is(entries.length, 2, "there is still two shistory entries"); is(entries[1].url, "http://example.com/test-entry/test-entry2/", "url is correct"); diff --git a/browser/components/sessionstore/test/browser_sessionStorage.js b/browser/components/sessionstore/test/browser_sessionStorage.js index 41d6700c3068..c0db92554859 100644 --- a/browser/components/sessionstore/test/browser_sessionStorage.js +++ b/browser/components/sessionstore/test/browser_sessionStorage.js @@ -34,7 +34,7 @@ add_task(function session_storage() { yield modifySessionStorage2(browser, {test: "modified2"}); SyncHandlers.get(browser).flush(); - let {storage} = JSON.parse(ss.getTabState(tab)); + ({storage} = JSON.parse(ss.getTabState(tab))); is(storage["http://example.com"].test, "modified2", "sessionStorage data for example.com has been serialized correctly"); is(storage["http://mochi.test:8888"].test, "modified", @@ -48,7 +48,7 @@ add_task(function session_storage() { // Flush to make sure chrome received all data. SyncHandlers.get(browser2).flush(); - let {storage} = JSON.parse(ss.getTabState(tab2)); + ({storage} = JSON.parse(ss.getTabState(tab2))); is(storage["http://example.com"].test, "modified2", "sessionStorage data for example.com has been duplicated correctly"); is(storage["http://mochi.test:8888"].test, "modified", @@ -59,7 +59,7 @@ add_task(function session_storage() { yield modifySessionStorage(browser2, {test: "modified3"}); SyncHandlers.get(browser2).flush(); - let {storage} = JSON.parse(ss.getTabState(tab2)); + ({storage} = JSON.parse(ss.getTabState(tab2))); is(storage["http://example.com"].test, "modified2", "sessionStorage data for example.com has been duplicated correctly"); is(storage["http://mochi.test:8888"].test, "modified3", @@ -70,7 +70,7 @@ add_task(function session_storage() { yield promiseBrowserLoaded(browser2); SyncHandlers.get(browser2).flush(); - let {storage} = JSON.parse(ss.getTabState(tab2)); + ({storage} = JSON.parse(ss.getTabState(tab2))); is(storage["http://mochi.test:8888"].test, "modified3", "navigating retains correct storage data"); ok(!storage["http://example.com"], "storage data was discarded"); @@ -130,11 +130,11 @@ add_task(function respect_privacy_level() { // Disable saving data for encrypted sites. Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1); - let tab = gBrowser.addTab(URL + "&secure"); + tab = gBrowser.addTab(URL + "&secure"); yield promiseBrowserLoaded(tab.linkedBrowser); gBrowser.removeTab(tab); - let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); + [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); is(storage["http://mochi.test:8888"].test, OUTER_VALUE, "http sessionStorage data has been saved"); ok(!storage["https://example.com"], @@ -144,14 +144,14 @@ add_task(function respect_privacy_level() { Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2); // Check that duplicating a tab copies all private data. - let tab = gBrowser.addTab(URL + "&secure"); + tab = gBrowser.addTab(URL + "&secure"); yield promiseBrowserLoaded(tab.linkedBrowser); let tab2 = gBrowser.duplicateTab(tab); yield promiseTabRestored(tab2); gBrowser.removeTab(tab); // With privacy_level=2 the |tab| shouldn't have any sessionStorage data. - let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); + [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); ok(!storage, "sessionStorage data has *not* been saved"); // Restore the default privacy level and close the duplicated tab. @@ -159,7 +159,7 @@ add_task(function respect_privacy_level() { gBrowser.removeTab(tab2); // With privacy_level=0 the duplicated |tab2| should persist all data. - let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); + [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window)); is(storage["http://mochi.test:8888"].test, OUTER_VALUE, "http sessionStorage data has been saved"); is(storage["https://example.com"].test, INNER_VALUE, diff --git a/browser/components/tabview/test/browser_tabview_bug631752.js b/browser/components/tabview/test/browser_tabview_bug631752.js index 04475cb1b092..3ab7631e26a0 100644 --- a/browser/components/tabview/test/browser_tabview_bug631752.js +++ b/browser/components/tabview/test/browser_tabview_bug631752.js @@ -19,7 +19,7 @@ function test() { let dragTabItem = function (tabItem) { let doc = cw.document.documentElement; - let tabItem = groupItem.getChild(0); + tabItem = groupItem.getChild(0); let container = tabItem.container; let aspectRange = getAspectRange(); diff --git a/browser/components/translation/test/unit/test_healthreport.js b/browser/components/translation/test/unit/test_healthreport.js index c4e7df454cec..ea58c5b6e651 100644 --- a/browser/components/translation/test/unit/test_healthreport.js +++ b/browser/components/translation/test/unit/test_healthreport.js @@ -146,14 +146,14 @@ add_task(function* test_record_translation() { yield provider.recordTranslation("es", "en", 4, now); values = yield m.getValues(); - let day = values.days.getDay(now); + day = values.days.getDay(now); Assert.ok(day.has("pageTranslatedCount")); Assert.equal(day.get("pageTranslatedCount"), 4); Assert.ok(day.has("charactersTranslatedCount")); Assert.equal(day.get("charactersTranslatedCount"), 1007); Assert.ok(day.has("pageTranslatedCountsByLanguage")); - let countsByLanguage = JSON.parse(day.get("pageTranslatedCountsByLanguage")); + countsByLanguage = JSON.parse(day.get("pageTranslatedCountsByLanguage")); Assert.ok("fr" in countsByLanguage); Assert.equal(countsByLanguage["fr"]["total"], 3); Assert.equal(countsByLanguage["fr"]["es"], 2); diff --git a/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js b/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js index bf29eb65960f..a24333d7d32a 100644 --- a/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js +++ b/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js @@ -73,7 +73,7 @@ function ifTestingSupported() { is(new Uint8Array(secondScreenshot.pixels.buffer)[3], 255, "The second screenshot has the correct alpha component."); - let gl = debuggee.gl; + gl = debuggee.gl; is(gl.getParameter(gl.FRAMEBUFFER_BINDING), debuggee.customFramebuffer, "The debuggee's gl context framebuffer still wasn't changed."); is(gl.getParameter(gl.RENDERBUFFER_BINDING), debuggee.customRenderbuffer, diff --git a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-call-search.js b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-call-search.js index c7c3edd1c900..7aff7985f20c 100644 --- a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-call-search.js +++ b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-call-search.js @@ -44,7 +44,7 @@ function ifTestingSupported() { "The visible item's caller has the expected value."); let secondRecordingFinished = once(window, EVENTS.SNAPSHOT_RECORDING_FINISHED); - let callListPopulated = once(window, EVENTS.CALL_LIST_POPULATED); + callListPopulated = once(window, EVENTS.CALL_LIST_POPULATED); SnapshotsListView._onRecordButtonClick(); yield secondRecordingFinished; diff --git a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-slider-02.js b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-slider-02.js index 120149bde291..4565250f5945 100644 --- a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-slider-02.js +++ b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-slider-02.js @@ -34,9 +34,9 @@ function ifTestingSupported() { yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED); ok(true, "The full-sized screenshot was displayed for the item at index 1."); - let thumbnailImageElementSet = waitForMozSetImageElement(window); + thumbnailImageElementSet = waitForMozSetImageElement(window); $("#calls-slider").value = 2; - let thumbnailPixels = yield thumbnailImageElementSet; + thumbnailPixels = yield thumbnailImageElementSet; ok(sameArray(thumbnailPixels, thumbnails[1].pixels), "The screenshot element should have a thumbnail as an immediate background."); @@ -44,9 +44,9 @@ function ifTestingSupported() { yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED); ok(true, "The full-sized screenshot was displayed for the item at index 2."); - let thumbnailImageElementSet = waitForMozSetImageElement(window); + thumbnailImageElementSet = waitForMozSetImageElement(window); $("#calls-slider").value = 7; - let thumbnailPixels = yield thumbnailImageElementSet; + thumbnailPixels = yield thumbnailImageElementSet; ok(sameArray(thumbnailPixels, thumbnails[3].pixels), "The screenshot element should have a thumbnail as an immediate background."); @@ -54,9 +54,9 @@ function ifTestingSupported() { yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED); ok(true, "The full-sized screenshot was displayed for the item at index 7."); - let thumbnailImageElementSet = waitForMozSetImageElement(window); + thumbnailImageElementSet = waitForMozSetImageElement(window); $("#calls-slider").value = 4; - let thumbnailPixels = yield thumbnailImageElementSet; + thumbnailPixels = yield thumbnailImageElementSet; ok(sameArray(thumbnailPixels, thumbnails[2].pixels), "The screenshot element should have a thumbnail as an immediate background."); @@ -64,9 +64,9 @@ function ifTestingSupported() { yield once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED); ok(true, "The full-sized screenshot was displayed for the item at index 4."); - let thumbnailImageElementSet = waitForMozSetImageElement(window); + thumbnailImageElementSet = waitForMozSetImageElement(window); $("#calls-slider").value = 0; - let thumbnailPixels = yield thumbnailImageElementSet; + thumbnailPixels = yield thumbnailImageElementSet; ok(sameArray(thumbnailPixels, thumbnails[0].pixels), "The screenshot element should have a thumbnail as an immediate background."); diff --git a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-snapshot-select.js b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-snapshot-select.js index 462442bf89b3..e6830e9b4c34 100644 --- a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-snapshot-select.js +++ b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-snapshot-select.js @@ -53,7 +53,7 @@ function ifTestingSupported() { "The first draw call should now be selected in the snapshot."); let firstSnapshotTarget = SnapshotsListView.getItemAtIndex(0).target; - let snapshotSelected = waitForSnapshotSelection(); + snapshotSelected = waitForSnapshotSelection(); EventUtils.sendMouseEvent({ type: "mousedown" }, firstSnapshotTarget, window); yield snapshotSelected; diff --git a/browser/devtools/commandline/test/browser_cmd_csscoverage_util.js b/browser/devtools/commandline/test/browser_cmd_csscoverage_util.js index 8accc4e61a32..9f3857c652c1 100644 --- a/browser/devtools/commandline/test/browser_cmd_csscoverage_util.js +++ b/browser/devtools/commandline/test/browser_cmd_csscoverage_util.js @@ -17,7 +17,7 @@ function testDeconstructRuleId() { is(rule.column, 20, "1 column"); // This is the harder case with a URL containing a '|' - let rule = csscoverage.deconstructRuleId("http://thing/blah?q=a|b|11|22"); + rule = csscoverage.deconstructRuleId("http://thing/blah?q=a|b|11|22"); is(rule.url, "http://thing/blah?q=a|b", "2 url"); is(rule.line, 11, "2 line"); is(rule.column, 22, "2 column"); diff --git a/browser/devtools/debugger/test/browser_dbg_break-on-dom-04.js b/browser/devtools/debugger/test/browser_dbg_break-on-dom-04.js index 10a09be92608..af79be02cb71 100644 --- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-04.js +++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-04.js @@ -45,7 +45,7 @@ function test() { testEventGroup("mouseEvents", false); testEventArrays("change,click,keydown,keyup", "change"); - let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); + updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger); yield updated; diff --git a/browser/devtools/debugger/test/browser_dbg_break-on-dom-05.js b/browser/devtools/debugger/test/browser_dbg_break-on-dom-05.js index ff3ba11e77ef..a5b9840b6e2c 100644 --- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-05.js +++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-05.js @@ -46,7 +46,7 @@ function test() { testEventGroup("mouseEvents", false); testEventArrays("change,click,keydown,keyup", "change"); - let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); + updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("interactionEvents"), gDebugger); yield updated; @@ -59,7 +59,7 @@ function test() { testEventGroup("mouseEvents", false); testEventArrays("change,click,keydown,keyup", ""); - let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); + updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger); yield updated; @@ -72,7 +72,7 @@ function test() { testEventGroup("mouseEvents", false); testEventArrays("change,click,keydown,keyup", "keydown,keyup"); - let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); + updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); EventUtils.sendMouseEvent({ type: "click" }, getGroupCheckboxNode("keyboardEvents"), gDebugger); yield updated; diff --git a/browser/devtools/debugger/test/browser_dbg_break-on-dom-06.js b/browser/devtools/debugger/test/browser_dbg_break-on-dom-06.js index 877697584de9..76ba19ff700d 100644 --- a/browser/devtools/debugger/test/browser_dbg_break-on-dom-06.js +++ b/browser/devtools/debugger/test/browser_dbg_break-on-dom-06.js @@ -58,7 +58,7 @@ function test() { testEventGroup("mouseEvents", false); testEventArrays("change,click,keydown,keyup", "change,click,keydown"); - let updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); + updated = waitForDebuggerEvents(aPanel, gDebugger.EVENTS.EVENT_BREAKPOINTS_UPDATED); EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(0), gDebugger); EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(1), gDebugger); EventUtils.sendMouseEvent({ type: "click" }, getItemCheckboxNode(2), gDebugger); diff --git a/browser/devtools/debugger/test/browser_dbg_cmd-blackbox.js b/browser/devtools/debugger/test/browser_dbg_cmd-blackbox.js index a3e2935b415a..797efc1a499a 100644 --- a/browser/devtools/debugger/test/browser_dbg_cmd-blackbox.js +++ b/browser/devtools/debugger/test/browser_dbg_cmd-blackbox.js @@ -42,7 +42,7 @@ function spawnTest() { // test Un-Black-Box Source yield cmd("dbg unblackbox " + BLACKBOXME_URL); - let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); + bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); ok(!bbButton.checked, "Should be able to stop black boxing a specific source."); @@ -50,7 +50,7 @@ function spawnTest() { yield cmd("dbg blackbox --glob *blackboxing_t*.js", 2, [/blackboxing_three\.js/g, /blackboxing_two\.js/g]); - let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); + bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); ok(!bbButton.checked, "blackboxme should not be black boxed because it doesn't match the glob."); bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL); @@ -67,7 +67,7 @@ function spawnTest() { // test Un-Black-Box Glob yield cmd("dbg unblackbox --glob *blackboxing_t*.js", 2); - let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL); + bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTWO_URL); ok(!bbButton.checked, "blackbox_two should be un-black boxed because it matches the glob."); bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXTHREE_URL); @@ -78,7 +78,7 @@ function spawnTest() { yield cmd("dbg blackbox --invert --glob *blackboxing_t*.js", 3, [/blackboxing_three\.js/g, /blackboxing_two\.js/g]); - let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); + bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); ok(bbButton.checked, "blackboxme should be black boxed because it doesn't match the glob."); bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL); @@ -98,7 +98,7 @@ function spawnTest() { // test Un-Black-Box Invert yield cmd("dbg unblackbox --invert --glob *blackboxing_t*.js", 3); - let bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); + bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXME_URL); ok(!bbButton.checked, "blackboxme should be un-black boxed because it does not match the glob."); bbButton = yield selectSourceAndGetBlackBoxButton(panel, BLACKBOXONE_URL); diff --git a/browser/devtools/debugger/test/browser_dbg_controller-evaluate-01.js b/browser/devtools/debugger/test/browser_dbg_controller-evaluate-01.js index f492cbd46c41..b5d69eb65e6d 100644 --- a/browser/devtools/debugger/test/browser_dbg_controller-evaluate-01.js +++ b/browser/devtools/debugger/test/browser_dbg_controller-evaluate-01.js @@ -62,7 +62,7 @@ function test() { ok(true, "Evaluating in the topmost frame works properly."); // Eval in a different frame, while paused. - let updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES); + updatedView = waitForDebuggerEvents(panel, events.FETCHED_SCOPES); try { yield frames.evaluate("foo", { depth: 3 }); // oldest frame } catch (result) { diff --git a/browser/devtools/debugger/test/browser_dbg_file-reload.js b/browser/devtools/debugger/test/browser_dbg_file-reload.js index 45d4c081d98f..9ab0e1f9123f 100644 --- a/browser/devtools/debugger/test/browser_dbg_file-reload.js +++ b/browser/devtools/debugger/test/browser_dbg_file-reload.js @@ -43,7 +43,7 @@ function test() { ok(gEditor.getText().contains("bacon"), "The newly shown source contains bacon. Mmm, delicious!"); - let { source } = gSources.selectedItem.attachment; + ({ source } = gSources.selectedItem.attachment); let [, secondText] = yield gControllerSources.getText(source); let secondNumber = parseFloat(secondText.match(/\d\.\d+/)[0]); diff --git a/browser/devtools/debugger/test/browser_dbg_optimized-out-vars.js b/browser/devtools/debugger/test/browser_dbg_optimized-out-vars.js index e53cacf99a1d..7191a85f7fd6 100644 --- a/browser/devtools/debugger/test/browser_dbg_optimized-out-vars.js +++ b/browser/devtools/debugger/test/browser_dbg_optimized-out-vars.js @@ -6,7 +6,7 @@ function test() { Task.spawn(function* () { const TAB_URL = EXAMPLE_URL + "doc_closure-optimized-out.html"; - let panel, debuggee, gDebugger, sources; + let gDebugger, sources; let [, debuggee, panel] = yield initDebugger(TAB_URL); gDebugger = panel.panelWin; diff --git a/browser/devtools/debugger/test/browser_dbg_paused-keybindings.js b/browser/devtools/debugger/test/browser_dbg_paused-keybindings.js index 603e34b9aec1..8b707bddd4b6 100644 --- a/browser/devtools/debugger/test/browser_dbg_paused-keybindings.js +++ b/browser/devtools/debugger/test/browser_dbg_paused-keybindings.js @@ -7,7 +7,7 @@ function test() { Task.spawn(function* () { const TAB_URL = EXAMPLE_URL + "doc_inline-script.html"; - let panel, debuggee, gDebugger, searchBox; + let gDebugger, searchBox; let [, debuggee, panel] = yield initDebugger(TAB_URL); gDebugger = panel.panelWin; diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js index 0ef9c876ea35..0415ea1e8082 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-05.js @@ -44,7 +44,8 @@ function test() { "The promise was correctly rejected with a meaningful message."); } - let [source, text] = yield gControllerSources.getText(source); + let text; + [source, text] = yield gControllerSources.getText(source); is(gSources.selectedValue, TAB_URL, "The correct source is still selected."); ok(gEditor.getText().contains("myFunction"), diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js index cbf3b01fdaef..dacd4715bad3 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-06.js @@ -60,7 +60,8 @@ function test() { "The promise was correctly rejected with a meaningful message."); } - let [source, text] = yield gControllerSources.getText(source); + let text; + [source, text] = yield gControllerSources.getText(source); is(gSources.selectedValue, JS_URL, "The correct source is still selected."); ok(gEditor.getText().contains("myFunction"), diff --git a/browser/devtools/debugger/test/browser_dbg_variables-view-data.js b/browser/devtools/debugger/test/browser_dbg_variables-view-data.js index 2e68772a21aa..c95d6855de0b 100644 --- a/browser/devtools/debugger/test/browser_dbg_variables-view-data.js +++ b/browser/devtools/debugger/test/browser_dbg_variables-view-data.js @@ -303,7 +303,7 @@ function testSecondLevelContents() { let objectItem6 = someProp6.get("p6"); let objectItem7 = someProp6.get("p7"); let objectItem8 = someProp6.get("p8"); - let __proto__ = someProp6.get("__proto__"); + __proto__ = someProp6.get("__proto__"); is(objectItem0.visible, true, "The first object item visible state is correct."); is(objectItem1.visible, true, "The second object item visible state is correct."); diff --git a/browser/devtools/debugger/test/browser_dbg_variables-view-override-01.js b/browser/devtools/debugger/test/browser_dbg_variables-view-override-01.js index d068594de10d..1e8bf6f726c2 100644 --- a/browser/devtools/debugger/test/browser_dbg_variables-view-override-01.js +++ b/browser/devtools/debugger/test/browser_dbg_variables-view-override-01.js @@ -83,7 +83,7 @@ function test() { // Test getOwnerScopeForVariableOrProperty with second-degree properties. let protoVar1 = argsVar1.get("__proto__"); - let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); + fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); protoVar1.expand(); yield fetched; @@ -98,7 +98,7 @@ function test() { // Only need to wait for a single FETCHED_VARIABLES event, just for the // global scope, because the other local scopes already have the // arguments and variables available as evironment bindings. - let fetched = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES); + fetched = waitForDebuggerEvents(panel, events.FETCHED_VARIABLES); secondScope.expand(); thirdScope.expand(); globalScope.expand(); @@ -118,7 +118,7 @@ function test() { // from non-topmost scopes. let argsVar2 = secondScope.get("arguments"); - let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); + fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); argsVar2.expand(); yield fetched; @@ -128,7 +128,7 @@ function test() { "The getOwnerScopeForVariableOrProperty method works properly (7)."); let argsVar3 = thirdScope.get("arguments"); - let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); + fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); argsVar3.expand(); yield fetched; @@ -141,7 +141,7 @@ function test() { // from non-topmost scopes. let protoVar2 = argsVar2.get("__proto__"); - let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); + fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); protoVar2.expand(); yield fetched; @@ -151,7 +151,7 @@ function test() { "The getOwnerScopeForVariableOrProperty method works properly (9)."); let protoVar3 = argsVar3.get("__proto__"); - let fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); + fetched = waitForDebuggerEvents(panel, events.FETCHED_PROPERTIES); protoVar3.expand(); yield fetched; diff --git a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-10.js b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-10.js index 19d155904064..8e5efe1a3c3b 100644 --- a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-10.js +++ b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-10.js @@ -49,7 +49,7 @@ function test() { } }); - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); yield openVarPopup(panel, { line: 14, ch: 15 }); yield expressionsEvaluated; diff --git a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-11.js b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-11.js index 8aa5f4670d4c..ad357b91cc94 100644 --- a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-11.js +++ b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-11.js @@ -50,25 +50,25 @@ function test() { ok(true, "The new watch expressions were re-evaluated and the panel got hidden (1)."); // Inspect non primitive value variable. - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); yield openVarPopup(panel, { line: 16, ch: 12 }, true); yield expressionsEvaluated; ok(true, "The watch expressions were re-evaluated when a new panel opened (1)."); - let popupHiding = once(tooltip, "popuphiding"); - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + popupHiding = once(tooltip, "popuphiding"); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); testExpressionButton(label, className, "b"); yield promise.all([popupHiding, expressionsEvaluated]); ok(true, "The new watch expressions were re-evaluated and the panel got hidden (2)."); // Inspect property of an object. - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); yield openVarPopup(panel, { line: 17, ch: 10 }); yield expressionsEvaluated; ok(true, "The watch expressions were re-evaluated when a new panel opened (2)."); - let popupHiding = once(tooltip, "popuphiding"); - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + popupHiding = once(tooltip, "popuphiding"); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); testExpressionButton(label, className, "b.a"); yield promise.all([popupHiding, expressionsEvaluated]); ok(true, "The new watch expressions were re-evaluated and the panel got hidden (3)."); diff --git a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-12.js b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-12.js index 79e035d7beb2..6cf3c70a6d52 100644 --- a/browser/devtools/debugger/test/browser_dbg_variables-view-popup-12.js +++ b/browser/devtools/debugger/test/browser_dbg_variables-view-popup-12.js @@ -41,26 +41,26 @@ function test() { ok(true, "The new watch expressions were re-evaluated and the panel got hidden (1)."); // Inspect property of an object. - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); yield openVarPopup(panel, { line: 17, ch: 10 }); yield expressionsEvaluated; ok(true, "The watch expressions were re-evaluated when a new panel opened (1)."); - let popupHiding = once(tooltip, "popuphiding"); - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + popupHiding = once(tooltip, "popuphiding"); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); tooltip.querySelector("button").click(); verifyContent("b.a", 2); yield promise.all([popupHiding, expressionsEvaluated]); ok(true, "The new watch expressions were re-evaluated and the panel got hidden (2)."); // Re-inspect primitive value variable. - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); yield openVarPopup(panel, { line: 15, ch: 12 }); yield expressionsEvaluated; ok(true, "The watch expressions were re-evaluated when a new panel opened (2)."); - let popupHiding = once(tooltip, "popuphiding"); - let expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); + popupHiding = once(tooltip, "popuphiding"); + expressionsEvaluated = waitForDebuggerEvents(panel, events.FETCHED_WATCH_EXPRESSIONS); tooltip.querySelector("button").click(); verifyContent("b.a", 2); yield promise.all([popupHiding, expressionsEvaluated]); diff --git a/browser/devtools/framework/test/browser_toolbox_theme_registration.js b/browser/devtools/framework/test/browser_toolbox_theme_registration.js index 9a065ffcf9fc..5f2681564783 100644 --- a/browser/devtools/framework/test/browser_toolbox_theme_registration.js +++ b/browser/devtools/framework/test/browser_toolbox_theme_registration.js @@ -65,13 +65,13 @@ function applyTheme() // Select test theme. testThemeOption.click(); - let color = panelWin.getComputedStyle(testThemeOption).color; + color = panelWin.getComputedStyle(testThemeOption).color; is(color, "rgb(255, 0, 0)", "style applied"); // Select light theme lightThemeOption.click(); - let color = panelWin.getComputedStyle(testThemeOption).color; + color = panelWin.getComputedStyle(testThemeOption).color; isnot(color, "rgb(255, 0, 0)", "style unapplied"); // Select test theme again. diff --git a/browser/devtools/inspector/test/browser_inspector_breadcrumbs_highlight_hover.js b/browser/devtools/inspector/test/browser_inspector_breadcrumbs_highlight_hover.js index 10affc4caa7b..6fd38ac431de 100644 --- a/browser/devtools/inspector/test/browser_inspector_breadcrumbs_highlight_hover.js +++ b/browser/devtools/inspector/test/browser_inspector_breadcrumbs_highlight_hover.js @@ -21,12 +21,12 @@ let test = asyncTest(function*() { ok(isHighlighting(), "The highlighter is shown on a markup container hover"); is(getHighlitNode(), getNode("body"), "The highlighter highlights the right node"); - let onNodeHighlighted = toolbox.once("node-highlight"); - let button = bcButtons.childNodes[2]; + onNodeHighlighted = toolbox.once("node-highlight"); + button = bcButtons.childNodes[2]; EventUtils.synthesizeMouseAtCenter(button, {type: "mousemove"}, button.ownerDocument.defaultView); yield onNodeHighlighted; ok(isHighlighting(), "The highlighter is shown on a markup container hover"); is(getHighlitNode(), getNode("span"), "The highlighter highlights the right node"); gBrowser.removeCurrentTab(); -}); \ No newline at end of file +}); diff --git a/browser/devtools/inspector/test/browser_inspector_highlighter-02.js b/browser/devtools/inspector/test/browser_inspector_highlighter-02.js index 32f762e077cb..22533a3bdc4d 100644 --- a/browser/devtools/inspector/test/browser_inspector_highlighter-02.js +++ b/browser/devtools/inspector/test/browser_inspector_highlighter-02.js @@ -32,7 +32,7 @@ let test = asyncTest(function*() { info("Selecting the zero width height DIV"); let zeroWidthHeight = getNode("#widthHeightZero-div"); - let onBoxModelUpdate = waitForBoxModelUpdate(); + onBoxModelUpdate = waitForBoxModelUpdate(); yield selectAndHighlightNode(zeroWidthHeight, inspector); yield onBoxModelUpdate; diff --git a/browser/devtools/markupview/test/browser_markupview_highlight_hover_03.js b/browser/devtools/markupview/test/browser_markupview_highlight_hover_03.js index 0c2d3e9d1ac8..d30768c0c3a2 100644 --- a/browser/devtools/markupview/test/browser_markupview_highlight_hover_03.js +++ b/browser/devtools/markupview/test/browser_markupview_highlight_hover_03.js @@ -42,13 +42,13 @@ let test = asyncTest(function*() { let onUpdated = inspector.once("inspector-updated"); EventUtils.synthesizeKey("VK_DOWN", {}); yield onUpdated; - let onUpdated = inspector.once("inspector-updated"); + onUpdated = inspector.once("inspector-updated"); EventUtils.synthesizeKey("VK_DOWN", {}); yield onUpdated; yield isHighlighting("#two", " is highlighted"); info("Navigate back to with the keyboard"); - let onUpdated = inspector.once("inspector-updated"); + onUpdated = inspector.once("inspector-updated"); EventUtils.synthesizeKey("VK_UP", {}); yield onUpdated; yield isHighlighting("#one", " is highlighted again"); diff --git a/browser/devtools/markupview/test/browser_markupview_tag_edit_03.js b/browser/devtools/markupview/test/browser_markupview_tag_edit_03.js index 3ea8637be841..e1a71da8e9f2 100644 --- a/browser/devtools/markupview/test/browser_markupview_tag_edit_03.js +++ b/browser/devtools/markupview/test/browser_markupview_tag_edit_03.js @@ -30,8 +30,8 @@ let test = asyncTest(function*() { yield mutated; info("Checking that the tagname change was done"); - let node = content.document.querySelector("#retag-me"); - let container = yield getContainerForSelector("#retag-me", inspector); + node = content.document.querySelector("#retag-me"); + container = yield getContainerForSelector("#retag-me", inspector); is(node.tagName, "P", "We've got #retag-me, it should now be a P"); ok(container.expanded, "It is still expanded"); ok(container.selected, "It is still selected"); diff --git a/browser/devtools/netmonitor/test/browser_net_post-data-03.js b/browser/devtools/netmonitor/test/browser_net_post-data-03.js index 94ada0e5c52a..620111abed38 100644 --- a/browser/devtools/netmonitor/test/browser_net_post-data-03.js +++ b/browser/devtools/netmonitor/test/browser_net_post-data-03.js @@ -54,8 +54,8 @@ function test() { yield waitFor(aMonitor.panelWin, TAB_UPDATED); - let tab = document.querySelectorAll("#details-pane tab")[2]; - let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2]; + tab = document.querySelectorAll("#details-pane tab")[2]; + tabpanel = document.querySelectorAll("#details-pane tabpanel")[2]; let formDataScope = tabpanel.querySelectorAll(".variables-view-scope")[0]; is(tab.getAttribute("selected"), "true", diff --git a/browser/devtools/profiler/test/browser_profiler_data-massaging-01.js b/browser/devtools/profiler/test/browser_profiler_data-massaging-01.js index dac9da56ef0e..571f9b8c3f94 100644 --- a/browser/devtools/profiler/test/browser_profiler_data-massaging-01.js +++ b/browser/devtools/profiler/test/browser_profiler_data-massaging-01.js @@ -33,7 +33,7 @@ let test = Task.async(function*() { // Perform the second recording... yield front.startRecording(); - let profilingStartTime = front._profilingStartTime; + profilingStartTime = front._profilingStartTime; info("Started profiling at: " + profilingStartTime); busyWait(WAIT_TIME); // allow the profiler module to sample more cpu activity diff --git a/browser/devtools/profiler/test/browser_profiler_jump-to-debugger-02.js b/browser/devtools/profiler/test/browser_profiler_jump-to-debugger-02.js index b156bf433879..7330a680b2b2 100644 --- a/browser/devtools/profiler/test/browser_profiler_jump-to-debugger-02.js +++ b/browser/devtools/profiler/test/browser_profiler_jump-to-debugger-02.js @@ -30,7 +30,7 @@ let test = Task.async(function*() { profilerWin.viewSourceInDebugger(SIMPLE_URL, 14); yield whenSourceShown; - let debuggerPanel = toolbox.getPanel("jsdebugger"); + debuggerPanel = toolbox.getPanel("jsdebugger"); ok(debuggerPanel, "The debugger panel was reselected."); is(DebuggerView.Sources.selectedValue, SIMPLE_URL, diff --git a/browser/devtools/profiler/test/browser_profiler_shared-connection-03.js b/browser/devtools/profiler/test/browser_profiler_shared-connection-03.js index 335db36f9d2d..36aaa5fa50d8 100644 --- a/browser/devtools/profiler/test/browser_profiler_shared-connection-03.js +++ b/browser/devtools/profiler/test/browser_profiler_shared-connection-03.js @@ -18,7 +18,7 @@ let test = Task.async(function*() { ok(nsIProfilerModule.IsActive(), "The built-in profiler module should now be active."); - let result = yield front._request("profiler", "stopProfiler"); + result = yield front._request("profiler", "stopProfiler"); is(result.started, false, "The request finished successfully and the profiler should've been stopped."); ok(!nsIProfilerModule.IsActive(), diff --git a/browser/devtools/profiler/test/browser_profiler_tree-abstract-01.js b/browser/devtools/profiler/test/browser_profiler_tree-abstract-01.js index 591684148998..9ca1523aff20 100644 --- a/browser/devtools/profiler/test/browser_profiler_tree-abstract-01.js +++ b/browser/devtools/profiler/test/browser_profiler_tree-abstract-01.js @@ -90,7 +90,7 @@ let test = Task.async(function*() { let receivedFocusEvent = treeRoot.once("focus"); EventUtils.sendMouseEvent({ type: "mousedown" }, fooItem.target); - let eventItem = yield receivedFocusEvent; + eventItem = yield receivedFocusEvent; is(eventItem, fooItem, "The 'focus' event target is correct."); is(document.commandDispatcher.focusedElement, fooItem.target, @@ -99,7 +99,7 @@ let test = Task.async(function*() { let receivedDblClickEvent = treeRoot.once("focus"); EventUtils.sendMouseEvent({ type: "dblclick" }, barItem.target); - let eventItem = yield receivedDblClickEvent; + eventItem = yield receivedDblClickEvent; is(eventItem, barItem, "The 'dblclick' event target is correct."); is(document.commandDispatcher.focusedElement, barItem.target, diff --git a/browser/devtools/profiler/test/browser_profiler_tree-view-06.js b/browser/devtools/profiler/test/browser_profiler_tree-view-06.js index 6b4b0010dce9..1b3648dabe8b 100644 --- a/browser/devtools/profiler/test/browser_profiler_tree-view-06.js +++ b/browser/devtools/profiler/test/browser_profiler_tree-view-06.js @@ -29,7 +29,7 @@ let test = Task.async(function*() { let receivedZoomEvent = treeRoot.once("zoom"); EventUtils.sendMouseEvent({ type: "mousedown" }, C.target.querySelector(".call-tree-zoom")); - let eventItem = yield receivedZoomEvent; + eventItem = yield receivedZoomEvent; is(eventItem, C, "The 'zoom' event target is correct."); finish(); diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js b/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js index e95f0af22610..45ba13359a08 100644 --- a/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js +++ b/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js @@ -18,10 +18,10 @@ let test = asyncTest(function*() { ok (textEditorContextMenuPopup, "The menu has loaded in the projecteditor document"); let projecteditor2 = yield addProjectEditorTabForTempDirectory(); - let contextMenuPopup = projecteditor2.document.getElementById("context-menu-popup"); - let textEditorContextMenuPopup = projecteditor2.document.getElementById("texteditor-context-popup"); + contextMenuPopup = projecteditor2.document.getElementById("context-menu-popup"); + textEditorContextMenuPopup = projecteditor2.document.getElementById("texteditor-context-popup"); ok (!contextMenuPopup, "The menu has NOT loaded in the projecteditor document"); ok (!textEditorContextMenuPopup, "The menu has NOT loaded in the projecteditor document"); ok (content.document.querySelector("#context-menu-popup"), "The menu has loaded in the specified element"); ok (content.document.querySelector("#texteditor-context-popup"), "The menu has loaded in the specified element"); -}); \ No newline at end of file +}); diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_editors_image.js b/browser/devtools/projecteditor/test/browser_projecteditor_editors_image.js index d9fa43ad38ca..b122932cd156 100644 --- a/browser/devtools/projecteditor/test/browser_projecteditor_editors_image.js +++ b/browser/devtools/projecteditor/test/browser_projecteditor_editors_image.js @@ -58,8 +58,8 @@ function testEditor(projecteditor, filePath) { projecteditor.projectTree.selectResource(resource); yield onceEditorActivated(projecteditor); - let editor = projecteditor.currentEditor; - let images = editor.elt.querySelectorAll("image"); + editor = projecteditor.currentEditor; + images = editor.elt.querySelectorAll("image"); ok (images.length, 1, "There is one image inside the editor"); is (images[0], editor.image, "The image property is set correctly with the DOM"); is (editor.image.getAttribute("src"), resource.uri, "The image has the resource URL"); diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_external_change.js b/browser/devtools/projecteditor/test/browser_projecteditor_external_change.js index 38014c1dd9de..033965cab743 100644 --- a/browser/devtools/projecteditor/test/browser_projecteditor_external_change.js +++ b/browser/devtools/projecteditor/test/browser_projecteditor_external_change.js @@ -50,7 +50,7 @@ function testChangeUnsavedFileExternally(projecteditor, filePath, newData) { projecteditor.projectTree.selectResource(resource); yield onceEditorActivated(projecteditor); - let editor = projecteditor.currentEditor; + editor = projecteditor.currentEditor; info ("Checking to make sure the editor is now populated correctly"); is (editor.editor.getText(), "foobar", "Editor has not been updated with new file contents"); @@ -76,7 +76,7 @@ function testChangeFileExternally(projecteditor, filePath, newData) { projecteditor.projectTree.selectResource(resource); yield onceEditorActivated(projecteditor); - let editor = projecteditor.currentEditor; + editor = projecteditor.currentEditor; info ("Checking to make sure the editor is now populated correctly"); is (editor.editor.getText(), newData, "Editor has been updated with correct file contents"); diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_menubar_01.js b/browser/devtools/projecteditor/test/browser_projecteditor_menubar_01.js index 1a0181a01587..c3fd452c841b 100644 --- a/browser/devtools/projecteditor/test/browser_projecteditor_menubar_01.js +++ b/browser/devtools/projecteditor/test/browser_projecteditor_menubar_01.js @@ -19,10 +19,10 @@ let test = asyncTest(function*() { let projecteditor2 = yield addProjectEditorTabForTempDirectory(); let menubar = projecteditor2.menubar; - let fileMenu = projecteditor2.document.getElementById("file-menu"); - let editMenu = projecteditor2.document.getElementById("edit-menu"); + fileMenu = projecteditor2.document.getElementById("file-menu"); + editMenu = projecteditor2.document.getElementById("edit-menu"); ok (!fileMenu, "The menu has NOT loaded in the projecteditor document"); ok (!editMenu, "The menu has NOT loaded in the projecteditor document"); ok (content.document.querySelector("#file-menu"), "The menu has loaded in the specified element"); ok (content.document.querySelector("#edit-menu"), "The menu has loaded in the specified element"); -}); \ No newline at end of file +}); diff --git a/browser/devtools/responsivedesign/test/browser_responsiveui.js b/browser/devtools/responsivedesign/test/browser_responsiveui.js index 5450df63ec8f..c82117102dd7 100644 --- a/browser/devtools/responsivedesign/test/browser_responsiveui.js +++ b/browser/devtools/responsivedesign/test/browser_responsiveui.js @@ -190,10 +190,10 @@ function test() { is(content.innerWidth, expectedWidth, "Size correctly updated (width)."); is(content.innerHeight, expectedHeight, "Size correctly updated (height)."); is(instance.menulist.selectedIndex, -1, "Custom menuitem cannot be selected"); - let label = instance.menulist.firstChild.firstChild.getAttribute("label"); - let value = instance.menulist.value; - isnot(label, value, "Label from the menulist item is different than the value of the menulist") - let [width, height] = extractSizeFromString(label); + label = instance.menulist.firstChild.firstChild.getAttribute("label"); + value = instance.menulist.value; + isnot(label, value, "Label from the menulist item is different than the value of the menulist"); + [width, height] = extractSizeFromString(label); is(width, expectedWidth, "Label updated (width)."); is(height, expectedHeight, "Label updated (height)."); [width, height] = extractSizeFromString(value); diff --git a/browser/devtools/shadereditor/test/browser_se_shaders-edit-02.js b/browser/devtools/shadereditor/test/browser_se_shaders-edit-02.js index ca6bb3a8014e..aee5d6041de9 100644 --- a/browser/devtools/shadereditor/test/browser_se_shaders-edit-02.js +++ b/browser/devtools/shadereditor/test/browser_se_shaders-edit-02.js @@ -36,7 +36,7 @@ function ifWebGLSupported() { "An assignment error is contained in the linkage status."); fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 }); - let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); ok(error, "The new fragment shader source was compiled with errors."); @@ -53,11 +53,11 @@ function ifWebGLSupported() { yield ensurePixelIs(gFront, { x: 511, y: 511 }, { r: 0, g: 255, b: 0, a: 255 }, true); vsEditor.replaceText("vec4", { line: 7, ch: 22 }, { line: 7, ch: 26 }); - let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); ok(!error, "The new vertex shader source was compiled successfully."); fsEditor.replaceText("vec3", { line: 2, ch: 14 }, { line: 2, ch: 18 }); - let [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); + [, error] = yield onceSpread(panel.panelWin, EVENTS.SHADER_COMPILED); ok(!error, "The new fragment shader source was compiled successfully."); yield ensurePixelIs(gFront, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true); diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-07.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-07.js index ebc68f1e58b1..62f564b002bb 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-07.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-07.js @@ -33,15 +33,15 @@ function ifWebGLSupported() { yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 255 }, true); yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true); - let vertSource = yield vertexShader.getText(); - let fragSource = yield fragmentShader.getText(); + vertSource = yield vertexShader.getText(); + fragSource = yield fragmentShader.getText(); ok(vertSource.contains("2.0"), "The vertex shader source is correct after changing it."); ok(!fragSource.contains("0.5"), "The fragment shader source is correct after changing the vertex shader."); let newFragSource = fragSource.replace("1.0", "0.5"); - let status = yield fragmentShader.compile(newFragSource); + status = yield fragmentShader.compile(newFragSource); ok(!status, "The new fragment shader source was compiled without errors."); @@ -49,8 +49,8 @@ function ifWebGLSupported() { yield ensurePixelIs(front, { x: 128, y: 128 }, { r: 255, g: 0, b: 0, a: 127 }, true); yield ensurePixelIs(front, { x: 511, y: 511 }, { r: 0, g: 0, b: 0, a: 255 }, true); - let vertSource = yield vertexShader.getText(); - let fragSource = yield fragmentShader.getText(); + vertSource = yield vertexShader.getText(); + fragSource = yield fragmentShader.getText(); ok(vertSource.contains("2.0"), "The vertex shader source is correct after changing the fragment shader."); ok(fragSource.contains("0.5"), diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-14.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-14.js index 95ae1e0cb432..9f40ba32859e 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-14.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-14.js @@ -28,9 +28,9 @@ function ifWebGLSupported() { yield ensurePixelIs(front, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2"); ok(true, "The first fragment shader was changed."); - let oldFragSource = yield secondFragmentShader.getText(); - let newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.75, 0.75, 0.75"); - let status = yield secondFragmentShader.compile(newFragSource); + oldFragSource = yield secondFragmentShader.getText(); + newFragSource = oldFragSource.replace("vec4(uColor", "vec4(0.75, 0.75, 0.75"); + status = yield secondFragmentShader.compile(newFragSource); ok(!status, "The second new fragment shader source was compiled without errors."); diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js index 85ebc77f1236..6da8a94cfe21 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-16.js @@ -32,7 +32,7 @@ function ifWebGLSupported() { navigate(target, MULTIPLE_CONTEXTS_URL); let [secondProgram, thirdProgram] = yield getPrograms(front, 2); - let programs = yield front.getPrograms(); + programs = yield front.getPrograms(); is(programs.length, 2, "The second and third programs should be returned by a call to getPrograms()."); is(programs[0], secondProgram, @@ -40,7 +40,7 @@ function ifWebGLSupported() { is(programs[1], thirdProgram, "The third programs was correctly retrieved from the cache."); - let allPrograms = yield front._getAllPrograms(); + allPrograms = yield front._getAllPrograms(); is(allPrograms.length, 3, "Should be three programs in cache."); @@ -53,11 +53,11 @@ function ifWebGLSupported() { reload(target); yield promise.all([programsLinked, globalDestroyed, globalCreated]); - let allPrograms = yield front._getAllPrograms(); + allPrograms = yield front._getAllPrograms(); is(allPrograms.length, 3, "Should be 3 programs total in cache."); - let programs = yield front.getPrograms(); + programs = yield front.getPrograms(); is(programs.length, 1, "There should be 1 cached program actor now."); @@ -68,18 +68,18 @@ function ifWebGLSupported() { yield navigateInHistory(target, "forward"); - let globalDestroyed = once(front, "global-created"); - let globalCreated = once(front, "global-destroyed"); - let programsLinked = getPrograms(front, 2); + globalDestroyed = once(front, "global-created"); + globalCreated = once(front, "global-destroyed"); + programsLinked = getPrograms(front, 2); reload(target); yield promise.all([programsLinked, globalDestroyed, globalCreated]); - let allPrograms = yield front._getAllPrograms(); + allPrograms = yield front._getAllPrograms(); is(allPrograms.length, 3, "Should be 3 programs total in cache."); - let programs = yield front.getPrograms(); + programs = yield front.getPrograms(); is(programs.length, 2, "There should be 2 cached program actors now."); diff --git a/browser/devtools/shadereditor/test/browser_webgl-actor-test-18.js b/browser/devtools/shadereditor/test/browser_webgl-actor-test-18.js index 89b396261653..3d6ff9b18983 100644 --- a/browser/devtools/shadereditor/test/browser_webgl-actor-test-18.js +++ b/browser/devtools/shadereditor/test/browser_webgl-actor-test-18.js @@ -20,7 +20,7 @@ function ifWebGLSupported() { is(pixel.b, 0, "correct `b` value for first canvas.") is(pixel.a, 255, "correct `a` value for first canvas.") - let pixel = yield front.getPixel({ selector: "#canvas2", position: { x: 0, y: 0 }}); + pixel = yield front.getPixel({ selector: "#canvas2", position: { x: 0, y: 0 }}); is(pixel.r, 0, "correct `r` value for second canvas.") is(pixel.g, 255, "correct `g` value for second canvas.") is(pixel.b, 255, "correct `b` value for second canvas.") diff --git a/browser/devtools/shared/test/browser_cubic-bezier-02.js b/browser/devtools/shared/test/browser_cubic-bezier-02.js index 550ec0b6bcce..dc46f835a22d 100644 --- a/browser/devtools/shared/test/browser_cubic-bezier-02.js +++ b/browser/devtools/shared/test/browser_cubic-bezier-02.js @@ -45,7 +45,7 @@ function* pointsCanBeDragged(widget) { is(bezier.P1[1], 1, "The new P1 progress coordinate is correct"); info("Listening for the update event"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); info("Generating a mousedown/move/up on P2"); widget._onPointMouseDown({target: widget.p2}); @@ -54,7 +54,7 @@ function* pointsCanBeDragged(widget) { EventUtils.synthesizeMouse(content.document.documentElement, 200, 300, {type: "mouseup"}, content.window); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P2[0], 1, "The new P2 time coordinate is correct"); is(bezier.P2[1], 0, "The new P2 progress coordinate is correct"); } @@ -76,12 +76,12 @@ function* curveCanBeClicked(widget) { is(bezier.P2[1], 0, "P2 progress coordinate remained unchanged"); info("Listening for the update event"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); info("Click close to P2"); widget._onCurveClick({pageX: 150, pageY: 250}); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P2[0], 0.75, "The new P2 time coordinate is correct"); is(bezier.P2[1], 0.25, "The new P2 progress coordinate is correct"); is(bezier.P1[0], 0.25, "P1 time coordinate remained unchanged"); @@ -99,45 +99,45 @@ function* pointsCanBeMovedWithKeyboard(widget) { is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct"); info("Moving P1 to the left, fast"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); widget._onPointKeyDown(getKeyEvent(widget.p1, 37, true)); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P1[0], 0.085, "The new P1 time coordinate is correct"); is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct"); info("Moving P1 to the right, fast"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); widget._onPointKeyDown(getKeyEvent(widget.p1, 39, true)); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct"); is(bezier.P1[1], 0.75, "The new P1 progress coordinate is correct"); info("Moving P1 to the bottom"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); widget._onPointKeyDown(getKeyEvent(widget.p1, 40)); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct"); is(bezier.P1[1], 0.735, "The new P1 progress coordinate is correct"); info("Moving P1 to the bottom, fast"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); widget._onPointKeyDown(getKeyEvent(widget.p1, 40, true)); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct"); is(bezier.P1[1], 0.585, "The new P1 progress coordinate is correct"); info("Moving P1 to the top, fast"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); widget._onPointKeyDown(getKeyEvent(widget.p1, 38, true)); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P1[0], 0.235, "The new P1 time coordinate is correct"); is(bezier.P1[1], 0.735, "The new P1 progress coordinate is correct"); info("Checking that keyboard events also work with P2"); info("Moving P2 to the left"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); widget._onPointKeyDown(getKeyEvent(widget.p2, 37)); - let bezier = yield onUpdated; + bezier = yield onUpdated; is(bezier.P2[0], 0.735, "The new P2 time coordinate is correct"); is(bezier.P2[1], 0.25, "The new P2 progress coordinate is correct"); } diff --git a/browser/devtools/shared/test/browser_cubic-bezier-03.js b/browser/devtools/shared/test/browser_cubic-bezier-03.js index 8b19f3472764..93d21a0d35e6 100644 --- a/browser/devtools/shared/test/browser_cubic-bezier-03.js +++ b/browser/devtools/shared/test/browser_cubic-bezier-03.js @@ -55,9 +55,9 @@ function* coordinatesCanBeChangedByProvidingAValue(widget) { is(bezier.P2[1], 1, "The new P2 progress coordinate is correct"); info("Setting a custom cubic-bezier css value"); - let onUpdated = widget.once("updated"); + onUpdated = widget.once("updated"); widget.cssCubicBezierValue = "cubic-bezier(.25,-0.5, 1, 1.45)"; - let bezier = yield onUpdated; + bezier = yield onUpdated; ok(true, "The updated event was fired as a result of setting cssValue"); is(bezier.P1[0], .25, "The new P1 time coordinate is correct"); diff --git a/browser/devtools/shared/test/browser_layoutHelpers-getBoxQuads.js b/browser/devtools/shared/test/browser_layoutHelpers-getBoxQuads.js index ed66bccd203f..af5360699b5e 100644 --- a/browser/devtools/shared/test/browser_layoutHelpers-getBoxQuads.js +++ b/browser/devtools/shared/test/browser_layoutHelpers-getBoxQuads.js @@ -171,7 +171,7 @@ function takesScrollingIntoAccount(doc, helper) { scrolledNode.scrollTop = 0; subScrolledNode.scrollTop = 0; - let quad = helper.getAdjustedQuads(innerNode, "content"); + quad = helper.getAdjustedQuads(innerNode, "content"); is(quad.p1.x, 0, "p1.x of the scrolled node is correct after scrolling up"); is(quad.p1.y, 0, "p1.y of the scrolled node is correct after scrolling up"); } diff --git a/browser/devtools/shared/test/browser_outputparser.js b/browser/devtools/shared/test/browser_outputparser.js index eee8f2add334..d49f8b676045 100644 --- a/browser/devtools/shared/test/browser_outputparser.js +++ b/browser/devtools/shared/test/browser_outputparser.js @@ -42,7 +42,7 @@ function testParseCssProperty() { target.innerHTML = ""; - let frag = parser.parseCssProperty("background-image", "linear-gradient(to right, #F60 10%, rgba(0,0,0,1))", { + frag = parser.parseCssProperty("background-image", "linear-gradient(to right, #F60 10%, rgba(0,0,0,1))", { colorSwatchClass: "test-colorswatch", colorClass: "test-color" }); diff --git a/browser/devtools/shared/test/browser_tableWidget_basic.js b/browser/devtools/shared/test/browser_tableWidget_basic.js index 9d9840ec5d23..ba0ac4c8363b 100644 --- a/browser/devtools/shared/test/browser_tableWidget_basic.js +++ b/browser/devtools/shared/test/browser_tableWidget_basic.js @@ -339,12 +339,12 @@ function testAPI() { // Calling it again should sort by it in descending manner table.sortBy("col2"); - let cell = table.tbody.children[2].firstChild.lastChild.previousSibling; + cell = table.tbody.children[2].firstChild.lastChild.previousSibling; checkDescendingOrder(cell); // Calling it again should sort by it in ascending manner table.sortBy("col2"); - let cell = table.tbody.children[2].firstChild.children[2]; + cell = table.tbody.children[2].firstChild.children[2]; checkAscendingOrder(cell); table.clear(); @@ -352,13 +352,13 @@ function testAPI() { // testing if sorting works should sort by ascending manner table.sortBy("col4"); - let cell = table.tbody.children[6].firstChild.children[1]; + cell = table.tbody.children[6].firstChild.children[1]; is(cell.textContent, "domnode", "DOMNode sorted correctly"); checkAscendingOrder(cell.nextSibling); // Calling it again should sort it in descending order table.sortBy("col4"); - let cell = table.tbody.children[6].firstChild.children[9]; + cell = table.tbody.children[6].firstChild.children[9]; is(cell.textContent, "domnode", "DOMNode sorted correctly"); checkDescendingOrder(cell.previousSibling); } diff --git a/browser/devtools/shared/test/browser_tableWidget_keyboard_interaction.js b/browser/devtools/shared/test/browser_tableWidget_keyboard_interaction.js index 04e7ce91a1fa..0ec5355e0295 100644 --- a/browser/devtools/shared/test/browser_tableWidget_keyboard_interaction.js +++ b/browser/devtools/shared/test/browser_tableWidget_keyboard_interaction.js @@ -147,7 +147,7 @@ let testKeyboardInteraction = Task.async(function*() { info("Pressing down key to select next row"); event = table.once(TableWidget.EVENTS.ROW_SELECTED); EventUtils.sendKey("DOWN", doc.defaultView); - let id = yield event; + id = yield event; is(id, "id2", "Correct row was selected after pressing down"); ok(node.classList.contains("theme-selected"), "row has selected class"); let nodes = doc.querySelectorAll(".theme-selected"); @@ -166,7 +166,7 @@ let testKeyboardInteraction = Task.async(function*() { id = yield event; is(id, "id3", "Correct row was selected after pressing down"); ok(node.classList.contains("theme-selected"), "row has selected class"); - let nodes = doc.querySelectorAll(".theme-selected"); + nodes = doc.querySelectorAll(".theme-selected"); for (let i = 0; i < nodes.length; i++) { is(nodes[i].getAttribute("data-id"), "id3", "Correct cell selected in all columns"); @@ -183,7 +183,7 @@ let testKeyboardInteraction = Task.async(function*() { id = yield event; is(id, "id2", "Correct row was selected after pressing down"); ok(node.classList.contains("theme-selected"), "row has selected class"); - let nodes = doc.querySelectorAll(".theme-selected"); + nodes = doc.querySelectorAll(".theme-selected"); for (let i = 0; i < nodes.length; i++) { is(nodes[i].getAttribute("data-id"), "id2", "Correct cell selected in all columns"); @@ -202,7 +202,7 @@ let testKeyboardInteraction = Task.async(function*() { id = yield event; is(id, "id1", "Correct row was selected after pressing down"); ok(node.classList.contains("theme-selected"), "row has selected class"); - let nodes = doc.querySelectorAll(".theme-selected"); + nodes = doc.querySelectorAll(".theme-selected"); for (let i = 0; i < nodes.length; i++) { is(nodes[i].getAttribute("data-id"), "id1", "Correct cell selected in all columns"); @@ -219,7 +219,7 @@ let testKeyboardInteraction = Task.async(function*() { id = yield event; is(id, "id9", "Correct row was selected after pressing down"); ok(node.classList.contains("theme-selected"), "row has selected class"); - let nodes = doc.querySelectorAll(".theme-selected"); + nodes = doc.querySelectorAll(".theme-selected"); for (let i = 0; i < nodes.length; i++) { is(nodes[i].getAttribute("data-id"), "id9", "Correct cell selected in all columns"); diff --git a/browser/devtools/shared/test/browser_tableWidget_mouse_interaction.js b/browser/devtools/shared/test/browser_tableWidget_mouse_interaction.js index 39a03de4cc40..efdc8ee07212 100644 --- a/browser/devtools/shared/test/browser_tableWidget_mouse_interaction.js +++ b/browser/devtools/shared/test/browser_tableWidget_mouse_interaction.js @@ -147,13 +147,13 @@ let testMouseInteraction = Task.async(function*() { is(id, "id1", "Correct row was selected"); info("clicking on third row to select it"); - let event = table.once(TableWidget.EVENTS.ROW_SELECTED); + event = table.once(TableWidget.EVENTS.ROW_SELECTED); let node2 = table.tbody.firstChild.firstChild.children[3]; // node should not have selected class ok(!node2.classList.contains("theme-selected"), "New node should not have selected class before clicking"); click(node2); - let id = yield event; + id = yield event; ok(node2.classList.contains("theme-selected"), "New node has selected class after clicking"); is(id, "id3", "Correct table path is emitted for new node") @@ -162,15 +162,15 @@ let testMouseInteraction = Task.async(function*() { "Old node should not have selected class after the click on new node"); // clicking on table header to sort by it - let event = table.once(TableWidget.EVENTS.COLUMN_SORTED); - let node = table.tbody.children[6].firstChild.children[0]; + event = table.once(TableWidget.EVENTS.COLUMN_SORTED); + node = table.tbody.children[6].firstChild.children[0]; info("clicking on the 4th coulmn header to sort the table by it"); ok(!node.hasAttribute("sorted"), "Node should not have sorted attribute before clicking"); ok(doc.querySelector("[sorted]"), "Although, something else should be sorted on"); isnot(doc.querySelector("[sorted]"), node, "Which is not equal to this node"); click(node); - let id = yield event; + id = yield event; is(id, "col4", "Correct column was sorted on"); ok(node.hasAttribute("sorted"), "Node should now have sorted attribute after clicking"); @@ -181,13 +181,13 @@ let testMouseInteraction = Task.async(function*() { // test context menu opening. // hiding second column // event listener for popupshown - let event = Promise.defer(); + event = Promise.defer(); table.menupopup.addEventListener("popupshown", function onPopupShown(e) { table.menupopup.removeEventListener("popupshown", onPopupShown); event.resolve(); }) info("right clicking on the first column header"); - let node = table.tbody.firstChild.firstChild.firstChild; + node = table.tbody.firstChild.firstChild.firstChild; click(node, 2); yield event.promise; is(table.menupopup.querySelectorAll("[disabled]").length, 1, @@ -197,52 +197,52 @@ let testMouseInteraction = Task.async(function*() { "Which is the unique column"); // popup should be open now // clicking on second column label - let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); - let node = table.menupopup.querySelector("[data-id='col2']"); + event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); + node = table.menupopup.querySelector("[data-id='col2']"); info("selecting to hide the second column"); ok(!table.tbody.children[2].hasAttribute("hidden"), "Column is not hidden before hiding it"); click(node); - let id = yield event; + id = yield event; is(id, "col2", "Correct column was triggered to be hidden"); is(table.tbody.children[2].getAttribute("hidden"), "true", "Column is hidden after hiding it"); // hiding third column // event listener for popupshown - let event = Promise.defer(); + event = Promise.defer(); table.menupopup.addEventListener("popupshown", function onPopupShown(e) { table.menupopup.removeEventListener("popupshown", onPopupShown); event.resolve(); }) info("right clicking on the first column header"); - let node = table.tbody.firstChild.firstChild.firstChild; + node = table.tbody.firstChild.firstChild.firstChild; click(node, 2); yield event.promise; is(table.menupopup.querySelectorAll("[disabled]").length, 1, "Only 1 menuitem is disabled"); // popup should be open now // clicking on second column label - let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); - let node = table.menupopup.querySelector("[data-id='col3']"); + event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); + node = table.menupopup.querySelector("[data-id='col3']"); info("selecting to hide the second column"); ok(!table.tbody.children[4].hasAttribute("hidden"), "Column is not hidden before hiding it"); click(node); - let id = yield event; + id = yield event; is(id, "col3", "Correct column was triggered to be hidden"); is(table.tbody.children[4].getAttribute("hidden"), "true", "Column is hidden after hiding it"); // opening again to see if 2 items are disabled now // event listener for popupshown - let event = Promise.defer(); + event = Promise.defer(); table.menupopup.addEventListener("popupshown", function onPopupShown(e) { table.menupopup.removeEventListener("popupshown", onPopupShown); event.resolve(); }) info("right clicking on the first column header"); - let node = table.tbody.firstChild.firstChild.firstChild; + node = table.tbody.firstChild.firstChild.firstChild; click(node, 2); yield event.promise; is(table.menupopup.querySelectorAll("[disabled]").length, 2, @@ -257,37 +257,37 @@ let testMouseInteraction = Task.async(function*() { // showing back 2nd column // popup should be open now // clicking on second column label - let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); - let node = table.menupopup.querySelector("[data-id='col2']"); + event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); + node = table.menupopup.querySelector("[data-id='col2']"); info("selecting to hide the second column"); is(table.tbody.children[2].getAttribute("hidden"), "true", "Column is hidden before unhiding it"); click(node); - let id = yield event; + id = yield event; is(id, "col2", "Correct column was triggered to be hidden"); ok(!table.tbody.children[2].hasAttribute("hidden"), "Column is not hidden after unhiding it"); // showing back 3rd column // event listener for popupshown - let event = Promise.defer(); + event = Promise.defer(); table.menupopup.addEventListener("popupshown", function onPopupShown(e) { table.menupopup.removeEventListener("popupshown", onPopupShown); event.resolve(); }) info("right clicking on the first column header"); - let node = table.tbody.firstChild.firstChild.firstChild; + node = table.tbody.firstChild.firstChild.firstChild; click(node, 2); yield event.promise; // popup should be open now // clicking on second column label - let event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); - let node = table.menupopup.querySelector("[data-id='col3']"); + event = table.once(TableWidget.EVENTS.HEADER_CONTEXT_MENU); + node = table.menupopup.querySelector("[data-id='col3']"); info("selecting to hide the second column"); is(table.tbody.children[4].getAttribute("hidden"), "true", "Column is hidden before unhiding it"); click(node); - let id = yield event; + id = yield event; is(id, "col3", "Correct column was triggered to be hidden"); ok(!table.tbody.children[4].hasAttribute("hidden"), "Column is not hidden after unhiding it"); diff --git a/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js b/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js index 9668020ca1dc..6a7a5b492d7f 100644 --- a/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js +++ b/browser/devtools/shared/test/browser_treeWidget_keyboard_interaction.js @@ -124,7 +124,7 @@ let testKeyboardInteraction = Task.async(function*() { event = Promise.defer(); tree.once("select", pass); EventUtils.sendKey("DOWN", content); - let [name, data, attachment] = yield event.promise; + [name, data, attachment] = yield event.promise; is(data.length, 2, "Correct level item was selected after second down keypress"); is(data[0], "level1", "Correct parent level"); is(data[1], "level2", "Correct second level"); @@ -133,7 +133,7 @@ let testKeyboardInteraction = Task.async(function*() { event = Promise.defer(); tree.once("select", pass); EventUtils.sendKey("DOWN", content); - let [name, data, attachment] = yield event.promise; + [name, data, attachment] = yield event.promise; is(data.length, 3, "Correct level item was selected after third down keypress"); is(data[0], "level1", "Correct parent level"); is(data[1], "level2", "Correct second level"); @@ -143,7 +143,7 @@ let testKeyboardInteraction = Task.async(function*() { event = Promise.defer(); tree.once("select", pass); EventUtils.sendKey("DOWN", content); - let [name, data, attachment] = yield event.promise; + [name, data, attachment] = yield event.promise; is(data.length, 2, "Correct level item was selected after fourth down keypress"); is(data[0], "level1", "Correct parent level"); is(data[1], "level2-1", "Correct second level"); @@ -173,7 +173,7 @@ let testKeyboardInteraction = Task.async(function*() { node = tree.root.children.firstChild.nextSibling.firstChild; ok(node.hasAttribute("expanded"), "Parent is expanded"); EventUtils.sendKey("LEFT", content); - let [name, data] = yield event.promise; + [name, data] = yield event.promise; is(data.length, 3, "Correct level item was selected after second left keypress"); is(data[0], "level1", "Correct parent level"); is(data[1], "level2", "Correct second level"); @@ -186,7 +186,7 @@ let testKeyboardInteraction = Task.async(function*() { event = Promise.defer(); tree.once("select", pass); EventUtils.sendKey("DOWN", content); - let [name, data, attachment] = yield event.promise; + [name, data, attachment] = yield event.promise; is(data.length, 2, "Correct level item was selected after fifth down keypress"); is(data[0], "level1", "Correct parent level"); is(data[1], "level2-1", "Correct second level"); diff --git a/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js b/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js index ef99dd6ddfec..ca18deb08a1f 100644 --- a/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js +++ b/browser/devtools/shared/test/browser_treeWidget_mouse_interaction.js @@ -123,7 +123,7 @@ let testMouseInteraction = Task.async(function*() { ok(!node2.hasAttribute("expanded"), "New node is not expanded before clicking"); tree.once("select", pass); click(node2); - let [name, data, attachment] = yield event.promise; + [name, data, attachment] = yield event.promise; ok(node2.classList.contains("theme-selected"), "New node has selected class after clicking"); is(data[0], "level1", "Correct tree path is emitted for new node") diff --git a/browser/devtools/shared/test/unit/test_bezierCanvas.js b/browser/devtools/shared/test/unit/test_bezierCanvas.js index fde8f4be49b3..9dd945a22aeb 100644 --- a/browser/devtools/shared/test/unit/test_bezierCanvas.js +++ b/browser/devtools/shared/test/unit/test_bezierCanvas.js @@ -35,8 +35,8 @@ function offsetsGetterReturnsData() { do_print("offsets getter returns data according to current padding"); - let b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [0, 0]); - let offsets = b.offsets; + b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [0, 0]); + offsets = b.offsets; do_check_eq(offsets[0].top, "400px"); do_check_eq(offsets[0].left, "0px"); @@ -57,14 +57,14 @@ function convertsOffsetsToCoordinates() { do_check_eq(coordinates[0], 0); do_check_eq(coordinates[1], 1.5); - let coordinates = b.offsetsToCoordinates({style: { + coordinates = b.offsetsToCoordinates({style: { left: "0px", top: "300px" }}); do_check_eq(coordinates[0], 0); do_check_eq(coordinates[1], 0); - let coordinates = b.offsetsToCoordinates({style: { + coordinates = b.offsetsToCoordinates({style: { left: "200px", top: "100px" }}); diff --git a/browser/devtools/shared/test/unit/test_cubicBezier.js b/browser/devtools/shared/test/unit/test_cubicBezier.js index 1be674384d55..3b2823536824 100644 --- a/browser/devtools/shared/test/unit/test_cubicBezier.js +++ b/browser/devtools/shared/test/unit/test_cubicBezier.js @@ -63,8 +63,8 @@ function coordinatesToStringOutputsAString() { let string = c.coordinates.toString(); do_check_eq(string, "0,1,.5,-2"); - let c = new CubicBezier([1, 1, 1, 1]); - let string = c.coordinates.toString(); + c = new CubicBezier([1, 1, 1, 1]); + string = c.coordinates.toString(); do_check_eq(string, "1,1,1,1"); } diff --git a/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js b/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js index 56c21b09239c..ffd8fdc06b47 100644 --- a/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js +++ b/browser/devtools/styleeditor/test/browser_styleeditor_cmd_edit.js @@ -193,7 +193,7 @@ function spawnTest() { }, ]); - let toolbox = gDevTools.getToolbox(options.target); + toolbox = gDevTools.getToolbox(options.target); ok(toolbox != null, "toolbox is open"); let styleEditor = toolbox.getCurrentPanel(); diff --git a/browser/devtools/styleeditor/test/browser_styleeditor_new.js b/browser/devtools/styleeditor/test/browser_styleeditor_new.js index 238e40acfa95..453dc58f06bb 100644 --- a/browser/devtools/styleeditor/test/browser_styleeditor_new.js +++ b/browser/devtools/styleeditor/test/browser_styleeditor_new.js @@ -73,7 +73,7 @@ function testInitialState(aEditor) { ok(aEditor.sourceEditor.hasFocus(), "new editor has focus"); - let summary = aEditor.summary; + summary = aEditor.summary; let ruleCount = summary.querySelector(".stylesheet-rule-count").textContent; is(parseInt(ruleCount), 0, "new editor initially shows 0 rules"); diff --git a/browser/devtools/styleinspector/test/browser_computedview_keybindings_02.js b/browser/devtools/styleinspector/test/browser_computedview_keybindings_02.js index b3e23fa7a045..60a9dea4d6ce 100644 --- a/browser/devtools/styleinspector/test/browser_computedview_keybindings_02.js +++ b/browser/devtools/styleinspector/test/browser_computedview_keybindings_02.js @@ -50,7 +50,7 @@ let test = asyncTest(function*() { ok(secondStyleSelectors.childNodes.length > 0, "Matched selectors expanded"); info("Tab back up and test the same thing, with space"); - let onExpanded = inspector.once("computed-view-property-expanded"); + onExpanded = inspector.once("computed-view-property-expanded"); EventUtils.synthesizeKey("VK_TAB", {shiftKey: true}); EventUtils.synthesizeKey("VK_SPACE", {}); yield onExpanded; diff --git a/browser/devtools/styleinspector/test/browser_ruleview_add-property-cancel_02.js b/browser/devtools/styleinspector/test/browser_ruleview_add-property-cancel_02.js index 6e7ba61cbd1d..bb7b047caa05 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_add-property-cancel_02.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_add-property-cancel_02.js @@ -45,7 +45,7 @@ let test = asyncTest(function*() { info("Pressing return to commit and focus the new value field"); let onValueFocus = once(elementRuleEditor.element, "focus", true); - let onModifications = elementRuleEditor.rule._applyingModifications; + onModifications = elementRuleEditor.rule._applyingModifications; EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView); yield onValueFocus; yield onModifications; @@ -62,7 +62,7 @@ let test = asyncTest(function*() { editor.input.value = "red"; info("Escaping out of the field"); - let onModifications = elementRuleEditor.rule._applyingModifications; + onModifications = elementRuleEditor.rule._applyingModifications; EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView); yield onModifications; @@ -70,7 +70,7 @@ let test = asyncTest(function*() { let focusedElement = inplaceEditor(elementRuleEditor.rule.textProps[0].editor.valueSpan).input; is(focusedElement, focusedElement.ownerDocument.activeElement, "Correct element has focus"); - let onModifications = elementRuleEditor.rule._applyingModifications; + onModifications = elementRuleEditor.rule._applyingModifications; EventUtils.synthesizeKey("VK_ESCAPE", {}, view.doc.defaultView); yield onModifications; diff --git a/browser/devtools/styleinspector/test/browser_ruleview_add-property_01.js b/browser/devtools/styleinspector/test/browser_ruleview_add-property_01.js index bf4f27337665..009962a37d7e 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_add-property_01.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_add-property_01.js @@ -68,7 +68,7 @@ function* testCreateNew(view) { info("Entering a value and bluring the field to expect a rule change"); editor.input.value = "#XYZ"; let onBlur = once(editor.input, "blur"); - let onModifications = elementRuleEditor.rule._applyingModifications; + onModifications = elementRuleEditor.rule._applyingModifications; editor.input.blur(); yield onBlur; yield onModifications; diff --git a/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js b/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js index 05ed35995f80..f1995bceff05 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_01.js @@ -54,7 +54,7 @@ function* testImageTooltipAfterColorChange(swatch, url, ruleView) { // After a color change, the property is re-populated, we need to get the new // dom node url = getRuleViewProperty(ruleView, "body", "background").valueSpan.querySelector(".theme-link"); - let anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url); + anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url); ok(anchor, "The image preview tooltip is shown on the url span"); is(anchor, url, "The anchor returned by the showOnHover callback is correct"); } diff --git a/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js b/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js index 5ada0738a14d..28bd8729cad9 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_colorpicker-and-image-tooltip_02.js @@ -49,13 +49,13 @@ function* testColorChangeIsntRevertedWhenOtherTooltipIsShown(ruleView) { info("Open the image preview tooltip"); let value = getRuleViewProperty(ruleView, "body", "background").valueSpan; let url = value.querySelector(".theme-link"); - let onShown = ruleView.tooltips.previewTooltip.once("shown"); + onShown = ruleView.tooltips.previewTooltip.once("shown"); let anchor = yield isHoverTooltipTarget(ruleView.tooltips.previewTooltip, url); ruleView.tooltips.previewTooltip.show(anchor); yield onShown; info("Image tooltip is shown, verify that the swatch is still correct"); - let swatch = value.querySelector(".ruleview-colorswatch"); + swatch = value.querySelector(".ruleview-colorswatch"); is(swatch.style.backgroundColor, "rgb(0, 0, 0)", "The swatch's color is correct"); is(swatch.nextSibling.textContent, "#000", "The color name is correct"); } diff --git a/browser/devtools/styleinspector/test/browser_ruleview_edit-property_01.js b/browser/devtools/styleinspector/test/browser_ruleview_edit-property_01.js index b10ab5b78538..86f366d82d7e 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_edit-property_01.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-property_01.js @@ -65,7 +65,7 @@ function* testEditProperty(view, name, value, browser) { info("Entering a new value, including ; to commit and blur the value"); let onBlur = once(input, "blur"); - let onModifications = idRuleEditor.rule._applyingModifications; + onModifications = idRuleEditor.rule._applyingModifications; for (let ch of value + ";") { EventUtils.sendChar(ch, view.doc.defaultView); } diff --git a/browser/devtools/styleinspector/test/browser_ruleview_edit-property_02.js b/browser/devtools/styleinspector/test/browser_ruleview_edit-property_02.js index 3d967e612a01..90ac30a0a430 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_edit-property_02.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-property_02.js @@ -76,7 +76,7 @@ function* testEditProperty(inspector, ruleView) { is(newValue, "red", "border-color should have been set."); info("Entering property name \"color\" followed by a colon to focus the value"); - let onFocus = once(idRuleEditor.element, "focus", true); + onFocus = once(idRuleEditor.element, "focus", true); for (let ch of "color:") { EventUtils.sendChar(ch, ruleView.doc.defaultView); } @@ -86,7 +86,7 @@ function* testEditProperty(inspector, ruleView) { editor = inplaceEditor(ruleView.doc.activeElement); info("Entering a value following by a semi-colon to commit it"); - let onBlur = once(editor.input, "blur"); + onBlur = once(editor.input, "blur"); for (let ch of "red;") { EventUtils.sendChar(ch, ruleView.doc.defaultView); } @@ -119,7 +119,7 @@ function* testDisableProperty(inspector, ruleView) { propEditor.enable.click(); yield idRuleEditor.rule._applyingModifications; - let newValue = yield executeInContent("Test:GetRulePropertyValue", { + newValue = yield executeInContent("Test:GetRulePropertyValue", { styleSheetIndex: 0, ruleIndex: 0, name: "border-color" diff --git a/browser/devtools/styleinspector/test/browser_ruleview_keybindings.js b/browser/devtools/styleinspector/test/browser_ruleview_keybindings.js index 42448f1b78eb..4db7a4d3b903 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_keybindings.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_keybindings.js @@ -27,17 +27,17 @@ let test = asyncTest(function*() { editor.input.value = "color"; info("Typing ENTER to focus the next field: property value"); - let onFocus = once(brace.parentNode, "focus", true); + onFocus = once(brace.parentNode, "focus", true); EventUtils.sendKey("return"); yield onFocus; ok(true, "The value field was focused"); info("Entering a property value"); - let editor = getCurrentInplaceEditor(view); + editor = getCurrentInplaceEditor(view); editor.input.value = "green"; info("Typing ENTER again should focus a new property name"); - let onFocus = once(brace.parentNode, "focus", true); + onFocus = once(brace.parentNode, "focus", true); EventUtils.sendKey("return"); yield onFocus; ok(true, "The new property name field was focused"); diff --git a/browser/devtools/styleinspector/test/browser_ruleview_pseudo-element.js b/browser/devtools/styleinspector/test/browser_ruleview_pseudo-element.js index 612185bd92f3..b4246209035e 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_pseudo-element.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_pseudo-element.js @@ -110,7 +110,7 @@ function* testTopLeft(inspector, view) { is(defaultView.getComputedStyle(element).getPropertyValue("padding-top"), "32px", "Added property should not apply to element"); - let firstProp = elementRuleView.addProperty("background-color", "rgb(0, 0, 255)", ""); + firstProp = elementRuleView.addProperty("background-color", "rgb(0, 0, 255)", ""); yield elementRule._applyingModifications; is(defaultView.getComputedStyle(element).getPropertyValue("background-color"), "rgb(0, 0, 255)", diff --git a/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js b/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js index 9c66c36dbdc0..db9a71f048e2 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-attribute-change_01.js @@ -38,7 +38,7 @@ let test = asyncTest(function*() { checkRuleViewContent(view, ["element", ".testclass"]); info("Reverting the ID attribute change"); - let ruleViewRefreshed = inspector.once("rule-view-refreshed"); + ruleViewRefreshed = inspector.once("rule-view-refreshed"); testElement.setAttribute("id", "testid"); yield ruleViewRefreshed; diff --git a/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-style-change.js b/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-style-change.js index 1848267f6166..5f7b8938f22b 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-style-change.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_refresh-on-style-change.js @@ -34,7 +34,7 @@ let test = asyncTest(function*() { is(textAlign, "right", "The rule view shows the new text align."); let color = getRuleViewPropertyValue(view, "element", "color"); is(color, "lightgoldenrodyellow", "The rule view shows the new color.") - let fontSize = getRuleViewPropertyValue(view, "element", "font-size"); + fontSize = getRuleViewPropertyValue(view, "element", "font-size"); is(fontSize, "3em", "The rule view shows the new font size."); let textTransform = getRuleViewPropertyValue(view, "element", "text-transform"); is(textTransform, "uppercase", "The rule view shows the new text transform."); diff --git a/browser/devtools/styleinspector/test/browser_ruleview_selector-highlighter_02.js b/browser/devtools/styleinspector/test/browser_ruleview_selector-highlighter_02.js index bf19c63a9592..f51698a57d5b 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_selector-highlighter_02.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_selector-highlighter_02.js @@ -63,7 +63,7 @@ let test = asyncTest(function*() { info("Checking that the right NodeFront reference and options are passed"); yield selectNode("p", inspector); - let selectorSpan = getRuleViewSelector(rView, "p").firstElementChild; + selectorSpan = getRuleViewSelector(rView, "p").firstElementChild; rView.highlighters._onMouseMove({target: selectorSpan}); is(HighlighterFront.nodeFront.tagName, "P", "The right NodeFront is passed to the highlighter (1)"); @@ -71,7 +71,7 @@ let test = asyncTest(function*() { "The right selector option is passed to the highlighter (1)"); yield selectNode("body", inspector); - let selectorSpan = getRuleViewSelector(rView, "body").firstElementChild; + selectorSpan = getRuleViewSelector(rView, "body").firstElementChild; rView.highlighters._onMouseMove({target: selectorSpan}); is(HighlighterFront.nodeFront.tagName, "BODY", "The right NodeFront is passed to the highlighter (2)"); diff --git a/browser/devtools/styleinspector/test/browser_ruleview_urls-clickable.js b/browser/devtools/styleinspector/test/browser_ruleview_urls-clickable.js index 3427e82800b8..24b710041e66 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_urls-clickable.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_urls-clickable.js @@ -31,7 +31,7 @@ function* selectNodes(inspector, ruleView) { is(relativeLink.getAttribute("href"), TEST_IMAGE, "href matches"); yield selectNode(relative2, inspector); - let relativeLink = ruleView.doc.querySelector(".ruleview-propertycontainer a"); + relativeLink = ruleView.doc.querySelector(".ruleview-propertycontainer a"); ok(relativeLink, "Link exists for relative2 node"); is(relativeLink.getAttribute("href"), TEST_IMAGE, "href matches"); diff --git a/browser/devtools/styleinspector/test/browser_ruleview_user-agent-styles.js b/browser/devtools/styleinspector/test/browser_ruleview_user-agent-styles.js index 9c7e526f890a..e9a9cf591c23 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_user-agent-styles.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_user-agent-styles.js @@ -66,16 +66,16 @@ function* userAgentStylesVisible(inspector, view) { yield selectNode("pre", inspector); yield compareAppliedStylesWithUI(inspector, view, "ua"); - let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); - let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); + userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); + uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); is (userRules.length, 1, "Correct number of user rules"); ok (uaRules.length > 0, "Has UA rules"); yield selectNode("a", inspector); yield compareAppliedStylesWithUI(inspector, view, "ua"); - let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); - let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); + userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); + uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); is (userRules.length, 1, "Correct number of user rules"); ok (userRules.some(rule=> rule.matchedSelectors.length === 0), @@ -103,16 +103,16 @@ function* userAgentStylesNotVisible(inspector, view) { yield selectNode("pre", inspector); yield compareAppliedStylesWithUI(inspector, view); - let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); - let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); + userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); + uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); is (userRules.length, 1, "Correct number of user rules"); is (uaRules.length, 0, "No UA rules"); yield selectNode("a", inspector); yield compareAppliedStylesWithUI(inspector, view); - let userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); - let uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); + userRules = view._elementStyle.rules.filter(rule=>rule.editor.isEditable); + uaRules = view._elementStyle.rules.filter(rule=>!rule.editor.isEditable); is (userRules.length, 1, "Correct number of user rules"); is (uaRules.length, 0, "No UA rules"); } diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_csslogic-content-stylesheets.js b/browser/devtools/styleinspector/test/browser_styleinspector_csslogic-content-stylesheets.js index 6284e52c04a1..30a702bfea62 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_csslogic-content-stylesheets.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_csslogic-content-stylesheets.js @@ -34,8 +34,8 @@ let test = asyncTest(function*() { allowXUL(); yield addTab(TEST_URI_XUL); - let {toolbox, inspector, view} = yield openRuleView(); - let target = getNode("#target"); + ({toolbox, inspector, view} = yield openRuleView()); + target = getNode("#target"); yield selectNode("#target", inspector); yield checkSheets(target); diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js index d8e0c4962a8b..a9fcd6d7d611 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-background-image.js @@ -42,7 +42,7 @@ let test = asyncTest(function*() { yield testTooltipAppearsEvenInEditMode(view); info("Switching over to the computed-view"); - let {view} = yield openComputedView(); + ({view} = yield openComputedView()); info("Testing that the background-image computed style has a tooltip too"); yield testComputedView(view); diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-closes-on-new-selection.js b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-closes-on-new-selection.js index c6abd58ede7f..57da400761ca 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-closes-on-new-selection.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-closes-on-new-selection.js @@ -16,7 +16,7 @@ let test = asyncTest(function*() { yield testRuleView(view, inspector); info("Testing computed view tooltip closes on new selection"); - let {view} = yield openComputedView(); + ({view} = yield openComputedView()); yield testComputedView(view, inspector); }); diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js index fcfa74e20f47..57877824fcbd 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_tooltip-longhand-fontfamily.js @@ -32,7 +32,7 @@ let test = asyncTest(function*() { yield testRuleView(view, inspector.selection.nodeFront); info("Opening the computed view"); - let {toolbox, inspector, view} = yield openComputedView(); + ({toolbox, inspector, view} = yield openComputedView()); yield testComputedView(view, inspector.selection.nodeFront); diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js index 5183857acede..04bda255d447 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-01.js @@ -31,12 +31,12 @@ let test = asyncTest(function*() { is(h, h2, "The same instance of highlighter is returned everytime in the rule-view"); let {view: cView} = yield openComputedView(); - let overlay = cView.highlighters; + overlay = cView.highlighters; ok(!overlay.highlighters[TYPE], "No highlighter exists in the computed-view"); - let h = yield overlay._getHighlighter(TYPE); + h = yield overlay._getHighlighter(TYPE); ok(overlay.highlighters[TYPE], "The highlighter has been created in the computed-view"); is(h, overlay.highlighters[TYPE], "The right highlighter has been created"); - let h2 = yield overlay._getHighlighter(TYPE); + h2 = yield overlay._getHighlighter(TYPE); is(h, h2, "The same instance of highlighter is returned everytime in the computed-view"); }); diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js index 826615fcc8e2..24d64936aae8 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-02.js @@ -36,28 +36,28 @@ let test = asyncTest(function*() { ok(!hs.promises[TYPE], "No highlighter is being created in the rule-view (2)"); info("Faking a mousemove on a transform property"); - let {valueSpan} = getRuleViewProperty(rView, "body", "transform"); + ({valueSpan} = getRuleViewProperty(rView, "body", "transform")); hs._onMouseMove({target: valueSpan}); ok(hs.promises[TYPE], "The highlighter is being initialized"); let h = yield hs.promises[TYPE]; is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one"); let {view: cView} = yield openComputedView(); - let hs = cView.highlighters; + hs = cView.highlighters; ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (1)"); ok(!hs.promises[TYPE], "No highlighter is being created in the computed-view (1)"); info("Faking a mousemove on a non-transform property"); - let {valueSpan} = getComputedViewProperty(cView, "color"); + ({valueSpan} = getComputedViewProperty(cView, "color")); hs._onMouseMove({target: valueSpan}); ok(!hs.highlighters[TYPE], "No highlighter exists in the computed-view (2)"); ok(!hs.promises[TYPE], "No highlighter is being created in the computed-view (2)"); info("Faking a mousemove on a transform property"); - let {valueSpan} = getComputedViewProperty(cView, "transform"); + ({valueSpan} = getComputedViewProperty(cView, "transform")); hs._onMouseMove({target: valueSpan}); ok(hs.promises[TYPE], "The highlighter is being initialized"); - let h = yield hs.promises[TYPE]; + h = yield hs.promises[TYPE]; is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one"); }); diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-03.js b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-03.js index eb57783dd606..8c90118b741c 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-03.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-03.js @@ -73,19 +73,19 @@ let test = asyncTest(function*() { info("Checking that the right NodeFront reference is passed"); yield selectNode("html", inspector); - let {valueSpan} = getRuleViewProperty(rView, "html", "transform"); + ({valueSpan} = getRuleViewProperty(rView, "html", "transform")); rView.highlighters._onMouseMove({target: valueSpan}); is(HighlighterFront.nodeFront.tagName, "HTML", "The right NodeFront is passed to the highlighter (1)"); yield selectNode("body", inspector); - let {valueSpan} = getRuleViewProperty(rView, "body", "transform"); + ({valueSpan} = getRuleViewProperty(rView, "body", "transform")); rView.highlighters._onMouseMove({target: valueSpan}); is(HighlighterFront.nodeFront.tagName, "BODY", "The right NodeFront is passed to the highlighter (2)"); info("Checking that the highlighter gets hidden when hovering a non-transform property"); - let {valueSpan} = getRuleViewProperty(rView, "body", "color"); + ({valueSpan} = getRuleViewProperty(rView, "body", "color")); rView.highlighters._onMouseMove({target: valueSpan}); ok(!HighlighterFront.isShown, "The highlighter is hidden"); }); diff --git a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-04.js b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-04.js index 7b39122e3498..9d5dbfed69ac 100644 --- a/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-04.js +++ b/browser/devtools/styleinspector/test/browser_styleinspector_transform-highlighter-04.js @@ -48,13 +48,13 @@ let test = asyncTest(function*() { yield classRuleEditor.rule._applyingModifications; info("Faking a mousemove on the disabled property"); - let {valueSpan} = getRuleViewProperty(rView, ".test", "transform"); + ({valueSpan} = getRuleViewProperty(rView, ".test", "transform")); hs._onMouseMove({target: valueSpan}); ok(!hs.highlighters[TYPE], "No highlighter was created for the disabled property"); ok(!hs.promises[TYPE], "And no highlighter is being initialized either"); info("Faking a mousemove on the now unoverriden property"); - let {valueSpan} = getRuleViewProperty(rView, "div", "transform"); + ({valueSpan} = getRuleViewProperty(rView, "div", "transform")); hs._onMouseMove({target: valueSpan}); ok(hs.promises[TYPE], "The highlighter is being initialized now"); let h = yield hs.promises[TYPE]; diff --git a/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-set-param.js b/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-set-param.js index 3122b8a433b1..da17619edb63 100644 --- a/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-set-param.js +++ b/browser/devtools/webaudioeditor/test/browser_audionode-actor-get-set-param.js @@ -19,17 +19,17 @@ function spawnTest () { let type = yield oscNode.getParam("type"); ise(type, "sine", "AudioNode:getParam correctly fetches non-AudioParam"); - let type = yield oscNode.getParam("not-a-valid-param"); + type = yield oscNode.getParam("not-a-valid-param"); ok(type.type === "undefined", "AudioNode:getParam correctly returns a grip value for `undefined` for an invalid param."); let resSuccess = yield oscNode.setParam("frequency", 220); - let freq = yield oscNode.getParam("frequency"); + freq = yield oscNode.getParam("frequency"); ise(freq, 220, "AudioNode:setParam correctly sets a `number` AudioParam"); is(resSuccess, undefined, "AudioNode:setParam returns undefined for correctly set AudioParam"); resSuccess = yield oscNode.setParam("type", "square"); - let type = yield oscNode.getParam("type"); + type = yield oscNode.getParam("type"); ise(type, "square", "AudioNode:setParam correctly sets a `string` non-AudioParam"); is(resSuccess, undefined, "AudioNode:setParam returns undefined for correctly set AudioParam"); diff --git a/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js b/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js index b5769daeaac2..e7151dfe7adb 100644 --- a/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js +++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-01.js @@ -40,8 +40,8 @@ function spawnTest() { is($("#content").hidden, false, "The tool's content should not be hidden anymore."); - let navigating = once(target, "will-navigate"); - let started = once(gFront, "start-context"); + navigating = once(target, "will-navigate"); + started = once(gFront, "start-context"); reload(target); diff --git a/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js b/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js index 29fe7bbd0aba..79242c2a16ed 100644 --- a/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js +++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-02.js @@ -24,12 +24,12 @@ function spawnTest() { reload(target); - let [actors] = yield Promise.all([ + [actors] = yield Promise.all([ get3(gFront, "create-node"), waitForGraphRendered(panelWin, 3, 2) ]); - let { nodes, edges } = countGraphObjects(panelWin); + ({ nodes, edges } = countGraphObjects(panelWin)); ise(nodes, 3, "after reload, should only be 3 nodes."); ise(edges, 2, "after reload, should only be 2 edges."); diff --git a/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js b/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js index 04c1092dfb1f..96dd9c95a4c7 100644 --- a/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js +++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-03.js @@ -29,11 +29,11 @@ function spawnTest() { reload(target); - let [actors] = yield Promise.all([ + [actors] = yield Promise.all([ get3(gFront, "create-node"), waitForGraphRendered(panelWin, 3, 2) ]); - let nodeIds = actors.map(actor => actor.actorID); + nodeIds = actors.map(actor => actor.actorID); ok(!WebAudioInspectorView.isVisible(), "InspectorView hidden on start."); ise(WebAudioInspectorView.getCurrentAudioNode(), null, diff --git a/browser/devtools/webaudioeditor/test/browser_wa_reset-04.js b/browser/devtools/webaudioeditor/test/browser_wa_reset-04.js index 6722980524a8..00a1eb92b4dc 100644 --- a/browser/devtools/webaudioeditor/test/browser_wa_reset-04.js +++ b/browser/devtools/webaudioeditor/test/browser_wa_reset-04.js @@ -37,7 +37,7 @@ function spawnTest() { is($("#content").hidden, true, "The tool's content should still be hidden."); - let navigating = once(target, "will-navigate"); + navigating = once(target, "will-navigate"); let started = once(gFront, "start-context"); reload(target); diff --git a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-connect-param.js b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-connect-param.js index af4078225535..7239a8a6e9c7 100644 --- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-connect-param.js +++ b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-connect-param.js @@ -7,7 +7,7 @@ function spawnTest () { let [target, debuggee, front] = yield initBackend(CONNECT_PARAM_URL); - let [_, _, [destNode, carrierNode, modNode, gainNode], _, connectParam] = yield Promise.all([ + let [, , [destNode, carrierNode, modNode, gainNode], , connectParam] = yield Promise.all([ front.setup({ reload: true }), once(front, "start-context"), getN(front, "create-node", 4), diff --git a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-destroy-node.js b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-destroy-node.js index 88dc96be0ac9..d6e15952ad30 100644 --- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-destroy-node.js +++ b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-destroy-node.js @@ -9,7 +9,7 @@ function spawnTest () { let [target, debuggee, front] = yield initBackend(DESTROY_NODES_URL); let waitUntilDestroyed = getN(front, "destroy-node", 10); - let [_, _, created] = yield Promise.all([ + let [, , created] = yield Promise.all([ front.setup({ reload: true }), once(front, "start-context"), // Should create 1 destination node and 10 disposable buffer nodes diff --git a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-simple.js b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-simple.js index 86dead3bc102..3dd444e571cd 100644 --- a/browser/devtools/webaudioeditor/test/browser_webaudio-actor-simple.js +++ b/browser/devtools/webaudioeditor/test/browser_webaudio-actor-simple.js @@ -26,7 +26,7 @@ function spawnTest () { is(source.actorID, oscNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on source (osc->gain)"); is(dest.actorID, gainNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on dest (osc->gain)"); - let { source, dest } = connect2; + ({ source, dest } = connect2); is(source.actorID, gainNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on source (gain->dest)"); is(dest.actorID, destNode.actorID, "WebAudioActor:connect-node returns correct actor with ID on dest (gain->dest)"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js index 649d468f0336..ec30d62bc6a5 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_586388_select_all.js @@ -80,7 +80,7 @@ function test() { selectAllItem.doCommand(); - let selectedCount = hud.ui.output.getSelectedMessages().length; + selectedCount = hud.ui.output.getSelectedMessages().length; is(selectedCount, outputNode.childNodes.length, "all console messages are selected after performing a select-all " + "operation from the context menu"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js index 65ea953f7208..82f9d1ef9763 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_network_panel.js +++ b/browser/devtools/webconsole/test/browser_webconsole_network_panel.js @@ -360,7 +360,7 @@ function testGen() { responseImageCached: true }); - let imgNode = networkPanel.document.getElementById("responseImageCachedNode"); + imgNode = networkPanel.document.getElementById("responseImageCachedNode"); is(imgNode.getAttribute("src"), "data:image/png;base64," + TEST_IMG_BASE64, "Displayed image is correct"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_split.js b/browser/devtools/webconsole/test/browser_webconsole_split.js index e7d5fa8c5a21..30ae9ce70852 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_split.js +++ b/browser/devtools/webconsole/test/browser_webconsole_split.js @@ -117,7 +117,7 @@ function test() // Make sure splitting console does nothing while webconsole is opened toolbox.toggleSplitConsole(); - let currentUIState = getCurrentUIState(); + currentUIState = getCurrentUIState(); ok (!currentUIState.splitterVisibility, "Splitter is hidden when console is opened."); is (currentUIState.deckHeight, 0, "Deck has a height == 0 when console is opened."); @@ -176,7 +176,7 @@ function test() toolbox.toggleSplitConsole(); - let currentUIState = getCurrentUIState(); + currentUIState = getCurrentUIState(); ok (currentUIState.splitterVisibility, "Splitter is visible when console is split"); ok (currentUIState.deckHeight > 0, "Deck has a height > 0 when console is split"); @@ -189,7 +189,7 @@ function test() toolbox.toggleSplitConsole(); - let currentUIState = getCurrentUIState(); + currentUIState = getCurrentUIState(); ok (!currentUIState.splitterVisibility, "Splitter is hidden after toggling"); is (currentUIState.deckHeight, currentUIState.containerHeight, "Deck has a height > 0 after toggling"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_split_focus.js b/browser/devtools/webconsole/test/browser_webconsole_split_focus.js index 3246311074c7..51d7b9a79a9e 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_split_focus.js +++ b/browser/devtools/webconsole/test/browser_webconsole_split_focus.js @@ -33,7 +33,7 @@ function test() { ok(toolbox.splitConsole, "Split console is now visible"); // Use the binding element since jsterm.inputNode is a XUL textarea element. - let activeElement = getActiveElement(toolbox.doc); + activeElement = getActiveElement(toolbox.doc); activeElement = activeElement.ownerDocument.getBindingParent(activeElement); let inputNode = toolbox.getPanel("webconsole").hud.jsterm.inputNode; is(activeElement, inputNode, "Split console input is focused by default"); @@ -42,7 +42,7 @@ function test() { info ("Making sure that the search box is refocused after closing the split console"); // Use the binding element since inspector.searchBox is a XUL element. - let activeElement = getActiveElement(inspector.panelDoc); + activeElement = getActiveElement(inspector.panelDoc); activeElement = activeElement.ownerDocument.getBindingParent(activeElement); is (activeElement, inspector.searchBox, "Search box is focused"); diff --git a/browser/devtools/webconsole/test/browser_webconsole_split_persist.js b/browser/devtools/webconsole/test/browser_webconsole_split_persist.js index d08ee0e49681..d9116f2b1ceb 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_split_persist.js +++ b/browser/devtools/webconsole/test/browser_webconsole_split_persist.js @@ -30,8 +30,8 @@ function test() { yield toolbox.destroy(); info("Opening a tab while there is a true user setting on split console pref"); - let {tab} = yield loadTab(TEST_URI); - let target = TargetFactory.forTab(tab); + ({tab} = yield loadTab(TEST_URI)); + target = TargetFactory.forTab(tab); toolbox = yield gDevTools.showToolbox(target, "inspector"); ok(toolbox.splitConsole, "Split console is visible by default."); @@ -63,8 +63,8 @@ function test() { info("Opening a tab while there is a false user setting on split console pref"); - let {tab} = yield loadTab(TEST_URI); - let target = TargetFactory.forTab(tab); + ({tab} = yield loadTab(TEST_URI)); + target = TargetFactory.forTab(tab); toolbox = yield gDevTools.showToolbox(target, "inspector"); ok(!toolbox.splitConsole, "Split console is hidden by default."); diff --git a/browser/devtools/webconsole/test/head.js b/browser/devtools/webconsole/test/head.js index 0a38806fb771..fee01e8797d1 100644 --- a/browser/devtools/webconsole/test/head.js +++ b/browser/devtools/webconsole/test/head.js @@ -348,19 +348,19 @@ function finishTest() return; } - let hud = HUDService.getHudByWindow(content); - if (!hud) { + let contentHud = HUDService.getHudByWindow(content); + if (!contentHud) { finish(); return; } - if (hud.jsterm) { - hud.jsterm.clearOutput(true); + if (contentHud.jsterm) { + contentHud.jsterm.clearOutput(true); } - closeConsole(hud.target.tab, finish); + closeConsole(contentHud.target.tab, finish); - hud = null; + contentHud = null; } function tearDown() diff --git a/browser/devtools/webide/test/test_newapp.html b/browser/devtools/webide/test/test_newapp.html index c727507ae01c..29c6db8b652c 100644 --- a/browser/devtools/webide/test/test_newapp.html +++ b/browser/devtools/webide/test/test_newapp.html @@ -28,7 +28,7 @@ }); let project = win.AppManager.selectedProject; - let tmpDir = FileUtils.getDir("TmpD", ["webidetmpapp"]); + tmpDir = FileUtils.getDir("TmpD", ["webidetmpapp"]); ok(tmpDir.isDirectory(), "Directory created"); is(project.location, tmpDir.path, "Location is valid (and lowercase)"); is(project.name, "webideTmpApp", "name field has been updated"); diff --git a/browser/experiments/test/xpcshell/test_activate.js b/browser/experiments/test/xpcshell/test_activate.js index cf702d67e79f..931901a8a72f 100644 --- a/browser/experiments/test/xpcshell/test_activate.js +++ b/browser/experiments/test/xpcshell/test_activate.js @@ -126,7 +126,7 @@ add_task(function* test_startStop() { Assert.equal(addons[0].userDisabled, false, "The add-on is not userDisabled."); Assert.ok(addons[0].isActive, "The add-on is active."); - let result = yield experiment.shouldStop(); + result = yield experiment.shouldStop(); Assert.equal(result.shouldStop, false, "shouldStop should be false."); Assert.equal(experiment.enabled, true, "Experiment should be enabled."); addons = yield getExperimentAddons(); @@ -156,7 +156,7 @@ add_task(function* test_startStop() { // Make sure "ignore hashes" mode works. gPolicy.ignoreHashes = true; - let changes = yield experiment.start(); + changes = yield experiment.start(); Assert.equal(changes, experiment.ADDON_CHANGE_INSTALL); yield experiment.stop(); gPolicy.ignoreHashes = false; diff --git a/browser/experiments/test/xpcshell/test_api.js b/browser/experiments/test/xpcshell/test_api.js index 16e66ac69748..c5da2a40c3c5 100644 --- a/browser/experiments/test/xpcshell/test_api.js +++ b/browser/experiments/test/xpcshell/test_api.js @@ -1632,7 +1632,7 @@ add_task(function* test_foreignUninstallAndRestart() { yield AddonTestUtils.uninstallAddonByID(EXPERIMENT1_ID); yield experiments._mainTask; - let addons = yield getExperimentAddons(); + addons = yield getExperimentAddons(); Assert.equal(addons.length, 0, "Experiment add-on should have been removed."); experimentList = yield experiments.getExperiments(); @@ -1645,7 +1645,7 @@ add_task(function* test_foreignUninstallAndRestart() { experiments = new Experiments.Experiments(gPolicy); yield experiments.updateManifest(); - let addons = yield getExperimentAddons(); + addons = yield getExperimentAddons(); Assert.equal(addons.length, 0, "No experiment add-ons installed."); experimentList = yield experiments.getExperiments(); diff --git a/browser/modules/test/browser_ContentSearch.js b/browser/modules/test/browser_ContentSearch.js index c4629860dee6..eea890af1301 100644 --- a/browser/modules/test/browser_ContentSearch.js +++ b/browser/modules/test/browser_ContentSearch.js @@ -59,7 +59,7 @@ add_task(function* SetCurrentEngine() { }); Services.search.currentEngine = oldCurrentEngine; - let msg = yield waitForTestMsg("CurrentEngine"); + msg = yield waitForTestMsg("CurrentEngine"); checkMsg(msg, { type: "CurrentEngine", data: yield currentEngineObj(oldCurrentEngine), diff --git a/browser/modules/test/browser_UITour2.js b/browser/modules/test/browser_UITour2.js index 3bc9eed7e760..40efaaaae1ff 100644 --- a/browser/modules/test/browser_UITour2.js +++ b/browser/modules/test/browser_UITour2.js @@ -78,7 +78,7 @@ let tests = [ gContentAPI.removePinnedTab(); isnot(gBrowser.tabs[0], tab, "First tab should not be the pinned tab"); - let tabInfo = UITour.pinnedTabs.get(window); + tabInfo = UITour.pinnedTabs.get(window); is(tabInfo, null, "Should not have any data about the removed pinned tab after removePinnedTab()"); gContentAPI.addPinnedTab(); diff --git a/caps/tests/mochitest/test_disableScript.xul b/caps/tests/mochitest/test_disableScript.xul index 4e77091ae9a1..fe9dc11047f8 100644 --- a/caps/tests/mochitest/test_disableScript.xul +++ b/caps/tests/mochitest/test_disableScript.xul @@ -98,7 +98,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=840488 } function testList(expectEnabled, win, list, idx) { - let idx = idx || 0; + idx = idx || 0; let deferred = Promise.defer(); let target = list[idx] + path; info("Testing scriptability for: " + target + ". expecting " + expectEnabled); diff --git a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js index 57059c090863..213122c1dac5 100644 --- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js +++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js @@ -114,7 +114,7 @@ function testReceiving_GSM_Language_and_Body() { let promise = Promise.resolve(); let testDcs = []; - dcs = 0; + let dcs = 0; while (dcs <= 0xFF) { try { let dcsInfo = { dcs: dcs }; @@ -123,7 +123,7 @@ function testReceiving_GSM_Language_and_Body() { testDcs.push(dcsInfo); } catch (e) { // Unsupported coding group, skip. - let dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10; + dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10; } dcs++; } diff --git a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_umts.js b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_umts.js index 2df6b3d1a751..c0daf399ca96 100644 --- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_umts.js +++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_umts.js @@ -130,7 +130,7 @@ function testReceiving_UMTS_Language_and_Body() { let promise = Promise.resolve(); let testDcs = []; - dcs = 0; + let dcs = 0; while (dcs <= 0xFF) { try { let dcsInfo = { dcs: dcs }; @@ -139,7 +139,7 @@ function testReceiving_UMTS_Language_and_Body() { testDcs.push(dcsInfo); } catch (e) { // Unsupported coding group, skip. - let dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10; + dcs = (dcs & PDU_DCS_CODING_GROUP_BITS) + 0x10; } dcs++; } diff --git a/dom/indexedDB/test/error_events_abort_transactions_iframe.html b/dom/indexedDB/test/error_events_abort_transactions_iframe.html index 858cf241c5a2..7be3de42fd78 100644 --- a/dom/indexedDB/test/error_events_abort_transactions_iframe.html +++ b/dom/indexedDB/test/error_events_abort_transactions_iframe.html @@ -96,12 +96,12 @@ is(event.target.error.name, "ConstraintError", "Right error"); is(originalRequest.transaction, null, "request.transaction should now be null"); - let request = indexedDB.open(window.location.pathname, 1); + request = indexedDB.open(window.location.pathname, 1); request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; - let db = event.target.result; + db = event.target.result; event.target.transaction.oncomplete = grabEventAndContinueHandler; event.target.transaction.onabort = unexpectedSuccessHandler; @@ -109,7 +109,7 @@ is(db.version, "1", "Correct version"); is(db.objectStoreNames.length, 0, "Correct objectStoreNames length"); - let objectStore = db.createObjectStore("foo"); + objectStore = db.createObjectStore("foo"); is(db.objectStoreNames.length, 1, "Correct objectStoreNames length"); ok(db.objectStoreNames.contains("foo"), "Has correct objectStore"); @@ -153,14 +153,14 @@ db.close(); - let request = indexedDB.open(window.location.pathname, 2); + request = indexedDB.open(window.location.pathname, 2); request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; - let db = event.target.result; + db = event.target.result; - let trans = event.target.transaction; + trans = event.target.transaction; trans.oncomplete = unexpectedSuccessHandler; is(db.version, "2", "Correct version"); @@ -169,7 +169,7 @@ ok(db.objectStoreNames.contains("bar"), "Has correct objectStore"); let createdObjectStore = db.createObjectStore("newlyCreated"); - let objectStore = trans.objectStore("foo"); + objectStore = trans.objectStore("foo"); let deletedObjectStore = trans.objectStore("bar"); deletedObjectStore.deleteIndex("foo"); db.deleteObjectStore("bar"); diff --git a/dom/indexedDB/test/exceptions_in_events_iframe.html b/dom/indexedDB/test/exceptions_in_events_iframe.html index 9f8a6be2f9cd..24929648ebb5 100644 --- a/dom/indexedDB/test/exceptions_in_events_iframe.html +++ b/dom/indexedDB/test/exceptions_in_events_iframe.html @@ -76,13 +76,13 @@ // Test 2: Throwing during a request's success handler should abort the // transaction. - let request = indexedDB.open(window.location.pathname, 1); + request = indexedDB.open(window.location.pathname, 1); request.onerror = errorHandler; request.onblocked = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; request.onsuccess = unexpectedSuccessHandler; let openrequest = request; - let event = yield undefined; + event = yield undefined; request.onupgradeneeded = unexpectedSuccessHandler; @@ -121,17 +121,17 @@ // Test 3: Throwing during a request's error handler should abort the // transaction, even if preventDefault is called on the error event. - let request = indexedDB.open(window.location.pathname, 1); + request = indexedDB.open(window.location.pathname, 1); request.onerror = errorHandler; request.onblocked = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; request.onsuccess = unexpectedSuccessHandler; - let openrequest = request; - let event = yield undefined; + openrequest = request; + event = yield undefined; request.onupgradeneeded = unexpectedSuccessHandler; - let db = event.target.result; + db = event.target.result; db.onerror = function(event) { event.preventDefault(); }; @@ -142,7 +142,7 @@ is(db.version, 1, "Correct version"); is(db.objectStoreNames.length, 0, "Correct objectStoreNames length"); - let objectStore = db.createObjectStore("foo"); + objectStore = db.createObjectStore("foo"); is(db.objectStoreNames.length, 1, "Correct objectStoreNames length"); ok(db.objectStoreNames.contains("foo"), "Has correct objectStore"); diff --git a/dom/indexedDB/test/test_blob_simple.html b/dom/indexedDB/test/test_blob_simple.html index 9714788ec412..e7e4407197a9 100644 --- a/dom/indexedDB/test/test_blob_simple.html +++ b/dom/indexedDB/test/test_blob_simple.html @@ -132,7 +132,7 @@ info("Retrieve blobs from database via index and verify contents."); - let index = db.transaction("foo").objectStore("foo").index("foo"); + index = db.transaction("foo").objectStore("foo").index("foo"); index.get(INDEX_KEY).onsuccess = grabEventAndContinueHandler; event = yield undefined; @@ -248,16 +248,16 @@ info("Stored blob back into database"); - let fileReader = new FileReader(); + fileReader = new FileReader(); fileReader.onload = grabEventAndContinueHandler; fileReader.readAsText(blobFromDB); event = yield undefined; is(event.target.result, BLOB_DATA.join(""), "Correct text"); - let blobURL = URL.createObjectURL(blobFromDB); + blobURL = URL.createObjectURL(blobFromDB); - let xhr = new XMLHttpRequest(); + xhr = new XMLHttpRequest(); xhr.open("GET", blobURL); xhr.onload = grabEventAndContinueHandler; xhr.send(); diff --git a/dom/indexedDB/test/test_file_transaction_abort.html b/dom/indexedDB/test/test_file_transaction_abort.html index 2f1911751b06..8c08c65177d2 100644 --- a/dom/indexedDB/test/test_file_transaction_abort.html +++ b/dom/indexedDB/test/test_file_transaction_abort.html @@ -32,14 +32,14 @@ let db = event.target.result; db.onerror = errorHandler; - objectStore = db.createObjectStore(objectStoreName, { }); + let objectStore = db.createObjectStore(objectStoreName, { }); event = yield undefined; is(event.type, "success", "Got correct event type"); let trans = db.transaction([objectStoreName], READ_WRITE); - let objectStore = trans.objectStore(objectStoreName); + objectStore = trans.objectStore(objectStoreName); request = objectStore.add(fileData.file, fileData.key); request.onsuccess = grabEventAndContinueHandler; diff --git a/dom/indexedDB/test/test_filehandle_store_snapshot.html b/dom/indexedDB/test/test_filehandle_store_snapshot.html index 12d48de91f8b..82d14256f26a 100644 --- a/dom/indexedDB/test/test_filehandle_store_snapshot.html +++ b/dom/indexedDB/test/test_filehandle_store_snapshot.html @@ -59,7 +59,7 @@ let file = event.target.result; let trans = db.transaction([objectStoreName], READ_WRITE); - let objectStore = trans.objectStore(objectStoreName); + objectStore = trans.objectStore(objectStoreName); request = objectStore.add(file, 42); request.onsuccess = grabEventAndContinueHandler; diff --git a/dom/indexedDB/test/test_persistenceType.html b/dom/indexedDB/test/test_persistenceType.html index 6b164c002170..773a84d6569d 100644 --- a/dom/indexedDB/test/test_persistenceType.html +++ b/dom/indexedDB/test/test_persistenceType.html @@ -80,7 +80,7 @@ request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; is(event.type, "upgradeneeded", "Got correct event type"); diff --git a/dom/indexedDB/test/unit/test_autoIncrement_indexes.js b/dom/indexedDB/test/unit/test_autoIncrement_indexes.js index 32fc4f693a3f..ce2d5d55279d 100644 --- a/dom/indexedDB/test/unit/test_autoIncrement_indexes.js +++ b/dom/indexedDB/test/unit/test_autoIncrement_indexes.js @@ -31,7 +31,7 @@ function testSteps() event = yield undefined; - let objectStore = db.transaction("foo").objectStore("foo"); + objectStore = db.transaction("foo").objectStore("foo"); let first = objectStore.index("first"); let second = objectStore.index("second"); let third = objectStore.index("third"); diff --git a/dom/indexedDB/test/unit/test_complex_keyPaths.js b/dom/indexedDB/test/unit/test_complex_keyPaths.js index 95e5ad44a20e..24375813d559 100644 --- a/dom/indexedDB/test/unit/test_complex_keyPaths.js +++ b/dom/indexedDB/test/unit/test_complex_keyPaths.js @@ -164,8 +164,8 @@ function testSteps() let store = db.createObjectStore("indexStore"); let indexes = {}; for (let i = 0; i < keyPaths.length; i++) { - let test = " for index test " + JSON.stringify(info); let info = keyPaths[i]; + let test = " for index test " + JSON.stringify(info); let indexName = JSON.stringify(info.keyPath); if (!indexes[indexName]) { try { diff --git a/dom/indexedDB/test/unit/test_create_index_with_integer_keys.js b/dom/indexedDB/test/unit/test_create_index_with_integer_keys.js index 3232e4608ab1..d14b5041192e 100644 --- a/dom/indexedDB/test/unit/test_create_index_with_integer_keys.js +++ b/dom/indexedDB/test/unit/test_create_index_with_integer_keys.js @@ -26,10 +26,10 @@ function testSteps() yield undefined; db.close(); - let request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 2); + request = indexedDB.open(this.window ? window.location.pathname : "Splendid Test", 2); request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; let db2 = event.target.result; db2.onerror = errorHandler; diff --git a/dom/indexedDB/test/unit/test_create_objectStore.js b/dom/indexedDB/test/unit/test_create_objectStore.js index 81b753257f74..215723c26920 100644 --- a/dom/indexedDB/test/unit/test_create_objectStore.js +++ b/dom/indexedDB/test/unit/test_create_objectStore.js @@ -113,7 +113,6 @@ function testSteps() is(ex.code, DOMException.INVALID_ACCESS_ERR, "should throw right exception"); // Can't handle autoincrement and array keypath - let ex; try { db.createObjectStore("storefail", { keyPath: ["a"], autoIncrement: true }); } diff --git a/dom/indexedDB/test/unit/test_deleteDatabase.js b/dom/indexedDB/test/unit/test_deleteDatabase.js index 270b50a4bdfe..7c9f76522580 100644 --- a/dom/indexedDB/test/unit/test_deleteDatabase.js +++ b/dom/indexedDB/test/unit/test_deleteDatabase.js @@ -35,7 +35,7 @@ function testSteps() ok(event.target.result instanceof IDBDatabase, "Result should be a database"); is(db.objectStoreNames.length, 1, "Expect an objectStore here"); - let request = indexedDB.open(name, 10); + request = indexedDB.open(name, 10); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; @@ -66,7 +66,7 @@ function testSteps() db.onversionchange = closeDBs; db2.onversionchange = closeDBs; - let request = indexedDB.deleteDatabase(name); + request = indexedDB.deleteDatabase(name); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; @@ -78,7 +78,7 @@ function testSteps() is(event.target, request, "event has right target"); ok(event.target.result === undefined, "event should have no result"); - let request = indexedDB.open(name, 1); + request = indexedDB.open(name, 1); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; @@ -87,14 +87,14 @@ function testSteps() is(event.target.result.objectStoreNames.length, 0, "DB should have no object stores"); - let request = indexedDB.deleteDatabase("thisDatabaseHadBetterNotExist"); + request = indexedDB.deleteDatabase("thisDatabaseHadBetterNotExist"); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; event = yield undefined; ok(true, "deleteDatabase on a non-existent database succeeded"); - let request = indexedDB.open("thisDatabaseHadBetterNotExist"); + request = indexedDB.open("thisDatabaseHadBetterNotExist"); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; diff --git a/dom/indexedDB/test/unit/test_deleteDatabase_interactions.js b/dom/indexedDB/test/unit/test_deleteDatabase_interactions.js index d15a1efc8234..90058e11a8a4 100644 --- a/dom/indexedDB/test/unit/test_deleteDatabase_interactions.js +++ b/dom/indexedDB/test/unit/test_deleteDatabase_interactions.js @@ -35,7 +35,7 @@ function testSteps() db.close(); - let request = indexedDB.deleteDatabase(name); + request = indexedDB.deleteDatabase(name); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; diff --git a/dom/indexedDB/test/unit/test_index_empty_keyPath.js b/dom/indexedDB/test/unit/test_index_empty_keyPath.js index a2f9e5a91d29..9fbcfc9c9701 100644 --- a/dom/indexedDB/test/unit/test_index_empty_keyPath.js +++ b/dom/indexedDB/test/unit/test_index_empty_keyPath.js @@ -47,29 +47,29 @@ function testSteps() objectStore = trans.objectStore("data"); index = objectStore.index("set"); - let request = index.get("bar"); + request = index.get("bar"); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; is(event.target.result, "bar", "Got correct result"); - let request = objectStore.add("foopy", 4); + request = objectStore.add("foopy", 4); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; yield undefined; - let request = index.get("foopy"); + request = index.get("foopy"); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; is(event.target.result, "foopy", "Got correct result"); - let request = objectStore.add("foopy", 5); + request = objectStore.add("foopy", 5); request.addEventListener("error", new ExpectError("ConstraintError", true)); request.onsuccess = unexpectedSuccessHandler; diff --git a/dom/indexedDB/test/unit/test_indexes.js b/dom/indexedDB/test/unit/test_indexes.js index 3b9f73fc5884..aaf536febe4d 100644 --- a/dom/indexedDB/test/unit/test_indexes.js +++ b/dom/indexedDB/test/unit/test_indexes.js @@ -252,7 +252,7 @@ function testSteps() ok(true, "Test group 5"); keyIndex = 2; - let keyRange = IDBKeyRange.bound("Bob", "Ron", true); + keyRange = IDBKeyRange.bound("Bob", "Ron", true); request = objectStore.index("name").openKeyCursor(keyRange); request.onerror = errorHandler; @@ -278,7 +278,7 @@ function testSteps() ok(true, "Test group 6"); keyIndex = 1; - let keyRange = IDBKeyRange.bound("Bob", "Ron", false, true); + keyRange = IDBKeyRange.bound("Bob", "Ron", false, true); request = objectStore.index("name").openKeyCursor(keyRange); request.onerror = errorHandler; diff --git a/dom/indexedDB/test/unit/test_multientry.js b/dom/indexedDB/test/unit/test_multientry.js index cc57a5566ebe..dc95acf942c0 100644 --- a/dom/indexedDB/test/unit/test_multientry.js +++ b/dom/indexedDB/test/unit/test_multientry.js @@ -143,7 +143,6 @@ function testSteps() index = store.createIndex("myindex", "x", { multiEntry: true, unique: true }); is(index.multiEntry, true, "index created with multiEntry"); - let i; let indexes; for (i = 0; i < tests.length; ++i) { let test = tests[i]; diff --git a/dom/indexedDB/test/unit/test_names_sorted.js b/dom/indexedDB/test/unit/test_names_sorted.js index 643fec2a8d63..eac03a84a649 100644 --- a/dom/indexedDB/test/unit/test_names_sorted.js +++ b/dom/indexedDB/test/unit/test_names_sorted.js @@ -74,15 +74,15 @@ function testSteps() db.close(); - let request = indexedDB.open(name, 1); + request = indexedDB.open(name, 1); request.onerror = errorHandler; request.onsuccess = grabEventAndContinueHandler; request.onupgradeneeded = unexpectedSuccessHandler; - let event = yield undefined; + event = yield undefined; - let db = event.target.result; + db = event.target.result; - let objectStoreNames = [] + objectStoreNames = [] for (let i = 0; i < objectStoreInfo.length; i++) { let info = objectStoreInfo[i]; objectStoreNames.push(info.name); @@ -99,7 +99,7 @@ function testSteps() } } - let trans = db.transaction(objectStoreNames); + trans = db.transaction(objectStoreNames); for (let i = 0; i < objectStoreInfo.length; i++) { let info = objectStoreInfo[i]; diff --git a/dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js b/dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js index 6c46cac4e51d..747820458b88 100644 --- a/dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js +++ b/dom/indexedDB/test/unit/test_objectStore_openKeyCursor.js @@ -327,7 +327,7 @@ function testSteps() { is(seenKeys.length, allKeys.length - 9, "Saw the right number of keys"); - let match = true; + match = true; for (let i = 0, j = 0; i < seenKeys.length; i++) { if (seenKeys[i] !== allKeys[i + j]) { match = false; @@ -383,7 +383,7 @@ function testSteps() { is(seenKeys.length, allKeys.length - 9, "Saw the right number of keys"); - let match = true; + match = true; for (let i = 0, j = 0; i < seenKeys.length; i++) { if (seenKeys[i] !== allKeys[i + j]) { match = false; diff --git a/dom/indexedDB/test/unit/test_open_for_principal.js b/dom/indexedDB/test/unit/test_open_for_principal.js index 19103e32268d..0c885194001d 100644 --- a/dom/indexedDB/test/unit/test_open_for_principal.js +++ b/dom/indexedDB/test/unit/test_open_for_principal.js @@ -56,7 +56,7 @@ function testSteps() request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; is(event.type, "upgradeneeded", "Got correct event type"); diff --git a/dom/indexedDB/test/unit/test_overlapping_transactions.js b/dom/indexedDB/test/unit/test_overlapping_transactions.js index 6dc58cac45d3..2606d7aea518 100644 --- a/dom/indexedDB/test/unit/test_overlapping_transactions.js +++ b/dom/indexedDB/test/unit/test_overlapping_transactions.js @@ -22,7 +22,7 @@ function testSteps() for (let i in objectStores) { db.createObjectStore(objectStores[i], { autoIncrement: true }); } - let event = yield undefined; + event = yield undefined; is(db.objectStoreNames.length, objectStores.length, "Correct objectStoreNames list"); diff --git a/dom/indexedDB/test/unit/test_persistenceType.js b/dom/indexedDB/test/unit/test_persistenceType.js index 3b8038f626cd..2347beda99c4 100644 --- a/dom/indexedDB/test/unit/test_persistenceType.js +++ b/dom/indexedDB/test/unit/test_persistenceType.js @@ -64,7 +64,7 @@ function testSteps() request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; request.onsuccess = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; is(event.type, "success", "Got correct event type"); diff --git a/dom/indexedDB/test/unit/test_remove_objectStore.js b/dom/indexedDB/test/unit/test_remove_objectStore.js index 81366b122b31..74ae01e89366 100644 --- a/dom/indexedDB/test/unit/test_remove_objectStore.js +++ b/dom/indexedDB/test/unit/test_remove_objectStore.js @@ -39,12 +39,12 @@ function testSteps() db.close(); - let request = indexedDB.open(name, 2); + request = indexedDB.open(name, 2); request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; - let db = event.target.result; + db = event.target.result; let trans = event.target.transaction; let oldObjectStore = trans.objectStore(objectStoreName); @@ -83,12 +83,12 @@ function testSteps() db.close(); - let request = indexedDB.open(name, 3); + request = indexedDB.open(name, 3); request.onerror = errorHandler; request.onupgradeneeded = grabEventAndContinueHandler; - let event = yield undefined; + event = yield undefined; - let db = event.target.result; + db = event.target.result; objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" }); diff --git a/dom/indexedDB/test/unit/test_temporary_storage.js b/dom/indexedDB/test/unit/test_temporary_storage.js index 5ba3609e467a..671c8771f3fb 100644 --- a/dom/indexedDB/test/unit/test_temporary_storage.js +++ b/dom/indexedDB/test/unit/test_temporary_storage.js @@ -200,7 +200,7 @@ function testSteps() is(event.type, "success", "Got correct event type"); - let db = event.target.result; + db = event.target.result; checkUsage(3); yield undefined; diff --git a/dom/indexedDB/test/unit/test_transaction_error.js b/dom/indexedDB/test/unit/test_transaction_error.js index 8d65a406a6f8..c88f4c89faa5 100644 --- a/dom/indexedDB/test/unit/test_transaction_error.js +++ b/dom/indexedDB/test/unit/test_transaction_error.js @@ -43,7 +43,7 @@ function testSteps() { info("Adding duplicate entry with preventDefault()"); - let request = objectStore.add(data, dataKey); + request = objectStore.add(data, dataKey); request.onsuccess = unexpectedSuccessHandler; request.onerror = grabEventAndContinueHandler; event = yield undefined; diff --git a/dom/indexedDB/test/unit/test_transaction_ordering.js b/dom/indexedDB/test/unit/test_transaction_ordering.js index 8cee3fd95311..5e3c2fd742ae 100644 --- a/dom/indexedDB/test/unit/test_transaction_ordering.js +++ b/dom/indexedDB/test/unit/test_transaction_ordering.js @@ -36,11 +36,11 @@ function testSteps() yield undefined; let trans3 = db.transaction("foo", "readonly"); - let request = trans3.objectStore("foo").get(42); + request = trans3.objectStore("foo").get(42); request.onsuccess = grabEventAndContinueHandler; request.onerror = errorHandler; - let event = yield undefined; + event = yield undefined; is(event.target.result, "2", "Transactions were ordered properly."); finishTest(); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js b/dom/system/gonk/tests/test_ril_worker_sms_cdma.js index c98bdfcdf931..459fc9d77227 100644 --- a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js +++ b/dom/system/gonk/tests/test_ril_worker_sms_cdma.js @@ -154,7 +154,7 @@ function pduToParcelData(cdmaPduHelper, pdu) { writeByte(0); // Bearer Data Length - let dataLength = pdu.bearerData.length; + dataLength = pdu.bearerData.length; writeByte(dataLength); // Bearer Data diff --git a/dom/system/gonk/tests/test_ril_worker_stk.js b/dom/system/gonk/tests/test_ril_worker_stk.js index 7842402e1da9..31de0b58e941 100644 --- a/dom/system/gonk/tests/test_ril_worker_stk.js +++ b/dom/system/gonk/tests/test_ril_worker_stk.js @@ -865,7 +865,7 @@ add_test(function test_stk_proactive_command_set_up_menu() { do_check_eq(tlv.value.typeOfCommand, STK_CMD_SET_UP_MENU); do_check_eq(tlv.value.commandQualifier, 0x00); - let menu = stkFactory.createParam(tlv.value, ctlvs); + menu = stkFactory.createParam(tlv.value, ctlvs); do_check_eq(menu.title, "Title"); do_check_eq(menu.items[0].identifier, 1); do_check_eq(menu.items[0].text, "item 1"); diff --git a/dom/system/tests/marionette/test_proximity_init.js b/dom/system/tests/marionette/test_proximity_init.js index 7fe55ded4555..1a56e6e463fa 100644 --- a/dom/system/tests/marionette/test_proximity_init.js +++ b/dom/system/tests/marionette/test_proximity_init.js @@ -24,7 +24,7 @@ function testEventInit() { // Test UserProximityEvent initialization log("Verifying UserProximityEvent constructor."); - let event = new UserProximityEvent("userproximity", {near: true}); + event = new UserProximityEvent("userproximity", {near: true}); is(event.type, "userproximity", "event type"); ok(event.near, "Initialization of UserProximityEvent"); verifyDefaultStatus(); diff --git a/dom/tests/mochitest/chrome/queryCaretRectUnix.html b/dom/tests/mochitest/chrome/queryCaretRectUnix.html index 1a2d4bd8a49b..0e419fc65f1a 100644 --- a/dom/tests/mochitest/chrome/queryCaretRectUnix.html +++ b/dom/tests/mochitest/chrome/queryCaretRectUnix.html @@ -140,7 +140,7 @@ offset = cp.offset; input.selectionStart = input.selectionEnd = offset; - let selection = getSelection(text); + selection = getSelection(text); testCaretPosition(domWinUtils, input.selectionStart, { min: { left: 390, top: 380 }, diff --git a/dom/tests/mochitest/chrome/queryCaretRectWin.html b/dom/tests/mochitest/chrome/queryCaretRectWin.html index edbc9337ad2a..dadbbd0949a4 100644 --- a/dom/tests/mochitest/chrome/queryCaretRectWin.html +++ b/dom/tests/mochitest/chrome/queryCaretRectWin.html @@ -149,7 +149,7 @@ offset = cp.offset; input.selectionStart = input.selectionEnd = offset; - let selection = getSelection(text); + selection = getSelection(text); testCaretPosition(domWinUtils, input.selectionStart, { min: { left: 390, top: 380 }, diff --git a/dom/tests/mochitest/chrome/selectAtPoint.html b/dom/tests/mochitest/chrome/selectAtPoint.html index cfe2e350f77d..dcf98c2d6db9 100644 --- a/dom/tests/mochitest/chrome/selectAtPoint.html +++ b/dom/tests/mochitest/chrome/selectAtPoint.html @@ -113,19 +113,19 @@ checkSelection(document, "SELECT_PARAGRAPH", "ttestselection1 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos. Ei munere officiis assentior pro, nibh decore ius at."); // Centered on the second character in the sentence div - let targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)), - yPos: rect.top + (charDims.height / 2) }; + targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)), + yPos: rect.top + (charDims.height / 2) }; setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER); checkSelection(document, "SELECT_CHARACTER", "te"); setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CLUSTER); checkSelection(document, "SELECT_CLUSTER", "te"); // Separate character blocks in a word 't(te)s(ts)election1' - let targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)), - yPos: rect.top + (charDims.height / 2) }; + targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)), + yPos: rect.top + (charDims.height / 2) }; setStart(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER); - let targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)), - yPos: rect.top + (charDims.height / 2) }; + targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)), + yPos: rect.top + (charDims.height / 2) }; setEnd(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER); if (isLinux || isMac) { // XXX I think this is a bug, the right hand selection is 4.5 characters over with a @@ -141,12 +141,12 @@ // Second div in the main page - let div = document.getElementById("div2"); - let rect = div.getBoundingClientRect(); + div = document.getElementById("div2"); + rect = div.getBoundingClientRect(); // Centered on the first line, first character in the paragraph div - let targetPoint = { xPos: rect.left + (charDims.width / 2), - yPos: rect.top + (charDims.height / 2) }; + targetPoint = { xPos: rect.left + (charDims.width / 2), + yPos: rect.top + (charDims.height / 2) }; setSingle(dwu, targetPoint.xPos + 50, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_PARAGRAPH); checkSelection(document, "SELECT_PARAGRAPH", "Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos."); @@ -162,10 +162,10 @@ frame.contentWindow.scrollTo(0, 0); - let rect = frame.getBoundingClientRect(); + rect = frame.getBoundingClientRect(); - let targetPoint = { xPos: charDims.width / 2, - yPos: charDims.height / 2 }; + targetPoint = { xPos: charDims.width / 2, + yPos: charDims.height / 2 }; setSingle(dwuFrame, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE); checkSelection(frame.contentWindow.document, "SELECT_WORDNOSPACE", "ttestselection2"); setSingle(dwuFrame, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORD); diff --git a/dom/tests/mochitest/whatwg/postMessage_structured_clone_helper.js b/dom/tests/mochitest/whatwg/postMessage_structured_clone_helper.js index 77d30da434d0..d56bc329880a 100644 --- a/dom/tests/mochitest/whatwg/postMessage_structured_clone_helper.js +++ b/dom/tests/mochitest/whatwg/postMessage_structured_clone_helper.js @@ -30,7 +30,7 @@ function getTestContent() recursiveobj.expando = recursiveobj; yield recursiveobj; - let obj = new Object(); + obj = new Object(); obj.expando1 = 1; obj.foo = new Object(); obj.foo.bar = 2; @@ -47,7 +47,7 @@ function getTestContent() yield obj; let diamond = new Object(); - let obj = new Object(); + obj = new Object(); obj.foo = "foo"; obj.bar = 92; obj.backref = diamond; @@ -56,7 +56,7 @@ function getTestContent() yield diamond; let doubleref = new Object(); - let obj = new Object(); + obj = new Object(); doubleref.ref1 = obj; doubleref.ref2 = obj; yield doubleref; diff --git a/dom/wappush/tests/test_si_pdu_helper.js b/dom/wappush/tests/test_si_pdu_helper.js index 9ac74343a826..7609e45474d0 100644 --- a/dom/wappush/tests/test_si_pdu_helper.js +++ b/dom/wappush/tests/test_si_pdu_helper.js @@ -55,7 +55,7 @@ add_test(function test_si_parse_wbxml_empty() { ]); data.offset = 0; let result = ""; - let msg = SI.PduHelper.parse(data, contentType); + msg = SI.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); @@ -79,7 +79,7 @@ add_test(function test_si_parse_wbxml_empty_public_id_string_table() { ]); data.offset = 0; let result = ""; - let msg = SI.PduHelper.parse(data, contentType); + msg = SI.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); @@ -104,7 +104,7 @@ add_test(function test_si_parse_wbxml_with_href() { data.offset = 0; let result = "" + "Check this website"; - let msg = SI.PduHelper.parse(data, contentType); + msg = SI.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); @@ -131,7 +131,7 @@ add_test(function test_si_parse_wbxml_with_href_reserved_char() { data.offset = 0; let result = "" + "Check this website"; - let msg = SI.PduHelper.parse(data, contentType); + msg = SI.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); @@ -162,7 +162,7 @@ add_test(function test_si_parse_wbxml_with_href_date() { let result = "" + "You have 4 new emails"; - let msg = SI.PduHelper.parse(data, contentType); + msg = SI.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); @@ -193,7 +193,7 @@ add_test(function test_si_parse_wbxml_with_attr_string_table() { let result = "" + "You have 4 new emails"; - let msg = SI.PduHelper.parse(data, contentType); + msg = SI.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); diff --git a/dom/wappush/tests/test_sl_pdu_helper.js b/dom/wappush/tests/test_sl_pdu_helper.js index 9b6a0e7ebb99..482c512d789c 100644 --- a/dom/wappush/tests/test_sl_pdu_helper.js +++ b/dom/wappush/tests/test_sl_pdu_helper.js @@ -51,7 +51,7 @@ add_test(function test_sl_parse_wbxml() { ]); data.offset = 0; let result = ""; - let msg = SL.PduHelper.parse(data, contentType); + msg = SL.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); @@ -61,7 +61,7 @@ add_test(function test_sl_parse_wbxml() { * SL compressed by WBXML, with public ID stored in string table */ add_test(function test_sl_parse_wbxml_public_id_string_table() { - let msg = {}; + let msg = {}; let contentType = ""; let data = {}; @@ -76,7 +76,7 @@ add_test(function test_sl_parse_wbxml_public_id_string_table() { ]); data.offset = 0; let result = ""; - let msg = SL.PduHelper.parse(data, contentType); + msg = SL.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); @@ -98,7 +98,7 @@ add_test(function test_sl_parse_wbxml_with_string_table() { ]); data.offset = 0; let result = ""; - let msg = SL.PduHelper.parse(data, contentType); + msg = SL.PduHelper.parse(data, contentType); do_check_eq(msg.content, result); run_next_test(); diff --git a/dom/workers/test/test_multi_sharedWorker_lifetimes.html b/dom/workers/test/test_multi_sharedWorker_lifetimes.html index 98ecbc038d46..a4f8755dbf6f 100644 --- a/dom/workers/test/test_multi_sharedWorker_lifetimes.html +++ b/dom/workers/test/test_multi_sharedWorker_lifetimes.html @@ -70,7 +70,7 @@ // Navigate when the bfcache is disabled. info("Navigating to about:blank"); - let frame = document.getElementById("frame"); + frame = document.getElementById("frame"); frame.onload = sendToGenerator; frame.src = "about:blank"; frame.contentWindow.document.body.offsetTop; @@ -86,7 +86,7 @@ frame = frame.contentWindow; frame.postMessage({ command: "retrieve" }, "*"); - let event = yield undefined; + event = yield undefined; ok(event instanceof MessageEvent, "Got a MessageEvent"); is(event.source, frame, "Correct window got the event"); is(event.data.type, "result", "Got a result message"); @@ -108,7 +108,7 @@ yield undefined; // Navigate when the bfcache is enabled. - let frame = document.getElementById("frame"); + frame = document.getElementById("frame"); frame.onload = sendToGenerator; info("Navigating to about:blank"); @@ -136,7 +136,7 @@ frame = frame.contentWindow; frame.postMessage({ command: "retrieve" }, "*"); - let event = yield undefined; + event = yield undefined; ok(event instanceof MessageEvent, "Got a MessageEvent"); is(event.source, frame, "Correct window got the event"); is(event.data.type, "result", "Got a result message"); diff --git a/dom/xbl/test/test_bug591198.html b/dom/xbl/test/test_bug591198.html index 4277080d0bf1..2c7df3613db3 100644 --- a/dom/xbl/test/test_bug591198.html +++ b/dom/xbl/test/test_bug591198.html @@ -31,7 +31,7 @@ function runTest() { is(res.anonChildCount, 2, "correct number of anon children"); iframe.src = "http://noxul.example.com/tests/dom/xbl/test/file_bug591198_inner.html"; - let res = (yield); + res = (yield); is(res.widths[0], res.widths[1], "binding was not rendered"); isnot(res.widths[0], res.widths[2], "binding was not rendered"); is("anonChildCount" in res, false, "no anon children"); diff --git a/extensions/cookie/test/unit/test_cookies_async_failure.js b/extensions/cookie/test/unit/test_cookies_async_failure.js index a1940125b356..f46220ca8c03 100644 --- a/extensions/cookie/test/unit/test_cookies_async_failure.js +++ b/extensions/cookie/test/unit/test_cookies_async_failure.js @@ -352,7 +352,7 @@ function run_test_3(generator) // Close the profile. do_close_profile(sub_generator); yield; - let db = Services.storage.openDatabase(do_get_cookie_file(profile)); + db = Services.storage.openDatabase(do_get_cookie_file(profile)); do_check_eq(do_count_cookies_in_db(db), 0); db.close(); diff --git a/extensions/cookie/test/unit/test_domain_eviction.js b/extensions/cookie/test/unit/test_domain_eviction.js index 7194850dafc9..3567c5ddd76d 100644 --- a/extensions/cookie/test/unit/test_domain_eviction.js +++ b/extensions/cookie/test/unit/test_domain_eviction.js @@ -77,7 +77,7 @@ function do_run_test() false, false, false, futureExpiry); do_check_eq(countCookies("captchart.com", "captchart.com"), 50); - let enumerator = Services.cookiemgr.getCookiesFromHost("captchart.com"); + enumerator = Services.cookiemgr.getCookiesFromHost("captchart.com"); while (enumerator.hasMoreElements()) { let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); do_check_true(cookie.expiry == futureExpiry); diff --git a/extensions/cookie/test/unit/test_schema_2_migration.js b/extensions/cookie/test/unit/test_schema_2_migration.js index 280847d87713..0990de58af65 100644 --- a/extensions/cookie/test/unit/test_schema_2_migration.js +++ b/extensions/cookie/test/unit/test_schema_2_migration.js @@ -115,7 +115,7 @@ function do_run_test() { // Attempt to add a cookie with the same (name, host, path) values as another // cookie. This should succeed since we have a REPLACE clause for conflict on // the unique index. - let cookie = new Cookie("oh", "hai", "baz.com", "/", + cookie = new Cookie("oh", "hai", "baz.com", "/", futureExpiry, now, now + 100, false, false, false); schema2db.insertCookie(cookie); diff --git a/extensions/cookie/test/unit/test_schema_3_migration.js b/extensions/cookie/test/unit/test_schema_3_migration.js index f53ab350bc33..79b4c1039fae 100644 --- a/extensions/cookie/test/unit/test_schema_3_migration.js +++ b/extensions/cookie/test/unit/test_schema_3_migration.js @@ -116,8 +116,8 @@ function do_run_test() { // Test the expected set of cookies. do_check_eq(Services.cookiemgr.countCookiesFromHost("cat.com"), 20); - let enumerator = Services.cookiemgr.getCookiesFromHost("cat.com"); - let cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); + enumerator = Services.cookiemgr.getCookiesFromHost("cat.com"); + cookie = enumerator.getNext().QueryInterface(Ci.nsICookie2); do_check_eq(cookie.creationTime, 0); finish_test(); diff --git a/image/test/unit/test_moz_icon_uri.js b/image/test/unit/test_moz_icon_uri.js index c223027bfb48..c179c9f06b44 100644 --- a/image/test/unit/test_moz_icon_uri.js +++ b/image/test/unit/test_moz_icon_uri.js @@ -113,7 +113,7 @@ function run_test() { exception = false; // reset exception value iconURI = uri.QueryInterface(Ci.nsIMozIconURI); - let fileURL = null; + fileURL = null; try { fileURL = iconURI.iconURL.QueryInterface(Ci.nsIFileURL); } catch (e) { diff --git a/js/xpconnect/tests/unit/test_sandbox_metadata.js b/js/xpconnect/tests/unit/test_sandbox_metadata.js index 127585dee871..c3db2c1b2f72 100644 --- a/js/xpconnect/tests/unit/test_sandbox_metadata.js +++ b/js/xpconnect/tests/unit/test_sandbox_metadata.js @@ -14,7 +14,7 @@ function run_test() do_check_eq(Components.utils.getSandboxMetadata(sandbox), "test metadata"); do_check_eq(Components.utils.getSandboxAddonId(sandbox), "12345"); - let sandbox = Components.utils.Sandbox("http://www.blah.com", { + sandbox = Components.utils.Sandbox("http://www.blah.com", { metadata: { foopy: { bar: 2 }, baz: "hi" } }); diff --git a/mobile/android/base/tests/testHomeProvider.js b/mobile/android/base/tests/testHomeProvider.js index caaa7f2ad5ae..c2c43b498319 100644 --- a/mobile/android/base/tests/testHomeProvider.js +++ b/mobile/android/base/tests/testHomeProvider.js @@ -66,7 +66,7 @@ add_task(function test_save_and_delete() { yield storage.deleteAll(); // Make sure the data was deleted. - let result = yield db.execute("SELECT * FROM items"); + result = yield db.execute("SELECT * FROM items"); do_check_eq(result.length, 0); db.close(); diff --git a/mobile/android/base/tests/testMozPay.js b/mobile/android/base/tests/testMozPay.js index f268f55496ea..d5dbe216d90a 100644 --- a/mobile/android/base/tests/testMozPay.js +++ b/mobile/android/base/tests/testMozPay.js @@ -81,7 +81,7 @@ add_task(function test_default() { yield deferred.promise; deferred = Promise.defer(); - let id = getRequestId(1); + id = getRequestId(1); shouldPass = false; ui.showPaymentFlow(id, { diff --git a/modules/libpref/test/unit/test_libPrefs.js b/modules/libpref/test/unit/test_libPrefs.js index bb77a5b9fe56..9fb883e88df5 100644 --- a/modules/libpref/test/unit/test_libPrefs.js +++ b/modules/libpref/test/unit/test_libPrefs.js @@ -166,22 +166,22 @@ function run_test() { // int ... pb.setIntPref("UserPref.root.intPref", 23); - let pb_1 = ps.getBranch("UserPref.root."); + pb_1 = ps.getBranch("UserPref.root."); do_check_eq(pb_1.getIntPref("intPref"), 23); - let pb_2 = ps.getBranch("UserPref.root.intPref"); + pb_2 = ps.getBranch("UserPref.root.intPref"); do_check_eq(pb_2.getIntPref(""), 23); pb_2.setIntPref(".anotherPref", 69); - let pb_3 = ps.getBranch("UserPref.root.intPre"); + pb_3 = ps.getBranch("UserPref.root.intPre"); do_check_eq(pb_3.getIntPref("f.anotherPref"), 69); // char... pb.setCharPref("UserPref.root.charPref", "_char"); - let pb_1 = ps.getBranch("UserPref.root."); + pb_1 = ps.getBranch("UserPref.root."); do_check_eq(pb_1.getCharPref("charPref"), "_char"); - let pb_2 = ps.getBranch("UserPref.root.charPref"); + pb_2 = ps.getBranch("UserPref.root.charPref"); do_check_eq(pb_2.getCharPref(""), "_char"); pb_2.setCharPref(".anotherPref", "_another"); - let pb_3 = ps.getBranch("UserPref.root.charPre"); + pb_3 = ps.getBranch("UserPref.root.charPre"); do_check_eq(pb_3.getCharPref("f.anotherPref"), "_another"); //**************************************************************************// diff --git a/services/common/tests/unit/test_storage_server.js b/services/common/tests/unit/test_storage_server.js index 1e85b595f5fd..04b4dfbbbdfe 100644 --- a/services/common/tests/unit/test_storage_server.js +++ b/services/common/tests/unit/test_storage_server.js @@ -152,7 +152,7 @@ add_test(function test_url_parsing() { // Check that we can parse a collection URI. parts = server.pathRE.exec("/2.0/123/storage/crypto"); - let [all, version, user, first, rest] = parts; + [all, version, user, first, rest] = parts; do_check_eq(all, "/2.0/123/storage/crypto"); do_check_eq(version, "2.0"); do_check_eq(user, "123"); @@ -165,7 +165,7 @@ add_test(function test_url_parsing() { // storage alone is a valid request. parts = server.pathRE.exec("/2.0/123456/storage"); - let [all, version, user, first, rest] = parts; + [all, version, user, first, rest] = parts; do_check_eq(all, "/2.0/123456/storage"); do_check_eq(version, "2.0"); do_check_eq(user, "123456"); @@ -173,7 +173,8 @@ add_test(function test_url_parsing() { do_check_eq(rest, undefined); parts = server.storageRE.exec("storage"); - let [all, storage, collection, id] = parts; + let storage, collection, id; + [all, storage, collection, id] = parts; do_check_eq(all, "storage"); do_check_eq(collection, undefined); @@ -213,8 +214,8 @@ add_test(function test_info_collections() { _("Creating an empty collection should result in collection appearing."); let coll = server.createCollection("123", "col1"); - let request = localRequest(server, path, "123", "password"); - let error = doGetRequest(request); + request = localRequest(server, path, "123", "password"); + error = doGetRequest(request); do_check_eq(error, null); do_check_eq(request.response.status, 200); let info = JSON.parse(request.response.body); @@ -322,10 +323,10 @@ add_test(function test_bso_if_modified_since_304() { do_check_eq(request.response.status, 304); do_check_false("content-type" in request.response.headers); - let request = localRequest(server, "/2.0/123/storage/test/bso", + request = localRequest(server, "/2.0/123/storage/test/bso", "123", "password"); request.setHeader("X-If-Modified-Since", "" + (server.serverTime() - 20000)); - let error = doGetRequest(request); + error = doGetRequest(request); do_check_eq(null, error); do_check_eq(request.response.status, 200); do_check_eq(request.response.headers["content-type"], "application/json"); @@ -359,11 +360,11 @@ add_test(function test_bso_if_unmodified_since() { do_check_eq(request.response.status, 412); _("Ensure we get a 204 if update goes through."); - let request = localRequest(server, "/2.0/123/storage/test/bso", - "123", "password"); + request = localRequest(server, "/2.0/123/storage/test/bso", + "123", "password"); request.setHeader("Content-Type", "application/json"); request.setHeader("X-If-Unmodified-Since", time + 1); - let error = doPutRequest(request, payload); + error = doPutRequest(request, payload); do_check_eq(null, error); do_check_eq(request.response.status, 204); do_check_true(coll.timestamp > time); @@ -371,11 +372,11 @@ add_test(function test_bso_if_unmodified_since() { // Not sure why a client would send X-If-Unmodified-Since if a BSO doesn't // exist. But, why not test it? _("Ensure we get a 201 if creation goes through."); - let request = localRequest(server, "/2.0/123/storage/test/none", - "123", "password"); + request = localRequest(server, "/2.0/123/storage/test/none", + "123", "password"); request.setHeader("Content-Type", "application/json"); request.setHeader("X-If-Unmodified-Since", time); - let error = doPutRequest(request, payload); + error = doPutRequest(request, payload); do_check_eq(null, error); do_check_eq(request.response.status, 201); @@ -432,9 +433,9 @@ add_test(function test_bso_delete_exists() { do_check_true(coll.timestamp > timestamp); _("On next request the BSO should not exist."); - let request = localRequest(server, "/2.0/123/storage/test/myid", - "123", "password"); - let error = doGetRequest(request); + request = localRequest(server, "/2.0/123/storage/test/myid", + "123", "password"); + error = doGetRequest(request); do_check_eq(error, null); do_check_eq(request.response.status, 404); @@ -463,9 +464,9 @@ add_test(function test_bso_delete_unmodified() { do_check_neq(coll.bso("myid"), null); _("Issuing a DELETE with a newer time should work."); - let request = localRequest(server, path, "123", "password"); + request = localRequest(server, path, "123", "password"); request.setHeader("X-If-Unmodified-Since", modified + 1000); - let error = doDeleteRequest(request); + error = doDeleteRequest(request); do_check_eq(error, null); do_check_eq(request.response.status, 204); do_check_true(coll.bso("myid").deleted); @@ -494,7 +495,7 @@ add_test(function test_collection_get_unmodified_since() { let request2 = localRequest(server, "/2.0/123/storage/testcoll", "123", "password"); request2.setHeader("X-If-Unmodified-Since", serverModified - 1); - let error = doGetRequest(request2); + error = doGetRequest(request2); do_check_null(error); do_check_eq(request2.response.status, 412); @@ -522,7 +523,7 @@ add_test(function test_bso_get_unmodified_since() { let request2 = localRequest(server, "/2.0/123/storage/testcoll/bso0", "123", "password"); request2.setHeader("X-If-Unmodified-Since", serverModified - 1); - let error = doGetRequest(request2); + error = doGetRequest(request2); do_check_null(error); do_check_eq(request2.response.status, 412); diff --git a/services/common/tests/unit/test_storageservice_bso.js b/services/common/tests/unit/test_storageservice_bso.js index b4ad27307dc8..05b9bbecda7d 100644 --- a/services/common/tests/unit/test_storageservice_bso.js +++ b/services/common/tests/unit/test_storageservice_bso.js @@ -21,12 +21,12 @@ add_test(function test_bso_constructor() { do_check_eq(bso.sortindex, 0); do_check_eq(bso.ttl, null); - let bso = new BasicStorageObject("foobar"); + bso = new BasicStorageObject("foobar"); do_check_eq(bso.id, "foobar"); do_check_eq(bso.collection, null); do_check_attribute_count(bso.data, 0); - let bso = new BasicStorageObject("foo", "coll"); + bso = new BasicStorageObject("foo", "coll"); do_check_eq(bso.id, "foo"); do_check_eq(bso.collection, "coll"); do_check_attribute_count(bso.data, 0); @@ -66,8 +66,8 @@ add_test(function test_bso_deserialize() { do_check_eq(bso.modified, 1223145532); _("Invalid JSON."); - let json = '{id: "foobar}'; - let bso = new BasicStorageObject(); + json = '{id: "foobar}'; + bso = new BasicStorageObject(); try { bso.deserialize(json); do_check_true(false); @@ -76,8 +76,8 @@ add_test(function test_bso_deserialize() { } _("Invalid key in JSON."); - let json = '{"id": "foo", "payload": "pay", "BADKEY": "irrelevant"}'; - let bso = new BasicStorageObject(); + json = '{"id": "foo", "payload": "pay", "BADKEY": "irrelevant"}'; + bso = new BasicStorageObject(); try { bso.deserialize(json); do_check_true(false); @@ -87,14 +87,14 @@ add_test(function test_bso_deserialize() { } _("Loading native JS objects works."); - let bso = new BasicStorageObject(); + bso = new BasicStorageObject(); bso.deserialize({id: "foo", payload: "pay"}); do_check_neq(bso, null); do_check_eq(bso.id, "foo"); do_check_eq(bso.payload, "pay"); _("Passing invalid type is caught."); - let bso = new BasicStorageObject(); + bso = new BasicStorageObject(); try { bso.deserialize(["foo", "bar"]); do_check_true(false); diff --git a/services/crypto/tests/unit/test_crypto_crypt.js b/services/crypto/tests/unit/test_crypto_crypt.js index 60ac15b0301d..0bbede021aae 100644 --- a/services/crypto/tests/unit/test_crypto_crypt.js +++ b/services/crypto/tests/unit/test_crypto_crypt.js @@ -38,7 +38,7 @@ function test_key_memoization() { do_check_eq(c, 0); let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); do_check_eq(c, 1); - let cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); + cipherText = cryptoSvc.encrypt("Hello, world.", key, iv); do_check_eq(c, 1); // ... as should decryption. diff --git a/services/crypto/tests/unit/test_utils_httpmac.js b/services/crypto/tests/unit/test_utils_httpmac.js index 64a8c82a6972..67b337373e3a 100644 --- a/services/crypto/tests/unit/test_utils_httpmac.js +++ b/services/crypto/tests/unit/test_utils_httpmac.js @@ -32,7 +32,7 @@ add_test(function test_sha1() { let ext = "EXTRA DATA; foo,bar=1"; - let result = CryptoUtils.computeHTTPMACSHA1(id, key, method, uri, + result = CryptoUtils.computeHTTPMACSHA1(id, key, method, uri, {ts: ts, nonce: nonce, ext: ext}); do_check_eq(btoa(result.mac), "bNf4Fnt5k6DnhmyipLPkuZroH68="); do_check_eq(result.getHeader(), @@ -56,13 +56,13 @@ add_test(function test_nonce_length() { let result = get_mac(12); do_check_eq(12, atob(result.nonce).length); - let result = get_mac(2); + result = get_mac(2); do_check_eq(2, atob(result.nonce).length); - let result = get_mac(0); + result = get_mac(0); do_check_eq(8, atob(result.nonce).length); - let result = get_mac(-1); + result = get_mac(-1); do_check_eq(8, atob(result.nonce).length); run_next_test(); diff --git a/services/fxaccounts/tests/xpcshell/test_accounts.js b/services/fxaccounts/tests/xpcshell/test_accounts.js index 9844cc6e2fc4..9443dcb9bb4a 100644 --- a/services/fxaccounts/tests/xpcshell/test_accounts.js +++ b/services/fxaccounts/tests/xpcshell/test_accounts.js @@ -162,7 +162,7 @@ add_task(function test_get_signed_in_user_initially_unset() { yield account.setSignedInUser(credentials); - let result = yield account.getSignedInUser(); + result = yield account.getSignedInUser(); do_check_eq(result.email, credentials.email); do_check_eq(result.assertion, credentials.assertion); do_check_eq(result.kB, credentials.kB); @@ -170,7 +170,7 @@ add_task(function test_get_signed_in_user_initially_unset() { // Delete the memory cache and force the user // to be read and parsed from storage (e.g. disk via JSONStorage). delete account.internal.signedInUser; - let result = yield account.getSignedInUser(); + result = yield account.getSignedInUser(); do_check_eq(result.email, credentials.email); do_check_eq(result.assertion, credentials.assertion); do_check_eq(result.kB, credentials.kB); @@ -180,7 +180,7 @@ add_task(function test_get_signed_in_user_initially_unset() { yield account.signOut(localOnly); // user should be undefined after sign out - let result = yield account.getSignedInUser(); + result = yield account.getSignedInUser(); do_check_eq(result, null); }); diff --git a/services/fxaccounts/tests/xpcshell/test_client.js b/services/fxaccounts/tests/xpcshell/test_client.js index fad064f49d37..8d246e0ec3f0 100644 --- a/services/fxaccounts/tests/xpcshell/test_client.js +++ b/services/fxaccounts/tests/xpcshell/test_client.js @@ -277,14 +277,14 @@ add_task(function test_signIn() { do_check_eq(undefined, result.keyFetchToken); // Login with retrieving optional keys - let result = yield client.signIn('you@example.com', 'bigsecret', true); + result = yield client.signIn('you@example.com', 'bigsecret', true); do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken); do_check_eq(result.unwrapBKey, "65970516211062112e955d6420bebe020269d6b6a91ebd288319fc8d0cb49624"); do_check_eq("keyFetchToken", result.keyFetchToken); // Retry due to wrong email capitalization - let result = yield client.signIn('You@example.com', 'bigsecret', true); + result = yield client.signIn('You@example.com', 'bigsecret', true); do_check_eq(FAKE_SESSION_TOKEN, result.sessionToken); do_check_eq(result.unwrapBKey, "65970516211062112e955d6420bebe020269d6b6a91ebd288319fc8d0cb49624"); diff --git a/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js b/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js index a9cf5f4499bd..872e9956824c 100644 --- a/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js +++ b/services/fxaccounts/tests/xpcshell/test_loginmgr_storage.js @@ -128,7 +128,7 @@ add_task(function test_migrationMPUnlocked() { Assert.deepEqual(data, creds, "we got all the data back"); // and verify it was actually migrated - re-read signedInUser back. - let data = yield CommonUtils.readJSON(path); + data = yield CommonUtils.readJSON(path); Assert.strictEqual(data.accountData.email, creds.email, "correct email in the clear text"); Assert.strictEqual(data.accountData.sessionToken, creds.sessionToken, "correct sessionToken in the clear text"); @@ -255,7 +255,7 @@ add_task(function test_consistentWithMPEdgeCases() { // Make a new FxA instance (otherwise the values in memory will be used.) // Because we haven't overridden _isLoggedIn for this new instance it will // treat the MP as unlocked. - let fxa = new FxAccounts({}); + fxa = new FxAccounts({}); let accountData = yield fxa.getSignedInUser(); Assert.strictEqual(accountData.email, creds2.email); diff --git a/services/sync/tests/unit/test_addons_reconciler.js b/services/sync/tests/unit/test_addons_reconciler.js index 40b0b8acd0d3..8cfa37d78f42 100644 --- a/services/sync/tests/unit/test_addons_reconciler.js +++ b/services/sync/tests/unit/test_addons_reconciler.js @@ -179,7 +179,7 @@ add_test(function test_prune_changes_before_date() { do_check_eq(2, reconciler._changes.length); _("Ensure pruning a single item works."); - let threshold = new Date(young.getTime() - 1000); + threshold = new Date(young.getTime() - 1000); reconciler.pruneChangesBeforeDate(threshold); do_check_eq(1, reconciler._changes.length); do_check_neq(undefined, reconciler._changes[0]); diff --git a/services/sync/tests/unit/test_bookmark_engine.js b/services/sync/tests/unit/test_bookmark_engine.js index 2caaea692384..bd4c740cbcd3 100644 --- a/services/sync/tests/unit/test_bookmark_engine.js +++ b/services/sync/tests/unit/test_bookmark_engine.js @@ -380,7 +380,6 @@ add_test(function test_bookmark_guidMap_fail() { let engine = new BookmarksEngine(Service); let store = engine._store; - let store = engine._store; let server = serverForFoo(engine); let coll = server.user("foo").collection("bookmarks"); new SyncTestingInfrastructure(server.server); diff --git a/services/sync/tests/unit/test_httpd_sync_server.js b/services/sync/tests/unit/test_httpd_sync_server.js index 194f8ac1d1d7..943dbfd738f6 100644 --- a/services/sync/tests/unit/test_httpd_sync_server.js +++ b/services/sync/tests/unit/test_httpd_sync_server.js @@ -36,7 +36,7 @@ add_test(function test_url_parsing() { // Check that we can parse a collection URI. parts = server.pathRE.exec("/1.1/johnsmith/storage/crypto"); - let [all, version, username, first, rest] = parts; + [all, version, username, first, rest] = parts; do_check_eq(all, "/1.1/johnsmith/storage/crypto"); do_check_eq(version, "1.1"); do_check_eq(username, "johnsmith"); @@ -49,7 +49,7 @@ add_test(function test_url_parsing() { // storage alone is a valid request. parts = server.pathRE.exec("/1.1/johnsmith/storage"); - let [all, version, username, first, rest] = parts; + [all, version, username, first, rest] = parts; do_check_eq(all, "/1.1/johnsmith/storage"); do_check_eq(version, "1.1"); do_check_eq(username, "johnsmith"); @@ -57,7 +57,8 @@ add_test(function test_url_parsing() { do_check_eq(rest, undefined); parts = server.storageRE.exec("storage"); - let [all, storage, collection, id] = parts; + let storage, collection, id; + [all, storage, collection, id] = parts; do_check_eq(all, "storage"); do_check_eq(collection, undefined); diff --git a/services/sync/tests/unit/test_resource.js b/services/sync/tests/unit/test_resource.js index 93dfe46b28a6..027d662b41fd 100644 --- a/services/sync/tests/unit/test_resource.js +++ b/services/sync/tests/unit/test_resource.js @@ -153,7 +153,7 @@ function run_test() { do_test_pending(); - logger = Log.repository.getLogger('Test'); + let logger = Log.repository.getLogger('Test'); Log.repository.rootLogger.addAppender(new Log.DumpAppender()); let server = httpd_setup({ @@ -206,7 +206,7 @@ function run_test() { do_check_eq(res.data, content); // Observe logging messages. - let logger = res._log; + logger = res._log; let dbg = logger.debug; let debugMessages = []; logger.debug = function (msg) { diff --git a/services/sync/tests/unit/test_syncengine_sync.js b/services/sync/tests/unit/test_syncengine_sync.js index b8b5f7d0ce09..6a6d047bf54a 100644 --- a/services/sync/tests/unit/test_syncengine_sync.js +++ b/services/sync/tests/unit/test_syncengine_sync.js @@ -401,8 +401,8 @@ add_test(function test_processIncoming_reconcile_local_deleted() { let wbo = new ServerWBO("DUPE_INCOMING", record, now + 2); server.insertWBO(user, "rotary", wbo); - let record = encryptPayload({id: "DUPE_LOCAL", denomination: "local"}); - let wbo = new ServerWBO("DUPE_LOCAL", record, now - 1); + record = encryptPayload({id: "DUPE_LOCAL", denomination: "local"}); + wbo = new ServerWBO("DUPE_LOCAL", record, now - 1); server.insertWBO(user, "rotary", wbo); engine._store.create({id: "DUPE_LOCAL", denomination: "local"}); @@ -475,7 +475,7 @@ add_test(function test_processIncoming_reconcile_locally_deleted_dupe_new() { do_check_empty(engine._store.items); let collection = server.getCollection(user, "rotary"); do_check_eq(1, collection.count()); - let wbo = collection.wbo("DUPE_INCOMING"); + wbo = collection.wbo("DUPE_INCOMING"); do_check_neq(null, wbo); let payload = JSON.parse(JSON.parse(wbo.payload).ciphertext); do_check_true(payload.deleted); @@ -515,7 +515,7 @@ add_test(function test_processIncoming_reconcile_locally_deleted_dupe_old() { let collection = server.getCollection(user, "rotary"); do_check_eq(1, collection.count()); - let wbo = collection.wbo("DUPE_INCOMING"); + wbo = collection.wbo("DUPE_INCOMING"); let payload = JSON.parse(JSON.parse(wbo.payload).ciphertext); do_check_eq("incoming", payload.denomination); @@ -551,7 +551,7 @@ add_test(function test_processIncoming_reconcile_changed_dupe() { // have its payload set to what was in the local record. let collection = server.getCollection(user, "rotary"); do_check_eq(1, collection.count()); - let wbo = collection.wbo("DUPE_INCOMING"); + wbo = collection.wbo("DUPE_INCOMING"); do_check_neq(undefined, wbo); let payload = JSON.parse(JSON.parse(wbo.payload).ciphertext); do_check_eq("local", payload.denomination); @@ -589,7 +589,7 @@ add_test(function test_processIncoming_reconcile_changed_dupe_new() { // have its payload retained. let collection = server.getCollection(user, "rotary"); do_check_eq(1, collection.count()); - let wbo = collection.wbo("DUPE_INCOMING"); + wbo = collection.wbo("DUPE_INCOMING"); do_check_neq(undefined, wbo); let payload = JSON.parse(JSON.parse(wbo.payload).ciphertext); do_check_eq("incoming", payload.denomination); diff --git a/services/sync/tests/unit/test_tab_store.js b/services/sync/tests/unit/test_tab_store.js index c7a7a9568f69..dc733e48f843 100644 --- a/services/sync/tests/unit/test_tab_store.js +++ b/services/sync/tests/unit/test_tab_store.js @@ -27,19 +27,19 @@ function test_create() { do_check_eq(Svc.Prefs.get("notifyTabState"), 1); _("Create a second record"); - let rec = {id: "id2", - clientName: "clientName2", - cleartext: "cleartext2", - modified: 2000}; + rec = {id: "id2", + clientName: "clientName2", + cleartext: "cleartext2", + modified: 2000}; store.applyIncoming(rec); do_check_eq(store._remoteClients["id2"], "cleartext2"); do_check_eq(Svc.Prefs.get("notifyTabState"), 0); _("Create a third record"); - let rec = {id: "id3", - clientName: "clientName3", - cleartext: "cleartext3", - modified: 3000}; + rec = {id: "id3", + clientName: "clientName3", + cleartext: "cleartext3", + modified: 3000}; store.applyIncoming(rec); do_check_eq(store._remoteClients["id3"], "cleartext3"); do_check_eq(Svc.Prefs.get("notifyTabState"), 0); diff --git a/storage/test/unit/test_cache_size.js b/storage/test/unit/test_cache_size.js index fa71adaefb23..e0a5e8723c41 100644 --- a/storage/test/unit/test_cache_size.js +++ b/storage/test/unit/test_cache_size.js @@ -38,7 +38,7 @@ function check_size(dbOpener, file, pageSize, expectedCacheSize) db = dbOpener(file); // Check cache size is as expected. - let stmt = db.createStatement("PRAGMA cache_size"); + stmt = db.createStatement("PRAGMA cache_size"); do_check_true(stmt.executeStep()); do_check_eq(stmt.row.cache_size, expectedCacheSize); stmt.finalize(); diff --git a/storage/test/unit/test_storage_connection.js b/storage/test/unit/test_storage_connection.js index 23db1815e6db..be1cacfb90f5 100644 --- a/storage/test/unit/test_storage_connection.js +++ b/storage/test/unit/test_storage_connection.js @@ -541,7 +541,6 @@ add_task(function test_clone_no_optional_param_async() do_check_true(adb1 instanceof Ci.mozIStorageAsyncConnection); do_print("Cloning database"); - do_check_true(Components.isSuccessCode(result)); let adb2 = yield asyncClone(adb1); do_print("Testing that the cloned db is a mozIStorageAsyncConnection " + diff --git a/toolkit/components/contentprefs/tests/unit/test_contentPrefsCache.js b/toolkit/components/contentprefs/tests/unit/test_contentPrefsCache.js index 51a5c53aa774..61e3e8d8d290 100644 --- a/toolkit/components/contentprefs/tests/unit/test_contentPrefsCache.js +++ b/toolkit/components/contentprefs/tests/unit/test_contentPrefsCache.js @@ -225,7 +225,7 @@ function testCacheEviction(uri, prefName) { } function selectValue(stmt, columnName, param1, param2) { - let stmt = cps.DBConnection.createStatement(stmt); + stmt = cps.DBConnection.createStatement(stmt); if (param1) stmt.params.param1 = param1; diff --git a/toolkit/components/crashes/tests/xpcshell/test_crash_store.js b/toolkit/components/crashes/tests/xpcshell/test_crash_store.js index d17f1586abbc..a44dafd5725e 100644 --- a/toolkit/components/crashes/tests/xpcshell/test_crash_store.js +++ b/toolkit/components/crashes/tests/xpcshell/test_crash_store.js @@ -523,7 +523,7 @@ add_task(function* test_addSubmission() { Assert.ok(s.addSubmissionResult("crash1", "sub2", DUMMY_DATE_2, SUBMISSION_RESULT_OK)); - let submission = s.getSubmission("crash1", "sub2"); + submission = s.getSubmission("crash1", "sub2"); Assert.ok(!!submission); Assert.equal(submission.result, SUBMISSION_RESULT_OK); }); diff --git a/toolkit/components/ctypes/tests/chrome/test_ctypes.xul b/toolkit/components/ctypes/tests/chrome/test_ctypes.xul index 6bcaf9ad4a2b..32a83ad66d23 100644 --- a/toolkit/components/ctypes/tests/chrome/test_ctypes.xul +++ b/toolkit/components/ctypes/tests/chrome/test_ctypes.xul @@ -40,7 +40,7 @@ let dir = Components.classes["@mozilla.org/file/directory_service;1"] .getService(Components.interfaces.nsIProperties) .get("CurWorkD", Components.interfaces.nsILocalFile); - let path = location.pathname; + path = location.pathname; path = path.slice("content/".length, -1 * "/test_ctypes.xul".length); let components = path.split("/"); diff --git a/toolkit/components/ctypes/tests/unit/test_jsctypes.js b/toolkit/components/ctypes/tests/unit/test_jsctypes.js index d89fa1ca73a6..e05cbdb869f9 100644 --- a/toolkit/components/ctypes/tests/unit/test_jsctypes.js +++ b/toolkit/components/ctypes/tests/unit/test_jsctypes.js @@ -978,8 +978,8 @@ function run_float_tests(library, t, name, size) { eval("let f2 = " + f1.toSource()); do_check_eq(f1.value, f2.value); } - let vals = [Infinity, -Infinity, -0, 0, 1, -1, 1/3, -1/3, 1/4, -1/4, - 1e-14, -1e-14, 0xfffffffffffff000, -0xfffffffffffff000]; + vals = [Infinity, -Infinity, -0, 0, 1, -1, 1/3, -1/3, 1/4, -1/4, + 1e-14, -1e-14, 0xfffffffffffff000, -0xfffffffffffff000]; for (let i = 0; i < vals.length; i++) test_roundtrip(t, vals[i]); do_check_eq(t(NaN).toSource(), t.toSource() + "(NaN)"); @@ -1703,7 +1703,7 @@ function run_PointerType_tests() { let f = new f_t(); do_check_throws(function() { f.contents; }, Error); do_check_throws(function() { f.contents = 0; }, Error); - let f = f_t(5); + f = f_t(5); do_check_throws(function() { f.contents = 0; }, Error); do_check_eq(f.toSource(), 'FILE.ptr(ctypes.UInt64("0x5"))'); @@ -1731,7 +1731,7 @@ function run_PointerType_tests() { do_check_true(n.isNull() === false); // Test 'increment'/'decrement'. - let g_t = ctypes.StructType("g_t", [{ a: ctypes.int32_t }, { b: ctypes.double }]); + g_t = ctypes.StructType("g_t", [{ a: ctypes.int32_t }, { b: ctypes.double }]); let a_t = ctypes.ArrayType(g_t, 2); let a = new a_t(); a[0] = g_t(1, 2); @@ -2715,7 +2715,7 @@ function run_variadic_tests(library) { do_check_eq(result.value, 3 + 5 + 7 + 11); - let result = ctypes.int32_t.array(3)([1,1,1]), + result = ctypes.int32_t.array(3)([1,1,1]), v1 = ctypes.int32_t.array(4)([1,2,3,5]), v2 = ctypes.int32_t.array(3)([7,11,13]), vector_add_va = library.declare("test_vector_add_va_cdecl", diff --git a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js b/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js index 2405d29f2452..4fd1695d2d92 100644 --- a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js +++ b/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js @@ -144,7 +144,7 @@ add_task(function test_getPreferredDownloadsDirectory() // Should return the system downloads directory because the dir preference // is not set. Services.prefs.setIntPref(folderListPrefName, 2); - let downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory(); + downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory(); do_check_neq(downloadDir, ""); do_check_eq(downloadDir, systemDir); @@ -171,7 +171,7 @@ add_task(function test_getPreferredDownloadsDirectory() // Should return the system downloads directory because the folderList // preference is invalid Services.prefs.setIntPref(folderListPrefName, 999); - let downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory(); + downloadDir = yield DownloadIntegration.getPreferredDownloadsDirectory(); do_check_eq(downloadDir, systemDir); cleanup(); diff --git a/toolkit/components/osfile/tests/xpcshell/test_unique.js b/toolkit/components/osfile/tests/xpcshell/test_unique.js index 81aca99a0532..8aa81b803495 100644 --- a/toolkit/components/osfile/tests/xpcshell/test_unique.js +++ b/toolkit/components/osfile/tests/xpcshell/test_unique.js @@ -30,7 +30,7 @@ function testFiles(filename) { yield openedFile.file.close(); exists = yield OS.File.exists(openedFile.path); do_check_true(exists); - let fileInfo = yield OS.File.stat(openedFile.path); + fileInfo = yield OS.File.stat(openedFile.path); do_check_true(fileInfo.size == 0); // Ensure that openUnique() generates different file names each time, using the HEX number algorithm @@ -49,7 +49,7 @@ function testFiles(filename) { yield openedFile.file.close(); exists = yield OS.File.exists(openedFile.path); do_check_true(exists); - let fileInfo = yield OS.File.stat(openedFile.path); + fileInfo = yield OS.File.stat(openedFile.path); do_check_true(fileInfo.size == 0); // Ensure that openUnique() generates different human readable file names each time diff --git a/toolkit/components/passwordmgr/test/unit/test_storage.js b/toolkit/components/passwordmgr/test/unit/test_storage.js index 2a9979b52089..3b693340034c 100644 --- a/toolkit/components/passwordmgr/test/unit/test_storage.js +++ b/toolkit/components/passwordmgr/test/unit/test_storage.js @@ -44,7 +44,7 @@ add_task(function test_storage_addLogin_nonascii() yield reloadAndCheckLogins([loginInfo]); // Store the string "test" using similarly looking glyphs. - let loginInfo = TestData.authLogin({ + loginInfo = TestData.authLogin({ httpRealm: String.fromCharCode(355, 277, 349, 357), }); Services.logins.addLogin(loginInfo); diff --git a/toolkit/components/places/tests/bookmarks/test_1017502-bookmarks_foreign_count.js b/toolkit/components/places/tests/bookmarks/test_1017502-bookmarks_foreign_count.js index 70bb9db9ad3c..74137ffec734 100644 --- a/toolkit/components/places/tests/bookmarks/test_1017502-bookmarks_foreign_count.js +++ b/toolkit/components/places/tests/bookmarks/test_1017502-bookmarks_foreign_count.js @@ -13,7 +13,7 @@ const T_URI = NetUtil.newURI("https://www.mozilla.org/firefox/nightly/firstrun/" function* getForeignCountForURL(conn, url) { yield promiseAsyncUpdates(); - let url = url instanceof Ci.nsIURI ? url.spec : url; + url = url instanceof Ci.nsIURI ? url.spec : url; let rows = yield conn.executeCached( "SELECT foreign_count FROM moz_places WHERE url = :t_url ", { t_url: url }); return rows[0].getResultByName("foreign_count"); diff --git a/toolkit/components/places/tests/bookmarks/test_477583_json-backup-in-future.js b/toolkit/components/places/tests/bookmarks/test_477583_json-backup-in-future.js index 369d090115c4..5e9b71d26d5f 100644 --- a/toolkit/components/places/tests/bookmarks/test_477583_json-backup-in-future.js +++ b/toolkit/components/places/tests/bookmarks/test_477583_json-backup-in-future.js @@ -22,7 +22,7 @@ function run_test() { dateObj.setYear(dateObj.getFullYear() + 1); let name = PlacesBackups.getFilenameForDate(dateObj); do_check_eq(name, "bookmarks-" + dateObj.toLocaleFormat("%Y-%m-%d") + ".json"); - let files = bookmarksBackupDir.directoryEntries; + files = bookmarksBackupDir.directoryEntries; while (files.hasMoreElements()) { let entry = files.getNext().QueryInterface(Ci.nsIFile); if (PlacesBackups.filenamesRegex.test(entry.leafName)) diff --git a/toolkit/components/places/tests/bookmarks/test_bookmarks.js b/toolkit/components/places/tests/bookmarks/test_bookmarks.js index c70b9cb95cd8..cd57ed2c51e7 100644 --- a/toolkit/components/places/tests/bookmarks/test_bookmarks.js +++ b/toolkit/components/places/tests/bookmarks/test_bookmarks.js @@ -349,7 +349,7 @@ add_task(function test_bookmarks() { do_check_eq("bar", k); // test getKeywordForURI - let k = bs.getKeywordForURI(uri("http://keywordtest.com/")); + k = bs.getKeywordForURI(uri("http://keywordtest.com/")); do_check_eq("bar", k); // test getURIForKeyword @@ -358,8 +358,8 @@ add_task(function test_bookmarks() { // test removeFolderChildren // 1) add/remove each child type (bookmark, separator, folder) - let tmpFolder = bs.createFolder(testRoot, "removeFolderChildren", - bs.DEFAULT_INDEX); + tmpFolder = bs.createFolder(testRoot, "removeFolderChildren", + bs.DEFAULT_INDEX); bs.insertBookmark(tmpFolder, uri("http://foo9.com/"), bs.DEFAULT_INDEX, ""); bs.createFolder(tmpFolder, "subfolder", bs.DEFAULT_INDEX); bs.insertSeparator(tmpFolder, bs.DEFAULT_INDEX); @@ -451,9 +451,9 @@ add_task(function test_bookmarks() { // test change bookmark uri let newId10 = bs.insertBookmark(testRoot, uri("http://foo10.com/"), bs.DEFAULT_INDEX, ""); - let dateAdded = bs.getItemDateAdded(newId10); + dateAdded = bs.getItemDateAdded(newId10); // after just inserting, modified should not be set - let lastModified = bs.getItemLastModified(newId10); + lastModified = bs.getItemLastModified(newId10); do_check_eq(lastModified, dateAdded); // Workaround possible VM timers issues moving lastModified and dateAdded @@ -464,7 +464,7 @@ add_task(function test_bookmarks() { bs.changeBookmarkURI(newId10, uri("http://foo11.com/")); // check that lastModified is set after we change the bookmark uri - let lastModified2 = bs.getItemLastModified(newId10); + lastModified2 = bs.getItemLastModified(newId10); LOG("test changeBookmarkURI"); LOG("dateAdded = " + dateAdded); LOG("lastModified = " + lastModified); @@ -597,8 +597,8 @@ add_task(function test_bookmarks() { // check setItemLastModified() and setItemDateAdded() let newId14 = bs.insertBookmark(testRoot, uri("http://bar.tld/"), bs.DEFAULT_INDEX, ""); - let dateAdded = bs.getItemDateAdded(newId14); - let lastModified = bs.getItemLastModified(newId14); + dateAdded = bs.getItemDateAdded(newId14); + lastModified = bs.getItemLastModified(newId14); do_check_eq(lastModified, dateAdded); bs.setItemLastModified(newId14, 1234); let fakeLastModified = bs.getItemLastModified(newId14); diff --git a/toolkit/components/places/tests/bookmarks/test_keywords.js b/toolkit/components/places/tests/bookmarks/test_keywords.js index b24f81ace7cf..b783553bbb96 100644 --- a/toolkit/components/places/tests/bookmarks/test_keywords.js +++ b/toolkit/components/places/tests/bookmarks/test_keywords.js @@ -27,7 +27,7 @@ function check_uri_keyword(aURI, aKeyword) function check_orphans() { - stmt = DBConn().createStatement( + let stmt = DBConn().createStatement( `SELECT id FROM moz_keywords k WHERE NOT EXISTS ( SELECT id FROM moz_bookmarks WHERE keyword_id = k.id )` @@ -39,7 +39,7 @@ function check_orphans() } print("Check there are no orphan database entries"); - let stmt = DBConn().createStatement( + stmt = DBConn().createStatement( `SELECT b.id FROM moz_bookmarks b LEFT JOIN moz_keywords k ON b.keyword_id = k.id WHERE keyword_id NOTNULL AND k.id ISNULL` diff --git a/toolkit/components/places/tests/browser/browser_bug248970.js b/toolkit/components/places/tests/browser/browser_bug248970.js index 75662ee90975..a41ee1bb40fe 100644 --- a/toolkit/components/places/tests/browser/browser_bug248970.js +++ b/toolkit/components/places/tests/browser/browser_bug248970.js @@ -118,7 +118,7 @@ function getPlacesItemsCount() { // Get history item count options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY; - let root = PlacesUtils.history.executeQuery( + root = PlacesUtils.history.executeQuery( PlacesUtils.history.getNewQuery(), options).root; root.containerOpen = true; cc += root.childCount; diff --git a/toolkit/components/places/tests/expiration/test_annos_expire_history.js b/toolkit/components/places/tests/expiration/test_annos_expire_history.js index 04ef706b9d9c..b2b29676eee3 100644 --- a/toolkit/components/places/tests/expiration/test_annos_expire_history.js +++ b/toolkit/components/places/tests/expiration/test_annos_expire_history.js @@ -77,11 +77,11 @@ add_task(function test_annos_expire_history() { // Expire all visits for the first 5 pages and the bookmarks. yield promiseForceExpirationStep(10); - let pages = as.getPagesWithAnnotation("page_expire1"); + pages = as.getPagesWithAnnotation("page_expire1"); do_check_eq(pages.length, 0); pages = as.getPagesWithAnnotation("page_expire2"); do_check_eq(pages.length, 0); - let items = as.getItemsWithAnnotation("item_persist1"); + items = as.getItemsWithAnnotation("item_persist1"); do_check_eq(items.length, 0); items = as.getItemsWithAnnotation("item_persist2"); do_check_eq(items.length, 0); @@ -89,4 +89,4 @@ add_task(function test_annos_expire_history() { do_check_eq(pages.length, 5); pages = as.getPagesWithAnnotation("page_persist2"); do_check_eq(pages.length, 5); -}); \ No newline at end of file +}); diff --git a/toolkit/components/places/tests/expiration/test_annos_expire_never.js b/toolkit/components/places/tests/expiration/test_annos_expire_never.js index 81e31dae1951..81dbb73fb062 100644 --- a/toolkit/components/places/tests/expiration/test_annos_expire_never.js +++ b/toolkit/components/places/tests/expiration/test_annos_expire_never.js @@ -78,11 +78,11 @@ add_task(function test_annos_expire_never() { // Expire all visits for the first 5 pages and the bookmarks. yield promiseForceExpirationStep(10); - let pages = as.getPagesWithAnnotation("page_expire1"); + pages = as.getPagesWithAnnotation("page_expire1"); do_check_eq(pages.length, 0); pages = as.getPagesWithAnnotation("page_expire2"); do_check_eq(pages.length, 0); - let items = as.getItemsWithAnnotation("item_persist1"); + items = as.getItemsWithAnnotation("item_persist1"); do_check_eq(items.length, 5); items = as.getItemsWithAnnotation("item_persist2"); do_check_eq(items.length, 5); diff --git a/toolkit/components/places/tests/expiration/test_removeAllPages.js b/toolkit/components/places/tests/expiration/test_removeAllPages.js index 21d818e08902..403b9e1144ab 100644 --- a/toolkit/components/places/tests/expiration/test_removeAllPages.js +++ b/toolkit/components/places/tests/expiration/test_removeAllPages.js @@ -93,7 +93,7 @@ add_task(function test_removeAllPages() { for (let i = 0; i < 5; i++) { let pageURI = uri("http://item_anno." + i + ".mozilla.org/"); // This visit will be expired. - yield promiseAddVisits({ uri: pageURI, visitDate: now++ }); + yield promiseAddVisits({ uri: pageURI }); let id = bs.insertBookmark(bs.unfiledBookmarksFolder, pageURI, bs.DEFAULT_INDEX, null); // Will persist because it's an EXPIRE_NEVER item anno. @@ -113,12 +113,11 @@ add_task(function test_removeAllPages() { } // Add some visited page and annotations for each. - let now = Date.now() * 1000; for (let i = 0; i < 5; i++) { // All page annotations related to these expired pages are expected to // expire as well. let pageURI = uri("http://page_anno." + i + ".mozilla.org/"); - yield promiseAddVisits({ uri: pageURI, visitDate: now++ }); + yield promiseAddVisits({ uri: pageURI }); as.setPageAnnotation(pageURI, "expire", "test", 0, as.EXPIRE_NEVER); as.setPageAnnotation(pageURI, "expire_session", "test", 0, as.EXPIRE_SESSION); add_old_anno(pageURI, "expire_days", "test", as.EXPIRE_DAYS, 8); diff --git a/toolkit/components/places/tests/unit/test_385397.js b/toolkit/components/places/tests/unit/test_385397.js index b00e09fc85f8..f7e8dddf5fbc 100644 --- a/toolkit/components/places/tests/unit/test_385397.js +++ b/toolkit/components/places/tests/unit/test_385397.js @@ -72,13 +72,13 @@ add_task(function test_execute() // ... // http://www.test-0.com/ // http://www.test-0.com/ - let options = PlacesUtils.history.getNewQueryOptions(); + options = PlacesUtils.history.getNewQueryOptions(); options.sortingMode = options.SORT_BY_DATE_DESCENDING; options.resultType = options.RESULTS_AS_VISIT; - let root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), + root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), options).root; root.containerOpen = true; - let cc = root.childCount; + cc = root.childCount; // 2 * TOTAL_SITES because we count the TYPED and LINK, but not EMBED or FRAMED do_check_eq(cc, 2 * TOTAL_SITES); for (let i=0; i < TOTAL_SITES; i++) { @@ -100,14 +100,14 @@ add_task(function test_execute() // http://www.test-19.com/ // ... // http://www.test-10.com/ - let options = PlacesUtils.history.getNewQueryOptions(); + options = PlacesUtils.history.getNewQueryOptions(); options.sortingMode = options.SORT_BY_DATE_DESCENDING; options.maxResults = 10; options.resultType = options.RESULTS_AS_URI; - let root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), + root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), options).root; root.containerOpen = true; - let cc = root.childCount; + cc = root.childCount; do_check_eq(cc, options.maxResults); for (let i=0; i < cc; i++) { let node = root.getChild(i); @@ -124,13 +124,13 @@ add_task(function test_execute() // http://www.test-19.com/ // ... // http://www.test-10.com/ - let options = PlacesUtils.history.getNewQueryOptions(); + options = PlacesUtils.history.getNewQueryOptions(); options.sortingMode = options.SORT_BY_DATE_DESCENDING; options.resultType = options.RESULTS_AS_URI; - let root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), + root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), options).root; root.containerOpen = true; - let cc = root.childCount; + cc = root.childCount; do_check_eq(cc, TOTAL_SITES); for (let i=0; i < 10; i++) { let node = root.getChild(i); diff --git a/toolkit/components/places/tests/unit/test_399266.js b/toolkit/components/places/tests/unit/test_399266.js index 6619f4023f1d..da9ed69437c1 100644 --- a/toolkit/components/places/tests/unit/test_399266.js +++ b/toolkit/components/places/tests/unit/test_399266.js @@ -60,13 +60,13 @@ add_task(function test_execute() // http://www.test-19.com/ // ... // http://www.test-10.com/ - let options = PlacesUtils.history.getNewQueryOptions(); + options = PlacesUtils.history.getNewQueryOptions(); options.sortingMode = options.SORT_BY_VISITCOUNT_DESCENDING; options.resultType = options.RESULTS_AS_URI; - let root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), + root = PlacesUtils.history.executeQuery(PlacesUtils.history.getNewQuery(), options).root; root.containerOpen = true; - let cc = root.childCount; + cc = root.childCount; do_check_eq(cc, TOTAL_SITES); for (let i = 0; i < 10; i++) { let node = root.getChild(i); diff --git a/toolkit/components/places/tests/unit/test_PlacesSearchAutocompleteProvider.js b/toolkit/components/places/tests/unit/test_PlacesSearchAutocompleteProvider.js index 1807d8d533b1..2e6628449ba4 100644 --- a/toolkit/components/places/tests/unit/test_PlacesSearchAutocompleteProvider.js +++ b/toolkit/components/places/tests/unit/test_PlacesSearchAutocompleteProvider.js @@ -61,7 +61,7 @@ add_task(function* test_parseSubmissionURL_basic() { do_check_eq(result.engineName, engine.name); do_check_eq(result.terms, "terms"); - let result = PlacesSearchAutocompleteProvider.parseSubmissionURL("http://example.org/"); + result = PlacesSearchAutocompleteProvider.parseSubmissionURL("http://example.org/"); do_check_eq(result, null); }); diff --git a/toolkit/components/places/tests/unit/test_async_transactions.js b/toolkit/components/places/tests/unit/test_async_transactions.js index b2a3ad22ede9..a4dcbd5105cf 100644 --- a/toolkit/components/places/tests/unit/test_async_transactions.js +++ b/toolkit/components/places/tests/unit/test_async_transactions.js @@ -510,7 +510,7 @@ add_task(function* test_move_items_to_folder() { , newIndex: 0 }); observer.reset(); }; - let ensureUndo = () => { + ensureUndo = () => { ensureUndoState([ [moveTxn] , [folder_b_txn] , [bkm_b_txn, bkm_a_txn, folder_a_txn] ], 1); diff --git a/toolkit/components/places/tests/unit/test_broken_folderShortcut_result.js b/toolkit/components/places/tests/unit/test_broken_folderShortcut_result.js index 982d6bade267..ba4f58f5ea26 100644 --- a/toolkit/components/places/tests/unit/test_broken_folderShortcut_result.js +++ b/toolkit/components/places/tests/unit/test_broken_folderShortcut_result.js @@ -60,10 +60,10 @@ add_task(function test_execute() root.containerOpen = false; // Broken folder shortcut as root node. - let query = PlacesUtils.history.getNewQuery(); + query = PlacesUtils.history.getNewQuery(); query.setFolders([1234], 1); - let options = PlacesUtils.history.getNewQueryOptions(); - let root = PlacesUtils.history.executeQuery(query, options).root; + options = PlacesUtils.history.getNewQueryOptions(); + root = PlacesUtils.history.executeQuery(query, options).root; root.containerOpen = true; do_check_eq(root.childCount, 0); root.containerOpen = false; diff --git a/toolkit/components/places/tests/unit/test_preventive_maintenance.js b/toolkit/components/places/tests/unit/test_preventive_maintenance.js index d67d03b7748f..f4b4be2ae9c1 100644 --- a/toolkit/components/places/tests/unit/test_preventive_maintenance.js +++ b/toolkit/components/places/tests/unit/test_preventive_maintenance.js @@ -1170,7 +1170,7 @@ tests.push({ setLastVisitDate(url, now++); // Add a page without visits. - let url = "http://5.moz.org/"; + url = "http://5.moz.org/"; addPlace(url); // Add a page without visits and set wrong visit_count. url = "http://6.moz.org/"; diff --git a/toolkit/components/prompts/test/test_modal_prompts.html b/toolkit/components/prompts/test/test_modal_prompts.html index 348d85c2c3d3..8483362457fc 100644 --- a/toolkit/components/prompts/test/test_modal_prompts.html +++ b/toolkit/components/prompts/test/test_modal_prompts.html @@ -1099,7 +1099,7 @@ function runTests() { // ConfirmEx (buttons from args, checkbox, cancel) testNum++; startCallbackTimer(); - let b = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING; + b = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING; flags = b * Ci.nsIPromptService.BUTTON_POS_2 + b * Ci.nsIPromptService.BUTTON_POS_1 + b * Ci.nsIPromptService.BUTTON_POS_0; @@ -1118,7 +1118,7 @@ function runTests() { // ConfirmEx (buttons from args, checkbox, button3) testNum++; startCallbackTimer(); - let b = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING; + b = Ci.nsIPromptService.BUTTON_TITLE_IS_STRING; flags = b * Ci.nsIPromptService.BUTTON_POS_2 + b * Ci.nsIPromptService.BUTTON_POS_1 + b * Ci.nsIPromptService.BUTTON_POS_0; diff --git a/toolkit/components/satchel/test/unit/test_autocomplete.js b/toolkit/components/satchel/test/unit/test_autocomplete.js index 12dc185d73b0..8f464ea5ef70 100644 --- a/toolkit/components/satchel/test/unit/test_autocomplete.js +++ b/toolkit/components/satchel/test/unit/test_autocomplete.js @@ -231,7 +231,7 @@ add_test(function test13() { do_check_eq(results.getValueAt(i), syncValues[i]); } - let results = autocompleteService.autoCompleteSearch("field5", "sync1", null, null); + results = autocompleteService.autoCompleteSearch("field5", "sync1", null, null); do_check_eq(results.matchCount, 2, "synchronous matchCount"); do_check_eq(results.getValueAt(0), "sync1"); do_check_eq(results.getValueAt(1), "sync1a"); diff --git a/toolkit/components/social/test/browser/browser_SocialProvider.js b/toolkit/components/social/test/browser/browser_SocialProvider.js index 3d3e6d22aae1..715388eb3d6f 100644 --- a/toolkit/components/social/test/browser/browser_SocialProvider.js +++ b/toolkit/components/social/test/browser/browser_SocialProvider.js @@ -45,7 +45,7 @@ let tests = { provider.enabled = true; ok(provider.enabled, "provider is re-enabled"); - let port = provider.getWorkerPort(); + port = provider.getWorkerPort(); ok(port, "should be able to get a port from re-enabled provider"); port.close(); ok(provider.workerAPI, "should be able to get a workerAPI from re-enabled provider"); diff --git a/toolkit/content/tests/chrome/findbar_window.xul b/toolkit/content/tests/chrome/findbar_window.xul index 1bff214b4c00..39a980f145ba 100644 --- a/toolkit/content/tests/chrome/findbar_window.xul +++ b/toolkit/content/tests/chrome/findbar_window.xul @@ -344,7 +344,7 @@ ok(a == b && b == c, "testFindWithHighlight 1: " + a + ", " + b + ", " + c + "."); let oldGetInitialSelection = gFindBar._getInitialSelection; - let searchStr = "t"; + searchStr = "t"; gFindBar._getInitialSelection = () => searchStr; findCommand.doCommand(); gFindBar._getInitialSelection = oldGetInitialSelection; diff --git a/toolkit/content/tests/chrome/test_bug557987.xul b/toolkit/content/tests/chrome/test_bug557987.xul index f7dcbbba3ba8..ba680568fffe 100644 --- a/toolkit/content/tests/chrome/test_bug557987.xul +++ b/toolkit/content/tests/chrome/test_bug557987.xul @@ -40,8 +40,8 @@ function test() { synthesizeMouse(button, centerX, centerY, {}, window); let menulist = $("menulist"); - let centerX = menulist.getBoundingClientRect().width / 2; - let centerY = menulist.getBoundingClientRect().height / 2; + centerX = menulist.getBoundingClientRect().width / 2; + centerY = menulist.getBoundingClientRect().height / 2; synthesizeMouse(menulist, centerX, centerY, {}, window); synthesizeMouse(document.getElementsByTagName("body")[0], 0, 0, {}, window); diff --git a/toolkit/devtools/server/tests/mochitest/inspector-helpers.js b/toolkit/devtools/server/tests/mochitest/inspector-helpers.js index ad875e588b63..7fbb97cb1eaa 100644 --- a/toolkit/devtools/server/tests/mochitest/inspector-helpers.js +++ b/toolkit/devtools/server/tests/mochitest/inspector-helpers.js @@ -166,7 +166,7 @@ function checkMissing(client, actorID) { let front = client.getActor(actorID); ok(!front, "Front shouldn't be accessible from the client for actorID: " + actorID); - let deferred = promise.defer(); + deferred = promise.defer(); client.request({ to: actorID, type: "request", @@ -183,7 +183,7 @@ function checkAvailable(client, actorID) { let front = client.getActor(actorID); ok(front, "Front should be accessible from the client for actorID: " + actorID); - let deferred = promise.defer(); + deferred = promise.defer(); client.request({ to: actorID, type: "garbageAvailableTest", diff --git a/toolkit/devtools/server/tests/mochitest/test_highlighter-boxmodel_02.html b/toolkit/devtools/server/tests/mochitest/test_highlighter-boxmodel_02.html index 96b02f1d1812..783cb471d031 100644 --- a/toolkit/devtools/server/tests/mochitest/test_highlighter-boxmodel_02.html +++ b/toolkit/devtools/server/tests/mochitest/test_highlighter-boxmodel_02.html @@ -239,7 +239,7 @@ window.onload = function() { }); let margin = container.querySelector(".box-model-margin"); - let points = margin.getAttribute("points").split(" ").map(xy => xy.split(",")); + points = margin.getAttribute("points").split(" ").map(xy => xy.split(",")); is(Math.ceil(guideTop.getAttribute("y1")), points[0][1], "Top guide's y1 is correct"); diff --git a/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html b/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html index 6b95ed1eaa7d..ee5c051eda1b 100644 --- a/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html +++ b/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-childlist.html @@ -102,7 +102,7 @@ function mutationTest(testSpec) { gWalker.once("mutations", (mutations) => { // Filter out our dummy mutation. - let mutations = mutations.filter(change => { + mutations = mutations.filter(change => { if (change.type == "attributes" && change.attributeName == "data-dummy") { return false; diff --git a/toolkit/devtools/server/tests/mochitest/test_styles-applied.html b/toolkit/devtools/server/tests/mochitest/test_styles-applied.html index b6129b786f21..c8f62b5dcd73 100644 --- a/toolkit/devtools/server/tests/mochitest/test_styles-applied.html +++ b/toolkit/devtools/server/tests/mochitest/test_styles-applied.html @@ -42,7 +42,6 @@ addTest(function setup() { }); addTest(function inheritedUserStyles() { - let node = node; promiseDone(gWalker.querySelector(gWalker.rootNode, "#test-node").then(node => { return gStyles.getApplied(node, { inherited: true, filter: "user" }); }).then(applied => { @@ -78,7 +77,6 @@ addTest(function inheritedUserStyles() { }); addTest(function inheritedSystemStyles() { - let node = node; promiseDone(gWalker.querySelector(gWalker.rootNode, "#test-node").then(node => { return gStyles.getApplied(node, { inherited: true, filter: "ua" }); }).then(applied => { @@ -95,7 +93,6 @@ addTest(function inheritedSystemStyles() { }); addTest(function noInheritedStyles() { - let node = node; promiseDone(gWalker.querySelector(gWalker.rootNode, "#test-node").then(node => { return gStyles.getApplied(node, { inherited: false, filter: "user" }); }).then(applied => { @@ -118,7 +115,6 @@ addTest(function matchedSelectors() { }); addTest(function testMediaQuery() { - let node = node; promiseDone(gWalker.querySelector(gWalker.rootNode, "#mediaqueried").then(node => { return gStyles.getApplied(node, { inherited: false, filter: "user", matchedSelectors: true diff --git a/toolkit/devtools/server/tests/mochitest/test_styles-svg.html b/toolkit/devtools/server/tests/mochitest/test_styles-svg.html index 0fbaa2510cb8..bae77142d221 100644 --- a/toolkit/devtools/server/tests/mochitest/test_styles-svg.html +++ b/toolkit/devtools/server/tests/mochitest/test_styles-svg.html @@ -43,7 +43,6 @@ addTest(function setup() { }); addTest(function inheritedUserStyles() { - let node = node; promiseDone(gWalker.querySelector(gWalker.rootNode, "#svgcontent rect").then(node => { return gStyles.getApplied(node, { inherited: true, filter: "user" }); }).then(applied => { diff --git a/toolkit/devtools/server/tests/unit/test_breakpoint-15.js b/toolkit/devtools/server/tests/unit/test_breakpoint-15.js index 146a4dd6deb4..b66453ea29bf 100644 --- a/toolkit/devtools/server/tests/unit/test_breakpoint-15.js +++ b/toolkit/devtools/server/tests/unit/test_breakpoint-15.js @@ -49,8 +49,8 @@ const testSameBreakpoint = Task.async(function* () { column: 6 }; - let [firstResponse, firstBpClient] = yield setBreakpoint(gThreadClient, columnLocation); - let [secondResponse, secondBpClient] = yield setBreakpoint(gThreadClient, columnLocation); + [firstResponse, firstBpClient] = yield setBreakpoint(gThreadClient, columnLocation); + [secondResponse, secondBpClient] = yield setBreakpoint(gThreadClient, columnLocation); do_check_eq(secondBpClient.actor, secondBpClient.actor, "Should get the same actor column breakpoints"); @@ -69,4 +69,4 @@ function evalCode() { SOURCE_URL, 1 ); -} \ No newline at end of file +} diff --git a/toolkit/devtools/tests/unit/test_consoleID.js b/toolkit/devtools/tests/unit/test_consoleID.js index 941aa5192d64..9fb43b2df59e 100644 --- a/toolkit/devtools/tests/unit/test_consoleID.js +++ b/toolkit/devtools/tests/unit/test_consoleID.js @@ -70,7 +70,7 @@ function run_test() { listener = new ConsoleAPIListener(null, callback, "foo"); listener.init(); - let messages = listener.getCachedMessages(); + messages = listener.getCachedMessages(); seenTypes = 0; seenMessages = 0; diff --git a/toolkit/modules/tests/browser/browser_Geometry.js b/toolkit/modules/tests/browser/browser_Geometry.js index 0a0cd82bce27..e656320105c1 100644 --- a/toolkit/modules/tests/browser/browser_Geometry.js +++ b/toolkit/modules/tests/browser/browser_Geometry.js @@ -30,9 +30,9 @@ let tests = { testIsEmpty: function() { let r = new Rect(0, 0, 0, 10); ok(r.isEmpty(), "rect with nonpositive width is empty"); - let r = new Rect(0, 0, 10, 0); + r = new Rect(0, 0, 10, 0); ok(r.isEmpty(), "rect with nonpositive height is empty"); - let r = new Rect(0, 0, 10, 10); + r = new Rect(0, 0, 10, 10); ok(!r.isEmpty(), "rect with positive dimensions is not empty"); }, @@ -42,18 +42,18 @@ let tests = { r1.restrictTo(r2); ok(r1.equals(new Rect(50, 50, 60, 60)), "intersection is non-empty"); - let r1 = new Rect(10, 10, 100, 100); - let r2 = new Rect(120, 120, 100, 100); + r1 = new Rect(10, 10, 100, 100); + r2 = new Rect(120, 120, 100, 100); r1.restrictTo(r2); ok(r1.isEmpty(), "intersection is empty"); - let r1 = new Rect(10, 10, 100, 100); - let r2 = new Rect(0, 0, 0, 0); + r1 = new Rect(10, 10, 100, 100); + r2 = new Rect(0, 0, 0, 0); r1.restrictTo(r2); ok(r1.isEmpty(), "intersection of rect and empty is empty"); - let r1 = new Rect(0, 0, 0, 0); - let r2 = new Rect(0, 0, 0, 0); + r1 = new Rect(0, 0, 0, 0); + r2 = new Rect(0, 0, 0, 0); r1.restrictTo(r2); ok(r1.isEmpty(), "intersection of empty and empty is empty"); }, @@ -64,18 +64,18 @@ let tests = { r1.expandToContain(r2); ok(r1.equals(new Rect(10, 10, 140, 140)), "correct expandToContain on intersecting rectangles"); - let r1 = new Rect(10, 10, 100, 100); - let r2 = new Rect(120, 120, 100, 100); + r1 = new Rect(10, 10, 100, 100); + r2 = new Rect(120, 120, 100, 100); r1.expandToContain(r2); ok(r1.equals(new Rect(10, 10, 210, 210)), "correct expandToContain on non-intersecting rectangles"); - let r1 = new Rect(10, 10, 100, 100); - let r2 = new Rect(0, 0, 0, 0); + r1 = new Rect(10, 10, 100, 100); + r2 = new Rect(0, 0, 0, 0); r1.expandToContain(r2); ok(r1.equals(new Rect(10, 10, 100, 100)), "expandToContain of rect and empty is rect"); - let r1 = new Rect(10, 10, 0, 0); - let r2 = new Rect(0, 0, 0, 0); + r1 = new Rect(10, 10, 0, 0); + r2 = new Rect(0, 0, 0, 0); r1.expandToContain(r2); ok(r1.isEmpty(), "expandToContain of empty and empty is empty"); }, @@ -91,16 +91,16 @@ let tests = { let r2 = new Rect(500, 500, 100, 100); ok(equals(r1.subtract(r2), [r1]), "subtract area outside of region yields same region"); - let r1 = new Rect(0, 0, 100, 100); - let r2 = new Rect(-10, -10, 50, 120); + r1 = new Rect(0, 0, 100, 100); + r2 = new Rect(-10, -10, 50, 120); ok(equals(r1.subtract(r2), [new Rect(40, 0, 60, 100)]), "subtracting vertical bar from edge leaves one rect"); - let r1 = new Rect(0, 0, 100, 100); - let r2 = new Rect(-10, -10, 120, 50); + r1 = new Rect(0, 0, 100, 100); + r2 = new Rect(-10, -10, 120, 50); ok(equals(r1.subtract(r2), [new Rect(0, 40, 100, 60)]), "subtracting horizontal bar from edge leaves one rect"); - let r1 = new Rect(0, 0, 100, 100); - let r2 = new Rect(40, 40, 20, 20); + r1 = new Rect(0, 0, 100, 100); + r2 = new Rect(40, 40, 20, 20); ok(equals(r1.subtract(r2), [ new Rect(0, 0, 40, 100), new Rect(40, 0, 20, 40), diff --git a/toolkit/modules/tests/xpcshell/test_Log.js b/toolkit/modules/tests/xpcshell/test_Log.js index 4ea90e2ddfab..d995d0ece8e2 100644 --- a/toolkit/modules/tests/xpcshell/test_Log.js +++ b/toolkit/modules/tests/xpcshell/test_Log.js @@ -169,7 +169,7 @@ add_task(function test_StructuredLogCommands() { do_check_true(errored); } - let errored = false; + errored = false; try { logger.logStructured("message_action", "invalid params"); } catch (e) { @@ -181,8 +181,8 @@ add_task(function test_StructuredLogCommands() { // Logging with unstructured interface should produce the same messages // as the structured interface for these cases. - let appender = new MockAppender(new Log.StructuredFormatter()); - let logger = Log.repository.getLogger("test.StructuredOutput1"); + appender = new MockAppender(new Log.StructuredFormatter()); + logger = Log.repository.getLogger("test.StructuredOutput1"); messageOne._namespace = "test.StructuredOutput1"; messageTwo._namespace = "test.StructuredOutput1"; logger.addAppender(appender); @@ -377,7 +377,7 @@ add_task(function log_message_with_params() { 'JSON is {"sneaky":"value"}'); // Fall back to .toSource() if JSON.stringify() fails on an object. - let ob = function() {}; + ob = function() {}; ob.toJSON = function() {throw "oh noes JSON"}; do_check_eq(formatMessage("Fail is ${sub}", {sub: ob}), 'Fail is (function () {})'); @@ -430,19 +430,19 @@ add_task(function log_message_with_params() { let str = formatMessage("Exception is ${}", err); do_check_true(str.contains('Exception is [Exception... "test exception"')); do_check_true(str.contains("(NS_ERROR_FAILURE)")); - let str = formatMessage("Exception is", err); + str = formatMessage("Exception is", err); do_check_true(str.contains('Exception is: [Exception... "test exception"')); - let str = formatMessage("Exception is ${error}", {error: err}); + str = formatMessage("Exception is ${error}", {error: err}); do_check_true(str.contains('Exception is [Exception... "test exception"')); - let str = formatMessage("Exception is", {_error: err}); + str = formatMessage("Exception is", {_error: err}); do_print(str); // Exceptions buried inside objects are formatted badly. do_check_true(str.contains('Exception is: {"_error":{}')); // If the message text is null, the message contains only the formatted params object. - let str = formatMessage(null, err); + str = formatMessage(null, err); do_check_true(str.startsWith('[Exception... "test exception"')); // If the text is null and 'params' is a String object, the message is exactly that string. - let str = formatMessage(null, new String("String in place of params")); + str = formatMessage(null, new String("String in place of params")); do_check_eq(str, "String in place of params"); // We use object.valueOf() internally; make sure a broken valueOf() method diff --git a/toolkit/modules/tests/xpcshell/test_sqlite.js b/toolkit/modules/tests/xpcshell/test_sqlite.js index 611c4e84d78f..58407e7821ef 100644 --- a/toolkit/modules/tests/xpcshell/test_sqlite.js +++ b/toolkit/modules/tests/xpcshell/test_sqlite.js @@ -711,7 +711,7 @@ add_task(function test_programmatic_binding_transaction_partial_rollback() { // Insert multiple rows. mozStorage will want to start a transaction. // One of the inserts will fail, so the transaction should be rolled back. - let result = yield c.execute(sql, bindings); + result = yield c.execute(sql, bindings); secondSucceeded = true; }); } catch (ex) { diff --git a/toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js b/toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js index 47c317b2fcae..35e57e53f697 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js +++ b/toolkit/mozapps/extensions/test/browser/browser_cancelCompatCheck.js @@ -232,6 +232,8 @@ function* check_addons_uninstalled(aAddonList) { // For this test, addon8 became disabled during update and addon9 was previously disabled, // so addon8 should update and addon9 should not add_task(function cancel_during_repopulate() { + let a5, a8, a9, a10; + Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true); Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0"); Services.prefs.setCharPref(PREF_UPDATEURL, TESTROOT + "missing.rdf"); @@ -250,7 +252,7 @@ add_task(function cancel_during_repopulate() { Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true); Services.prefs.setCharPref(PREF_GETADDONS_BYIDS, TESTROOT + "browser_bug557956.xml"); - let [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]); + [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]); ok(!a5.isCompatible, "addon5 should not be compatible"); ok(!a8.isCompatible, "addon8 should not be compatible"); ok(!a9.isCompatible, "addon9 should not be compatible"); @@ -279,7 +281,7 @@ add_task(function cancel_during_repopulate() { // addon8 should have updated in the background, // addon9 was listed as previously disabled so it should not have updated - let [a5, a8, a9, a10] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id, ao10.id]); + [a5, a8, a9, a10] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id, ao10.id]); ok(a5.isCompatible, "addon5 should be compatible"); ok(a8.isCompatible, "addon8 should have been upgraded"); ok(!a9.isCompatible, "addon9 should not have been upgraded"); @@ -295,6 +297,8 @@ add_task(function cancel_during_repopulate() { // For this test, both addon8 and addon9 were disabled by this update, but addon8 // is set to not auto-update, so only addon9 should update in the background add_task(function cancel_during_findUpdates() { + let a5, a8, a9; + Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true); Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0"); @@ -310,7 +314,7 @@ add_task(function cancel_during_findUpdates() { yield promise_install_test_addons(addonList, TESTROOT + "cancelCompatCheck.sjs"); - let [a8] = yield promise_addons_by_ids([ao8.id]); + [a8] = yield promise_addons_by_ids([ao8.id]); a8.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE; Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true); @@ -334,7 +338,7 @@ add_task(function cancel_during_findUpdates() { // addon8 should have updated in the background, // addon9 was listed as previously disabled so it should not have updated - let [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]); + [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]); ok(a5.isCompatible, "addon5 should be compatible"); ok(!a8.isCompatible, "addon8 should not have been upgraded"); ok(a9.isCompatible, "addon9 should have been upgraded"); @@ -353,6 +357,8 @@ add_task(function cancel_during_findUpdates() { // Same conditions as the previous test - addon8 and addon9 have updates available, // addon8 is set to not auto-update so only addon9 should become compatible add_task(function cancel_mismatch() { + let a3, a5, a7, a8, a9; + Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true); Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0"); @@ -367,11 +373,11 @@ add_task(function cancel_mismatch() { yield promise_install_test_addons(addonList, TESTROOT + "cancelCompatCheck.sjs"); - let [a8] = yield promise_addons_by_ids([ao8.id]); + [a8] = yield promise_addons_by_ids([ao8.id]); a8.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE; // Check that the addons start out not compatible. - let [a3, a7, a8, a9] = yield promise_addons_by_ids([ao3.id, ao7.id, ao8.id, ao9.id]); + [a3, a7, a8, a9] = yield promise_addons_by_ids([ao3.id, ao7.id, ao8.id, ao9.id]); ok(!a3.isCompatible, "addon3 should not be compatible"); ok(!a7.isCompatible, "addon7 should not be compatible"); ok(!a8.isCompatible, "addon8 should not be compatible"); @@ -392,7 +398,7 @@ add_task(function cancel_mismatch() { // addon8 should not have updated in the background, // addon9 was listed as previously disabled so it should not have updated - let [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]); + [a5, a8, a9] = yield promise_addons_by_ids([ao5.id, ao8.id, ao9.id]); ok(a5.isCompatible, "addon5 should be compatible"); ok(!a8.isCompatible, "addon8 should not have been upgraded"); ok(a9.isCompatible, "addon9 should have been upgraded"); @@ -410,6 +416,8 @@ add_task(function cancel_mismatch() { // Cancelling during the 'mismatch' screen with only add-ons that have // no updates available add_task(function cancel_mismatch_no_updates() { + let a3, a5, a6 + Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true); Services.prefs.setCharPref(PREF_MIN_PLATFORM_COMPAT, "0"); @@ -421,7 +429,7 @@ add_task(function cancel_mismatch_no_updates() { TESTROOT + "cancelCompatCheck.sjs"); // Check that the addons start out not compatible. - let [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]); + [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]); ok(!a3.isCompatible, "addon3 should not be compatible"); ok(!a5.isCompatible, "addon5 should not be compatible"); ok(!a6.isCompatible, "addon6 should not be compatible"); @@ -437,7 +445,7 @@ add_task(function cancel_mismatch_no_updates() { yield promise_window_close(compatWindow); - let [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]); + [a3, a5, a6] = yield promise_addons_by_ids([ao3.id, ao5.id, ao6.id]); ok(!a3.isCompatible, "addon3 should not be compatible"); ok(a5.isCompatible, "addon5 should have become compatible"); ok(a6.isCompatible, "addon6 should have become compatible"); diff --git a/toolkit/mozapps/extensions/test/browser/browser_experiments.js b/toolkit/mozapps/extensions/test/browser/browser_experiments.js index c8202e632e45..620d37fd22e5 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_experiments.js +++ b/toolkit/mozapps/extensions/test/browser/browser_experiments.js @@ -582,7 +582,7 @@ add_task(function testDetailView() { yield gCategoryUtilities.openType("experiment"); yield openDetailsView("experiment-3"); - let el = gManagerWindow.document.getElementById("detail-experiment-state"); + el = gManagerWindow.document.getElementById("detail-experiment-state"); is_element_visible(el, "Experiment state label should be visible."); if (gIsEnUsLocale) { Assert.equal(el.value, "Complete"); diff --git a/toolkit/mozapps/extensions/test/browser/browser_openH264.js b/toolkit/mozapps/extensions/test/browser/browser_openH264.js index 2be43fd318d4..4a8d9bc23a1d 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_openH264.js +++ b/toolkit/mozapps/extensions/test/browser/browser_openH264.js @@ -249,7 +249,7 @@ add_task(function* testUpdateButton() { wait_for_view_load(gManagerWindow, deferred.resolve); yield deferred.promise; - let button = doc.getElementById("detail-findUpdates-btn"); + button = doc.getElementById("detail-findUpdates-btn"); Assert.ok(button != null, "Got detail-findUpdates-btn"); EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, gManagerWindow); yield gInstallDeferred.promise; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js index 1335d978c829..dfd86a31b793 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js @@ -793,7 +793,7 @@ add_task(function* run_blocklist_update_test() { yield Pload_blocklist("blocklist_update2.xml"); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); check_addon(s2, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); @@ -815,7 +815,7 @@ add_task(function* run_blocklist_update_test() { yield Pload_blocklist("blocklist_update2.xml"); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "1.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); @@ -829,7 +829,7 @@ add_task(function* run_blocklist_update_test() { yield Pload_blocklist("blocklist_update1.xml"); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); @@ -1098,7 +1098,7 @@ add_task(function* run_background_update_test() { yield Pbackground_update(); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); check_addon(s2, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); @@ -1155,7 +1155,7 @@ add_task(function* run_background_update_2_test() { yield Pbackground_update(); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "1.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); check_addon(s2, "1.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); @@ -1198,7 +1198,7 @@ add_task(function* run_manual_update_test() { yield Pmanual_update("2"); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); @@ -1212,7 +1212,7 @@ add_task(function* run_manual_update_test() { yield Pmanual_update("3"); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); @@ -1268,7 +1268,7 @@ add_task(function* run_manual_update_2_test() { yield Pmanual_update("2"); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "2.0", true, true, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); check_addon(s2, "2.0", true, false, Ci.nsIBlocklistService.STATE_SOFTBLOCKED); @@ -1282,7 +1282,7 @@ add_task(function* run_manual_update_2_test() { yield Pmanual_update("3"); yield promiseRestartManager(); - let [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); + [s1, s2, s3, s4, s5, h, r] = yield promiseAddonsByIDs(ADDON_IDS); check_addon(s1, "3.0", false, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); check_addon(s2, "3.0", true, false, Ci.nsIBlocklistService.STATE_NOT_BLOCKED); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js index ffef6b7d169b..8ac5490b4a7a 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js @@ -119,8 +119,8 @@ function run_test() { stagedXPIs.append("addon8@tests.mozilla.org"); stagedXPIs.create(AM_Ci.nsIFile.DIRECTORY_TYPE, 0755); - let addon7 = do_get_addon("test_migrate8"); - addon7.copyTo(stagedXPIs, "tmp.xpi"); + let addon8 = do_get_addon("test_migrate8"); + addon8.copyTo(stagedXPIs, "tmp.xpi"); stagedXPIs = stagedXPIs.parent; let old = do_get_file("data/test_migrate.rdf"); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_overrideblocklist.js b/toolkit/mozapps/extensions/test/xpcshell/test_overrideblocklist.js index 81cf2c9aaf18..8a6bedea162a 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_overrideblocklist.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_overrideblocklist.js @@ -187,8 +187,8 @@ add_test(function test_missing() { startupManager(false); reloadBlocklist(); - let blocklist = AM_Cc["@mozilla.org/extensions/blocklist;1"]. - getService(AM_Ci.nsIBlocklistService); + blocklist = AM_Cc["@mozilla.org/extensions/blocklist;1"]. + getService(AM_Ci.nsIBlocklistService); do_check_false(blocklist.isAddonBlocklisted(invalidAddon)); do_check_false(blocklist.isAddonBlocklisted(ancientAddon)); do_check_true(blocklist.isAddonBlocklisted(oldAddon)); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js b/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js index 1b227b0bf256..46a47c160e81 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiOnlyAllowOneWindow.js @@ -52,7 +52,7 @@ function run_test() { // didn't throw and otherwise it would report no tests run. do_check_true(true); - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), WindowWatcherFactory); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af56}"), diff --git a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js index 53dc418dcda8..174740dffa0d 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/uiSilentPref.js @@ -57,7 +57,7 @@ function run_test() { // didn't throw and otherwise it would report no tests run. do_check_true(true); - let registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); + registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar); registrar.unregisterFactory(Components.ID("{1dfeb90a-2193-45d5-9cb8-864928b2af55}"), WindowWatcherFactory); diff --git a/toolkit/profile/test/test_create_profile.xul b/toolkit/profile/test/test_create_profile.xul index 9d65051fc3d3..040b1256b2cf 100644 --- a/toolkit/profile/test/test_create_profile.xul +++ b/toolkit/profile/test/test_create_profile.xul @@ -119,7 +119,7 @@ function createProfile(profileName) { profile.remove(true); // Create with non-null aRootDir - let profile = gProfileService.createProfile(profileDir, profileName); + profile = gProfileService.createProfile(profileDir, profileName); let localProfileDir = profile.localDir; ok(gDefaultLocalProfileParent.contains(localProfileDir, false), From 33c5396ab8df1bc8853aae6f515d05c8ca2bbadc Mon Sep 17 00:00:00 2001 From: David Burns Date: Tue, 16 Sep 2014 00:39:25 +0100 Subject: [PATCH 22/32] Bug 1022862: Create a manifest just for marionette web-api tests; r=jgriffin DONTBUILD --- .../client/marionette/tests/webapi-tests.ini | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 testing/marionette/client/marionette/tests/webapi-tests.ini diff --git a/testing/marionette/client/marionette/tests/webapi-tests.ini b/testing/marionette/client/marionette/tests/webapi-tests.ini new file mode 100644 index 000000000000..70fd49d2e195 --- /dev/null +++ b/testing/marionette/client/marionette/tests/webapi-tests.ini @@ -0,0 +1,28 @@ +[DEFAULT] +; true if the test requires an emulator, otherwise false +qemu = false + +; true if the test is compatible with the browser, otherwise false +browser = true + +; true if the test is compatible with b2g, otherwise false +b2g = true + +; true if the test should be skipped +skip = false + +; webapi tests +[include:../../../../../dom/bluetooth/tests/marionette/manifest.ini] +[include:../../../../../dom/telephony/test/marionette/manifest.ini] +[include:../../../../../dom/voicemail/test/marionette/manifest.ini] +[include:../../../../../dom/battery/test/marionette/manifest.ini] +[include:../../../../../dom/mobilemessage/tests/marionette/manifest.ini] +[include:../../../../../dom/mobileconnection/tests/marionette/manifest.ini] +[include:../../../../../dom/system/gonk/tests/marionette/manifest.ini] +[include:../../../../../dom/icc/tests/marionette/manifest.ini] +[include:../../../../../dom/system/tests/marionette/manifest.ini] +[include:../../../../../dom/nfc/tests/marionette/manifest.ini] +[include:../../../../../dom/events/test/marionette/manifest.ini] +[include:../../../../../dom/wifi/test/marionette/manifest.ini] +[include:../../../../../dom/cellbroadcast/tests/marionette/manifest.ini] +[include:../../../../../dom/tethering/tests/marionette/manifest.ini] \ No newline at end of file From 3653f564e9c1fb7311aff8d9f1f288373f1e8e51 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 15 Sep 2014 16:42:26 -0700 Subject: [PATCH 23/32] Bug 1060046 - e10s EventTarget shim broken because interpositions don't delegate properly (r=mconley) --- .../addoncompat/RemoteAddonsParent.jsm | 31 ++++++++++--------- .../addoncompat/multiprocessShims.js | 7 ++--- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/toolkit/components/addoncompat/RemoteAddonsParent.jsm b/toolkit/components/addoncompat/RemoteAddonsParent.jsm index 4cc77fa4e683..63aeb0cb3e9e 100644 --- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm @@ -86,16 +86,17 @@ NotificationTracker.init(); // getters, and setters. See multiprocessShims.js for an explanation // of how these are used. The constructor here just allows one // interposition to inherit members from another. -function Interposition(base) +function Interposition(name, base) { + this.name = name; if (base) { this.methods = Object.create(base.methods); this.getters = Object.create(base.getters); this.setters = Object.create(base.setters); } else { - this.methods = {}; - this.getters = {}; - this.setters = {}; + this.methods = Object.create(null); + this.getters = Object.create(null); + this.setters = Object.create(null); } } @@ -157,7 +158,7 @@ ContentPolicyParent.init(); // This interposition intercepts calls to add or remove new content // policies and forwards these requests to ContentPolicyParent. -let CategoryManagerInterposition = new Interposition(); +let CategoryManagerInterposition = new Interposition("CategoryManagerInterposition"); CategoryManagerInterposition.methods.addCategoryEntry = function(addon, target, category, entry, value, persist, replace) { @@ -248,7 +249,7 @@ let AboutProtocolParent = { }; AboutProtocolParent.init(); -let ComponentRegistrarInterposition = new Interposition(); +let ComponentRegistrarInterposition = new Interposition("ComponentRegistrarInterposition"); ComponentRegistrarInterposition.methods.registerFactory = function(addon, target, class_, className, contractID, factory) { @@ -319,7 +320,7 @@ let TOPIC_WHITELIST = ["content-document-global-created", // This interposition listens for // nsIObserverService.{add,remove}Observer. -let ObserverInterposition = new Interposition(); +let ObserverInterposition = new Interposition("ObserverInterposition"); ObserverInterposition.methods.addObserver = function(addon, target, observer, topic, ownsWeak) { @@ -457,7 +458,7 @@ let EventTargetParent = { dispatch: function(browser, type, isTrusted, event) { let targets = this.getTargets(browser); - for (target of targets) { + for (let target of targets) { let listeners = this._listeners.get(target); if (!listeners) { continue; @@ -483,7 +484,7 @@ EventTargetParent.init(); // This interposition redirects addEventListener and // removeEventListener to EventTargetParent. -let EventTargetInterposition = new Interposition(); +let EventTargetInterposition = new Interposition("EventTargetInterposition"); EventTargetInterposition.methods.addEventListener = function(addon, target, type, listener, useCapture, wantsUntrusted) { @@ -501,7 +502,7 @@ EventTargetInterposition.methods.removeEventListener = // process docshell. In the child, each docshell is its own // root. However, add-ons expect the root to be the chrome docshell, // so we make that happen here. -let ContentDocShellTreeItemInterposition = new Interposition(); +let ContentDocShellTreeItemInterposition = new Interposition("ContentDocShellTreeItemInterposition"); ContentDocShellTreeItemInterposition.getters.rootTreeItem = function(addon, target) { @@ -569,7 +570,7 @@ let SandboxParent = { // This interposition redirects calls to Cu.Sandbox and // Cu.evalInSandbox to SandboxParent if the principals are content // principals. -let ComponentsUtilsInterposition = new Interposition(); +let ComponentsUtilsInterposition = new Interposition("ComponentsUtilsInterposition"); ComponentsUtilsInterposition.methods.Sandbox = function(addon, target, principal, ...rest) { @@ -596,7 +597,7 @@ ComponentsUtilsInterposition.methods.evalInSandbox = // chrome XUL node into a content document. It doesn't actually do the // import, which we can't support. It just avoids throwing an // exception. -let ContentDocumentInterposition = new Interposition(); +let ContentDocumentInterposition = new Interposition("ContentDocumentInterposition"); ContentDocumentInterposition.methods.importNode = function(addon, target, node, deep) { @@ -614,7 +615,8 @@ ContentDocumentInterposition.methods.importNode = // This interposition ensures that calling browser.docShell from an // add-on returns a CPOW around the dochell. -let RemoteBrowserElementInterposition = new Interposition(EventTargetInterposition); +let RemoteBrowserElementInterposition = new Interposition("RemoteBrowserElementInterposition", + EventTargetInterposition); RemoteBrowserElementInterposition.getters.docShell = function(addon, target) { let remoteChromeGlobal = RemoteAddonsParent.browserToGlobal.get(target); @@ -633,7 +635,8 @@ RemoteBrowserElementInterposition.getters.contentDocument = function(addon, targ return target.contentDocumentAsCPOW; }; -let ChromeWindowInterposition = new Interposition(EventTargetInterposition); +let ChromeWindowInterposition = new Interposition("ChromeWindowInterposition", + EventTargetInterposition); ChromeWindowInterposition.getters.content = function(addon, target) { return target.gBrowser.selectedBrowser.contentWindowAsCPOW; diff --git a/toolkit/components/addoncompat/multiprocessShims.js b/toolkit/components/addoncompat/multiprocessShims.js index c14396450658..5be6ffc38f94 100644 --- a/toolkit/components/addoncompat/multiprocessShims.js +++ b/toolkit/components/addoncompat/multiprocessShims.js @@ -119,18 +119,17 @@ AddonInterpositionService.prototype = { let desc = { configurable: false, enumerable: true }; - if ("methods" in interp && interp.methods.hasOwnProperty(prop)) { + if ("methods" in interp && prop in interp.methods) { desc.writable = false; desc.value = function(...args) { return interp.methods[prop](addon, target, ...args); } return desc; - } else if ("getters" in interp && - interp.getters.hasOwnProperty(prop)) { + } else if ("getters" in interp && prop in interp.getters) { desc.get = function() { return interp.getters[prop](addon, target); }; - if ("setters" in interp && interp.setters.hasOwnProperty(prop)) { + if ("setters" in interp && prop in interp.setters) { desc.set = function(v) { return interp.setters[prop](addon, target, v); }; } From fcd7b9d897308e1b61f05ef442ae94b9227cc3c4 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 15 Sep 2014 16:42:26 -0700 Subject: [PATCH 24/32] Bug 1066433 - Remove simple mochitest e10s shim (r=jimm) --- testing/mochitest/jar.mn | 1 - .../mochitest/mochitest-e10s-utils-content.js | 16 ---- testing/mochitest/mochitest-e10s-utils.js | 76 ------------------- 3 files changed, 93 deletions(-) delete mode 100644 testing/mochitest/mochitest-e10s-utils-content.js diff --git a/testing/mochitest/jar.mn b/testing/mochitest/jar.mn index 7019a39fdee4..8bf8ea7f9c81 100644 --- a/testing/mochitest/jar.mn +++ b/testing/mochitest/jar.mn @@ -6,7 +6,6 @@ mochikit.jar: content/cc-analyzer.js (cc-analyzer.js) content/chrome-harness.js (chrome-harness.js) content/mochitest-e10s-utils.js (mochitest-e10s-utils.js) - content/mochitest-e10s-utils-content.js (mochitest-e10s-utils-content.js) content/harness.xul (harness.xul) content/redirect.html (redirect.html) content/server.js (server.js) diff --git a/testing/mochitest/mochitest-e10s-utils-content.js b/testing/mochitest/mochitest-e10s-utils-content.js deleted file mode 100644 index 02f361e480d1..000000000000 --- a/testing/mochitest/mochitest-e10s-utils-content.js +++ /dev/null @@ -1,16 +0,0 @@ -// This is the content script for mochitest-e10s-utils - -// We hook up some events and forward them back to the parent for the tests -// This is only a partial solution to tests using these events - tests which -// check, eg, event.target is the content window are still likely to be -// confused. -// But it's a good start... -["load", "DOMContentLoaded", "pageshow"].forEach(eventName => { - addEventListener(eventName, function eventHandler(event) { - // Some tests also rely on load events from, eg, iframes, so we should see - // if we can do something sane to support that too. - if (event.target == content.document) { - sendAsyncMessage("Test:Event", {name: event.type}); - } - }, true); -}); diff --git a/testing/mochitest/mochitest-e10s-utils.js b/testing/mochitest/mochitest-e10s-utils.js index 24cac2c212e4..55fe1e2453cb 100644 --- a/testing/mochitest/mochitest-e10s-utils.js +++ b/testing/mochitest/mochitest-e10s-utils.js @@ -1,82 +1,6 @@ // Utilities for running tests in an e10s environment. -// There are some tricks/shortcuts that test code takes that we don't see -// in the real browser code. These include setting content.location.href -// (which doesn't work in test code with e10s enabled as the document object -// is yet to be created), waiting for certain events the main browser doesn't -// care about and so doesn't normally get special support, eg, the "pageshow" -// or "load" events). -// So we make some hacks to pretend these work in the test suite. - -// Ideally all these hacks could be removed, but this can only happen when -// the tests are refactored to not use these tricks. But this would be a huge -// amount of work and is unlikely to happen anytime soon... - -const CONTENT_URL = "chrome://mochikit/content/mochitest-e10s-utils-content.js"; - -// This is an object that is used as the "location" on a remote document or -// window. It will be overwritten as the real document and window are made -// available. -let locationStub = function(browser) { - this.browser = browser; -}; -locationStub.prototype = { - get href() { - return this.browser.webNavigation.currentURI.spec; - }, - set href(val) { - this.browser.loadURI(val); - }, - assign: function(url) { - this.href = url; - } -}; - -// This object is used in place of contentWindow while we wait for it to be -// overwritten as the real window becomes available. -let TemporaryWindowStub = function(browser) { - this._locationStub = new locationStub(browser); -}; - -TemporaryWindowStub.prototype = { - // save poor developers from getting confused about why the window isn't - // working like a window should.. - toString: function() { - return "[Window Stub for e10s tests]"; - }, - get location() { - return this._locationStub; - }, - set location(val) { - this._locationStub.href = val; - }, - get document() { - // so tests can say: document.location.... - return this; - } -}; - -// An observer called when a new remote browser element is created. We replace -// the _contentWindow in new browsers with our TemporaryWindowStub object. -function observeNewFrameloader(subject, topic, data) { - let browser = subject.QueryInterface(Ci.nsIFrameLoader).ownerElement; - browser._contentWindow = new TemporaryWindowStub(browser); -} - function e10s_init() { - // Use the global message manager to inject a content script into all browsers. - let globalMM = Cc["@mozilla.org/globalmessagemanager;1"] - .getService(Ci.nsIMessageListenerManager); - globalMM.loadFrameScript(CONTENT_URL, true); - globalMM.addMessageListener("Test:Event", function(message) { - let event = document.createEvent('HTMLEvents'); - event.initEvent(message.data.name, true, true, {}); - message.target.dispatchEvent(event); - }); - - // We add an observer so we can notice new elements created - Services.obs.addObserver(observeNewFrameloader, "remote-browser-shown", false); - // Listen for an 'oop-browser-crashed' event and log it so people analysing // test logs have a clue about what is going on. window.addEventListener("oop-browser-crashed", (event) => { From c63d728731ed3787812d695df92a8effcea6a1fc Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 15 Sep 2014 16:42:27 -0700 Subject: [PATCH 25/32] Bug 1066433 - Fix how event notifications work for e10s shims (r=mconley) --- .../addoncompat/RemoteAddonsChild.jsm | 115 ++++++++++++------ .../addoncompat/RemoteAddonsParent.jsm | 4 +- toolkit/content/browser-child.js | 4 + 3 files changed, 81 insertions(+), 42 deletions(-) diff --git a/toolkit/components/addoncompat/RemoteAddonsChild.jsm b/toolkit/components/addoncompat/RemoteAddonsChild.jsm index 8eee6ace8971..d8f2b552dcd7 100644 --- a/toolkit/components/addoncompat/RemoteAddonsChild.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsChild.jsm @@ -42,45 +42,52 @@ let NotificationTracker = { init: function() { let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"] .getService(Ci.nsISyncMessageSender); - cpmm.addMessageListener("Addons:AddNotification", this); - cpmm.addMessageListener("Addons:RemoveNotification", this); + cpmm.addMessageListener("Addons:ChangeNotification", this); let [paths] = cpmm.sendSyncMessage("Addons:GetNotifications"); this._paths = paths; + this._registered = new Map(); this._watchers = {}; }, receiveMessage: function(msg) { - let path = msg.data; + let path = msg.data.path; + let count = msg.data.count; let tracked = this._paths; for (let component of path) { tracked = setDefault(tracked, component, {}); } - let count = tracked._count || 0; - - switch (msg.name) { - case "Addons:AddNotification": - count++; - break; - case "Addons:RemoveNotification": - count--; - break; - } tracked._count = count; - for (let cb of this._watchers[path[0]]) { - cb(path, count); + if (this._watchers[path[0]]) { + for (let watcher of this._watchers[path[0]]) { + this.runCallback(watcher, path, count); + } } }, - watch: function(component1, callback) { - setDefault(this._watchers, component1, []).push(callback); + runCallback: function(watcher, path, count) { + let pathString = path.join("/"); + let registeredSet = this._registered.get(watcher); + let registered = registeredSet.has(pathString); + if (count && !registered) { + watcher.track(path, true); + registeredSet.add(pathString); + } else if (!count && registered) { + watcher.track(path, false); + registeredSet.delete(pathString); + } + }, - function enumerate(tracked, curPath) { + watch: function(component1, watcher) { + setDefault(this._watchers, component1, []).push(watcher); + this._registered.set(watcher, new Set()); + + let enumerate = (tracked, curPath) => { for (let component in tracked) { if (component == "_count") { - callback(curPath, tracked._count); + this.runCallback(watcher, curPath, tracked._count); } else { let path = curPath.slice(); if (component === "true") { @@ -94,7 +101,17 @@ let NotificationTracker = { } } enumerate(this._paths[component1] || {}, [component1]); - } + }, + + unwatch: function(component1, watcher) { + let watchers = this._watchers[component1]; + let index = watchers.lastIndexOf(watcher); + if (index > -1) { + watchers.splice(index, 1); + } + + this._registered.delete(watcher); + }, }; // This code registers an nsIContentPolicy in the child process. When @@ -110,18 +127,18 @@ let ContentPolicyChild = { let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); registrar.registerFactory(this._classID, this._classDescription, this._contractID, this); - NotificationTracker.watch("content-policy", (path, count) => this.track(path, count)); + NotificationTracker.watch("content-policy", this); }, QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver, Ci.nsIChannelEventSink, Ci.nsIFactory, Ci.nsISupportsWeakReference]), - track: function(path, count) { + track: function(path, register) { let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); - if (count == 1) { + if (register) { catMan.addCategoryEntry("content-policy", this._contractID, this._contractID, false, true); - } else if (count == 0) { + } else { catMan.deleteCategoryEntry("content-policy", this._contractID, false); } }, @@ -294,17 +311,17 @@ let AboutProtocolChild = { init: function() { this._instances = {}; - NotificationTracker.watch("about-protocol", (path, count) => this.track(path, count)); + NotificationTracker.watch("about-protocol", this); }, - track: function(path, count) { + track: function(path, register) { let contractID = path[1]; let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); - if (count == 1) { + if (register) { let instance = new AboutProtocolInstance(contractID); this._instances[contractID] = instance; registrar.registerFactory(this._classID, this._classDescription, contractID, instance); - } else if (count == 0) { + } else { delete this._instances[contractID]; registerFactory.unregisterFactory(this._classID, this); } @@ -315,14 +332,14 @@ let AboutProtocolChild = { // the parent asks for notifications on the given topic. let ObserverChild = { init: function() { - NotificationTracker.watch("observer", (path, count) => this.track(path, count)); + NotificationTracker.watch("observer", this); }, - track: function(path, count) { + track: function(path, register) { let topic = path[1]; - if (count == 1) { + if (register) { Services.obs.addObserver(this, topic, false); - } else if (count == 0) { + } else { Services.obs.removeObserver(this, topic); } }, @@ -344,16 +361,20 @@ let ObserverChild = { function EventTargetChild(childGlobal) { this._childGlobal = childGlobal; - NotificationTracker.watch("event", (path, count) => this.track(path, count)); + NotificationTracker.watch("event", this); } EventTargetChild.prototype = { - track: function(path, count) { + uninit: function() { + NotificationTracker.unwatch("event", this); + }, + + track: function(path, register) { let eventType = path[1]; let useCapture = path[2]; - if (count == 1) { + if (register) { this._childGlobal.addEventListener(eventType, this, useCapture, true); - } else if (count == 0) { + } else { this._childGlobal.removeEventListener(eventType, this, useCapture); } }, @@ -380,6 +401,10 @@ function SandboxChild(chromeGlobal) } SandboxChild.prototype = { + uninit: function() { + this.clearSandboxes(); + }, + addListener: function() { let webProgress = this.chromeGlobal.docShell.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebProgress); @@ -393,10 +418,7 @@ SandboxChild.prototype = { }, onLocationChange: function(webProgress, request, location, flags) { - if (this.sandboxes.length) { - this.removeListener(); - } - this.sandboxes = []; + this.clearSandboxes(); }, addSandbox: function(sandbox) { @@ -406,6 +428,13 @@ SandboxChild.prototype = { this.sandboxes.push(sandbox); }, + clearSandboxes: function() { + if (this.sandboxes.length) { + this.removeListener(); + } + this.sandboxes = []; + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference]) }; @@ -434,4 +463,10 @@ let RemoteAddonsChild = { // Return this so it gets rooted in the content script. return [new EventTargetChild(global), sandboxChild]; }, + + uninit: function(perTabShims) { + for (let shim of perTabShims) { + shim.uninit(); + } + }, }; diff --git a/toolkit/components/addoncompat/RemoteAddonsParent.jsm b/toolkit/components/addoncompat/RemoteAddonsParent.jsm index 63aeb0cb3e9e..231a2d69f224 100644 --- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm @@ -59,7 +59,7 @@ let NotificationTracker = { let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); - ppmm.broadcastAsyncMessage("Addons:AddNotification", path); + ppmm.broadcastAsyncMessage("Addons:ChangeNotification", {path: path, count: count}); }, remove: function(path) { @@ -71,7 +71,7 @@ let NotificationTracker = { let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"] .getService(Ci.nsIMessageBroadcaster); - ppmm.broadcastAsyncMessage("Addons:RemoveNotification", path); + ppmm.broadcastAsyncMessage("Addons:ChangeNotification", {path: path, count: tracked._count}); }, receiveMessage: function(msg) { diff --git a/toolkit/content/browser-child.js b/toolkit/content/browser-child.js index 02a9363c228b..39c0300897ac 100644 --- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -373,6 +373,10 @@ if (Services.appinfo.browserTabsRemoteAutostart) { // Currently, the addon shims are only supported when autostarting // with remote tabs. AddonsChild = RemoteAddonsChild.init(this); + + addEventListener("unload", () => { + RemoteAddonsChild.uninit(AddonsChild); + }); } addMessageListener("NetworkPrioritizer:AdjustPriority", (msg) => { From 19f4c40d0c7add1f36f3201084bc301cfbb9b556 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Mon, 15 Sep 2014 16:42:27 -0700 Subject: [PATCH 26/32] Bug 1066433 - Make shims work when contentWindow is unavailable (r=mconley) --- .../addoncompat/RemoteAddonsParent.jsm | 53 ++++++++++++++++++- .../addoncompat/multiprocessShims.js | 13 +++-- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/toolkit/components/addoncompat/RemoteAddonsParent.jsm b/toolkit/components/addoncompat/RemoteAddonsParent.jsm index 231a2d69f224..2a76c277bc82 100644 --- a/toolkit/components/addoncompat/RemoteAddonsParent.jsm +++ b/toolkit/components/addoncompat/RemoteAddonsParent.jsm @@ -627,19 +627,69 @@ RemoteBrowserElementInterposition.getters.docShell = function(addon, target) { return remoteChromeGlobal.docShell; }; +// We use this in place of the real browser.contentWindow if we +// haven't yet received a CPOW for the child process's window. This +// happens if the tab has just started loading. +function makeDummyContentWindow(browser) { + let dummyContentWindow = { + set location(url) { + browser.loadURI(url, null, null); + } + }; + return dummyContentWindow; +} + RemoteBrowserElementInterposition.getters.contentWindow = function(addon, target) { + // If we don't have a CPOW yet, just return something we can use for + // setting the location. This is useful for tests that create a tab + // and immediately set contentWindow.location. + if (!target.contentWindowAsCPOW) { + return makeDummyContentWindow(target); + } return target.contentWindowAsCPOW; }; +let DummyContentDocument = { + readyState: "loading" +}; + RemoteBrowserElementInterposition.getters.contentDocument = function(addon, target) { + // If we don't have a CPOW yet, just return something we can use to + // examine readyState. This is useful for tests that create a new + // tab and then immediately start polling readyState. + if (!target.contentDocumentAsCPOW) { + return DummyContentDocument; + } return target.contentDocumentAsCPOW; }; +let TabBrowserElementInterposition = new Interposition("TabBrowserElementInterposition", + EventTargetInterposition); + +TabBrowserElementInterposition.getters.contentWindow = function(addon, target) { + if (!target.selectedBrowser.contentWindowAsCPOW) { + return makeDummyContentWindow(target.selectedBrowser); + } + return target.selectedBrowser.contentWindowAsCPOW; +}; + +TabBrowserElementInterposition.getters.contentDocument = function(addon, target) { + let browser = target.selectedBrowser; + if (!browser.contentDocumentAsCPOW) { + return DummyContentDocument; + } + return browser.contentDocumentAsCPOW; +}; + let ChromeWindowInterposition = new Interposition("ChromeWindowInterposition", EventTargetInterposition); ChromeWindowInterposition.getters.content = function(addon, target) { - return target.gBrowser.selectedBrowser.contentWindowAsCPOW; + let browser = target.gBrowser.selectedBrowser; + if (!browser.contentWindowAsCPOW) { + return makeDummyContentWindow(browser); + } + return browser.contentWindowAsCPOW; }; let RemoteAddonsParent = { @@ -677,6 +727,7 @@ let RemoteAddonsParent = { register("ContentDocShellTreeItem", ContentDocShellTreeItemInterposition); register("ContentDocument", ContentDocumentInterposition); register("RemoteBrowserElement", RemoteBrowserElementInterposition); + register("TabBrowserElement", TabBrowserElementInterposition); register("ChromeWindow", ChromeWindowInterposition); return result; diff --git a/toolkit/components/addoncompat/multiprocessShims.js b/toolkit/components/addoncompat/multiprocessShims.js index 5be6ffc38f94..51a0d1b72ea4 100644 --- a/toolkit/components/addoncompat/multiprocessShims.js +++ b/toolkit/components/addoncompat/multiprocessShims.js @@ -87,11 +87,14 @@ AddonInterpositionService.prototype = { } const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - if ((target instanceof Ci.nsIDOMXULElement) && - target.localName == "browser" && - target.namespaceURI == XUL_NS && - target.getAttribute("remote") == "true") { - return "RemoteBrowserElement"; + if (target instanceof Ci.nsIDOMXULElement) { + if (target.localName == "browser" && target.isRemoteBrowser) { + return "RemoteBrowserElement"; + } + + if (target.localName == "tabbrowser") { + return "TabBrowserElement"; + } } if (target instanceof Ci.nsIDOMChromeWindow) { From 4728b7838284e79959a289dfb533c73fcc54a94c Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Mon, 15 Sep 2014 19:46:14 -0400 Subject: [PATCH 27/32] bug 1062567 - prevent gcc lto builds from dropping SyscallAsm on the floor r=froydnj --- security/sandbox/linux/moz.build | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/security/sandbox/linux/moz.build b/security/sandbox/linux/moz.build index e08cc3617e8a..04397a6b284f 100644 --- a/security/sandbox/linux/moz.build +++ b/security/sandbox/linux/moz.build @@ -23,6 +23,12 @@ SOURCES += [ 'SandboxFilter.cpp', ] +# gcc lto likes to put the top level asm in syscall.cc in a different partition +# from the function using it which breaks the build. Work around that by +# forcing there to be only one partition. +if '-flto' in CONFIG['OS_CXXFLAGS'] and not CONFIG['CLANG_CXX']: + LDFLAGS += ['--param lto-partitions=1'] + DEFINES['NS_NO_XPCOM'] = True DISABLE_STL_WRAPPING = True From 9a1ec24aef98ac853c3bdb0573e37cf322c9bd65 Mon Sep 17 00:00:00 2001 From: Camilo Viecco Date: Mon, 15 Sep 2014 17:17:12 -0700 Subject: [PATCH 28/32] Bug 1067565 - Built-in pins expires decades later. r=keeler --- security/manager/boot/src/PublicKeyPinningService.cpp | 3 ++- security/pkix/include/pkix/Time.h | 3 +++ security/pkix/lib/pkixtime.cpp | 8 ++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/security/manager/boot/src/PublicKeyPinningService.cpp b/security/manager/boot/src/PublicKeyPinningService.cpp index f34c214bd8fa..a4fb4969776d 100644 --- a/security/manager/boot/src/PublicKeyPinningService.cpp +++ b/security/manager/boot/src/PublicKeyPinningService.cpp @@ -296,7 +296,8 @@ PublicKeyPinningService::ChainHasValidPins(const CERTCertList* certList, if (!certList) { return false; } - if (time > TimeFromElapsedSecondsAD(kPreloadPKPinsExpirationTime)) { + if (time > TimeFromEpochInSeconds(kPreloadPKPinsExpirationTime / + PR_USEC_PER_SEC)) { return true; } if (!hostname || hostname[0] == 0) { diff --git a/security/pkix/include/pkix/Time.h b/security/pkix/include/pkix/Time.h index 7fd8811e3e8e..b8d6ee906145 100644 --- a/security/pkix/include/pkix/Time.h +++ b/security/pkix/include/pkix/Time.h @@ -118,6 +118,9 @@ inline Time TimeFromElapsedSecondsAD(uint64_t elapsedSecondsAD) Time Now(); +// Note the epoch is the unix epoch (ie 00:00:00 UTC, 1 January 1970) +Time TimeFromEpochInSeconds(uint64_t secondsSinceEpoch); + } } // namespace mozilla::pkix #endif // mozilla_pkix__Time_h diff --git a/security/pkix/lib/pkixtime.cpp b/security/pkix/lib/pkixtime.cpp index 5a6d4394e099..499784e4ecb3 100644 --- a/security/pkix/lib/pkixtime.cpp +++ b/security/pkix/lib/pkixtime.cpp @@ -59,4 +59,12 @@ Now() return TimeFromElapsedSecondsAD(seconds); } +Time +TimeFromEpochInSeconds(uint64_t secondsSinceEpoch) +{ + uint64_t seconds = (DaysBeforeYear(1970) * Time::ONE_DAY_IN_SECONDS) + + secondsSinceEpoch; + return TimeFromElapsedSecondsAD(seconds); +} + } } // namespace mozilla::pkix From 70f2e5e54b7685eb725d5341b8b3fcaeb332f521 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 15 Sep 2014 20:25:12 -0400 Subject: [PATCH 29/32] Bug 1049774 - GMPInstallManager logs when logging disabled. r=gfritzsche --- toolkit/modules/GMPInstallManager.jsm | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/toolkit/modules/GMPInstallManager.jsm b/toolkit/modules/GMPInstallManager.jsm index 87b280aa6696..af4b9c38b826 100644 --- a/toolkit/modules/GMPInstallManager.jsm +++ b/toolkit/modules/GMPInstallManager.jsm @@ -32,10 +32,16 @@ this.EXPORTED_SYMBOLS = ["GMPInstallManager", "GMPExtractor", "GMPDownloader", var gLocale = null; const PARENT_LOGGER_ID = "GMPInstallManager"; +// Used to determine if logging should be enabled +XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function() { + return Preferences.get("media.gmp-manager.log", false); +}); + // Setup the parent logger with dump logging. It'll only be used if logging is -// enabled though. +// enabled though. We don't actually have any fatal logging errors, so setting +// the log level to fatal effectively disables it. let parentLogger = Log.repository.getLogger(PARENT_LOGGER_ID); -parentLogger.level = Log.Level.Debug; +parentLogger.level = gLogEnabled ? Log.Level.Debug : Log.Level.Fatal; let appender = new Log.DumpAppender(); parentLogger.addAppender(appender); @@ -49,18 +55,12 @@ XPCOMUtils.defineLazyGetter(this, "gCertUtils", function() { XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel", "resource://gre/modules/UpdateChannel.jsm"); -// Used to determine if logging should be enabled -XPCOMUtils.defineLazyGetter(this, "gLogEnabled", function() { - return GMPPrefs.get(GMPPrefs.KEY_LOG_ENABLED); -}); - - function getScopedLogger(prefix) { - var parentScope = gLogEnabled ? PARENT_LOGGER_ID + "." : ""; - return Log.repository.getLogger(parentScope + prefix); + // `PARENT_LOGGER_ID.` being passed here effectively links this logger + // to the parentLogger. + return Log.repository.getLogger(PARENT_LOGGER_ID + "." + prefix); } - /** * Manages preferences for GMP addons */ @@ -294,7 +294,7 @@ GMPInstallManager.prototype = { * Obtains a URL with replacement of vars */ _getURL: function() { - let log = getScopedLogger("GMPInstallManager._getURL"); + let log = getScopedLogger("_getURL"); // Use the override URL if it is specified. The override URL is just like // the normal URL but it does not check the cert. let url = GMPPrefs.get(GMPPrefs.KEY_URL_OVERRIDE); @@ -336,7 +336,7 @@ GMPInstallManager.prototype = { * type: Sometimes specifies type of rejection */ checkForAddons: function() { - let log = getScopedLogger("GMPInstallManager.checkForAddons"); + let log = getScopedLogger("checkForAddons"); if (this._deferred) { log.error("checkForAddons already called"); return Promise.reject({type: "alreadycalled"}); @@ -419,7 +419,7 @@ GMPInstallManager.prototype = { * This will only install/update the OpenH264 plugin */ simpleCheckAndInstall: function() { - let log = getScopedLogger("GMPInstallManager.simpleCheckAndInstall"); + let log = getScopedLogger("simpleCheckAndInstall"); let autoUpdate = GMPPrefs.get(GMPPrefs.KEY_ADDON_AUTOUPDATE, OPEN_H264_ID, true); @@ -505,7 +505,7 @@ GMPInstallManager.prototype = { * @param event The nsIDOMEvent for the load */ onLoadXML: function(event) { - let log = getScopedLogger("GMPInstallManager.onLoadXML"); + let log = getScopedLogger("onLoadXML"); log.info("request completed downloading document"); let certs = null; @@ -526,7 +526,7 @@ GMPInstallManager.prototype = { * Returns the status code for the XMLHttpRequest */ _getChannelStatus: function(request) { - let log = getScopedLogger("GMPInstallManager._getChannelStatus"); + let log = getScopedLogger("_getChannelStatus"); let status = 0; try { status = request.status; @@ -546,7 +546,7 @@ GMPInstallManager.prototype = { * @param event The nsIDOMEvent for the error */ onErrorXML: function(event) { - let log = getScopedLogger("GMPInstallManager.onErrorXML"); + let log = getScopedLogger("onErrorXML"); let request = event.target; let status = this._getChannelStatus(request); let message = "request.status: " + status; @@ -566,7 +566,7 @@ GMPInstallManager.prototype = { */ parseResponseXML: function() { try { - let log = getScopedLogger("GMPInstallManager.parseResponseXML"); + let log = getScopedLogger("parseResponseXML"); let updatesElement = this._request.responseXML.documentElement; if (!updatesElement) { let message = "empty updates document"; From 2175404baccd08ee59826787f0b173b2cf1175c9 Mon Sep 17 00:00:00 2001 From: "Brian R. Bondy" Date: Mon, 15 Sep 2014 20:29:35 -0400 Subject: [PATCH 30/32] Backout bug 945192 for intermittent failures. r=rstrong --- .../maintenanceservice/workmonitor.cpp | 2 + toolkit/components/telemetry/Histograms.json | 8 +- toolkit/mozapps/update/common/errors.h | 5 - toolkit/mozapps/update/common/uachelper.cpp | 95 --------- toolkit/mozapps/update/common/uachelper.h | 7 +- .../mozapps/update/common/updatehelper.cpp | 1 + toolkit/mozapps/update/common/updatehelper.h | 4 - toolkit/mozapps/update/nsUpdateService.js | 6 +- .../tests/unit_aus_update/head_update.js | 3 - toolkit/mozapps/update/updater/moz.build | 2 - toolkit/mozapps/update/updater/updater.cpp | 194 ++++-------------- 11 files changed, 47 insertions(+), 280 deletions(-) diff --git a/toolkit/components/maintenanceservice/workmonitor.cpp b/toolkit/components/maintenanceservice/workmonitor.cpp index dd74aa4047dd..50e4beddb110 100644 --- a/toolkit/components/maintenanceservice/workmonitor.cpp +++ b/toolkit/components/maintenanceservice/workmonitor.cpp @@ -30,6 +30,8 @@ static const int TIME_TO_WAIT_ON_UPDATER = 15 * 60 * 1000; char16_t* MakeCommandLine(int argc, char16_t **argv); BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode); +BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath, + LPCWSTR newFileName); /* * Read the update.status file and sets isApplying to true if diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 6b3350c673b1..3ed0456ba79c 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -3337,15 +3337,9 @@ "description": "Updater: The interval in days between the previous and the current background update check when the check was timer initiated" }, "UPDATER_STATUS_CODES": { - "expires_in_version": "35", - "kind": "enumerated", - "n_values": 50, - "description": "Updater: the status of the latest update performed" - }, - "UPDATER_ALL_STATUS_CODES": { "expires_in_version": "never", "kind": "enumerated", - "n_values": 200, + "n_values": 50, "description": "Updater: the status of the latest update performed" }, "UPDATER_UPDATES_ENABLED": { diff --git a/toolkit/mozapps/update/common/errors.h b/toolkit/mozapps/update/common/errors.h index b79740165187..360f2e3f2539 100644 --- a/toolkit/mozapps/update/common/errors.h +++ b/toolkit/mozapps/update/common/errors.h @@ -69,11 +69,6 @@ #define WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID 47 #define WRITE_ERROR_SHARING_VIOLATION_NOPID 48 -#define FOTA_FILE_OPERATION_ERROR 49 -#define FOTA_RECOVERY_ERROR 50 - -#define SECURE_LOCATION_UPDATE_ERROR 51 - // The following error codes are only used by updater.exe // when a fallback key exists and XPCShell tests are being run. #define FALLBACKKEY_UNKNOWN_ERROR 100 diff --git a/toolkit/mozapps/update/common/uachelper.cpp b/toolkit/mozapps/update/common/uachelper.cpp index 7e29e05ce26d..74ae4ca283f1 100644 --- a/toolkit/mozapps/update/common/uachelper.cpp +++ b/toolkit/mozapps/update/common/uachelper.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "uachelper.h" #include "updatelogging.h" @@ -162,15 +161,11 @@ UACHelper::DisableUnneededPrivileges(HANDLE token, BOOL result = TRUE; for (size_t i = 0; i < count; i++) { if (SetPrivilege(token, unneededPrivs[i], FALSE)) { -#ifdef UPDATER_LOG_PRIVS LOG(("Disabled unneeded token privilege: %s.", unneededPrivs[i])); -#endif } else { -#ifdef UPDATER_LOG_PRIVS LOG(("Could not disable token privilege value: %s. (%d)", unneededPrivs[i], GetLastError())); -#endif result = FALSE; } } @@ -225,93 +220,3 @@ UACHelper::CanUserElevate() return canElevate; } - -/** - * Denies write access for everyone on the specified path. - * - * @param path The file path to modify the DACL on - * @param originalACL out parameter, set only if successful. - * caller must free. - * @return true on success - */ -bool -UACHelper::DenyWriteACLOnPath(LPCWSTR path, PACL *originalACL, - PSECURITY_DESCRIPTOR *sd) -{ - // Get the old security information on the path. - // Note that the actual buffer to be freed is contained in *sd. - // originalACL points within *sd's buffer. - *originalACL = nullptr; - *sd = nullptr; - DWORD result = - GetNamedSecurityInfoW(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, - nullptr, nullptr, originalACL, nullptr, sd); - if (result != ERROR_SUCCESS) { - *sd = nullptr; - *originalACL = nullptr; - return false; - } - - // Adjust the security for everyone to deny write - EXPLICIT_ACCESSW ea; - ZeroMemory(&ea, sizeof(EXPLICIT_ACCESSW)); - ea.grfAccessPermissions = FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | - FILE_WRITE_DATA | FILE_WRITE_EA; - ea.grfAccessMode = DENY_ACCESS; - ea.grfInheritance = NO_INHERITANCE; - ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; - ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP; - ea.Trustee.ptstrName = L"EVERYONE"; - PACL dacl = nullptr; - result = SetEntriesInAclW(1, &ea, *originalACL, &dacl); - if (result != ERROR_SUCCESS) { - LocalFree(*sd); - *originalACL = nullptr; - *sd = nullptr; - return false; - } - - // Update the path to have a the new DACL - result = SetNamedSecurityInfoW(const_cast(path), SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION, nullptr, nullptr, - dacl, nullptr); - LocalFree(dacl); - return result == ERROR_SUCCESS; -} - -/** - * Determines if the specified directory only has updater.exe inside of it, - * and nothing else. - * - * @param inputPath the directory path to search - * @return true if updater.exe is the only file in the directory - */ -bool -UACHelper::IsDirectorySafe(LPCWSTR inputPath) -{ - WIN32_FIND_DATAW findData; - HANDLE findHandle = nullptr; - - WCHAR searchPath[MAX_PATH + 1] = { L'\0' }; - wsprintfW(searchPath, L"%s\\*.*", inputPath); - - findHandle = FindFirstFileW(searchPath, &findData); - if(findHandle == INVALID_HANDLE_VALUE) { - return false; - } - - // Enumerate the files and if we find anything other than the current - // directory, the parent directory, or updater.exe. Then fail. - do { - if(wcscmp(findData.cFileName, L".") != 0 && - wcscmp(findData.cFileName, L"..") != 0 && - wcscmp(findData.cFileName, L"updater.exe") != 0) { - FindClose(findHandle); - return false; - } - } while(FindNextFileW(findHandle, &findData)); - FindClose(findHandle); - - return true; -} - diff --git a/toolkit/mozapps/update/common/uachelper.h b/toolkit/mozapps/update/common/uachelper.h index cad7ebabd0ec..6481ff5b5ee4 100644 --- a/toolkit/mozapps/update/common/uachelper.h +++ b/toolkit/mozapps/update/common/uachelper.h @@ -12,15 +12,12 @@ public: static HANDLE OpenLinkedToken(HANDLE token); static BOOL DisablePrivileges(HANDLE token); static bool CanUserElevate(); - static bool IsDirectorySafe(LPCWSTR inputPath); - static bool DenyWriteACLOnPath(LPCWSTR path, PACL *originalACL, - PSECURITY_DESCRIPTOR *sd); private: static BOOL SetPrivilege(HANDLE token, LPCTSTR privs, BOOL enable); - static BOOL DisableUnneededPrivileges(HANDLE token, + static BOOL DisableUnneededPrivileges(HANDLE token, LPCTSTR *unneededPrivs, size_t count); - static LPCTSTR PrivsToDisable[]; + static LPCTSTR PrivsToDisable[]; }; #endif diff --git a/toolkit/mozapps/update/common/updatehelper.cpp b/toolkit/mozapps/update/common/updatehelper.cpp index ae3e177cb1b3..45ab09212132 100644 --- a/toolkit/mozapps/update/common/updatehelper.cpp +++ b/toolkit/mozapps/update/common/updatehelper.cpp @@ -33,6 +33,7 @@ using mozilla::MakeUnique; using mozilla::UniquePtr; WCHAR* MakeCommandLine(int argc, WCHAR **argv); +BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra); /** * Obtains the path of a file in the same directory as the specified file. diff --git a/toolkit/mozapps/update/common/updatehelper.h b/toolkit/mozapps/update/common/updatehelper.h index 5ba2b0c0a583..9e21a9c646e5 100644 --- a/toolkit/mozapps/update/common/updatehelper.h +++ b/toolkit/mozapps/update/common/updatehelper.h @@ -17,10 +17,6 @@ BOOL DoesFallbackKeyExist(); BOOL IsLocalFile(LPCWSTR file, BOOL &isLocal); DWORD StartServiceCommand(int argc, LPCWSTR* argv); BOOL IsUnpromptedElevation(BOOL &isUnpromptedElevation); -BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, - LPCWSTR siblingFilePath, - LPCWSTR newFileName); -BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra); #define SVC_NAME L"MozillaMaintenance" diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js index fe3a3ff2de02..b4c3af66e8ec 100644 --- a/toolkit/mozapps/update/nsUpdateService.js +++ b/toolkit/mozapps/update/nsUpdateService.js @@ -162,7 +162,6 @@ const WRITE_ERROR_SHARING_VIOLATION_NOPROCESSFORPID = 47; const WRITE_ERROR_SHARING_VIOLATION_NOPID = 48; const FOTA_FILE_OPERATION_ERROR = 49; const FOTA_RECOVERY_ERROR = 50; -const SECURE_LOCATION_UPDATE_ERROR = 51; const CERT_ATTR_CHECK_FAILED_NO_UPDATE = 100; const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101; @@ -1478,8 +1477,7 @@ function handleUpdateFailure(update, errorCode) { return true; } - if (update.errorCode == ELEVATION_CANCELED || - update.errorCode == SECURE_LOCATION_UPDATE_ERROR) { + if (update.errorCode == ELEVATION_CANCELED) { writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING); return true; } @@ -2385,7 +2383,7 @@ UpdateService.prototype = { if (parts.length > 1) { result = parseInt(parts[1]) || INVALID_UPDATER_STATUS_CODE; } - Services.telemetry.getHistogramById("UPDATER_ALL_STATUS_CODES").add(result); + Services.telemetry.getHistogramById("UPDATER_STATUS_CODES").add(result); } catch(e) { // Don't allow any exception to be propagated. Cu.reportError(e); diff --git a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js index d7e312828eab..f68292310ac3 100644 --- a/toolkit/mozapps/update/tests/unit_aus_update/head_update.js +++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js @@ -1508,18 +1508,15 @@ function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) { if (gDisableReplaceFallback) { env.set("MOZ_NO_REPLACE_FALLBACK", "1"); } - env.set("MOZ_EMULATE_ELEVATION_PATH", "1"); let process = AUS_Cc["@mozilla.org/process/util;1"]. createInstance(AUS_Ci.nsIProcess); process.init(updateBin); - process.run(true, args, args.length); if (gDisableReplaceFallback) { env.set("MOZ_NO_REPLACE_FALLBACK", ""); } - env.set("MOZ_EMULATE_ELEVATION_PATH", ""); let status = readStatusFile(); if (process.exitValue != aExpectedExitValue || status != aExpectedStatus) { diff --git a/toolkit/mozapps/update/updater/moz.build b/toolkit/mozapps/update/updater/moz.build index f1ee7649927f..153217539d6c 100644 --- a/toolkit/mozapps/update/updater/moz.build +++ b/toolkit/mozapps/update/updater/moz.build @@ -41,8 +41,6 @@ if CONFIG['OS_ARCH'] == 'WINNT': 'shlwapi', 'crypt32', 'advapi32', - 'ole32', - 'rpcrt4', ] else: USE_LIBS += [ diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 01fd9f6c6f64..ce6af32b9f3b 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -111,7 +111,6 @@ static bool sUseHardLinks = true; #ifdef XP_WIN #include "updatehelper.h" -#include // Closes the handle if valid and if the updater is elevated returns with the // return code specified. This prevents multiple launches of the callback @@ -2394,9 +2393,8 @@ int NS_main(int argc, NS_tchar **argv) bool useService = false; bool testOnlyFallbackKeyExists = false; bool noServiceFallback = getenv("MOZ_NO_SERVICE_FALLBACK") != nullptr; - bool emulateElevation = getenv("MOZ_EMULATE_ELEVATION_PATH") != nullptr; putenv(const_cast("MOZ_NO_SERVICE_FALLBACK=")); - putenv(const_cast("MOZ_EMULATE_ELEVATION_PATH=")); + // We never want the service to be used unless we build with // the maintenance service. #ifdef MOZ_MAINTENANCE_SERVICE @@ -2486,6 +2484,12 @@ int NS_main(int argc, NS_tchar **argv) return 1; } + if (sStagedUpdate) { + LOG(("Performing a staged update")); + } else if (sReplaceRequest) { + LOG(("Performing a replace request")); + } + #ifdef MOZ_WIDGET_GONK const char *prioEnv = getenv("MOZ_UPDATER_PRIO"); if (prioEnv) { @@ -2614,15 +2618,13 @@ int NS_main(int argc, NS_tchar **argv) return 1; } - if (!emulateElevation) { - updateLockFileHandle = CreateFileW(updateLockFilePath, - GENERIC_READ | GENERIC_WRITE, - 0, - nullptr, - OPEN_ALWAYS, - FILE_FLAG_DELETE_ON_CLOSE, - nullptr); - } + updateLockFileHandle = CreateFileW(updateLockFilePath, + GENERIC_READ | GENERIC_WRITE, + 0, + nullptr, + OPEN_ALWAYS, + FILE_FLAG_DELETE_ON_CLOSE, + nullptr); NS_tsnprintf(elevatedLockFilePath, sizeof(elevatedLockFilePath)/sizeof(elevatedLockFilePath[0]), @@ -2773,8 +2775,7 @@ int NS_main(int argc, NS_tchar **argv) // If the service can't be used when staging and update, make sure that // the UAC prompt is not shown! In this case, just set the status to // pending and the update will be applied during the next startup. - // When emulateElevation is true fall through to the elevation code path. - if (!useService && sStagedUpdate && !emulateElevation) { + if (!useService && sStagedUpdate) { if (updateLockFileHandle != INVALID_HANDLE_VALUE) { CloseHandle(updateLockFileHandle); } @@ -2800,145 +2801,35 @@ int NS_main(int argc, NS_tchar **argv) } } - DWORD returnCode = 0; - - // If we didn't want to use the service at all, or if an update was - // already happening, or launching the service command failed, then + // If we didn't want to use the service at all, or if an update was + // already happening, or launching the service command failed, then // launch the elevated updater.exe as we do without the service. // We don't launch the elevated updater in the case that we did have // write access all along because in that case the only reason we're - // using the service is because we are testing. - if (!useService && !noServiceFallback && + // using the service is because we are testing. + if (!useService && !noServiceFallback && updateLockFileHandle == INVALID_HANDLE_VALUE) { + SHELLEXECUTEINFO sinfo; + memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO)); + sinfo.cbSize = sizeof(SHELLEXECUTEINFO); + sinfo.fMask = SEE_MASK_FLAG_NO_UI | + SEE_MASK_FLAG_DDEWAIT | + SEE_MASK_NOCLOSEPROCESS; + sinfo.hwnd = nullptr; + sinfo.lpFile = argv[0]; + sinfo.lpParameters = cmdLine; + sinfo.lpVerb = L"runas"; + sinfo.nShow = SW_SHOWNORMAL; - // Get a unique directory name to secure - RPC_WSTR guidString = RPC_WSTR(L""); - GUID guid; - HRESULT hr = CoCreateGuid(&guid); - BOOL result = TRUE; - bool safeToUpdate = true; - WCHAR secureUpdaterPath[MAX_PATH + 1] = { L'\0' }; - WCHAR secureDirPath[MAX_PATH + 1] = { L'\0' }; - if (SUCCEEDED(hr)) { - UuidToString(&guid, &guidString); - result = PathGetSiblingFilePath(secureDirPath, argv[0], - reinterpret_cast(guidString)); - RpcStringFree(&guidString); + bool result = ShellExecuteEx(&sinfo); + free(cmdLine); + + if (result) { + WaitForSingleObject(sinfo.hProcess, INFINITE); + CloseHandle(sinfo.hProcess); } else { - // This should never happen, but just in case - result = PathGetSiblingFilePath(secureDirPath, argv[0], L"tmp_update"); + WriteStatusFile(ELEVATION_CANCELED); } - - if (!result) { - fprintf(stderr, "Could not obtain secure update directory path"); - safeToUpdate = false; - } - - // If it's still safe to update, create the directory - if (safeToUpdate) { - result = CreateDirectoryW(secureDirPath, nullptr); - if (!result) { - fprintf(stderr, "Could not create secure update directory"); - safeToUpdate = false; - } - } - - // If it's still safe to update, get the new updater path - if (safeToUpdate) { - wcsncpy(secureUpdaterPath, secureDirPath, MAX_PATH); - result = PathAppendSafe(secureUpdaterPath, L"updater.exe"); - if (!result) { - fprintf(stderr, "Could not obtain secure updater file name"); - safeToUpdate = false; - } - } - - // If it's still safe to update, copy the file in - if (safeToUpdate) { - result = CopyFileW(argv[0], secureUpdaterPath, TRUE); - if (!result) { - fprintf(stderr, "Could not copy updater to secure location"); - safeToUpdate = false; - } - } - - // If it's still safe to update, restrict access to the directory item - // itself so that the directory cannot be deleted and re-created, - // nor have its properties modified. Note that this does not disallow - // adding items inside the directory. - HANDLE handle = INVALID_HANDLE_VALUE; - if (safeToUpdate) { - handle = CreateFileW(secureDirPath, GENERIC_READ, FILE_SHARE_READ, - nullptr, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, nullptr); - safeToUpdate = handle != INVALID_HANDLE_VALUE; - } - - // If it's still safe to update, deny write access completely to the - // directory. - PACL originalACL = nullptr; - PSECURITY_DESCRIPTOR sd = nullptr; - if (safeToUpdate) { - safeToUpdate = UACHelper::DenyWriteACLOnPath(secureDirPath, - &originalACL, &sd); - } - - // If it's still safe to update, verify that there is only updater.exe - // in the directory and nothing else. - if (safeToUpdate) { - if (!UACHelper::IsDirectorySafe(secureDirPath)) { - safeToUpdate = false; - } - } - - if (!safeToUpdate) { - fprintf(stderr, "Will not proceed to copy secure updater because it " - "is not safe to do so."); - WriteStatusFile(SECURE_LOCATION_UPDATE_ERROR); - } else { - SHELLEXECUTEINFO sinfo; - memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO)); - sinfo.cbSize = sizeof(SHELLEXECUTEINFO); - sinfo.fMask = SEE_MASK_FLAG_NO_UI | - SEE_MASK_FLAG_DDEWAIT | - SEE_MASK_NOCLOSEPROCESS; - sinfo.hwnd = nullptr; - sinfo.lpFile = secureUpdaterPath; - sinfo.lpParameters = cmdLine; - sinfo.lpVerb = emulateElevation ? L"open" : L"runas"; - sinfo.nShow = SW_SHOWNORMAL; - - bool result = ShellExecuteEx(&sinfo); - free(cmdLine); - - if (result) { - WaitForSingleObject(sinfo.hProcess, INFINITE); - // Bubble the elevated updater return code to this updater - GetExitCodeProcess(sinfo.hProcess, &returnCode); - CloseHandle(sinfo.hProcess); - } else { - WriteStatusFile(ELEVATION_CANCELED); - } - } - - // All done, revert back the permissions. - if (originalACL) { - SetNamedSecurityInfoW(const_cast(secureDirPath), SE_FILE_OBJECT, - DACL_SECURITY_INFORMATION, nullptr, nullptr, - originalACL, nullptr); - } - if (sd) { - LocalFree(sd); - } - - // Done with the directory, no need to lock it. - if (INVALID_HANDLE_VALUE != handle) { - CloseHandle(handle); - } - - // We no longer need the secure updater and directory - DeleteFileW(secureUpdaterPath); - RemoveDirectoryW(secureDirPath); } if (argc > callbackIndex) { @@ -2953,7 +2844,7 @@ int NS_main(int argc, NS_tchar **argv) // We didn't use the service and we did run the elevated updater.exe. // The elevated updater.exe is responsible for writing out the // update.status file. - return returnCode; + return 0; } else if(useService) { // The service command was launched. The service is responsible for // writing out the update.status file. @@ -2975,13 +2866,6 @@ int NS_main(int argc, NS_tchar **argv) } #endif - if (sStagedUpdate) { - LOG(("Performing a staged update")); - } - else if (sReplaceRequest) { - LOG(("Performing a replace request")); - } - #if defined(MOZ_WIDGET_GONK) // In gonk, the master b2g process sets its umask to 0027 because // there's no reason for it to ever create world-readable files. @@ -3286,7 +3170,7 @@ int NS_main(int argc, NS_tchar **argv) } } } - EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, gSucceeded ? 0 : 1); + EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0); #endif /* XP_WIN */ #ifdef XP_MACOSX if (gSucceeded) { From 3eee564f75d5efd11a14ef2e329db2598f10f43d Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Mon, 15 Sep 2014 18:23:03 -0700 Subject: [PATCH 31/32] Bug 1001090 - Followup: fix merge error in browser-plugins.js on a CLOSED TREE. r=bustage --- browser/base/content/browser-plugins.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index e021cb79a359..ba2f9505034f 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -620,8 +620,8 @@ var gPluginHandler = { buttons.push(submitButton); #endif - let notification = notificationBox.appendNotification(messageString, "plugin-crashed", - iconURL, priority, buttons); + notification = notificationBox.appendNotification(messageString, "plugin-crashed", + iconURL, priority, buttons); // Add the "learn more" link. let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; From c0b6c35cc741f39e7560981779b31ceafced60ef Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 15 Sep 2014 23:20:24 -0400 Subject: [PATCH 32/32] No bug - Revert browser-plugins.js to revision 687318d464a5. a=me --- browser/base/content/browser-plugins.js | 1080 +++++++++++++++++++---- 1 file changed, 912 insertions(+), 168 deletions(-) diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index ba2f9505034f..a300291ae9df 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -8,81 +8,10 @@ var gPluginHandler = { PREF_HIDE_MISSING_PLUGINS_NOTIFICATION: "plugins.hideMissingPluginsNotification", PREF_SESSION_PERSIST_MINUTES: "plugin.sessionPermissionNow.intervalInMinutes", PREF_PERSISTENT_DAYS: "plugin.persistentPermissionAlways.intervalInDays", - MESSAGES: [ - "PluginContent:ShowClickToPlayNotification", - "PluginContent:RemoveNotification", - "PluginContent:UpdateHiddenPluginUI", - "PluginContent:HideNotificationBar", - "PluginContent:ShowInstallNotification", - "PluginContent:InstallSinglePlugin", - "PluginContent:ShowPluginCrashedNotification", - "PluginContent:SubmitReport", - "PluginContent:LinkClickCallback", - ], - init: function () { - const mm = window.messageManager; - for (let msg of this.MESSAGES) { - mm.addMessageListener(msg, this); - } - window.addEventListener("unload", this); - }, - - uninit: function () { - const mm = window.messageManager; - for (let msg of this.MESSAGES) { - mm.removeMessageListener(msg, this); - } - window.removeEventListener("unload", this); - }, - - handleEvent: function (event) { - if (event.type == "unload") { - this.uninit(); - } - }, - - receiveMessage: function (msg) { - switch (msg.name) { - case "PluginContent:ShowClickToPlayNotification": - this.showClickToPlayNotification(msg.target, msg.data.plugins, msg.data.showNow, - msg.principal, msg.data.host); - break; - case "PluginContent:RemoveNotification": - this.removeNotification(msg.target, msg.data.name); - break; - case "PluginContent:UpdateHiddenPluginUI": - this.updateHiddenPluginUI(msg.target, msg.data.haveInsecure, msg.data.actions, - msg.principal, msg.data.host); - break; - case "PluginContent:HideNotificationBar": - this.hideNotificationBar(msg.target, msg.data.name); - break; - case "PluginContent:ShowInstallNotification": - return this.showInstallNotification(msg.target, msg.data.pluginInfo); - case "PluginContent:InstallSinglePlugin": - this.installSinglePlugin(msg.data.pluginInfo); - break; - case "PluginContent:ShowPluginCrashedNotification": - this.showPluginCrashedNotification(msg.target, msg.data.messageString, - msg.data.pluginDumpID, msg.data.browserDumpID); - break; - case "PluginContent:SubmitReport": - this.submitReport(msg.data.pluginDumpID, msg.data.browserDumpID, msg.data.keyVals); - break; - case "PluginContent:LinkClickCallback": - switch (msg.data.name) { - case "managePlugins": - case "openHelpPage": - case "openPluginUpdatePage": - this[msg.data.name].apply(this); - break; - } - break; - default: - Cu.reportError("gPluginHandler did not expect to handle message " + msg.name); - break; - } + getPluginUI: function (plugin, anonid) { + return plugin.ownerDocument. + getAnonymousElementByAttribute(plugin, "anonid", anonid); }, #ifdef MOZ_CRASHREPORTER @@ -93,6 +22,186 @@ var gPluginHandler = { }, #endif + _getPluginInfo: function (pluginElement) { + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + pluginElement.QueryInterface(Ci.nsIObjectLoadingContent); + + let tagMimetype; + let pluginName = gNavigatorBundle.getString("pluginInfo.unknownPlugin"); + let pluginTag = null; + let permissionString = null; + let fallbackType = null; + let blocklistState = null; + + tagMimetype = pluginElement.actualType; + if (tagMimetype == "") { + tagMimetype = pluginElement.type; + } + + if (gPluginHandler.isKnownPlugin(pluginElement)) { + pluginTag = pluginHost.getPluginTagForType(pluginElement.actualType); + pluginName = gPluginHandler.makeNicePluginName(pluginTag.name); + + permissionString = pluginHost.getPermissionStringForType(pluginElement.actualType); + fallbackType = pluginElement.defaultFallbackType; + blocklistState = pluginHost.getBlocklistStateForType(pluginElement.actualType); + // Make state-softblocked == state-notblocked for our purposes, + // they have the same UI. STATE_OUTDATED should not exist for plugin + // items, but let's alias it anyway, just in case. + if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED || + blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) { + blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + } + } + + return { mimetype: tagMimetype, + pluginName: pluginName, + pluginTag: pluginTag, + permissionString: permissionString, + fallbackType: fallbackType, + blocklistState: blocklistState, + }; + }, + + // Map the plugin's name to a filtered version more suitable for user UI. + makeNicePluginName : function (aName) { + if (aName == "Shockwave Flash") + return "Adobe Flash"; + + // Clean up the plugin name by stripping off parenthetical clauses, + // trailing version numbers or "plugin". + // EG, "Foo Bar (Linux) Plugin 1.23_02" --> "Foo Bar" + // Do this by first stripping the numbers, etc. off the end, and then + // removing "Plugin" (and then trimming to get rid of any whitespace). + // (Otherwise, something like "Java(TM) Plug-in 1.7.0_07" gets mangled) + let newName = aName.replace(/\(.*?\)/g, ""). + replace(/[\s\d\.\-\_\(\)]+$/, ""). + replace(/\bplug-?in\b/i, "").trim(); + return newName; + }, + + /** + * Update the visibility of the plugin overlay. + */ + setVisibility : function (plugin, overlay, shouldShow) { + overlay.classList.toggle("visible", shouldShow); + }, + + /** + * Check whether the plugin should be visible on the page. A plugin should + * not be visible if the overlay is too big, or if any other page content + * overlays it. + * + * This function will handle showing or hiding the overlay. + * @returns true if the plugin is invisible. + */ + shouldShowOverlay : function (plugin, overlay) { + // If the overlay size is 0, we haven't done layout yet. Presume that + // plugins are visible until we know otherwise. + if (overlay.scrollWidth == 0) { + return true; + } + + // Is the 's size too small to hold what we want to show? + let pluginRect = plugin.getBoundingClientRect(); + // XXX bug 446693. The text-shadow on the submitted-report text at + // the bottom causes scrollHeight to be larger than it should be. + let overflows = (overlay.scrollWidth > Math.ceil(pluginRect.width)) || + (overlay.scrollHeight - 5 > Math.ceil(pluginRect.height)); + if (overflows) { + return false; + } + + // Is the plugin covered up by other content so that it is not clickable? + // Floating point can confuse .elementFromPoint, so inset just a bit + let left = pluginRect.left + 2; + let right = pluginRect.right - 2; + let top = pluginRect.top + 2; + let bottom = pluginRect.bottom - 2; + let centerX = left + (right - left) / 2; + let centerY = top + (bottom - top) / 2; + let points = [[left, top], + [left, bottom], + [right, top], + [right, bottom], + [centerX, centerY]]; + + if (right <= 0 || top <= 0) { + return false; + } + + let contentWindow = plugin.ownerDocument.defaultView; + let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + + for (let [x, y] of points) { + let el = cwu.elementFromPoint(x, y, true, true); + if (el !== plugin) { + return false; + } + } + + return true; + }, + + addLinkClickCallback: function (linkNode, callbackName /*callbackArgs...*/) { + // XXX just doing (callback)(arg) was giving a same-origin error. bug? + let self = this; + let callbackArgs = Array.prototype.slice.call(arguments).slice(2); + linkNode.addEventListener("click", + function(evt) { + if (!evt.isTrusted) + return; + evt.preventDefault(); + if (callbackArgs.length == 0) + callbackArgs = [ evt ]; + (self[callbackName]).apply(self, callbackArgs); + }, + true); + + linkNode.addEventListener("keydown", + function(evt) { + if (!evt.isTrusted) + return; + if (evt.keyCode == evt.DOM_VK_RETURN) { + evt.preventDefault(); + if (callbackArgs.length == 0) + callbackArgs = [ evt ]; + evt.preventDefault(); + (self[callbackName]).apply(self, callbackArgs); + } + }, + true); + }, + + // Helper to get the binding handler type from a plugin object + _getBindingType : function(plugin) { + if (!(plugin instanceof Ci.nsIObjectLoadingContent)) + return null; + + switch (plugin.pluginFallbackType) { + case Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED: + return "PluginNotFound"; + case Ci.nsIObjectLoadingContent.PLUGIN_DISABLED: + return "PluginDisabled"; + case Ci.nsIObjectLoadingContent.PLUGIN_BLOCKLISTED: + return "PluginBlocklisted"; + case Ci.nsIObjectLoadingContent.PLUGIN_OUTDATED: + return "PluginOutdated"; + case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY: + return "PluginClickToPlay"; + case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE: + return "PluginVulnerableUpdatable"; + case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE: + return "PluginVulnerableNoUpdate"; + case Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW: + return "PluginPlayPreview"; + default: + // Not all states map to a handler + return null; + } + }, + supportedPlugins: { "mimetypes": { "application/x-shockwave-flash": "flash", @@ -156,6 +265,196 @@ var gPluginHandler = { return false; }, + handleEvent : function(event) { + let eventType = event.type; + + if (eventType == "PluginRemoved") { + let doc = event.target; + let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document); + if (browser) + this._setPluginNotificationIcon(browser); + return; + } + + if (eventType == "PluginCrashed" && + !(event.target instanceof Ci.nsIObjectLoadingContent)) { + // If the event target is not a plugin object (i.e., an or + // element), this call is for a window-global plugin. + this.pluginInstanceCrashed(event.target, event); + return; + } + + let plugin = event.target; + let doc = plugin.ownerDocument; + + if (!(plugin instanceof Ci.nsIObjectLoadingContent)) + return; + + if (eventType == "PluginBindingAttached") { + // The plugin binding fires this event when it is created. + // As an untrusted event, ensure that this object actually has a binding + // and make sure we don't handle it twice + let overlay = this.getPluginUI(plugin, "main"); + if (!overlay || overlay._bindingHandled) { + return; + } + overlay._bindingHandled = true; + + // Lookup the handler for this binding + eventType = this._getBindingType(plugin); + if (!eventType) { + // Not all bindings have handlers + return; + } + } + + let shouldShowNotification = false; + let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document); + if (!browser) + return; + + switch (eventType) { + case "PluginCrashed": + this.pluginInstanceCrashed(plugin, event); + break; + + case "PluginNotFound": + let installable = this.showInstallNotification(plugin, eventType); + // For non-object plugin tags, register a click handler to install the + // plugin. Object tags can, and often do, deal with that themselves, + // so don't stomp on the page developers toes. + if (installable && !(plugin instanceof HTMLObjectElement)) { + let installStatus = this.getPluginUI(plugin, "installStatus"); + installStatus.setAttribute("installable", "true"); + let iconStatus = this.getPluginUI(plugin, "icon"); + iconStatus.setAttribute("installable", "true"); + + let installLink = this.getPluginUI(plugin, "installPluginLink"); + this.addLinkClickCallback(installLink, "installSinglePlugin", plugin); + } + break; + + case "PluginBlocklisted": + case "PluginOutdated": + shouldShowNotification = true; + break; + + case "PluginVulnerableUpdatable": + let updateLink = this.getPluginUI(plugin, "checkForUpdatesLink"); + this.addLinkClickCallback(updateLink, "openPluginUpdatePage"); + /* FALLTHRU */ + + case "PluginVulnerableNoUpdate": + case "PluginClickToPlay": + this._handleClickToPlayEvent(plugin); + let overlay = this.getPluginUI(plugin, "main"); + let pluginName = this._getPluginInfo(plugin).pluginName; + let messageString = gNavigatorBundle.getFormattedString("PluginClickToActivate", [pluginName]); + let overlayText = this.getPluginUI(plugin, "clickToPlay"); + overlayText.textContent = messageString; + if (eventType == "PluginVulnerableUpdatable" || + eventType == "PluginVulnerableNoUpdate") { + let vulnerabilityString = gNavigatorBundle.getString(eventType); + let vulnerabilityText = this.getPluginUI(plugin, "vulnerabilityStatus"); + vulnerabilityText.textContent = vulnerabilityString; + } + shouldShowNotification = true; + break; + + case "PluginPlayPreview": + this._handlePlayPreviewEvent(plugin); + break; + + case "PluginDisabled": + let manageLink = this.getPluginUI(plugin, "managePluginsLink"); + this.addLinkClickCallback(manageLink, "managePlugins"); + shouldShowNotification = true; + break; + + case "PluginInstantiated": + shouldShowNotification = true; + break; + } + + // Show the in-content UI if it's not too big. The crashed plugin handler already did this. + if (eventType != "PluginCrashed") { + let overlay = this.getPluginUI(plugin, "main"); + if (overlay != null) { + this.setVisibility(plugin, overlay, + this.shouldShowOverlay(plugin, overlay)); + let resizeListener = (event) => { + this.setVisibility(plugin, overlay, + this.shouldShowOverlay(plugin, overlay)); + this._setPluginNotificationIcon(browser); + }; + plugin.addEventListener("overflow", resizeListener); + plugin.addEventListener("underflow", resizeListener); + } + } + + let closeIcon = this.getPluginUI(plugin, "closeIcon"); + if (closeIcon) { + closeIcon.addEventListener("click", function(aEvent) { + if (aEvent.button == 0 && aEvent.isTrusted) + gPluginHandler.hideClickToPlayOverlay(plugin); + }, true); + } + + if (shouldShowNotification) { + this._showClickToPlayNotification(browser, plugin, false); + } + }, + + isKnownPlugin: function PH_isKnownPlugin(objLoadingContent) { + return (objLoadingContent.getContentTypeForMIMEType(objLoadingContent.actualType) == + Ci.nsIObjectLoadingContent.TYPE_PLUGIN); + }, + + canActivatePlugin: function PH_canActivatePlugin(objLoadingContent) { + // if this isn't a known plugin, we can't activate it + // (this also guards pluginHost.getPermissionStringForType against + // unexpected input) + if (!gPluginHandler.isKnownPlugin(objLoadingContent)) + return false; + + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType); + let principal = objLoadingContent.ownerDocument.defaultView.top.document.nodePrincipal; + let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString); + + let isFallbackTypeValid = + objLoadingContent.pluginFallbackType >= Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY && + objLoadingContent.pluginFallbackType <= Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE; + + if (objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW) { + // checking if play preview is subject to CTP rules + let playPreviewInfo = pluginHost.getPlayPreviewInfo(objLoadingContent.actualType); + isFallbackTypeValid = !playPreviewInfo.ignoreCTP; + } + + return !objLoadingContent.activated && + pluginPermission != Ci.nsIPermissionManager.DENY_ACTION && + isFallbackTypeValid; + }, + + hideClickToPlayOverlay: function(aPlugin) { + let overlay = this.getPluginUI(aPlugin, "main"); + if (overlay) { + overlay.classList.remove("visible"); + } + }, + + stopPlayPreview: function PH_stopPlayPreview(aPlugin, aPlayPlugin) { + let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent); + if (objLoadingContent.activated) + return; + + if (aPlayPlugin) + objLoadingContent.playPlugin(); + else + objLoadingContent.cancelPlayPreview(); + }, + newPluginInstalled : function(event) { // browser elements are anonymous so we can't just use target. var browser = event.originalTarget; @@ -172,8 +471,10 @@ var gPluginHandler = { }, // Callback for user clicking on a missing (unsupported) plugin. - installSinglePlugin: function (pluginInfo) { + installSinglePlugin: function (plugin) { var missingPlugins = new Map(); + + var pluginInfo = this._getPluginInfo(plugin); missingPlugins.set(pluginInfo.mimetype, pluginInfo); openDialog("chrome://mozapps/content/plugins/pluginInstallerWizard.xul", @@ -182,19 +483,27 @@ var gPluginHandler = { }, // Callback for user clicking on a disabled plugin - managePlugins: function () { + managePlugins: function (aEvent) { BrowserOpenAddonsMgr("addons://list/plugin"); }, // Callback for user clicking on the link in a click-to-play plugin // (where the plugin has an update) - openPluginUpdatePage: function () { + openPluginUpdatePage: function (aEvent) { openUILinkIn(Services.urlFormatter.formatURLPref("plugins.update.url"), "tab"); }, #ifdef MOZ_CRASHREPORTER - submitReport: function submitReport(pluginDumpID, browserDumpID, keyVals) { - keyVals = keyVals || {}; + submitReport: function submitReport(pluginDumpID, browserDumpID, plugin) { + let keyVals = {}; + if (plugin) { + let userComment = this.getPluginUI(plugin, "submitComment").value.trim(); + if (userComment) + keyVals.PluginUserComment = userComment; + if (this.getPluginUI(plugin, "submitURLOptIn").checked) + keyVals.PluginContentURL = plugin.ownerDocument.URL; + } + this.CrashSubmit.submit(pluginDumpID, { recordSubmission: true, extraExtraKeyVals: keyVals }); if (browserDumpID) @@ -212,16 +521,19 @@ var gPluginHandler = { openHelpLink("plugin-crashed", false); }, - showInstallNotification: function (browser, pluginInfo) { + showInstallNotification: function (aPlugin) { let hideMissingPluginsNotification = Services.prefs.getBoolPref(this.PREF_HIDE_MISSING_PLUGINS_NOTIFICATION); if (hideMissingPluginsNotification) { return false; } + let browser = gBrowser.getBrowserForDocument(aPlugin.ownerDocument + .defaultView.top.document); if (!browser.missingPlugins) browser.missingPlugins = new Map(); + let pluginInfo = this._getPluginInfo(aPlugin); browser.missingPlugins.set(pluginInfo.mimetype, pluginInfo); // only show notification for small subset of plugins @@ -271,6 +583,120 @@ var gPluginHandler = { mainAction, secondaryActions, options); return true; }, + // Event listener for click-to-play plugins. + _handleClickToPlayEvent: function PH_handleClickToPlayEvent(aPlugin) { + let doc = aPlugin.ownerDocument; + let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document); + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent); + // guard against giving pluginHost.getPermissionStringForType a type + // not associated with any known plugin + if (!gPluginHandler.isKnownPlugin(objLoadingContent)) + return; + let permissionString = pluginHost.getPermissionStringForType(objLoadingContent.actualType); + let principal = doc.defaultView.top.document.nodePrincipal; + let pluginPermission = Services.perms.testPermissionFromPrincipal(principal, permissionString); + + let overlay = this.getPluginUI(aPlugin, "main"); + + if (pluginPermission == Ci.nsIPermissionManager.DENY_ACTION) { + if (overlay) { + overlay.classList.remove("visible"); + } + return; + } + + if (overlay) { + overlay.addEventListener("click", gPluginHandler._overlayClickListener, true); + } + }, + + _overlayClickListener: { + handleEvent: function PH_handleOverlayClick(aEvent) { + let plugin = document.getBindingParent(aEvent.target); + let contentWindow = plugin.ownerDocument.defaultView.top; + // gBrowser.getBrowserForDocument does not exist in the case where we + // drag-and-dropped a tab from a window containing only that tab. In + // that case, the window gets destroyed. + let browser = gBrowser.getBrowserForDocument ? + gBrowser.getBrowserForDocument(contentWindow.document) : + null; + // If browser is null here, we've been drag-and-dropped from another + // window, and this is the wrong click handler. + if (!browser) { + aEvent.target.removeEventListener("click", gPluginHandler._overlayClickListener, true); + return; + } + let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + // Have to check that the target is not the link to update the plugin + if (!(aEvent.originalTarget instanceof HTMLAnchorElement) && + (aEvent.originalTarget.getAttribute('anonid') != 'closeIcon') && + aEvent.button == 0 && aEvent.isTrusted) { + gPluginHandler._showClickToPlayNotification(browser, plugin, true); + aEvent.stopPropagation(); + aEvent.preventDefault(); + } + } + }, + + _handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) { + let doc = aPlugin.ownerDocument; + let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document); + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + let pluginInfo = this._getPluginInfo(aPlugin); + let playPreviewInfo = pluginHost.getPlayPreviewInfo(pluginInfo.mimetype); + + let previewContent = this.getPluginUI(aPlugin, "previewPluginContent"); + let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; + if (!iframe) { + // lazy initialization of the iframe + iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe"); + iframe.className = "previewPluginContentFrame"; + previewContent.appendChild(iframe); + + // Force a style flush, so that we ensure our binding is attached. + aPlugin.clientTop; + } + iframe.src = playPreviewInfo.redirectURL; + + // MozPlayPlugin event can be dispatched from the extension chrome + // code to replace the preview content with the native plugin + previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(aEvent) { + if (!aEvent.isTrusted) + return; + + previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true); + + let playPlugin = !aEvent.detail; + gPluginHandler.stopPlayPreview(aPlugin, playPlugin); + + // cleaning up: removes overlay iframe from the DOM + let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0]; + if (iframe) + previewContent.removeChild(iframe); + }, true); + + if (!playPreviewInfo.ignoreCTP) { + gPluginHandler._showClickToPlayNotification(browser, aPlugin, false); + } + }, + + reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() { + let browser = gBrowser.selectedBrowser; + let contentWindow = browser.contentWindow; + let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let plugins = cwu.plugins; + for (let plugin of plugins) { + let overlay = this.getPluginUI(plugin, "main"); + if (overlay) + overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true); + let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent); + if (gPluginHandler.canActivatePlugin(objLoadingContent)) + gPluginHandler._handleClickToPlayEvent(plugin); + } + gPluginHandler._showClickToPlayNotification(browser, null, false); + }, _clickToPlayNotificationEventCallback: function PH_ctpEventCallback(event) { if (event == "showing") { @@ -289,11 +715,20 @@ var gPluginHandler = { // list again this.options.primaryPlugin = null; } - else if (event == "removed") { - // Once the notification is removed, let the content script clear any - // caches it may have populated. - this.browser.messageManager.sendAsyncMessage("BrowserPlugins:NotificationRemoved"); + }, + + // Match the behaviour of nsPermissionManager + _getHostFromPrincipal: function PH_getHostFromPrincipal(principal) { + if (!principal.URI || principal.URI.schemeIs("moz-nullprincipal")) { + return "(null)"; } + + try { + if (principal.URI.host) + return principal.URI.host; + } catch (e) {} + + return principal.origin; }, /** @@ -301,7 +736,7 @@ var gPluginHandler = { * and activate plugins if necessary. * aNewState should be either "allownow" "allowalways" or "block" */ - _updatePluginPermission: function (aNotification, aPluginInfo, aNewState) { + _updatePluginPermission: function PH_setPermissionForPlugins(aNotification, aPluginInfo, aNewState) { let permission; let expireType; let expireTime; @@ -359,20 +794,74 @@ var gPluginHandler = { let browser = aNotification.browser; let contentWindow = browser.contentWindow; if (aNewState != "continue") { - let principal = aNotification.options.principal; + let principal = contentWindow.document.nodePrincipal; Services.perms.addFromPrincipal(principal, aPluginInfo.permissionString, permission, expireType, expireTime); aPluginInfo.pluginPermissionType = expireType; } - browser.messageManager.sendAsyncMessage("BrowserPlugins:ActivatePlugins", { - pluginInfo: aPluginInfo, - newState: aNewState, - }); + // Manually activate the plugins that would have been automatically + // activated. + let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let plugins = cwu.plugins; + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + + let pluginFound = false; + for (let plugin of plugins) { + plugin.QueryInterface(Ci.nsIObjectLoadingContent); + if (!gPluginHandler.isKnownPlugin(plugin)) { + continue; + } + if (aPluginInfo.permissionString == pluginHost.getPermissionStringForType(plugin.actualType)) { + pluginFound = true; + if (aNewState == "block") { + plugin.reload(true); + } else { + if (gPluginHandler.canActivatePlugin(plugin)) { + let overlay = this.getPluginUI(plugin, "main"); + if (overlay) { + overlay.removeEventListener("click", gPluginHandler._overlayClickListener, true); + } + plugin.playPlugin(); + } + } + } + } + + // If there are no instances of the plugin on the page any more, what the + // user probably needs is for us to allow and then refresh. + if (aNewState != "block" && !pluginFound) { + browser.reload(); + } + + this._setPluginNotificationIcon(browser); }, - showClickToPlayNotification: function (browser, plugins, showNow, principal, host) { - let notification = PopupNotifications.getNotification("click-to-play-plugins", browser); + _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser, aPlugin, aShowNow) { + let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser); + let plugins = []; + + // if aPlugin is null, that means the user has navigated back to a page with plugins, and we need + // to collect all the plugins + if (aPlugin === null) { + let contentWindow = aBrowser.contentWindow; + let contentDoc = aBrowser.contentDocument; + let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + // cwu.plugins may contain non-plugin s, filter them out + plugins = cwu.plugins.filter((plugin) => + plugin.getContentTypeForMIMEType(plugin.actualType) == Ci.nsIObjectLoadingContent.TYPE_PLUGIN); + + if (plugins.length == 0) { + if (notification) { + PopupNotifications.remove(notification); + } + return; + } + } else { + plugins = [aPlugin]; + } // If this is a new notification, create a pluginData map, otherwise append let pluginData; @@ -382,11 +871,30 @@ var gPluginHandler = { pluginData = new Map(); } - for (var pluginInfo of plugins) { + let principal = aBrowser.contentDocument.nodePrincipal; + let principalHost = this._getHostFromPrincipal(principal); + + for (var plugin of plugins) { + let pluginInfo = this._getPluginInfo(plugin); + if (pluginInfo.permissionString === null) { + Cu.reportError("No permission string for active plugin."); + continue; + } if (pluginData.has(pluginInfo.permissionString)) { continue; } + let permissionObj = Services.perms. + getPermissionObject(principal, pluginInfo.permissionString, false); + if (permissionObj) { + pluginInfo.pluginPermissionHost = permissionObj.host; + pluginInfo.pluginPermissionType = permissionObj.expireType; + } + else { + pluginInfo.pluginPermissionHost = principalHost; + pluginInfo.pluginPermissionType = undefined; + } + let url; // TODO: allow the blocklist to specify a better link, bug 873093 if (pluginInfo.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) { @@ -404,55 +912,106 @@ var gPluginHandler = { } let primaryPluginPermission = null; - if (showNow) { - primaryPluginPermission = plugins[0].permissionString; + if (aShowNow) { + primaryPluginPermission = this._getPluginInfo(aPlugin).permissionString; } if (notification) { // Don't modify the notification UI while it's on the screen, that would be // jumpy and might allow clickjacking. - if (showNow) { + if (aShowNow) { notification.options.primaryPlugin = primaryPluginPermission; notification.reshow(); - browser.messageManager.sendAsyncMessage("BrowserPlugins:NotificationShown"); + setTimeout(() => { this._setPluginNotificationIcon(aBrowser); }, 0); } return; } let options = { - dismissed: !showNow, + dismissed: !aShowNow, eventCallback: this._clickToPlayNotificationEventCallback, primaryPlugin: primaryPluginPermission, - pluginData: pluginData, - principal: principal, - host: host, + pluginData: pluginData }; - PopupNotifications.show(browser, "click-to-play-plugins", + PopupNotifications.show(aBrowser, "click-to-play-plugins", "", "plugins-notification-icon", null, null, options); - browser.messageManager.sendAsyncMessage("BrowserPlugins:NotificationShown"); + setTimeout(() => { this._setPluginNotificationIcon(aBrowser); }, 0); }, - removeNotification: function (browser, name) { - let notification = PopupNotifications.getNotification(name, browser); - if (notification) - PopupNotifications.remove(notification); - }, + _setPluginNotificationIcon : function PH_setPluginNotificationIcon(aBrowser) { + // Because this is called on a timeout, sanity-check before continuing + if (!aBrowser.docShell || !aBrowser.contentWindow) { + return; + } - hideNotificationBar: function (browser, name) { - let notificationBox = gBrowser.getNotificationBox(browser); - let notification = notificationBox.getNotificationWithValue(name); - if (notification) - notificationBox.removeNotification(notification, true); - }, + let notification = PopupNotifications.getNotification("click-to-play-plugins", aBrowser); + if (!notification) + return; + + // Make a copy of the actions, removing active plugins and checking for + // outdated plugins. + let haveInsecure = false; + let actions = new Map(); + for (let action of notification.options.pluginData.values()) { + switch (action.fallbackType) { + // haveInsecure will trigger the red flashing icon and the infobar + // styling below + case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE: + case Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE: + haveInsecure = true; + // fall through + + case Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY: + actions.set(action.permissionString, action); + continue; + } + } + + // check for hidden plugins + let contentWindow = aBrowser.contentWindow; + let contentDoc = aBrowser.contentDocument; + let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + for (let plugin of cwu.plugins) { + let info = this._getPluginInfo(plugin); + if (!actions.has(info.permissionString)) { + continue; + } + let fallbackType = info.fallbackType; + if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) { + actions.delete(info.permissionString); + if (actions.size == 0) { + break; + } + continue; + } + if (fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY && + fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_UPDATABLE && + fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE) { + continue; + } + let overlay = this.getPluginUI(plugin, "main"); + if (!overlay) { + continue; + } + let shouldShow = this.shouldShowOverlay(plugin, overlay); + this.setVisibility(plugin, overlay, shouldShow); + if (shouldShow) { + actions.delete(info.permissionString); + if (actions.size == 0) { + break; + } + } + } - updateHiddenPluginUI: function (browser, haveInsecure, actions, principal, host) { // Set up the icon document.getElementById("plugins-notification-icon").classList. toggle("plugin-blocked", haveInsecure); // Now configure the notification bar - let notificationBox = gBrowser.getNotificationBox(browser); + + let notificationBox = gBrowser.getNotificationBox(aBrowser); function hideNotification() { let n = notificationBox.getNotificationWithValue("plugin-hidden"); @@ -481,10 +1040,11 @@ var gPluginHandler = { let message; // Icons set directly cannot be manipulated using moz-image-region, so // we use CSS classes instead. + let host = gPluginHandler._getHostFromPrincipal(aBrowser.contentDocument.nodePrincipal); let brand = document.getElementById("bundle_brand").getString("brandShortName"); - if (actions.length == 1) { - let pluginInfo = actions[0]; + if (actions.size == 1) { + let pluginInfo = [...actions.values()][0]; let pluginName = pluginInfo.pluginName; switch (pluginInfo.fallbackType) { @@ -507,6 +1067,12 @@ var gPluginHandler = { // Multi-plugin message = gNavigatorBundle.getFormattedString( "pluginActivateMultiple.message", [host]); + + for (let action of actions.values()) { + if (action.fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY) { + break; + } + } } let buttons = [ @@ -517,7 +1083,7 @@ var gPluginHandler = { Services.telemetry.getHistogramById("PLUGINS_INFOBAR_BLOCK"). add(true); - Services.perms.addFromPrincipal(principal, + Services.perms.addFromPrincipal(aBrowser.contentDocument.nodePrincipal, "plugin-hidden-notification", Services.perms.DENY_ACTION); } @@ -531,7 +1097,7 @@ var gPluginHandler = { let curNotification = PopupNotifications.getNotification("click-to-play-plugins", - browser); + aBrowser); if (curNotification) { curNotification.reshow(); } @@ -546,11 +1112,11 @@ var gPluginHandler = { } } - if (actions.length == 0) { + if (actions.size == 0) { hideNotification(); } else { let notificationPermission = Services.perms.testPermissionFromPrincipal( - principal, "plugin-hidden-notification"); + aBrowser.contentDocument.nodePrincipal, "plugin-hidden-notification"); if (notificationPermission == Ci.nsIPermissionManager.DENY_ACTION) { hideNotification(); } else { @@ -559,11 +1125,6 @@ var gPluginHandler = { } }, - contextMenuCommand: function (browser, plugin, command) { - browser.messageManager.sendAsyncMessage("BrowserPlugins:ContextMenuCommand", - { command: command }, { plugin: plugin }); - }, - // Crashed-plugin observer. Notified once per plugin crash, before events // are dispatched to individual plugin instances. pluginCrashed : function(subject, topic, data) { @@ -587,54 +1148,237 @@ var gPluginHandler = { #endif }, - showPluginCrashedNotification: function (browser, messageString, pluginDumpID, browserDumpID) { - // If there's already an existing notification bar, don't do anything. - let notificationBox = gBrowser.getNotificationBox(browser); - let notification = notificationBox.getNotificationWithValue("plugin-crashed"); - if (notification) + // Crashed-plugin event listener. Called for every instance of a + // plugin in content. + pluginInstanceCrashed: function (target, aEvent) { + // Ensure the plugin and event are of the right type. + if (!(aEvent instanceof Ci.nsIDOMCustomEvent)) return; - // Configure the notification bar - let priority = notificationBox.PRIORITY_WARNING_MEDIUM; - let iconURL = "chrome://mozapps/skin/plugins/notifyPluginCrashed.png"; - let reloadLabel = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label"); - let reloadKey = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey"); - let submitLabel = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.label"); - let submitKey = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.accesskey"); + let propBag = aEvent.detail.QueryInterface(Ci.nsIPropertyBag2); + let submittedReport = propBag.getPropertyAsBool("submittedCrashReport"); + let doPrompt = true; // XXX followup for .getPropertyAsBool("doPrompt"); + let submitReports = true; // XXX followup for .getPropertyAsBool("submitReports"); + let pluginName = propBag.getPropertyAsAString("pluginName"); + let pluginDumpID = propBag.getPropertyAsAString("pluginDumpID"); + let browserDumpID = null; + let gmpPlugin = false; - let buttons = [{ - label: reloadLabel, - accessKey: reloadKey, - popup: null, - callback: function() { browser.reload(); }, - }]; + try { + browserDumpID = propBag.getPropertyAsAString("browserDumpID"); + } catch (e) { + // For GMP crashes we don't get a browser dump. + } + try { + gmpPlugin = propBag.getPropertyAsBool("gmpPlugin"); + } catch (e) { + // This property is only set for GMP plugins. + } + + // For non-GMP plugins, remap the plugin name to a more user-presentable form. + if (!gmpPlugin) { + pluginName = this.makeNicePluginName(pluginName); + } + + let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]); + + let plugin = null, doc; + if (target instanceof Ci.nsIObjectLoadingContent) { + plugin = target; + doc = plugin.ownerDocument; + } else { + doc = target.document; + if (!doc) { + return; + } + // doPrompt is specific to the crashed plugin overlay, and + // therefore is not applicable for window-global plugins. + doPrompt = false; + } + + let status; #ifdef MOZ_CRASHREPORTER - let submitButton = { - label: submitLabel, - accessKey: submitKey, - popup: null, - callback: function() { gPluginHandler.submitReport(pluginDumpID, browserDumpID); }, - }; - if (pluginDumpID) - buttons.push(submitButton); + // Determine which message to show regarding crash reports. + if (submittedReport) { // submitReports && !doPrompt, handled in observer + status = "submitted"; + } + else if (!submitReports && !doPrompt) { + status = "noSubmit"; + } + else if (!pluginDumpID) { + // If we don't have a minidumpID, we can't (or didn't) submit anything. + // This can happen if the plugin is killed from the task manager. + status = "noReport"; + } + else { + status = "please"; + } + + // If we're showing the link to manually trigger report submission, we'll + // want to be able to update all the instances of the UI for this crash to + // show an updated message when a report is submitted. + if (doPrompt) { + let observer = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + observe : (subject, topic, data) => { + let propertyBag = subject; + if (!(propertyBag instanceof Ci.nsIPropertyBag2)) + return; + // Ignore notifications for other crashes. + if (propertyBag.get("minidumpID") != pluginDumpID) + return; + + let statusDiv = this.getPluginUI(plugin, "submitStatus"); + statusDiv.setAttribute("status", data); + }, + + handleEvent : function(event) { + // Not expected to be called, just here for the closure. + } + } + + // Use a weak reference, so we don't have to remove it... + Services.obs.addObserver(observer, "crash-report-status", true); + // ...alas, now we need something to hold a strong reference to prevent + // it from being GC. But I don't want to manually manage the reference's + // lifetime (which should be no greater than the page). + // Clever solution? Use a closue with an event listener on the document. + // When the doc goes away, so do the listener references and the closure. + doc.addEventListener("mozCleverClosureHack", observer, false); + } #endif - notification = notificationBox.appendNotification(messageString, "plugin-crashed", - iconURL, priority, buttons); + let browser = gBrowser.getBrowserForDocument(doc.defaultView.top.document); + let notificationBox = gBrowser.getNotificationBox(browser); + let isShowing = false; - // Add the "learn more" link. - let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - let link = notification.ownerDocument.createElementNS(XULNS, "label"); - link.className = "text-link"; - link.setAttribute("value", gNavigatorBundle.getString("crashedpluginsMessage.learnMore")); - let crashurl = formatURL("app.support.baseURL", true); - crashurl += "plugin-crashed-notificationbar"; - link.href = crashurl; + if (plugin) { + // If there's no plugin (an or element), this call is + // for a window-global plugin. In this case, there's no overlay to show. + isShowing = _setUpPluginOverlay.call(this, plugin, doPrompt, browser); + } - let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText"); - description.appendChild(link); - }, + if (isShowing) { + // If a previous plugin on the page was too small and resulted in adding a + // notification bar, then remove it because this plugin instance it big + // enough to serve as in-content notification. + hideNotificationBar(); + doc.mozNoPluginCrashedNotification = true; + } else { + // If another plugin on the page was large enough to show our UI, we don't + // want to show a notification bar. + if (!doc.mozNoPluginCrashedNotification) + showNotificationBar(pluginDumpID, browserDumpID); + } + + function hideNotificationBar() { + let notification = notificationBox.getNotificationWithValue("plugin-crashed"); + if (notification) + notificationBox.removeNotification(notification, true); + } + + function showNotificationBar(pluginDumpID, browserDumpID) { + // If there's already an existing notification bar, don't do anything. + let notification = notificationBox.getNotificationWithValue("plugin-crashed"); + if (notification) + return; + + // Configure the notification bar + let priority = notificationBox.PRIORITY_WARNING_MEDIUM; + let iconURL = "chrome://mozapps/skin/plugins/notifyPluginCrashed.png"; + let reloadLabel = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.label"); + let reloadKey = gNavigatorBundle.getString("crashedpluginsMessage.reloadButton.accesskey"); + let submitLabel = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.label"); + let submitKey = gNavigatorBundle.getString("crashedpluginsMessage.submitButton.accesskey"); + + let buttons = [{ + label: reloadLabel, + accessKey: reloadKey, + popup: null, + callback: function() { browser.reload(); }, + }]; +#ifdef MOZ_CRASHREPORTER + let submitButton = { + label: submitLabel, + accessKey: submitKey, + popup: null, + callback: function() { gPluginHandler.submitReport(pluginDumpID, browserDumpID); }, + }; + if (pluginDumpID) + buttons.push(submitButton); +#endif + + notification = notificationBox.appendNotification(messageString, "plugin-crashed", + iconURL, priority, buttons); + + // Add the "learn more" link. + let XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + let link = notification.ownerDocument.createElementNS(XULNS, "label"); + link.className = "text-link"; + link.setAttribute("value", gNavigatorBundle.getString("crashedpluginsMessage.learnMore")); + let crashurl = formatURL("app.support.baseURL", true); + crashurl += "plugin-crashed-notificationbar"; + link.href = crashurl; + + let description = notification.ownerDocument.getAnonymousElementByAttribute(notification, "anonid", "messageText"); + description.appendChild(link); + + // Remove the notfication when the page is reloaded. + doc.defaultView.top.addEventListener("unload", function() { + notificationBox.removeNotification(notification); + }, false); + } + + // Configure the crashed-plugin placeholder. + // Returns true if the plugin overlay is visible. + function _setUpPluginOverlay(plugin, doPromptSubmit, browser) { + if (!plugin) { + return false; + } + + // Force a layout flush so the binding is attached. + plugin.clientTop; + let overlay = this.getPluginUI(plugin, "main"); + let statusDiv = this.getPluginUI(plugin, "submitStatus"); + + if (doPromptSubmit) { + this.getPluginUI(plugin, "submitButton").addEventListener("click", + function (event) { + if (event.button != 0 || !event.isTrusted) + return; + this.submitReport(pluginDumpID, browserDumpID, plugin); + pref.setBoolPref("", optInCB.checked); + }.bind(this)); + let optInCB = this.getPluginUI(plugin, "submitURLOptIn"); + let pref = Services.prefs.getBranch("dom.ipc.plugins.reportCrashURL"); + optInCB.checked = pref.getBoolPref(""); + } + + statusDiv.setAttribute("status", status); + + let helpIcon = this.getPluginUI(plugin, "helpIcon"); + this.addLinkClickCallback(helpIcon, "openHelpPage"); + + let crashText = this.getPluginUI(plugin, "crashedText"); + crashText.textContent = messageString; + + let link = this.getPluginUI(plugin, "reloadLink"); + this.addLinkClickCallback(link, "reloadPage", browser); + + let isShowing = this.shouldShowOverlay(plugin, overlay); + + // Is the 's size too small to hold what we want to show? + if (!isShowing) { + // First try hiding the crash report submission UI. + statusDiv.removeAttribute("status"); + + isShowing = this.shouldShowOverlay(plugin, overlay); + } + this.setVisibility(plugin, overlay, isShowing); + + return isShowing; + } + } }; - -gPluginHandler.init();