From 590825b1b61a83b51d26864cf8b506b9b2214f13 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Tue, 19 Nov 2013 16:27:36 -0500 Subject: [PATCH 001/268] Bug 672843 part A - Create the new macro NS_WARN_IF and deprecate NS_ENSURE_* in favor of the explicit warning/return style. Also localize each macro so that it's debug and non-debug versions are local in the file, because that makes it easier for new contributors to understand. r=froydnj sr=jst --- xpcom/glue/nsDebug.h | 127 +++++++++++++++++++++++++++---------------- 1 file changed, 81 insertions(+), 46 deletions(-) diff --git a/xpcom/glue/nsDebug.h b/xpcom/glue/nsDebug.h index 1e656c8127fc..4259c2d2ac8e 100644 --- a/xpcom/glue/nsDebug.h +++ b/xpcom/glue/nsDebug.h @@ -12,7 +12,7 @@ #ifndef nsError_h__ #include "nsError.h" -#endif +#endif #include "nsXPCOM.h" #include "mozilla/Assertions.h" @@ -22,7 +22,35 @@ #include "prprf.h" #endif +/** + * Warn if the given condition is true. The condition is evaluated in both + * release and debug builds, and the result is an expression which can be + * used in subsequent expressions, such as: + * + * if (NS_WARN_IF(NS_FAILED(rv)) + * return rv; + * + * This explicit warning and return is preferred to the NS_ENSURE_* macros + * which hide the warning and the return control flow. + * + * @note This is C++-only + */ +#ifdef __cplusplus #ifdef DEBUG +inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, + int32_t line) +{ + if (MOZ_UNLIKELY(condition)) { + NS_DebugBreak(NS_DEBUG_WARNING, nullptr, expr, file, line); + } + return condition; +} +#define NS_WARN_IF(condition) \ + NS_warn_if_impl(condition, #condition, __FILE__, __LINE__) +#else +#define NS_WARN_IF(condition) (bool)(condition) +#endif +#endif /** * Abort the execution of the program if the expression evaluates to @@ -40,12 +68,16 @@ * Note also that the non-debug version of this macro does not * evaluate the message argument. */ +#ifdef DEBUG #define NS_ABORT_IF_FALSE(_expr, _msg) \ do { \ if (!(_expr)) { \ NS_DebugBreak(NS_DEBUG_ABORT, _msg, #_expr, __FILE__, __LINE__); \ } \ } while(0) +#else +#define NS_ABORT_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) +#endif /** * Warn if a given condition is false. @@ -55,103 +87,105 @@ * Note also that the non-debug version of this macro does not * evaluate the message argument. */ +#ifdef DEBUG #define NS_WARN_IF_FALSE(_expr,_msg) \ do { \ if (!(_expr)) { \ NS_DebugBreak(NS_DEBUG_WARNING, _msg, #_expr, __FILE__, __LINE__); \ } \ } while(0) +#else +#define NS_WARN_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) +#endif -/** - * Test a precondition for truth. If the expression is not true then - * trigger a program failure. - */ -#define NS_PRECONDITION(expr, str) \ - do { \ - if (!(expr)) { \ - NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ - } \ - } while(0) /** * Test an assertion for truth. If the expression is not true then * trigger a program failure. + * + * Note that the non-debug version of this macro does not + * evaluate the message argument. */ +#ifdef DEBUG #define NS_ASSERTION(expr, str) \ do { \ if (!(expr)) { \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ } \ } while(0) +#else +#define NS_ASSERTION(expr, str) do { /* nothing */ } while(0) +#endif /** - * Test a post-condition for truth. If the expression is not true then - * trigger a program failure. + * NS_PRECONDITION/POSTCONDITION are synonyms for NS_ASSERTION. */ -#define NS_POSTCONDITION(expr, str) \ - do { \ - if (!(expr)) { \ - NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ - } \ - } while(0) +#define NS_PRECONDITION(expr, str) NS_ASSERTION(expr, str) +#define NS_POSTCONDITION(expr, str) NS_ASSERTION(expr, str) /** * This macros triggers a program failure if executed. It indicates that * an attempt was made to execute some unimplemented functionality. */ +#ifdef DEBUG #define NS_NOTYETIMPLEMENTED(str) \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, "NotYetImplemented", __FILE__, __LINE__) +#else +#define NS_NOTYETIMPLEMENTED(str) do { /* nothing */ } while(0) +#endif /** * This macros triggers a program failure if executed. It indicates that - * an attempt was made to execute some unimplemented functionality. + * an attempt was made to execute a codepath which should not be reachable. */ +#ifdef DEBUG #define NS_NOTREACHED(str) \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Not Reached", __FILE__, __LINE__) +#else +#define NS_NOTREACHED(str) do { /* nothing */ } while(0) +#endif /** * Log an error message. */ +#ifdef DEBUG #define NS_ERROR(str) \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Error", __FILE__, __LINE__) +#else +#define NS_ERROR(str) do { /* nothing */ } while(0) +#endif /** * Log a warning message. */ +#ifdef DEBUG #define NS_WARNING(str) \ NS_DebugBreak(NS_DEBUG_WARNING, str, nullptr, __FILE__, __LINE__) +#else +#define NS_WARNING(str) do { /* nothing */ } while(0) +#endif /** - * Trigger an abort + * Trigger an debug-only abort. + * + * @see NS_RUNTIMEABORT for release-mode asserts. */ +#ifdef DEBUG #define NS_ABORT() \ NS_DebugBreak(NS_DEBUG_ABORT, nullptr, nullptr, __FILE__, __LINE__) +#else +#define NS_ABORT() do { /* nothing */ } while(0) +#endif /** - * Cause a break + * Trigger a debugger breakpoint, only in debug builds. */ +#ifdef DEBUG #define NS_BREAK() \ NS_DebugBreak(NS_DEBUG_BREAK, nullptr, nullptr, __FILE__, __LINE__) - -#else /* DEBUG */ - -/** - * The non-debug version of these macros do not evaluate the - * expression or the message arguments to the macro. - */ -#define NS_ABORT_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) -#define NS_WARN_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) -#define NS_PRECONDITION(expr, str) do { /* nothing */ } while(0) -#define NS_ASSERTION(expr, str) do { /* nothing */ } while(0) -#define NS_POSTCONDITION(expr, str) do { /* nothing */ } while(0) -#define NS_NOTYETIMPLEMENTED(str) do { /* nothing */ } while(0) -#define NS_NOTREACHED(str) do { /* nothing */ } while(0) -#define NS_ERROR(str) do { /* nothing */ } while(0) -#define NS_WARNING(str) do { /* nothing */ } while(0) -#define NS_ABORT() do { /* nothing */ } while(0) +#else #define NS_BREAK() do { /* nothing */ } while(0) - -#endif /* ! DEBUG */ +#endif /****************************************************************************** ** Macros for static assertions. These are used by the sixgill tool. @@ -230,7 +264,7 @@ /****************************************************************************** ** Macros for terminating execution when an unrecoverable condition is -** reached. These need to be compiled regardless of the DEBUG flag. +** reached. These need to be compiled regardless of the DEBUG flag. ******************************************************************************/ /** @@ -242,10 +276,11 @@ NS_DebugBreak(NS_DEBUG_ABORT, msg, nullptr, __FILE__, __LINE__) -/* Macros for checking the trueness of an expression passed in within an - * interface implementation. These need to be compiled regardless of the */ -/* DEBUG flag -******************************************************************************/ +/* Macros for checking the trueness of an expression passed in within an + * interface implementation. These need to be compiled regardless of the + * DEBUG flag. New code should use NS_WARN_IF(condition) instead! + * @status deprecated + */ #define NS_ENSURE_TRUE(x, ret) \ do { \ From 896491a67948b7d192c27d01a3e1c9e0e3b90869 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Tue, 19 Nov 2013 16:27:36 -0500 Subject: [PATCH 002/268] Bug 672843 part B - Remove NS_ENSURE_PROPER_AGGREGATION, r=froydnj --- xpcom/base/nsAgg.h | 12 ++++++------ xpcom/glue/nsDebug.h | 3 --- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/xpcom/base/nsAgg.h b/xpcom/base/nsAgg.h index 5b9ff7227978..bd1a36d52cc9 100644 --- a/xpcom/base/nsAgg.h +++ b/xpcom/base/nsAgg.h @@ -285,9 +285,9 @@ static nsresult \ _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ void **aResult) \ { \ - *aResult = nullptr; \ - \ - NS_ENSURE_PROPER_AGGREGATION(aOuter, aIID); \ + *aResult = nullptr; \ + if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ + return NS_ERROR_INVALID_ARG; \ \ _InstanceClass* inst = new _InstanceClass(aOuter); \ if (!inst) { \ @@ -308,9 +308,9 @@ static nsresult \ _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ void **aResult) \ { \ - *aResult = nullptr; \ - \ - NS_ENSURE_PROPER_AGGREGATION(aOuter, aIID); \ + *aResult = nullptr; \ + if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ + return NS_ERROR_INVALID_ARG; \ \ _InstanceClass* inst = new _InstanceClass(aOuter); \ if (!inst) { \ diff --git a/xpcom/glue/nsDebug.h b/xpcom/glue/nsDebug.h index 4259c2d2ac8e..8d3f543829c9 100644 --- a/xpcom/glue/nsDebug.h +++ b/xpcom/glue/nsDebug.h @@ -375,9 +375,6 @@ inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, #define NS_ENSURE_NO_AGGREGATION(outer) \ NS_ENSURE_FALSE(outer, NS_ERROR_NO_AGGREGATION) -#define NS_ENSURE_PROPER_AGGREGATION(outer, iid) \ - NS_ENSURE_FALSE(outer && !iid.Equals(NS_GET_IID(nsISupports)), NS_ERROR_INVALID_ARG) - /*****************************************************************************/ #ifdef XPCOM_GLUE From 820707774b001115d005f63646f8e776f2f5461f Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Tue, 19 Nov 2013 16:27:37 -0500 Subject: [PATCH 003/268] Bug 672843 part C - convert most of XPCOM except for xpcom/tests, r=vdjeric --- xpcom/base/nsCycleCollector.cpp | 33 +++++--- xpcom/base/nsDebugImpl.cpp | 3 +- xpcom/base/nsErrorService.cpp | 3 +- xpcom/base/nsGZFileWriter.cpp | 25 ++++-- xpcom/base/nsIMemoryReporter.idl | 3 +- xpcom/base/nsMacUtilsImpl.cpp | 3 +- xpcom/base/nsMemoryImpl.cpp | 3 +- xpcom/base/nsMemoryInfoDumper.cpp | 98 ++++++++++++++-------- xpcom/base/nsMemoryReporterManager.cpp | 18 ++-- xpcom/base/nsMessageLoop.cpp | 6 +- xpcom/base/nsSystemInfo.cpp | 12 ++- xpcom/build/Omnijar.cpp | 6 +- xpcom/build/nsXPCOMStrings.cpp | 6 +- xpcom/build/nsXPComInit.cpp | 56 +++++++------ xpcom/build/perfprobe.cpp | 3 +- xpcom/components/nsCategoryManager.cpp | 26 +++--- xpcom/components/nsComponentManager.cpp | 12 ++- xpcom/ds/nsHashPropertyBag.cpp | 3 +- xpcom/ds/nsINIParserImpl.cpp | 3 +- xpcom/ds/nsObserverService.cpp | 24 ++++-- xpcom/ds/nsProperties.cpp | 17 ++-- xpcom/ds/nsStringEnumerator.cpp | 31 +++---- xpcom/ds/nsSupportsArray.cpp | 3 +- xpcom/ds/nsSupportsPrimitives.cpp | 6 +- xpcom/ds/nsWindowsRegKey.cpp | 74 +++++++++++------ xpcom/glue/nsArrayEnumerator.cpp | 1 - xpcom/glue/nsCOMArray.cpp | 3 +- xpcom/glue/nsComponentManagerUtils.cpp | 18 ++-- xpcom/glue/nsINIParser.cpp | 3 +- xpcom/glue/nsMemory.cpp | 3 +- xpcom/glue/nsThreadUtils.cpp | 36 +++++--- xpcom/glue/nsThreadUtils.h | 3 +- xpcom/io/Base64.cpp | 3 +- xpcom/io/CocoaFileUtils.mm | 20 +++-- xpcom/io/nsAnonymousTemporaryFile.cpp | 36 +++++--- xpcom/io/nsAppFileLocationProvider.cpp | 19 +++-- xpcom/io/nsBinaryStream.cpp | 104 +++++++++++++++--------- xpcom/io/nsDirectoryService.cpp | 24 ++++-- xpcom/io/nsIOUtil.cpp | 8 +- xpcom/io/nsInputStreamTee.cpp | 16 ++-- xpcom/io/nsLocalFileCommon.cpp | 6 +- xpcom/io/nsLocalFileUnix.cpp | 93 ++++++++++++++------- xpcom/io/nsLocalFileWin.cpp | 72 ++++++++++------ xpcom/io/nsMultiplexInputStream.cpp | 58 ++++++++----- xpcom/io/nsPipe3.cpp | 3 +- xpcom/io/nsStorageStream.cpp | 31 +++---- xpcom/io/nsStringStream.cpp | 19 +++-- xpcom/reflect/xptcall/src/xptcall.cpp | 6 +- xpcom/threads/LazyIdleThread.cpp | 42 ++++++---- xpcom/threads/nsEnvironment.cpp | 12 ++- xpcom/threads/nsMemoryPressure.cpp | 1 - xpcom/threads/nsProcessCommon.cpp | 9 +- xpcom/threads/nsThread.cpp | 48 ++++++----- xpcom/threads/nsThreadManager.cpp | 15 ++-- xpcom/threads/nsThreadPool.cpp | 9 +- xpcom/threads/nsTimerImpl.cpp | 19 +++-- 56 files changed, 777 insertions(+), 440 deletions(-) diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 4079ca38ca56..a88436d36e83 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1221,12 +1221,14 @@ public: // want scripts which poll the filesystem looking for gc/cc dumps to // grab a file before we're finished writing to it.) nsCOMPtr gcLogFile = CreateTempFile("incomplete-gc-edges"); - NS_ENSURE_STATE(gcLogFile); + if (NS_WARN_IF(!gcLogFile)) + return NS_ERROR_UNEXPECTED; // Dump the JS heap. FILE* gcLogANSIFile = nullptr; gcLogFile->OpenANSIFileDesc("w", &gcLogANSIFile); - NS_ENSURE_STATE(gcLogANSIFile); + if (NS_WARN_IF(!gcLogANSIFile)) + return NS_ERROR_UNEXPECTED; MozillaRegisterDebugFILE(gcLogANSIFile); CollectorData *data = sCollectorData.get(); if (data && data->mRuntime) @@ -1237,11 +1239,13 @@ public: // Strip off "incomplete-". nsCOMPtr gcLogFileFinalDestination = CreateTempFile("gc-edges"); - NS_ENSURE_STATE(gcLogFileFinalDestination); + if (NS_WARN_IF(!gcLogFileFinalDestination)) + return NS_ERROR_UNEXPECTED; nsAutoString gcLogFileFinalDestinationName; gcLogFileFinalDestination->GetLeafName(gcLogFileFinalDestinationName); - NS_ENSURE_STATE(!gcLogFileFinalDestinationName.IsEmpty()); + if (NS_WARN_IF(gcLogFileFinalDestinationName.IsEmpty())) + return NS_ERROR_UNEXPECTED; gcLogFile->MoveTo(/* directory */ nullptr, gcLogFileFinalDestinationName); @@ -1260,10 +1264,12 @@ public: // Open a file for dumping the CC graph. We again prefix with // "incomplete-". mOutFile = CreateTempFile("incomplete-cc-edges"); - NS_ENSURE_STATE(mOutFile); + if (NS_WARN_IF(!mOutFile)) + return NS_ERROR_UNEXPECTED; MOZ_ASSERT(!mStream); mOutFile->OpenANSIFileDesc("w", &mStream); - NS_ENSURE_STATE(mStream); + if (NS_WARN_IF(!mStream)) + return NS_ERROR_UNEXPECTED; MozillaRegisterDebugFILE(mStream); fprintf(mStream, "# WantAllTraces=%s\n", mWantAllTraces ? "true" : "false"); @@ -1388,11 +1394,13 @@ public: // Strip off "incomplete-" from the log file's name. nsCOMPtr logFileFinalDestination = CreateTempFile("cc-edges"); - NS_ENSURE_STATE(logFileFinalDestination); + if (NS_WARN_IF(!logFileFinalDestination)) + return NS_ERROR_UNEXPECTED; nsAutoString logFileFinalDestinationName; logFileFinalDestination->GetLeafName(logFileFinalDestinationName); - NS_ENSURE_STATE(!logFileFinalDestinationName.IsEmpty()); + if (NS_WARN_IF(logFileFinalDestinationName.IsEmpty())) + return NS_ERROR_UNEXPECTED; mOutFile->MoveTo(/* directory = */ nullptr, logFileFinalDestinationName); @@ -1415,7 +1423,8 @@ public: NS_IMETHOD ProcessNext(nsICycleCollectorHandler* aHandler, bool* aCanContinue) { - NS_ENSURE_STATE(aHandler && mWantAfterProcessing); + if (NS_WARN_IF(!aHandler) || NS_WARN_IF(!mWantAfterProcessing)) + return NS_ERROR_UNEXPECTED; CCGraphDescriber* d = mDescribers.popFirst(); if (d) { switch (d->mType) { @@ -1515,7 +1524,8 @@ nsCycleCollectorLoggerConstructor(nsISupports* aOuter, const nsIID& aIID, void* *aInstancePtr) { - NS_ENSURE_TRUE(!aOuter, NS_ERROR_NO_AGGREGATION); + if (NS_WARN_IF(aOuter)) + return NS_ERROR_NO_AGGREGATION; nsISupports *logger = new nsCycleCollectorLogger(); @@ -2438,7 +2448,8 @@ class CycleCollectorReporter MOZ_FINAL : public MemoryMultiReporter nsIMemoryReporter::KIND_HEAP, \ nsIMemoryReporter::UNITS_BYTES, _amount, \ NS_LITERAL_CSTRING(_desc), aClosure); \ - NS_ENSURE_SUCCESS(rv, rv); \ + if (NS_WARN_IF(NS_FAILED(rv))) \ + return rv; \ } \ } while (0) diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index cd9e12a1d0ca..3cb01f4432a2 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -565,7 +565,8 @@ static const nsDebugImpl kImpl; nsresult nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { - NS_ENSURE_NO_AGGREGATION(outer); + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; return const_cast(&kImpl)-> QueryInterface(aIID, aInstancePtr); diff --git a/xpcom/base/nsErrorService.cpp b/xpcom/base/nsErrorService.cpp index dd5464d7e5c7..58ef07b817fc 100644 --- a/xpcom/base/nsErrorService.cpp +++ b/xpcom/base/nsErrorService.cpp @@ -65,7 +65,8 @@ NS_IMPL_ISUPPORTS1(nsErrorService, nsIErrorService) nsresult nsErrorService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { - NS_ENSURE_NO_AGGREGATION(outer); + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; nsRefPtr serv = new nsErrorService(); return serv->QueryInterface(aIID, aInstancePtr); } diff --git a/xpcom/base/nsGZFileWriter.cpp b/xpcom/base/nsGZFileWriter.cpp index c1e96cacf476..166e199d54cf 100644 --- a/xpcom/base/nsGZFileWriter.cpp +++ b/xpcom/base/nsGZFileWriter.cpp @@ -33,21 +33,25 @@ nsGZFileWriter::~nsGZFileWriter() NS_IMETHODIMP nsGZFileWriter::Init(nsIFile* aFile) { - NS_ENSURE_FALSE(mInitialized, NS_ERROR_FAILURE); - NS_ENSURE_FALSE(mFinished, NS_ERROR_FAILURE); + if (NS_WARN_IF(mInitialized) || + NS_WARN_IF(mFinished)) + return NS_ERROR_FAILURE; // Get a FILE out of our nsIFile. Convert that into a file descriptor which // gzip can own. Then close our FILE, leaving only gzip's fd open. FILE* file; nsresult rv = aFile->OpenANSIFileDesc("wb", &file); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mGZFile = gzdopen(dup(fileno(file)), "wb"); fclose(file); // gzdopen returns nullptr on error. - NS_ENSURE_TRUE(mGZFile, NS_ERROR_FAILURE); + if (NS_WARN_IF(!mGZFile)) + return NS_ERROR_FAILURE; + mInitialized = true; return NS_OK; @@ -56,8 +60,9 @@ nsGZFileWriter::Init(nsIFile* aFile) NS_IMETHODIMP nsGZFileWriter::Write(const nsACString& aStr) { - NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_FALSE(mFinished, NS_ERROR_FAILURE); + if (NS_WARN_IF(!mInitialized) || + NS_WARN_IF(mFinished)) + return NS_ERROR_FAILURE; // gzwrite uses a return value of 0 to indicate failure. Otherwise, it // returns the number of uncompressed bytes written. To ensure we can @@ -71,7 +76,8 @@ nsGZFileWriter::Write(const nsACString& aStr) // always be either 0 or aStr.Length(), and we shouldn't have to call it // multiple times in order to get it to read the whole buffer. int rv = gzwrite(mGZFile, aStr.BeginReading(), aStr.Length()); - NS_ENSURE_TRUE(rv == static_cast(aStr.Length()), NS_ERROR_FAILURE); + if (NS_WARN_IF(rv != static_cast(aStr.Length()))) + return NS_ERROR_FAILURE; return NS_OK; } @@ -79,8 +85,9 @@ nsGZFileWriter::Write(const nsACString& aStr) NS_IMETHODIMP nsGZFileWriter::Finish() { - NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_FALSE(mFinished, NS_ERROR_FAILURE); + if (NS_WARN_IF(!mInitialized) || + NS_WARN_IF(mFinished)) + return NS_ERROR_FAILURE; mFinished = true; gzclose(mGZFile); diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 66e7ade7ac8f..4b9d0a8c0d68 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -537,7 +537,8 @@ public: { int64_t amount; nsresult rv = GetAmount(&amount); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return aCallback->Callback(EmptyCString(), mNameAndPath, mKind, mUnits, amount, mDescription, aData); diff --git a/xpcom/base/nsMacUtilsImpl.cpp b/xpcom/base/nsMacUtilsImpl.cpp index 84a030051dc9..bf9828ad8499 100644 --- a/xpcom/base/nsMacUtilsImpl.cpp +++ b/xpcom/base/nsMacUtilsImpl.cpp @@ -89,7 +89,8 @@ nsresult nsMacUtilsImpl::GetArchString(nsAString& archString) NS_IMETHODIMP nsMacUtilsImpl::GetIsUniversalBinary(bool *aIsUniversalBinary) { - NS_ENSURE_ARG_POINTER(aIsUniversalBinary); + if (NS_WARN_IF(!aIsUniversalBinary)) + return NS_ERROR_INVALID_ARG; *aIsUniversalBinary = false; nsAutoString archString; diff --git a/xpcom/base/nsMemoryImpl.cpp b/xpcom/base/nsMemoryImpl.cpp index f8b9bfc5a236..2b25086e13f4 100644 --- a/xpcom/base/nsMemoryImpl.cpp +++ b/xpcom/base/nsMemoryImpl.cpp @@ -93,7 +93,8 @@ nsMemoryImpl::IsLowMemoryPlatform(bool *result) /*static*/ nsresult nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void **aResult) { - NS_ENSURE_NO_AGGREGATION(outer); + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; return sGlobalMemory.QueryInterface(aIID, aResult); } diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp index c5ae19f08404..23a4d5fcc5e0 100644 --- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -416,15 +416,18 @@ public: } } else { rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file)); - NS_ENSURE_SUCCESS(rv, -1); + if (NS_WARN_IF(NS_FAILED(rv))) + return -1; } rv = file->AppendNative(NS_LITERAL_CSTRING("debug_info_trigger")); - NS_ENSURE_SUCCESS(rv, -1); + if (NS_WARN_IF(NS_FAILED(rv))) + return -1; nsAutoCString path; rv = file->GetNativePath(path); - NS_ENSURE_SUCCESS(rv, -1); + if (NS_WARN_IF(NS_FAILED(rv))) + return -1; // unlink might fail because the file doesn't exist, or for other reasons. // But we don't care it fails; any problems will be detected later, when we @@ -606,7 +609,8 @@ namespace mozilla { #define DUMP(o, s) \ do { \ nsresult rv = (o)->Write(s); \ - NS_ENSURE_SUCCESS(rv, rv); \ + if (NS_WARN_IF(NS_FAILED(rv))) \ + return rv; \ } while (0) static nsresult @@ -680,7 +684,8 @@ public: nsISupports *aData) { nsCOMPtr writer = do_QueryInterface(aData); - NS_ENSURE_TRUE(writer, NS_ERROR_FAILURE); + if (NS_WARN_IF(!writer)) + return NS_ERROR_FAILURE; nsresult rv = DumpReport(writer, mIsFirst, aProcess, aPath, aKind, aUnits, aAmount, aDescription); @@ -722,7 +727,8 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) nsresult rv; if (!*aFile) { rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, aFile); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } #ifdef ANDROID @@ -731,7 +737,8 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) // users to be able to remove these files, so we write them into a // subdirectory of the temp directory and chmod 777 that directory. rv = (*aFile)->AppendNative(NS_LITERAL_CSTRING("memory-reports")); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // It's OK if this fails; that probably just means that the directory already // exists. @@ -739,7 +746,8 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) nsAutoCString dirPath; rv = (*aFile)->GetNativePath(dirPath); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; while (chmod(dirPath.get(), 0777) == -1 && errno == EINTR) {} #endif @@ -747,10 +755,12 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) nsCOMPtr file(*aFile); rv = file->AppendNative(aFilename); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; #ifdef ANDROID // Make this file world-read/writable; the permissions passed to the @@ -758,7 +768,8 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) // umask. nsAutoCString path; rv = file->GetNativePath(path); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; while (chmod(path.get(), 0666) == -1 && errno == EINTR) {} #endif @@ -801,7 +812,8 @@ DumpHeader(nsIGZFileWriter* aWriter) nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); - NS_ENSURE_STATE(mgr); + if (NS_WARN_IF(!mgr)) + return NS_ERROR_UNEXPECTED; DUMP(aWriter, mgr->GetHasMozMallocUsableSize() ? "true" : "false"); DUMP(aWriter, ",\n"); @@ -872,11 +884,12 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) rv = nsMemoryInfoDumper::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") + mrFilename, getter_AddRefs(mrTmpFile)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) return rv; nsRefPtr mrWriter = new nsGZFileWriter(); rv = mrWriter->Init(mrTmpFile); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Dump the memory reports to the file. DumpProcessMemoryReportsToGZFileWriter(mrWriter); @@ -894,11 +907,13 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) nsCOMPtr dmdFile; rv = nsMemoryInfoDumper::OpenTempFile(dmdFilename, getter_AddRefs(dmdFile)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; nsRefPtr dmdWriter = new nsGZFileWriter(); rv = dmdWriter->Init(dmdFile); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Dump DMD output to the file. @@ -907,7 +922,8 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) dmd::Dump(w); rv = dmdWriter->Finish(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; #endif // MOZ_DMD // The call to Finish() deallocates the memory allocated by mrWriter's first @@ -916,42 +932,51 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) // them -- by "heap-allocated" if nothing else -- we want DMD to see it as // well. So we deliberately don't call Finish() until after DMD finishes. rv = mrWriter->Finish(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Rename the memory reports file, now that we're done writing all the files. // Its final name is "memory-report<-identifier>-.json.gz". nsCOMPtr mrFinalFile; rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mrFinalFile)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; #ifdef ANDROID rv = mrFinalFile->AppendNative(NS_LITERAL_CSTRING("memory-reports")); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; #endif rv = mrFinalFile->AppendNative(mrFilename); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = mrFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; nsAutoString mrActualFinalFilename; rv = mrFinalFile->GetLeafName(mrActualFinalFilename); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = mrTmpFile->MoveTo(/* directory */ nullptr, mrActualFinalFilename); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Write a message to the console. nsCOMPtr cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; nsString path; mrTmpFile->GetPath(path); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; nsString msg = NS_LITERAL_STRING( "nsIMemoryInfoDumper dumped reports to "); @@ -988,7 +1013,8 @@ nsMemoryInfoDumper::DumpMemoryInfoToTempDir(const nsAString& aIdentifier, /* dumpChildProcesses = */ false); nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); - NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE); + if (NS_WARN_IF(!mgr)) + return NS_ERROR_FAILURE; nsCOMPtr runnable; mgr->MinimizeMemoryUsage(callback, getter_AddRefs(runnable)); return NS_OK; @@ -1043,28 +1069,34 @@ nsMemoryInfoDumper::DumpMemoryReportsToNamedFile( nsCOMPtr mrFile; nsresult rv = NS_NewLocalFile(aFilename, false, getter_AddRefs(mrFile)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mrFile->InitWithPath(aFilename); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; bool exists; rv = mrFile->Exists(&exists); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; if (!exists) { rv = mrFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } // Write the memory reports to the file. nsRefPtr mrWriter = new nsGZFileWriter(); rv = mrWriter->Init(mrFile); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = DumpHeader(mrWriter); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Process reports and finish up. nsRefPtr dumpReport = new DumpReportCallback(); diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index dfa41367055c..45dd68558859 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -99,7 +99,8 @@ private: *aAmount = 0; FILE *f = fopen("/proc/self/smaps", "r"); - NS_ENSURE_STATE(f); + if (NS_WARN_IF(!f)) + return NS_ERROR_UNEXPECTED; int64_t total = 0; char line[256]; @@ -716,7 +717,8 @@ public: nsIMemoryReporter::KIND_HEAP, \ nsIMemoryReporter::UNITS_BYTES, _amount, \ NS_LITERAL_CSTRING(_desc), aData); \ - NS_ENSURE_SUCCESS(rv, rv); \ + if (NS_WARN_IF(NS_FAILED(rv))) \ + return rv; \ } while (0) REPORT("explicit/dmd/stack-traces/used", @@ -1244,7 +1246,8 @@ NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIHandleReportCallback) NS_IMETHODIMP nsMemoryReporterManager::GetExplicit(int64_t* aAmount) { - NS_ENSURE_ARG_POINTER(aAmount); + if (NS_WARN_IF(!aAmount)) + return NS_ERROR_INVALID_ARG; *aAmount = 0; #ifndef HAVE_JEMALLOC_STATS return NS_ERROR_NOT_AVAILABLE; @@ -1510,7 +1513,8 @@ NS_IMETHODIMP nsMemoryReporterManager::MinimizeMemoryUsage(nsIRunnable* aCallback, nsICancelableRunnable** aResult) { - NS_ENSURE_ARG_POINTER(aResult); + if (NS_WARN_IF(!aResult)) + return NS_ERROR_INVALID_ARG; nsRefPtr runnable = new MinimizeMemoryUsageRunnable(aCallback); @@ -1533,7 +1537,8 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, { nsCOMPtr global = do_QueryInterface(aTopWindow); nsCOMPtr piWindow = do_QueryInterface(aTopWindow); - NS_ENSURE_TRUE(!!global && !!piWindow, NS_ERROR_FAILURE); + if (NS_WARN_IF(!global) || NS_WARN_IF(!piWindow)) + return NS_ERROR_FAILURE; TimeStamp t1 = TimeStamp::Now(); @@ -1543,7 +1548,8 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, nsresult rv = mSizeOfTabFns.mJS(global->GetGlobalJSObject(), &jsObjectsSize, &jsStringsSize, &jsPrivateSize, &jsOtherSize); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; TimeStamp t2 = TimeStamp::Now(); diff --git a/xpcom/base/nsMessageLoop.cpp b/xpcom/base/nsMessageLoop.cpp index 0f1bd536e4e2..8ef4c17a39a2 100644 --- a/xpcom/base/nsMessageLoop.cpp +++ b/xpcom/base/nsMessageLoop.cpp @@ -87,7 +87,8 @@ nsresult MessageLoopIdleTask::Init(uint32_t aEnsureRunsAfterMS) { mTimer = do_CreateInstance("@mozilla.org/timer;1"); - NS_ENSURE_STATE(mTimer); + if (NS_WARN_IF(!mTimer)) + return NS_ERROR_UNEXPECTED; nsRefPtr callback = new MessageLoopTimerCallback(this); @@ -153,7 +154,8 @@ nsMessageLoopConstructor(nsISupports* aOuter, const nsIID& aIID, void** aInstancePtr) { - NS_ENSURE_FALSE(aOuter, NS_ERROR_NO_AGGREGATION); + if (NS_WARN_IF(aOuter)) + return NS_ERROR_NO_AGGREGATION; nsISupports* messageLoop = new nsMessageLoop(); return messageLoop->QueryInterface(aIID, aInstancePtr); } diff --git a/xpcom/base/nsSystemInfo.cpp b/xpcom/base/nsSystemInfo.cpp index 9439092ee94f..0c32ac7901a5 100644 --- a/xpcom/base/nsSystemInfo.cpp +++ b/xpcom/base/nsSystemInfo.cpp @@ -165,7 +165,8 @@ nsSystemInfo::Init() if (PR_GetSystemInfo(items[i].cmd, buf, sizeof(buf)) == PR_SUCCESS) { rv = SetPropertyAsACString(NS_ConvertASCIItoUTF16(items[i].name), nsDependentCString(buf)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } else { NS_WARNING("PR_GetSystemInfo failed"); @@ -182,7 +183,8 @@ nsSystemInfo::Init() for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) { rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name), cpuPropItems[i].propfun()); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } #ifdef XP_WIN @@ -191,7 +193,8 @@ nsSystemInfo::Init() NS_WARN_IF_FALSE(gotWow64Value, "IsWow64Process failed"); if (gotWow64Value) { rv = SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } nsAutoCString hddModel, hddRevision; if (NS_SUCCEEDED(GetProfileHDDInfo(hddModel, hddRevision))) { @@ -210,7 +213,8 @@ nsSystemInfo::Init() rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), nsDependentCString(gtkver)); PR_smprintf_free(gtkver); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } #endif diff --git a/xpcom/build/Omnijar.cpp b/xpcom/build/Omnijar.cpp index 4d75c7ef7b55..3bc74178821a 100644 --- a/xpcom/build/Omnijar.cpp +++ b/xpcom/build/Omnijar.cpp @@ -145,7 +145,8 @@ Omnijar::GetURIString(Type aType, nsACString &result) nsAutoCString omniJarSpec; if (sPath[aType]) { nsresult rv = NS_GetURLSpecFromActualFile(sPath[aType], omniJarSpec); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; result = "jar:"; if (sIsNested[aType]) @@ -158,7 +159,8 @@ Omnijar::GetURIString(Type aType, nsACString &result) nsCOMPtr dir; nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile), getter_AddRefs(dir)); nsresult rv = NS_GetURLSpecFromActualFile(dir, result); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } result += "/"; return NS_OK; diff --git a/xpcom/build/nsXPCOMStrings.cpp b/xpcom/build/nsXPCOMStrings.cpp index d5df93ac3215..02796a835b1e 100644 --- a/xpcom/build/nsXPCOMStrings.cpp +++ b/xpcom/build/nsXPCOMStrings.cpp @@ -40,7 +40,8 @@ NS_StringContainerInit2(nsStringContainer &aContainer, { if (aDataLength == UINT32_MAX) { - NS_ENSURE_ARG(!(aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING)); + if (NS_WARN_IF(aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING)) + return NS_ERROR_INVALID_ARG; aDataLength = nsCharTraits::length(aData); } @@ -200,7 +201,8 @@ NS_CStringContainerInit2(nsCStringContainer &aContainer, { if (aDataLength == UINT32_MAX) { - NS_ENSURE_ARG(!(aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING)); + if (NS_WARN_IF(aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING)) + return NS_ERROR_INVALID_ARG; aDataLength = nsCharTraits::length(aData); } diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index de58a8acd9e7..c3784f3f9724 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -219,7 +219,8 @@ nsThreadManagerGetSingleton(nsISupports* outer, void* *aInstancePtr) { NS_ASSERTION(aInstancePtr, "null outptr"); - NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; return nsThreadManager::get()->QueryInterface(aIID, aInstancePtr); } @@ -232,7 +233,8 @@ nsXPTIInterfaceInfoManagerGetSingleton(nsISupports* outer, void* *aInstancePtr) { NS_ASSERTION(aInstancePtr, "null outptr"); - NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; nsCOMPtr iim (XPTInterfaceInfoManager::GetSingleton()); @@ -313,16 +315,16 @@ static nsIDebug* gDebug = nullptr; EXPORT_XPCOM_API(nsresult) NS_GetDebug(nsIDebug** result) { - return nsDebugImpl::Create(nullptr, - NS_GET_IID(nsIDebug), + return nsDebugImpl::Create(nullptr, + NS_GET_IID(nsIDebug), (void**) result); } EXPORT_XPCOM_API(nsresult) NS_GetTraceRefcnt(nsITraceRefcnt** result) { - return nsTraceRefcntImpl::Create(nullptr, - NS_GET_IID(nsITraceRefcnt), + return nsTraceRefcntImpl::Create(nullptr, + NS_GET_IID(nsITraceRefcnt), (void**) result); } @@ -411,38 +413,38 @@ NS_InitXPCOM2(nsIServiceManager* *result, if (!AtExitManager::AlreadyRegistered()) { sExitManager = new AtExitManager(); - NS_ENSURE_STATE(sExitManager); } if (!MessageLoop::current()) { sMessageLoop = new MessageLoopForUI(MessageLoop::TYPE_MOZILLA_UI); - NS_ENSURE_STATE(sMessageLoop); } if (XRE_GetProcessType() == GeckoProcessType_Default && !BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO)) { scoped_ptr ioThread( new BrowserProcessSubThread(BrowserProcessSubThread::IO)); - NS_ENSURE_TRUE(ioThread.get(), NS_ERROR_OUT_OF_MEMORY); base::Thread::Options options; options.message_loop_type = MessageLoop::TYPE_IO; - NS_ENSURE_TRUE(ioThread->StartWithOptions(options), NS_ERROR_FAILURE); + if (NS_WARN_IF(!ioThread->StartWithOptions(options))) + return NS_ERROR_FAILURE; sIOThread = ioThread.release(); } // Establish the main thread here. rv = nsThreadManager::get()->Init(); - if (NS_FAILED(rv)) return rv; + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Set up the timer globals/timer thread rv = nsTimerImpl::Startup(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; #ifndef ANDROID // If the locale hasn't already been setup by our embedder, - // get us out of the "C" locale and into the system + // get us out of the "C" locale and into the system if (strcmp(setlocale(LC_ALL, nullptr), "C") == 0) setlocale(LC_ALL, ""); #endif @@ -493,18 +495,21 @@ NS_InitXPCOM2(nsIServiceManager* *result, CommandLine::Init(0, nullptr); #else nsCOMPtr binaryFile; - nsDirectoryService::gService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, - NS_GET_IID(nsIFile), + nsDirectoryService::gService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), getter_AddRefs(binaryFile)); - NS_ENSURE_STATE(binaryFile); - + if (NS_WARN_IF(!binaryFile)) + return NS_ERROR_FAILURE; + rv = binaryFile->AppendNative(NS_LITERAL_CSTRING("nonexistent-executable")); - NS_ENSURE_SUCCESS(rv, rv); - + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + nsCString binaryPath; rv = binaryFile->GetNativePath(binaryPath); - NS_ENSURE_SUCCESS(rv, rv); - + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + static char const *const argv = { strdup(binaryPath.get()) }; CommandLine::Init(1, &argv); #endif @@ -568,7 +573,7 @@ NS_InitXPCOM2(nsIServiceManager* *result, mozilla::AvailableMemoryTracker::Activate(); // Notify observers of xpcom autoregistration start - NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_CATEGORY, + NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_CATEGORY, nullptr, NS_XPCOM_STARTUP_OBSERVER_ID); #ifdef XP_WIN @@ -626,7 +631,9 @@ ShutdownXPCOM(nsIServiceManager* servMgr) // Make sure the hang monitor is enabled for shutdown. HangMonitor::NotifyActivity(); - NS_ENSURE_STATE(NS_IsMainThread()); + if (!NS_IsMainThread()) { + NS_RUNTIMEABORT("Shutdown on wrong thread"); + } nsresult rv; nsCOMPtr moduleLoaders; @@ -637,7 +644,8 @@ ShutdownXPCOM(nsIServiceManager* servMgr) // servicemanager shutdown nsCOMPtr thread = do_GetCurrentThread(); - NS_ENSURE_STATE(thread); + if (NS_WARN_IF(!thread)) + return NS_ERROR_UNEXPECTED; nsRefPtr observerService; CallGetService("@mozilla.org/observer-service;1", diff --git a/xpcom/build/perfprobe.cpp b/xpcom/build/perfprobe.cpp index f74eb978e829..6c584b50c5a0 100644 --- a/xpcom/build/perfprobe.cpp +++ b/xpcom/build/perfprobe.cpp @@ -213,7 +213,8 @@ nsresult ProbeManager::StartSession(nsTArray> &aProbes) used only for unregistration*/ ); delete[] probes; - NS_ENSURE_TRUE(result == ERROR_SUCCESS, NS_ERROR_UNEXPECTED); + if (NS_WARN_IF(result != ERROR_SUCCESS)) + return NS_ERROR_UNEXPECTED; return NS_OK; } diff --git a/xpcom/components/nsCategoryManager.cpp b/xpcom/components/nsCategoryManager.cpp index b35dc180665a..6e2b43a635a7 100644 --- a/xpcom/components/nsCategoryManager.cpp +++ b/xpcom/components/nsCategoryManager.cpp @@ -299,7 +299,8 @@ CategoryNode::DeleteLeaf(const char* aEntryName) NS_METHOD CategoryNode::Enumerate(nsISimpleEnumerator **_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; MutexAutoLock lock(mLock); EntryEnumerator* enumObj = EntryEnumerator::Create(mTable); @@ -593,9 +594,10 @@ nsCategoryManager::GetCategoryEntry( const char *aCategoryName, const char *aEntryName, char **_retval ) { - NS_ENSURE_ARG_POINTER(aCategoryName); - NS_ENSURE_ARG_POINTER(aEntryName); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!aCategoryName) || + NS_WARN_IF(!aEntryName) || + NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG;; nsresult status = NS_ERROR_NOT_AVAILABLE; @@ -687,8 +689,9 @@ nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName, const char *aEntryName, bool aDontPersist) { - NS_ENSURE_ARG_POINTER(aCategoryName); - NS_ENSURE_ARG_POINTER(aEntryName); + if (NS_WARN_IF(!aCategoryName) || + NS_WARN_IF(!aEntryName)) + return NS_ERROR_INVALID_ARG; /* Note: no errors are reported since failure to delete @@ -715,7 +718,8 @@ nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName, NS_IMETHODIMP nsCategoryManager::DeleteCategory( const char *aCategoryName ) { - NS_ENSURE_ARG_POINTER(aCategoryName); + if (NS_WARN_IF(!aCategoryName)) + return NS_ERROR_INVALID_ARG; // the categories are arena-allocated, so we don't // actually delete them. We just remove all of the @@ -740,8 +744,9 @@ NS_IMETHODIMP nsCategoryManager::EnumerateCategory( const char *aCategoryName, nsISimpleEnumerator **_retval ) { - NS_ENSURE_ARG_POINTER(aCategoryName); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!aCategoryName) || + NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; CategoryNode* category; { @@ -759,7 +764,8 @@ nsCategoryManager::EnumerateCategory( const char *aCategoryName, NS_IMETHODIMP nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; MutexAutoLock lock(mLock); CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable); diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index 0d27e9f17f82..af51024ac798 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -932,8 +932,9 @@ nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID, const nsIID &aIID, void **aResult) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_ARG_POINTER(contractID); + if (NS_WARN_IF(!aResult) || + NS_WARN_IF(!contractID)) + return NS_ERROR_INVALID_ARG; nsresult rv; @@ -1052,7 +1053,8 @@ nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID, const nsIID &aIID, void **aResult) { - NS_ENSURE_ARG_POINTER(aContractID); + if (NS_WARN_IF(!aContractID)) + return NS_ERROR_INVALID_ARG; // test this first, since there's no point in creating a component during // shutdown -- whether it's available or not would depend on the order it @@ -1607,7 +1609,9 @@ NS_IMETHODIMP nsComponentManagerImpl::IsContractIDRegistered(const char *aClass, bool *_retval) { - NS_ENSURE_ARG_POINTER(aClass); + if (NS_WARN_IF(!aClass)) + return NS_ERROR_INVALID_ARG; + nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass)); if (entry) diff --git a/xpcom/ds/nsHashPropertyBag.cpp b/xpcom/ds/nsHashPropertyBag.cpp index 29ea0c8c3eb1..9f60de99aedc 100644 --- a/xpcom/ds/nsHashPropertyBag.cpp +++ b/xpcom/ds/nsHashPropertyBag.cpp @@ -64,7 +64,8 @@ nsHashPropertyBag::GetProperty(const nsAString& name, nsIVariant* *_retval) NS_IMETHODIMP nsHashPropertyBag::SetProperty(const nsAString& name, nsIVariant *value) { - NS_ENSURE_ARG_POINTER(value); + if (NS_WARN_IF(!value)) + return NS_ERROR_INVALID_ARG; mPropertyHash.Put(name, value); diff --git a/xpcom/ds/nsINIParserImpl.cpp b/xpcom/ds/nsINIParserImpl.cpp index 1e4421436378..86d6241356c1 100644 --- a/xpcom/ds/nsINIParserImpl.cpp +++ b/xpcom/ds/nsINIParserImpl.cpp @@ -51,7 +51,8 @@ nsINIParserFactory::CreateInstance(nsISupports* aOuter, REFNSIID aIID, void **aResult) { - NS_ENSURE_NO_AGGREGATION(aOuter); + if (NS_WARN_IF(aOuter)) + return NS_ERROR_NO_AGGREGATION; // We are our own singleton. return QueryInterface(aIID, aResult); diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index b62b5d188531..f79fc75505b9 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -150,7 +150,8 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "respect to the number of windows."), aClosure); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } rv = cb->Callback(/* process */ EmptyCString(), @@ -162,7 +163,8 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "observer service."), aClosure); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = cb->Callback(/* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/alive"), @@ -173,7 +175,8 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "observer service that are still alive."), aClosure); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = cb->Callback(/* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/dead"), @@ -184,7 +187,8 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "observer service that are dead."), aClosure); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return NS_OK; } @@ -266,7 +270,8 @@ nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, (void*) anObserver, aTopic)); NS_ENSURE_VALIDCALL - NS_ENSURE_ARG(anObserver && aTopic); + if (NS_WARN_IF(!anObserver) || NS_WARN_IF(!aTopic)) + return NS_ERROR_INVALID_ARG; if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8)) { return NS_ERROR_NOT_IMPLEMENTED; @@ -285,7 +290,8 @@ nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic) LOG(("nsObserverService::RemoveObserver(%p: %s)", (void*) anObserver, aTopic)); NS_ENSURE_VALIDCALL - NS_ENSURE_ARG(anObserver && aTopic); + if (NS_WARN_IF(!anObserver) || NS_WARN_IF(!aTopic)) + return NS_ERROR_INVALID_ARG; nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); if (!observerList) @@ -302,7 +308,8 @@ nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator) { NS_ENSURE_VALIDCALL - NS_ENSURE_ARG(aTopic && anEnumerator); + if (NS_WARN_IF(!anEnumerator) || NS_WARN_IF(!aTopic)) + return NS_ERROR_INVALID_ARG; nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); if (!observerList) @@ -319,7 +326,8 @@ NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject, LOG(("nsObserverService::NotifyObservers(%s)", aTopic)); NS_ENSURE_VALIDCALL - NS_ENSURE_ARG(aTopic); + if (NS_WARN_IF(!aTopic)) + return NS_ERROR_INVALID_ARG; nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); if (observerList) diff --git a/xpcom/ds/nsProperties.cpp b/xpcom/ds/nsProperties.cpp index 27d1f28779e4..8df2e9445c82 100644 --- a/xpcom/ds/nsProperties.cpp +++ b/xpcom/ds/nsProperties.cpp @@ -15,7 +15,8 @@ NS_INTERFACE_MAP_END NS_IMETHODIMP nsProperties::Get(const char* prop, const nsIID & uuid, void* *result) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; nsCOMPtr value; if (!nsProperties_HashBase::Get(prop, getter_AddRefs(value))) { @@ -27,7 +28,8 @@ nsProperties::Get(const char* prop, const nsIID & uuid, void* *result) NS_IMETHODIMP nsProperties::Set(const char* prop, nsISupports* value) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; Put(prop, value); return NS_OK; } @@ -35,7 +37,8 @@ nsProperties::Set(const char* prop, nsISupports* value) NS_IMETHODIMP nsProperties::Undefine(const char* prop) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; nsCOMPtr value; if (!nsProperties_HashBase::Get(prop, getter_AddRefs(value))) @@ -48,7 +51,8 @@ nsProperties::Undefine(const char* prop) NS_IMETHODIMP nsProperties::Has(const char* prop, bool *result) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; nsCOMPtr value; *result = nsProperties_HashBase::Get(prop, @@ -82,12 +86,11 @@ GetKeysEnumerate(const char *key, nsISupports* data, NS_IMETHODIMP nsProperties::GetKeys(uint32_t *count, char ***keys) { - NS_ENSURE_ARG(count); - NS_ENSURE_ARG(keys); + if (NS_WARN_IF(!count) || NS_WARN_IF(!keys)) + return NS_ERROR_INVALID_ARG; uint32_t n = Count(); char ** k = (char **) nsMemory::Alloc(n * sizeof(char *)); - NS_ENSURE_TRUE(k, NS_ERROR_OUT_OF_MEMORY); GetKeysEnumData gked; gked.keys = k; diff --git a/xpcom/ds/nsStringEnumerator.cpp b/xpcom/ds/nsStringEnumerator.cpp index c71bd5cebbed..8af283354602 100644 --- a/xpcom/ds/nsStringEnumerator.cpp +++ b/xpcom/ds/nsStringEnumerator.cpp @@ -84,7 +84,6 @@ NS_IMPL_ISUPPORTS3(nsStringEnumerator, NS_IMETHODIMP nsStringEnumerator::HasMore(bool* aResult) { - NS_ENSURE_ARG_POINTER(aResult); *aResult = mIndex < Count(); return NS_OK; } @@ -119,7 +118,8 @@ nsStringEnumerator::GetNext(nsISupports** aResult) NS_IMETHODIMP nsStringEnumerator::GetNext(nsAString& aResult) { - NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + if (NS_WARN_IF(mIndex >= Count())) + return NS_ERROR_UNEXPECTED; if (mIsUnicode) aResult = mArray->ElementAt(mIndex++); @@ -132,7 +132,8 @@ nsStringEnumerator::GetNext(nsAString& aResult) NS_IMETHODIMP nsStringEnumerator::GetNext(nsACString& aResult) { - NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); + if (NS_WARN_IF(mIndex >= Count())) + return NS_ERROR_UNEXPECTED; if (mIsUnicode) CopyUTF16toUTF8(mArray->ElementAt(mIndex++), aResult); @@ -160,8 +161,8 @@ nsresult NS_NewStringEnumerator(nsIStringEnumerator** aResult, const nsTArray* aArray, nsISupports* aOwner) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_ARG_POINTER(aArray); + if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) + return NS_ERROR_INVALID_ARG; *aResult = new nsStringEnumerator(aArray, aOwner); return StringEnumeratorTail(aResult); @@ -172,8 +173,8 @@ nsresult NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, const nsTArray* aArray, nsISupports* aOwner) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_ARG_POINTER(aArray); + if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) + return NS_ERROR_INVALID_ARG; *aResult = new nsStringEnumerator(aArray, aOwner); return StringEnumeratorTail(aResult); @@ -183,8 +184,8 @@ nsresult NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, nsTArray* aArray) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_ARG_POINTER(aArray); + if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) + return NS_ERROR_INVALID_ARG; *aResult = new nsStringEnumerator(aArray, true); return StringEnumeratorTail(aResult); @@ -194,8 +195,8 @@ nsresult NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, nsTArray* aArray) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_ARG_POINTER(aArray); + if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) + return NS_ERROR_INVALID_ARG; *aResult = new nsStringEnumerator(aArray, true); return StringEnumeratorTail(aResult); @@ -206,8 +207,8 @@ nsresult NS_NewStringEnumerator(nsIStringEnumerator** aResult, const nsTArray* aArray) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_ARG_POINTER(aArray); + if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) + return NS_ERROR_INVALID_ARG; *aResult = new nsStringEnumerator(aArray, false); return StringEnumeratorTail(aResult); @@ -217,8 +218,8 @@ nsresult NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, const nsTArray* aArray) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_ARG_POINTER(aArray); + if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) + return NS_ERROR_INVALID_ARG; *aResult = new nsStringEnumerator(aArray, false); return StringEnumeratorTail(aResult); diff --git a/xpcom/ds/nsSupportsArray.cpp b/xpcom/ds/nsSupportsArray.cpp index 176c73cf28d5..1c742f0eff6e 100644 --- a/xpcom/ds/nsSupportsArray.cpp +++ b/xpcom/ds/nsSupportsArray.cpp @@ -585,7 +585,8 @@ nsSupportsArray::Clone(nsISupportsArray** aResult) { nsCOMPtr newArray; nsresult rv = NS_NewISupportsArray(getter_AddRefs(newArray)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; uint32_t count = 0; Count(&count); diff --git a/xpcom/ds/nsSupportsPrimitives.cpp b/xpcom/ds/nsSupportsPrimitives.cpp index a5c4f1d6146d..fb6d61427fa8 100644 --- a/xpcom/ds/nsSupportsPrimitives.cpp +++ b/xpcom/ds/nsSupportsPrimitives.cpp @@ -810,7 +810,8 @@ nsSupportsDependentCString::nsSupportsDependentCString(const char* aStr) NS_IMETHODIMP nsSupportsDependentCString::GetType(uint16_t *aType) { - NS_ENSURE_ARG_POINTER(aType); + if (NS_WARN_IF(!aType)) + return NS_ERROR_INVALID_ARG; *aType = TYPE_CSTRING; return NS_OK; @@ -826,7 +827,8 @@ nsSupportsDependentCString::GetData(nsACString& aData) NS_IMETHODIMP nsSupportsDependentCString::ToString(char **_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = ToNewCString(mData); if (!*_retval) diff --git a/xpcom/ds/nsWindowsRegKey.cpp b/xpcom/ds/nsWindowsRegKey.cpp index 524e382061b9..25b51b4e79b9 100644 --- a/xpcom/ds/nsWindowsRegKey.cpp +++ b/xpcom/ds/nsWindowsRegKey.cpp @@ -103,7 +103,8 @@ NS_IMETHODIMP nsWindowsRegKey::OpenChild(const nsAString &path, uint32_t mode, nsIWindowsRegKey **result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; nsCOMPtr child = new nsWindowsRegKey(); @@ -119,7 +120,8 @@ NS_IMETHODIMP nsWindowsRegKey::CreateChild(const nsAString &path, uint32_t mode, nsIWindowsRegKey **result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; nsCOMPtr child = new nsWindowsRegKey(); @@ -134,13 +136,15 @@ nsWindowsRegKey::CreateChild(const nsAString &path, uint32_t mode, NS_IMETHODIMP nsWindowsRegKey::GetChildCount(uint32_t *result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; DWORD numSubKeys; LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, &numSubKeys, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - NS_ENSURE_STATE(rv == ERROR_SUCCESS); + if (rv != ERROR_SUCCESS) + return NS_ERROR_FAILURE; *result = numSubKeys; return NS_OK; @@ -149,7 +153,8 @@ nsWindowsRegKey::GetChildCount(uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::GetChildName(uint32_t index, nsAString &result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; FILETIME lastWritten; @@ -169,7 +174,8 @@ nsWindowsRegKey::GetChildName(uint32_t index, nsAString &result) NS_IMETHODIMP nsWindowsRegKey::HasChild(const nsAString &name, bool *result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; // Check for the existence of a child key by opening the key with minimal // rights. Perhaps there is a more efficient way to do this? @@ -187,13 +193,15 @@ nsWindowsRegKey::HasChild(const nsAString &name, bool *result) NS_IMETHODIMP nsWindowsRegKey::GetValueCount(uint32_t *result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; DWORD numValues; LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &numValues, nullptr, nullptr, nullptr, nullptr); - NS_ENSURE_STATE(rv == ERROR_SUCCESS); + if (rv != ERROR_SUCCESS) + return NS_ERROR_FAILURE; *result = numValues; return NS_OK; @@ -202,7 +210,8 @@ nsWindowsRegKey::GetValueCount(uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::GetValueName(uint32_t index, nsAString &result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; PRUnichar nameBuf[MAX_VALUE_NAME_LEN]; DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]); @@ -220,7 +229,8 @@ nsWindowsRegKey::GetValueName(uint32_t index, nsAString &result) NS_IMETHODIMP nsWindowsRegKey::HasValue(const nsAString &name, bool *result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, nullptr, nullptr); @@ -232,7 +242,8 @@ nsWindowsRegKey::HasValue(const nsAString &name, bool *result) NS_IMETHODIMP nsWindowsRegKey::RemoveChild(const nsAString &name) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; LONG rv = RegDeleteKeyW(mKey, PromiseFlatString(name).get()); @@ -242,7 +253,8 @@ nsWindowsRegKey::RemoveChild(const nsAString &name) NS_IMETHODIMP nsWindowsRegKey::RemoveValue(const nsAString &name) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; LONG rv = RegDeleteValueW(mKey, PromiseFlatString(name).get()); @@ -252,7 +264,8 @@ nsWindowsRegKey::RemoveValue(const nsAString &name) NS_IMETHODIMP nsWindowsRegKey::GetValueType(const nsAString &name, uint32_t *result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, (LPDWORD) result, nullptr, nullptr); @@ -263,7 +276,8 @@ nsWindowsRegKey::GetValueType(const nsAString &name, uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; DWORD type, size; @@ -275,12 +289,12 @@ nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result) // This must be a string type in order to fetch the value as a string. // We're being a bit forgiving here by allowing types other than REG_SZ. - NS_ENSURE_STATE(type == REG_SZ || - type == REG_EXPAND_SZ || - type == REG_MULTI_SZ); + if (type != REG_SZ && type == REG_EXPAND_SZ && type == REG_MULTI_SZ) + return NS_ERROR_FAILURE; // The buffer size must be a multiple of 2. - NS_ENSURE_STATE(size % 2 == 0); + if (size % 2 != 0) + return NS_ERROR_UNEXPECTED; if (size == 0) { result.Truncate(); @@ -337,7 +351,8 @@ nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result) NS_IMETHODIMP nsWindowsRegKey::ReadIntValue(const nsAString &name, uint32_t *result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; DWORD size = sizeof(*result); LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, @@ -349,7 +364,8 @@ nsWindowsRegKey::ReadIntValue(const nsAString &name, uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::ReadInt64Value(const nsAString &name, uint64_t *result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; DWORD size = sizeof(*result); LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, @@ -361,7 +377,8 @@ nsWindowsRegKey::ReadInt64Value(const nsAString &name, uint64_t *result) NS_IMETHODIMP nsWindowsRegKey::ReadBinaryValue(const nsAString &name, nsACString &result) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; DWORD size; LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, @@ -385,7 +402,8 @@ nsWindowsRegKey::ReadBinaryValue(const nsAString &name, nsACString &result) NS_IMETHODIMP nsWindowsRegKey::WriteStringValue(const nsAString &name, const nsAString &value) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; // Need to indicate complete size of buffer including null terminator. const nsString &flatValue = PromiseFlatString(value); @@ -400,7 +418,8 @@ nsWindowsRegKey::WriteStringValue(const nsAString &name, const nsAString &value) NS_IMETHODIMP nsWindowsRegKey::WriteIntValue(const nsAString &name, uint32_t value) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_DWORD, (const BYTE *) &value, sizeof(value)); @@ -411,7 +430,8 @@ nsWindowsRegKey::WriteIntValue(const nsAString &name, uint32_t value) NS_IMETHODIMP nsWindowsRegKey::WriteInt64Value(const nsAString &name, uint64_t value) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_QWORD, (const BYTE *) &value, sizeof(value)); @@ -422,7 +442,8 @@ nsWindowsRegKey::WriteInt64Value(const nsAString &name, uint64_t value) NS_IMETHODIMP nsWindowsRegKey::WriteBinaryValue(const nsAString &name, const nsACString &value) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; const nsCString &flatValue = PromiseFlatCString(value); LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_BINARY, @@ -434,7 +455,8 @@ nsWindowsRegKey::WriteBinaryValue(const nsAString &name, const nsACString &value NS_IMETHODIMP nsWindowsRegKey::StartWatching(bool recurse) { - NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mKey)) + return NS_ERROR_NOT_INITIALIZED; if (mWatchEvent) return NS_OK; diff --git a/xpcom/glue/nsArrayEnumerator.cpp b/xpcom/glue/nsArrayEnumerator.cpp index 572fc665a437..5c2588f59745 100644 --- a/xpcom/glue/nsArrayEnumerator.cpp +++ b/xpcom/glue/nsArrayEnumerator.cpp @@ -180,7 +180,6 @@ nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) // do the actual allocation nsCOMArrayEnumerator * result = static_cast(::operator new(size)); - NS_ENSURE_TRUE(result, nullptr); // now need to copy over the values, and addref each one // now this might seem like a lot of work, but we're actually just diff --git a/xpcom/glue/nsCOMArray.cpp b/xpcom/glue/nsCOMArray.cpp index 99b1b5e481a6..7b227a6c5a3a 100644 --- a/xpcom/glue/nsCOMArray.cpp +++ b/xpcom/glue/nsCOMArray.cpp @@ -57,7 +57,8 @@ int32_t nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { nsCOMPtr supports = do_QueryInterface(aObject); - NS_ENSURE_TRUE(supports, -1); + if (NS_WARN_IF(!supports)) + return -1; uint32_t i, count; int32_t retval = -1; diff --git a/xpcom/glue/nsComponentManagerUtils.cpp b/xpcom/glue/nsComponentManagerUtils.cpp index f20d5e72e3b8..21decc4f4fab 100644 --- a/xpcom/glue/nsComponentManagerUtils.cpp +++ b/xpcom/glue/nsComponentManagerUtils.cpp @@ -46,7 +46,8 @@ nsresult CallGetService(const nsCID &aCID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!compMgr)) + return NS_ERROR_NOT_INITIALIZED; return compMgr->nsComponentManagerImpl::GetService(aCID, aIID, aResult); } @@ -55,7 +56,8 @@ nsresult CallGetService(const char *aContractID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!compMgr)) + return NS_ERROR_NOT_INITIALIZED; return compMgr-> nsComponentManagerImpl::GetServiceByContractID(aContractID, @@ -119,7 +121,8 @@ CallCreateInstance(const nsCID &aCID, nsISupports *aDelegate, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!compMgr)) + return NS_ERROR_NOT_INITIALIZED; return compMgr-> nsComponentManagerImpl::CreateInstance(aCID, aDelegate, aIID, aResult); @@ -130,7 +133,8 @@ CallCreateInstance(const char *aContractID, nsISupports *aDelegate, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!compMgr)) + return NS_ERROR_NOT_INITIALIZED; return compMgr-> nsComponentManagerImpl::CreateInstanceByContractID(aContractID, @@ -142,7 +146,8 @@ nsresult CallGetClassObject(const nsCID &aCID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!compMgr)) + return NS_ERROR_NOT_INITIALIZED; return compMgr-> nsComponentManagerImpl::GetClassObject(aCID, aIID, aResult); @@ -152,7 +157,8 @@ nsresult CallGetClassObject(const char *aContractID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!compMgr)) + return NS_ERROR_NOT_INITIALIZED; return compMgr-> nsComponentManagerImpl::GetClassObjectByContractID(aContractID, aIID, diff --git a/xpcom/glue/nsINIParser.cpp b/xpcom/glue/nsINIParser.cpp index 918c2f2427d8..9ce71aa9b0fd 100644 --- a/xpcom/glue/nsINIParser.cpp +++ b/xpcom/glue/nsINIParser.cpp @@ -65,7 +65,8 @@ nsINIParser::Init(nsIFile* aFile) #ifdef XP_WIN nsAutoString path; nsresult rv = aFile->GetPath(path); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; fd = _wfopen(path.get(), READ_BINARYMODE); #else diff --git a/xpcom/glue/nsMemory.cpp b/xpcom/glue/nsMemory.cpp index 6b63420c9ec6..f77567a3f686 100644 --- a/xpcom/glue/nsMemory.cpp +++ b/xpcom/glue/nsMemory.cpp @@ -19,7 +19,8 @@ nsMemory::HeapMinimize(bool aImmediate) { nsCOMPtr mem; nsresult rv = NS_GetMemoryManager(getter_AddRefs(mem)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return mem->HeapMinimize(aImmediate); } diff --git a/xpcom/glue/nsThreadUtils.cpp b/xpcom/glue/nsThreadUtils.cpp index a99c2dea3ca7..c89faa4e7746 100644 --- a/xpcom/glue/nsThreadUtils.cpp +++ b/xpcom/glue/nsThreadUtils.cpp @@ -70,15 +70,18 @@ NS_NewThread(nsIThread **result, nsIRunnable *event, uint32_t stackSize) nsresult rv; nsCOMPtr mgr = do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = mgr->NewThread(0, stackSize, getter_AddRefs(thread)); #endif - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; if (event) { rv = thread->Dispatch(event, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } *result = nullptr; @@ -95,7 +98,8 @@ NS_GetCurrentThread(nsIThread **result) nsresult rv; nsCOMPtr mgr = do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return mgr->GetCurrentThread(result); #endif } @@ -109,7 +113,8 @@ NS_GetMainThread(nsIThread **result) nsresult rv; nsCOMPtr mgr = do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return mgr->GetMainThread(result); #endif } @@ -161,7 +166,8 @@ NS_DispatchToCurrentThread(nsIRunnable *event) #else nsCOMPtr thread; nsresult rv = NS_GetCurrentThread(getter_AddRefs(thread)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; #endif return thread->Dispatch(event, NS_DISPATCH_NORMAL); } @@ -171,7 +177,8 @@ NS_DispatchToMainThread(nsIRunnable *event, uint32_t dispatchFlags) { nsCOMPtr thread; nsresult rv = NS_GetMainThread(getter_AddRefs(thread)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return thread->Dispatch(event, dispatchFlags); } @@ -184,13 +191,15 @@ NS_ProcessPendingEvents(nsIThread *thread, PRIntervalTime timeout) #ifdef MOZILLA_INTERNAL_API if (!thread) { thread = NS_GetCurrentThread(); - NS_ENSURE_STATE(thread); + if (NS_WARN_IF(!thread)) + return NS_ERROR_UNEXPECTED; } #else nsCOMPtr current; if (!thread) { rv = NS_GetCurrentThread(getter_AddRefs(current)); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; thread = current.get(); } #endif @@ -225,7 +234,8 @@ NS_HasPendingEvents(nsIThread *thread) return hasPendingEvents(current); #else thread = NS_GetCurrentThread(); - NS_ENSURE_TRUE(thread, false); + if (NS_WARN_IF(!thread)) + return false; #endif } return hasPendingEvents(thread); @@ -237,13 +247,15 @@ NS_ProcessNextEvent(nsIThread *thread, bool mayWait) #ifdef MOZILLA_INTERNAL_API if (!thread) { thread = NS_GetCurrentThread(); - NS_ENSURE_TRUE(thread, false); + if (NS_WARN_IF(!thread)) + return false; } #else nsCOMPtr current; if (!thread) { NS_GetCurrentThread(getter_AddRefs(current)); - NS_ENSURE_TRUE(current, false); + if (NS_WARN_IF(!current)) + return false; thread = current.get(); } #endif diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h index e53cc013153c..c567de3a4666 100644 --- a/xpcom/glue/nsThreadUtils.h +++ b/xpcom/glue/nsThreadUtils.h @@ -71,7 +71,8 @@ NS_NewNamedThread(const char (&name)[LEN], uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE) { nsresult rv = NS_NewThread(result, nullptr, stackSize); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; NS_SetThreadName(*result, name); if (initialEvent) { rv = (*result)->Dispatch(initialEvent, NS_DISPATCH_NORMAL); diff --git a/xpcom/io/Base64.cpp b/xpcom/io/Base64.cpp index 94fec02775ae..4a6419eca57d 100644 --- a/xpcom/io/Base64.cpp +++ b/xpcom/io/Base64.cpp @@ -163,7 +163,8 @@ EncodeInputStream(nsIInputStream *aInputStream, if (!aCount) { rv = aInputStream->Available(&count64); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // if count64 is over 4GB, it will be failed at the below condition, // then will return NS_ERROR_OUT_OF_MEMORY aCount = (uint32_t)count64; diff --git a/xpcom/io/CocoaFileUtils.mm b/xpcom/io/CocoaFileUtils.mm index ca4e1b4fc3be..3f6872745536 100644 --- a/xpcom/io/CocoaFileUtils.mm +++ b/xpcom/io/CocoaFileUtils.mm @@ -16,7 +16,8 @@ nsresult RevealFileInFinder(CFURLRef url) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ENSURE_ARG_POINTER(url); + if (NS_WARN_IF(!url)) + return NS_ERROR_INVALID_ARG; NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; BOOL success = [[NSWorkspace sharedWorkspace] selectFile:[(NSURL*)url path] inFileViewerRootedAtPath:@""]; @@ -31,7 +32,8 @@ nsresult OpenURL(CFURLRef url) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ENSURE_ARG_POINTER(url); + if (NS_WARN_IF(!url)) + return NS_ERROR_INVALID_ARG; NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; BOOL success = [[NSWorkspace sharedWorkspace] openURL:(NSURL*)url]; @@ -46,8 +48,8 @@ nsresult GetFileCreatorCode(CFURLRef url, OSType *creatorCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ENSURE_ARG_POINTER(url); - NS_ENSURE_ARG_POINTER(creatorCode); + if (NS_WARN_IF(!url) || NS_WARN_IF(!creatorCode)) + return NS_ERROR_INVALID_ARG; nsAutoreleasePool localPool; @@ -76,7 +78,8 @@ nsresult SetFileCreatorCode(CFURLRef url, OSType creatorCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ENSURE_ARG_POINTER(url); + if (NS_WARN_IF(!url)) + return NS_ERROR_INVALID_ARG; NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:creatorCode] forKey:NSFileHFSCreatorCode]; @@ -91,8 +94,8 @@ nsresult GetFileTypeCode(CFURLRef url, OSType *typeCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ENSURE_ARG_POINTER(url); - NS_ENSURE_ARG_POINTER(typeCode); + if (NS_WARN_IF(!url) || NS_WARN_IF(!typeCode)) + return NS_ERROR_INVALID_ARG; nsAutoreleasePool localPool; @@ -121,7 +124,8 @@ nsresult SetFileTypeCode(CFURLRef url, OSType typeCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ENSURE_ARG_POINTER(url); + if (NS_WARN_IF(!url)) + return NS_ERROR_INVALID_ARG; NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:typeCode] forKey:NSFileHFSTypeCode]; diff --git a/xpcom/io/nsAnonymousTemporaryFile.cpp b/xpcom/io/nsAnonymousTemporaryFile.cpp index aaac18958a22..de0cc43caf23 100644 --- a/xpcom/io/nsAnonymousTemporaryFile.cpp +++ b/xpcom/io/nsAnonymousTemporaryFile.cpp @@ -50,19 +50,23 @@ using namespace mozilla; static nsresult GetTempDir(nsIFile** aTempDir) { - NS_ENSURE_ARG(aTempDir); + if (NS_WARN_IF(!aTempDir)) + return NS_ERROR_INVALID_ARG; nsCOMPtr tmpFile; nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; #ifdef XP_WIN // On windows DELETE_ON_CLOSE is unreliable, so we store temporary files // in a subdir of the temp dir and delete that in an idle service observer // to ensure it's been cleared. rv = tmpFile->AppendNative(nsDependentCString("mozilla-temp-files")); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); - NS_ENSURE_TRUE(rv == NS_ERROR_FILE_ALREADY_EXISTS || NS_SUCCEEDED(rv), rv); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) + return rv; #endif tmpFile.forget(aTempDir); @@ -73,12 +77,14 @@ GetTempDir(nsIFile** aTempDir) nsresult NS_OpenAnonymousTemporaryFile(PRFileDesc** aOutFileDesc) { - NS_ENSURE_ARG(aOutFileDesc); + if (NS_WARN_IF(!aOutFileDesc)) + return NS_ERROR_INVALID_ARG; nsresult rv; nsCOMPtr tmpFile; rv = GetTempDir(getter_AddRefs(tmpFile)); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Give the temp file a name with a random element. CreateUnique will also // append a counter to the name if it encounters a name collision. Adding @@ -90,10 +96,12 @@ NS_OpenAnonymousTemporaryFile(PRFileDesc** aOutFileDesc) name.AppendInt(rand()); rv = tmpFile->AppendNative(name); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0700); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = tmpFile->OpenNSPRFileDesc(PR_RDWR | nsIFile::DELETE_ON_CLOSE, PR_IRWXU, aOutFileDesc); @@ -146,16 +154,19 @@ public: // service is installed when running in xpcshell, and this interferes with // the fake idle service, causing xpcshell-test failures. mTimer = do_CreateInstance(NS_TIMER_CONTRACTID); - NS_ENSURE_TRUE(mTimer != nullptr, NS_ERROR_FAILURE); + if (NS_WARN_IF(!mTimer)) + return NS_ERROR_FAILURE; nsresult rv = mTimer->Init(this, SCHEDULE_TIMEOUT_MS, nsITimer::TYPE_ONE_SHOT); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Register shutdown observer so we can cancel the timer if we shutdown before // the timer runs. nsCOMPtr obsSrv = services::GetObserverService(); - NS_ENSURE_TRUE(obsSrv != nullptr, NS_ERROR_FAILURE); + if (NS_WARN_IF(!obsSrv)) + return NS_ERROR_FAILURE; return obsSrv->AddObserver(this, XPCOM_SHUTDOWN_TOPIC, false); } @@ -211,7 +222,8 @@ public: void RemoveAnonTempFileFiles() { nsCOMPtr tmpDir; nsresult rv = GetTempDir(getter_AddRefs(tmpDir)); - NS_ENSURE_SUCCESS_VOID(rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return; // Remove the directory recursively. tmpDir->Remove(true); diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp index b0243c514e7c..c0f77437c7ac 100644 --- a/xpcom/io/nsAppFileLocationProvider.cpp +++ b/xpcom/io/nsAppFileLocationProvider.cpp @@ -87,10 +87,12 @@ NS_IMPL_ISUPPORTS2(nsAppFileLocationProvider, nsIDirectoryServiceProvider, nsIDi NS_IMETHODIMP nsAppFileLocationProvider::GetFile(const char *prop, bool *persistent, nsIFile **_retval) { + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; + nsCOMPtr localFile; nsresult rv = NS_ERROR_FAILURE; - NS_ENSURE_ARG(prop); *_retval = nullptr; *persistent = true; @@ -250,7 +252,8 @@ nsAppFileLocationProvider::GetFile(const char *prop, bool *persistent, nsIFile * NS_METHOD nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile **aLocalFile) { - NS_ENSURE_ARG_POINTER(aLocalFile); + if (NS_WARN_IF(!aLocalFile)) + return NS_ERROR_INVALID_ARG; nsresult rv; if (!mMozBinDirectory) @@ -291,7 +294,8 @@ NS_METHOD nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile **aLocalFile) //---------------------------------------------------------------------------------------- NS_METHOD nsAppFileLocationProvider::GetProductDirectory(nsIFile **aLocalFile, bool aLocal) { - NS_ENSURE_ARG_POINTER(aLocalFile); + if (NS_WARN_IF(!aLocalFile)) + return NS_ERROR_INVALID_ARG; nsresult rv; bool exists; @@ -352,7 +356,8 @@ NS_METHOD nsAppFileLocationProvider::GetProductDirectory(nsIFile **aLocalFile, b //---------------------------------------------------------------------------------------- NS_METHOD nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsIFile **aLocalFile, bool aLocal) { - NS_ENSURE_ARG_POINTER(aLocalFile); + if (NS_WARN_IF(!aLocalFile)) + return NS_ERROR_INVALID_ARG; nsresult rv; nsCOMPtr localDir; @@ -416,7 +421,8 @@ class nsAppDirectoryEnumerator : public nsISimpleEnumerator NS_IMETHOD GetNext(nsISupports **result) { - NS_ENSURE_ARG_POINTER(result); + if (NS_WARN_IF(!result)) + return NS_ERROR_INVALID_ARG; *result = nullptr; bool hasMore; @@ -511,7 +517,8 @@ class nsPathsDirectoryEnumerator : public nsAppDirectoryEnumerator NS_IMETHODIMP nsAppFileLocationProvider::GetFiles(const char *prop, nsISimpleEnumerator **_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = nullptr; nsresult rv = NS_ERROR_FAILURE; diff --git a/xpcom/io/nsBinaryStream.cpp b/xpcom/io/nsBinaryStream.cpp index e3917845870c..67784f9eea54 100644 --- a/xpcom/io/nsBinaryStream.cpp +++ b/xpcom/io/nsBinaryStream.cpp @@ -34,21 +34,24 @@ NS_IMPL_ISUPPORTS3(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputS NS_IMETHODIMP nsBinaryOutputStream::Flush() { - NS_ENSURE_STATE(mOutputStream); + if (NS_WARN_IF(!mOutputStream)) + return NS_ERROR_UNEXPECTED; return mOutputStream->Flush(); } NS_IMETHODIMP nsBinaryOutputStream::Close() { - NS_ENSURE_STATE(mOutputStream); + if (NS_WARN_IF(!mOutputStream)) + return NS_ERROR_UNEXPECTED; return mOutputStream->Close(); } NS_IMETHODIMP nsBinaryOutputStream::Write(const char *aBuf, uint32_t aCount, uint32_t *aActualBytes) { - NS_ENSURE_STATE(mOutputStream); + if (NS_WARN_IF(!mOutputStream)) + return NS_ERROR_UNEXPECTED; return mOutputStream->Write(aBuf, aCount, aActualBytes); } @@ -69,14 +72,16 @@ nsBinaryOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, uin NS_IMETHODIMP nsBinaryOutputStream::IsNonBlocking(bool *aNonBlocking) { - NS_ENSURE_STATE(mOutputStream); + if (NS_WARN_IF(!mOutputStream)) + return NS_ERROR_UNEXPECTED; return mOutputStream->IsNonBlocking(aNonBlocking); } nsresult nsBinaryOutputStream::WriteFully(const char *aBuf, uint32_t aCount) { - NS_ENSURE_STATE(mOutputStream); + if (NS_WARN_IF(!mOutputStream)) + return NS_ERROR_UNEXPECTED; nsresult rv; uint32_t bytesWritten; @@ -91,7 +96,8 @@ nsBinaryOutputStream::WriteFully(const char *aBuf, uint32_t aCount) NS_IMETHODIMP nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream) { - NS_ENSURE_ARG_POINTER(aOutputStream); + if (NS_WARN_IF(!aOutputStream)) + return NS_ERROR_INVALID_ARG; mOutputStream = aOutputStream; mBufferAccess = do_QueryInterface(aOutputStream); return NS_OK; @@ -245,23 +251,25 @@ nsBinaryOutputStream::WriteCompoundObject(nsISupports* aObject, const nsIID& aIID, bool aIsStrongRef) { - // Can't deal with weak refs - NS_ENSURE_TRUE(aIsStrongRef, NS_ERROR_UNEXPECTED); - nsCOMPtr classInfo = do_QueryInterface(aObject); - NS_ENSURE_TRUE(classInfo, NS_ERROR_NOT_AVAILABLE); - nsCOMPtr serializable = do_QueryInterface(aObject); - NS_ENSURE_TRUE(serializable, NS_ERROR_NOT_AVAILABLE); + + // Can't deal with weak refs + if (NS_WARN_IF(!aIsStrongRef)) + return NS_ERROR_UNEXPECTED; + if (NS_WARN_IF(!classInfo) || NS_WARN_IF(!serializable)) + return NS_ERROR_NOT_AVAILABLE; nsCID cid; classInfo->GetClassIDNoAlloc(&cid); nsresult rv = WriteID(cid); - NS_ENSURE_SUCCESS(rv, rv); - + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; + rv = WriteID(aIID); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return serializable->Write(this); } @@ -270,17 +278,21 @@ NS_IMETHODIMP nsBinaryOutputStream::WriteID(const nsIID& aIID) { nsresult rv = Write32(aIID.m0); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = Write16(aIID.m1); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = Write16(aIID.m2); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; for (int i = 0; i < 8; ++i) { rv = Write8(aIID.m3[i]); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } return NS_OK; @@ -306,14 +318,16 @@ NS_IMPL_ISUPPORTS3(nsBinaryInputStream, nsIObjectInputStream, nsIBinaryInputStre NS_IMETHODIMP nsBinaryInputStream::Available(uint64_t* aResult) { - NS_ENSURE_STATE(mInputStream); + if (NS_WARN_IF(!mInputStream)) + return NS_ERROR_UNEXPECTED; return mInputStream->Available(aResult); } NS_IMETHODIMP nsBinaryInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t *aNumRead) { - NS_ENSURE_STATE(mInputStream); + if (NS_WARN_IF(!mInputStream)) + return NS_ERROR_UNEXPECTED; // mInputStream might give us short reads, so deal with that. uint32_t totalRead = 0; @@ -383,7 +397,8 @@ ReadSegmentForwardingThunk(nsIInputStream* aStream, NS_IMETHODIMP nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, uint32_t count, uint32_t *_retval) { - NS_ENSURE_STATE(mInputStream); + if (NS_WARN_IF(!mInputStream)) + return NS_ERROR_UNEXPECTED; ReadSegmentsClosure thunkClosure = { this, closure, writer, NS_OK, 0 }; @@ -416,21 +431,24 @@ nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, uint NS_IMETHODIMP nsBinaryInputStream::IsNonBlocking(bool *aNonBlocking) { - NS_ENSURE_STATE(mInputStream); + if (NS_WARN_IF(!mInputStream)) + return NS_ERROR_UNEXPECTED; return mInputStream->IsNonBlocking(aNonBlocking); } NS_IMETHODIMP -nsBinaryInputStream::Close() -{ - NS_ENSURE_STATE(mInputStream); - return mInputStream->Close(); +nsBinaryInputStream::Close() +{ + if (NS_WARN_IF(!mInputStream)) + return NS_ERROR_UNEXPECTED; + return mInputStream->Close(); } NS_IMETHODIMP nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream) { - NS_ENSURE_ARG_POINTER(aInputStream); + if (NS_WARN_IF(!aInputStream)) + return NS_ERROR_INVALID_ARG; mInputStream = aInputStream; mBufferAccess = do_QueryInterface(aInputStream); return NS_OK; @@ -729,7 +747,8 @@ nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength, const JS::Value& aBuffer, uint32_t bytesRead; nsresult rv = Read(reinterpret_cast(data), aLength, &bytesRead); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; if (bytesRead != aLength) { return NS_ERROR_FAILURE; } @@ -742,10 +761,12 @@ nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports* *aObject) nsCID cid; nsIID iid; nsresult rv = ReadID(&cid); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = ReadID(&iid); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // HACK: Intercept old (pre-gecko6) nsIURI IID, and replace with // the updated IID, so that we're QI'ing to an actual interface. @@ -774,13 +795,16 @@ nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports* *aObject) // END HACK nsCOMPtr object = do_CreateInstance(cid, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; nsCOMPtr serializable = do_QueryInterface(object); - NS_ENSURE_TRUE(serializable, NS_ERROR_UNEXPECTED); + if (NS_WARN_IF(!serializable)) + return NS_ERROR_UNEXPECTED; rv = serializable->Read(this); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return object->QueryInterface(iid, reinterpret_cast(aObject)); } @@ -789,17 +813,21 @@ NS_IMETHODIMP nsBinaryInputStream::ReadID(nsID *aResult) { nsresult rv = Read32(&aResult->m0); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = Read16(&aResult->m1); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = Read16(&aResult->m2); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; for (int i = 0; i < 8; ++i) { rv = Read8(&aResult->m3[i]); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } return NS_OK; diff --git a/xpcom/io/nsDirectoryService.cpp b/xpcom/io/nsDirectoryService.cpp index 603c9c015ca0..a1078d4dfb9a 100644 --- a/xpcom/io/nsDirectoryService.cpp +++ b/xpcom/io/nsDirectoryService.cpp @@ -59,7 +59,8 @@ nsresult nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile) //---------------------------------------------------------------------------------------- { - NS_ENSURE_ARG_POINTER(aFile); + if (NS_WARN_IF(!aFile)) + return NS_ERROR_INVALID_ARG; *aFile = nullptr; // Set the component registry location: @@ -225,8 +226,10 @@ nsDirectoryService::nsDirectoryService() nsresult nsDirectoryService::Create(nsISupports *outer, REFNSIID aIID, void **aResult) { - NS_ENSURE_ARG_POINTER(aResult); - NS_ENSURE_NO_AGGREGATION(outer); + if (NS_WARN_IF(!aResult)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; if (!gService) { @@ -284,7 +287,8 @@ NS_IMPL_ISUPPORTS4(nsDirectoryService, nsIProperties, nsIDirectoryService, nsIDi NS_IMETHODIMP nsDirectoryService::Undefine(const char* prop) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; nsDependentCString key(prop); if (!mHashtable.Get(key, nullptr)) @@ -360,7 +364,8 @@ static bool FindProviderFile(nsIDirectoryServiceProvider* aElement, NS_IMETHODIMP nsDirectoryService::Get(const char* prop, const nsIID & uuid, void* *result) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; nsDependentCString key(prop); @@ -409,7 +414,8 @@ nsDirectoryService::Get(const char* prop, const nsIID & uuid, void* *result) NS_IMETHODIMP nsDirectoryService::Set(const char* prop, nsISupports* value) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; nsDependentCString key(prop); if (mHashtable.Get(key, nullptr) || !value) { @@ -431,7 +437,8 @@ nsDirectoryService::Set(const char* prop, nsISupports* value) NS_IMETHODIMP nsDirectoryService::Has(const char *prop, bool *_retval) { - NS_ENSURE_ARG(prop); + if (NS_WARN_IF(!prop)) + return NS_ERROR_INVALID_ARG; *_retval = false; nsCOMPtr value; @@ -910,7 +917,8 @@ nsDirectoryService::GetFile(const char *prop, bool *persistent, nsIFile **_retva NS_IMETHODIMP nsDirectoryService::GetFiles(const char *prop, nsISimpleEnumerator **_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = nullptr; return NS_ERROR_FAILURE; diff --git a/xpcom/io/nsIOUtil.cpp b/xpcom/io/nsIOUtil.cpp index 4363355de1a9..e4062793b0ba 100644 --- a/xpcom/io/nsIOUtil.cpp +++ b/xpcom/io/nsIOUtil.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -13,7 +13,8 @@ NS_IMPL_ISUPPORTS1(nsIOUtil, nsIIOUtil) NS_IMETHODIMP nsIOUtil::InputStreamIsBuffered(nsIInputStream* aStream, bool* _retval) { - NS_ENSURE_ARG_POINTER(aStream); + if (NS_WARN_IF(!aStream)) + return NS_ERROR_INVALID_ARG; *_retval = NS_InputStreamIsBuffered(aStream); return NS_OK; } @@ -21,7 +22,8 @@ nsIOUtil::InputStreamIsBuffered(nsIInputStream* aStream, bool* _retval) NS_IMETHODIMP nsIOUtil::OutputStreamIsBuffered(nsIOutputStream* aStream, bool* _retval) { - NS_ENSURE_ARG_POINTER(aStream); + if (NS_WARN_IF(!aStream)) + return NS_ERROR_INVALID_ARG; *_retval = NS_OutputStreamIsBuffered(aStream); return NS_OK; } diff --git a/xpcom/io/nsInputStreamTee.cpp b/xpcom/io/nsInputStreamTee.cpp index 4ac153dfe217..cebf04d20c7f 100644 --- a/xpcom/io/nsInputStreamTee.cpp +++ b/xpcom/io/nsInputStreamTee.cpp @@ -164,7 +164,6 @@ nsInputStreamTee::TeeSegment(const char *buf, uint32_t count) } nsRefPtr event = new nsInputStreamTeeWriteEvent(buf, count, mSink, this); - NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); LOG(("nsInputStreamTee::TeeSegment [%p] dispatching write %u bytes\n", this, count)); return mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL); @@ -214,7 +213,8 @@ NS_IMPL_ISUPPORTS2(nsInputStreamTee, NS_IMETHODIMP nsInputStreamTee::Close() { - NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSource)) + return NS_ERROR_NOT_INITIALIZED; nsresult rv = mSource->Close(); mSource = 0; mSink = 0; @@ -224,14 +224,16 @@ nsInputStreamTee::Close() NS_IMETHODIMP nsInputStreamTee::Available(uint64_t *avail) { - NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSource)) + return NS_ERROR_NOT_INITIALIZED; return mSource->Available(avail); } NS_IMETHODIMP nsInputStreamTee::Read(char *buf, uint32_t count, uint32_t *bytesRead) { - NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSource)) + return NS_ERROR_NOT_INITIALIZED; nsresult rv = mSource->Read(buf, count, bytesRead); if (NS_FAILED(rv) || (*bytesRead == 0)) @@ -246,7 +248,8 @@ nsInputStreamTee::ReadSegments(nsWriteSegmentFun writer, uint32_t count, uint32_t *bytesRead) { - NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSource)) + return NS_ERROR_NOT_INITIALIZED; mWriter = writer; mClosure = closure; @@ -257,7 +260,8 @@ nsInputStreamTee::ReadSegments(nsWriteSegmentFun writer, NS_IMETHODIMP nsInputStreamTee::IsNonBlocking(bool *result) { - NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSource)) + return NS_ERROR_NOT_INITIALIZED; return mSource->IsNonBlocking(result); } diff --git a/xpcom/io/nsLocalFileCommon.cpp b/xpcom/io/nsLocalFileCommon.cpp index 5ec4bae22b3a..75c53483877f 100644 --- a/xpcom/io/nsLocalFileCommon.cpp +++ b/xpcom/io/nsLocalFileCommon.cpp @@ -33,7 +33,8 @@ void NS_ShutdownLocalFile() NS_IMETHODIMP nsLocalFile::InitWithFile(nsIFile *aFile) { - NS_ENSURE_ARG(aFile); + if (NS_WARN_IF(!aFile)) + return NS_ERROR_INVALID_ARG; nsAutoCString path; aFile->GetNativePath(path); @@ -189,7 +190,8 @@ static int32_t SplitPath(PRUnichar *path, PRUnichar **nodeArray, int32_t arrayLe NS_IMETHODIMP nsLocalFile::GetRelativeDescriptor(nsIFile *fromFile, nsACString& _retval) { - NS_ENSURE_ARG_POINTER(fromFile); + if (NS_WARN_IF(!fromFile)) + return NS_ERROR_INVALID_ARG; const int32_t kMaxNodesInPath = 32; // diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index 099bcea90280..c0127e80949b 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -243,8 +243,10 @@ nsLocalFile::nsLocalFileConstructor(nsISupports *outer, const nsIID &aIID, void **aInstancePtr) { - NS_ENSURE_ARG_POINTER(aInstancePtr); - NS_ENSURE_NO_AGGREGATION(outer); + if (NS_WARN_IF(!aInstancePtr)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; *aInstancePtr = nullptr; @@ -1005,7 +1007,8 @@ NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRTime *aLastModTime) { CHECK_mPath(); - NS_ENSURE_ARG(aLastModTime); + if (NS_WARN_IF(!aLastModTime)) + return NS_ERROR_INVALID_ARG; PRFileInfo64 info; if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS) @@ -1043,7 +1046,8 @@ NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRTime *aLastModTimeOfLink) { CHECK_mPath(); - NS_ENSURE_ARG(aLastModTimeOfLink); + if (NS_WARN_IF(!aLastModTimeOfLink)) + return NS_ERROR_INVALID_ARG; struct STAT sbuf; if (LSTAT(mPath.get(), &sbuf) == -1) @@ -1072,7 +1076,8 @@ nsLocalFile::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink) NS_IMETHODIMP nsLocalFile::GetPermissions(uint32_t *aPermissions) { - NS_ENSURE_ARG(aPermissions); + if (NS_WARN_IF(!aPermissions)) + return NS_ERROR_INVALID_ARG; ENSURE_STAT_CACHE(); *aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode); return NS_OK; @@ -1082,7 +1087,8 @@ NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(uint32_t *aPermissionsOfLink) { CHECK_mPath(); - NS_ENSURE_ARG(aPermissionsOfLink); + if (NS_WARN_IF(!aPermissionsOfLink)) + return NS_ERROR_INVALID_ARG; struct STAT sbuf; if (LSTAT(mPath.get(), &sbuf) == -1) @@ -1127,7 +1133,8 @@ nsLocalFile::SetPermissionsOfLink(uint32_t aPermissions) NS_IMETHODIMP nsLocalFile::GetFileSize(int64_t *aFileSize) { - NS_ENSURE_ARG_POINTER(aFileSize); + if (NS_WARN_IF(!aFileSize)) + return NS_ERROR_INVALID_ARG; *aFileSize = 0; ENSURE_STAT_CACHE(); @@ -1176,7 +1183,8 @@ NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(int64_t *aFileSize) { CHECK_mPath(); - NS_ENSURE_ARG(aFileSize); + if (NS_WARN_IF(!aFileSize)) + return NS_ERROR_INVALID_ARG; struct STAT sbuf; if (LSTAT(mPath.get(), &sbuf) == -1) @@ -1241,7 +1249,8 @@ GetDeviceName(int deviceMajor, int deviceMinor, nsACString &deviceName) NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable) { - NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); + if (NS_WARN_IF(!aDiskSpaceAvailable)) + return NS_ERROR_INVALID_ARG; // These systems have the operations necessary to check disk space. @@ -1326,7 +1335,8 @@ NS_IMETHODIMP nsLocalFile::GetParent(nsIFile **aParent) { CHECK_mPath(); - NS_ENSURE_ARG_POINTER(aParent); + if (NS_WARN_IF(!aParent)) + return NS_ERROR_INVALID_ARG; *aParent = nullptr; // if '/' we are at the top of the volume, return null @@ -1372,7 +1382,8 @@ NS_IMETHODIMP nsLocalFile::Exists(bool *_retval) { CHECK_mPath(); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = (access(mPath.get(), F_OK) == 0); return NS_OK; @@ -1383,7 +1394,8 @@ NS_IMETHODIMP nsLocalFile::IsWritable(bool *_retval) { CHECK_mPath(); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = (access(mPath.get(), W_OK) == 0); if (*_retval || errno == EACCES) @@ -1395,7 +1407,8 @@ NS_IMETHODIMP nsLocalFile::IsReadable(bool *_retval) { CHECK_mPath(); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = (access(mPath.get(), R_OK) == 0); if (*_retval || errno == EACCES) @@ -1407,7 +1420,8 @@ NS_IMETHODIMP nsLocalFile::IsExecutable(bool *_retval) { CHECK_mPath(); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; // Check extension (bug 663899). On certain platforms, the file // extension may cause the OS to treat it as executable regardless of @@ -1496,7 +1510,8 @@ nsLocalFile::IsExecutable(bool *_retval) NS_IMETHODIMP nsLocalFile::IsDirectory(bool *_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = false; ENSURE_STAT_CACHE(); *_retval = S_ISDIR(mCachedStat.st_mode); @@ -1506,7 +1521,8 @@ nsLocalFile::IsDirectory(bool *_retval) NS_IMETHODIMP nsLocalFile::IsFile(bool *_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = false; ENSURE_STAT_CACHE(); *_retval = S_ISREG(mCachedStat.st_mode); @@ -1516,7 +1532,8 @@ nsLocalFile::IsFile(bool *_retval) NS_IMETHODIMP nsLocalFile::IsHidden(bool *_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; nsACString::const_iterator begin, end; LocateNativeLeafName(begin, end); *_retval = (*begin == '.'); @@ -1526,7 +1543,8 @@ nsLocalFile::IsHidden(bool *_retval) NS_IMETHODIMP nsLocalFile::IsSymlink(bool *_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; CHECK_mPath(); struct STAT symStat; @@ -1539,7 +1557,8 @@ nsLocalFile::IsSymlink(bool *_retval) NS_IMETHODIMP nsLocalFile::IsSpecial(bool *_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; ENSURE_STAT_CACHE(); *_retval = S_ISCHR(mCachedStat.st_mode) || S_ISBLK(mCachedStat.st_mode) || @@ -1554,8 +1573,10 @@ nsLocalFile::IsSpecial(bool *_retval) NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, bool *_retval) { - NS_ENSURE_ARG(inFile); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!inFile)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = false; nsAutoCString inPath; @@ -1573,8 +1594,10 @@ NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, bool recur, bool *_retval) { CHECK_mPath(); - NS_ENSURE_ARG(inFile); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!inFile)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; nsAutoCString inPath; nsresult rv; @@ -1710,7 +1733,8 @@ NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval) { CHECK_mPath(); - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; #ifdef NS_BUILD_REFCNT_LOGGING nsTraceRefcntImpl::SetActivityIsLegal(false); @@ -2121,7 +2145,8 @@ nsLocalFile::InitWithCFURL(CFURLRef aCFURL) NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef) { - NS_ENSURE_ARG(aFSRef); + if (NS_WARN_IF(!aFSRef)) + return NS_ERROR_INVALID_ARG; CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef); if (newURLRef) { @@ -2151,7 +2176,8 @@ nsLocalFile::GetCFURL(CFURLRef *_retval) NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; nsresult rv = NS_ERROR_FAILURE; @@ -2169,7 +2195,8 @@ nsLocalFile::GetFSRef(FSRef *_retval) NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval) { - NS_ENSURE_ARG_POINTER(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; FSRef fsRef; nsresult rv = GetFSRef(&fsRef); @@ -2184,7 +2211,8 @@ nsLocalFile::GetFSSpec(FSSpec *_retval) NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(int64_t *aFileSizeWithResFork) { - NS_ENSURE_ARG_POINTER(aFileSizeWithResFork); + if (NS_WARN_IF(!aFileSizeWithResFork)) + return NS_ERROR_INVALID_ARG; FSRef fsRef; nsresult rv = GetFSRef(&fsRef); @@ -2343,7 +2371,8 @@ nsLocalFile::OpenDocWithApp(nsIFile *aAppToOpenWith, bool aLaunchInBackground) NS_IMETHODIMP nsLocalFile::IsPackage(bool *_retval) { - NS_ENSURE_ARG(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = false; CFURLRef url; @@ -2414,7 +2443,8 @@ NS_IMETHODIMP nsLocalFile::GetBundleContentsLastModifiedTime(int64_t *aLastModTime) { CHECK_mPath(); - NS_ENSURE_ARG_POINTER(aLastModTime); + if (NS_WARN_IF(!aLastModTime)) + return NS_ERROR_INVALID_ARG; bool isPackage = false; nsresult rv = IsPackage(&isPackage); @@ -2440,7 +2470,8 @@ nsLocalFile::GetBundleContentsLastModifiedTime(int64_t *aLastModTime) NS_IMETHODIMP nsLocalFile::InitWithFile(nsIFile *aFile) { - NS_ENSURE_ARG(aFile); + if (NS_WARN_IF(!aFile)) + return NS_ERROR_INVALID_ARG; nsAutoCString nativePath; nsresult rv = aFile->GetNativePath(nativePath); diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index c8cd7911f159..3d1e3e01ab0f 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -725,7 +725,8 @@ struct nsDir static nsresult OpenDir(const nsAFlatString &name, nsDir * *dir) { - NS_ENSURE_ARG_POINTER(dir); + if (NS_WARN_IF(!dir)) + return NS_ERROR_INVALID_ARG; *dir = nullptr; if (name.Length() + 3 >= MAX_PATH) @@ -765,7 +766,8 @@ static nsresult ReadDir(nsDir *dir, PRDirFlags flags, nsString& name) { name.Truncate(); - NS_ENSURE_ARG(dir); + if (NS_WARN_IF(!dir)) + return NS_ERROR_INVALID_ARG; while (1) { BOOL rv; @@ -809,7 +811,8 @@ ReadDir(nsDir *dir, PRDirFlags flags, nsString& name) static nsresult CloseDir(nsDir *&d) { - NS_ENSURE_ARG(d); + if (NS_WARN_IF(!d)) + return NS_ERROR_INVALID_ARG; BOOL isOk = FindClose(d->handle); // PR_DELETE also nulls out the passed in pointer. @@ -962,8 +965,10 @@ nsLocalFile::nsLocalFile() nsresult nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { - NS_ENSURE_ARG_POINTER(aInstancePtr); - NS_ENSURE_NO_AGGREGATION(outer); + if (NS_WARN_IF(!aInstancePtr)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; nsLocalFile* inst = new nsLocalFile(); if (inst == nullptr) @@ -1149,7 +1154,8 @@ nsLocalFile::Clone(nsIFile **file) NS_IMETHODIMP nsLocalFile::InitWithFile(nsIFile *aFile) { - NS_ENSURE_ARG(aFile); + if (NS_WARN_IF(!aFile)) + return NS_ERROR_INVALID_ARG; nsAutoString path; aFile->GetPath(path); @@ -2072,7 +2078,8 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow return NS_ERROR_FAILURE; rv = file->MoveTo(target, EmptyString()); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_FAILED(rv)) + return rv; } else { @@ -2080,7 +2087,8 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow rv = file->CopyToFollowingLinks(target, EmptyString()); else rv = file->CopyTo(target, EmptyString()); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_FAILED(rv)) + return rv; } } } @@ -2093,7 +2101,8 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow if (move) { rv = Remove(false /* recursive */); - NS_ENSURE_SUCCESS(rv,rv); + if (NS_FAILED(rv)) + return rv; } } @@ -2258,7 +2267,8 @@ nsLocalFile::GetLastModifiedTime(PRTime *aLastModifiedTime) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(aLastModifiedTime); + if (NS_WARN_IF(!aLastModifiedTime)) + return NS_ERROR_INVALID_ARG; // get the modified time of the target as determined by mFollowSymlinks // If true, then this will be for the target of the shortcut file, @@ -2281,7 +2291,8 @@ nsLocalFile::GetLastModifiedTimeOfLink(PRTime *aLastModifiedTime) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(aLastModifiedTime); + if (NS_WARN_IF(!aLastModifiedTime)) + return NS_ERROR_INVALID_ARG; // The caller is assumed to have already called IsSymlink // and to have found that this file is a link. @@ -2381,7 +2392,8 @@ nsLocalFile::SetModDate(PRTime aLastModifiedTime, const PRUnichar *filePath) NS_IMETHODIMP nsLocalFile::GetPermissions(uint32_t *aPermissions) { - NS_ENSURE_ARG(aPermissions); + if (NS_WARN_IF(!aPermissions)) + return NS_ERROR_INVALID_ARG; // get the permissions of the target as determined by mFollowSymlinks // If true, then this will be for the target of the shortcut file, @@ -2410,7 +2422,8 @@ nsLocalFile::GetPermissionsOfLink(uint32_t *aPermissions) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(aPermissions); + if (NS_WARN_IF(!aPermissions)) + return NS_ERROR_INVALID_ARG; // The caller is assumed to have already called IsSymlink // and to have found that this file is a link. It is not @@ -2479,7 +2492,8 @@ nsLocalFile::SetPermissionsOfLink(uint32_t aPermissions) NS_IMETHODIMP nsLocalFile::GetFileSize(int64_t *aFileSize) { - NS_ENSURE_ARG(aFileSize); + if (NS_WARN_IF(!aFileSize)) + return NS_ERROR_INVALID_ARG; nsresult rv = ResolveAndStat(); if (NS_FAILED(rv)) @@ -2496,7 +2510,8 @@ nsLocalFile::GetFileSizeOfLink(int64_t *aFileSize) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(aFileSize); + if (NS_WARN_IF(!aFileSize)) + return NS_ERROR_INVALID_ARG; // The caller is assumed to have already called IsSymlink // and to have found that this file is a link. @@ -2551,7 +2566,8 @@ nsLocalFile::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(aDiskSpaceAvailable); + if (NS_WARN_IF(!aDiskSpaceAvailable)) + return NS_ERROR_INVALID_ARG; ResolveAndStat(); @@ -2580,7 +2596,8 @@ nsLocalFile::GetParent(nsIFile * *aParent) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG_POINTER(aParent); + if (NS_WARN_IF(!aParent)) + return NS_ERROR_INVALID_ARG; // A two-character path must be a drive such as C:, so it has no parent if (mWorkingPath.Length() == 2) { @@ -2624,7 +2641,8 @@ nsLocalFile::Exists(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = false; MakeDirty(); @@ -2694,7 +2712,8 @@ nsLocalFile::IsReadable(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = false; nsresult rv = ResolveAndStat(); @@ -2712,7 +2731,8 @@ nsLocalFile::IsExecutable(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; *_retval = false; nsresult rv; @@ -2867,7 +2887,8 @@ nsLocalFile::IsHidden(bool *_retval) nsresult nsLocalFile::HasFileAttribute(DWORD fileAttrib, bool *_retval) { - NS_ENSURE_ARG(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; nsresult rv = Resolve(); if (NS_FAILED(rv)) { @@ -2889,7 +2910,8 @@ nsLocalFile::IsSymlink(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - NS_ENSURE_ARG(_retval); + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; // unless it is a valid shortcut path it's not a symlink if (!IsShortcutPath(mWorkingPath)) { @@ -2920,8 +2942,10 @@ nsLocalFile::IsSpecial(bool *_retval) NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, bool *_retval) { - NS_ENSURE_ARG(inFile); - NS_ENSURE_ARG(_retval); + if (NS_WARN_IF(!inFile)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(!_retval)) + return NS_ERROR_INVALID_ARG; EnsureShortPath(); diff --git a/xpcom/io/nsMultiplexInputStream.cpp b/xpcom/io/nsMultiplexInputStream.cpp index 2373cfaa737b..4d36fb90721f 100644 --- a/xpcom/io/nsMultiplexInputStream.cpp +++ b/xpcom/io/nsMultiplexInputStream.cpp @@ -118,7 +118,6 @@ nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, uint32_t aIndex) { NS_ASSERTION(SeekableStreamAtBeginning(aStream), "Inserted stream not at beginning."); bool result = mStreams.InsertElementAt(aIndex, aStream); - NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY); if (mCurrentStream > aIndex || (mCurrentStream == aIndex && mStartedReadingCurrent)) ++mCurrentStream; @@ -143,7 +142,8 @@ NS_IMETHODIMP nsMultiplexInputStream::GetStream(uint32_t aIndex, nsIInputStream **_retval) { *_retval = mStreams.SafeElementAt(aIndex, nullptr); - NS_ENSURE_TRUE(*_retval, NS_ERROR_NOT_AVAILABLE); + if (NS_WARN_IF(!*_retval)) + return NS_ERROR_NOT_AVAILABLE; NS_ADDREF(*_retval); return NS_OK; @@ -181,7 +181,8 @@ nsMultiplexInputStream::Available(uint64_t *_retval) for (uint32_t i = mCurrentStream; i < len; i++) { uint64_t streamAvail; rv = mStreams[i]->Available(&streamAvail); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; avail += streamAvail; } *_retval = avail; @@ -328,7 +329,8 @@ nsMultiplexInputStream::IsNonBlocking(bool *aNonBlocking) } for (uint32_t i = 0; i < len; ++i) { nsresult rv = mStreams[i]->IsNonBlocking(aNonBlocking); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // If one is non-blocking the entire stream becomes non-blocking // (except that we don't implement nsIAsyncInputStream, so there's // not much for the caller to do if Read returns "would block") @@ -367,7 +369,8 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) if (i < oldCurrentStream || (i == oldCurrentStream && oldStartedReadingCurrent)) { rv = stream->Seek(NS_SEEK_SET, 0); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; continue; } else { @@ -383,13 +386,15 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) } else { rv = stream->Tell(&streamPos); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } // See if we need to seek current stream forward or backward if (remaining < streamPos) { rv = stream->Seek(NS_SEEK_SET, remaining); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mCurrentStream = i; mStartedReadingCurrent = remaining != 0; @@ -405,12 +410,14 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) else { uint64_t avail; rv = mStreams[i]->Available(&avail); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; int64_t newPos = XPCOM_MIN(remaining, streamPos + (int64_t)avail); rv = stream->Seek(NS_SEEK_SET, newPos); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mCurrentStream = i; mStartedReadingCurrent = true; @@ -436,12 +443,14 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) uint64_t avail; rv = mStreams[i]->Available(&avail); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; int64_t seek = XPCOM_MIN((int64_t)avail, remaining); rv = stream->Seek(NS_SEEK_CUR, seek); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mCurrentStream = i; mStartedReadingCurrent = true; @@ -460,12 +469,14 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) int64_t pos; rv = stream->Tell(&pos); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; int64_t seek = XPCOM_MIN(pos, remaining); rv = stream->Seek(NS_SEEK_CUR, -seek); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mCurrentStream = i; mStartedReadingCurrent = seek != -pos; @@ -495,7 +506,8 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) if (remaining == 0) { if (i >= oldCurrentStream) { rv = stream->Seek(NS_SEEK_END, 0); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } else { break; @@ -509,7 +521,8 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) } else { uint64_t avail; rv = mStreams[i]->Available(&avail); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; streamPos = avail; } @@ -517,7 +530,8 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) // See if we have enough data in the current stream. if (DeprecatedAbs(remaining) < streamPos) { rv = stream->Seek(NS_SEEK_END, remaining); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mCurrentStream = i; mStartedReadingCurrent = true; @@ -531,12 +545,14 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) } else { int64_t avail; rv = stream->Tell(&avail); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; int64_t newPos = streamPos + XPCOM_MIN(avail, DeprecatedAbs(remaining)); rv = stream->Seek(NS_SEEK_END, -newPos); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mCurrentStream = i; mStartedReadingCurrent = true; @@ -570,11 +586,13 @@ nsMultiplexInputStream::Tell(int64_t *_retval) last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream; for (i = 0; i < last; ++i) { nsCOMPtr stream = do_QueryInterface(mStreams[i]); - NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE); + if (NS_WARN_IF(!stream)) + return NS_ERROR_NO_INTERFACE; int64_t pos; rv = stream->Tell(&pos); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; ret64 += pos; } *_retval = ret64; diff --git a/xpcom/io/nsPipe3.cpp b/xpcom/io/nsPipe3.cpp index eb63ef92432f..4c988cf083bf 100644 --- a/xpcom/io/nsPipe3.cpp +++ b/xpcom/io/nsPipe3.cpp @@ -356,7 +356,8 @@ nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream) NS_IMETHODIMP nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream) { - NS_ENSURE_TRUE(mInited, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mInited)) + return NS_ERROR_NOT_INITIALIZED; NS_ADDREF(*aOutputStream = &mOutput); return NS_OK; } diff --git a/xpcom/io/nsStorageStream.cpp b/xpcom/io/nsStorageStream.cpp index 1bf82156757a..5c745819b5b3 100644 --- a/xpcom/io/nsStorageStream.cpp +++ b/xpcom/io/nsStorageStream.cpp @@ -88,8 +88,10 @@ NS_IMETHODIMP nsStorageStream::GetOutputStream(int32_t aStartingOffset, nsIOutputStream * *aOutputStream) { - NS_ENSURE_ARG(aOutputStream); - NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!aOutputStream)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(!mSegmentedBuffer)) + return NS_ERROR_NOT_INITIALIZED; if (mWriteInProgress) return NS_ERROR_NOT_AVAILABLE; @@ -116,7 +118,8 @@ nsStorageStream::GetOutputStream(int32_t aStartingOffset, NS_IMETHODIMP nsStorageStream::Close() { - NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSegmentedBuffer)) + return NS_ERROR_NOT_INITIALIZED; mWriteInProgress = false; @@ -145,15 +148,15 @@ nsStorageStream::Flush() NS_IMETHODIMP nsStorageStream::Write(const char *aBuffer, uint32_t aCount, uint32_t *aNumWritten) { - NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!aNumWritten) || NS_WARN_IF(!aBuffer)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(!mSegmentedBuffer)) + return NS_ERROR_NOT_INITIALIZED; const char* readCursor; uint32_t count, availableInSegment, remaining; nsresult rv = NS_OK; - NS_ENSURE_ARG_POINTER(aNumWritten); - NS_ENSURE_ARG(aBuffer); - LOG(("nsStorageStream [%p] Write mWriteCursor=%x mSegmentEnd=%x aCount=%d\n", this, mWriteCursor, mSegmentEnd, aCount)); @@ -223,7 +226,6 @@ nsStorageStream::IsNonBlocking(bool *aNonBlocking) NS_IMETHODIMP nsStorageStream::GetLength(uint32_t *aLength) { - NS_ENSURE_ARG(aLength); *aLength = mLogicalLength; return NS_OK; } @@ -232,7 +234,8 @@ nsStorageStream::GetLength(uint32_t *aLength) NS_IMETHODIMP nsStorageStream::SetLength(uint32_t aLength) { - NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSegmentedBuffer)) + return NS_ERROR_NOT_INITIALIZED; if (mWriteInProgress) return NS_ERROR_NOT_AVAILABLE; @@ -257,8 +260,6 @@ nsStorageStream::SetLength(uint32_t aLength) NS_IMETHODIMP nsStorageStream::GetWriteInProgress(bool *aWriteInProgress) { - NS_ENSURE_ARG(aWriteInProgress); - *aWriteInProgress = mWriteInProgress; return NS_OK; } @@ -266,7 +267,8 @@ nsStorageStream::GetWriteInProgress(bool *aWriteInProgress) NS_METHOD nsStorageStream::Seek(int32_t aPosition) { - NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSegmentedBuffer)) + return NS_ERROR_NOT_INITIALIZED; // An argument of -1 means "seek to end of stream" if (aPosition == -1) @@ -358,7 +360,8 @@ NS_IMPL_ISUPPORTS2(nsStorageInputStream, NS_IMETHODIMP nsStorageStream::NewInputStream(int32_t aStartingOffset, nsIInputStream* *aInputStream) { - NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mSegmentedBuffer)) + return NS_ERROR_NOT_INITIALIZED; nsStorageInputStream *inputStream = new nsStorageInputStream(this, mSegmentSize); if (!inputStream) @@ -524,8 +527,6 @@ nsStorageInputStream::Seek(uint32_t aPosition) nsresult NS_NewStorageStream(uint32_t segmentSize, uint32_t maxSize, nsIStorageStream **result) { - NS_ENSURE_ARG(result); - nsStorageStream* storageStream = new nsStorageStream(); if (!storageStream) return NS_ERROR_OUT_OF_MEMORY; diff --git a/xpcom/io/nsStringStream.cpp b/xpcom/io/nsStringStream.cpp index f32817811921..f6bfd18d9f72 100644 --- a/xpcom/io/nsStringStream.cpp +++ b/xpcom/io/nsStringStream.cpp @@ -112,7 +112,8 @@ nsStringInputStream::GetData(nsACString &data) // The stream doesn't have any data when it is closed. We could fake it // and return an empty string here, but it seems better to keep this return // value consistent with the behavior of the other 'getter' methods. - NS_ENSURE_TRUE(!Closed(), NS_BASE_STREAM_CLOSED); + if (NS_WARN_IF(Closed())) + return NS_BASE_STREAM_CLOSED; data.Assign(mData); return NS_OK; @@ -140,7 +141,8 @@ nsStringInputStream::ToString(char **result) NS_IMETHODIMP nsStringInputStream::SetData(const char *data, int32_t dataLen) { - NS_ENSURE_ARG_POINTER(data); + if (NS_WARN_IF(!data)) + return NS_ERROR_INVALID_ARG; mData.Assign(data, dataLen); mOffset = 0; return NS_OK; @@ -149,7 +151,8 @@ nsStringInputStream::SetData(const char *data, int32_t dataLen) NS_IMETHODIMP nsStringInputStream::AdoptData(char *data, int32_t dataLen) { - NS_ENSURE_ARG_POINTER(data); + if (NS_WARN_IF(!data)) + return NS_ERROR_INVALID_ARG; mData.Adopt(data, dataLen); mOffset = 0; return NS_OK; @@ -158,7 +161,8 @@ nsStringInputStream::AdoptData(char *data, int32_t dataLen) NS_IMETHODIMP nsStringInputStream::ShareData(const char *data, int32_t dataLen) { - NS_ENSURE_ARG_POINTER(data); + if (NS_WARN_IF(!data)) + return NS_ERROR_INVALID_ARG; if (dataLen < 0) dataLen = strlen(data); @@ -262,8 +266,8 @@ nsStringInputStream::Seek(int32_t whence, int64_t offset) return NS_ERROR_INVALID_ARG; } - NS_ENSURE_ARG(newPos >= 0); - NS_ENSURE_ARG(newPos <= Length()); + if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length())) + return NS_ERROR_INVALID_ARG; mOffset = (uint32_t)newPos; return NS_OK; @@ -386,7 +390,8 @@ nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result) { *result = nullptr; - NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); + if (NS_WARN_IF(outer)) + return NS_ERROR_NO_AGGREGATION; nsStringInputStream *inst = new nsStringInputStream(); if (!inst) diff --git a/xpcom/reflect/xptcall/src/xptcall.cpp b/xpcom/reflect/xptcall/src/xptcall.cpp index e46ddd559d3d..a33b1e70051d 100644 --- a/xpcom/reflect/xptcall/src/xptcall.cpp +++ b/xpcom/reflect/xptcall/src/xptcall.cpp @@ -40,11 +40,13 @@ EXPORT_XPCOM_API(nsresult) NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, nsISomeInterface* *aResult) { - NS_ENSURE_ARG(aOuter && aResult); + if (NS_WARN_IF(!aOuter) || NS_WARN_IF(!aResult)) + return NS_ERROR_INVALID_ARG; XPTInterfaceInfoManager *iim = XPTInterfaceInfoManager::GetSingleton(); - NS_ENSURE_TRUE(iim, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!iim)) + return NS_ERROR_NOT_INITIALIZED; xptiInterfaceEntry *iie = iim->GetInterfaceEntryForIID(&aIID); if (!iie || !iie->EnsureResolved() || iie->GetBuiltinClassFlag()) diff --git a/xpcom/threads/LazyIdleThread.cpp b/xpcom/threads/LazyIdleThread.cpp index 0cf14ad0acd5..71bf2ea53718 100644 --- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -147,21 +147,26 @@ LazyIdleThread::EnsureThread() if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) { nsCOMPtr obs = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = obs->AddObserver(this, "xpcom-shutdown-threads", false); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); - NS_ENSURE_TRUE(mIdleTimer, NS_ERROR_FAILURE); + if (NS_WARN_IF(!mIdleTimer)) + return NS_ERROR_UNEXPECTED; nsCOMPtr runnable = NS_NewRunnableMethod(this, &LazyIdleThread::InitThread); - NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE); + if (NS_WARN_IF(!runnable)) + return NS_ERROR_UNEXPECTED; rv = NS_NewThread(getter_AddRefs(mThread), runnable); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return NS_OK; } @@ -268,12 +273,14 @@ LazyIdleThread::ShutdownThread() nsCOMPtr runnable = NS_NewRunnableMethod(this, &LazyIdleThread::CleanupThread); - NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE); + if (NS_WARN_IF(!runnable)) + return NS_ERROR_UNEXPECTED; PreDispatch(); rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; // Put the temporary queue in place before calling Shutdown(). mQueuedRunnables = &queuedRunnables; @@ -299,7 +306,8 @@ LazyIdleThread::ShutdownThread() if (mIdleTimer) { rv = mIdleTimer->Cancel(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; mIdleTimer = nullptr; } @@ -376,7 +384,8 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent, ASSERT_OWNING_THREAD(); // LazyIdleThread can't always support synchronous dispatch currently. - NS_ENSURE_TRUE(aFlags == NS_DISPATCH_NORMAL, NS_ERROR_NOT_IMPLEMENTED); + if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) + return NS_ERROR_NOT_IMPLEMENTED; // If our thread is shutting down then we can't actually dispatch right now. // Queue this runnable for later. @@ -386,7 +395,8 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent, } nsresult rv = EnsureThread(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; PreDispatch(); @@ -427,7 +437,8 @@ LazyIdleThread::Shutdown() mIdleObserver = nullptr; - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return NS_OK; } @@ -467,7 +478,8 @@ LazyIdleThread::Notify(nsITimer* aTimer) } nsresult rv = ShutdownThread(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; return NS_OK; } @@ -513,10 +525,12 @@ LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */, if (shouldNotifyIdle) { nsCOMPtr runnable = NS_NewRunnableMethod(this, &LazyIdleThread::ScheduleTimer); - NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE); + if (NS_WARN_IF(!runnable)) + return NS_ERROR_UNEXPECTED; nsresult rv = mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; } return NS_OK; diff --git a/xpcom/threads/nsEnvironment.cpp b/xpcom/threads/nsEnvironment.cpp index f5c0656b4ed3..53b207556735 100644 --- a/xpcom/threads/nsEnvironment.cpp +++ b/xpcom/threads/nsEnvironment.cpp @@ -48,7 +48,8 @@ nsEnvironment::Exists(const nsAString& aName, bool *aOutValue) { nsAutoCString nativeName; nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; nsAutoCString nativeVal; #if defined(XP_UNIX) @@ -78,7 +79,8 @@ nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue) { nsAutoCString nativeName; nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; nsAutoCString nativeVal; const char *value = PR_GetEnv(nativeName.get()); @@ -122,10 +124,12 @@ nsEnvironment::Set(const nsAString& aName, const nsAString& aValue) nsAutoCString nativeVal; nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; rv = NS_CopyUnicodeToNative(aValue, nativeVal); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; MutexAutoLock lock(mLock); diff --git a/xpcom/threads/nsMemoryPressure.cpp b/xpcom/threads/nsMemoryPressure.cpp index 0e1b556054ea..094d4c06ab04 100644 --- a/xpcom/threads/nsMemoryPressure.cpp +++ b/xpcom/threads/nsMemoryPressure.cpp @@ -49,6 +49,5 @@ NS_DispatchMemoryPressure(MemoryPressureState state) { NS_DispatchEventualMemoryPressure(state); nsCOMPtr event = new nsRunnable; - NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); return NS_DispatchToMainThread(event); } diff --git a/xpcom/threads/nsProcessCommon.cpp b/xpcom/threads/nsProcessCommon.cpp index 8a6345d11d35..d2d660bafb66 100644 --- a/xpcom/threads/nsProcessCommon.cpp +++ b/xpcom/threads/nsProcessCommon.cpp @@ -88,7 +88,8 @@ nsProcess::Init(nsIFile* executable) if (mExecutable) return NS_ERROR_ALREADY_INITIALIZED; - NS_ENSURE_ARG_POINTER(executable); + if (NS_WARN_IF(!executable)) + return NS_ERROR_INVALID_ARG; bool isFile; //First make sure the file exists @@ -408,8 +409,10 @@ nsresult nsProcess::RunProcess(bool blocking, char **my_argv, nsIObserver* observer, bool holdWeak, bool argsUTF8) { - NS_ENSURE_TRUE(mExecutable, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_FALSE(mThread, NS_ERROR_ALREADY_INITIALIZED); + if (NS_WARN_IF(!mExecutable)) + return NS_ERROR_NOT_INITIALIZED; + if (NS_WARN_IF(mThread)) + return NS_ERROR_ALREADY_INITIALIZED; if (observer) { if (holdWeak) { diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 94e8a04da130..9cc4e2528e8f 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -152,9 +152,9 @@ NS_IMPL_CI_INTERFACE_GETTER4(nsThread, nsIThread, nsIThreadInternal, class nsThreadStartupEvent : public nsRunnable { public: - // Create a new thread startup object. - static nsThreadStartupEvent *Create() { - return new nsThreadStartupEvent(); + nsThreadStartupEvent() + : mMon("nsThreadStartupEvent.mMon") + , mInitialized(false) { } // This method does not return until the thread startup object is in the @@ -180,11 +180,6 @@ private: return NS_OK; } - nsThreadStartupEvent() - : mMon("nsThreadStartupEvent.mMon") - , mInitialized(false) { - } - ReentrantMonitor mMon; bool mInitialized; }; @@ -310,8 +305,7 @@ nsresult nsThread::Init() { // spawn thread and wait until it is fully setup - nsRefPtr startup = nsThreadStartupEvent::Create(); - NS_ENSURE_TRUE(startup, NS_ERROR_OUT_OF_MEMORY); + nsRefPtr startup = new nsThreadStartupEvent(); NS_ADDREF_THIS(); @@ -377,7 +371,8 @@ nsThread::Dispatch(nsIRunnable *event, uint32_t flags) { LOG(("THRD(%p) Dispatch [%p %x]\n", this, event, flags)); - NS_ENSURE_ARG_POINTER(event); + if (NS_WARN_IF(!event)) + return NS_ERROR_INVALID_ARG; if (gXPCOMThreadsShutDown && MAIN_THREAD != mIsMainThread) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; @@ -385,7 +380,8 @@ nsThread::Dispatch(nsIRunnable *event, uint32_t flags) if (flags & DISPATCH_SYNC) { nsThread *thread = nsThreadManager::get()->GetCurrentThread(); - NS_ENSURE_STATE(thread); + if (NS_WARN_IF(!thread)) + return NS_ERROR_NOT_AVAILABLE; // XXX we should be able to do something better here... we should // be able to monitor the slot occupied by this event and use @@ -437,7 +433,8 @@ nsThread::Shutdown() if (!mThread) return NS_OK; - NS_ENSURE_STATE(mThread != PR_GetCurrentThread()); + if (NS_WARN_IF(mThread == PR_GetCurrentThread())) + return NS_ERROR_UNEXPECTED; // Prevent multiple calls to this method { @@ -490,7 +487,8 @@ nsThread::Shutdown() NS_IMETHODIMP nsThread::HasPendingEvents(bool *result) { - NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); + if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) + return NS_ERROR_NOT_SAME_THREAD; *result = mEvents.GetEvent(false, nullptr); return NS_OK; @@ -548,7 +546,8 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result) { LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, mayWait, mRunningEvent)); - NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); + if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) + return NS_ERROR_NOT_SAME_THREAD; if (MAIN_THREAD == mIsMainThread && mayWait && !ShuttingDown()) HangMonitor::Suspend(); @@ -644,7 +643,8 @@ nsThread::GetPriority(int32_t *priority) NS_IMETHODIMP nsThread::SetPriority(int32_t priority) { - NS_ENSURE_STATE(mThread); + if (NS_WARN_IF(!mThread)) + return NS_ERROR_NOT_INITIALIZED; // NSPR defines the following four thread priorities: // PR_PRIORITY_LOW @@ -690,7 +690,8 @@ nsThread::GetObserver(nsIThreadObserver **obs) NS_IMETHODIMP nsThread::SetObserver(nsIThreadObserver *obs) { - NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); + if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) + return NS_ERROR_NOT_SAME_THREAD; MutexAutoLock lock(mLock); mObserver = obs; @@ -700,8 +701,8 @@ nsThread::SetObserver(nsIThreadObserver *obs) NS_IMETHODIMP nsThread::GetRecursionDepth(uint32_t *depth) { - NS_ENSURE_ARG_POINTER(depth); - NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); + if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) + return NS_ERROR_NOT_SAME_THREAD; *depth = mRunningEvent; return NS_OK; @@ -710,8 +711,10 @@ nsThread::GetRecursionDepth(uint32_t *depth) NS_IMETHODIMP nsThread::AddObserver(nsIThreadObserver *observer) { - NS_ENSURE_ARG_POINTER(observer); - NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); + if (NS_WARN_IF(!observer)) + return NS_ERROR_INVALID_ARG; + if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) + return NS_ERROR_NOT_SAME_THREAD; NS_WARN_IF_FALSE(!mEventObservers.Contains(observer), "Adding an observer twice!"); @@ -727,7 +730,8 @@ nsThread::AddObserver(nsIThreadObserver *observer) NS_IMETHODIMP nsThread::RemoveObserver(nsIThreadObserver *observer) { - NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); + if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) + return NS_ERROR_NOT_SAME_THREAD; if (observer && !mEventObservers.RemoveElement(observer)) { NS_WARNING("Removing an observer that was never added!"); diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 52d1364f6953..cf41dcdb49a9 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -217,7 +217,8 @@ nsThreadManager::NewThread(uint32_t creationFlags, nsIThread **result) { // No new threads during Shutdown - NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mInitialized)) + return NS_ERROR_NOT_INITIALIZED; nsThread *thr = new nsThread(nsThread::NOT_MAIN_THREAD, stackSize); if (!thr) @@ -242,8 +243,10 @@ NS_IMETHODIMP nsThreadManager::GetThreadFromPRThread(PRThread *thread, nsIThread **result) { // Keep this functioning during Shutdown - NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED); - NS_ENSURE_ARG_POINTER(thread); + if (NS_WARN_IF(!mMainThread)) + return NS_ERROR_NOT_INITIALIZED; + if (NS_WARN_IF(!thread)) + return NS_ERROR_INVALID_ARG; nsRefPtr temp; { @@ -259,7 +262,8 @@ NS_IMETHODIMP nsThreadManager::GetMainThread(nsIThread **result) { // Keep this functioning during Shutdown - NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mMainThread)) + return NS_ERROR_NOT_INITIALIZED; NS_ADDREF(*result = mMainThread); return NS_OK; } @@ -268,7 +272,8 @@ NS_IMETHODIMP nsThreadManager::GetCurrentThread(nsIThread **result) { // Keep this functioning during Shutdown - NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!mMainThread)) + return NS_ERROR_NOT_INITIALIZED; *result = GetCurrentThread(); if (!*result) return NS_ERROR_OUT_OF_MEMORY; diff --git a/xpcom/threads/nsThreadPool.cpp b/xpcom/threads/nsThreadPool.cpp index 2ccc4b0142f2..6e3236db7a73 100644 --- a/xpcom/threads/nsThreadPool.cpp +++ b/xpcom/threads/nsThreadPool.cpp @@ -92,7 +92,8 @@ nsThreadPool::PutEvent(nsIRunnable *event) nsThreadManager::get()->NewThread(0, nsIThreadManager::DEFAULT_STACK_SIZE, getter_AddRefs(thread)); - NS_ENSURE_STATE(thread); + if (NS_WARN_IF(!thread)) + return NS_ERROR_UNEXPECTED; bool killThread = false; { @@ -225,12 +226,14 @@ nsThreadPool::Dispatch(nsIRunnable *event, uint32_t flags) { LOG(("THRD-P(%p) dispatch [%p %x]\n", this, event, flags)); - NS_ENSURE_STATE(!mShutdown); + if (NS_WARN_IF(mShutdown)) + return NS_ERROR_NOT_AVAILABLE; if (flags & DISPATCH_SYNC) { nsCOMPtr thread; nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread)); - NS_ENSURE_STATE(thread); + if (NS_WARN_IF(!thread)) + return NS_ERROR_NOT_AVAILABLE; nsRefPtr wrapper = new nsThreadSyncDispatch(thread, event); diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index bb59fc98bf10..3aa9e606e24c 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -317,14 +317,16 @@ nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay) { nsresult rv; - NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED); + if (NS_WARN_IF(!gThread)) + return NS_ERROR_NOT_INITIALIZED; if (!mEventTarget) { NS_ERROR("mEventTarget is NULL"); return NS_ERROR_NOT_INITIALIZED; } rv = gThread->Init(); - NS_ENSURE_SUCCESS(rv, rv); + if (NS_WARN_IF(NS_FAILED(rv))) + return rv; /** * In case of re-Init, both with and without a preceding Cancel, clear the @@ -357,7 +359,8 @@ NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc, uint32_t aDelay, uint32_t aType) { - NS_ENSURE_ARG_POINTER(aFunc); + if (NS_WARN_IF(!aFunc)) + return NS_ERROR_INVALID_ARG; ReleaseCallback(); mCallbackType = CALLBACK_TYPE_FUNC; @@ -371,7 +374,8 @@ NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback, uint32_t aDelay, uint32_t aType) { - NS_ENSURE_ARG_POINTER(aCallback); + if (NS_WARN_IF(!aCallback)) + return NS_ERROR_INVALID_ARG; ReleaseCallback(); mCallbackType = CALLBACK_TYPE_INTERFACE; @@ -385,7 +389,8 @@ NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver, uint32_t aDelay, uint32_t aType) { - NS_ENSURE_ARG_POINTER(aObserver); + if (NS_WARN_IF(!aObserver)) + return NS_ERROR_INVALID_ARG; ReleaseCallback(); mCallbackType = CALLBACK_TYPE_OBSERVER; @@ -481,8 +486,8 @@ NS_IMETHODIMP nsTimerImpl::GetTarget(nsIEventTarget** aTarget) NS_IMETHODIMP nsTimerImpl::SetTarget(nsIEventTarget* aTarget) { - NS_ENSURE_TRUE(mCallbackType == CALLBACK_TYPE_UNKNOWN, - NS_ERROR_ALREADY_INITIALIZED); + if (NS_WARN_IF(mCallbackType != CALLBACK_TYPE_UNKNOWN)) + return NS_ERROR_ALREADY_INITIALIZED; if (aTarget) mEventTarget = aTarget; From 5fc06e9d01e6faa3a7b33c7e6156259cb4f47524 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Tue, 19 Nov 2013 16:27:37 -0500 Subject: [PATCH 004/268] Bug 672843 part D - make NS_ERROR_INVALID_POINTER an alias of NS_ERROR_INVALID_ARG, r=froydnj --- accessible/src/windows/msaa/IUnknownImpl.cpp | 2 +- xpcom/base/ErrorList.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/accessible/src/windows/msaa/IUnknownImpl.cpp b/accessible/src/windows/msaa/IUnknownImpl.cpp index f6ae9f6a132c..4a9fa5383b23 100644 --- a/accessible/src/windows/msaa/IUnknownImpl.cpp +++ b/accessible/src/windows/msaa/IUnknownImpl.cpp @@ -23,7 +23,7 @@ GetHRESULT(nsresult aResult) case NS_OK: return S_OK; - case NS_ERROR_INVALID_ARG: case NS_ERROR_INVALID_POINTER: + case NS_ERROR_INVALID_ARG: return E_INVALIDARG; case NS_ERROR_OUT_OF_MEMORY: diff --git a/xpcom/base/ErrorList.h b/xpcom/base/ErrorList.h index 1552bb0e11d6..94cd4893e969 100644 --- a/xpcom/base/ErrorList.h +++ b/xpcom/base/ErrorList.h @@ -16,8 +16,6 @@ /* Returned when a given interface is not supported. */ ERROR(NS_NOINTERFACE, 0x80004002), ERROR(NS_ERROR_NO_INTERFACE, NS_NOINTERFACE), - ERROR(NS_ERROR_INVALID_POINTER, 0x80004003), - ERROR(NS_ERROR_NULL_POINTER, NS_ERROR_INVALID_POINTER), /* Returned when a function aborts */ ERROR(NS_ERROR_ABORT, 0x80004004), /* Returned when a function fails */ @@ -29,6 +27,8 @@ /* Returned when an illegal value is passed */ ERROR(NS_ERROR_ILLEGAL_VALUE, 0x80070057), ERROR(NS_ERROR_INVALID_ARG, NS_ERROR_ILLEGAL_VALUE), + ERROR(NS_ERROR_INVALID_POINTER, NS_ERROR_INVALID_ARG), + ERROR(NS_ERROR_NULL_POINTER, NS_ERROR_INVALID_ARG), /* Returned when a class doesn't allow aggregation */ ERROR(NS_ERROR_NO_AGGREGATION, 0x80040110), /* Returned when an operation can't complete due to an unavailable resource */ From 8213b73fa75e86c3bd915035d6e5858a3fb627f5 Mon Sep 17 00:00:00 2001 From: Nikhil Marathe Date: Tue, 19 Nov 2013 13:29:47 -0800 Subject: [PATCH 005/268] Bug 939906 - Make Promise.resolve(), Promise.reject(), Promise.prototype.then() and Promise.prototype.catch() spec compliant. r=baku --HG-- extra : rebase_source : 7f32dd1222e4ab04f3f0cb4f450b734a4014c805 --- dom/promise/Promise.cpp | 22 ++++--- dom/promise/Promise.h | 10 +-- dom/promise/tests/test_promise.html | 95 +++++++++++++++++++++++++++++ dom/webidl/Promise.webidl | 10 +-- 4 files changed, 117 insertions(+), 20 deletions(-) diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index e715af35748e..4ec10453569d 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -320,7 +320,7 @@ Promise::Constructor(const GlobalObject& aGlobal, /* static */ already_AddRefed Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx, - JS::Handle aValue, ErrorResult& aRv) + const Optional>& aValue, ErrorResult& aRv) { nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); if (!window) { @@ -330,13 +330,14 @@ Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr promise = new Promise(window); - promise->MaybeResolveInternal(aCx, aValue); + promise->MaybeResolveInternal(aCx, + aValue.WasPassed() ? aValue.Value() : JS::UndefinedHandleValue); return promise.forget(); } /* static */ already_AddRefed Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx, - JS::Handle aValue, ErrorResult& aRv) + const Optional>& aValue, ErrorResult& aRv) { nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); if (!window) { @@ -346,27 +347,28 @@ Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx, nsRefPtr promise = new Promise(window); - promise->MaybeRejectInternal(aCx, aValue); + promise->MaybeRejectInternal(aCx, + aValue.WasPassed() ? aValue.Value() : JS::UndefinedHandleValue); return promise.forget(); } already_AddRefed -Promise::Then(const Optional >& aResolveCallback, - const Optional >& aRejectCallback) +Promise::Then(const Optional>& aResolveCallback, + const Optional>& aRejectCallback) { nsRefPtr promise = new Promise(GetParentObject()); nsRefPtr resolveCb = PromiseCallback::Factory(promise, aResolveCallback.WasPassed() - ? &aResolveCallback.Value() + ? aResolveCallback.Value() : nullptr, PromiseCallback::Resolve); nsRefPtr rejectCb = PromiseCallback::Factory(promise, aRejectCallback.WasPassed() - ? &aRejectCallback.Value() + ? aRejectCallback.Value() : nullptr, PromiseCallback::Reject); @@ -376,9 +378,9 @@ Promise::Then(const Optional >& aResolveCallback, } already_AddRefed -Promise::Catch(const Optional >& aRejectCallback) +Promise::Catch(const Optional>& aRejectCallback) { - Optional > resolveCb; + Optional> resolveCb; return Then(resolveCb, aRejectCallback); } diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h index f416e647e6bd..dea5ace85d47 100644 --- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -66,19 +66,19 @@ public: static already_AddRefed Resolve(const GlobalObject& aGlobal, JSContext* aCx, - JS::Handle aValue, ErrorResult& aRv); + const Optional>& aValue, ErrorResult& aRv); static already_AddRefed Reject(const GlobalObject& aGlobal, JSContext* aCx, - JS::Handle aValue, ErrorResult& aRv); + const Optional>& aValue, ErrorResult& aRv); already_AddRefed - Then(const Optional >& aResolveCallback, - const Optional >& aRejectCallback); + Then(const Optional>& aResolveCallback, + const Optional>& aRejectCallback); already_AddRefed - Catch(const Optional >& aRejectCallback); + Catch(const Optional>& aRejectCallback); void AppendNativeHandler(PromiseNativeHandler* aRunnable); diff --git a/dom/promise/tests/test_promise.html b/dom/promise/tests/test_promise.html index 3e5b1f3cad6a..fceaa68cc4d8 100644 --- a/dom/promise/tests/test_promise.html +++ b/dom/promise/tests/test_promise.html @@ -34,6 +34,22 @@ function promiseResolve() { }); } +function promiseResolveNoArg() { + var promise = new Promise(function(resolve, reject) { + ok(resolve, "Promise.resolve exists"); + ok(reject, "Promise.reject exists"); + + resolve(); + }).then(function(what) { + ok(true, "Then - resolveCb has been called"); + is(what, undefined, "ResolveCb received undefined"); + runTest(); + }, function() { + ok(false, "Then - rejectCb has been called"); + runTest(); + }); +} + function promiseReject() { var promise = new Promise(function(resolve, reject) { reject(42); @@ -47,6 +63,19 @@ function promiseReject() { }); } +function promiseRejectNoArg() { + var promise = new Promise(function(resolve, reject) { + reject(); + }).then(function(what) { + ok(false, "Then - resolveCb has been called"); + runTest(); + }, function(what) { + ok(true, "Then - rejectCb has been called"); + is(what, undefined, "RejectCb received undefined"); + runTest(); + }); +} + function promiseException() { var promise = new Promise(function(resolve, reject) { throw 42; @@ -164,6 +193,51 @@ function promiseThenCatchThen() { }); } +function promiseThenNoArg() { + var promise = new Promise(function(resolve, reject) { + resolve(42); + }); + + var clone = promise.then(); + isnot(promise, clone, "These 2 promise objs are different"); + promise.then(function(v) { + clone.then(function(cv) { + is(v, cv, "Both resolve to the same value"); + runTest(); + }); + }); +} + +function promiseThenUndefinedResolveFunction() { + var promise = new Promise(function(resolve, reject) { + reject(42); + }); + + try { + promise.then(undefined, function(v) { + is(v, 42, "Promise rejected with 42"); + runTest(); + }); + } catch (e) { + ok(false, "then should not throw on undefined resolve function"); + } +} + +function promiseThenNullResolveFunction() { + var promise = new Promise(function(resolve, reject) { + reject(42); + }); + + try { + promise.then(null, function(v) { + is(v, 42, "Promise rejected with 42"); + runTest(); + }); + } catch (e) { + ok(false, "then should not throw on null resolve function"); + } +} + function promiseRejectThenCatchThen() { var promise = new Promise(function(resolve, reject) { reject(42); @@ -280,6 +354,21 @@ function promiseThenCatchOrderingReject() { }); } +function promiseCatchNoArg() { + var promise = new Promise(function(resolve, reject) { + reject(42); + }); + + var clone = promise.catch(); + isnot(promise, clone, "These 2 promise objs are different"); + promise.catch(function(v) { + clone.catch(function(cv) { + is(v, cv, "Both reject to the same value"); + runTest(); + }); + }); +} + function promiseNestedPromise() { new Promise(function(resolve, reject) { resolve(new Promise(function(resolve, reject) { @@ -380,6 +469,12 @@ var tests = [ promiseResolve, promiseReject, promiseWrongNestedPromise, promiseLoop, promiseStaticReject, promiseStaticResolve, promiseResolveNestedPromise, + promiseResolveNoArg, + promiseRejectNoArg, + promiseThenNoArg, + promiseThenUndefinedResolveFunction, + promiseThenNullResolveFunction, + promiseCatchNoArg ]; function runTest() { diff --git a/dom/webidl/Promise.webidl b/dom/webidl/Promise.webidl index f2ca4c665eca..99383ac63942 100644 --- a/dom/webidl/Promise.webidl +++ b/dom/webidl/Promise.webidl @@ -23,14 +23,14 @@ interface Promise { // Promise object in this scope without having resolved the interface object // first. [NewObject, Throws, Func="mozilla::dom::Promise::EnabledForScope"] - static Promise resolve(any value); // same as any(value) + static Promise resolve(optional any value); [NewObject, Throws, Func="mozilla::dom::Promise::EnabledForScope"] - static Promise reject(any value); + static Promise reject(optional any value); [NewObject] - Promise then(optional AnyCallback fulfillCallback, - optional AnyCallback rejectCallback); + Promise then(optional AnyCallback? fulfillCallback, + optional AnyCallback? rejectCallback); [NewObject] - Promise catch(optional AnyCallback rejectCallback); + Promise catch(optional AnyCallback? rejectCallback); }; From 6a658de601904acc3e12841644fd3e4d86039fe2 Mon Sep 17 00:00:00 2001 From: Chris Double Date: Tue, 19 Nov 2013 00:48:04 +1300 Subject: [PATCH 006/268] Bug 939655 - Remove LOG macro definition from MediaStreamGraphImpl.h - r=roc Removing this reduces opportunity for macro name clashes and using the wrong log object if this header file is included out of order in a .cpp file. --HG-- rename : browser/themes/linux/Toolbar-inverted.png => browser/themes/windows/Toolbar-inverted.png extra : rebase_source : 053384512e0f3a70d07ebe9ca0a07dc0f39d9b5b --- content/media/MediaStreamGraph.cpp | 11 +++++++++++ content/media/MediaStreamGraphImpl.h | 14 +------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index 7b3c7aa4627d..17a0287c5943 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -32,6 +32,9 @@ namespace mozilla { #ifdef PR_LOGGING PRLogModuleInfo* gMediaStreamGraphLog; +#define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg) +#else +#define LOG(type, msg) #endif /** @@ -39,6 +42,14 @@ PRLogModuleInfo* gMediaStreamGraphLog; */ static MediaStreamGraphImpl* gGraph; +MediaStreamGraphImpl::~MediaStreamGraphImpl() +{ + NS_ASSERTION(IsEmpty(), + "All streams should have been destroyed by messages from the main thread"); + LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p destroyed", this)); +} + + StreamTime MediaStreamGraphImpl::GetDesiredBufferEnd(MediaStream* aStream) { diff --git a/content/media/MediaStreamGraphImpl.h b/content/media/MediaStreamGraphImpl.h index c7d2e8721b21..8027e6feca50 100644 --- a/content/media/MediaStreamGraphImpl.h +++ b/content/media/MediaStreamGraphImpl.h @@ -19,13 +19,6 @@ namespace mozilla { template class LinkedList; -#ifdef PR_LOGGING -extern PRLogModuleInfo* gMediaStreamGraphLog; -#define LOG(type, msg) PR_LOG(gMediaStreamGraphLog, type, msg) -#else -#define LOG(type, msg) -#endif - /** * Assume we can run an iteration of the MediaStreamGraph loop in this much time * or less. @@ -120,12 +113,7 @@ public: * implement OfflineAudioContext. They do not support MediaStream inputs. */ explicit MediaStreamGraphImpl(bool aRealtime); - ~MediaStreamGraphImpl() - { - NS_ASSERTION(IsEmpty(), - "All streams should have been destroyed by messages from the main thread"); - LOG(PR_LOG_DEBUG, ("MediaStreamGraph %p destroyed", this)); - } + ~MediaStreamGraphImpl(); // Main thread only. /** From 9e246ccf6be3bba08bb399d9e95e7122e3fdf456 Mon Sep 17 00:00:00 2001 From: Chris Double Date: Tue, 19 Nov 2013 02:09:47 +1300 Subject: [PATCH 007/268] Bug 939716 - Destructor for MediaStreamGraph should be virtual - r=roc The destructor for MediaStreamGraph is non-virtual but it has a derived class, MediaStreamGraphImpl, that overrides the destructor. This destructor won't be called if an instance is deleted using a pointer type of MediaStreamGraph. It's unclear whether this actually happens but MediaStreamGraph.cpp has code that creates a MediaStreamGraphImpl and returns it as a MediaStreamGraph. --HG-- extra : rebase_source : 9d006e5bf9bb056b5a54fc7aec159c26376c1459 --- content/media/MediaStreamGraph.h | 2 +- content/media/MediaStreamGraphImpl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index cf1e4a5d6f43..7a35db6cb52c 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -1057,7 +1057,7 @@ protected: { MOZ_COUNT_CTOR(MediaStreamGraph); } - ~MediaStreamGraph() + virtual ~MediaStreamGraph() { MOZ_COUNT_DTOR(MediaStreamGraph); } diff --git a/content/media/MediaStreamGraphImpl.h b/content/media/MediaStreamGraphImpl.h index 8027e6feca50..c8cd27a8b1be 100644 --- a/content/media/MediaStreamGraphImpl.h +++ b/content/media/MediaStreamGraphImpl.h @@ -113,7 +113,7 @@ public: * implement OfflineAudioContext. They do not support MediaStream inputs. */ explicit MediaStreamGraphImpl(bool aRealtime); - ~MediaStreamGraphImpl(); + virtual ~MediaStreamGraphImpl(); // Main thread only. /** From cb3eece0fc045a06938d7eefbfcea9e1a3273264 Mon Sep 17 00:00:00 2001 From: Jim Blandy Date: Mon, 18 Nov 2013 13:48:45 -0800 Subject: [PATCH 008/268] Bug 937404 - Remove the unused NotableStringInfo copy constructor. r=jimb --HG-- extra : rebase_source : 9af09cb34a2bda3b1cbee61c85617a25c5876106 --- js/public/MemoryMetrics.h | 7 +++---- js/src/vm/MemoryMetrics.cpp | 16 ++-------------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/js/public/MemoryMetrics.h b/js/public/MemoryMetrics.h index f8782a41df3f..f758f52a96eb 100644 --- a/js/public/MemoryMetrics.h +++ b/js/public/MemoryMetrics.h @@ -272,7 +272,6 @@ struct NotableStringInfo : public StringInfo { NotableStringInfo(); NotableStringInfo(JSString *str, const StringInfo &info); - NotableStringInfo(const NotableStringInfo& info); NotableStringInfo(NotableStringInfo &&info); NotableStringInfo &operator=(NotableStringInfo &&info); @@ -286,10 +285,10 @@ struct NotableStringInfo : public StringInfo return js::MemoryReportingSundriesThreshold(); } - // The amount of memory we requested for |buffer|; i.e. - // buffer = malloc(bufferSize). - size_t bufferSize; char *buffer; + + private: + NotableStringInfo(const NotableStringInfo& info) MOZ_DELETE; }; // These measurements relate directly to the JSRuntime, and not to zones and diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index 8b2301cea0fb..3175beeb9949 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -94,14 +94,13 @@ InefficientNonFlatteningStringHashPolicy::match(const JSString *const &k, const namespace JS { NotableStringInfo::NotableStringInfo() - : bufferSize(0), - buffer(0) + : buffer(0) {} NotableStringInfo::NotableStringInfo(JSString *str, const StringInfo &info) : StringInfo(info) { - bufferSize = Min(str->length() + 1, size_t(4096)); + size_t bufferSize = Min(str->length() + 1, size_t(4096)); buffer = js_pod_malloc(bufferSize); if (!buffer) { MOZ_CRASH("oom"); @@ -123,17 +122,6 @@ NotableStringInfo::NotableStringInfo(JSString *str, const StringInfo &info) PutEscapedString(buffer, bufferSize, chars, str->length(), /* quote */ 0); } -NotableStringInfo::NotableStringInfo(const NotableStringInfo& info) - : StringInfo(info), - bufferSize(info.bufferSize) -{ - buffer = js_pod_malloc(bufferSize); - if (!buffer) - MOZ_CRASH("oom"); - - strcpy(buffer, info.buffer); -} - NotableStringInfo::NotableStringInfo(NotableStringInfo &&info) : StringInfo(Move(info)) { From 103b972b31d8a3a879fc389ce80ca7fb92999a18 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 19 Nov 2013 21:46:47 +0000 Subject: [PATCH 009/268] bug 928026 - use Roboto / Droid Sans Mono for Greek, until Fira glyphs are revised. r=mwu --- modules/libpref/src/init/all.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index a410fdde3a65..e87d35c72a58 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -3407,8 +3407,8 @@ pref("font.alias-list", "sans,sans-serif,serif,monospace"); // ar pref("font.name.serif.el", "Droid Serif"); -pref("font.name.sans-serif.el", "Fira Sans OT"); -pref("font.name.monospace.el", "Fira Mono OT"); +pref("font.name.sans-serif.el", "Roboto"); // To be updated once the Greek letters in Fira are revised +pref("font.name.monospace.el", "Droid Sans Mono"); pref("font.name.serif.he", "Charis SIL Compact"); pref("font.name.sans-serif.he", "Fira Sans OT"); From df54fc7ee2ce3672238cd2263c9fdfd4d7757721 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 19 Nov 2013 16:54:09 -0500 Subject: [PATCH 010/268] Bug 939758 - Build gfx/gl in unified mode - r=ehsan --- gfx/gl/GLLibraryEGL.cpp | 4 ++-- gfx/gl/moz.build | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 8ac22e8c7277..0043bfc81058 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -18,7 +18,7 @@ namespace gl { GLLibraryEGL sEGLLibrary; // should match the order of EGLExtensions, and be null-terminated. -static const char *sExtensionNames[] = { +static const char *sEGLExtensionNames[] = { "EGL_KHR_image_base", "EGL_KHR_image_pixmap", "EGL_KHR_gl_texture_2D_image", @@ -321,7 +321,7 @@ GLLibraryEGL::InitExtensions() const bool firstRun = false; #endif - GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions, sExtensionNames, firstRun && debugMode); + GLContext::InitializeExtensionsBitSet(mAvailableExtensions, extensions, sEGLExtensionNames, firstRun && debugMode); #ifdef DEBUG firstRun = false; diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build index ba3ac861f407..df92abcc4ec9 100644 --- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -59,36 +59,48 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': 'SharedSurfaceANGLE.h', 'WGLLibrary.h', ] - SOURCES += [ + UNIFIED_SOURCES += [ 'GLContextProviderEGL.cpp', 'SharedSurfaceANGLE.cpp', ] if CONFIG['MOZ_ENABLE_SKIA_GPU']: EXPORTS += ['GLContextSkia.h'] - SOURCES += [ + UNIFIED_SOURCES += [ 'GLContextSkia.cpp', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - SOURCES += ['SharedSurfaceGralloc.cpp'] + UNIFIED_SOURCES += ['SharedSurfaceGralloc.cpp'] EXPORTS += ['SharedSurfaceGralloc.h'] if gl_provider == 'CGL': + # This file includes Mac headers that are unfriendly to unified builds, + # and we have only one .mm file here anyway. SOURCES += [ "GLContextProvider%s.mm" % (gl_provider), ] EXPORTS += [ 'SharedSurfaceIO.h', ] + # SharedSurfaceIO.cpp includes MacIOSurface.h which include Mac headers + # which define Size and Point types in root namespace with often conflict with + # our own types. While I haven't actually hit this issue in the present case, + # it's been an issue in gfx/layers so let's not risk it. SOURCES += [ 'SharedSurfaceIO.cpp', ] -else: +elif gl_provider == 'GLX': + # GLContextProviderGLX.cpp needs to be kept out of UNIFIED_SOURCES + # as it includes X11 headers which cause conflicts. SOURCES += [ + 'GLContextProviderGLX.cpp', + ] +else: + UNIFIED_SOURCES += [ 'GLContextProvider%s.cpp' % gl_provider, ] -SOURCES += [ +UNIFIED_SOURCES += [ 'GfxTexturesReporter.cpp', 'GLContext.cpp', 'GLContextFeatures.cpp', From b7f24c712a7f4efdf471ab3a792ff68b0a88a73a Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 19 Nov 2013 16:55:50 -0500 Subject: [PATCH 011/268] Bug 940129 - Build part of widget/gonk in unified mode - r=roc,ehsan --- widget/gonk/HwcComposer2D.cpp | 1 - widget/gonk/moz.build | 29 +++++++++++++++++++++-------- widget/gonk/nativewindow/moz.build | 4 ++-- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp index 13bd5fc88f9c..b00b3c0df8a1 100644 --- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -50,7 +50,6 @@ #define LAYER_COUNT_INCREMENTS 5 -using namespace android; using namespace mozilla::layers; namespace mozilla { diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build index 6cbb987d4aa2..fc0b96ff2ec1 100644 --- a/widget/gonk/moz.build +++ b/widget/gonk/moz.build @@ -21,18 +21,14 @@ EXPORTS += [ DIRS += ['libdisplay', 'nativewindow'] # libui files -SOURCES += ['libui/' + src for src in [ +UNIFIED_SOURCES += ['libui/' + src for src in [ 'EventHub.cpp', 'Input.cpp', 'InputApplication.cpp', 'InputDevice.cpp', - 'InputDispatcher.cpp', 'InputListener.cpp', - 'InputReader.cpp', - 'InputTransport.cpp', 'InputWindow.cpp', 'Keyboard.cpp', - 'KeyCharacterMap.cpp', 'KeyLayoutMap.cpp', 'PointerController.cpp', 'SpriteController.cpp', @@ -42,21 +38,38 @@ SOURCES += ['libui/' + src for src in [ 'VirtualKeyMap.cpp', ]] -SOURCES += [ +# libui files that can't be UNIFIED_SOURCES because they define +# a symbol that's already defined in some above file. +# Could easily unify if it's OK to patch libui. +SOURCES += ['libui/' + src for src in [ + 'InputDispatcher.cpp', # because of toString in EventHub.cpp + 'InputReader.cpp', # because of toString in EventHub.cpp + 'InputTransport.cpp', # because of NANOS_PER_MS in VelocityTracker.cpp + 'KeyCharacterMap.cpp', # because of toString in EventHub.cpp +]] + +UNIFIED_SOURCES += [ 'Framebuffer.cpp', 'GfxInfo.cpp', 'GonkMemoryPressureMonitoring.cpp', 'HwcComposer2D.cpp', 'HwcUtils.cpp', - 'nsAppShell.cpp', 'nsIdleServiceGonk.cpp', 'nsLookAndFeel.cpp', 'nsWidgetFactory.cpp', - 'nsWindow.cpp', 'OrientationObserver.cpp', 'ProcessOrientation.cpp' ] +# These files couldn't be added to UNIFIED_SOURCES for now: +SOURCES += [ + # nsAppShell has a 'using namespace android' that is very unfriendly to UNIFIED_SOURCES. + # Can unify if we're OK to add a lot of android:: in that file. + 'nsAppShell.cpp', + # nsWindow.cpp doesn't build in UNIFIED_SOURCES due to logging macros being redefined. + 'nsWindow.cpp', +] + LIBRARY_NAME = 'widget_gonk' include('/ipc/chromium/chromium-config.mozbuild') diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build index 88695c7349bd..6c27d5ecd7ec 100644 --- a/widget/gonk/nativewindow/moz.build +++ b/widget/gonk/nativewindow/moz.build @@ -34,14 +34,14 @@ elif CONFIG['ANDROID_VERSION'] == '15': if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER']: if CONFIG['ANDROID_VERSION'] in ('17', '18'): - SOURCES += [ + UNIFIED_SOURCES += [ 'GonkBufferQueue.cpp', 'GonkConsumerBase.cpp', 'GonkNativeWindowClientJB.cpp', 'GonkNativeWindowJB.cpp', ] elif CONFIG['ANDROID_VERSION'] == '15': - SOURCES += [ + UNIFIED_SOURCES += [ 'GonkNativeWindowClientICS.cpp', 'GonkNativeWindowICS.cpp', ] From 2c24080b6877361037f103a29ba5cd8c47cb01e2 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 19 Nov 2013 16:56:22 -0500 Subject: [PATCH 012/268] Bug 938368 - Make ANR reporter use the new telemetry ping format; r=blassey --- mobile/android/base/ANRReporter.java | 71 ++++++++++------------------ 1 file changed, 26 insertions(+), 45 deletions(-) diff --git a/mobile/android/base/ANRReporter.java b/mobile/android/base/ANRReporter.java index 8eaf69fa2654..05a87eec5ca1 100644 --- a/mobile/android/base/ANRReporter.java +++ b/mobile/android/base/ANRReporter.java @@ -29,8 +29,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; -import java.security.GeneralSecurityException; -import java.security.MessageDigest; import java.util.UUID; import java.util.regex.Pattern; @@ -48,12 +46,8 @@ public final class ANRReporter extends BroadcastReceiver private static final int TRACES_LINE_SIZE = 100; // Size of block to use when processing traces.txt private static final int TRACES_BLOCK_SIZE = 2000; - // we use us-ascii here because when telemetry calculates checksum - // for the ping file, it lossily converts utf-16 to ascii. therefore, - // we have to treat characters in the traces file as ascii rather than - // say utf-8. otherwise, we will get a wrong checksum - private static final String TRACES_CHARSET = "us-ascii"; - private static final String PING_CHARSET = "us-ascii"; + private static final String TRACES_CHARSET = "utf-8"; + private static final String PING_CHARSET = "utf-8"; private static final ANRReporter sInstance = new ANRReporter(); private static int sRegisteredCount; @@ -266,11 +260,11 @@ public final class ANRReporter extends BroadcastReceiver /* a saved telemetry ping file consists of JSON in the following format, { + "reason": "android-anr-report", "slug": "", - "payload": "", - "checksum": "" + "payload": } - for Android ANR, our unescaped JSON payload should look like, + for Android ANR, our JSON payload should look like, { "ver": 1, "simpleMeasurements": { @@ -287,32 +281,27 @@ public final class ANRReporter extends BroadcastReceiver */ private static int writePingPayload(OutputStream ping, - MessageDigest checksum, String payload) throws IOException { - byte [] data = payload.getBytes(PING_CHARSET); - checksum.update(data); - - data = JSONObject.quote(payload).getBytes(PING_CHARSET); - // first and last bytes are quotes inserted by JSONObject.quote; discard them - ping.write(data, 1, data.length - 2); - return data.length - 2; + ping.write(data); + return data.length; } - private static void fillPingHeader(OutputStream ping, MessageDigest checksum, String slug) + private static void fillPingHeader(OutputStream ping, String slug) throws IOException { // ping file header byte [] data = ("{" + + "\"reason\":\"android-anr-report\"," + "\"slug\":" + JSONObject.quote(slug) + "," + - "\"payload\":\"").getBytes(PING_CHARSET); + "\"payload\":").getBytes(PING_CHARSET); ping.write(data); if (DEBUG) { Log.d(LOGTAG, "wrote ping header, size = " + String.valueOf(data.length)); } // payload start - int size = writePingPayload(ping, checksum, ("{" + + int size = writePingPayload(ping, ("{" + "\"ver\":1," + "\"simpleMeasurements\":{" + "\"uptime\":" + String.valueOf(getUptimeMins()) + @@ -392,9 +381,9 @@ public final class ANRReporter extends BroadcastReceiver return 0; } - // Copy the content of reader to ping and update checksum; + // Copy the content of reader to ping; // copying stops when endPattern is found in the input stream - private static int fillPingBlock(OutputStream ping, MessageDigest checksum, + private static int fillPingBlock(OutputStream ping, Reader reader, String endPattern) throws IOException { @@ -409,7 +398,7 @@ public final class ANRReporter extends BroadcastReceiver stringBlock = stringBlock.substring(0, endIndex); } String quoted = JSONObject.quote(stringBlock); - total += writePingPayload(ping, checksum, quoted.substring(1, quoted.length() - 1)); + total += writePingPayload(ping, quoted.substring(1, quoted.length() - 1)); if (endIndex > 0) { // End pattern already found; return now break; @@ -418,13 +407,13 @@ public final class ANRReporter extends BroadcastReceiver return total; } - private static void fillPingFooter(OutputStream ping, MessageDigest checksum, + private static void fillPingFooter(OutputStream ping, boolean haveNativeStack) throws IOException { // We are at the end of ANR data - int total = writePingPayload(ping, checksum, ("\"," + + int total = writePingPayload(ping, ("\"," + "\"androidLogcat\":\"")); try { @@ -435,7 +424,7 @@ public final class ANRReporter extends BroadcastReceiver .start(); try { Reader procOut = new InputStreamReader(proc.getInputStream(), TRACES_CHARSET); - int size = fillPingBlock(ping, checksum, procOut, null); + int size = fillPingBlock(ping, procOut, null); if (DEBUG) { Log.d(LOGTAG, "wrote logcat, size = " + String.valueOf(size)); } @@ -448,25 +437,20 @@ public final class ANRReporter extends BroadcastReceiver } if (haveNativeStack) { - total += writePingPayload(ping, checksum, ("\"," + - "\"androidNativeStack\":\"")); + total += writePingPayload(ping, ("\"," + + "\"androidNativeStack\":")); String nativeStack = String.valueOf(getNativeStack()); - int size = fillPingBlock(ping, checksum, new StringReader(nativeStack), null); + int size = writePingPayload(ping, nativeStack); if (DEBUG) { Log.d(LOGTAG, "wrote native stack, size = " + String.valueOf(size)); } + total += size + writePingPayload(ping, "}"); + } else { + total += writePingPayload(ping, "\"}"); } - total += writePingPayload(ping, checksum, "\"}"); - - String base64Checksum = Base64.encodeToString(checksum.digest(), Base64.NO_WRAP); - if (DEBUG) { - Log.d(LOGTAG, "checksum: " + base64Checksum); - } byte [] data = ( - "\"," + - "\"checksum\":" + JSONObject.quote(base64Checksum) + "}").getBytes(PING_CHARSET); ping.write(data); if (DEBUG) { @@ -481,8 +465,7 @@ public final class ANRReporter extends BroadcastReceiver OutputStream ping = new BufferedOutputStream( new FileOutputStream(pingFile), TRACES_BLOCK_SIZE); try { - MessageDigest checksum = MessageDigest.getInstance("SHA-256"); - fillPingHeader(ping, checksum, pingFile.getName()); + fillPingHeader(ping, pingFile.getName()); // Traces file has the format // ----- pid xxx at xxx ----- // Cmd line: org.mozilla.xxx @@ -494,11 +477,11 @@ public final class ANRReporter extends BroadcastReceiver // ... // If we end the stack dump at the first end marker, // only Fennec stacks will be dumped - int size = fillPingBlock(ping, checksum, traces, "\n----- end"); + int size = fillPingBlock(ping, traces, "\n----- end"); if (DEBUG) { Log.d(LOGTAG, "wrote traces, size = " + String.valueOf(size)); } - fillPingFooter(ping, checksum, haveNativeStack); + fillPingFooter(ping, haveNativeStack); if (DEBUG) { Log.d(LOGTAG, "finished creating ping file"); } @@ -509,8 +492,6 @@ public final class ANRReporter extends BroadcastReceiver releaseNativeStack(); } } - } catch (GeneralSecurityException e) { - Log.w(LOGTAG, e); } catch (IOException e) { Log.w(LOGTAG, e); } From 004961a8fc31aaaee91360477afd89c236d690ef Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Mon, 18 Nov 2013 13:48:48 -0800 Subject: [PATCH 013/268] Bug 936720 (Part 1) - Add a new mochitest for animated image operators. r=tn --HG-- extra : rebase_source : f3db726b4deffa7304f0cf0123d26bba680bdcfd --- image/test/mochitest/bug900200-ref.png | Bin 0 -> 660 bytes image/test/mochitest/bug900200.png | Bin 0 -> 840 bytes image/test/mochitest/clear.gif | Bin 0 -> 321 bytes image/test/mochitest/clear.png | Bin 0 -> 622 bytes image/test/mochitest/clear2-results.gif | Bin 0 -> 177 bytes image/test/mochitest/clear2.gif | Bin 0 -> 219 bytes image/test/mochitest/green-background.html | 28 ++++ image/test/mochitest/green.png | Bin 0 -> 255 bytes image/test/mochitest/grey.png | Bin 0 -> 256 bytes image/test/mochitest/keep.gif | Bin 0 -> 321 bytes image/test/mochitest/keep.png | Bin 0 -> 622 bytes image/test/mochitest/mochitest.ini | 16 ++ image/test/mochitest/over.png | Bin 0 -> 525 bytes image/test/mochitest/restore-previous.gif | Bin 0 -> 457 bytes image/test/mochitest/restore-previous.png | Bin 0 -> 622 bytes image/test/mochitest/source.png | Bin 0 -> 525 bytes .../mochitest/test_animation_operators.html | 157 ++++++++++++++++++ image/test/reftest/animated/delay-test.html | 2 +- 18 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 image/test/mochitest/bug900200-ref.png create mode 100644 image/test/mochitest/bug900200.png create mode 100644 image/test/mochitest/clear.gif create mode 100644 image/test/mochitest/clear.png create mode 100644 image/test/mochitest/clear2-results.gif create mode 100644 image/test/mochitest/clear2.gif create mode 100644 image/test/mochitest/green-background.html create mode 100644 image/test/mochitest/green.png create mode 100644 image/test/mochitest/grey.png create mode 100644 image/test/mochitest/keep.gif create mode 100644 image/test/mochitest/keep.png create mode 100644 image/test/mochitest/over.png create mode 100644 image/test/mochitest/restore-previous.gif create mode 100644 image/test/mochitest/restore-previous.png create mode 100644 image/test/mochitest/source.png create mode 100644 image/test/mochitest/test_animation_operators.html diff --git a/image/test/mochitest/bug900200-ref.png b/image/test/mochitest/bug900200-ref.png new file mode 100644 index 0000000000000000000000000000000000000000..636013132500247606f272dfaa84e5d66f45fffb GIT binary patch literal 660 zcmV;F0&D$=P)R5d*fr!uo=z}!RV~rtVG^hNq=1g3?k0k!q;92yzNFTZLTgfssi8Zml>|Xj^J#*l=99(XAv3|ZveiV& zAgTGp*@pXV*w$7*)Bp5{#)H&vO`o@`Z>ndCmB#f<$Jf$t&N8vpzK9XBSD7=cn`Xu_ zb{Q;fB|f}*8@vjfxeVoNF{CDCd;y2HpxJ$hme6Hf6ezfv9Q1TtRskxa&q2913^2hv zE-v+?QH+#o0N^u*dHkqnE4?r{!TZ4q)zIR>&{<2cIJ-|9mCkZ%!+;)@4T;VoEW#oz z!Xhjlghg0{RSK5(KMAOZL}x9*3h0NJ$MK-E{Ms;-O~r$uvs_^XF_%Ud2zt#Ac@Kgt zRgDk;a)s+F%?bVnEQNBom`g?UIVh5Lgo_-srObF~30=lTfr6Wrm+PKTwk z`0(nae81h1vY5}M*71A8dpdTQLVa&|4JP8pnN!Xh{7LTT`XF>EgDo$)HWXP%w>8)I z#F1cL4YRyt8;Z1HLv#I?EcS5do_lyd?Hdqa(9%-789x{q6HL|)ZivX-moGdOSAoz uBekp>s~ICJvSpthxU!o;im>y(;Qj&kAj_*L-&R2Y0000O~;A0Q19Vr=PJ{0vA-r9s4i zOo#>$0}L2Je49=y5uoDJo-U3d6}R5r%@sPNz~dTN@%w&ptYfaiL*wc9qfUNQ4NI5F z()5qqJuj;^C3er%T@0t!ZJv2oXN|^!r3H^Sx*7YbNVl0@&X{(KVa-+_<&#buza>gJ zFFU=|$y{vWn%tR-l$YrQ2}YNyyjEDYphI)+l;qD|>Q6NsC6`ul2L`QNS2QJj)n1LI z)3S7YZ!V4E5()Zd)H-EvglO2A27gg)=aWvS;w*AsoupI_@smjhnzyoxF`qWu<{_5LAr_&&cGsW# z8YQOIQSJY#lRReL{!pbK-PpDF&e5P==6_!6r!6vhcWJt3>0PUs$5-Pzp6xlq z8q_!Y(&D{U=I`w?AFTNw{`+3?+S;GZOT3=E)UbBfc_Di>Px@BassfLTS!-lZ^jZGP zT6k+E`)Xgc-A_*JD=fG!$0nJy{TK6h_IJ5$OaIuKdqOyF_uJx1F z?!IYQl$UyQO5hQ;F!>ey;YU9;M-^7w46$5r^;$tdZEnKMHyj&$$^<&pl=)&V$7)P^ z!dewN{bGQ@T*h0IJ=VWEAdu(1WL0gVwvNC-sXwODlO@(9uxdwmZ)BPNGbTxB|Dj1$ zd+Q|LdWvYiIX|KP>C4u)i~>KK>|FFWRyR+||QeKD$hugTe~DWM4f2qs?x literal 0 HcmV?d00001 diff --git a/image/test/mochitest/clear.gif b/image/test/mochitest/clear.gif new file mode 100644 index 0000000000000000000000000000000000000000..7ae79ba86e4e95e9b3aff0f2330dbdecfb3cefef GIT binary patch literal 321 zcmZ?wbhEHbOkqf2SjfcipMe30|AT?zPZmZl21W)Qpcqg#g@J*oxTk;R>9_og=WMyv zz4_jr-~4TlJf=PCT=weJws+jeKlxn$*8BX|x$pn@dAQn-Ec)2tqc#1^vd^5oUdykn z`r36iYx|vb-?{m^k3ZS;v&V1s^*7so^Y)*9{$!I2rkzyNdyC%QXY2F4x0@L+(12O}_G7?_w`7#XYq2Wp{9 literal 0 HcmV?d00001 diff --git a/image/test/mochitest/clear.png b/image/test/mochitest/clear.png new file mode 100644 index 0000000000000000000000000000000000000000..b09aecaaa031c1be3239a2ca634f5b0a57f295e8 GIT binary patch literal 622 zcmeAS@N?(olHy`uVBq!ia0vp^DImO~;A0Q24GwyuV6$YfG(ja0$ zCPV{>0R}0|FBll6AM95K@;D1TB8wRqxP?KOkzv*x37{Z*iKnkC`&~96Av3w^sUmNI zLi0Rb978H@y}e+_2(*rQLFWH+Q3ubnD+SCfxWbika+0d|G#%DW5C&5ugwd!2W-N7> z24(~)0M!6RG$()*M{W{10oD~sx%OY%I^!9St2A%o0lF0CZ=gFd{msZAx-w)NP-anD ziem_nW`3W4qKt9NC5CD$LqqCzv z0J#ECKe2FJPfqx89_TqHMux1Pd5?f{!X>T|CBgY=CFO}lsSI9;1$pTTMTUl!>Mu4Y Pf=u#s^>bP0l+XkKORT{V literal 0 HcmV?d00001 diff --git a/image/test/mochitest/clear2-results.gif b/image/test/mochitest/clear2-results.gif new file mode 100644 index 0000000000000000000000000000000000000000..965b65025334e4b55e8c95cf3bff18a4b23f15f1 GIT binary patch literal 177 zcmV;i08al$Nk%w1VPpVH0Du7i0RI60|NkNR1OW;F0RSuj0001F080P>0*H){smtvT zqnxzbi?iOm`wxcVNS5Y_rs~SJ?hD8AOxN~}=lag~{tpZahs2`sh)gP%%%<}RjY_A~ zs`ZM^YPZ}7;0q3mv*L1?Y&N6QV=TM8et+X~`rFRNr}b*L9Lxvj_XiNzc11Wh_-A;w fSoe4rnK!vt+1Hh+xyjk-`3V{-I!anvQ2+otwc}UV literal 0 HcmV?d00001 diff --git a/image/test/mochitest/clear2.gif b/image/test/mochitest/clear2.gif new file mode 100644 index 0000000000000000000000000000000000000000..00ad873c65d75052b02a316d7fb4a26e1a922449 GIT binary patch literal 219 zcmZ?wbhEHbOkwb5SjfcipMe30|AT?zPZmx_AYTWF89?$3ObI>xD^I`WUp!~at?teD z_Wb5=d*m_gS?97>r?$Q0KK{w)`nTTazs`OC$Irvneq_ + + +Background color wrapper for clear image tests + + + + + + + diff --git a/image/test/mochitest/green.png b/image/test/mochitest/green.png new file mode 100644 index 0000000000000000000000000000000000000000..7df25f33bdb26cc7f41138501ab399059839137d GIT binary patch literal 255 zcmeAS@N?(olHy`uVBq!ia0vp^DImFdgVmrY2>Os;yW$XlS$JWm(LkcwMxFBmd1FmNz0$ozjU>fm{HrGS|QSGZD6PEz%r zro*}k!eEMoFdB8hjHM3Kz>FXTpcFdgVmrY1SREIOoZy!)-zNd?0NX4zU7YrF07&w>}w*FWZeegWH(gn}1*?|h)({v&? zrD#r21v5lWOae2wQci*yteYSVCZHOSNFzw`$w^Bcz`9NbQLO#icGj$gOs=ig4y8b+ OGI+ZBxvX9_og=WMyv zz4_jr-~4TlJf=PCT=weJws+jeKlxn$*8BX|x$pn@dAQn-Ec)2tqc#1^vd^5oUdykn z`r36iYx|vb-?{m^k3ZS;v&V1s^*7so^Y)*9{$!I2rkzyNUv1ByF(2FxAM@L&W63 literal 0 HcmV?d00001 diff --git a/image/test/mochitest/keep.png b/image/test/mochitest/keep.png new file mode 100644 index 0000000000000000000000000000000000000000..aa3ff7445025fb6c91ad9df2e1f43a005c459126 GIT binary patch literal 622 zcmeAS@N?(olHy`uVBq!ia0vp^DImO~;A0Q24GwyuV6$YfG(ja0$ zCPV{>0R}0|FBll6AM95K@;D1TB8wRqxP?KOkzv*x37{Z*iKnkC`&~96Av4Xx8XF%0 zh30v>IEGZ*dV9f;5ojH=!q)odkq6JSD_ziB=hmnbxhdu3q@@niz>FXTZ!kl1f-0CH za$*vg!39(UVz7b~0~t(UU8>%cYrikn6~}ly>(}<}K$pV&4Rj|qfAefg{SK5_l$PQc z0;HJ`ep-zopr05<-_4FCWD literal 0 HcmV?d00001 diff --git a/image/test/mochitest/mochitest.ini b/image/test/mochitest/mochitest.ini index 5846156b79d3..9d443106aba5 100644 --- a/image/test/mochitest/mochitest.ini +++ b/image/test/mochitest/mochitest.ini @@ -28,16 +28,31 @@ support-files = bug767779.sjs bug89419-iframe.html bug89419.sjs + bug900200.png + bug900200-ref.png + clear.gif + clear.png + clear2.gif + clear2-results.gif damon.jpg error-early.png + green.png + green-background.html + grey.png imgutils.js invalid.jpg + keep.gif + keep.png lime100x100.svg red.png + restore-previous.gif + restore-previous.png rillybad.jpg schrep.png shaver.png short_header.gif + source.png + over.png [test_ImageContentLoaded.html] [test_bug399925.html] @@ -63,6 +78,7 @@ support-files = [test_bug865919.html] [test_bug89419-1.html] [test_bug89419-2.html] +[test_animation_operators.html] [test_drawDiscardedImage.html] [test_error_events.html] [test_short_gif_header.html] diff --git a/image/test/mochitest/over.png b/image/test/mochitest/over.png new file mode 100644 index 0000000000000000000000000000000000000000..9e957182f7e7cf45c3b903d1a2bde8d478087627 GIT binary patch literal 525 zcmeAS@N?(olHy`uVBq!ia0vp^DIm|M+3}G2z$bP-AP+sYYTPU>;XC!<|RfT8yp5;?|=x9ml&(J zh9&~pE7DRNL4m>q@|L3@&|8N$Si1k(aImoQio@h>i>;5cAbiD`#3I1RsH6b1o7QXv zc%bgv&hMeTv&hHhKhUkhC9V-A!TD(=<%vb93|@%^dFcv8hK82vFE)d`#Ng@b=d#Wz Gp$Pyh!)g2g literal 0 HcmV?d00001 diff --git a/image/test/mochitest/restore-previous.gif b/image/test/mochitest/restore-previous.gif new file mode 100644 index 0000000000000000000000000000000000000000..15ba9ddc48dfd6e54699763553f2bdb3b096da7a GIT binary patch literal 457 zcmZ?wbhEHbOkqf2SjfcipMe30|AT?zPZmZl21W)Qpcqg#g@J*oxTk;R>9_og=WMyv zz4_jr-~4TlJf=PCT=weJws+jeKlxn$*8BX|x$pn@dAQn-Ec)2tqc#1^vd^5oUdykn z`r36iYx|vb-?{m^k3ZS;v&V1s^*7so^Y)*9{$!I2rkzyNUv!(ea+FM4>i40L!f0wailiOGeL!5RSQi|c>@ literal 0 HcmV?d00001 diff --git a/image/test/mochitest/restore-previous.png b/image/test/mochitest/restore-previous.png new file mode 100644 index 0000000000000000000000000000000000000000..09dee638208922cc7ca66ba27b7e31d98f46882d GIT binary patch literal 622 zcmeAS@N?(olHy`uVBq!ia0vp^DImO~;A0Q24GwyuV6$YfG(ja0$ zCPV{>0R}0|FBll6AM95K@;D1TB8wRqxP?KOkzv*x37{Z*iKnkC`&~96Av3w^sUmNI zLi0Rb978H@y}e+_2(*rQLFWH+Q3ubnD+SCfxWbika+0d|G#%DW5C&5ugwd!2W-N7> z24(~)0M!6RG$()*M{W{10oD~sx%OY%I^!9St2A%o0lF0CZ=gFd{msN+*TP;3lv$LP z;ur#?nGk+b*joQQ66B`~n(N%?=5|~mcVDb4j`8>;ojpZJegelYkPq@31c2l6=ln literal 0 HcmV?d00001 diff --git a/image/test/mochitest/source.png b/image/test/mochitest/source.png new file mode 100644 index 0000000000000000000000000000000000000000..df1c76dae5d2ecbaa3405d5f3b648ef9c155936c GIT binary patch literal 525 zcmeAS@N?(olHy`uVBq!ia0vp^DIm|M+3}G2z$bP-AP+sYYTPU>;XC!<|RfT8yp5;?|=xfmv}a% zeh0Ewq@_550)+|WEk{A1w+?TxbpN&CU}5DIhsoO(TOVaX_=+)!MSzh}Ndaazt=S6j zK;5^U-$Qw4k&n%Ppj(AYTq8 + + + + Test for Bug 936720 + + + + + +Mozilla Bug 936720 +
+
+
+ + diff --git a/image/test/reftest/animated/delay-test.html b/image/test/reftest/animated/delay-test.html index f2ed5279e1b3..7372a6bc2435 100644 --- a/image/test/reftest/animated/delay-test.html +++ b/image/test/reftest/animated/delay-test.html @@ -38,7 +38,7 @@ function forceDecode() { } function startTimer() { - const delay = 1000; + const delay = 10000; setTimeout("document.documentElement.className = '';", delay); } From 043317ae8a7bf07f7de68bffd03565431ac85427 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Tue, 19 Nov 2013 15:14:30 -0700 Subject: [PATCH 014/268] Bug 938124 - Add mprotect mechanism indicating which GC heap accesses made during Ion compilation are threadsafe, r=jandem. --- js/src/builtin/Eval.cpp | 6 + js/src/builtin/Eval.h | 5 + js/src/gc/Barrier.h | 3 + js/src/gc/Heap.h | 42 +++- js/src/jit/BaselineFrame.h | 4 +- js/src/jit/BaselineInspector.h | 4 +- js/src/jit/BytecodeAnalysis.cpp | 20 +- js/src/jit/BytecodeAnalysis.h | 8 +- js/src/jit/CodeGenerator.cpp | 13 +- js/src/jit/CompileInfo.h | 18 +- js/src/jit/Ion.cpp | 22 +- js/src/jit/Ion.h | 6 + js/src/jit/IonBuilder.cpp | 219 ++++++++++---------- js/src/jit/IonCode.h | 1 + js/src/jit/IonMacroAssembler.cpp | 18 +- js/src/jit/MCallOptimize.cpp | 17 +- js/src/jit/MIR.cpp | 10 +- js/src/jit/MIR.h | 27 ++- js/src/jit/MIRGraph.h | 2 +- js/src/jit/ParallelFunctions.cpp | 6 +- js/src/jit/Snapshots.cpp | 10 +- js/src/jit/shared/CodeGenerator-shared.cpp | 1 + js/src/jsanalyze.h | 2 +- js/src/jsapi-tests/testConservativeGC.cpp | 1 - js/src/jsapi.h | 4 +- js/src/jsarray.cpp | 4 +- js/src/jsatominlines.h | 1 + js/src/jsbool.cpp | 2 +- js/src/jscntxt.cpp | 4 +- js/src/jscntxt.h | 2 +- js/src/jscompartmentinlines.h | 2 +- js/src/jsfun.h | 60 ++++-- js/src/jsinfer.cpp | 34 ++- js/src/jsinfer.h | 35 +++- js/src/jsinferinlines.h | 23 ++- js/src/jsobj.cpp | 2 + js/src/jsobj.h | 19 +- js/src/jsopcode.cpp | 5 +- js/src/jsopcodeinlines.h | 8 +- js/src/jsscript.cpp | 16 +- js/src/jsscript.h | 228 +++++++++++++++++++-- js/src/jsscriptinlines.h | 5 +- js/src/jsstr.cpp | 11 +- js/src/jsstr.h | 16 +- js/src/shell/js.cpp | 14 +- js/src/vm/GlobalObject.h | 44 +++- js/src/vm/ObjectImpl.cpp | 19 ++ js/src/vm/ObjectImpl.h | 42 +++- js/src/vm/RegExpObject.h | 8 +- js/src/vm/Runtime-inl.h | 7 +- js/src/vm/Runtime.cpp | 75 +++++++ js/src/vm/Runtime.h | 31 +++ js/src/vm/ScopeObject-inl.h | 9 +- js/src/vm/ScopeObject.cpp | 4 +- js/src/vm/ScopeObject.h | 25 ++- js/src/vm/Shape.cpp | 2 +- js/src/vm/Shape.h | 66 +++++- js/src/vm/String.h | 2 + js/src/vm/TypedArrayObject.h | 4 + 59 files changed, 959 insertions(+), 339 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 4923281c6720..8d2cdb7539e5 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -431,6 +431,12 @@ js::IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v) return scopeChain->global().getOriginalEval() == v; } +bool +js::IsBuiltinEvalForScope(GlobalObject *global, const Value &v) +{ + return global->getOriginalEval() == v; +} + bool js::IsAnyBuiltinEval(JSFunction *fun) { diff --git a/js/src/builtin/Eval.h b/js/src/builtin/Eval.h index 1d15b00c04b5..6016d86270ed 100644 --- a/js/src/builtin/Eval.h +++ b/js/src/builtin/Eval.h @@ -38,6 +38,11 @@ DirectEvalFromIon(JSContext *cx, extern bool IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v); +class GlobalObject; + +extern bool +IsBuiltinEvalForScope(GlobalObject *global, const Value &v); + // True iff fun is a built-in eval function. extern bool IsAnyBuiltinEval(JSFunction *fun); diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index dfbfc52ed8f6..6f9d927668b1 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -159,6 +159,9 @@ class BarrieredCell : public gc::Cell static JS_ALWAYS_INLINE void readBarrier(T *thing) { #ifdef JSGC_INCREMENTAL + // Off thread Ion compilation never occurs when barriers are active. + AutoUnprotectCell unprotect(thing); + JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread(); if (shadowZone->needsBarrier()) { MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone)); diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index 8ec61d7cba08..a398bd37aae6 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -993,12 +993,6 @@ Cell::shadowRuntimeFromAnyThread() const return reinterpret_cast(runtimeFromAnyThread()); } -AllocKind -Cell::tenuredGetAllocKind() const -{ - return arenaHeader()->getAllocKind(); -} - bool Cell::isMarked(uint32_t color /* = BLACK */) const { @@ -1114,6 +1108,42 @@ InFreeList(ArenaHeader *aheader, void *thing) } } /* namespace gc */ + +// Ion compilation mainly occurs off the main thread, and may run while the +// main thread is performing arbitrary VM operations, excepting GC activity. +// The below class is used to mark functions and other operations which can +// safely be performed off thread without racing. When running with thread +// safety checking on, any access to a GC thing outside of an AutoUnprotectCell +// will cause an access violation. +class AutoUnprotectCell +{ +public: +#if defined(DEBUG) && !defined(XP_WIN) + JSRuntime *runtime; + gc::ArenaHeader *arena; + + AutoUnprotectCell(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoUnprotectCell(); +#else + AutoUnprotectCell(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + ~AutoUnprotectCell() {} +#endif + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +typedef AutoUnprotectCell AutoUnprotectCellUnderCompilationLock; +typedef AutoUnprotectCell AutoUnprotectCellForWrite; + +gc::AllocKind +gc::Cell::tenuredGetAllocKind() const +{ + AutoUnprotectCell unprotect(this); + return arenaHeader()->getAllocKind(); +} + } /* namespace js */ #endif /* gc_Heap_h */ diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index 6602991c3bb7..b32bd098e3bb 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -152,7 +152,7 @@ class BaselineFrame Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i)); - JS_ASSERT(i < script()->nfixed); + JS_ASSERT(i < script()->getNfixed()); return *valueSlot(i); } @@ -183,7 +183,7 @@ class BaselineFrame offsetOfNumActualArgs()); } unsigned numFormalArgs() const { - return script()->function()->nargs; + return script()->function()->getNargs(); } Value &thisValue() const { return *(Value *)(reinterpret_cast(this) + diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index e488d5217334..dfc506bd0584 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -67,14 +67,14 @@ class BaselineInspector private: #ifdef DEBUG bool isValidPC(jsbytecode *pc) { - return (pc >= script->code) && (pc < script->code + script->length); + return (pc >= script->getCode()) && (pc < script->getCode() + script->getLength()); } #endif ICEntry &icEntryFromPC(jsbytecode *pc) { JS_ASSERT(hasBaselineScript()); JS_ASSERT(isValidPC(pc)); - ICEntry &ent = baselineScript()->icEntryFromPCOffset(pc - script->code, prevLookedUpEntry); + ICEntry &ent = baselineScript()->icEntryFromPCOffset(pc - script->getCode(), prevLookedUpEntry); JS_ASSERT(ent.isForOp()); prevLookedUpEntry = &ent; return ent; diff --git a/js/src/jit/BytecodeAnalysis.cpp b/js/src/jit/BytecodeAnalysis.cpp index e2295c9fb639..f9724bc7d189 100644 --- a/js/src/jit/BytecodeAnalysis.cpp +++ b/js/src/jit/BytecodeAnalysis.cpp @@ -42,10 +42,10 @@ struct CatchFinallyRange bool BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) { - if (!infos_.growByUninitialized(script_->length)) + if (!infos_.growByUninitialized(script_->getLength())) return false; - jsbytecode *end = script_->code + script_->length; + jsbytecode *end = script_->getCode() + script_->getLength(); // Clear all BytecodeInfo. mozilla::PodZero(infos_.begin(), infos_.length()); @@ -53,12 +53,12 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) Vector catchFinallyRanges(alloc); - for (jsbytecode *pc = script_->code; pc < end; pc += GetBytecodeLength(pc)) { + for (jsbytecode *pc = script_->getCode(); pc < end; pc += GetBytecodeLength(pc)) { JSOp op = JSOp(*pc); - unsigned offset = pc - script_->code; + unsigned offset = pc - script_->getCode(); IonSpew(IonSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s", - int(pc - script_->code), int(end - script_->code), js_CodeName[op]); + int(pc - script_->getCode()), int(end - script_->getCode()), js_CodeName[op]); // If this bytecode info has not yet been initialized, it's not reachable. if (!infos_[offset].initialized) @@ -68,7 +68,7 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) unsigned stackDepth = infos_[offset].stackDepth; #ifdef DEBUG for (jsbytecode *chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++) - JS_ASSERT(!infos_[chkpc - script_->code].initialized); + JS_ASSERT(!infos_[chkpc - script_->getCode()].initialized); #endif unsigned nuses = GetUseCount(script_, offset); @@ -108,7 +108,7 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) JSTryNote *tn = script_->trynotes()->vector; JSTryNote *tnlimit = tn + script_->trynotes()->length; for (; tn < tnlimit; tn++) { - unsigned startOffset = script_->mainOffset + tn->start; + unsigned startOffset = script_->getMainOffset() + tn->start; if (startOffset == offset + 1) { unsigned catchOffset = startOffset + tn->length; @@ -134,7 +134,7 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset) catchFinallyRanges.popBack(); - CatchFinallyRange range(endOfTry - script_->code, afterTry - script_->code); + CatchFinallyRange range(endOfTry - script_->getCode(), afterTry - script_->getCode()); if (!catchFinallyRanges.append(range)) return false; break; @@ -191,14 +191,14 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) infos_[targetOffset].jumpTarget = true; if (jumpBack) - pc = script_->code + targetOffset; + pc = script_->getCode() + targetOffset; } // Handle any fallthrough from this opcode. if (BytecodeFallsThrough(op)) { jsbytecode *nextpc = pc + GetBytecodeLength(pc); JS_ASSERT(nextpc < end); - unsigned nextOffset = nextpc - script_->code; + unsigned nextOffset = nextpc - script_->getCode(); infos_[nextOffset].init(stackDepth); diff --git a/js/src/jit/BytecodeAnalysis.h b/js/src/jit/BytecodeAnalysis.h index 30b3663ac580..44c836551042 100644 --- a/js/src/jit/BytecodeAnalysis.h +++ b/js/src/jit/BytecodeAnalysis.h @@ -50,13 +50,13 @@ class BytecodeAnalysis bool init(TempAllocator &alloc, GSNCache &gsn); BytecodeInfo &info(jsbytecode *pc) { - JS_ASSERT(infos_[pc - script_->code].initialized); - return infos_[pc - script_->code]; + JS_ASSERT(infos_[pc - script_->getCode()].initialized); + return infos_[pc - script_->getCode()]; } BytecodeInfo *maybeInfo(jsbytecode *pc) { - if (infos_[pc - script_->code].initialized) - return &infos_[pc - script_->code]; + if (infos_[pc - script_->getCode()].initialized) + return &infos_[pc - script_->getCode()]; return nullptr; } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 4d7c0ef37f6f..7d3689111752 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -822,7 +822,7 @@ CodeGenerator::emitLambdaInit(const Register &output, const Register &scopeChain } s; uint32_t word; } u; - u.s.nargs = info.fun->nargs; + u.s.nargs = info.nargs; u.s.flags = info.flags & ~JSFunction::EXTENDED; JS_STATIC_ASSERT(offsetof(JSFunction, flags) == offsetof(JSFunction, nargs) + 2); @@ -2036,7 +2036,7 @@ CodeGenerator::visitCallKnown(LCallKnown *call) // Native single targets are handled by LCallNative. JS_ASSERT(!target->isNative()); // Missing arguments must have been explicitly appended by the IonBuilder. - JS_ASSERT(target->nargs <= call->numStackArgs()); + JS_ASSERT(target->getNargs() <= call->numStackArgs()); JS_ASSERT_IF(call->mir()->isConstructing(), target->isInterpretedConstructor()); @@ -2280,7 +2280,7 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply) masm.cmp32(argcreg, copyreg); masm.j(Assembler::Below, &underflow); } else { - masm.cmp32(argcreg, Imm32(apply->getSingleTarget()->nargs)); + masm.cmp32(argcreg, Imm32(apply->getSingleTarget()->getNargs())); masm.j(Assembler::Below, &underflow); } @@ -3249,6 +3249,7 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir) Register obj = ToRegister(lir->output()); JSObject *templateObj = lir->mir()->templateObject(); + AutoUnprotectCell unprotect(templateObj); // If we have a template object, we can inline call object creation. OutOfLineCode *ool; @@ -5743,7 +5744,7 @@ CodeGenerator::generate() { IonSpew(IonSpew_Codegen, "# Emitting code for script %s:%d", gen->info().script()->filename(), - gen->info().script()->lineno); + gen->info().script()->getLineno()); if (!safepoints_.init(gen->alloc(), graph.totalSlotCount())) return false; @@ -6549,7 +6550,7 @@ CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir) pushArg(ImmGCPtr(lir->mir()->name())); pushArg(ToValue(lir, LCallDeleteProperty::Value)); - if (lir->mir()->block()->info().script()->strict) + if (lir->mir()->block()->info().script()->getStrict()) return callVM(DeletePropertyStrictInfo, lir); return callVM(DeletePropertyNonStrictInfo, lir); @@ -6567,7 +6568,7 @@ CodeGenerator::visitCallDeleteElement(LCallDeleteElement *lir) pushArg(ToValue(lir, LCallDeleteElement::Index)); pushArg(ToValue(lir, LCallDeleteElement::Value)); - if (lir->mir()->block()->info().script()->strict) + if (lir->mir()->block()->info().script()->getStrict()) return callVM(DeleteElementStrictInfo, lir); return callVM(DeleteElementNonStrictInfo, lir); diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index 2c190a4dfb26..6bfd4ab20f5e 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -15,7 +15,7 @@ namespace js { namespace jit { inline unsigned -StartArgSlot(JSScript *script, JSFunction *fun) +StartArgSlot(JSScript *script) { // Reserved slots: // Slot 0: Scope chain. @@ -37,7 +37,7 @@ CountArgSlots(JSScript *script, JSFunction *fun) // Slot x + n: Argument n. // Note: when updating this, please also update the assert in SnapshotWriter::startFrame - return StartArgSlot(script, fun) + (fun ? fun->nargs + 1 : 0); + return StartArgSlot(script) + (fun ? fun->getNargs() + 1 : 0); } // Contains information about the compilation source for IR being generated. @@ -58,11 +58,11 @@ class CompileInfo JS_ASSERT(fun_->isTenured()); } - nimplicit_ = StartArgSlot(script, fun) /* scope chain and argument obj */ + nimplicit_ = StartArgSlot(script) /* scope chain and argument obj */ + (fun ? 1 : 0); /* this */ - nargs_ = fun ? fun->nargs : 0; - nlocals_ = script->nfixed; - nstack_ = script->nslots - script->nfixed; + nargs_ = fun ? fun->getNargs() : 0; + nlocals_ = script->getNfixed(); + nstack_ = script->getNslots() - script->getNfixed(); nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; } @@ -96,10 +96,10 @@ class CompileInfo } jsbytecode *startPC() const { - return script_->code; + return script_->getCode(); } jsbytecode *limitPC() const { - return script_->code + script_->length; + return script_->getCode() + script_->getLength(); } const char *filename() const { @@ -209,7 +209,7 @@ class CompileInfo uint32_t startArgSlot() const { JS_ASSERT(script()); - return StartArgSlot(script(), fun()); + return StartArgSlot(script()); } uint32_t endArgSlot() const { JS_ASSERT(script()); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index e337353c68fe..27785ed53237 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -46,6 +46,8 @@ #include "jsinferinlines.h" #include "jsobjinlines.h" +using mozilla::Maybe; + using namespace js; using namespace js::jit; @@ -1275,7 +1277,7 @@ OptimizeMIR(MIRGenerator *mir) // repeated bailouts. Disable it if this script is known to bailout // frequently. JSScript *script = mir->info().script(); - if (!script || !script->hadFrequentBailouts) { + if (!script || !script->getHadFrequentBailouts()) { LICM licm(mir, graph); if (!licm.analyze()) return false; @@ -1552,9 +1554,9 @@ OffThreadCompilationAvailable(JSContext *cx) // CodeGenerator::maybeCreateScriptCounts will not attach script profiles // when running off thread. // - // Also skip off thread compilation if the SPS profiler is enabled, as it - // stores strings in the spsProfiler data structure, which is not protected - // by a lock. + // Skip off thread compilation if the SPS profiler is enabled, as it stores + // strings in the spsProfiler data structure, which is not protected by a + // lock. return OffThreadIonCompilationEnabled(cx->runtime()) && cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL && !cx->runtime()->profilingScripts @@ -1657,6 +1659,15 @@ IonCompile(JSContext *cx, JSScript *script, RootedScript builderScript(cx, builder->script()); IonSpewNewFunction(graph, builderScript); + Maybe protect; + if (js_IonOptions.checkThreadSafety && + cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL && + !cx->runtime()->profilingScripts && + !cx->runtime()->spsProfiler.enabled()) + { + protect.construct(cx->runtime()); + } + bool succeeded = builder->build(); builder->clearForBackEnd(); @@ -1692,6 +1703,9 @@ IonCompile(JSContext *cx, JSScript *script, return AbortReason_Disable; } + if (!protect.empty()) + protect.destroy(); + bool success = codegen->link(cx, builder->constraints()); IonSpewEndFunction(); diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 3ccb0a856ecf..987e911a894a 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -83,6 +83,12 @@ struct IonOptions // Default: false bool checkRangeAnalysis; + // Whether to protect the GC heap during Ion compilation and ensure that + // only threadsafe operations are performed on it. + // + // Default: false + bool checkThreadSafety; + // Whether to perform expensive graph-consistency DEBUG-only assertions. // It can be useful to disable this to reduce DEBUG-compile time of large // asm.js programs. diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 3f59b68a839a..1559a0a6cfa3 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -65,8 +65,8 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, Tem inspector(inspector), inliningDepth_(inliningDepth), numLoopRestarts_(0), - failedBoundsCheck_(info->script()->failedBoundsCheck), - failedShapeGuard_(info->script()->failedShapeGuard), + failedBoundsCheck_(info->script()->getFailedBoundsCheck()), + failedShapeGuard_(info->script()->getFailedShapeGuard()), nonStringIteration_(false), lazyArguments_(nullptr), inlineCallInfo_(nullptr) @@ -218,12 +218,12 @@ IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constr } else { types::TypeObject *typeObj = calleeTypes->getTypeObject(i); JS_ASSERT(typeObj); - if (!typeObj->interpretedFunction) { + if (!typeObj->getInterpretedFunction()) { targets.clear(); return true; } - fun = typeObj->interpretedFunction; + fun = typeObj->getInterpretedFunction(); *gotLambda = true; } @@ -254,16 +254,13 @@ IonBuilder::canEnterInlinedFunction(JSFunction *target) JSScript *targetScript = target->nonLazyScript(); - if (targetScript->uninlineable) - return false; - - if (!targetScript->analyzedArgsUsage()) + if (targetScript->getUninlineable()) return false; if (targetScript->needsArgsObj()) return false; - if (!targetScript->compileAndGo) + if (!targetScript->getCompileAndGo()) return false; types::TypeObjectKey *targetType = types::TypeObjectKey::get(target); @@ -281,11 +278,6 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) return false; } - if (target->getParent() != &script()->global()) { - IonSpew(IonSpew_Inlining, "Cannot inline due to scope mismatch"); - return false; - } - // Allow constructing lazy scripts when performing the definite properties // analysis, as baseline has not been used to warm the caller up yet. if (target->isInterpreted() && info().executionMode() == DefinitePropertiesAnalysis) { @@ -311,29 +303,28 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) } JSScript *inlineScript = target->nonLazyScript(); + + IonSpew(IonSpew_Inlining, "Trying to inline %s:%d", inlineScript->filename(), inlineScript->getLineno()); + ExecutionMode executionMode = info().executionMode(); if (!CanIonCompile(inlineScript, executionMode)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to disable Ion compilation", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to disable Ion compilation"); return false; } // Don't inline functions which don't have baseline scripts. if (!inlineScript->hasBaselineScript()) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline target with no baseline jitcode", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline target with no baseline jitcode"); return false; } - if (TooManyArguments(target->nargs)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline too many args", - inlineScript->filename(), inlineScript->lineno); + if (TooManyArguments(target->getNargs())) { + IonSpew(IonSpew_Inlining, "Cannot inline too many args"); return false; } if (TooManyArguments(callInfo.argc())) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline too many args", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline too many args"); return false; } @@ -341,17 +332,14 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) IonBuilder *builder = callerBuilder_; while (builder) { if (builder->script() == inlineScript) { - IonSpew(IonSpew_Inlining, "%s:%d Not inlining recursive call", - inlineScript->filename(), inlineScript->lineno); + IonSpew(IonSpew_Inlining, "Not inlining recursive call"); return false; } builder = builder->callerBuilder_; } if (!canEnterInlinedFunction(target)) { - IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to oracle veto %d", - inlineScript->filename(), inlineScript->lineno, - script()->lineno); + IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d"); return false; } @@ -565,7 +553,8 @@ IonBuilder::build() return false; IonSpew(IonSpew_Scripts, "Analyzing script %s:%d (%p) (usecount=%d)", - script()->filename(), script()->lineno, (void *)script(), (int)script()->getUseCount()); + script()->filename(), script()->getLineno(), + (void *)script(), (int)script()->getUseCount()); if (!initParameters()) return false; @@ -707,7 +696,7 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi inlineCallInfo_ = &callInfo; IonSpew(IonSpew_Scripts, "Inlining script %s:%d (%p)", - script()->filename(), script()->lineno, (void *)script()); + script()->filename(), script()->getLineno(), (void *)script()); callerBuilder_ = callerBuilder; callerResumePoint_ = callerResumePoint; @@ -905,7 +894,7 @@ IonBuilder::initScopeChain(MDefinition *callee) // will try to access the scope. For other scripts, the scope instructions // will be held live by resume points and code will still be generated for // them, so just use a constant undefined value. - if (!script()->compileAndGo) + if (!script()->getCompileAndGo()) return abort("non-CNG global scripts are not supported"); if (JSFunction *fun = info().fun()) { @@ -941,8 +930,7 @@ IonBuilder::initScopeChain(MDefinition *callee) bool IonBuilder::initArgumentsObject() { - IonSpew(IonSpew_MIR, "%s:%d - Emitting code to initialize arguments object! block=%p", - script()->filename(), script()->lineno, current); + IonSpew(IonSpew_MIR, "Emitting code to initialize arguments object! block=%p", current); JS_ASSERT(info().needsArgsObj()); MCreateArgumentsObject *argsObj = MCreateArgumentsObject::New(alloc(), current->scopeChain()); current->add(argsObj); @@ -1187,7 +1175,7 @@ IonBuilder::traverseBytecode() // adding any SSA uses and doesn't call setFoldedUnchecked on it. Vector popped(alloc()); Vector poppedUses(alloc()); - unsigned nuses = GetUseCount(script_, pc - script_->code); + unsigned nuses = GetUseCount(script_, pc - script_->getCode()); for (unsigned i = 0; i < nuses; i++) { MDefinition *def = current->peek(-int32_t(i + 1)); @@ -1672,7 +1660,7 @@ IonBuilder::inspectOpcode(JSOp op) return jsop_in(); case JSOP_SETRVAL: - JS_ASSERT(!script()->noScriptRval); + JS_ASSERT(!script()->getNoScriptRval()); current->setSlot(info().returnValueSlot(), current->pop()); return true; @@ -3473,7 +3461,7 @@ IonBuilder::processReturn(JSOp op) case JSOP_RETRVAL: // Return undefined eagerly if script doesn't use return value. - if (script()->noScriptRval) { + if (script()->getNoScriptRval()) { MInstruction *ins = MConstant::New(alloc(), UndefinedValue()); current->add(ins); def = ins; @@ -3786,17 +3774,21 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) JSScript *calleeScript = target->nonLazyScript(); BaselineInspector inspector(calleeScript); - // Improve type information of |this| when not set. - if (callInfo.constructing() && - !callInfo.thisArg()->resultTypeSet() && - calleeScript->types) { - types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript); - if (!types->unknown()) { - MTypeBarrier *barrier = - MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc())); - current->add(barrier); - callInfo.setThis(barrier); + AutoUnprotectCellUnderCompilationLock unprotect(calleeScript); + + // Improve type information of |this| when not set. + if (callInfo.constructing() && + !callInfo.thisArg()->resultTypeSet() && + calleeScript->types) + { + types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript); + if (!types->unknown()) { + MTypeBarrier *barrier = + MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc().lifoAlloc())); + current->add(barrier); + callInfo.setThis(barrier); + } } } @@ -3826,6 +3818,7 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) // Inlining the callee failed. Mark the callee as uninlineable only if // the inlining was aborted for a non-exception reason. if (inlineBuilder.abortReason_ == AbortReason_Disable) { + AutoUnprotectCellForWrite unprotect(calleeScript); calleeScript->uninlineable = true; abortReason_ = AbortReason_Inlining; } else if (inlineBuilder.abortReason_ == AbortReason_Inlining) { @@ -3931,7 +3924,7 @@ IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasic static bool IsSmallFunction(JSScript *script) { - return script->length <= js_IonOptions.smallFunctionMaxBytecodeLength; + return script->getLength() <= js_IonOptions.smallFunctionMaxBytecodeLength; } bool @@ -3956,34 +3949,33 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) // Heuristics! JSScript *targetScript = target->nonLazyScript(); + IonSpew(IonSpew_Inlining, "Deciding whether to inline %s:%d", + targetScript->filename(), targetScript->getLineno()); + // Skip heuristics if we have an explicit hint to inline. - if (!targetScript->shouldInline) { + if (!targetScript->getShouldInline()) { // Cap the inlining depth. if (IsSmallFunction(targetScript)) { if (inliningDepth_ >= js_IonOptions.smallFunctionMaxInlineDepth) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding allowed inline depth", - targetScript->filename(), targetScript->lineno); + IonSpew(IonSpew_Inlining, "Vetoed: exceeding allowed inline depth"); return false; } } else { if (inliningDepth_ >= js_IonOptions.maxInlineDepth) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding allowed inline depth", - targetScript->filename(), targetScript->lineno); + IonSpew(IonSpew_Inlining, "Vetoed: exceeding allowed inline depth"); return false; } if (targetScript->hasLoops()) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: big function that contains a loop", - targetScript->filename(), targetScript->lineno); + IonSpew(IonSpew_Inlining, "Vetoed: big function that contains a loop"); return false; } } // Callee must not be excessively large. // This heuristic also applies to the callsite as a whole. - if (targetScript->length > js_IonOptions.inlineMaxTotalBytecodeLength) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: callee excessively large.", - targetScript->filename(), targetScript->lineno); + if (targetScript->getLength() > js_IonOptions.inlineMaxTotalBytecodeLength) { + IonSpew(IonSpew_Inlining, "Vetoed: callee excessively large"); return false; } @@ -3993,8 +3985,7 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) if (callerUses < js_IonOptions.usesBeforeInlining() && info().executionMode() != DefinitePropertiesAnalysis) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: caller is insufficiently hot.", - targetScript->filename(), targetScript->lineno); + IonSpew(IonSpew_Inlining, "Vetoed: caller is insufficiently hot"); return false; } @@ -4002,8 +3993,7 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) if (targetScript->getUseCount() * js_IonOptions.inlineUseCountRatio < callerUses && info().executionMode() != DefinitePropertiesAnalysis) { - IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: callee is not hot.", - targetScript->filename(), targetScript->lineno); + IonSpew(IonSpew_Inlining, "Vetoed: callee is not hot"); return false; } } @@ -4030,7 +4020,7 @@ IonBuilder::selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, Boo // Enforce a maximum inlined bytecode limit at the callsite. if (inlineable && target->isInterpreted()) { - totalSize += target->nonLazyScript()->length; + totalSize += target->nonLazyScript()->getLength(); if (totalSize > js_IonOptions.inlineMaxTotalBytecodeLength) inlineable = false; } @@ -4531,6 +4521,7 @@ IonBuilder::createDeclEnvObject(MDefinition *callee, MDefinition *scope) // Get a template CallObject that we'll use to generate inline object // creation. DeclEnvObject *templateObj = inspector->templateDeclEnvObject(); + AutoUnprotectCell unprotect(templateObj); // One field is added to the function to handle its name. This cannot be a // dynamic slot because there is still plenty of room on the DeclEnv object. @@ -4558,12 +4549,14 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) // Get a template CallObject that we'll use to generate inline object // creation. CallObject *templateObj = inspector->templateCallObject(); + AutoUnprotectCell unprotect(templateObj); // If the CallObject needs dynamic slots, allocate those now. MInstruction *slots; if (templateObj->hasDynamicSlots()) { - size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(), - templateObj->slotSpan()); + AutoUnprotectCell unprotect(templateObj); + size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlotsForCompilation(), + templateObj->lastProperty()->slotSpan(templateObj->getClass())); slots = MNewSlots::New(alloc(), nslots); } else { slots = MConstant::New(alloc(), NullValue()); @@ -4574,7 +4567,7 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) // instructions could potentially bailout, thus leaking the dynamic slots // pointer. Run-once scripts need a singleton type, so always do a VM call // in such cases. - MInstruction *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce, slots); + MInstruction *callObj = MNewCallObject::New(alloc(), templateObj, script()->getTreatAsRunOnce(), slots); current->add(callObj); // Insert a post barrier to protect the following writes if we allocated @@ -4592,8 +4585,8 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) unsigned slot = i.scopeSlot(); unsigned formal = i.frameIndex(); MDefinition *param = current->getSlot(info().argSlotUnchecked(formal)); - if (slot >= templateObj->numFixedSlots()) - current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param)); + if (slot >= templateObj->numFixedSlotsForCompilation()) + current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlotsForCompilation(), param)); else current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param)); } @@ -4658,17 +4651,20 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee) if (!proto) return nullptr; - if (!target->nonLazyScript()->types) - return nullptr; - JSObject *templateObject = inspector->getTemplateObject(pc); if (!templateObject || !templateObject->is()) return nullptr; if (templateObject->getProto() != proto) return nullptr; - if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject))) - return nullptr; + { + AutoUnprotectCellUnderCompilationLock unprotect(target->nonLazyScript()); + if (!target->nonLazyScript()->types) + return nullptr; + + if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject))) + return nullptr; + } // For template objects with NewScript info, the appropriate allocation // kind to use may change due to dynamic property adds. In these cases @@ -4966,7 +4962,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing) ObjectVector targets(alloc()); for (uint32_t i = 0; i < originals.length(); i++) { JSFunction *fun = &originals[i]->as(); - if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite) { + if (fun->hasScript() && fun->nonLazyScript()->getShouldCloneAtCallsite()) { if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment->callsiteClones(), fun, script(), pc)) { fun = clone; hasClones = true; @@ -5101,17 +5097,20 @@ IonBuilder::testNeedsArgumentCheck(JSFunction *target, CallInfo &callInfo) return true; JSScript *targetScript = target->nonLazyScript(); + + AutoUnprotectCellUnderCompilationLock lock(targetScript); + if (!targetScript->types) return true; if (!ArgumentTypesMatch(callInfo.thisArg(), types::TypeScript::ThisTypes(targetScript))) return true; - uint32_t expected_args = Min(callInfo.argc(), target->nargs); + uint32_t expected_args = Min(callInfo.argc(), target->getNargs()); for (size_t i = 0; i < expected_args; i++) { if (!ArgumentTypesMatch(callInfo.getArg(i), types::TypeScript::ArgTypes(targetScript, i))) return true; } - for (size_t i = callInfo.argc(); i < target->nargs; i++) { + for (size_t i = callInfo.argc(); i < target->getNargs(); i++) { if (!types::TypeScript::ArgTypes(targetScript, i)->mightBeType(JSVAL_TYPE_UNDEFINED)) return true; } @@ -5132,7 +5131,7 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC // Collect number of missing arguments provided that the target is // scripted. Native functions are passed an explicit 'argc' parameter. if (target && !target->isNative()) - targetArgs = Max(target->nargs, callInfo.argc()); + targetArgs = Max(target->getNargs(), callInfo.argc()); MCall *call = MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(), callInfo.constructing()); @@ -5318,9 +5317,10 @@ IonBuilder::jsop_eval(uint32_t argc) string->getOperand(1)->isConstant() && string->getOperand(1)->toConstant()->value().isString()) { - JSString *str = string->getOperand(1)->toConstant()->value().toString(); + JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom(); + AutoUnprotectCell unprotect(atom); - if (str->isLinear() && StringEqualsAscii(&str->asLinear(), "()")) { + if (StringEqualsAscii(atom, "()")) { MDefinition *name = string->getOperand(0); MInstruction *dynamicName = MGetDynamicName::New(alloc(), scopeChain, name); current->add(dynamicName); @@ -5373,7 +5373,7 @@ IonBuilder::jsop_compare(JSOp op) bool IonBuilder::jsop_newarray(uint32_t count) { - JS_ASSERT(script()->compileAndGo); + JS_ASSERT(script()->getCompileAndGo()); JSObject *templateObject = inspector->getTemplateObject(pc); if (!templateObject) @@ -5403,7 +5403,7 @@ bool IonBuilder::jsop_newobject() { // Don't bake in the TypeObject for non-CNG scripts. - JS_ASSERT(script()->compileAndGo); + JS_ASSERT(script()->getCompileAndGo()); JSObject *templateObject = inspector->getTemplateObject(pc); if (!templateObject) @@ -5470,7 +5470,10 @@ IonBuilder::jsop_initelem_array() MElements *elements = MElements::New(alloc(), obj); current->add(elements); - if (obj->toNewArray()->templateObject()->shouldConvertDoubleElements()) { + JSObject *templateObject = obj->toNewArray()->templateObject(); + AutoUnprotectCell unprotect(templateObject); + + if (templateObject->shouldConvertDoubleElementsForCompilation()) { MInstruction *valueDouble = MToDouble::New(alloc(), value); current->add(valueDouble); value = valueDouble; @@ -5497,8 +5500,11 @@ IonBuilder::jsop_initprop(PropertyName *name) MDefinition *obj = current->peek(-1); JSObject *templateObject = obj->toNewObject()->templateObject(); - - Shape *shape = templateObject->nativeLookupPure(name); + Shape *shape; + { + AutoUnprotectCell unprotect(templateObject); + shape = templateObject->lastProperty()->searchLinear(NameToId(name)); + } if (!shape) { // JSOP_NEWINIT becomes an MNewObject without preconfigured properties. @@ -5670,7 +5676,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry) // Initialize |return value| { MInstruction *returnValue; - if (!script()->noScriptRval) + if (!script()->getNoScriptRval()) returnValue = MOsrReturnValue::New(alloc(), entry); else returnValue = MConstant::New(alloc(), UndefinedValue()); @@ -5838,10 +5844,14 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool if (info().fun() && i == info().thisSlot()) { existingValue = baselineFrame_->thisValue(); } else if (arg < info().nargs()) { - if (info().needsArgsObj()) + if (info().needsArgsObj()) { + // Note: baseline frame contents need to be copied into temporary space + // when triggering an OSR off thread compilation. + AutoUnprotectCell unprotect(&baselineFrame_->argsObj()); existingValue = baselineFrame_->argsObj().arg(arg); - else + } else { existingValue = baselineFrame_->unaliasedFormal(arg); + } } else { existingValue = baselineFrame_->unaliasedVar(var); } @@ -6306,9 +6316,6 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name) MDefinition *value = current->peek(-1); - if (staticObject->watched()) - return jsop_setprop(name); - types::TypeObjectKey *staticType = types::TypeObjectKey::get(staticObject); if (staticType->unknownProperties()) return jsop_setprop(name); @@ -6709,7 +6716,7 @@ IonBuilder::getElemTryTypedStatic(bool *emitted, MDefinition *obj, MDefinition * return true; TypedArrayObject *tarr = &tarrObj->as(); - ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(tarr); + ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type(); // LoadTypedArrayElementStatic currently treats uint32 arrays as int32. if (viewType == ArrayBufferView::TYPE_UINT32) @@ -7266,7 +7273,7 @@ IonBuilder::setElemTryTypedStatic(bool *emitted, MDefinition *object, return true; TypedArrayObject *tarr = &tarrObj->as(); - ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(tarr); + ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type(); MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType); if (!ptr) @@ -7399,7 +7406,7 @@ IonBuilder::setElemTryCache(bool *emitted, MDefinition *object, current->add(MPostWriteBarrier::New(alloc(), object, value)); // Emit SetElementCache. - MInstruction *ins = MSetElementCache::New(alloc(), object, index, value, script()->strict, guardHoles); + MInstruction *ins = MSetElementCache::New(alloc(), object, index, value, script()->getStrict(), guardHoles); current->add(ins); current->push(value); @@ -7970,7 +7977,7 @@ IonBuilder::invalidatedIdempotentCache() { IonBuilder *builder = this; do { - if (builder->script()->invalidatedIdempotentCache) + if (builder->script()->getInvalidatedIdempotentCache()) return true; builder = builder->callerBuilder_; } while (builder); @@ -8006,9 +8013,6 @@ bool IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType, bool barrier, types::TemporaryTypeSet *types) { - JS_ASSERT(shape->hasDefaultGetter()); - JS_ASSERT(shape->hasSlot()); - return loadSlot(obj, shape->slot(), shape->numFixedSlots(), rvalType, barrier, types); } @@ -8043,10 +8047,7 @@ bool IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier, MIRType slotType /* = MIRType_None */) { - JS_ASSERT(shape->hasDefaultSetter()); JS_ASSERT(shape->writable()); - JS_ASSERT(shape->hasSlot()); - return storeSlot(obj, shape->slot(), shape->numFixedSlots(), value, needsBarrier, slotType); } @@ -8554,7 +8555,7 @@ IonBuilder::jsop_setprop(PropertyName *name) // Always use a call if we are doing the definite properties analysis and // not actually emitting code, to simplify later analysis. if (info().executionMode() == DefinitePropertiesAnalysis) { - MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->strict); + MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->getStrict()); current->add(ins); current->push(value); return resumeAfter(ins); @@ -8589,7 +8590,7 @@ IonBuilder::jsop_setprop(PropertyName *name) return emitted; // Emit call. - MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->strict); + MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->getStrict()); current->add(ins); current->push(value); return resumeAfter(ins); @@ -8863,7 +8864,7 @@ IonBuilder::setPropTryCache(bool *emitted, MDefinition *obj, JS_ASSERT(*emitted == false); // Emit SetPropertyCache. - MSetPropertyCache *ins = MSetPropertyCache::New(alloc(), obj, value, name, script()->strict, barrier); + MSetPropertyCache *ins = MSetPropertyCache::New(alloc(), obj, value, name, script()->getStrict(), barrier); if (!objTypes || objTypes->propertyNeedsBarrier(constraints(), NameToId(name))) ins->setNeedsBarrier(); @@ -8907,11 +8908,6 @@ IonBuilder::jsop_delelem() bool IonBuilder::jsop_regexp(RegExpObject *reobj) { - JSObject *prototype = reobj->getProto(); - JS_ASSERT(prototype == script()->global().maybeGetRegExpPrototype()); - - JS_ASSERT(&reobj->JSObject::global() == &script()->global()); - // JS semantics require regular expression literals to create different // objects every time they execute. We only need to do this cloning if the // script could actually observe the effect of such cloning, for instance @@ -8921,6 +8917,9 @@ IonBuilder::jsop_regexp(RegExpObject *reobj) // then check if this regex object only flows into known natives and can // avoid cloning in this case. + // RegExpObjects embedded in scripts are immutable. + AutoUnprotectCell unprotect(reobj); + bool mustClone = true; types::TypeObjectKey *typeObj = types::TypeObjectKey::get(&script()->global()); if (!typeObj->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) { @@ -8934,6 +8933,8 @@ IonBuilder::jsop_regexp(RegExpObject *reobj) mustClone = false; } + JSObject *prototype = reobj->getProto(); + MRegExp *regexp = MRegExp::New(alloc(), reobj, prototype, mustClone); current->add(regexp); current->push(regexp); @@ -9093,7 +9094,7 @@ IonBuilder::jsop_this() if (!info().fun()) return abort("JSOP_THIS outside of a JSFunction."); - if (script()->strict || info().fun()->isSelfHostedBuiltin()) { + if (script()->getStrict() || info().fun()->isSelfHostedBuiltin()) { // No need to wrap primitive |this| in strict mode or self-hosted code. current->pushSlot(info().thisSlot()); return true; @@ -9246,7 +9247,7 @@ bool IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall) { JSScript *outerScript = ScopeCoordinateFunctionScript(script(), pc); - if (!outerScript || !outerScript->treatAsRunOnce) + if (!outerScript || !outerScript->getTreatAsRunOnce()) return false; types::TypeObjectKey *funType = types::TypeObjectKey::get(outerScript->function()); diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index 314cda55f2ae..05a17154a2df 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -88,6 +88,7 @@ class IonCode : public gc::BarrieredCell public: uint8_t *raw() const { + AutoUnprotectCell unprotect(this); return code_; } size_t instructionsSize() const { diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 8f2985905891..4c43af12fb98 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -685,7 +685,6 @@ MacroAssembler::newGCThing(const Register &result, JSObject *templateObject, Lab { gc::AllocKind allocKind = templateObject->tenuredGetAllocKind(); JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); - JS_ASSERT(!templateObject->hasDynamicElements()); gc::InitialHeap initialHeap = templateObject->type()->initialHeapForJITAlloc(); newGCThing(result, allocKind, fail, initialHeap); @@ -758,7 +757,6 @@ MacroAssembler::newGCThingPar(const Register &result, const Register &slice, { gc::AllocKind allocKind = templateObject->tenuredGetAllocKind(); JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); - JS_ASSERT(!templateObject->hasDynamicElements()); newGCThingPar(result, slice, tempReg1, tempReg2, allocKind, fail); } @@ -784,12 +782,17 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) { // Fast initialization of an empty object returned by NewGCThing(). + // Template objects provided to the code generator should not be modified by the main thread. + AutoUnprotectCell unprotect(templateObject); + + JS_ASSERT(!templateObject->hasDynamicElements()); + storePtr(ImmGCPtr(templateObject->lastProperty()), Address(obj, JSObject::offsetOfShape())); storePtr(ImmGCPtr(templateObject->type()), Address(obj, JSObject::offsetOfType())); storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots())); if (templateObject->is()) { - JS_ASSERT(!templateObject->getDenseInitializedLength()); + JS_ASSERT(!templateObject->getDenseInitializedLengthForCompilation()); int elementsOffset = JSObject::offsetOfFixedElements(); @@ -798,13 +801,13 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) addPtr(Imm32(-elementsOffset), obj); // Fill in the elements header. - store32(Imm32(templateObject->getDenseCapacity()), + store32(Imm32(templateObject->getDenseCapacityForCompilation()), Address(obj, elementsOffset + ObjectElements::offsetOfCapacity())); - store32(Imm32(templateObject->getDenseInitializedLength()), + store32(Imm32(templateObject->getDenseInitializedLengthForCompilation()), Address(obj, elementsOffset + ObjectElements::offsetOfInitializedLength())); store32(Imm32(templateObject->as().length()), Address(obj, elementsOffset + ObjectElements::offsetOfLength())); - store32(Imm32(templateObject->shouldConvertDoubleElements() + store32(Imm32(templateObject->shouldConvertDoubleElementsForCompilation() ? ObjectElements::CONVERT_DOUBLE_ELEMENTS : 0), Address(obj, elementsOffset + ObjectElements::offsetOfFlags())); @@ -813,7 +816,8 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) // Fixed slots of non-array objects are required to be initialized. // Use the values currently in the template object. - size_t nslots = Min(templateObject->numFixedSlots(), templateObject->slotSpan()); + size_t nslots = Min(templateObject->numFixedSlotsForCompilation(), + templateObject->lastProperty()->slotSpan(templateObject->getClassImmutable())); for (unsigned i = 0; i < nslots; i++) { storeValue(templateObject->getFixedSlot(i), Address(obj, JSObject::getFixedSlotOffset(i))); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 8e304d9b571a..3bb5bded4bff 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -248,8 +248,10 @@ IonBuilder::inlineArray(CallInfo &callInfo) types::TemporaryTypeSet::DoubleConversion conversion = getInlineReturnTypeSet()->convertDoubleElements(constraints()); - if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) + if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) { + AutoUnprotectCell unprotect(templateObject); templateObject->setShouldConvertDoubleElements(); + } MNewArray *ins = MNewArray::New(alloc(), initLength, templateObject, allocating); current->add(ins); @@ -457,11 +459,8 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (!baseThisType) return InliningStatus_NotInlined; types::TypeObjectKey *thisType = types::TypeObjectKey::get(baseThisType); - if (thisType->unknownProperties() || - &thisType->proto().toObject()->global() != &script()->global()) - { + if (thisType->unknownProperties()) return InliningStatus_NotInlined; - } // Don't inline if 'this' is packed and the argument may not be packed // (the result array will reuse the 'this' type). @@ -1265,7 +1264,7 @@ IonBuilder::inlineNewParallelArray(CallInfo &callInfo) JSFunction *target = nullptr; if (targetObj && targetObj->is()) target = &targetObj->as(); - if (target && target->isInterpreted() && target->nonLazyScript()->shouldCloneAtCallsite) { + if (target && target->isInterpreted() && target->nonLazyScript()->getShouldCloneAtCallsite()) { if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment->callsiteClones(), target, script(), pc)) target = clone; } @@ -1290,7 +1289,7 @@ IonBuilder::inlineParallelArray(CallInfo &callInfo) if (!target) return InliningStatus_NotInlined; - JS_ASSERT(target->nonLazyScript()->shouldCloneAtCallsite); + JS_ASSERT(target->nonLazyScript()->getShouldCloneAtCallsite()); if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment->callsiteClones(), target, script(), pc)) target = clone; @@ -1324,7 +1323,7 @@ IonBuilder::inlineParallelArrayTail(CallInfo &callInfo, if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1) return InliningStatus_NotInlined; types::TypeObject *typeObject = returnTypes->getTypeObject(0); - if (!typeObject || typeObject->clasp != &ParallelArrayObject::class_) + if (!typeObject || typeObject->getClass() != &ParallelArrayObject::class_) return InliningStatus_NotInlined; JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native); @@ -1334,7 +1333,7 @@ IonBuilder::inlineParallelArrayTail(CallInfo &callInfo, // Create the call and add in the non-this arguments. uint32_t targetArgs = argc; if (target && !target->isNative()) - targetArgs = Max(target->nargs, argc); + targetArgs = Max(target->getNargs(), argc); MCall *call = MCall::New(alloc(), target, targetArgs + 1, argc, false); if (!call) diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 5b34080061ff..b8f21a9a9035 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -661,6 +661,7 @@ MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers) { if ((type() == MIRType_Int32) && (string()->isConstant())) { Value value = string()->toConstant()->value(); + AutoUnprotectCell unprotect(&value.toString()->asAtom()); size_t length = JS_GetStringLength(value.toString()); return MConstant::New(alloc, Int32Value(length)); @@ -2319,10 +2320,8 @@ MCompare::evaluateConstantOperands(bool *result) // Fold away some String equality comparisons. if (lhs.isString() && rhs.isString()) { int32_t comp = 0; // Default to equal. - if (left != right) { - if (!CompareStrings(GetIonContext()->cx, lhs.toString(), rhs.toString(), &comp)) - return false; - } + if (left != right) + comp = CompareAtoms(&lhs.toString()->asAtom(), &rhs.toString()->asAtom()); switch (jsop_) { case JSOP_LT: @@ -2503,6 +2502,7 @@ MBeta::printOpcode(FILE *fp) const bool MNewObject::shouldUseVM() const { + AutoUnprotectCell unprotect(templateObject()); return templateObject()->hasSingletonType() || templateObject()->hasDynamicSlots(); } @@ -2928,7 +2928,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx, JSObject *obj = object->singleton() ? object->singleton() : object->proto().toObjectOrNull(); while (obj) { - if (!obj->isNative()) + if (!obj->getClass()->isNative()) break; types::TypeObjectKey *typeObj = types::TypeObjectKey::get(obj); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 849a65716207..b920a845d4a1 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -966,8 +966,18 @@ class MConstant : public MNullaryInstruction return &value_; } const bool valueToBoolean() const { - // A hack to avoid this wordy pattern everywhere in the JIT. - return ToBoolean(HandleValue::fromMarkedLocation(&value_)); + if (value_.isString()) { + AutoUnprotectCell unprotect(&value_.toString()->asAtom()); + return ToBoolean(value_); + } + if (value_.isObject()) { + // Note: ToBoolean can't be called off thread as it will try to + // unwrap wrappers. IsWrapper goes through public API methods which + // don't unprotect the right pointers. Since wrappers don't have + // singleton type just ignore this case. + return !value_.toObject().getClass()->emulatesUndefined(); + } + return ToBoolean(value_); } void printOpcode(FILE *fp) const; @@ -4816,13 +4826,14 @@ struct LambdaFunctionInfo // the script, and are immutable except for delazification. Record this // information while still on the main thread to avoid races. CompilerRootFunction fun; + uint16_t nargs; uint16_t flags; gc::Cell *scriptOrLazyScript; bool singletonType; bool useNewTypeForClone; LambdaFunctionInfo(JSFunction *fun) - : fun(fun), flags(fun->flags), + : fun(fun), nargs(fun->getNargs()), flags(fun->getFlags()), scriptOrLazyScript(fun->hasScript() ? (gc::Cell *) fun->nonLazyScript() : (gc::Cell *) fun->lazyScript()), @@ -4831,7 +4842,7 @@ struct LambdaFunctionInfo {} LambdaFunctionInfo(const LambdaFunctionInfo &info) - : fun((JSFunction *) info.fun), flags(info.flags), + : fun((JSFunction *) info.fun), nargs(info.nargs), flags(info.flags), scriptOrLazyScript(info.scriptOrLazyScript), singletonType(info.singletonType), useNewTypeForClone(info.useNewTypeForClone) @@ -5959,7 +5970,9 @@ class MLoadTypedArrayElementStatic return new(alloc) MLoadTypedArrayElementStatic(typedArray, ptr); } - ArrayBufferView::ViewType viewType() const { return JS_GetArrayBufferViewType(typedArray_); } + ArrayBufferView::ViewType viewType() const { + return (ArrayBufferView::ViewType) typedArray_->type(); + } void *base() const; size_t length() const; @@ -6141,7 +6154,9 @@ class MStoreTypedArrayElementStatic : return this; } - ArrayBufferView::ViewType viewType() const { return JS_GetArrayBufferViewType(typedArray_); } + ArrayBufferView::ViewType viewType() const { + return (ArrayBufferView::ViewType) typedArray_->type(); + } bool isFloatArray() const { return (viewType() == ArrayBufferView::TYPE_FLOAT32 || viewType() == ArrayBufferView::TYPE_FLOAT64); diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index 66fc665c8d1a..420099eadee0 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -468,7 +468,7 @@ class MBasicBlock : public TempObject, public InlineListNode } bool strict() const { - return info_.script()->strict; + return info_.script()->getStrict(); } void dumpStack(FILE *fp); diff --git a/js/src/jit/ParallelFunctions.cpp b/js/src/jit/ParallelFunctions.cpp index aaa83df02ea9..ef16a54b5c04 100644 --- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -258,9 +258,9 @@ CompareStringsPar(ForkJoinSlice *slice, JSString *left, JSString *right, int32_t if (!leftInspector.ensureChars(slice) || !rightInspector.ensureChars(slice)) return false; - return CompareChars(leftInspector.chars(), left->length(), - rightInspector.chars(), right->length(), - res); + *res = CompareChars(leftInspector.chars(), left->length(), + rightInspector.chars(), right->length()); + return true; } static bool diff --git a/js/src/jit/Snapshots.cpp b/js/src/jit/Snapshots.cpp index 1b30728c618f..917d38779c9e 100644 --- a/js/src/jit/Snapshots.cpp +++ b/js/src/jit/Snapshots.cpp @@ -306,18 +306,18 @@ SnapshotWriter::startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, ui // +4 to account for scope chain, return value, this value and maybe arguments_object. JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); - uint32_t implicit = StartArgSlot(script, fun); + uint32_t implicit = StartArgSlot(script); uint32_t formalArgs = CountArgSlots(script, fun); - nslots_ = formalArgs + script->nfixed + exprStack; + nslots_ = formalArgs + script->getNfixed() + exprStack; slotsWritten_ = 0; IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u", - implicit, formalArgs - implicit, script->nfixed, exprStack); + implicit, formalArgs - implicit, script->getNfixed(), exprStack); - JS_ASSERT(script->code <= pc && pc <= script->code + script->length); + JS_ASSERT(script->getCode() <= pc && pc <= script->getCode() + script->getLength()); - uint32_t pcoff = uint32_t(pc - script->code); + uint32_t pcoff = uint32_t(pc - script->getCode()); IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nslots_); writer_.writeUnsigned(pcoff); writer_.writeUnsigned(nslots_); diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 19bcca9ab128..a591ba282c34 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -279,6 +279,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot) #ifdef DEBUG if (GetIonContext()->cx) { + AutoUnprotectCell unprotect(script); uint32_t stackDepth; if (ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth)) { if (JSOp(*bailPC) == JSOP_FUNCALL) { diff --git a/js/src/jsanalyze.h b/js/src/jsanalyze.h index bc6e6efa2c28..30a43b0e4a58 100644 --- a/js/src/jsanalyze.h +++ b/js/src/jsanalyze.h @@ -225,7 +225,7 @@ static inline uint32_t ArgSlot(uint32_t arg) { return 1 + arg; } static inline uint32_t LocalSlot(JSScript *script, uint32_t local) { - return 1 + (script->function() ? script->function()->nargs : 0) + local; + return 1 + (script->function() ? script->function()->getNargs() : 0) + local; } static inline uint32_t TotalSlots(JSScript *script) { return LocalSlot(script, 0) + script->nfixed; diff --git a/js/src/jsapi-tests/testConservativeGC.cpp b/js/src/jsapi-tests/testConservativeGC.cpp index be33d5dd6cdb..16c4456804f4 100644 --- a/js/src/jsapi-tests/testConservativeGC.cpp +++ b/js/src/jsapi-tests/testConservativeGC.cpp @@ -60,7 +60,6 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj) { /* Ignore fields which are unstable across GCs. */ CHECK(savedCopy->lastProperty() == obj->lastProperty()); - CHECK(savedCopy->getProto() == obj->getProto()); return true; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index bee0b4f9abc3..c3b80ec03da7 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1056,7 +1056,7 @@ ToNumberSlow(JSContext *cx, JS::Value v, double *dp); * DO NOT CALL THIS. Use JS::ToBoolean */ extern JS_PUBLIC_API(bool) -ToBooleanSlow(JS::HandleValue v); +ToBooleanSlow(const JS::Value &v); /* * DO NOT CALL THIS. Use JS::ToString @@ -1085,7 +1085,7 @@ ToNumber(JSContext *cx, Handle v, double *out) } JS_ALWAYS_INLINE bool -ToBoolean(HandleValue v) +ToBoolean(const Value &v) { if (v.isBoolean()) return v.toBoolean(); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 1b05c9ef87ec..8ce9b1cd50eb 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1491,10 +1491,10 @@ CompareSubStringValues(JSContext *cx, const jschar *s1, size_t l1, if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; - int32_t result; - if (!s1 || !s2 || !CompareChars(s1, l1, s2, l2, &result)) + if (!s1 || !s2) return false; + int32_t result = CompareChars(s1, l1, s2, l2); *lessOrEqualp = (result <= 0); return true; } diff --git a/js/src/jsatominlines.h b/js/src/jsatominlines.h index f6ed26e39bda..a7d916b017a9 100644 --- a/js/src/jsatominlines.h +++ b/js/src/jsatominlines.h @@ -31,6 +31,7 @@ namespace js { inline jsid AtomToId(JSAtom *atom) { + AutoUnprotectCell unprotect(atom); JS_STATIC_ASSERT(JSID_INT_MIN == 0); uint32_t index; diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index 9c6c00f94d32..0acfc41f743a 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -182,7 +182,7 @@ js_BooleanToString(ExclusiveContext *cx, bool b) } JS_PUBLIC_API(bool) -js::ToBooleanSlow(HandleValue v) +js::ToBooleanSlow(const Value &v) { if (v.isString()) return v.toString()->length() != 0; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 07c22fe19fc5..98398ef203d2 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -113,7 +113,7 @@ JSFunction * js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun, JSScript *script, jsbytecode *pc) { - JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite); + JS_ASSERT(fun->nonLazyScript()->getShouldCloneAtCallsite()); JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope()); JS_ASSERT(types::UseNewTypeForClone(fun)); @@ -126,7 +126,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction if (!table.initialized()) return nullptr; - CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, pc - script->code)); + CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, pc - script->getCode())); if (p) return p->value; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 3c9d060cf5a2..88860cf858d4 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -51,7 +51,7 @@ struct CallsiteCloneKey { typedef CallsiteCloneKey Lookup; static inline uint32_t hash(CallsiteCloneKey key) { - return uint32_t(size_t(key.script->code + key.offset) ^ size_t(key.original)); + return uint32_t(size_t(key.script->getCode() + key.offset) ^ size_t(key.original)); } static inline bool match(const CallsiteCloneKey &a, const CallsiteCloneKey &b) { diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h index c2a6c5ca1189..303f7a4fc06d 100644 --- a/js/src/jscompartmentinlines.h +++ b/js/src/jscompartmentinlines.h @@ -22,7 +22,7 @@ JSCompartment::initGlobal(js::GlobalObject &global) js::GlobalObject * JSCompartment::maybeGlobal() const { - JS_ASSERT_IF(global_, global_->compartment() == this); + JS_ASSERT_IF(global_ && !runtime_->heapProtected(), global_->compartment() == this); return global_; } diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 4b2f0b6d659d..77afcfcce96f 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -65,7 +65,19 @@ class JSFunction : public JSObject uint16_t nargs; /* number of formal arguments (including defaults and the rest parameter unlike f.length) */ + + uint16_t getNargs() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); + return nargs; + } + uint16_t flags; /* bitfield composed of the above Flags enum */ + + uint16_t getFlags() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); + return flags; + } + union U { class Native { friend class JSFunction; @@ -98,31 +110,31 @@ class JSFunction : public JSObject return false; // Note: this should be kept in sync with FunctionBox::isHeavyweight(). - return nonLazyScript()->bindings.hasAnyAliasedBindings() || - nonLazyScript()->funHasExtensibleScope || - nonLazyScript()->funNeedsDeclEnvObject; + return nonLazyScript()->getHasAnyAliasedBindings() || + nonLazyScript()->getFunHasExtensibleScope() || + nonLazyScript()->getFunNeedsDeclEnvObject(); } /* A function can be classified as either native (C++) or interpreted (JS): */ - bool isInterpreted() const { return flags & (INTERPRETED | INTERPRETED_LAZY); } + bool isInterpreted() const { return getFlags() & (INTERPRETED | INTERPRETED_LAZY); } bool isNative() const { return !isInterpreted(); } /* Possible attributes of a native function: */ - bool isNativeConstructor() const { return flags & NATIVE_CTOR; } + bool isNativeConstructor() const { return getFlags() & NATIVE_CTOR; } /* Possible attributes of an interpreted function: */ - bool isFunctionPrototype() const { return flags & IS_FUN_PROTO; } - bool isInterpretedLazy() const { return flags & INTERPRETED_LAZY; } - bool hasScript() const { return flags & INTERPRETED; } - bool isExprClosure() const { return flags & EXPR_CLOSURE; } - bool hasGuessedAtom() const { return flags & HAS_GUESSED_ATOM; } - bool isLambda() const { return flags & LAMBDA; } - bool isSelfHostedBuiltin() const { return flags & SELF_HOSTED; } - bool isSelfHostedConstructor() const { return flags & SELF_HOSTED_CTOR; } - bool hasRest() const { return flags & HAS_REST; } + bool isFunctionPrototype() const { return getFlags() & IS_FUN_PROTO; } + bool isInterpretedLazy() const { return getFlags() & INTERPRETED_LAZY; } + bool hasScript() const { return getFlags() & INTERPRETED; } + bool isExprClosure() const { return getFlags() & EXPR_CLOSURE; } + bool hasGuessedAtom() const { return getFlags() & HAS_GUESSED_ATOM; } + bool isLambda() const { return getFlags() & LAMBDA; } + bool isSelfHostedBuiltin() const { return getFlags() & SELF_HOSTED; } + bool isSelfHostedConstructor() const { return getFlags() & SELF_HOSTED_CTOR; } + bool hasRest() const { return getFlags() & HAS_REST; } bool isWrappable() const { - JS_ASSERT_IF(flags & SH_WRAPPABLE, isSelfHostedBuiltin()); - return flags & SH_WRAPPABLE; + JS_ASSERT_IF(getFlags() & SH_WRAPPABLE, isSelfHostedBuiltin()); + return getFlags() & SH_WRAPPABLE; } bool hasJITCode() const { @@ -143,7 +155,7 @@ class JSFunction : public JSObject // // isArrow() is true for all three of these Function objects. // isBoundFunction() is true only for the last one. - bool isArrow() const { return flags & ARROW; } + bool isArrow() const { return getFlags() & ARROW; } /* Compound attributes: */ bool isBuiltin() const { @@ -156,7 +168,7 @@ class JSFunction : public JSObject (!isSelfHostedBuiltin() || isSelfHostedConstructor()); } bool isNamedLambda() const { - return isLambda() && atom_ && !hasGuessedAtom(); + return isLambda() && displayAtom() && !hasGuessedAtom(); } bool hasParallelNative() const { return isNative() && jitInfo() && !!jitInfo()->parallelNative; @@ -208,7 +220,11 @@ class JSFunction : public JSObject JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); } void initAtom(JSAtom *atom) { atom_.init(atom); } - JSAtom *displayAtom() const { return atom_; } + + JSAtom *displayAtom() const { + js::AutoUnprotectCell unprotect(this); + return atom_; + } void setGuessedAtom(JSAtom *atom) { JS_ASSERT(atom_ == nullptr); @@ -227,6 +243,7 @@ class JSFunction : public JSObject */ JSObject *environment() const { JS_ASSERT(isInterpreted()); + js::AutoUnprotectCell unprotect(this); return u.i.env_; } @@ -299,6 +316,7 @@ class JSFunction : public JSObject } JSScript *nonLazyScript() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(hasScript()); return u.i.s.script_; } @@ -309,11 +327,13 @@ class JSFunction : public JSObject } js::LazyScript *lazyScript() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_); return u.i.s.lazy_; } js::LazyScript *lazyScriptOrNull() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(isInterpretedLazy()); return u.i.s.lazy_; } @@ -354,6 +374,7 @@ class JSFunction : public JSObject JSNative native() const { JS_ASSERT(isNative()); + js::AutoUnprotectCell unprotect(this); return u.n.native; } @@ -378,6 +399,7 @@ class JSFunction : public JSObject const JSJitInfo *jitInfo() const { JS_ASSERT(isNative()); + js::AutoUnprotectCell unprotect(this); return u.n.jitinfo; } diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index de5874f003ad..845aa438b7de 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -687,6 +687,8 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script TemporaryTypeSet **pArgTypes, TemporaryTypeSet **pBytecodeTypes) { + AutoUnprotectCellUnderCompilationLock unprotect(script); + LifoAlloc *alloc = IonAlloc(); StackTypeSet *existing = script->types->typeArray(); @@ -702,7 +704,7 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script } *pThisTypes = types + (ThisTypes(script) - existing); - *pArgTypes = (script->function() && script->function()->nargs) + *pArgTypes = (script->function() && script->function()->getNargs()) ? (types + (ArgTypes(script, 0) - existing)) : nullptr; *pBytecodeTypes = types; @@ -784,29 +786,26 @@ CompilerConstraintInstance::generateTypeConstraint(JSContext *cx, RecompileIn const Class * TypeObjectKey::clasp() { - return isTypeObject() ? asTypeObject()->clasp : asSingleObject()->getClass(); + return isTypeObject() ? asTypeObject()->getClass() : asSingleObject()->getClass(); } TaggedProto TypeObjectKey::proto() { - return isTypeObject() ? TaggedProto(asTypeObject()->proto) : asSingleObject()->getTaggedProto(); + return isTypeObject() ? TaggedProto(asTypeObject()->getProto()) : asSingleObject()->getTaggedProto(); } JSObject * TypeObjectKey::singleton() { - return isTypeObject() ? asTypeObject()->singleton : asSingleObject(); + return isTypeObject() ? asTypeObject()->getSingleton() : asSingleObject(); } TypeNewScript * TypeObjectKey::newScript() { - if (isTypeObject()) { - TypeObjectAddendum *addendum = asTypeObject()->addendum; - if (addendum && addendum->isNewScript()) - return addendum->asNewScript(); - } + if (isTypeObject() && asTypeObject()->hasNewScript()) + return asTypeObject()->newScript(); return nullptr; } @@ -1630,14 +1629,11 @@ TemporaryTypeSet::getCommonPrototype() unsigned count = getObjectCount(); for (unsigned i = 0; i < count; i++) { - TaggedProto nproto; - if (JSObject *object = getSingleObject(i)) - nproto = object->getProto(); - else if (TypeObject *object = getTypeObject(i)) - nproto = object->proto.get(); - else + TypeObjectKey *object = getObject(i); + if (!object) continue; + TaggedProto nproto = object->proto(); if (proto) { if (nproto != proto) return nullptr; @@ -3379,7 +3375,7 @@ types::UseNewTypeForClone(JSFunction *fun) if (!fun->isInterpreted()) return false; - if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite) + if (fun->hasScript() && fun->nonLazyScript()->getShouldCloneAtCallsite()) return true; if (fun->isArrow()) @@ -3414,10 +3410,10 @@ types::UseNewTypeForClone(JSFunction *fun) uint32_t begin, end; if (fun->hasScript()) { - if (!fun->nonLazyScript()->usesArgumentsAndApply) + if (!fun->nonLazyScript()->getUsesArgumentsAndApply()) return false; - begin = fun->nonLazyScript()->sourceStart; - end = fun->nonLazyScript()->sourceEnd; + begin = fun->nonLazyScript()->getSourceStart(); + end = fun->nonLazyScript()->getSourceEnd(); } else { if (!fun->lazyScript()->usesArgumentsAndApply()) return false; diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index c20fd739e78e..94a0dfb853bd 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -874,9 +874,19 @@ struct TypeObject : gc::BarrieredCell /* Class shared by objects using this type. */ const Class *clasp; + const Class *getClass() { + AutoUnprotectCell unprotect(this); + return clasp; + } + /* Prototype shared by objects using this type. */ HeapPtrObject proto; + JSObject *getProto() { + AutoUnprotectCellUnderCompilationLock unprotect(this); + return proto; + } + /* * Whether there is a singleton JS object with this type. That JS object * must appear in type sets instead of this; we include the back reference @@ -884,12 +894,20 @@ struct TypeObject : gc::BarrieredCell */ HeapPtrObject singleton; + JSObject *getSingleton() { + AutoUnprotectCell unprotect(this); + return singleton; + } + /* * Value held by singleton if this is a standin type for a singleton JS * object whose type has not been constructed yet. */ static const size_t LAZY_SINGLETON = 1; - bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; } + bool lazy() const { + AutoUnprotectCellUnderCompilationLock unprotect(this); + return singleton == (JSObject *) LAZY_SINGLETON; + } /* Flags for this object. */ TypeObjectFlags flags; @@ -907,18 +925,22 @@ struct TypeObject : gc::BarrieredCell HeapPtr addendum; bool hasNewScript() const { + AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum && addendum->isNewScript(); } TypeNewScript *newScript() { + AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum->asNewScript(); } bool hasTypedObject() { + AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum && addendum->isTypedObject(); } TypeTypedObject *typedObject() { + AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum->asTypedObject(); } @@ -966,6 +988,11 @@ struct TypeObject : gc::BarrieredCell /* If this is an interpreted function, the function object. */ HeapPtrFunction interpretedFunction; + JSFunction *getInterpretedFunction() { + AutoUnprotectCell unprotect(this); + return interpretedFunction; + } + #if JS_BITS_PER_WORD == 32 uint32_t padding; #endif @@ -973,15 +1000,18 @@ struct TypeObject : gc::BarrieredCell inline TypeObject(const Class *clasp, TaggedProto proto, bool unknown); bool hasAnyFlags(TypeObjectFlags flags) { + AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); return !!(this->flags & flags); } bool hasAllFlags(TypeObjectFlags flags) { + AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); return (this->flags & flags) == flags; } bool unknownProperties() { + AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES, hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK)); return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES); @@ -1016,7 +1046,10 @@ struct TypeObject : gc::BarrieredCell /* Returns true if the allocating script should be recompiled. */ bool incrementTenureCount(); + uint32_t tenureCount() const { + // Note: We ignore races when reading the tenure count of a type off thread. + AutoUnprotectCell unprotect(this); return (flags & OBJECT_FLAG_TENURE_COUNT_MASK) >> OBJECT_FLAG_TENURE_COUNT_SHIFT; } diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index f44b4c6c22d0..0a3ae267682c 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -132,8 +132,8 @@ Type::ObjectType(JSObject *obj) /* static */ inline Type Type::ObjectType(TypeObject *obj) { - if (obj->singleton) - return Type(uintptr_t(obj->singleton.get()) | 1); + if (obj->getSingleton()) + return Type(uintptr_t(obj->getSingleton()) | 1); return Type(uintptr_t(obj)); } @@ -221,7 +221,8 @@ IdToTypeId(jsid id) * and overflowing integers. */ if (JSID_IS_STRING(id)) { - JSFlatString *str = JSID_TO_FLAT_STRING(id); + JSAtom *str = JSID_TO_ATOM(id); + AutoUnprotectCell unprotect(str); JS::TwoByteChars cp = str->range(); if (JS7_ISDEC(cp[0]) || cp[0] == '-') { for (size_t i = 1; i < cp.length(); ++i) { @@ -609,7 +610,7 @@ TypeScript::ThisTypes(JSScript *script) /* static */ inline StackTypeSet * TypeScript::ArgTypes(JSScript *script, unsigned i) { - JS_ASSERT(i < script->function()->nargs); + JS_ASSERT(i < script->function()->getNargs()); return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i); } @@ -624,11 +625,11 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPE uint32_t *bytecodeMap = nullptr; MOZ_CRASH(); #endif - uint32_t offset = pc - script->code; - JS_ASSERT(offset < script->length); + uint32_t offset = pc - script->getCode(); + JS_ASSERT(offset < script->getLength()); // See if this pc is the next typeset opcode after the last one looked up. - if (bytecodeMap[*hint + 1] == offset && (*hint + 1) < script->nTypeSets) { + if (bytecodeMap[*hint + 1] == offset && (*hint + 1) < script->getNumTypeSets()) { (*hint)++; return typeArray + *hint; } @@ -639,7 +640,7 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPE // Fall back to a binary search. size_t bottom = 0; - size_t top = script->nTypeSets - 1; + size_t top = script->getNumTypeSets() - 1; size_t mid = bottom + (top - bottom) / 2; while (mid < top) { if (bytecodeMap[mid] < offset) @@ -1181,7 +1182,7 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded) if (type.isTypeObject()) { TypeObject *nobject = type.typeObject(); - JS_ASSERT(!nobject->singleton); + JS_ASSERT(!nobject->getSingleton()); if (nobject->unknownProperties()) goto unknownObject; } @@ -1313,7 +1314,7 @@ TypeSet::getObjectClass(unsigned i) const if (JSObject *object = getSingleObject(i)) return object->getClass(); if (TypeObject *object = getTypeObject(i)) - return object->clasp; + return object->getClass(); return nullptr; } @@ -1402,6 +1403,8 @@ TypeObject::maybeGetProperty(jsid id) JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); JS_ASSERT(!unknownProperties()); + AutoUnprotectCellUnderCompilationLock unprotect(this); + Property *prop = HashSetLookup (propertySet, basePropertyCount(), id); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 6ee71302c171..a0c3630a3dfb 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -5554,6 +5554,8 @@ DumpProperty(JSObject *obj, Shape &shape) bool JSObject::uninlinedIsProxy() const { + AutoUnprotectCellUnderCompilationLock unprotect0(this); + AutoUnprotectCellUnderCompilationLock unprotect1(type_); return is(); } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 8909ec0bae45..d174ea73d8ad 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -288,6 +288,10 @@ class JSObject : public js::ObjectImpl } bool isBoundFunction() const { + // Note: This function can race when it is called during off thread compilation. + js::AutoUnprotectCell unprotect0(this); + js::AutoUnprotectCell unprotect1(lastProperty()); + js::AutoUnprotectCell unprotect2(lastProperty()->base()); return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION); } @@ -349,6 +353,10 @@ class JSObject : public js::ObjectImpl return lastProperty()->entryCount(); } + uint32_t propertyCountForCompilation() const { + return lastProperty()->entryCountForCompilation(); + } + bool hasShapeTable() const { return lastProperty()->hasTable(); } @@ -365,13 +373,13 @@ class JSObject : public js::ObjectImpl /* Whether a slot is at a fixed offset from this object. */ bool isFixedSlot(size_t slot) { - return slot < numFixedSlots(); + return slot < numFixedSlotsForCompilation(); } /* Index into the dynamic slots array to use for a dynamic slot. */ size_t dynamicSlotIndex(size_t slot) { - JS_ASSERT(slot >= numFixedSlots()); - return slot - numFixedSlots(); + JS_ASSERT(slot >= numFixedSlotsForCompilation()); + return slot - numFixedSlotsForCompilation(); } /* @@ -740,6 +748,11 @@ class JSObject : public js::ObjectImpl return getElementsHeader()->shouldConvertDoubleElements(); } + bool shouldConvertDoubleElementsForCompilation() { + // Note: isNative() generally can't be safely called off thread. + return getElementsHeader()->shouldConvertDoubleElements(); + } + inline void setShouldConvertDoubleElements(); /* Packed information for this object's elements. */ diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 00f9eecb48c6..9ffef95337b9 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -126,7 +126,10 @@ NumBlockSlots(JSScript *script, jsbytecode *pc) JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET1_LENGTH); JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET2_LENGTH); - return script->getObject(GET_UINT32_INDEX(pc))->as().slotCount(); + StaticBlockObject *block = &script->getObject(GET_UINT32_INDEX(pc))->as(); + AutoUnprotectCell unprotect(block); + + return block->propertyCountForCompilation(); } unsigned diff --git a/js/src/jsopcodeinlines.h b/js/src/jsopcodeinlines.h index 71cea13f58f0..4ce35ff87f68 100644 --- a/js/src/jsopcodeinlines.h +++ b/js/src/jsopcodeinlines.h @@ -16,8 +16,8 @@ namespace js { static inline unsigned GetDefCount(JSScript *script, unsigned offset) { - JS_ASSERT(offset < script->length); - jsbytecode *pc = script->code + offset; + JS_ASSERT(offset < script->getLength()); + jsbytecode *pc = script->getCode() + offset; /* * Add an extra pushed value for OR/AND opcodes, so that they are included @@ -43,8 +43,8 @@ GetDefCount(JSScript *script, unsigned offset) static inline unsigned GetUseCount(JSScript *script, unsigned offset) { - JS_ASSERT(offset < script->length); - jsbytecode *pc = script->code + offset; + JS_ASSERT(offset < script->getLength()); + jsbytecode *pc = script->getCode() + offset; if (JSOp(*pc) == JSOP_PICK) return (pc[1] + 1); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index c83216d75330..a58470b38638 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2092,11 +2092,11 @@ GSNCache::purge() jssrcnote * js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc) { - size_t target = pc - script->code; - if (target >= size_t(script->length)) + size_t target = pc - script->getCode(); + if (target >= size_t(script->getLength())) return nullptr; - if (cache.code == script->code) { + if (cache.code == script->getCode()) { JS_ASSERT(cache.map.initialized()); GSNCache::Map::Ptr p = cache.map.lookup(pc); return p ? p->value : nullptr; @@ -2116,7 +2116,7 @@ js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc) } } - if (cache.code != script->code && script->length >= GSN_CACHE_THRESHOLD) { + if (cache.code != script->getCode() && script->getLength() >= GSN_CACHE_THRESHOLD) { unsigned nsrcnotes = 0; for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { @@ -2129,14 +2129,14 @@ js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc) cache.code = nullptr; } if (cache.map.init(nsrcnotes)) { - pc = script->code; + pc = script->getCode(); for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { pc += SN_DELTA(sn); if (SN_IS_GETTABLE(sn)) JS_ALWAYS_TRUE(cache.map.put(pc, sn)); } - cache.code = script->code; + cache.code = script->getCode(); } } @@ -2202,7 +2202,7 @@ js::PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp) if (!pc) return 0; - return PCToLineNumber(script->lineno, script->notes(), script->code, pc, columnp); + return PCToLineNumber(script->getLineno(), script->notes(), script->getCode(), pc, columnp); } /* The line number limit is the same as the jssrcnote offset limit. */ @@ -2956,12 +2956,14 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script) bool JSScript::varIsAliased(unsigned varSlot) { + AutoUnprotectCell unprotect(this); return bindings.bindingIsAliased(bindings.numArgs() + varSlot); } bool JSScript::formalIsAliased(unsigned argSlot) { + AutoUnprotectCell unprotect(this); return bindings.bindingIsAliased(argSlot); } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 21e00a1af318..b6d596b48117 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -184,11 +184,13 @@ class Bindings bool bindingArrayUsingTemporaryStorage() const { return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT; } + + public: + Binding *bindingArray() const { return reinterpret_cast(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT); } - public: inline Bindings(); /* @@ -224,7 +226,14 @@ class Bindings bool bindingIsAliased(unsigned bindingIndex); /* Return whether this scope has any aliased bindings. */ - bool hasAnyAliasedBindings() const { return callObjShape_ && !callObjShape_->isEmptyShape(); } + bool hasAnyAliasedBindings() const { + if (!callObjShape_) + return false; + + // Binding shapes are immutable once constructed. + AutoUnprotectCell unprotect(callObjShape_); + return !callObjShape_->isEmptyShape(); + } void trace(JSTracer *trc); }; @@ -428,6 +437,10 @@ class ScriptSourceObject : public JSObject static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source); ScriptSource *source() { + // Script source objects are immutable. + AutoUnprotectCell unprotect0(this); + AutoUnprotectCell unprotect1(lastProperty()); + AutoUnprotectCell unprotect2(lastProperty()->base()); return static_cast(getReservedSlot(SOURCE_SLOT).toPrivate()); } @@ -469,10 +482,31 @@ class JSScript : public js::gc::BarrieredCell js::Bindings bindings; /* names of top-level variables in this script (and arguments if this is a function script) */ + bool getHasAnyAliasedBindings() const { + js::AutoUnprotectCell unprotect(this); + return bindings.hasAnyAliasedBindings(); + } + + js::Binding *bindingArray() const { + js::AutoUnprotectCell unprotect(this); + return bindings.bindingArray(); + } + + unsigned numArgs() const { + js::AutoUnprotectCell unprotect(this); + return bindings.numArgs(); + } + // Word-sized fields. public: jsbytecode *code; /* bytecodes and their immediate operands */ + + jsbytecode *getCode() { + js::AutoUnprotectCell unprotect(this); + return code; + } + uint8_t *data; /* pointer to variable-length data array (see comment above Create() for details) */ @@ -510,20 +544,46 @@ class JSScript : public js::gc::BarrieredCell public: uint32_t length; /* length of code vector */ + uint32_t getLength() { + js::AutoUnprotectCell unprotect(this); + return length; + } + uint32_t dataSize; /* size of the used part of the data array */ uint32_t lineno; /* base line number of script */ + + uint32_t getLineno() { + js::AutoUnprotectCell unprotect(this); + return lineno; + } + uint32_t column; /* base column of script, optionally set */ uint32_t mainOffset; /* offset of main entry point from code, after predef'ing prolog */ + uint32_t getMainOffset() { + js::AutoUnprotectCell unprotect(this); + return mainOffset; + } + uint32_t natoms; /* length of atoms array */ /* Range of characters in scriptSource which contains this script's source. */ uint32_t sourceStart; uint32_t sourceEnd; + uint32_t getSourceStart() { + js::AutoUnprotectCell unprotect(this); + return sourceStart; + } + + uint32_t getSourceEnd() { + js::AutoUnprotectCell unprotect(this); + return sourceEnd; + } + private: uint32_t useCount; /* Number of times the script has been called * or has had backedges taken. Reset if the @@ -549,10 +609,26 @@ class JSScript : public js::gc::BarrieredCell uint16_t nfixed; /* number of slots besides stack operands in slot array */ + uint16_t getNfixed() { + js::AutoUnprotectCell unprotect(this); + return nfixed; + } + uint16_t nTypeSets; /* number of type sets used in this script for dynamic type monitoring */ + uint16_t getNumTypeSets() { + js::AutoUnprotectCell unprotect(this); + return nTypeSets; + } + uint16_t nslots; /* vars plus maximum stack depth */ + + uint16_t getNslots() { + js::AutoUnprotectCell unprotect(this); + return nslots; + } + uint16_t staticLevel;/* static level for display maintenance */ // Bit fields. @@ -584,20 +660,62 @@ class JSScript : public js::gc::BarrieredCell public: bool noScriptRval:1; /* no need for result value of last expression statement */ + + bool getNoScriptRval() const { + js::AutoUnprotectCell unprotect(this); + return noScriptRval; + } + bool savedCallerFun:1; /* can call getCallerFunction() */ bool strict:1; /* code is in strict mode */ + + bool getStrict() const { + js::AutoUnprotectCell unprotect(this); + return strict; + } + bool explicitUseStrict:1; /* code has "use strict"; explicitly */ bool compileAndGo:1; /* see Parser::compileAndGo */ + + bool getCompileAndGo() const { + js::AutoUnprotectCell unprotect(this); + return compileAndGo; + } + bool selfHosted:1; /* see Parser::selfHostingMode */ bool bindingsAccessedDynamically:1; /* see FunctionContextFlags */ bool funHasExtensibleScope:1; /* see FunctionContextFlags */ + + bool getFunHasExtensibleScope() const { + js::AutoUnprotectCell unprotect(this); + return funHasExtensibleScope; + } + bool funNeedsDeclEnvObject:1; /* see FunctionContextFlags */ + + bool getFunNeedsDeclEnvObject() const { + js::AutoUnprotectCell unprotect(this); + return funNeedsDeclEnvObject; + } + bool funHasAnyAliasedFormal:1; /* true if any formalIsAliased(i) */ + + bool getFunHasAnyAliasedFormal() const { + js::AutoUnprotectCell unprotect(this); + return funHasAnyAliasedFormal; + } + bool warnedAboutUndefinedProp:1; /* have warned about uses of undefined properties in this script */ bool hasSingletons:1; /* script has singleton objects */ bool treatAsRunOnce:1; /* script is a lambda to treat as running once. */ + + bool getTreatAsRunOnce() const { + js::AutoUnprotectCell unprotect(this); + return treatAsRunOnce; + } + bool hasRunOnce:1; /* if treatAsRunOnce, whether script has executed. */ bool hasBeenCloned:1; /* script has been reused for a clone. */ bool isActiveEval:1; /* script came from eval(), and is still active */ @@ -609,25 +727,65 @@ class JSScript : public js::gc::BarrieredCell // Both 'arguments' and f.apply() are used. This is likely to be a wrapper. bool usesArgumentsAndApply:1; + bool getUsesArgumentsAndApply() const { + js::AutoUnprotectCell unprotect(this); + return usesArgumentsAndApply; + } + /* script is attempted to be cloned anew at each callsite. This is temporarily needed for ParallelArray selfhosted code until type information can be made context sensitive. See discussion in bug 826148. */ bool shouldCloneAtCallsite:1; + + bool getShouldCloneAtCallsite() const { + js::AutoUnprotectCell unprotect(this); + return shouldCloneAtCallsite; + } + bool isCallsiteClone:1; /* is a callsite clone; has a link to the original function */ bool shouldInline:1; /* hint to inline when possible */ + + bool getShouldInline() const { + js::AutoUnprotectCell unprotect(this); + return shouldInline; + } + bool uninlineable:1; /* explicitly marked as uninlineable */ -#ifdef JS_ION + + bool getUninlineable() const { + js::AutoUnprotectCell unprotect(this); + return uninlineable; + } + bool failedBoundsCheck:1; /* script has had hoisted bounds checks fail */ + + bool getFailedBoundsCheck() const { + js::AutoUnprotectCell unprotect(this); + return failedBoundsCheck; + } + bool failedShapeGuard:1; /* script has had hoisted shape guard fail */ + + bool getFailedShapeGuard() const { + js::AutoUnprotectCell unprotect(this); + return failedShapeGuard; + } + bool hadFrequentBailouts:1; -#else - bool failedBoundsCheckPad:1; - bool failedShapeGuardPad:1; - bool hadFrequentBailoutsPad:1; -#endif + + bool getHadFrequentBailouts() const { + js::AutoUnprotectCell unprotect(this); + return hadFrequentBailouts; + } + bool invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */ + bool getInvalidatedIdempotentCache() const { + js::AutoUnprotectCell unprotect(this); + return invalidatedIdempotentCache; + } + // If the generator was created implicitly via a generator expression, // isGeneratorExp will be true. bool isGeneratorExp:1; @@ -678,11 +836,14 @@ class JSScript : public js::gc::BarrieredCell void setVersion(JSVersion v) { version = v; } /* See ContextFlags::funArgumentsHasLocalBinding comment. */ - bool argumentsHasVarBinding() const { return argsHasVarBinding_; } + bool argumentsHasVarBinding() const { + js::AutoUnprotectCell unprotect(this); + return argsHasVarBinding_; + } jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; } void setArgumentsHasVarBinding(); bool argumentsAliasesFormals() const { - return argumentsHasVarBinding() && !strict; + return argumentsHasVarBinding() && !getStrict(); } js::GeneratorKind generatorKind() const { @@ -709,7 +870,10 @@ class JSScript : public js::gc::BarrieredCell * that needsArgsObj is only called after the script has been analyzed. */ bool analyzedArgsUsage() const { return !needsArgsAnalysis_; } - bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; } + bool needsArgsObj() const { + js::AutoUnprotectCell unprotect(this); + JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; + } void setNeedsArgsObj(bool needsArgsObj); static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script); @@ -723,7 +887,7 @@ class JSScript : public js::gc::BarrieredCell * opcodes won't be emitted at all. */ bool argsObjAliasesFormals() const { - return needsArgsObj() && !strict; + return needsArgsObj() && !getStrict(); } bool hasAnyIonScript() const { @@ -734,6 +898,7 @@ class JSScript : public js::gc::BarrieredCell return ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT; } bool canIonCompile() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); return ion != ION_DISABLED_SCRIPT; } @@ -759,6 +924,7 @@ class JSScript : public js::gc::BarrieredCell } bool hasBaselineScript() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); return baseline && baseline != BASELINE_DISABLED_SCRIPT; } bool canBaselineCompile() const { @@ -766,6 +932,7 @@ class JSScript : public js::gc::BarrieredCell } js::jit::BaselineScript *baselineScript() const { JS_ASSERT(hasBaselineScript()); + js::AutoUnprotectCellUnderCompilationLock unprotect(this); return baseline; } inline void setBaselineScript(js::jit::BaselineScript *baselineScript); @@ -777,6 +944,7 @@ class JSScript : public js::gc::BarrieredCell } bool canParallelIonCompile() const { + js::AutoUnprotectCellUnderCompilationLock unprotect(this); return parallelIon != ION_DISABLED_SCRIPT; } @@ -817,7 +985,10 @@ class JSScript : public js::gc::BarrieredCell * Original compiled function for the script, if it has a function. * nullptr for global and eval scripts. */ - JSFunction *function() const { return function_; } + JSFunction *function() const { + js::AutoUnprotectCell unprotect(this); + return function_; + } inline void setFunction(JSFunction *fun); JSFunction *originalFunction() const; @@ -831,7 +1002,10 @@ class JSScript : public js::gc::BarrieredCell js::ScriptSourceObject *sourceObject() const; js::ScriptSource *scriptSource() const { return sourceObject()->source(); } JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); } - const char *filename() const { return scriptSource()->filename(); } + const char *filename() const { + js::AutoUnprotectCell unprotect(this); + return scriptSource()->filename(); + } public: @@ -865,6 +1039,7 @@ class JSScript : public js::gc::BarrieredCell /* See StaticScopeIter comment. */ JSObject *enclosingStaticScope() const { + js::AutoUnprotectCell unprotect(this); if (isCallsiteClone) return nullptr; return enclosingScopeOrOriginalFunction_; @@ -887,7 +1062,11 @@ class JSScript : public js::gc::BarrieredCell bool makeAnalysis(JSContext *cx); public: - uint32_t getUseCount() const { return useCount; } + uint32_t getUseCount() const { + // Note: We ignore races when reading the use count of a script off thread. + js::AutoUnprotectCell unprotect(this); + return useCount; + } uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; } uint32_t *addressOfUseCount() { return &useCount; } static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); } @@ -917,10 +1096,14 @@ class JSScript : public js::gc::BarrieredCell uint32_t numNotes(); /* Number of srcnote slots in the srcnotes section */ /* Script notes are allocated right after the code. */ - jssrcnote *notes() { return (jssrcnote *)(code + length); } + jssrcnote *notes() { return (jssrcnote *)(getCode() + getLength()); } - bool hasArray(ArrayKind kind) { return (hasArrayBits & (1 << kind)); } - void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); } + bool hasArray(ArrayKind kind) { + js::AutoUnprotectCell unprotect(this); + return (hasArrayBits & (1 << kind)); + } + + void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); } void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; } bool hasConsts() { return hasArray(CONSTS); } @@ -939,21 +1122,25 @@ class JSScript : public js::gc::BarrieredCell js::ConstArray *consts() { JS_ASSERT(hasConsts()); + js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + constsOffset()); } js::ObjectArray *objects() { JS_ASSERT(hasObjects()); + js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + objectsOffset()); } js::ObjectArray *regexps() { JS_ASSERT(hasRegexps()); + js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + regexpsOffset()); } js::TryNoteArray *trynotes() { JS_ASSERT(hasTrynotes()); + js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + trynotesOffset()); } @@ -965,6 +1152,7 @@ class JSScript : public js::gc::BarrieredCell bool hasLoops(); js::HeapPtrAtom &getAtom(size_t index) const { + js::AutoUnprotectCell unprotect(this); JS_ASSERT(index < natoms); return atoms[index]; } @@ -984,6 +1172,7 @@ class JSScript : public js::gc::BarrieredCell } JSObject *getObject(size_t index) { + js::AutoUnprotectCell unprotect(this); js::ObjectArray *arr = objects(); JS_ASSERT(index < arr->length); return arr->vector[index]; @@ -1316,6 +1505,7 @@ class LazyScript : public gc::BarrieredCell } bool usesArgumentsAndApply() const { + AutoUnprotectCell unprotect(this); return usesArgumentsAndApply_; } void setUsesArgumentsAndApply() { @@ -1340,9 +1530,11 @@ class LazyScript : public gc::BarrieredCell return sourceObject()->source(); } uint32_t begin() const { + AutoUnprotectCell unprotect(this); return begin_; } uint32_t end() const { + AutoUnprotectCell unprotect(this); return end_; } uint32_t lineno() const { diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index cce910b7863b..0eb228519010 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -26,9 +26,9 @@ Bindings::Bindings() inline AliasedFormalIter::AliasedFormalIter(JSScript *script) - : begin_(script->bindings.bindingArray()), + : begin_(script->bindingArray()), p_(begin_), - end_(begin_ + (script->funHasAnyAliasedFormal ? script->bindings.numArgs() : 0)), + end_(begin_ + (script->getFunHasAnyAliasedFormal() ? script->numArgs() : 0)), slot_(CallObject::RESERVED_SLOTS) { settle(); @@ -98,6 +98,7 @@ JSScript::global() const * A JSScript always marks its compartment's global (via bindings) so we * can assert that maybeGlobal is non-null here. */ + js::AutoUnprotectCell unprotect(this); return *compartment()->maybeGlobal(); } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 898035495fba..a45a66fb1ef1 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -4093,7 +4093,8 @@ CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32_t *resul if (!s2) return false; - return CompareChars(s1, str1->length(), s2, str2->length(), result); + *result = CompareChars(s1, str1->length(), s2, str2->length()); + return true; } bool @@ -4102,6 +4103,14 @@ js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *resul return CompareStringsImpl(cx, str1, str2, result); } +int32_t +js::CompareAtoms(JSAtom *atom1, JSAtom *atom2) +{ + AutoUnprotectCell unprotect1(atom1); + AutoUnprotectCell unprotect2(atom2); + return CompareChars(atom1->chars(), atom1->length(), atom2->chars(), atom2->length()); +} + bool js::StringEqualsAscii(JSLinearString *str, const char *asciiBytes) { diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 504b7bd67a56..1f8286f9331d 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -48,19 +48,16 @@ SkipSpace(const jschar *s, const jschar *end) // Return less than, equal to, or greater than zero depending on whether // s1 is less than, equal to, or greater than s2. -inline bool -CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2, int32_t *result) +inline int32_t +CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2) { size_t n = Min(l1, l2); for (size_t i = 0; i < n; i++) { - if (int32_t cmp = s1[i] - s2[i]) { - *result = cmp; - return true; - } + if (int32_t cmp = s1[i] - s2[i]) + return cmp; } - *result = (int32_t)(l1 - l2); - return true; + return (int32_t)(l1 - l2); } } /* namespace js */ @@ -210,6 +207,9 @@ EqualStrings(JSLinearString *str1, JSLinearString *str2); extern bool CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result); +int32_t +CompareAtoms(JSAtom *atom1, JSAtom *atom2); + /* * Return true if the string matches the given sequence of ASCII bytes. */ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 9d64c2575ccc..c8b7ed6eb721 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5429,6 +5429,9 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op) if (op->getBoolOption("ion-check-range-analysis")) jit::js_IonOptions.checkRangeAnalysis = true; + if (op->getBoolOption("ion-check-thread-safety")) + jit::js_IonOptions.checkThreadSafety = true; + if (const char *str = op->getStringOption("ion-inlining")) { if (strcmp(str, "on") == 0) jit::js_IonOptions.inlining = true; @@ -5740,6 +5743,8 @@ main(int argc, char **argv, char **envp) "Range analysis (default: on, off to disable)") || !op.addBoolOption('\0', "ion-check-range-analysis", "Range analysis checking") + || !op.addBoolOption('\0', "ion-check-thread-safety", + "Builder thread safety checking") || !op.addStringOption('\0', "ion-inlining", "on/off", "Inline methods where possible (default: on, off to disable)") || !op.addStringOption('\0', "ion-osr", "on/off", @@ -5833,8 +5838,15 @@ main(int argc, char **argv, char **envp) if (!JS_Init()) return 1; + // When doing thread safety checks for VM accesses made during Ion compilation, + // we rely on protected memory and only the main thread should be active. + JSUseHelperThreads useHelperThreads = + op.getBoolOption("ion-check-thread-safety") + ? JS_NO_HELPER_THREADS + : JS_USE_HELPER_THREADS; + /* Use the same parameters as the browser in xpcjsruntime.cpp. */ - rt = JS_NewRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS); + rt = JS_NewRuntime(32L * 1024L * 1024L, useHelperThreads); if (!rt) return 1; gTimeoutFunc = NullValue(); diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index cbe9ee03d224..8f83d8ecd812 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -153,8 +153,9 @@ class GlobalObject : public JSObject public: Value getConstructor(JSProtoKey key) const { + AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(key <= JSProto_LIMIT); - return getSlot(APPLICATION_SLOTS + key); + return getSlotRefForCompilation(APPLICATION_SLOTS + key); } void setConstructor(JSProtoKey key, const Value &v) { @@ -163,8 +164,9 @@ class GlobalObject : public JSObject } Value getPrototype(JSProtoKey key) const { + AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(key <= JSProto_LIMIT); - return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key); + return getSlotRefForCompilation(APPLICATION_SLOTS + JSProto_LIMIT + key); } void setPrototype(JSProtoKey key, const Value &value) { @@ -348,6 +350,7 @@ class GlobalObject : public JSObject } JSObject *maybeGetArrayPrototype() { + AutoUnprotectCellUnderCompilationLock unprotect(this); if (arrayClassInitialized()) return &getPrototype(JSProto_Array).toObject(); return nullptr; @@ -462,6 +465,18 @@ class GlobalObject : public JSObject return &self->getSlot(slot).toObject(); } + const HeapSlot &getSlotRefForCompilation(uint32_t slot) const { + // This method should only be used for slots that are either eagerly + // initialized on creation of the global or only change under the + // compilation lock. Note that the dynamic slots pointer for global + // objects can only change under the compilation lock. + JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(getClass())); + uint32_t fixed = numFixedSlotsForCompilation(); + if (slot < fixed) + return fixedSlots()[slot]; + return slots[slot - fixed]; + } + public: JSObject *getOrCreateIteratorPrototype(JSContext *cx) { return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_LIMIT + JSProto_Iterator, @@ -512,12 +527,18 @@ class GlobalObject : public JSObject } JSObject *intrinsicsHolder() { - JS_ASSERT(!getSlotRef(INTRINSICS).isUndefined()); - return &getSlotRef(INTRINSICS).toObject(); + AutoUnprotectCellUnderCompilationLock unprotect(this); + JS_ASSERT(!getSlotRefForCompilation(INTRINSICS).isUndefined()); + return &getSlotRefForCompilation(INTRINSICS).toObject(); } bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) { JSObject *holder = intrinsicsHolder(); + + AutoUnprotectCellUnderCompilationLock unprotect0(holder); + AutoUnprotectCellUnderCompilationLock unprotect1(holder->lastProperty()); + AutoUnprotectCellUnderCompilationLock unprotect2(holder->lastProperty()->base()); + if (Shape *shape = holder->nativeLookupPure(name)) { *vp = holder->getSlot(shape->slot()); return true; @@ -550,8 +571,10 @@ class GlobalObject : public JSObject unsigned nargs, MutableHandleValue funVal); RegExpStatics *getRegExpStatics() const { - JSObject &resObj = getSlot(REGEXP_STATICS).toObject(); - return static_cast(resObj.getPrivate()); + AutoUnprotectCellUnderCompilationLock unprotect0(this); + JSObject &resObj = getSlotRefForCompilation(REGEXP_STATICS).toObject(); + AutoUnprotectCell unprotect1(&resObj); + return static_cast(resObj.getPrivate(/* nfixed = */ 1)); } JSObject *getThrowTypeError() const { @@ -578,9 +601,10 @@ class GlobalObject : public JSObject // in which |obj| was created, if no prior warning was given. static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj); - const Value &getOriginalEval() const { - JS_ASSERT(getSlot(EVAL).isObject()); - return getSlot(EVAL); + Value getOriginalEval() const { + AutoUnprotectCellUnderCompilationLock unprotect(this); + JS_ASSERT(getSlotRefForCompilation(EVAL).isObject()); + return getSlotRefForCompilation(EVAL); } // Implemented in jsiter.cpp. @@ -765,7 +789,7 @@ template<> inline bool JSObject::is() const { - return !!(js::GetObjectClass(const_cast(this))->flags & JSCLASS_IS_GLOBAL); + return !!(getClass()->flags & JSCLASS_IS_GLOBAL); } #endif /* vm_GlobalObject_h */ diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index 00276cd204ea..da57ba4a209e 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -334,6 +334,25 @@ js::ObjectImpl::nativeLookupPure(jsid id) return Shape::searchNoHashify(lastProperty(), id); } +uint32_t +js::ObjectImpl::numFixedSlotsForCompilation() const +{ + // This is an alternative method for getting the number of fixed slots + // in an object. It requires more logic and memory accesses than + // numFixedSlots() but is safe to be called from the compilation thread, + // even if the main thread is actively mutating the VM. + if (static_cast(this)->is()) + return 0; +#ifdef JSGC_GENERATIONAL + // The compiler does not have access to nursery things, so if this object + // is in the nursery we can fall back to numFixedSlots(). + if (!isTenured()) + return numFixedSlots(); +#endif + gc::AllocKind kind = tenuredGetAllocKind(); + return gc::GetGCKindSlots(kind, getClass()); +} + void js::ObjectImpl::markChildren(JSTracer *trc) { diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index d4af46f472b7..8319a8ca88ca 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -980,11 +980,19 @@ class ObjectImpl : public gc::BarrieredCell public: JSObject * getProto() const { - return type_->proto; + AutoUnprotectCellUnderCompilationLock unprotect0(this); + return type_->getProto(); } const Class *getClass() const { - return type_->clasp; + AutoUnprotectCellUnderCompilationLock unprotect0(this); + return type_->getClass(); + } + + const Class *getClassImmutable() { + // For use on objects which cannot be modified after construction. + AutoUnprotectCell unprotect(this); + return type_->getClass(); } static inline bool @@ -1027,10 +1035,18 @@ class ObjectImpl : public gc::BarrieredCell JS_ASSERT(isNative()); return getElementsHeader()->initializedLength; } + uint32_t getDenseInitializedLengthForCompilation() { + // Note: isNative() generally can't be safely called off thread. + return getElementsHeader()->initializedLength; + } uint32_t getDenseCapacity() { JS_ASSERT(isNative()); return getElementsHeader()->capacity; } + uint32_t getDenseCapacityForCompilation() { + // Note: isNative() generally can't be safely called off thread. + return getElementsHeader()->capacity; + } bool makeElementsSparse(JSContext *cx) { JS_NEW_OBJECT_REPRESENTATION_ONLY(); @@ -1194,6 +1210,7 @@ class ObjectImpl : public gc::BarrieredCell types::TypeObject *type() const { MOZ_ASSERT(!hasLazyType()); + AutoUnprotectCellUnderCompilationLock unprotect(this); return type_; } @@ -1201,17 +1218,26 @@ class ObjectImpl : public gc::BarrieredCell return reinterpret_cast(this)->numFixedSlots(); } + uint32_t numFixedSlotsForCompilation() const; + /* * Whether this is the only object which has its specified type. This * object will have its type constructed lazily as needed by analysis. */ - bool hasSingletonType() const { return !!type_->singleton; } + bool hasSingletonType() const { + AutoUnprotectCellUnderCompilationLock unprotect0(this); + AutoUnprotectCellUnderCompilationLock unprotect1(type_); + return !!type_->singleton; + } /* * Whether the object's type has not been constructed yet. If an object * might have a lazy type, use getType() below, otherwise type(). */ - bool hasLazyType() const { return type_->lazy(); } + bool hasLazyType() const { + AutoUnprotectCellUnderCompilationLock unprotect(this); + return type_->lazy(); + } uint32_t slotSpan() const { if (inDictionaryMode()) @@ -1368,7 +1394,7 @@ class ObjectImpl : public gc::BarrieredCell } const Value &getFixedSlot(uint32_t slot) const { - MOZ_ASSERT(slot < numFixedSlots()); + MOZ_ASSERT(slot < numFixedSlotsForCompilation()); return fixedSlots()[slot]; } @@ -1465,7 +1491,7 @@ class ObjectImpl : public gc::BarrieredCell * Private pointers are stored immediately after the last fixed slot of * the object. */ - MOZ_ASSERT(nfixed == numFixedSlots()); + MOZ_ASSERT(nfixed == numFixedSlotsForCompilation()); MOZ_ASSERT(hasPrivate()); HeapSlot *end = &fixedSlots()[nfixed]; return *reinterpret_cast(end); @@ -1539,6 +1565,10 @@ JS_ALWAYS_INLINE Zone * BarrieredCell::zoneFromAnyThread() const { const ObjectImpl* obj = static_cast(this); + + // If accesses to this object are permitted then so are accesses to its zone. + AutoUnprotectCell unprotect(obj->shape_); + return obj->shape_->zoneFromAnyThread(); } diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index 41b569aac345..a4c492b4e158 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -412,10 +412,10 @@ class RegExpObject : public JSObject setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled)); } - bool ignoreCase() const { return getSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); } - bool global() const { return getSlot(GLOBAL_FLAG_SLOT).toBoolean(); } - bool multiline() const { return getSlot(MULTILINE_FLAG_SLOT).toBoolean(); } - bool sticky() const { return getSlot(STICKY_FLAG_SLOT).toBoolean(); } + bool ignoreCase() const { return getFixedSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); } + bool global() const { return getFixedSlot(GLOBAL_FLAG_SLOT).toBoolean(); } + bool multiline() const { return getFixedSlot(MULTILINE_FLAG_SLOT).toBoolean(); } + bool sticky() const { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); } void shared(RegExpGuard *g) const { JS_ASSERT(maybeShared() != nullptr); diff --git a/js/src/vm/Runtime-inl.h b/js/src/vm/Runtime-inl.h index cfae42c3acbf..ca6e3484768c 100644 --- a/js/src/vm/Runtime-inl.h +++ b/js/src/vm/Runtime-inl.h @@ -47,7 +47,12 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi Entry *entry = &entries[entry_]; JSObject *templateObj = reinterpret_cast(&entry->templateObject); - if (templateObj->type()->isLongLivedForCachedAlloc()) + + // Do an end run around JSObject::type() to avoid doing AutoUnprotectCell + // on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread. + types::TypeObject *type = templateObj->type_; + + if (type->isLongLivedForCachedAlloc()) heap = gc::TenuredHeap; JSObject *obj = js_NewGCObject(cx, entry->kind, heap); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 64b294ea9026..0f5219db8247 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -15,6 +15,10 @@ #include #include +#if defined(DEBUG) && !defined(XP_WIN) +# include +#endif + #include "jsatom.h" #include "jsdtoa.h" #include "jsgc.h" @@ -262,6 +266,7 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) decimalSeparator(0), numGrouping(0), #endif + heapProtected_(false), mathCache_(nullptr), activeCompilations_(0), keepAtoms_(0), @@ -788,6 +793,76 @@ JSRuntime::activeGCInAtomsZone() return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted(); } +#if defined(DEBUG) && !defined(XP_WIN) + +AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) + : runtime(rt) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + + JS_ASSERT(!runtime->heapProtected_); + runtime->heapProtected_ = true; + + for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) { + Chunk *chunk = r.front(); + // Note: Don't protect the last page in the chunk, which stores + // immutable info and needs to be accessible for runtimeFromAnyThread() + // in AutoUnprotectCell. + if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_NONE)) + MOZ_CRASH(); + } +} + +AutoProtectHeapForCompilation::~AutoProtectHeapForCompilation() +{ + JS_ASSERT(runtime->heapProtected_); + JS_ASSERT(runtime->unprotectedArenas.empty()); + runtime->heapProtected_ = false; + + for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) { + Chunk *chunk = r.front(); + if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_READ | PROT_WRITE)) + MOZ_CRASH(); + } +} + +AutoUnprotectCell::AutoUnprotectCell(const Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) + : runtime(cell->runtimeFromAnyThread()), arena(nullptr) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + + if (!runtime->heapProtected_) + return; + + ArenaHeader *base = cell->arenaHeader(); + for (size_t i = 0; i < runtime->unprotectedArenas.length(); i++) { + if (base == runtime->unprotectedArenas[i]) + return; + } + + arena = base; + + if (mprotect(arena, sizeof(Arena), PROT_READ | PROT_WRITE)) + MOZ_CRASH(); + + if (!runtime->unprotectedArenas.append(arena)) + MOZ_CRASH(); +} + +AutoUnprotectCell::~AutoUnprotectCell() +{ + if (!arena) + return; + + if (mprotect(arena, sizeof(Arena), PROT_NONE)) + MOZ_CRASH(); + + JS_ASSERT(arena == runtime->unprotectedArenas.back()); + runtime->unprotectedArenas.popBack(); +} + +#endif // DEBUG && !XP_WIN + #ifdef JS_WORKER_THREADS void diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index eb76993eb61e..7f5d6fad3e5e 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -677,6 +677,7 @@ class MarkingValidator; typedef Vector ZoneVector; class AutoLockForExclusiveAccess; +class AutoProtectHeapForCompilation; void RecomputeStackLimit(JSRuntime *rt, StackKind kind); @@ -1430,6 +1431,19 @@ struct JSRuntime : public JS::shadow::Runtime, const char *numGrouping; #endif + private: + friend class js::AutoProtectHeapForCompilation; + friend class js::AutoUnprotectCell; + mozilla::DebugOnly heapProtected_; +#ifdef DEBUG + js::Vector unprotectedArenas; + + public: + bool heapProtected() { + return heapProtected_; + } +#endif + private: js::MathCache *mathCache_; js::MathCache *createMathCache(JSContext *cx); @@ -2016,6 +2030,23 @@ class RuntimeAllocPolicy extern const JSSecurityCallbacks NullSecurityCallbacks; +class AutoProtectHeapForCompilation +{ + public: +#if defined(DEBUG) && !defined(XP_WIN) + JSRuntime *runtime; + + AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~AutoProtectHeapForCompilation(); +#else + AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } +#endif + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + } /* namespace js */ #ifdef _MSC_VER diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index cfb878a9038c..e72d0731df2d 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -74,9 +74,12 @@ StaticScopeIter::scopeShape() const { JS_ASSERT(hasDynamicScopeObject()); JS_ASSERT(type() != NAMED_LAMBDA); - return type() == BLOCK - ? block().lastProperty() - : funScript()->bindings.callObjShape(); + if (type() == BLOCK) { + AutoUnprotectCell unprotect(&block()); + return block().lastProperty(); + } + AutoUnprotectCell unprotect(funScript()); + return funScript()->bindings.callObjShape(); } template diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 7686b7121229..ddae036e96b3 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -35,7 +35,7 @@ typedef Rooted RootedArgumentsObject; static JSObject * InnermostStaticScope(JSScript *script, jsbytecode *pc) { - JS_ASSERT(pc >= script->code && pc < script->code + script->length); + JS_ASSERT(pc >= script->getCode() && pc < script->getCode() + script->getLength()); JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t)); @@ -68,7 +68,7 @@ js::ScopeCoordinateName(JSScript *script, jsbytecode *pc) ScopeCoordinate sc(pc); while (r.front().slot() != sc.slot) r.popFront(); - jsid id = r.front().propid(); + jsid id = r.front().propidRaw(); /* Beware nameless destructuring formal. */ if (!JSID_IS_ATOM(id)) diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 3c65f296e184..6f50e88a854d 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -181,7 +181,8 @@ class ScopeObject : public JSObject * enclosing scope of a ScopeObject is necessarily non-null. */ inline JSObject &enclosingScope() const { - return getReservedSlot(SCOPE_CHAIN_SLOT).toObject(); + AutoUnprotectCell unprotect(this); + return getFixedSlot(SCOPE_CHAIN_SLOT).toObject(); } void setEnclosingScope(HandleObject obj); @@ -232,10 +233,11 @@ class CallObject : public ScopeObject /* True if this is for a strict mode eval frame. */ bool isForEval() const { - JS_ASSERT(getReservedSlot(CALLEE_SLOT).isObjectOrNull()); - JS_ASSERT_IF(getReservedSlot(CALLEE_SLOT).isObject(), - getReservedSlot(CALLEE_SLOT).toObject().is()); - return getReservedSlot(CALLEE_SLOT).isNull(); + AutoUnprotectCell unprotect(this); + JS_ASSERT(getFixedSlot(CALLEE_SLOT).isObjectOrNull()); + JS_ASSERT_IF(getFixedSlot(CALLEE_SLOT).isObject(), + getFixedSlot(CALLEE_SLOT).toObject().is()); + return getFixedSlot(CALLEE_SLOT).isNull(); } /* @@ -243,7 +245,8 @@ class CallObject : public ScopeObject * only be called if !isForEval.) */ JSFunction &callee() const { - return getReservedSlot(CALLEE_SLOT).toObject().as(); + AutoUnprotectCell unprotect(this); + return getFixedSlot(CALLEE_SLOT).toObject().as(); } /* Get/set the aliased variable referred to by 'bi'. */ @@ -333,7 +336,7 @@ class BlockObject : public NestedScopeObject /* Return the number of variables associated with this block. */ uint32_t slotCount() const { - return propertyCount(); + return propertyCountForCompilation(); } /* @@ -368,7 +371,8 @@ class StaticBlockObject : public BlockObject /* See StaticScopeIter comment. */ JSObject *enclosingStaticScope() const { - return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull(); + AutoUnprotectCell unprotect(this); + return getFixedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull(); } /* @@ -398,7 +402,10 @@ class StaticBlockObject : public BlockObject * variable of the block isAliased. */ bool needsClone() { - return !slotValue(0).isFalse(); + // The first variable slot will always indicate whether the object has + // any aliased vars. Bypass slotValue() to allow testing this off thread. + AutoUnprotectCell unprotect(this); + return !getFixedSlot(RESERVED_SLOTS).isFalse(); } /* Frontend-only functions ***********************************************/ diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 6b2313b74623..111b452f91f7 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -194,7 +194,7 @@ ShapeTable::search(jsid id, bool adding) /* Hit: return entry. */ shape = SHAPE_CLEAR_COLLISION(stored); - if (shape && shape->propid() == id) + if (shape && shape->propidRaw() == id) return spp; /* Collision: double hash. */ diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 975035b91424..0cbf05452e35 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1033,11 +1033,15 @@ class Shape : public gc::BarrieredCell void popFront() { JS_ASSERT(!empty()); + AutoUnprotectCell unprotect(cursor); cursor = cursor->parent; } }; - const Class *getObjectClass() const { return base()->clasp; } + const Class *getObjectClass() const { + AutoUnprotectCell unprotect(base()); + return base()->clasp; + } JSObject *getObjectParent() const { return base()->parent; } JSObject *getObjectMetadata() const { return base()->metadata; } @@ -1094,12 +1098,15 @@ class Shape : public gc::BarrieredCell PUBLIC_FLAGS = HAS_SHORTID }; - bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; } + bool inDictionary() const { + AutoUnprotectCell unprotect(this); + return (flags & IN_DICTIONARY) != 0; + } unsigned getFlags() const { return flags & PUBLIC_FLAGS; } bool hasShortID() const { return (flags & HAS_SHORTID) != 0; } PropertyOp getter() const { return base()->rawGetter; } - bool hasDefaultGetter() const { return !base()->rawGetter; } + bool hasDefaultGetter() const { return !base()->rawGetter; } PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; } JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return base()->getterObj; } @@ -1157,21 +1164,35 @@ class Shape : public gc::BarrieredCell BaseShape *base() const { return base_.get(); } - bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; } + bool hasSlot() const { + AutoUnprotectCell unprotect(this); + return (attrs & JSPROP_SHARED) == 0; + } uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); } - uint32_t maybeSlot() const { return slotInfo & SLOT_MASK; } + uint32_t maybeSlot() const { + // Note: Reading a shape's slot off thread can race against main thread + // updates to the number of linear searches on the shape, which is + // stored in the same slotInfo field. We tolerate this. + AutoUnprotectCell unprotect(this); + return slotInfo & SLOT_MASK; + } bool isEmptyShape() const { + AutoUnprotectCell unprotect(this); JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot()); return JSID_IS_EMPTY(propid_); } - uint32_t slotSpan() const { + uint32_t slotSpan(const Class *clasp) const { JS_ASSERT(!inDictionary()); - uint32_t free = JSSLOT_FREE(getObjectClass()); + uint32_t free = JSSLOT_FREE(clasp); return hasMissingSlot() ? free : Max(free, maybeSlot() + 1); } + uint32_t slotSpan() const { + return slotSpan(getObjectClass()); + } + void setSlot(uint32_t slot) { JS_ASSERT(slot <= SHAPE_INVALID_SLOT); slotInfo = slotInfo & ~Shape::SLOT_MASK; @@ -1179,6 +1200,8 @@ class Shape : public gc::BarrieredCell } uint32_t numFixedSlots() const { + // Note: The same race applies here as in maybeSlot(). + AutoUnprotectCell unprotect(this); return (slotInfo >> FIXED_SLOTS_SHIFT); } @@ -1200,12 +1223,18 @@ class Shape : public gc::BarrieredCell } const EncapsulatedId &propid() const { + AutoUnprotectCell unprotect(this); JS_ASSERT(!isEmptyShape()); JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; } EncapsulatedId &propidRef() { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; } + jsid propidRaw() const { + AutoUnprotectCell unprotect(this); + return propid(); + } + int16_t shortid() const { JS_ASSERT(hasShortID()); return maybeShortid(); } int16_t maybeShortid() const { return shortid_; } @@ -1220,6 +1249,7 @@ class Shape : public gc::BarrieredCell bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; } bool writable() const { // JS_ASSERT(isDataDescriptor()); + AutoUnprotectCell unprotect(this); return (attrs & JSPROP_READONLY) == 0; } bool hasGetterValue() const { return attrs & JSPROP_GETTER; } @@ -1257,13 +1287,27 @@ class Shape : public gc::BarrieredCell if (hasTable()) return table().entryCount; - Shape *shape = this; uint32_t count = 0; - for (Shape::Range r(shape); !r.empty(); r.popFront()) + for (Shape::Range r(this); !r.empty(); r.popFront()) ++count; return count; } + uint32_t entryCountForCompilation() { + JS_ASSERT(!inDictionary()); + + uint32_t count = 0; + + for (Shape *shape = this; shape; ) { + AutoUnprotectCell unprotect(shape); + if (!shape->isEmptyShape()) + ++count; + shape = shape->parent; + } + + return count; + } + bool isBigEnoughForAShapeTable() { JS_ASSERT(!hasTable()); Shape *shape = this; @@ -1594,9 +1638,11 @@ Shape::searchLinear(jsid id) */ JS_ASSERT(!inDictionary()); - for (Shape *shape = this; shape; shape = shape->parent) { + for (Shape *shape = this; shape; ) { + AutoUnprotectCell unprotect(shape); if (shape->propidRef() == id) return shape; + shape = shape->parent; } return nullptr; diff --git a/js/src/vm/String.h b/js/src/vm/String.h index ea4b7ca43638..2004abe7192b 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -394,6 +394,7 @@ class JSString : public js::gc::BarrieredCell JS_ALWAYS_INLINE JSAtom &asAtom() const { + js::AutoUnprotectCell unprotect(this); JS_ASSERT(isAtom()); return *(JSAtom *)this; } @@ -1129,6 +1130,7 @@ JSString::base() const inline js::PropertyName * JSAtom::asPropertyName() { + js::AutoUnprotectCell unprotect(this); #ifdef DEBUG uint32_t dummy; JS_ASSERT(!isIndex(&dummy)); diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 848512a43dfc..ecb471521b42 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -326,9 +326,11 @@ class TypedArrayObject : public ArrayBufferViewObject return tarr->getFixedSlot(BYTEOFFSET_SLOT); } static Value byteLengthValue(TypedArrayObject *tarr) { + AutoUnprotectCellUnderCompilationLock unprotect(tarr); return tarr->getFixedSlot(BYTELENGTH_SLOT); } static Value lengthValue(TypedArrayObject *tarr) { + AutoUnprotectCellUnderCompilationLock unprotect(tarr); return tarr->getFixedSlot(LENGTH_SLOT); } @@ -346,9 +348,11 @@ class TypedArrayObject : public ArrayBufferViewObject } uint32_t type() const { + AutoUnprotectCell unprotect(this); return getFixedSlot(TYPE_SLOT).toInt32(); } void *viewData() const { + AutoUnprotectCellUnderCompilationLock unprotect(this); return static_cast(getPrivate(DATA_SLOT)); } From 2311502c50c50dba1b2e37eded007ccf0ac9823a Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Tue, 19 Nov 2013 14:17:13 -0800 Subject: [PATCH 015/268] Bug 935228 - Toggle debug traps only in debug mode. (r=jandem) --- js/src/jit/BaselineCompiler.cpp | 3 +++ js/src/jit/BaselineJIT.cpp | 4 ++++ js/src/jit/BaselineJIT.h | 13 ++++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 21f49248e635..4324968887f4 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -251,6 +251,9 @@ BaselineCompiler::compile() bytecodeMap[script->nTypeSets] = 0; } + if (script->compartment()->debugMode()) + baselineScript->setDebugMode(); + return Method_Compiled; } diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 2a1b6956924a..6ea55d9010f6 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -746,6 +746,10 @@ BaselineScript::toggleDebugTraps(JSScript *script, jsbytecode *pc) { JS_ASSERT(script->baselineScript() == this); + // Only scripts compiled for debug mode have toggled calls. + if (!debugMode()) + return; + SrcNoteLineScanner scanner(script->notes(), script->lineno); JSRuntime *rt = script->runtimeFromMainThread(); diff --git a/js/src/jit/BaselineJIT.h b/js/src/jit/BaselineJIT.h index d9c8960a4fce..473edf187112 100644 --- a/js/src/jit/BaselineJIT.h +++ b/js/src/jit/BaselineJIT.h @@ -132,7 +132,11 @@ struct BaselineScript // Flag set when the script contains any writes to its on-stack // (rather than call object stored) arguments. - MODIFIES_ARGUMENTS = 1 << 2 + MODIFIES_ARGUMENTS = 1 << 2, + + // Flag set when compiled for use for debug mode. Handles various + // Debugger hooks and compiles toggled calls for traps. + DEBUG_MODE = 1 << 3 }; private: @@ -201,6 +205,13 @@ struct BaselineScript return flags_ & MODIFIES_ARGUMENTS; } + void setDebugMode() { + flags_ |= DEBUG_MODE; + } + bool debugMode() const { + return flags_ & DEBUG_MODE; + } + uint32_t prologueOffset() const { return prologueOffset_; } From d772c95c75601736a8033f76e66c509b3b9e695f Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Tue, 19 Nov 2013 23:15:59 +0100 Subject: [PATCH 016/268] Bug 918880 - MaybeAllowOfflineAppByDefault must work on child processes, r=jduell --- content/base/public/nsContentUtils.h | 2 +- content/base/src/nsContentSink.cpp | 2 +- content/base/src/nsContentUtils.cpp | 20 +++--- dom/ipc/PBrowser.ipdl | 7 +++ dom/ipc/TabParent.cpp | 8 +++ dom/ipc/TabParent.h | 1 + uriloader/prefetch/nsIOfflineCacheUpdate.idl | 9 ++- uriloader/prefetch/nsOfflineCacheUpdate.h | 5 ++ .../prefetch/nsOfflineCacheUpdateService.cpp | 62 +++++++++++++++++++ 9 files changed, 101 insertions(+), 15 deletions(-) diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 1e8b5825fe0f..9cdf562889d0 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1456,7 +1456,7 @@ public: * If offline-apps.allow_by_default is true, we set offline-app permission * for the principal and return true. Otherwise false. */ - static bool MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal); + static bool MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, nsIDOMWindow *aWindow); /** * Increases the count of blockers preventing scripts from running. diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index 3d1a140e2dd9..0f21846b1f45 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -1064,7 +1064,7 @@ nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec) // Only continue if the document has permission to use offline APIs or // when preferences indicate to permit it automatically. if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal()) && - !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal()) && + !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal(), mDocument->GetWindow()) && !nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) { return; } diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 787a1d5fd2c7..5ef9ecdfac33 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -1426,7 +1426,8 @@ nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal) } bool -nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal) +nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, + nsIDOMWindow *aWindow) { if (!Preferences::GetRootBranch()) return false; @@ -1442,19 +1443,14 @@ nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal) if (!allowedByDefault) return false; - nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); - if (!permissionManager) + nsCOMPtr updateService = + do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); + if (!updateService) { return false; + } - rv = permissionManager->AddFromPrincipal( - aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION, - nsIPermissionManager::EXPIRE_NEVER, 0); - if (NS_FAILED(rv)) - return false; - - // We have added the permission - return true; + rv = updateService->AllowOfflineApp(aWindow, aPrincipal); + return NS_SUCCEEDED(rv); } // static diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 53d350f39b87..6e04131e71ed 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -258,6 +258,13 @@ parent: POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI, bool stickDocument); + /** + * Sets "offline-app" permission for the principal. Called when we hit + * a web app with the manifest attribute in and + * offline-apps.allow_by_default is set to true. + */ + SetOfflinePermission(Principal principal); + sync PIndexedDB(nsCString group, nsCString asciiOrigin) returns (bool allowed); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 9a06193e6890..465d04b21729 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1512,6 +1512,14 @@ TabParent::DeallocPOfflineCacheUpdateParent(mozilla::docshell::POfflineCacheUpda return true; } +bool +TabParent::RecvSetOfflinePermission(const IPC::Principal& aPrincipal) +{ + nsIPrincipal* principal = aPrincipal; + nsContentUtils::MaybeAllowOfflineAppByDefault(principal, nullptr); + return true; +} + bool TabParent::ShouldDelayDialogs() { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index eb67fbe060f6..87d43cc90026 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -234,6 +234,7 @@ public: const URIParams& aDocumentURI, const bool& stickDocument) MOZ_OVERRIDE; virtual bool DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* actor); + virtual bool RecvSetOfflinePermission(const IPC::Principal& principal); bool GetGlobalJSObject(JSContext* cx, JSObject** globalp); diff --git a/uriloader/prefetch/nsIOfflineCacheUpdate.idl b/uriloader/prefetch/nsIOfflineCacheUpdate.idl index dddbf255eb61..adf202fad7f7 100644 --- a/uriloader/prefetch/nsIOfflineCacheUpdate.idl +++ b/uriloader/prefetch/nsIOfflineCacheUpdate.idl @@ -197,7 +197,7 @@ interface nsIOfflineCacheUpdate : nsISupports { readonly attribute uint64_t byteProgress; }; -[scriptable, uuid(cf362a31-4166-4994-8443-b68704ecdcc0)] +[scriptable, uuid(6ee353ba-11ea-4008-a78a-55b343fb2a49)] interface nsIOfflineCacheUpdateService : nsISupports { /** * Constants for the offline-app permission. @@ -296,4 +296,11 @@ interface nsIOfflineCacheUpdateService : nsISupports { */ boolean offlineAppAllowedForURI(in nsIURI aURI, in nsIPrefBranch aPrefBranch); + + /** + * Sets the "offline-app" permission for the principal. + * In the single process model calls directly on permission manager. + * In the multi process model dispatches to the parent process. + */ + void allowOfflineApp(in nsIDOMWindow aWindow, in nsIPrincipal aPrincipal); }; diff --git a/uriloader/prefetch/nsOfflineCacheUpdate.h b/uriloader/prefetch/nsOfflineCacheUpdate.h index 6dd0eb175fa7..36d410495d7f 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdate.h +++ b/uriloader/prefetch/nsOfflineCacheUpdate.h @@ -32,6 +32,8 @@ #include "nsWeakReference.h" #include "nsICryptoHash.h" #include "mozilla/Attributes.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" class nsOfflineCacheUpdate; @@ -350,10 +352,13 @@ public: nsIPrefBranch *aPrefBranch, bool *aPinned); + static nsTHashtable* AllowedDomains(); + private: nsresult ProcessNextUpdate(); nsTArray > mUpdates; + static nsTHashtable* mAllowedDomains; bool mDisabled; bool mUpdateRunning; diff --git a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp index d3acc291c96c..2bec71550a3f 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp @@ -47,11 +47,28 @@ #include "mozilla/Preferences.h" #include "mozilla/Attributes.h" #include "nsIDiskSpaceWatcher.h" +#include "nsIDocShell.h" +#include "nsIDocShellTreeItem.h" +#include "nsIDocShellTreeOwner.h" +#include "mozilla/dom/TabChild.h" +#include "mozilla/dom/PermissionMessageUtils.h" using namespace mozilla; +using namespace mozilla::dom; static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr; +nsTHashtable* nsOfflineCacheUpdateService::mAllowedDomains = nullptr; + +nsTHashtable* nsOfflineCacheUpdateService::AllowedDomains() +{ + if (!mAllowedDomains) + mAllowedDomains = new nsTHashtable(); + + return mAllowedDomains; +} + + typedef mozilla::docshell::OfflineCacheUpdateParent OfflineCacheUpdateParent; typedef mozilla::docshell::OfflineCacheUpdateChild OfflineCacheUpdateChild; typedef mozilla::docshell::OfflineCacheUpdateGlue OfflineCacheUpdateGlue; @@ -688,6 +705,15 @@ OfflineAppPermForURI(nsIURI *aURI, } } + nsAutoCString domain; + rv = innerURI->GetAsciiHost(domain); + NS_ENSURE_SUCCESS(rv, rv); + + if (nsOfflineCacheUpdateService::AllowedDomains()->Contains(domain)) { + *aAllowed = true; + return NS_OK; + } + nsCOMPtr permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); if (!permissionManager) { @@ -724,3 +750,39 @@ nsOfflineCacheUpdateService::OfflineAppPinnedForURI(nsIURI *aDocumentURI, { return OfflineAppPermForURI(aDocumentURI, aPrefBranch, true, aPinned); } + +NS_IMETHODIMP +nsOfflineCacheUpdateService::AllowOfflineApp(nsIDOMWindow *aWindow, + nsIPrincipal *aPrincipal) +{ + nsresult rv; + + if (GeckoProcessType_Default != XRE_GetProcessType()) { + TabChild* child = TabChild::GetFrom(aWindow); + NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); + + if (!child->SendSetOfflinePermission(IPC::Principal(aPrincipal))) { + return NS_ERROR_FAILURE; + } + + nsAutoCString domain; + rv = aPrincipal->GetBaseDomain(domain); + NS_ENSURE_SUCCESS(rv, rv); + + nsOfflineCacheUpdateService::AllowedDomains()->PutEntry(domain); + } + else { + nsCOMPtr permissionManager = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + if (!permissionManager) + return NS_ERROR_NOT_AVAILABLE; + + rv = permissionManager->AddFromPrincipal( + aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION, + nsIPermissionManager::EXPIRE_NEVER, 0); + if (NS_FAILED(rv)) + return rv; + } + + return NS_OK; +} From 55305d3e8b89f7d284a390a125f4548c0a1e319a Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 19 Nov 2013 14:24:59 -0800 Subject: [PATCH 017/268] Bug 917595 (Part 1) - Respect image-orientation in zoomed image documents. r=smaug --HG-- extra : rebase_source : e5e27e3d8c9f63704e9f83970b6c9ddb2c08dfe1 --- content/html/document/src/ImageDocument.cpp | 39 +++++++++++++++++++++ content/html/document/src/ImageDocument.h | 2 ++ 2 files changed, 41 insertions(+) diff --git a/content/html/document/src/ImageDocument.cpp b/content/html/document/src/ImageDocument.cpp index ebe217d0ccc6..dd530a41ac6b 100644 --- a/content/html/document/src/ImageDocument.cpp +++ b/content/html/document/src/ImageDocument.cpp @@ -15,6 +15,7 @@ #include "nsIDOMKeyEvent.h" #include "nsIDOMMouseEvent.h" #include "nsIDOMEventListener.h" +#include "nsIFrame.h" #include "nsGkAtoms.h" #include "imgIRequest.h" #include "imgILoader.h" @@ -209,6 +210,7 @@ ImageDocument::Destroy() if (mImageContent) { // Remove our event listener from the image content. nsCOMPtr target = do_QueryInterface(mImageContent); + target->RemoveEventListener(NS_LITERAL_STRING("load"), this, false); target->RemoveEventListener(NS_LITERAL_STRING("click"), this, false); // Break reference cycle with mImageContent, if we have one @@ -253,6 +255,7 @@ ImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject) NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document"); target = do_QueryInterface(mImageContent); + target->AddEventListener(NS_LITERAL_STRING("load"), this, false); target->AddEventListener(NS_LITERAL_STRING("click"), this, false); } @@ -509,8 +512,11 @@ ImageDocument::SetModeClass(eModeClasses mode) nsresult ImageDocument::OnStartContainer(imgIRequest* aRequest, imgIContainer* aImage) { + // Styles have not yet been applied, so we don't know the final size. For now, + // default to the image's intrinsic size. aImage->GetWidth(&mImageWidth); aImage->GetHeight(&mImageHeight); + nsCOMPtr runnable = NS_NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing); nsContentUtils::AddScriptRunner(runnable); @@ -573,11 +579,44 @@ ImageDocument::HandleEvent(nsIDOMEvent* aEvent) else if (mImageIsOverflowing) { ShrinkToFit(); } + } else if (eventType.EqualsLiteral("load")) { + UpdateSizeFromLayout(); } return NS_OK; } +void +ImageDocument::UpdateSizeFromLayout() +{ + // Pull an updated size from the content frame to account for any size + // change due to CSS properties like |image-orientation|. + Element* contentElement = mImageContent->AsElement(); + if (!contentElement) { + return; + } + + nsIFrame* contentFrame = contentElement->GetPrimaryFrame(Flush_Frames); + if (!contentFrame) { + return; + } + + nsIntSize oldSize(mImageWidth, mImageHeight); + IntrinsicSize newSize = contentFrame->GetIntrinsicSize(); + + if (newSize.width.GetUnit() == eStyleUnit_Coord) { + mImageWidth = nsPresContext::AppUnitsToFloatCSSPixels(newSize.width.GetCoordValue()); + } + if (newSize.height.GetUnit() == eStyleUnit_Coord) { + mImageHeight = nsPresContext::AppUnitsToFloatCSSPixels(newSize.height.GetCoordValue()); + } + + // Ensure that our information about overflow is up-to-date if needed. + if (mImageWidth != oldSize.width || mImageHeight != oldSize.height) { + CheckOverflowing(false); + } +} + nsresult ImageDocument::CreateSyntheticDocument() { diff --git a/content/html/document/src/ImageDocument.h b/content/html/document/src/ImageDocument.h index d431b29a4ff9..45de6062deb2 100644 --- a/content/html/document/src/ImageDocument.h +++ b/content/html/document/src/ImageDocument.h @@ -94,6 +94,8 @@ protected: void ResetZoomLevel(); float GetZoomLevel(); + void UpdateSizeFromLayout(); + enum eModeClasses { eNone, eShrinkToFit, From 3f661abe22b1bca0923fecf222a2c1c1ee06f013 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Tue, 19 Nov 2013 14:25:02 -0800 Subject: [PATCH 018/268] Bug 917595 (Part 2) - Reftests for zoomed image documents with EXIF orientations. r=smaug --HG-- extra : rebase_source : ffe78a522420a4ae8a51e76c02c8817f9fc03d42 --- .../document/reftests/bug917595-1-ref.html | 18 ++++++++++++++++++ .../reftests/bug917595-exif-rotated.jpg | Bin 0 -> 90700 bytes .../document/reftests/bug917595-iframe-1.html | 18 ++++++++++++++++++ .../reftests/bug917595-pixel-rotated.jpg | Bin 0 -> 91596 bytes .../document/reftests/bug917595-unrotated.jpg | Bin 0 -> 90864 bytes content/html/document/reftests/reftests.list | 7 +++++++ 6 files changed, 43 insertions(+) create mode 100644 content/html/document/reftests/bug917595-1-ref.html create mode 100644 content/html/document/reftests/bug917595-exif-rotated.jpg create mode 100644 content/html/document/reftests/bug917595-iframe-1.html create mode 100644 content/html/document/reftests/bug917595-pixel-rotated.jpg create mode 100644 content/html/document/reftests/bug917595-unrotated.jpg diff --git a/content/html/document/reftests/bug917595-1-ref.html b/content/html/document/reftests/bug917595-1-ref.html new file mode 100644 index 000000000000..6bb9e2dc92e4 --- /dev/null +++ b/content/html/document/reftests/bug917595-1-ref.html @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/content/html/document/reftests/bug917595-exif-rotated.jpg b/content/html/document/reftests/bug917595-exif-rotated.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7b0c22f35102e02473f6cd3c4e42305fc6c95f6 GIT binary patch literal 90700 zcmeI4d0b52|Hsd4O{?}IGLsPbR4T31NVJGgA+nFONm{h1q%NWC*|V2@*9V^#ONO$G zvQ!9dQiS$xnz{FPCO%}l>|6o-IF7Pqhro?Q<F+5jUxnor3&Ol$nKlNN;}-aOg~ReASnfM7%-g_|8SLvbCzL(FV<6km!or;G;1xd4D>PKk z#ofctJ=l|N8|WY89uNt@hdPV)0!kv=vZ0Yp4J}Mf^^EkP`9FO~fBdu+c|mk%|#gYfWheP1sReUU*weZ+3?Y0DoMI-O5nbiPlvV~_Omb`P5u$`%>bBXC||STH*z z$lb$>t@pJP|HnIax~xvu@yB>CZ?9ml0C=iN(93)SeBkX4@bnG!4GduW2K?v_|A)JE zx&~44gI~jf@&O#EaP@>_q;N%K>y{89``>pa@nppafKa zYETQBK|2&OCPj{-OzA;kQTkB^QH&_&6l=;T${5Oc$`r~hiVr1#5=L1>SxQ+=*+|(z z*-JS}IZZi7xk9-`xlegQDW$xo)KmCW8da96Le-@9ry5YrsWwz6sw;H{)rUHtx{$hz zx{kVyx{rE-nnt}sy+h5XmQbsyO*BB0p{dcdXnHhrnk~(lHkIa03#P@;R?)W7_R&t! z&eLwt9@0u^Z)t6G3A!?!P1mCjr903k(mm+&=`r**^d0mg^fdZa`a^mty_SwMq7RN<>Mlk=QMfB5_&b zzC^i16O+m8!5qZ2VmdS3nW4-$=62=@CXe}mS;1_Tl#ygf8cEtoPL&LhjFsFfc}((> zx1~ESA|O^Owv`nNpcHStVIrSzFoZvSG68WDm<;mVF}IASWl+Uv9YE zRJl;Ob#h1LvgKaLwRThPrr*u6n`bwy+s#ydh zHcu@^SkqVuzQT^;n!nBkMthT zHRu|;8sjv=HTGy+(|FrcrRUI|9z9p}Jk#@OFKRE{UgLX3_1fPnr&p6^Z%up6AkFQX z*_v;AtMwk6h5=M!%N+I{n@H z$M;X~U!~Js$5CgY&T*Y*1LOv92FxF@Z@{C05(CW#`VHJYFi)4NYoa?xcc*UdAnG8~ zLB4}_54!&c;}45J0{+jqo{ioDz2kbN`fB=P^kenY_1_!xHJEC!!Qh4gKGeF6L{@Z(1-cMp$4L7cJT>O)Wz$&sf$B)f?(J^w`j< zVLHRSh8-AIZq>)i-DaBU)@NZKG{3kED&XAGvDey-`Y|CXU)M>V;h&J0H8_cD42<_EGki9T*Ny4jUW_ z9W@<29FIEIjy4+|J^HGXtkVRi9ZqFqbjJjbIX{*Mg@&xXLV-uQPN4O@q7EK&5F>GSiB>73xCmo&C z;x^K4qg%;jgUQj8?@ZB{;yWc{Ds$?jsfVUEO&c|B%e0E=Ce!1l7tGL^5i#S|OpTfI zW@d8bx$fMvvlz47W*wU)aCdg!=iW5iarUm+wH~$}i5}IS!#y{9zV@>6+UQm3ZRNeu zyUNGPXOqwCIh;9L=e+f`_1)oHH`ifq(%cq5XTQUK#5}ioDgKiFv;5BmC@-Wx-SnH`gbX=BTY33yv#{9~z&ug1*9c#l4lrE4Q!2S9z|wy?XHK zt*ZrVJl5P^Yq)mXT4J5|x_b$x347K{tPfaUuz|DT$VSDD3pbW;8oMcNGkf!@&5c{Q zTW)O~vNb7DIx#G-qjr~dBu_pVgs z)KzJew8*sD^f~Dz8B;RupBsHH>-^C3sTcGw9KNV^ac8D#X2K=uOUo`1yoJ1`%R!gl zUh%n7p2f{7%ATD4=<2wu_pUizyLsL2diD*Q8@!uVH!t3@ymjuj`R(*OrgzeEOmb51 zn%qsjXL>I!*DN<9&m!;q{bBbnJ>WdJ@^IwC>yI2C-O2wm|9-*5g2#o^3rik*KCXH) z?@8U$1y9?H7C&P=TlHMw`PLV`UhFF#Se#N~T9R2hvNWe`LRnF{M|t(jke7mrWv}F3 zZLMTg9<4H}y7=1eb>5q4Zz`&Ts@vbjy;FR*>-~WDf7cAJ$*G-OTTvHWN7S!r=+SVv zaY$oUlS|W!X8-2)mQ}4iT934ux82~o@hjWI1x&#<;XvVe+zEe1_!9(C3T}>y@bv~@ z>{y@+X+RP%DN29_OBC3P02B?#2Oqd%Hl^pM@?6S*kK0h;kA|?%0U;9p52hG(lvQ9k zHr}@bFhoqU75*1}U|*(#Q98a|d?UQ(`MZY(2D6RyjQ}tjY-nsb*v!(%lx=7#Dwsfu zrX^E8o(Uc&nflKWX;sOzf6B}}(V>Y_%F&O+8W5uI?io1SOWz~V-yp(0$iPs4umKnr zVHx2cFgF3)cbX@n@fnlLmefo$_^y%~QI{kw_o#?w&`*dWu<1ko9OWR;Cky%{> z1Ls+PY2{%CU;qC3gdMw%4fOQ&jvVP8>SZmuA9{n$^o&eh|G6I@cJH*!$GwLci0aU( zP9F@`u@+j)S{m;7kM*ski6USt>fHX)M|6;1I)G?r;xbT_WaiPTXcR?2Riw}qDa2L4 zf={Ztm}6YcPsSg2+4+o<36O9TKQ5@=mr~2k zZSV=>w)o)cZN}A{I4qdeGNH|_e9?rud;+BNOfk;JCROB*(+>|#<+h=vz`R*;nIokY`hEuC}S1``q-TBz_q*m_B+!J^Y;Z5wh za|L&8o%0Ph{Dt6&KzRK^K6IPLIaSuNydhCM=uK-gi;oMg9bk8XyLU7wT7xz3nEboN zU3NZ8`Bp)~8{WP1x&&Yd2w)mMkpK&@Qf!m;*;bzxEdqpbw#1lS<7jf*qZ)h~S~P0h zpyS-%pUjsQ+vLQ$mj6!Bb>C4OTYgM>5w?JM>-_7y&@eV zm3$h~A+gkebO`B?SSJw|4v`Ka9TMjwq!t3nNQaOPAszZ<3y`)l#6#kHlSqe<4*hZ~ zL_CCa2=S0OA^F8-hVnxwKP1)yNQaOPAszZ!Y0-EYxh|mbvadbn8+)PgGI6qk#_h#M zXQV^lw5!hH8jahF&(|OwLOLWiSaohx-!m7|A*4g%e1z0OAQ|b<_Zn7bqahwbJS5fv zogL;ISw}pCc<9$WNTg9nhs4?t@etA>#6#kM=9~ER?{+{sgmg%(1&|IQ9r|~&@~>41 z>5$k~hX)H@*{^w!h?S5I ziM1i(A*4fyhs1TPe$bg9b)8PfL^_0YNUQ}&oeA*};-O#jAjCsICE|#OkPaap>clQT z)oMt6=G%iI9ulkNNQX#$3h@x)A+c?U)PoQY{gkpJ9U}E2q(exDkPe9-5&S8wA!}(! zhsdlm0O=6YA*4e{hrYG|nr|;&7tnh@zRl2l8L!d&GO^l<=9iK433?ynmrd$BOGt;1 z4t>Wh{@rK<(jlZn|ITB+u@}-Iq(exDe%S)ww5!g|67|bazf5eOg4BaV8io30Vr__c zh}4Ua4j~;9+lELz2dYt<5YxF1U7p{p-H*bDB+ShUGs8FG zKFwHxdSWpF=+@VxdB*sVs4zh>-?=RwtwnY~{(#!W|6?Vv^?q!AJ%%S-IQRUemUiA) zyVKG_YXY?XaX0S%rGlgy*@aEQm`q`m+t|_7k1w4MtQ7k3cW*Hq^yUH2fmhA1F1S&^ zlRdHRfX*IjWjz5nWqx(1bWfeDe4gG=+`wzPfX9^2b9FuDf1&LH0l3D+e7DM-Z(1XHE^EQw61@zO@QQ!*|0H; zBS3`>0i)h62AW$Pf4yVjEBLRdJ&_!7Xn zf&j6_ZSew!a76;-&4kB~9YBEkWCAS5SVD#u0eCJ1s2hS^wYGk9{F$aq|GKLKtp{lXUa z37}9tgaApw1h^6?$j18)T>&rA03QE}3fAU=W$|DI&JdvZ2-doTQ>N*i)bO6$sz-or z*wy&?@bX@o+AI<%|jP0@9Oiy^;()cc#5;420Qr=BpH>|s(3dsn|JXR1*`ob zw61Ir96uDJ>Ah}EV&62sseu?TeL|#=VZQQV5Wm3V*qKa?X`uv2oCJ|DdQ0u`(gVi! z-NGWTFQ}x-+q{V{+~`*y)2}w&^!UJ3>7Bf`1%hHM`()ys25Yu(*COW~w*$;`@@HHK z&f8yji~v5-7cb@>RxU}~k+-tj=>^?S&EGlC2Nx>y3oBEy-V$K@DaZGaeRFuZb*U+@ z7C8yG3B0hj?%vIXxcd?AZ34V~+E$&iVY;B_!+NZ2en_h@i2!R0lImoP3mgl62uOo(}UEka=`0m>V(tLa|6Mn#CvS3)2p((t~1@w_S>1GqflLmE~t zGKv7hr`5E#`w`$q)z@cX3LFaMvAjRI@T`YBlA9X!E%@T};+Ez@0wlofrqc7RFe_;X zQ<98a0<4#B-EgWmyo6m4NEyx@IoU62vLEkv0VX$-*RXIIh_`H3o%VDqm_4SRv4gQzeN3vRSZ|He8om@vNY}c;6)srz%$cxWYVA1w6cRI^Q#S2PF<U(~7^p2@4c-&mYoTolvt=j8c&=Z;Mebo7sGGB=|MIMZt< z@pZj2?xe4|(!c$|iKb}Q`;?X!!i0hhpXP|#>ptBrW}nG;QTS@F8$@`0&BpMU!#o{< zif+Yh2%XEKCf@|uiPQW_jvq56uaF~fyfm%f-KMt^nO3{~stFK;9d1cVHh6OO%GR^j zz4Ti6nK1?M$pTiw?Q4+k8T1Q%lUnVY0?m)us3QV1n#YvAkkjn_+kp&;t6E;ldyA;jSoD1rMR)jCIXb2V7Lpbw$_Qq zS5M`(xA_p@Rw#x}fJ}tE2(<$w6-Z4{JU}56Q3c|n|5bF1QH;Ec&&O4TUiU8CdB3t< zzToi7-XYj7Yg*B!LNY<(>;M2OVAoT466V zg#^fLD?8};;vE5I{HZ&6d$hN~jJ_!?cnr4kU5rwO|7o0cm{nMZ$L#6tJgP9dC2cK! zxY36?yW*D91GBc*t#202Szi)unFKrM)hSaZZH#Rc#t6CF+a>rbGcz%pDN(){e6&of z=xz+>WzV9*MwJgM*y%e2*iEzal&S&E5Ac(?O`r*!x3E4ikefH|-9h0rLF@}Z_^dzs z#S32Y{vs!SdK=?nVL5IiI;MSEVpCwfOk~Op!P2OOcx-~d!JFcjY7N|kHi_mYA*1(G zZa(j(-YXufUhZ8rU)t(#-f?XGG;{^X2FMTon{C1VR%(Mz?O!gG;S8Vxe)pGFRZQGs zU3>f@c9FBwCFlVGBDrP4aqng-wx1@zp0dng*3}QV+l8u^dD(EFJ^*F_?T@TmS~Um` z(I;Ys4Xo6YiTl*f4ty`fHkWl}TXVIi|I9N)l&zmiUSLonJurpI!__-nMZF zWjv>;Tv#f2x->4a9X?X4{w85=ZNl>eL5u3^(w3PU1-VtH7`P^Z2F63G{!z_jH^=av^JPvh)T5q_Aq_Up?wI zg!jU&mFF7ewk+l?R+*9FEPuW+@f9{I$ecc^}K8R{ZB7yw|Ef1>e|AH z=)wa$WB#BeSiCd-oB$6J#%VJ1+~A}?eQ4BI9KUG>BlWx|Jm>Rr1}OY)LHOu2i;}q3 zn9TAnP#}0hYVY`}In)DK^^NxIwp6B^LCY50AisBhDeD5O?fsyK+3z#^wI$u3E+eqS znrraQ3s=DR6lAj6!iAV&`_v~3wfv0s)a2vt!(+Qf5@;{^Z4Ir{zoSgQ!+{kVIkv-9 zwFxkj^MZBvh`BFzF{Li%NOOv$@G%6<`7`&h!d@HX;Hyfwr4I>^jy3LoWN*``3Lm<< z!>evfcv^7hzRZ-(Eiow#()2FU1eQ)=Zc;NY;|BU=rw~%v((jm9-gN zBz6db#OWr2ATh3pAm}@~(+R&31c^f_1VLmTgdj*<^RJf>1R)3_4^jw%5Cr|s2NV$m zk%u@0K?s7#Jp@6}zs8;~cR&z?AP7Ow@0{X;GC}12g&>GL#32Ym5Jc`F2!g(3nt#27 zAP7Mad5}VxAe0G0nV`;L2+a-?8)ncHdGfG=rpS{A9W+H=%!EG%KvU#Nq7s@SFD|cx zrpSxwTcauRq!NT62tklIjp+={-|0jl2tp7fHi1X(LkNNp1d)cR@5oLk)j|-2Ac(x9 z-pN_MqeKXT5CoBX2)X`1mqHMPAP7Ma3B{1R2l?m}oEV5QLE;1oK@fr<1VLhjj??S_2VmtXL6GXyL2!ap`pyviw*#yQ zf)E5D2qKq}Um5K{nIKZ{LJ))?h#Zr@4Ow4BJOn}H>V+~vqzZ&GK|f9+b_6~&941bn zP$mdvg2+4S + + + + + + + diff --git a/content/html/document/reftests/bug917595-pixel-rotated.jpg b/content/html/document/reftests/bug917595-pixel-rotated.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ac39faadadd9e6c012aa5064ecbbcf7946f6c5a1 GIT binary patch literal 91596 zcmeI530zEV+raNxYFf1liKdc}nij39L9|$&ED;`z)U-&87KL=|9`eXuw#J_HXso5s zplpvG*|S%Yq-fu!nRC7~MZDkd&62m@_j~)U<5yjsbD!nD&b9pS>%JSr6QU3)k9Bf& zLKF%Gxsd-5@mgWJtD_@l;$$}`*YRV>0|+U&jQ0-;rYa*87!)2l*?AOm`iz-O#vMdO zvPc@4BIM~67BXRqlRF|e*D;RFFtU+E{<1YZM&y+cdSK)-k;(kB|A!b;1!6jwdcv4=w$e$ZY$`46-z=DWCe^PEDW%WR=XBa|s1q4YHf^?vqc-+=uHDXm5*E$^%TXh`hE zFFZWNmc@#Uj5PM=dKpU;+P;0aL3_)Ng|F^sEV*C1?wF&wKAsT^!kH4KdIc{CjtFIj zg?M^#nMVKHh&z4aSC948a}1r#_2GtcgUDM=BdyFo$d`QGLEir1{=q>^|DcZEa3@du z>KP*zMRiyoops1TK) za#V#HPzxEz7!*Z{8l?|Ko1#xKq?l2xDGrn|l<}0wlo^z{6kkdZC4v%7Sw)GZY^Cg` z9H1mqPEj%_S17kA_b5*(MU*m14Mj+$Q5C4_)PB@~R2J2mI+8k$>Q0?a^`$PPE}^cb zZlWeo4^sc4rctj@Z&M#p3#sMQdK#k1(==#0G$Wcd&5`Ctn@RJbh05bC+r1{d9 zrSC}>OV=|Pj6MuQhCRcL;mHVRtYz$C{KXJ3?lVdlO)~N_+A?M`PBJrPf@D_8?36h! zlO=Osrc|ayR#{eG)>hU{)?0S5Y@F<2*-Y6y*%H|nITbkrIeR&Gx%qM{<6q|ae^)T+?+QYjC)?-hPv>x|+d{mNE(pMU(G)HNP(oUr_N_k2Z z%CgD>l^vBmm1C6mC}$|=E7z;2shFy`sRXKQR5`A4OXZy^Lv^6)7*%i8)vAY7vsH`L zXliH7Pt~5odQR&Z)pJkJOFauUXc_}G zTs0PG#A%$?c&s7p)vwpcUff>md!_ce->b2A-`*p7b9-;-&F}rFx3CYh&zL>|eYW&T z@AFcVt~o?=l4hi4qUJTtioWW7hxhgByP@ytzR$F%T0^uZYc16}q?M~x->-i^=YApm zcJ<5dSJ7Xi|A_wc`)}``)xS(zP1`}+UwgZ@K>IzjCvzlo0W*P_!>rQL(s9v=&^e%U zN2f*CKzFL{N?pG0OFcO~Yds&m?Rr=Bss?Bem@puEK+1q;`m*}g`hNQH`Zx3&2O13Y z7`Sd=`oMPvy$xIqmKdZMycnc7h&^cGpo4=R4wfElJvdBBK(MPb47C}bIkm_dG#>EVccPf!=6~ESxm54XK~d+ zY-wc~YME+TW;MWSuGLBzw&=a2kr$uGE@@U#<=g}KR-x;GiX6l&TV_rGwI{7-KI8`}YI4^a+>>}kd&Si^B zzH2{MFV|$(sV&ZqwoQ2PoBnS>zook&H&?f9 zZZ9VqOk6ne!X)WQ6DRGN^mel84+N^2G z(;7WSdu;V6oX(oQZ2IjPnlt=ooS(^*u-7+dHqy%h4;|tK55p_jd0xu03}vx75ep zXRFUUUwhwezGZ%Fzny*+{*L~;{j2A@%;(K-3~&ob3LqAEEZ_&q1kMf22vQ9S2+9fW z9~>2YFT^lpZAjrl+l4z8R)vlWJsL&{n;mvOT%Cle+=xLDYa)skIV{?l zEB;w&vU2Onx>X*lGFSIoy?k}?8s{}BYkRB>U7Npd_&VMn^gsOnxU=4T{jT-+2Ja1j z$C||Mj1_J4+W7aMrhg{16*$E}^icJkuo;v?b<6UHZ;-!)*@=3S!Qe!Cy-8MTMMS8MP3y^Z_4_uWq%k(kQs z$BX3&_xtaEa=`gO+QESbcOH^HwCK>=!_yAmIAVPy`Kad6*rVd4prpcMlaJ*jTO}tS z*E$}TLQRQCDf?^IUw2Q8K5;(PDD?negCBbmos2m7{?y!4k57*~ef5m>nbfoTXZM~{ zJGUW?lD0UlD%~%=@cfMP_cF$2T+JMwdG3Pog`|r*7x!H1c_}VSE^BobAy^`)zZ`P8 z;)?H;;;Wpi&$FjzKg^kwbLZN)Yd5buUC+KT@`m81{mqNFY;R@!ZT)xpZOhwfxfZ$S z{;~My+#Sn1X?a$8=kMCw&AexKFY7-0{*?!#A6$Rv`tbIn-yYq2JoWLD{8{;hPrRSJ zd%ECh^|M9KTAnX|A@yRzOXZh4UunHMSTMMNUuao)sc3Xj?&~S9pBH--m%j;nBPv<_ zR`Ko5Qti^@cV_P{mN}K(egFIWlJb!9mWs6>R6gweIOyZq$`O^hRnx0Vsza-ZnvJ!6 zYLn`Q)m^QhSpTXau%V@KLsOroW6jphH-sL-(w0aOLzEyMEY8Ho;V+0lf*^{}%`s8_ zJ_t>ifQFDXAcGhbRYW5tii9R8nj{~zam74J-*$OEWzeTKRPvxHIp!cClKcv#n6=94 zq`Y#Se=A@}m}DpUCE3WaOe>?b{+#F^#a$5S86F(UG&43s$jrpl+}6a(*36P=YAF#c zNQ$QIr+j&u{nXD_WZd0P`z+JmNiIzkQIbCqYfzZ6r+4r?uCZ5eAS=onyUpfKAgd)?M%wxlfC&C+GIHVF@~*PT9LB1wLsT&9Jwsj-=^gB+8| zvC@@tZ}z%hF><82ad4x# zRI2UT63dco6e^7_CC!kLm6InMoKr?r3XMjk)1;*6Bt%n|k;f5TMM_o2bfmP}Bu|F! zLUpqhTMo$RjXHIu=j3};1I*`zu9TJ2=+(QArv5;KL4$`3v#_+Xwy|{_J;uq|#dYiy z_o>r7NV@m(=KA>h`Ogmvk608LwRp*@)oa$S`(yovt=qQm*cqR&YxluJhmRahI+lF= z^qI5g($ddoWM0kAxpw`=&0BxpfAH|pepB+c^j+Ee>YCcR`i91)W}&2C zq${6)#OQ6IJCz^N;;dgha> zdd>^IC#NxBSdo6Uq-(7``>~F#>{QR%JNBht&yWI*LcTnj3SuLXHvff^@Uk2^j@eIL z-o1WM{bCxM>nsj0;=IO$<7`6;`qmN1{6pSTC7d0>7vix5a-GY6t9>|56zhjQ>BkWp zJ6ElH5Rbc7Sczlb6R0dAE+dACrQ8>k|0NLWmy5X7y>O=;*fn-8fz}I>;zZk{+**2j z5a@x0o598MCZ)HAg?@qBe7wp!) zgfCO{?-$?1!?)hqYjs`B&TR>6a3oON%K%((kU;mR8#b>i(<6}XGwlWjX#wN5h;-^o z2()#nB7x=!1;W{0A31+$zpvv9%USsPB?RgdJ%&JAj&Q2oYT2)Y%Zdr4-(L;C-jhIe z|4g}6X^YdEH#BMXbr!Z5R7qRKu1>*WU-`My2rqEl^D-) zrZX2eAkg76Ns841w_1l6;>`pqZk$OV{yRb4PC49D=t7{IY3sx*9+4*X29sH4gS|=2 z#-3#H@%ZU2@vj-eONMynZ2}#fBe>2{!QS|Lh^C10n)V2z2z1MNHGxj8!Nlh7HB0XZ zmgDoXq}SfVvu=qf>z|WDm3yl-_;3;(Rb z17|V*X$*NbG-EaTa_?Cknc($jV0Ei&5y^Z@h#^!(fC1C^exi#z~506hRb z|2FJMb^`QtUFZSmf$6PZniGdg4^(T?e2Cpr=FQ_*PtPJqBxf zzN?~NSxXAg1JKhc=LF~h=mF^I&~*TM0D3w!j_+o4fS&KF2%x6}2ZQOY4iwXQcWk#c zfF6JzfSwK=381IzLJye`VNDOL>FGQdL8S*OJsn2wZcdG zuC^Y7O3!yy)IR#|L`#4kfSyh{CqNHC4?s_ct^?2m(9@xDd^b-6^n6!E06iTz7))<< zpqS3PW4o;Z^Z@h#^mOP*06kq7ddP$b(_1jT)p;(0N)J?eI*i=kGAn={fF6LJ4qXSJ z2cV}zuwZ9N8+p6{xtee~UlmH<5fJ)Lq+fF6JzfSwLr2cQR_r$giTZk`6{`L2op zdOC10nBM9@F`akEc3T7J0q6nf>Clk?db%$3kO>i{w_tj!^IQa#9;ozm7`eY?RscN! zJper&x(+}OKu?Fp@vXSpdJHN(-&Ilj=(`gw0eS#>I^~=IJperbJsr9ZKo3AqhsN>U zJPpwET^0Qj^d!EpcP=GRe%pVxu9*EW1`{tqR!Wna2~__MeLA|I7E-UxBhZ}X&_bdu z&JUix1v{}v625nfNT==%R=ugH{y8fJ6ZJUN$jXuKJ1omt^%n1XuN$SDVyi!H5oo^q zz4F1hAA!~jlGYTcc(N-zIn_tpYnEQM^0F%yDMl;OE6zR_ooMD=whsSLLm*ZSSF_Ca zSK{3-a9S7NRg?|t)A<&h2+mjDZ**$Y|n_WSm6arnYb$BA) zs+(!`?D`|G*rrTx0^Po7k11szHEiBirgi`J$rlB6@>9}9B3^NNafWDcU18EpI~&J+ z7Wfs;(t@TPOB)>usw;XOv^NiB3m?-q;qLoFhu4eBMM2dX;nVyl*KpKd@n`4X7Ueai z2p9df`}I)P@Nu|$zyI3H9kV&~e$<~6^?hS;CzPmbqa_0Ly)#a`FEZp&f<+2xhA-9GzS(S;jT1Tv{% zu}gP}jy0TJN>d3d$6@7_O7NhdQLs^PCJ0XuM&HSSjy4c2!W8_rCIUOF=VFn2#MhNgy7ldFU!!MW4*aSTcd+98z0Ymk5*q z2SEv73E&P86Cf}`c7PNKoB*%{PzYoU!-M~ZF;c7st~&chBgSLrD>HQ?(p2Peh*+ z%_b1-jO^vjp;*S8G||ViE#jb<)iF8RN*vv5=UUQ^*H;jcGX|;cobjUqFwAPe86sQX%gTrY&akE2lfO01M%al5DW1W z@(1Kk;0NF*;78zR7(c-HsoReqeM@{8`$Z{urhQ&{0)d{*zkRx8742?}`%+%M$&5vu zkhx2g{*DV1zLht={ZT<_Wb>qt*sLqur^~Lac*hj(^d+|EiipFYt_&a0^frSQPjL1d#vBNIPJoLL!4K z^KzP})wye>xm6Nq-K%W&Z&+bsvf8YsbxT%aX?pM3W!Lk2S3cw=4-~9-*rl=Q_mw3N z#4C@q6g;1XUub-XC2-E}V%3{VzbYS`^PE78{489sFYkWdpM&MfGHo^v@>*oR>3qwu zjJ(%USRQACu^W5e^BD0Q!7ENx;Nw@3?AkbSk|KdpXJEk}qTS|XWviVKaB3YQ?dnU* zIlFiz+-L6xk_jcb)}gWzd+Xr)Qd}v@mgJ|f)*V`T7s!QAYb7b??XrSb1j@DHMK%g* zTQgN|i$F5D)7G*z`|N7O$R+G1pPII2E%T3fBkuXBsU+ELYP-j$rji8Kc9V5&EhTBM z?H)bgVL&q|0c@tt@xYr}BND_Jh`^AW$dvluo+#NehWPC~@#QvimZN>IV<3}gX zSRoM0zb8=HGr?OdzToUW0$uM%eniPB2l7uWN|uzC`CcD2VeOVY(M9sJk@QQ*g%x-v z`L`F9>f|z%rL5|y*amj(4sntpZmuA}Z}jGgol*%jEt(v9#q&yBCQ?R7A$8Q}uR8?NBu~JE6eM?Gf)NyUI<_)KaY^UgJfe`@_fLhQfK+%`-Ft z%@YcQOOkO;%zdm`?kVBf1P+~Q1O;z{V<)qOBzTr22sCL7h`J$=pVOXhQ%Wr}= zCvOWX7Op4I!}+DlJxWTOCwD(1Y3-5rs(J$XFz~|e=?FG4RU&N5iDM#8zK_*|2lc*X zaU!)!+(G0>AkXOps@rs5umMlt)eOB%peI>;Jn^_B$nbEN3T^TFYPK*YLpY;)8*Vo& zPDp+z-SfqU_|oVp1lmHbn(OKIk9PCl_yd0PP_xPwt$A3zW=3Jp=Eb=Cnr;|UNNZsf zim|6F2z0*N#miP#=)t+j)_xN(pWUne>7R9V;u%6Rn9y4Y6emz7jbj>Htaq0GT5!}r z6l=n6V5N|YE06O^8b272Ya)j;$WRmQhVxQmc1DvQauKJfhi738uf~$8s6dj6$R(B6 zrqnv)p@OsJ_&9|NpHfkjRLmS~hfcRlLh6(zHm6}O_OW|<11-K%=|;2Wv$$*GMPAG7 z+0$akDZDEV1S+n~VK?-QBaq7n!zO+inM8DRmBg_UhIyaVysX8QG>1)BNQ>gBktS5m zJHqS3F3xr#KSzWoPTwjhO~1x&?k}iz7u_S!Uj7GL(!8>bN#MCo8rr0kL<)e*e`_uV zaQV+=4gePbmmeM80Js3S{0xKuxB$5PWJw4rE>Lm#F_Qss0dN6ufr`t2ZYcD{ngCn? zTz)JIwc8AU3xLaynGApnfJ=MW_)ZBHDlSlQfr`uLxC&E6T>!fPE&wi{9qikSR{&f9 zTmW34;?f042-dj38ke6nD*zV&7XTM>$s;Vz{ZT6UHs7{h1u8C3ae<1<=ePGDP;r5Z3shV_$5p7f zbOG!FxB$3(cCc@=E`SSw3xEq$T)H3$!Qxz4ocpt81>geU0^kCRbAQYR09*iEem28= zr#RO-T7sz}m@4|o2n65);PPW80~HsjxB$2SxB$5P=Z@zQp-XWe46+m^ov#T?p zP$*y={0E3CrJ1fyPF(jXZqBX~$HEl=D2c0RO!UL55MZQ4X=uUZ`78x8G8&>k2R6&wIz52%}t>DKYd77e%gxMklfpkTeM8> zx@Q#aqR-1d@B4XK=zaif+n{eYeqJ_zCjeP10qFJY^Rj^%05DeoaG|(cd9)?*;vX3q zW@l;|9UW~F;OlK7apUi*%4u0 z-o9+(zXtJtykob^>UJGJOz~ad8}1tdPc;KZSwM&%yxk!_0g(ZrA?$#VFWuq)aJO#P zATdA2H8eC1;y{yY0#u7N0qtE8plc`s+T6Wx4dv5)n!dn17Hlyfejb|MuD+lJa7Zk zz%1Yiyn#Om2H_wYECI{FDzFx81lzzakPZ%lW8gG61G2ysa1C4sx4}J70?I%Ir~wV2 z3ABSwC}gq}Wr_x+H-$wRL@}b6Q*0>?l(CeFlqr;1lz9|CN(d#2vV^jnvX-)$vWv2h za*XmToj%E_E=~lxjQW120^iRMO|ONarEhQZ~7v7B7Gfw7yT&x0zIGpkX}h|qT>u@Mn8rT z!;ay~n91;CL^D<~wlfYh&NB)aC5#$IyNryCw#*P28<}x3vt$;^#LKLc*&~xF^P9|l znQECfSy|cMvPQD@vTm|ovXQc@WOvG*l;z1jkgbvB%PGpS=mXdEL2#gutVXrLV?0_ zg%(9cMLosgijx%s6qhRQQ2a&lhGM0nKuKN6P{~PYu2PiJ2BjlPzbQRcYEf2J9;`e{ zdA4$-@&@H&%6ZB!mH8?fDkdtfDn2ThN}9?Al?N*Cnexm*Oh=|CGmg2Pd6rqse5)$2 zI#|_7)k`%|HBI%BYN=|QnueO0nwwg%+B&u4YB$yD)n(NOtB+OpQD32cKs`^rT7#yc zui>QOt+8C=phkg4ji!v|5KULjg_>(MPifxOY|>KKvecTP6{D4=m7`UmP17E%?W!H5 zouYk4`?0oAM_0#D$5&^y&S{+oIvu_G_8Qg8x7V6pnY~JS34619kL?}UdsFYM-Y@#l z`xy3_+$Xxv-aZ9=-uBh(JEE_5-!*;D^nKQk+Rw1xlz#F34)iPP*QVQF*F`r>cc*Ti z?%V#_{YUj**neyPtNmZIG*}L-0M=F(kM)MF#dc%|v3IcZ*-Zob4H!2dYQVk$cL#Lp z4bhvfm!y}e_d;Jm-&TKt{#N~5{icDefs+O<8F*sgvqAEMYzO%dN*z=yWr1Cx$#XP&VKgEHc<{@Mx&aP}`w_L-!25XGk@)GW0i0Gb}cu8d)0! z80|5-{{!QP;Xj1@u>XfrV>=M&CNE>_+ZMMM z?nB%cxnG_vGueG|+T_|PW>c0-DV(Y?l{@wL)b?qkr=?6Qn{F^YYI^Pr=8U;Bj?L)s z7~`?oqhhA%%!HY@XZ4vCFze!M+1WE@AD-PdXY8D9b86;V&0RJ3@lQj3iuviLXCKcX z&m1n3>%~1gk1@|<-tl=NFE_9KUTyPT=kK21fPWo%4e(3YhQcc&AxRD>=$fa zQ155&x5e+ZKgWN&|JwkkfL#I23&$-?U)T}o7I-9(2=WNZ43-O?7knv1JtQzBKeT^n zOz8bEqp($B6^rZ^ZClh7J|X;Y1SR69h>MY$5T=Tv45C&>RW5c|oVJ)BJtO*Tj9N@c zOi`?1?CRLMIOn)S@$`7__}nD}mMmLRnc$ePFOiZsKQR~6$5vo9OI?;8U8b-saM_)t zVM&{lT9!zoM;%Vd4`!cmN*Zu;2iTdTuuk(I=d}hL#+_Sc4PoEofZufbO z^J^|pF2r7F%JR>uxH#+L{Y&F7v@Hag}fW~H?G{YyLsuB?X9fa*0(PdSrwhX zV|C~JUF*9SifxK7-Wz@|`~JxLS08X5Tzfd?;q^zZk8YRzSaSdI^v6$1=ayDH@p)4J zH0Wvbv&GLk%a%T8JYVxd^~Ls={a)@bA6lMSVO^0^Ii|9xYHC$kwRd&HtB6;kniaLm zwcG1hb;s(>>#w|aetqxFoHsQMVGW&cSG`kvxBI=p`*V$>8jG4{Hq|tTHxnP$we)T| z(rVe7+veW(vOT!HvttdvH~*->R!}JP5Y}}@i)2MR#6!i|_yqhp5lj$7CAcv*CSU;o zlO_Q}NCR>}mZA=5(4t6ag3<@_!AGu`PwD%~UPv+ceH$uVX$Jco5F+9KaEf`CtqJX< zH2mLi17^y_KFM*XPcXt17JSP%))M%jh(qQ+ss;GSV4-W zWl%m}O$POkBhu z?z6yd${6S0cZa|1^|~=~w1r7%xSuKPGYmH!W^QV3ZVb0Dj))D3^olVKiO~OekUx$y z26mXj1H!t%QgU3c`Jqvf_Ii4f6Mg#pex1Q#pHB3TMf-GQxZ_AzMmwi)Ux{0%g@y(> z{MpMRP5-+7^9j3lofPU5upoAfSER3lk1#~c*kj(>RHL4ha(PLj@Tk3N!v^ymPRor&Lonw;!CT0M=T2B>Njni_@32P_z* zjE~2bM3&@3q0;CK8Cf}b1x2{Qc~wBA&}dXTjlrNph^8dK^?`{eXT|9VYp%KfH+7W2cC66R;v0Tsz6e^ugqsvOlMWIGZ3a&XcbqKiwMawHe3_i)=uP{6y(X`3F{Mds ze)xR_?SYn+gPJ8p>nhpT6)fpLD%q!keJp)KOxd-5j}n3A%04LmH0$qab^1RWbq?>I=@^~6otKOypvx1JTQmr zAxL-Lu)N-=#pQAvwv%7>LdYwcJ^DLcFLf!$qCuE}KlyIwv&bMo$_@O4s9}F*6Sug< zFN)jYhwBI|8aS)4a8}1ufk*X{sm&z>$l_UJoJFVG61cSqee9SSnRog(mf(KXq0w&$ zU=|?vU2do(WJJZ8ZV zLpmgt8jubl9g-R((wal0Lr90D#R#c~KnBtwq(exDdh7wxT84N?dT$cx5YnL@*FwZY zNQV#)NfVMDRx^|zLir)79zZ&TbO`CtUzHY(myzoN8ZY~6#Qe=)XuM3Cte|mwsjV~8 zp}*Cu?#(qCx0jx;K{|wVNNQu%y;A*?yO0hc9g-F!q#gnpNQeHZVs&>K;vvLCQa#W; zVE!iSh=&jl^(=xU8ijO7st*wlAss?IBn@c();|5a9gq$o9g^w+q(exD{++D+YgIxz zB()YI9zr^VbO`AXde0TT=h`g=gPy1E=8P|>1A3nN3y%5Jo}lL#rScbgo|>G$(0i^@ zdp$^pkPb-=l24lag)NZ|AsvzyBcvWe@3~5!O;gsNQV#)N$XgBp))}mI^B+mbO`B?R1c5_6XGGnLp_Ti#6w>t;)sWk4j~@u#x7q~ zYe-|}?*~IXBvs3i4w1$b;vvLCQtJ?D1R);!DrHAHL>fg%hmZ~-9g;pG_*Gg%R@0CU zk$J}e=@8N(q(exD{^|krzP)r^K=Xe5Jwx;7_8PrkCRJO}`(@;Og63oVbCvpsUr2|L z4*f$|{JYTzq(exD{$0fU&0k1|kPaao>ahp@R%S_99SFex;m)f2S0C@ayvjbVE}fe>wc%Oz@fn^4Z4aB@2}KG4xU@#XN+s{}~HO1X9KtqaDEKU~HeahU)=6=Rvj z%$svAhhDzu{{32o>QKH%GXd_+;C8k#3829(OK(;=>n7+h6=@TohyW41DyNGncv1^f zq~=0^ZL%UGJ^|{DOvS=v0<1oO4|p6v0EZd^B$W%2MdPB?;L$w2;7 zQD-Wyh}E*12Rw%-cZ^NO1OOzl&3)yCA*gJ(q7xfE`$V@*;S7wJg3~3IPn6e|Cn8 z$m!%mJmEG07`zrHf8%?7czIXypfXG*K#d~-6mX7E0j^HmM}R7S0{k4c3oE{aRb=7N z0qVN>SgXzstYQsEbd*!cErbP_g*86nh$gYR`x3eQ;YSN?X0e_|EZL!K07lLt=Z_g5BXqoe?DZ<+IMFtZtb#sj&C16FI~E z?>CfSXRp5WT)f!t;p(P2ll;dd&%CVUyeKWm4;O0)YkBsGI(4Eu;cn3cFgb){>rY`8 zRq1aFtBnY7BhTgnuSIz@K8XNl7dBqa7WjK`WLlekv|5{9_?7^okaG|WXYFlI#TBqx z4*#%CuN>@LL<*-ph*Mi{dc%!BbvvuI*Chhn#BduI(deR%bG)Xh1TZ5&fmuu*zG`?O zuHnTKjKgww{{jKDpctP3Q97GbrR|q<2!eJxp1n^yRk~^z698sEE;;7DO8$E zfLA;M^o5YVApRMbKU6}z=$Oc#D3(w?LK=ef6SWL5C@Iw1C`TjiCvYNQgN;@HQG>8dL^uz51>5R1y z&+_H9sx61v%m@f{G<;xSGOvD!Df|s7QIdvKj*Tb4s5ytpDp-WJTjjnb^G_ zx$vwMadD1|Xu@Kc?RD(M z5$SO7QJgC0i}838%+-ptIFh7qX)3Rk0aN0<3p`O`3V-|CEIer##y7!4OR@a*VI5*R zOfK^cF-a0N(-f;$OdtRjjPb>+X5*)!V){G+G(pl809fumm5oCA+i<}&xWFCD^Ynz} z((c6ZXONhMoT@oz%7t>*psS(ZKTweGk?&F5ca72@%|V)j^d7afsIBcrY>0EdBV)>8 zfw!xeBG=GtmLM>gkKGRWR2w}L??P^6GwZGLvI%gmrV+1{P^sp8@u|j@&$8O>1$lnr zC|+jfo(g4PUKmXPsJ6q!hbcyaych`0O#>caYXw0V-2lV$s*UQ zvj*L1dn=P;zX#I!>vX#qzG1z-JviOR&Zoh~9%9 zLI@sln^Ql+6yCb&Ji$z?z}j{MzT6xW4bFt@Ps97mM-yOl`w0lqKR`$}N#Sp~au#3S zbq+h8u)dpWP(VhFsDh491~oXUz+tkrZOuj4~80X9pz7w8PgODL95eL$*#v=y}v zs1-%5fq3bEkSaxbEoq`^k&*EBp6JvU8ttr8ZZ}5O62KNd89cl+HsL-KEkOQ2;qYHt z8RVRY zsu>@E&46i>tX(4PhD}yxy+Qi}{1omOY6V~5*cckhy*K&YA@Lkh(#ybRxS8aT2g)W0 zvjmJQrPa7&P7dbiav`-X^n+q-W}#?#d>o#X5^VaW{FQbKH$@=R-X>=Bf5t80-7rR1 zfP8@B;QzBO=)Za<*utOrm$?MK!R!rPXHaeBIE~VRFE@E|Ub5~SwGF_oWHu)rZO@bw zLzOCC_1d%uUsJ)YgbBthto6Vn7spmDm!am>_OW2Gz;lYl16T~&x+BTQ-F)r^5@%S~ZO`Vyp ziGHmfR061^i!T%4Q2+gQ%#2JI{3j^hMTw6uc>X-Q=*Zly7S1vYa zQ@fYIh~s={6yo0P=g+i`e(Y-x--yp$_U%Kb>kP6t+gj?HE`FC-Wq<+oiK~_xy5Lu^ zE1Wd-dx^+xdFoK&o| zg?0W^>VECBL*I+JwVHC@NfsR3GSfLLbEVJU(S07u|1^{+Os7^$$`nppwYXCBZ279x z&RYb~d6TlRDdk0qs6*>@WrycxQE~lg2CmELgq_Xt_G2Phj-Dx^%Q$a`_*77i>iL~+ z(Qn{ur5TRjM-?a^5|#)=Cf{1=ey13-qmDdGeNI>WP)q?<5M$Ee&B3A9&2K?{HGcTzh9LB9*l7rzh$kvDD#g1#6!U2=*bNSbaU z2$It7A_yX9Hv~b_Pzpg1Sp*>nB5%S_CP>;$jtGLtBM3ndf*|q;k(y6J5Jc95DF6gP z2!hCa>f{M)1VPdS3T1-G;|oC$c?2N{LJ&kAAqawcIP8HS2tg2eBZVNSXU{1i2qKR! z1VQ9Y9D*POLF5sFAP7N_G>Yk28|IFN!^m=pC=(=2pb!Kh28bJ_(pl|wSHG&`nK?s7R^~T9Thipg{ z4Tq6O7s>=li#-HE2!apdz1hoMZ6 z)c8UWgdhkFhmntG^+18pGeP7H7 Date: Mon, 18 Nov 2013 22:24:12 -0800 Subject: [PATCH 019/268] Bug 939385 (part 1, attempt 2) - Rename largestContiguousVMBlock as vsizeMaxContiguous. r=froydnj. --HG-- extra : rebase_source : e5bdf43ab2a228f3ade93e803988f81d4f3a646e --- .../mochitest/tests/SimpleTest/TestRunner.js | 2 +- xpcom/base/nsIMemoryReporter.idl | 12 ++++----- xpcom/base/nsMemoryReporterManager.cpp | 26 +++++++++---------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/testing/mochitest/tests/SimpleTest/TestRunner.js b/testing/mochitest/tests/SimpleTest/TestRunner.js index 28254f437752..b6f14d0a1a21 100644 --- a/testing/mochitest/tests/SimpleTest/TestRunner.js +++ b/testing/mochitest/tests/SimpleTest/TestRunner.js @@ -405,8 +405,8 @@ var MEM_STAT_UNSUPPORTED = 1; var MEM_STAT_SUPPORTED = 2; TestRunner._hasMemoryStatistics = {} TestRunner._hasMemoryStatistics.vsize = MEM_STAT_UNKNOWN; +TestRunner._hasMemoryStatistics.vsizeMaxContiguous = MEM_STAT_UNKNOWN; TestRunner._hasMemoryStatistics.heapAllocated = MEM_STAT_UNKNOWN; -TestRunner._hasMemoryStatistics.largestContiguousVMBlock = MEM_STAT_UNKNOWN; /** * This stub is called by SimpleTest when a test is finished. diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index 4b9d0a8c0d68..df2154451e14 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -185,7 +185,7 @@ interface nsIFinishReportingCallback : nsISupports void callback(in nsISupports data); }; -[scriptable, builtinclass, uuid(2596fa26-495a-4827-a5f5-e34e7f4dd7b5)] +[scriptable, builtinclass, uuid(41c667f4-16b3-424f-95d9-a6f903f72eb2)] interface nsIMemoryReporterManager : nsISupports { /* @@ -263,6 +263,9 @@ interface nsIMemoryReporterManager : nsISupports * |vsize| (UNITS_BYTES) The virtual size, i.e. the amount of address space * taken up. * + * |vsizeMaxContiguous| (UNITS_BYTES) The size of the largest contiguous + * block of virtual memory. + * * |resident| (UNITS_BYTES) The resident size (a.k.a. RSS or physical memory * used). * @@ -300,13 +303,10 @@ interface nsIMemoryReporterManager : nsISupports * * |pageFaultsHard| (UNITS_COUNT_CUMULATIVE) The number of hard (a.k.a. * major) page faults that have occurred since the process started. - * - * |largestContiguousVMBlock| (UNITS_BYTES) The size of the largest - * contiguous block of virtual memory. Only available on Windows; on all - * other platforms, reading this value returns 0. */ readonly attribute int64_t explicit; readonly attribute int64_t vsize; + readonly attribute int64_t vsizeMaxContiguous; readonly attribute int64_t resident; readonly attribute int64_t residentFast; @@ -329,8 +329,6 @@ interface nsIMemoryReporterManager : nsISupports readonly attribute int64_t pageFaultsHard; - readonly attribute int64_t largestContiguousVMBlock; - /* * This attribute indicates if moz_malloc_usable_size() works. */ diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 45dd68558859..2253d32983d2 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -372,8 +372,8 @@ static nsresult GetResidentFast(int64_t* aN) return GetResident(aN); } -#define HAVE_LARGEST_CONTIGUOUS_BLOCK_REPORTERS 1 -static nsresult LargestContiguousVMBlock(int64_t* aN) +#define HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER 1 +static nsresult GetVsizeMaxContiguous(int64_t* aN) { SIZE_T biggestRegion = 0; MEMORY_BASIC_INFORMATION vmemInfo = {0}; @@ -1288,6 +1288,17 @@ nsMemoryReporterManager::GetVsize(int64_t* aVsize) #endif } +NS_IMETHODIMP +nsMemoryReporterManager::GetVsizeMaxContiguous(int64_t* aAmount) +{ +#ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER + return ::GetVsizeMaxContiguous(aAmount); +#else + *aAmount = 0; + return NS_ERROR_NOT_AVAILABLE; +#endif +} + NS_IMETHODIMP nsMemoryReporterManager::GetResident(int64_t* aAmount) { @@ -1414,17 +1425,6 @@ nsMemoryReporterManager::GetPageFaultsHard(int64_t* aAmount) #endif } -NS_IMETHODIMP -nsMemoryReporterManager::GetLargestContiguousVMBlock(int64_t* aAmount) -{ -#ifdef HAVE_LARGEST_CONTIGUOUS_BLOCK_REPORTERS - return LargestContiguousVMBlock(aAmount); -#else - *aAmount = 0; - return NS_ERROR_NOT_AVAILABLE; -#endif -} - NS_IMETHODIMP nsMemoryReporterManager::GetHasMozMallocUsableSize(bool* aHas) { From 2e69b12e8d52479acf0a88d3ff261e519d2ba6c1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Nov 2013 22:24:18 -0800 Subject: [PATCH 020/268] Bug 939385 (part 2, attempt 2) - Expose vsizeMaxContiguous to telemetry. r=froydnj. --HG-- extra : rebase_source : c6d4438abd5d17ab70805c59baa68bbc2962b9ba --- toolkit/components/telemetry/Histograms.json | 8 ++++++++ toolkit/components/telemetry/TelemetryPing.js | 1 + 2 files changed, 9 insertions(+) diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 9a7ff2774123..7261ce9ad6ce 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -255,6 +255,14 @@ "extended_statistics_ok": true, "description": "Virtual memory size (KB)" }, + "MEMORY_VSIZE_MAX_CONTIGUOUS": { + "kind": "exponential", + "low": "32 * 1024", + "high": "16 * 1024 * 1024", + "n_buckets": 100, + "extended_statistics_ok": true, + "description": "Maximum-sized block of contiguous virtual memory (KB)" + }, "MEMORY_JS_COMPARTMENTS_SYSTEM": { "kind": "exponential", "high": "1000", diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index f206ef760a13..c2eca6adb067 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -452,6 +452,7 @@ TelemetryPing.prototype = { let p = (id, n) => h(id, Ci.nsIMemoryReporter.UNITS_PERCENTAGE, n); b("MEMORY_VSIZE", "vsize"); + b("MEMORY_VSIZE_MAX_CONTIGUOUS", "vsizeMaxContiguous"); b("MEMORY_RESIDENT", "residentFast"); b("MEMORY_HEAP_ALLOCATED", "heapAllocated"); p("MEMORY_HEAP_COMMITTED_UNUSED_RATIO", "heapOverheadRatio"); From 8a5c15606bc73ab025b5eeb7bf31629fa43a3b9e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Nov 2013 22:37:38 -0800 Subject: [PATCH 021/268] Bug 939385 (part 3, attempt 2) - Expose vsizeMaxContiguous to about:memory. r=froydnj. --HG-- extra : rebase_source : 2a7dcf2121c323bb37094b23e329c322f25dfeeb --- .../aboutmemory/tests/test_aboutmemory5.xul | 3 ++- xpcom/base/nsMemoryReporterManager.cpp | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul b/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul index 50a464310cce..9aa61e290a66 100644 --- a/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul +++ b/toolkit/components/aboutmemory/tests/test_aboutmemory5.xul @@ -104,7 +104,8 @@ // If we have more than 1000 chars, we've probably successfully // copy+pasted. if (actual.length > 1000) { - let vsizes = actual.match(/vsize/g); + // Note: Match "vsize" but not "vsize-max-contiguous". + let vsizes = actual.match(/vsize[^-]/g); let endOfBrowsers = actual.match(/End of Browser/g); if (vsizes.length == 4 && endOfBrowsers.length == 3) { diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index 2253d32983d2..a6594960fa33 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -400,6 +400,20 @@ static nsresult GetVsizeMaxContiguous(int64_t* aN) return NS_OK; } +class VsizeMaxContiguousReporter MOZ_FINAL : public MemoryUniReporter +{ +public: + VsizeMaxContiguousReporter() + : MemoryUniReporter("vsize-max-contiguous", KIND_OTHER, UNITS_BYTES, +"Size of the maximum contiguous block of available virtual memory.") + {} + + NS_IMETHOD GetAmount(int64_t* aAmount) + { + return GetVsizeMaxContiguous(aAmount); + } +}; + #define HAVE_PRIVATE_REPORTER class PrivateReporter MOZ_FINAL : public MemoryUniReporter { @@ -778,6 +792,10 @@ nsMemoryReporterManager::Init() RegisterReporter(new ResidentReporter); #endif +#ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER + RegisterReporter(new VsizeMaxContiguousReporter); +#endif + #ifdef HAVE_RESIDENT_UNIQUE_REPORTER RegisterReporter(new ResidentUniqueReporter); #endif From c2c5f678c249f605550e5928b11136b1186fcf19 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 18 Nov 2013 22:37:39 -0800 Subject: [PATCH 022/268] Bug 939385 (part 4, attempt 2) - Rename some distinguished amount functions. r=froydnj. --HG-- extra : rebase_source : fc5a8b80752156cf8d13908eb2f961d75a954126 --- xpcom/base/nsMemoryReporterManager.cpp | 82 ++++++++++++++++---------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index a6594960fa33..aa6cc938b46e 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -59,19 +59,22 @@ static nsresult GetProcSelfStatmField(int aField, int64_t* aN) } #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1 -static nsresult GetVsize(int64_t* aN) +static nsresult +VsizeDistinguishedAmount(int64_t* aN) { return GetProcSelfStatmField(0, aN); } -static nsresult GetResident(int64_t* aN) +static nsresult +ResidentDistinguishedAmount(int64_t* aN) { return GetProcSelfStatmField(1, aN); } -static nsresult GetResidentFast(int64_t* aN) +static nsresult +ResidentFastDistinguishedAmount(int64_t* aN) { - return GetResident(aN); + return ResidentDistinguishedAmount(aN); } #define HAVE_RESIDENT_UNIQUE_REPORTER @@ -173,7 +176,8 @@ static nsresult GetKinfoProcSelf(KINFO_PROC* aProc) } #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1 -static nsresult GetVsize(int64_t* aN) +static nsresult +VsizeDistinguishedAmount(int64_t* aN) { KINFO_PROC proc; nsresult rv = GetKinfoProcSelf(&proc); @@ -183,7 +187,8 @@ static nsresult GetVsize(int64_t* aN) return rv; } -static nsresult GetResident(int64_t* aN) +static nsresult +ResidentDistinguishedAmount(int64_t* aN) { KINFO_PROC proc; nsresult rv = GetKinfoProcSelf(&proc); @@ -193,9 +198,10 @@ static nsresult GetResident(int64_t* aN) return rv; } -static nsresult GetResidentFast(int64_t* aN) +static nsresult +ResidentFastDistinguishedAmount(int64_t* aN) { - return GetResident(aN); + return ResidentDistinguishedAmount(aN); } #elif defined(SOLARIS) @@ -246,7 +252,8 @@ static void XMappingIter(int64_t& vsize, int64_t& resident) } #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1 -static nsresult GetVsize(int64_t* aN) +static nsresult +VsizeDistinguishedAmount(int64_t* aN) { int64_t vsize, resident; XMappingIter(vsize, resident); @@ -257,7 +264,8 @@ static nsresult GetVsize(int64_t* aN) return NS_OK; } -static nsresult GetResident(int64_t* aN) +static nsresult +ResidentDistinguishedAmount(int64_t* aN) { int64_t vsize, resident; XMappingIter(vsize, resident); @@ -268,9 +276,10 @@ static nsresult GetResident(int64_t* aN) return NS_OK; } -static nsresult GetResidentFast(int64_t* aN) +static nsresult +ResidentFastDistinguishedAmount(int64_t* aN) { - return GetResident(aN); + return ResidentDistinguishedAmount(aN); } #elif defined(XP_MACOSX) @@ -290,7 +299,8 @@ static bool GetTaskBasicInfo(struct task_basic_info* aTi) // absurdly high, eg. 2GB+ even at start-up. But both 'top' and 'ps' report // it, so we might as well too. #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1 -static nsresult GetVsize(int64_t* aN) +static nsresult +VsizeDistinguishedAmount(int64_t* aN) { task_basic_info ti; if (!GetTaskBasicInfo(&ti)) @@ -307,7 +317,7 @@ static nsresult GetVsize(int64_t* aN) // // Purging these pages can take a long time for some users (see bug 789975), // so we provide the option to get the RSS without purging first. -static nsresult GetResident(int64_t* aN, bool aDoPurge) +static nsresult ResidentDistinguishedAmountHelper(int64_t* aN, bool aDoPurge) { #ifdef HAVE_JEMALLOC_STATS if (aDoPurge) { @@ -324,14 +334,16 @@ static nsresult GetResident(int64_t* aN, bool aDoPurge) return NS_OK; } -static nsresult GetResidentFast(int64_t* aN) +static nsresult +ResidentFastDistinguishedAmount(int64_t* aN) { - return GetResident(aN, /* doPurge = */ false); + return ResidentDistinguishedAmountHelper(aN, /* doPurge = */ false); } -static nsresult GetResident(int64_t* aN) +static nsresult +ResidentDistinguishedAmount(int64_t* aN) { - return GetResident(aN, /* doPurge = */ true); + return ResidentDistinguishedAmountHelper(aN, /* doPurge = */ true); } #elif defined(XP_WIN) @@ -341,7 +353,8 @@ static nsresult GetResident(int64_t* aN) #include #define HAVE_VSIZE_AND_RESIDENT_REPORTERS 1 -static nsresult GetVsize(int64_t* aN) +static nsresult +VsizeDistinguishedAmount(int64_t* aN) { MEMORYSTATUSEX s; s.dwLength = sizeof(s); @@ -354,7 +367,8 @@ static nsresult GetVsize(int64_t* aN) return NS_OK; } -static nsresult GetResident(int64_t* aN) +static nsresult +ResidentDistinguishedAmount(int64_t* aN) { PROCESS_MEMORY_COUNTERS pmc; pmc.cb = sizeof(PROCESS_MEMORY_COUNTERS); @@ -367,13 +381,15 @@ static nsresult GetResident(int64_t* aN) return NS_OK; } -static nsresult GetResidentFast(int64_t* aN) +static nsresult +ResidentFastDistinguishedAmount(int64_t* aN) { - return GetResident(aN); + return ResidentDistinguishedAmount(aN); } #define HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER 1 -static nsresult GetVsizeMaxContiguous(int64_t* aN) +static nsresult +VsizeMaxContiguousDistinguishedAmount(int64_t* aN) { SIZE_T biggestRegion = 0; MEMORY_BASIC_INFORMATION vmemInfo = {0}; @@ -410,7 +426,7 @@ public: NS_IMETHOD GetAmount(int64_t* aAmount) { - return GetVsizeMaxContiguous(aAmount); + return VsizeMaxContiguousDistinguishedAmount(aAmount); } }; @@ -458,7 +474,10 @@ public: "resources used by the process.") {} - NS_IMETHOD GetAmount(int64_t* aAmount) { return GetVsize(aAmount); } + NS_IMETHOD GetAmount(int64_t* aAmount) + { + return VsizeDistinguishedAmount(aAmount); + } }; class ResidentReporter MOZ_FINAL : public MemoryUniReporter @@ -474,7 +493,10 @@ public: "time.") {} - NS_IMETHOD GetAmount(int64_t* aAmount) { return GetResident(aAmount); } + NS_IMETHOD GetAmount(int64_t* aAmount) + { + return ResidentDistinguishedAmount(aAmount); + } }; #endif // HAVE_VSIZE_AND_RESIDENT_REPORTERS @@ -1299,7 +1321,7 @@ NS_IMETHODIMP nsMemoryReporterManager::GetVsize(int64_t* aVsize) { #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS - return ::GetVsize(aVsize); + return VsizeDistinguishedAmount(aVsize); #else *aResident = 0; return NS_ERROR_NOT_AVAILABLE; @@ -1310,7 +1332,7 @@ NS_IMETHODIMP nsMemoryReporterManager::GetVsizeMaxContiguous(int64_t* aAmount) { #ifdef HAVE_VSIZE_MAX_CONTIGUOUS_REPORTER - return ::GetVsizeMaxContiguous(aAmount); + return VsizeMaxContiguousDistinguishedAmount(aAmount); #else *aAmount = 0; return NS_ERROR_NOT_AVAILABLE; @@ -1321,7 +1343,7 @@ NS_IMETHODIMP nsMemoryReporterManager::GetResident(int64_t* aAmount) { #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS - return ::GetResident(aAmount); + return ResidentDistinguishedAmount(aAmount); #else *aAmount = 0; return NS_ERROR_NOT_AVAILABLE; @@ -1332,7 +1354,7 @@ NS_IMETHODIMP nsMemoryReporterManager::GetResidentFast(int64_t* aAmount) { #ifdef HAVE_VSIZE_AND_RESIDENT_REPORTERS - return ::GetResidentFast(aAmount); + return ResidentFastDistinguishedAmount(aAmount); #else *aAmount = 0; return NS_ERROR_NOT_AVAILABLE; From 362ecb8b1ae4fa4c78e9718d3550a2d5f59a5ab7 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 19 Nov 2013 14:38:29 -0800 Subject: [PATCH 023/268] Backed out 4 changesets (bug 672843) for xpcshell bustage Backed out changeset bbb7760083ae (bug 672843) Backed out changeset eaf2fd75d7fc (bug 672843) Backed out changeset eb08cc206b8d (bug 672843) Backed out changeset 6a0e4afd52ab (bug 672843) --- accessible/src/windows/msaa/IUnknownImpl.cpp | 2 +- xpcom/base/ErrorList.h | 4 +- xpcom/base/nsAgg.h | 12 +- xpcom/base/nsCycleCollector.cpp | 33 ++--- xpcom/base/nsDebugImpl.cpp | 3 +- xpcom/base/nsErrorService.cpp | 3 +- xpcom/base/nsGZFileWriter.cpp | 25 ++-- xpcom/base/nsIMemoryReporter.idl | 3 +- xpcom/base/nsMacUtilsImpl.cpp | 3 +- xpcom/base/nsMemoryImpl.cpp | 3 +- xpcom/base/nsMemoryInfoDumper.cpp | 98 +++++--------- xpcom/base/nsMemoryReporterManager.cpp | 18 +-- xpcom/base/nsMessageLoop.cpp | 6 +- xpcom/base/nsSystemInfo.cpp | 12 +- xpcom/build/Omnijar.cpp | 6 +- xpcom/build/nsXPCOMStrings.cpp | 6 +- xpcom/build/nsXPComInit.cpp | 56 ++++---- xpcom/build/perfprobe.cpp | 3 +- xpcom/components/nsCategoryManager.cpp | 26 ++-- xpcom/components/nsComponentManager.cpp | 12 +- xpcom/ds/nsHashPropertyBag.cpp | 3 +- xpcom/ds/nsINIParserImpl.cpp | 3 +- xpcom/ds/nsObserverService.cpp | 24 ++-- xpcom/ds/nsProperties.cpp | 17 +-- xpcom/ds/nsStringEnumerator.cpp | 31 +++-- xpcom/ds/nsSupportsArray.cpp | 3 +- xpcom/ds/nsSupportsPrimitives.cpp | 6 +- xpcom/ds/nsWindowsRegKey.cpp | 74 ++++------- xpcom/glue/nsArrayEnumerator.cpp | 1 + xpcom/glue/nsCOMArray.cpp | 3 +- xpcom/glue/nsComponentManagerUtils.cpp | 18 +-- xpcom/glue/nsDebug.h | 130 +++++++------------ xpcom/glue/nsINIParser.cpp | 3 +- xpcom/glue/nsMemory.cpp | 3 +- xpcom/glue/nsThreadUtils.cpp | 36 ++--- xpcom/glue/nsThreadUtils.h | 3 +- xpcom/io/Base64.cpp | 3 +- xpcom/io/CocoaFileUtils.mm | 20 ++- xpcom/io/nsAnonymousTemporaryFile.cpp | 36 ++--- xpcom/io/nsAppFileLocationProvider.cpp | 19 +-- xpcom/io/nsBinaryStream.cpp | 106 ++++++--------- xpcom/io/nsDirectoryService.cpp | 24 ++-- xpcom/io/nsIOUtil.cpp | 8 +- xpcom/io/nsInputStreamTee.cpp | 16 +-- xpcom/io/nsLocalFileCommon.cpp | 6 +- xpcom/io/nsLocalFileUnix.cpp | 93 +++++-------- xpcom/io/nsLocalFileWin.cpp | 72 ++++------ xpcom/io/nsMultiplexInputStream.cpp | 58 +++------ xpcom/io/nsPipe3.cpp | 3 +- xpcom/io/nsStorageStream.cpp | 31 +++-- xpcom/io/nsStringStream.cpp | 19 +-- xpcom/reflect/xptcall/src/xptcall.cpp | 6 +- xpcom/threads/LazyIdleThread.cpp | 42 ++---- xpcom/threads/nsEnvironment.cpp | 12 +- xpcom/threads/nsMemoryPressure.cpp | 1 + xpcom/threads/nsProcessCommon.cpp | 9 +- xpcom/threads/nsThread.cpp | 48 ++++--- xpcom/threads/nsThreadManager.cpp | 15 +-- xpcom/threads/nsThreadPool.cpp | 9 +- xpcom/threads/nsTimerImpl.cpp | 19 +-- 60 files changed, 499 insertions(+), 868 deletions(-) diff --git a/accessible/src/windows/msaa/IUnknownImpl.cpp b/accessible/src/windows/msaa/IUnknownImpl.cpp index 4a9fa5383b23..f6ae9f6a132c 100644 --- a/accessible/src/windows/msaa/IUnknownImpl.cpp +++ b/accessible/src/windows/msaa/IUnknownImpl.cpp @@ -23,7 +23,7 @@ GetHRESULT(nsresult aResult) case NS_OK: return S_OK; - case NS_ERROR_INVALID_ARG: + case NS_ERROR_INVALID_ARG: case NS_ERROR_INVALID_POINTER: return E_INVALIDARG; case NS_ERROR_OUT_OF_MEMORY: diff --git a/xpcom/base/ErrorList.h b/xpcom/base/ErrorList.h index 94cd4893e969..1552bb0e11d6 100644 --- a/xpcom/base/ErrorList.h +++ b/xpcom/base/ErrorList.h @@ -16,6 +16,8 @@ /* Returned when a given interface is not supported. */ ERROR(NS_NOINTERFACE, 0x80004002), ERROR(NS_ERROR_NO_INTERFACE, NS_NOINTERFACE), + ERROR(NS_ERROR_INVALID_POINTER, 0x80004003), + ERROR(NS_ERROR_NULL_POINTER, NS_ERROR_INVALID_POINTER), /* Returned when a function aborts */ ERROR(NS_ERROR_ABORT, 0x80004004), /* Returned when a function fails */ @@ -27,8 +29,6 @@ /* Returned when an illegal value is passed */ ERROR(NS_ERROR_ILLEGAL_VALUE, 0x80070057), ERROR(NS_ERROR_INVALID_ARG, NS_ERROR_ILLEGAL_VALUE), - ERROR(NS_ERROR_INVALID_POINTER, NS_ERROR_INVALID_ARG), - ERROR(NS_ERROR_NULL_POINTER, NS_ERROR_INVALID_ARG), /* Returned when a class doesn't allow aggregation */ ERROR(NS_ERROR_NO_AGGREGATION, 0x80040110), /* Returned when an operation can't complete due to an unavailable resource */ diff --git a/xpcom/base/nsAgg.h b/xpcom/base/nsAgg.h index bd1a36d52cc9..5b9ff7227978 100644 --- a/xpcom/base/nsAgg.h +++ b/xpcom/base/nsAgg.h @@ -285,9 +285,9 @@ static nsresult \ _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ void **aResult) \ { \ - *aResult = nullptr; \ - if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ - return NS_ERROR_INVALID_ARG; \ + *aResult = nullptr; \ + \ + NS_ENSURE_PROPER_AGGREGATION(aOuter, aIID); \ \ _InstanceClass* inst = new _InstanceClass(aOuter); \ if (!inst) { \ @@ -308,9 +308,9 @@ static nsresult \ _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ void **aResult) \ { \ - *aResult = nullptr; \ - if (NS_WARN_IF(aOuter && !aIID.Equals(NS_GET_IID(nsISupports)))) \ - return NS_ERROR_INVALID_ARG; \ + *aResult = nullptr; \ + \ + NS_ENSURE_PROPER_AGGREGATION(aOuter, aIID); \ \ _InstanceClass* inst = new _InstanceClass(aOuter); \ if (!inst) { \ diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index a88436d36e83..4079ca38ca56 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -1221,14 +1221,12 @@ public: // want scripts which poll the filesystem looking for gc/cc dumps to // grab a file before we're finished writing to it.) nsCOMPtr gcLogFile = CreateTempFile("incomplete-gc-edges"); - if (NS_WARN_IF(!gcLogFile)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(gcLogFile); // Dump the JS heap. FILE* gcLogANSIFile = nullptr; gcLogFile->OpenANSIFileDesc("w", &gcLogANSIFile); - if (NS_WARN_IF(!gcLogANSIFile)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(gcLogANSIFile); MozillaRegisterDebugFILE(gcLogANSIFile); CollectorData *data = sCollectorData.get(); if (data && data->mRuntime) @@ -1239,13 +1237,11 @@ public: // Strip off "incomplete-". nsCOMPtr gcLogFileFinalDestination = CreateTempFile("gc-edges"); - if (NS_WARN_IF(!gcLogFileFinalDestination)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(gcLogFileFinalDestination); nsAutoString gcLogFileFinalDestinationName; gcLogFileFinalDestination->GetLeafName(gcLogFileFinalDestinationName); - if (NS_WARN_IF(gcLogFileFinalDestinationName.IsEmpty())) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(!gcLogFileFinalDestinationName.IsEmpty()); gcLogFile->MoveTo(/* directory */ nullptr, gcLogFileFinalDestinationName); @@ -1264,12 +1260,10 @@ public: // Open a file for dumping the CC graph. We again prefix with // "incomplete-". mOutFile = CreateTempFile("incomplete-cc-edges"); - if (NS_WARN_IF(!mOutFile)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mOutFile); MOZ_ASSERT(!mStream); mOutFile->OpenANSIFileDesc("w", &mStream); - if (NS_WARN_IF(!mStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mStream); MozillaRegisterDebugFILE(mStream); fprintf(mStream, "# WantAllTraces=%s\n", mWantAllTraces ? "true" : "false"); @@ -1394,13 +1388,11 @@ public: // Strip off "incomplete-" from the log file's name. nsCOMPtr logFileFinalDestination = CreateTempFile("cc-edges"); - if (NS_WARN_IF(!logFileFinalDestination)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(logFileFinalDestination); nsAutoString logFileFinalDestinationName; logFileFinalDestination->GetLeafName(logFileFinalDestinationName); - if (NS_WARN_IF(logFileFinalDestinationName.IsEmpty())) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(!logFileFinalDestinationName.IsEmpty()); mOutFile->MoveTo(/* directory = */ nullptr, logFileFinalDestinationName); @@ -1423,8 +1415,7 @@ public: NS_IMETHOD ProcessNext(nsICycleCollectorHandler* aHandler, bool* aCanContinue) { - if (NS_WARN_IF(!aHandler) || NS_WARN_IF(!mWantAfterProcessing)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(aHandler && mWantAfterProcessing); CCGraphDescriber* d = mDescribers.popFirst(); if (d) { switch (d->mType) { @@ -1524,8 +1515,7 @@ nsCycleCollectorLoggerConstructor(nsISupports* aOuter, const nsIID& aIID, void* *aInstancePtr) { - if (NS_WARN_IF(aOuter)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_TRUE(!aOuter, NS_ERROR_NO_AGGREGATION); nsISupports *logger = new nsCycleCollectorLogger(); @@ -2448,8 +2438,7 @@ class CycleCollectorReporter MOZ_FINAL : public MemoryMultiReporter nsIMemoryReporter::KIND_HEAP, \ nsIMemoryReporter::UNITS_BYTES, _amount, \ NS_LITERAL_CSTRING(_desc), aClosure); \ - if (NS_WARN_IF(NS_FAILED(rv))) \ - return rv; \ + NS_ENSURE_SUCCESS(rv, rv); \ } \ } while (0) diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index 3cb01f4432a2..cd9e12a1d0ca 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -565,8 +565,7 @@ static const nsDebugImpl kImpl; nsresult nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_NO_AGGREGATION(outer); return const_cast(&kImpl)-> QueryInterface(aIID, aInstancePtr); diff --git a/xpcom/base/nsErrorService.cpp b/xpcom/base/nsErrorService.cpp index 58ef07b817fc..dd5464d7e5c7 100644 --- a/xpcom/base/nsErrorService.cpp +++ b/xpcom/base/nsErrorService.cpp @@ -65,8 +65,7 @@ NS_IMPL_ISUPPORTS1(nsErrorService, nsIErrorService) nsresult nsErrorService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_NO_AGGREGATION(outer); nsRefPtr serv = new nsErrorService(); return serv->QueryInterface(aIID, aInstancePtr); } diff --git a/xpcom/base/nsGZFileWriter.cpp b/xpcom/base/nsGZFileWriter.cpp index 166e199d54cf..c1e96cacf476 100644 --- a/xpcom/base/nsGZFileWriter.cpp +++ b/xpcom/base/nsGZFileWriter.cpp @@ -33,25 +33,21 @@ nsGZFileWriter::~nsGZFileWriter() NS_IMETHODIMP nsGZFileWriter::Init(nsIFile* aFile) { - if (NS_WARN_IF(mInitialized) || - NS_WARN_IF(mFinished)) - return NS_ERROR_FAILURE; + NS_ENSURE_FALSE(mInitialized, NS_ERROR_FAILURE); + NS_ENSURE_FALSE(mFinished, NS_ERROR_FAILURE); // Get a FILE out of our nsIFile. Convert that into a file descriptor which // gzip can own. Then close our FILE, leaving only gzip's fd open. FILE* file; nsresult rv = aFile->OpenANSIFileDesc("wb", &file); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mGZFile = gzdopen(dup(fileno(file)), "wb"); fclose(file); // gzdopen returns nullptr on error. - if (NS_WARN_IF(!mGZFile)) - return NS_ERROR_FAILURE; - + NS_ENSURE_TRUE(mGZFile, NS_ERROR_FAILURE); mInitialized = true; return NS_OK; @@ -60,9 +56,8 @@ nsGZFileWriter::Init(nsIFile* aFile) NS_IMETHODIMP nsGZFileWriter::Write(const nsACString& aStr) { - if (NS_WARN_IF(!mInitialized) || - NS_WARN_IF(mFinished)) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_FALSE(mFinished, NS_ERROR_FAILURE); // gzwrite uses a return value of 0 to indicate failure. Otherwise, it // returns the number of uncompressed bytes written. To ensure we can @@ -76,8 +71,7 @@ nsGZFileWriter::Write(const nsACString& aStr) // always be either 0 or aStr.Length(), and we shouldn't have to call it // multiple times in order to get it to read the whole buffer. int rv = gzwrite(mGZFile, aStr.BeginReading(), aStr.Length()); - if (NS_WARN_IF(rv != static_cast(aStr.Length()))) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(rv == static_cast(aStr.Length()), NS_ERROR_FAILURE); return NS_OK; } @@ -85,9 +79,8 @@ nsGZFileWriter::Write(const nsACString& aStr) NS_IMETHODIMP nsGZFileWriter::Finish() { - if (NS_WARN_IF(!mInitialized) || - NS_WARN_IF(mFinished)) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_FALSE(mFinished, NS_ERROR_FAILURE); mFinished = true; gzclose(mGZFile); diff --git a/xpcom/base/nsIMemoryReporter.idl b/xpcom/base/nsIMemoryReporter.idl index df2154451e14..5a64aa83a911 100644 --- a/xpcom/base/nsIMemoryReporter.idl +++ b/xpcom/base/nsIMemoryReporter.idl @@ -535,8 +535,7 @@ public: { int64_t amount; nsresult rv = GetAmount(&amount); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return aCallback->Callback(EmptyCString(), mNameAndPath, mKind, mUnits, amount, mDescription, aData); diff --git a/xpcom/base/nsMacUtilsImpl.cpp b/xpcom/base/nsMacUtilsImpl.cpp index bf9828ad8499..84a030051dc9 100644 --- a/xpcom/base/nsMacUtilsImpl.cpp +++ b/xpcom/base/nsMacUtilsImpl.cpp @@ -89,8 +89,7 @@ nsresult nsMacUtilsImpl::GetArchString(nsAString& archString) NS_IMETHODIMP nsMacUtilsImpl::GetIsUniversalBinary(bool *aIsUniversalBinary) { - if (NS_WARN_IF(!aIsUniversalBinary)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aIsUniversalBinary); *aIsUniversalBinary = false; nsAutoString archString; diff --git a/xpcom/base/nsMemoryImpl.cpp b/xpcom/base/nsMemoryImpl.cpp index 2b25086e13f4..f8b9bfc5a236 100644 --- a/xpcom/base/nsMemoryImpl.cpp +++ b/xpcom/base/nsMemoryImpl.cpp @@ -93,8 +93,7 @@ nsMemoryImpl::IsLowMemoryPlatform(bool *result) /*static*/ nsresult nsMemoryImpl::Create(nsISupports* outer, const nsIID& aIID, void **aResult) { - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_NO_AGGREGATION(outer); return sGlobalMemory.QueryInterface(aIID, aResult); } diff --git a/xpcom/base/nsMemoryInfoDumper.cpp b/xpcom/base/nsMemoryInfoDumper.cpp index 23a4d5fcc5e0..c5ae19f08404 100644 --- a/xpcom/base/nsMemoryInfoDumper.cpp +++ b/xpcom/base/nsMemoryInfoDumper.cpp @@ -416,18 +416,15 @@ public: } } else { rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(file)); - if (NS_WARN_IF(NS_FAILED(rv))) - return -1; + NS_ENSURE_SUCCESS(rv, -1); } rv = file->AppendNative(NS_LITERAL_CSTRING("debug_info_trigger")); - if (NS_WARN_IF(NS_FAILED(rv))) - return -1; + NS_ENSURE_SUCCESS(rv, -1); nsAutoCString path; rv = file->GetNativePath(path); - if (NS_WARN_IF(NS_FAILED(rv))) - return -1; + NS_ENSURE_SUCCESS(rv, -1); // unlink might fail because the file doesn't exist, or for other reasons. // But we don't care it fails; any problems will be detected later, when we @@ -609,8 +606,7 @@ namespace mozilla { #define DUMP(o, s) \ do { \ nsresult rv = (o)->Write(s); \ - if (NS_WARN_IF(NS_FAILED(rv))) \ - return rv; \ + NS_ENSURE_SUCCESS(rv, rv); \ } while (0) static nsresult @@ -684,8 +680,7 @@ public: nsISupports *aData) { nsCOMPtr writer = do_QueryInterface(aData); - if (NS_WARN_IF(!writer)) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(writer, NS_ERROR_FAILURE); nsresult rv = DumpReport(writer, mIsFirst, aProcess, aPath, aKind, aUnits, aAmount, aDescription); @@ -727,8 +722,7 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) nsresult rv; if (!*aFile) { rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, aFile); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } #ifdef ANDROID @@ -737,8 +731,7 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) // users to be able to remove these files, so we write them into a // subdirectory of the temp directory and chmod 777 that directory. rv = (*aFile)->AppendNative(NS_LITERAL_CSTRING("memory-reports")); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // It's OK if this fails; that probably just means that the directory already // exists. @@ -746,8 +739,7 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) nsAutoCString dirPath; rv = (*aFile)->GetNativePath(dirPath); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); while (chmod(dirPath.get(), 0777) == -1 && errno == EINTR) {} #endif @@ -755,12 +747,10 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) nsCOMPtr file(*aFile); rv = file->AppendNative(aFilename); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = file->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0666); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); #ifdef ANDROID // Make this file world-read/writable; the permissions passed to the @@ -768,8 +758,7 @@ nsMemoryInfoDumper::OpenTempFile(const nsACString &aFilename, nsIFile* *aFile) // umask. nsAutoCString path; rv = file->GetNativePath(path); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); while (chmod(path.get(), 0666) == -1 && errno == EINTR) {} #endif @@ -812,8 +801,7 @@ DumpHeader(nsIGZFileWriter* aWriter) nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); - if (NS_WARN_IF(!mgr)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mgr); DUMP(aWriter, mgr->GetHasMozMallocUsableSize() ? "true" : "false"); DUMP(aWriter, ",\n"); @@ -884,12 +872,11 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) rv = nsMemoryInfoDumper::OpenTempFile(NS_LITERAL_CSTRING("incomplete-") + mrFilename, getter_AddRefs(mrTmpFile)); - if (NS_WARN_IF(NS_FAILED(rv))) return rv; + NS_ENSURE_SUCCESS(rv, rv); nsRefPtr mrWriter = new nsGZFileWriter(); rv = mrWriter->Init(mrTmpFile); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Dump the memory reports to the file. DumpProcessMemoryReportsToGZFileWriter(mrWriter); @@ -907,13 +894,11 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) nsCOMPtr dmdFile; rv = nsMemoryInfoDumper::OpenTempFile(dmdFilename, getter_AddRefs(dmdFile)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsRefPtr dmdWriter = new nsGZFileWriter(); rv = dmdWriter->Init(dmdFile); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Dump DMD output to the file. @@ -922,8 +907,7 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) dmd::Dump(w); rv = dmdWriter->Finish(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); #endif // MOZ_DMD // The call to Finish() deallocates the memory allocated by mrWriter's first @@ -932,51 +916,42 @@ DumpProcessMemoryInfoToTempDir(const nsAString& aIdentifier) // them -- by "heap-allocated" if nothing else -- we want DMD to see it as // well. So we deliberately don't call Finish() until after DMD finishes. rv = mrWriter->Finish(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Rename the memory reports file, now that we're done writing all the files. // Its final name is "memory-report<-identifier>-.json.gz". nsCOMPtr mrFinalFile; rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(mrFinalFile)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); #ifdef ANDROID rv = mrFinalFile->AppendNative(NS_LITERAL_CSTRING("memory-reports")); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); #endif rv = mrFinalFile->AppendNative(mrFilename); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = mrFinalFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsAutoString mrActualFinalFilename; rv = mrFinalFile->GetLeafName(mrActualFinalFilename); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = mrTmpFile->MoveTo(/* directory */ nullptr, mrActualFinalFilename); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Write a message to the console. nsCOMPtr cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsString path; mrTmpFile->GetPath(path); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsString msg = NS_LITERAL_STRING( "nsIMemoryInfoDumper dumped reports to "); @@ -1013,8 +988,7 @@ nsMemoryInfoDumper::DumpMemoryInfoToTempDir(const nsAString& aIdentifier, /* dumpChildProcesses = */ false); nsCOMPtr mgr = do_GetService("@mozilla.org/memory-reporter-manager;1"); - if (NS_WARN_IF(!mgr)) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE); nsCOMPtr runnable; mgr->MinimizeMemoryUsage(callback, getter_AddRefs(runnable)); return NS_OK; @@ -1069,34 +1043,28 @@ nsMemoryInfoDumper::DumpMemoryReportsToNamedFile( nsCOMPtr mrFile; nsresult rv = NS_NewLocalFile(aFilename, false, getter_AddRefs(mrFile)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mrFile->InitWithPath(aFilename); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); bool exists; rv = mrFile->Exists(&exists); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); if (!exists) { rv = mrFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } // Write the memory reports to the file. nsRefPtr mrWriter = new nsGZFileWriter(); rv = mrWriter->Init(mrFile); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = DumpHeader(mrWriter); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Process reports and finish up. nsRefPtr dumpReport = new DumpReportCallback(); diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index aa6cc938b46e..3b470b9ae162 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -102,8 +102,7 @@ private: *aAmount = 0; FILE *f = fopen("/proc/self/smaps", "r"); - if (NS_WARN_IF(!f)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(f); int64_t total = 0; char line[256]; @@ -753,8 +752,7 @@ public: nsIMemoryReporter::KIND_HEAP, \ nsIMemoryReporter::UNITS_BYTES, _amount, \ NS_LITERAL_CSTRING(_desc), aData); \ - if (NS_WARN_IF(NS_FAILED(rv))) \ - return rv; \ + NS_ENSURE_SUCCESS(rv, rv); \ } while (0) REPORT("explicit/dmd/stack-traces/used", @@ -1286,8 +1284,7 @@ NS_IMPL_ISUPPORTS1(ExplicitCallback, nsIHandleReportCallback) NS_IMETHODIMP nsMemoryReporterManager::GetExplicit(int64_t* aAmount) { - if (NS_WARN_IF(!aAmount)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aAmount); *aAmount = 0; #ifndef HAVE_JEMALLOC_STATS return NS_ERROR_NOT_AVAILABLE; @@ -1553,8 +1550,7 @@ NS_IMETHODIMP nsMemoryReporterManager::MinimizeMemoryUsage(nsIRunnable* aCallback, nsICancelableRunnable** aResult) { - if (NS_WARN_IF(!aResult)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); nsRefPtr runnable = new MinimizeMemoryUsageRunnable(aCallback); @@ -1577,8 +1573,7 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, { nsCOMPtr global = do_QueryInterface(aTopWindow); nsCOMPtr piWindow = do_QueryInterface(aTopWindow); - if (NS_WARN_IF(!global) || NS_WARN_IF(!piWindow)) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(!!global && !!piWindow, NS_ERROR_FAILURE); TimeStamp t1 = TimeStamp::Now(); @@ -1588,8 +1583,7 @@ nsMemoryReporterManager::SizeOfTab(nsIDOMWindow* aTopWindow, nsresult rv = mSizeOfTabFns.mJS(global->GetGlobalJSObject(), &jsObjectsSize, &jsStringsSize, &jsPrivateSize, &jsOtherSize); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); TimeStamp t2 = TimeStamp::Now(); diff --git a/xpcom/base/nsMessageLoop.cpp b/xpcom/base/nsMessageLoop.cpp index 8ef4c17a39a2..0f1bd536e4e2 100644 --- a/xpcom/base/nsMessageLoop.cpp +++ b/xpcom/base/nsMessageLoop.cpp @@ -87,8 +87,7 @@ nsresult MessageLoopIdleTask::Init(uint32_t aEnsureRunsAfterMS) { mTimer = do_CreateInstance("@mozilla.org/timer;1"); - if (NS_WARN_IF(!mTimer)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mTimer); nsRefPtr callback = new MessageLoopTimerCallback(this); @@ -154,8 +153,7 @@ nsMessageLoopConstructor(nsISupports* aOuter, const nsIID& aIID, void** aInstancePtr) { - if (NS_WARN_IF(aOuter)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_FALSE(aOuter, NS_ERROR_NO_AGGREGATION); nsISupports* messageLoop = new nsMessageLoop(); return messageLoop->QueryInterface(aIID, aInstancePtr); } diff --git a/xpcom/base/nsSystemInfo.cpp b/xpcom/base/nsSystemInfo.cpp index 0c32ac7901a5..9439092ee94f 100644 --- a/xpcom/base/nsSystemInfo.cpp +++ b/xpcom/base/nsSystemInfo.cpp @@ -165,8 +165,7 @@ nsSystemInfo::Init() if (PR_GetSystemInfo(items[i].cmd, buf, sizeof(buf)) == PR_SUCCESS) { rv = SetPropertyAsACString(NS_ConvertASCIItoUTF16(items[i].name), nsDependentCString(buf)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } else { NS_WARNING("PR_GetSystemInfo failed"); @@ -183,8 +182,7 @@ nsSystemInfo::Init() for (uint32_t i = 0; i < ArrayLength(cpuPropItems); i++) { rv = SetPropertyAsBool(NS_ConvertASCIItoUTF16(cpuPropItems[i].name), cpuPropItems[i].propfun()); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } #ifdef XP_WIN @@ -193,8 +191,7 @@ nsSystemInfo::Init() NS_WARN_IF_FALSE(gotWow64Value, "IsWow64Process failed"); if (gotWow64Value) { rv = SetPropertyAsBool(NS_LITERAL_STRING("isWow64"), !!isWow64); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } nsAutoCString hddModel, hddRevision; if (NS_SUCCEEDED(GetProfileHDDInfo(hddModel, hddRevision))) { @@ -213,8 +210,7 @@ nsSystemInfo::Init() rv = SetPropertyAsACString(NS_LITERAL_STRING("secondaryLibrary"), nsDependentCString(gtkver)); PR_smprintf_free(gtkver); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } #endif diff --git a/xpcom/build/Omnijar.cpp b/xpcom/build/Omnijar.cpp index 3bc74178821a..4d75c7ef7b55 100644 --- a/xpcom/build/Omnijar.cpp +++ b/xpcom/build/Omnijar.cpp @@ -145,8 +145,7 @@ Omnijar::GetURIString(Type aType, nsACString &result) nsAutoCString omniJarSpec; if (sPath[aType]) { nsresult rv = NS_GetURLSpecFromActualFile(sPath[aType], omniJarSpec); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); result = "jar:"; if (sIsNested[aType]) @@ -159,8 +158,7 @@ Omnijar::GetURIString(Type aType, nsACString &result) nsCOMPtr dir; nsDirectoryService::gService->Get(SPROP(aType), NS_GET_IID(nsIFile), getter_AddRefs(dir)); nsresult rv = NS_GetURLSpecFromActualFile(dir, result); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } result += "/"; return NS_OK; diff --git a/xpcom/build/nsXPCOMStrings.cpp b/xpcom/build/nsXPCOMStrings.cpp index 02796a835b1e..d5df93ac3215 100644 --- a/xpcom/build/nsXPCOMStrings.cpp +++ b/xpcom/build/nsXPCOMStrings.cpp @@ -40,8 +40,7 @@ NS_StringContainerInit2(nsStringContainer &aContainer, { if (aDataLength == UINT32_MAX) { - if (NS_WARN_IF(aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(!(aFlags & NS_STRING_CONTAINER_INIT_SUBSTRING)); aDataLength = nsCharTraits::length(aData); } @@ -201,8 +200,7 @@ NS_CStringContainerInit2(nsCStringContainer &aContainer, { if (aDataLength == UINT32_MAX) { - if (NS_WARN_IF(aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(!(aFlags & NS_CSTRING_CONTAINER_INIT_SUBSTRING)); aDataLength = nsCharTraits::length(aData); } diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index c3784f3f9724..de58a8acd9e7 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -219,8 +219,7 @@ nsThreadManagerGetSingleton(nsISupports* outer, void* *aInstancePtr) { NS_ASSERTION(aInstancePtr, "null outptr"); - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); return nsThreadManager::get()->QueryInterface(aIID, aInstancePtr); } @@ -233,8 +232,7 @@ nsXPTIInterfaceInfoManagerGetSingleton(nsISupports* outer, void* *aInstancePtr) { NS_ASSERTION(aInstancePtr, "null outptr"); - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); nsCOMPtr iim (XPTInterfaceInfoManager::GetSingleton()); @@ -315,16 +313,16 @@ static nsIDebug* gDebug = nullptr; EXPORT_XPCOM_API(nsresult) NS_GetDebug(nsIDebug** result) { - return nsDebugImpl::Create(nullptr, - NS_GET_IID(nsIDebug), + return nsDebugImpl::Create(nullptr, + NS_GET_IID(nsIDebug), (void**) result); } EXPORT_XPCOM_API(nsresult) NS_GetTraceRefcnt(nsITraceRefcnt** result) { - return nsTraceRefcntImpl::Create(nullptr, - NS_GET_IID(nsITraceRefcnt), + return nsTraceRefcntImpl::Create(nullptr, + NS_GET_IID(nsITraceRefcnt), (void**) result); } @@ -413,38 +411,38 @@ NS_InitXPCOM2(nsIServiceManager* *result, if (!AtExitManager::AlreadyRegistered()) { sExitManager = new AtExitManager(); + NS_ENSURE_STATE(sExitManager); } if (!MessageLoop::current()) { sMessageLoop = new MessageLoopForUI(MessageLoop::TYPE_MOZILLA_UI); + NS_ENSURE_STATE(sMessageLoop); } if (XRE_GetProcessType() == GeckoProcessType_Default && !BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO)) { scoped_ptr ioThread( new BrowserProcessSubThread(BrowserProcessSubThread::IO)); + NS_ENSURE_TRUE(ioThread.get(), NS_ERROR_OUT_OF_MEMORY); base::Thread::Options options; options.message_loop_type = MessageLoop::TYPE_IO; - if (NS_WARN_IF(!ioThread->StartWithOptions(options))) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(ioThread->StartWithOptions(options), NS_ERROR_FAILURE); sIOThread = ioThread.release(); } // Establish the main thread here. rv = nsThreadManager::get()->Init(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + if (NS_FAILED(rv)) return rv; // Set up the timer globals/timer thread rv = nsTimerImpl::Startup(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); #ifndef ANDROID // If the locale hasn't already been setup by our embedder, - // get us out of the "C" locale and into the system + // get us out of the "C" locale and into the system if (strcmp(setlocale(LC_ALL, nullptr), "C") == 0) setlocale(LC_ALL, ""); #endif @@ -495,21 +493,18 @@ NS_InitXPCOM2(nsIServiceManager* *result, CommandLine::Init(0, nullptr); #else nsCOMPtr binaryFile; - nsDirectoryService::gService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, - NS_GET_IID(nsIFile), + nsDirectoryService::gService->Get(NS_XPCOM_CURRENT_PROCESS_DIR, + NS_GET_IID(nsIFile), getter_AddRefs(binaryFile)); - if (NS_WARN_IF(!binaryFile)) - return NS_ERROR_FAILURE; - + NS_ENSURE_STATE(binaryFile); + rv = binaryFile->AppendNative(NS_LITERAL_CSTRING("nonexistent-executable")); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - + NS_ENSURE_SUCCESS(rv, rv); + nsCString binaryPath; rv = binaryFile->GetNativePath(binaryPath); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - + NS_ENSURE_SUCCESS(rv, rv); + static char const *const argv = { strdup(binaryPath.get()) }; CommandLine::Init(1, &argv); #endif @@ -573,7 +568,7 @@ NS_InitXPCOM2(nsIServiceManager* *result, mozilla::AvailableMemoryTracker::Activate(); // Notify observers of xpcom autoregistration start - NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_CATEGORY, + NS_CreateServicesFromCategory(NS_XPCOM_STARTUP_CATEGORY, nullptr, NS_XPCOM_STARTUP_OBSERVER_ID); #ifdef XP_WIN @@ -631,9 +626,7 @@ ShutdownXPCOM(nsIServiceManager* servMgr) // Make sure the hang monitor is enabled for shutdown. HangMonitor::NotifyActivity(); - if (!NS_IsMainThread()) { - NS_RUNTIMEABORT("Shutdown on wrong thread"); - } + NS_ENSURE_STATE(NS_IsMainThread()); nsresult rv; nsCOMPtr moduleLoaders; @@ -644,8 +637,7 @@ ShutdownXPCOM(nsIServiceManager* servMgr) // servicemanager shutdown nsCOMPtr thread = do_GetCurrentThread(); - if (NS_WARN_IF(!thread)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(thread); nsRefPtr observerService; CallGetService("@mozilla.org/observer-service;1", diff --git a/xpcom/build/perfprobe.cpp b/xpcom/build/perfprobe.cpp index 6c584b50c5a0..f74eb978e829 100644 --- a/xpcom/build/perfprobe.cpp +++ b/xpcom/build/perfprobe.cpp @@ -213,8 +213,7 @@ nsresult ProbeManager::StartSession(nsTArray> &aProbes) used only for unregistration*/ ); delete[] probes; - if (NS_WARN_IF(result != ERROR_SUCCESS)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(result == ERROR_SUCCESS, NS_ERROR_UNEXPECTED); return NS_OK; } diff --git a/xpcom/components/nsCategoryManager.cpp b/xpcom/components/nsCategoryManager.cpp index 6e2b43a635a7..b35dc180665a 100644 --- a/xpcom/components/nsCategoryManager.cpp +++ b/xpcom/components/nsCategoryManager.cpp @@ -299,8 +299,7 @@ CategoryNode::DeleteLeaf(const char* aEntryName) NS_METHOD CategoryNode::Enumerate(nsISimpleEnumerator **_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); MutexAutoLock lock(mLock); EntryEnumerator* enumObj = EntryEnumerator::Create(mTable); @@ -594,10 +593,9 @@ nsCategoryManager::GetCategoryEntry( const char *aCategoryName, const char *aEntryName, char **_retval ) { - if (NS_WARN_IF(!aCategoryName) || - NS_WARN_IF(!aEntryName) || - NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG;; + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + NS_ENSURE_ARG_POINTER(_retval); nsresult status = NS_ERROR_NOT_AVAILABLE; @@ -689,9 +687,8 @@ nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName, const char *aEntryName, bool aDontPersist) { - if (NS_WARN_IF(!aCategoryName) || - NS_WARN_IF(!aEntryName)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); /* Note: no errors are reported since failure to delete @@ -718,8 +715,7 @@ nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName, NS_IMETHODIMP nsCategoryManager::DeleteCategory( const char *aCategoryName ) { - if (NS_WARN_IF(!aCategoryName)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aCategoryName); // the categories are arena-allocated, so we don't // actually delete them. We just remove all of the @@ -744,9 +740,8 @@ NS_IMETHODIMP nsCategoryManager::EnumerateCategory( const char *aCategoryName, nsISimpleEnumerator **_retval ) { - if (NS_WARN_IF(!aCategoryName) || - NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(_retval); CategoryNode* category; { @@ -764,8 +759,7 @@ nsCategoryManager::EnumerateCategory( const char *aCategoryName, NS_IMETHODIMP nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); MutexAutoLock lock(mLock); CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable); diff --git a/xpcom/components/nsComponentManager.cpp b/xpcom/components/nsComponentManager.cpp index af51024ac798..0d27e9f17f82 100644 --- a/xpcom/components/nsComponentManager.cpp +++ b/xpcom/components/nsComponentManager.cpp @@ -932,9 +932,8 @@ nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID, const nsIID &aIID, void **aResult) { - if (NS_WARN_IF(!aResult) || - NS_WARN_IF(!contractID)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(contractID); nsresult rv; @@ -1053,8 +1052,7 @@ nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID, const nsIID &aIID, void **aResult) { - if (NS_WARN_IF(!aContractID)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aContractID); // test this first, since there's no point in creating a component during // shutdown -- whether it's available or not would depend on the order it @@ -1609,9 +1607,7 @@ NS_IMETHODIMP nsComponentManagerImpl::IsContractIDRegistered(const char *aClass, bool *_retval) { - if (NS_WARN_IF(!aClass)) - return NS_ERROR_INVALID_ARG; - + NS_ENSURE_ARG_POINTER(aClass); nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass)); if (entry) diff --git a/xpcom/ds/nsHashPropertyBag.cpp b/xpcom/ds/nsHashPropertyBag.cpp index 9f60de99aedc..29ea0c8c3eb1 100644 --- a/xpcom/ds/nsHashPropertyBag.cpp +++ b/xpcom/ds/nsHashPropertyBag.cpp @@ -64,8 +64,7 @@ nsHashPropertyBag::GetProperty(const nsAString& name, nsIVariant* *_retval) NS_IMETHODIMP nsHashPropertyBag::SetProperty(const nsAString& name, nsIVariant *value) { - if (NS_WARN_IF(!value)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(value); mPropertyHash.Put(name, value); diff --git a/xpcom/ds/nsINIParserImpl.cpp b/xpcom/ds/nsINIParserImpl.cpp index 86d6241356c1..1e4421436378 100644 --- a/xpcom/ds/nsINIParserImpl.cpp +++ b/xpcom/ds/nsINIParserImpl.cpp @@ -51,8 +51,7 @@ nsINIParserFactory::CreateInstance(nsISupports* aOuter, REFNSIID aIID, void **aResult) { - if (NS_WARN_IF(aOuter)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_NO_AGGREGATION(aOuter); // We are our own singleton. return QueryInterface(aIID, aResult); diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index f79fc75505b9..b62b5d188531 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -150,8 +150,7 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "respect to the number of windows."), aClosure); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } rv = cb->Callback(/* process */ EmptyCString(), @@ -163,8 +162,7 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "observer service."), aClosure); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = cb->Callback(/* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/alive"), @@ -175,8 +173,7 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "observer service that are still alive."), aClosure); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = cb->Callback(/* process */ EmptyCString(), NS_LITERAL_CSTRING("observer-service/referent/weak/dead"), @@ -187,8 +184,7 @@ ObserverServiceReporter::CollectReports(nsIMemoryReporterCallback* cb, "observer service that are dead."), aClosure); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -270,8 +266,7 @@ nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, (void*) anObserver, aTopic)); NS_ENSURE_VALIDCALL - if (NS_WARN_IF(!anObserver) || NS_WARN_IF(!aTopic)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(anObserver && aTopic); if (mozilla::net::IsNeckoChild() && !strncmp(aTopic, "http-on-", 8)) { return NS_ERROR_NOT_IMPLEMENTED; @@ -290,8 +285,7 @@ nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic) LOG(("nsObserverService::RemoveObserver(%p: %s)", (void*) anObserver, aTopic)); NS_ENSURE_VALIDCALL - if (NS_WARN_IF(!anObserver) || NS_WARN_IF(!aTopic)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(anObserver && aTopic); nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); if (!observerList) @@ -308,8 +302,7 @@ nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator) { NS_ENSURE_VALIDCALL - if (NS_WARN_IF(!anEnumerator) || NS_WARN_IF(!aTopic)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aTopic && anEnumerator); nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); if (!observerList) @@ -326,8 +319,7 @@ NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject, LOG(("nsObserverService::NotifyObservers(%s)", aTopic)); NS_ENSURE_VALIDCALL - if (NS_WARN_IF(!aTopic)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aTopic); nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic); if (observerList) diff --git a/xpcom/ds/nsProperties.cpp b/xpcom/ds/nsProperties.cpp index 8df2e9445c82..27d1f28779e4 100644 --- a/xpcom/ds/nsProperties.cpp +++ b/xpcom/ds/nsProperties.cpp @@ -15,8 +15,7 @@ NS_INTERFACE_MAP_END NS_IMETHODIMP nsProperties::Get(const char* prop, const nsIID & uuid, void* *result) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); nsCOMPtr value; if (!nsProperties_HashBase::Get(prop, getter_AddRefs(value))) { @@ -28,8 +27,7 @@ nsProperties::Get(const char* prop, const nsIID & uuid, void* *result) NS_IMETHODIMP nsProperties::Set(const char* prop, nsISupports* value) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); Put(prop, value); return NS_OK; } @@ -37,8 +35,7 @@ nsProperties::Set(const char* prop, nsISupports* value) NS_IMETHODIMP nsProperties::Undefine(const char* prop) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); nsCOMPtr value; if (!nsProperties_HashBase::Get(prop, getter_AddRefs(value))) @@ -51,8 +48,7 @@ nsProperties::Undefine(const char* prop) NS_IMETHODIMP nsProperties::Has(const char* prop, bool *result) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); nsCOMPtr value; *result = nsProperties_HashBase::Get(prop, @@ -86,11 +82,12 @@ GetKeysEnumerate(const char *key, nsISupports* data, NS_IMETHODIMP nsProperties::GetKeys(uint32_t *count, char ***keys) { - if (NS_WARN_IF(!count) || NS_WARN_IF(!keys)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(count); + NS_ENSURE_ARG(keys); uint32_t n = Count(); char ** k = (char **) nsMemory::Alloc(n * sizeof(char *)); + NS_ENSURE_TRUE(k, NS_ERROR_OUT_OF_MEMORY); GetKeysEnumData gked; gked.keys = k; diff --git a/xpcom/ds/nsStringEnumerator.cpp b/xpcom/ds/nsStringEnumerator.cpp index 8af283354602..c71bd5cebbed 100644 --- a/xpcom/ds/nsStringEnumerator.cpp +++ b/xpcom/ds/nsStringEnumerator.cpp @@ -84,6 +84,7 @@ NS_IMPL_ISUPPORTS3(nsStringEnumerator, NS_IMETHODIMP nsStringEnumerator::HasMore(bool* aResult) { + NS_ENSURE_ARG_POINTER(aResult); *aResult = mIndex < Count(); return NS_OK; } @@ -118,8 +119,7 @@ nsStringEnumerator::GetNext(nsISupports** aResult) NS_IMETHODIMP nsStringEnumerator::GetNext(nsAString& aResult) { - if (NS_WARN_IF(mIndex >= Count())) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); if (mIsUnicode) aResult = mArray->ElementAt(mIndex++); @@ -132,8 +132,7 @@ nsStringEnumerator::GetNext(nsAString& aResult) NS_IMETHODIMP nsStringEnumerator::GetNext(nsACString& aResult) { - if (NS_WARN_IF(mIndex >= Count())) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(mIndex < Count(), NS_ERROR_UNEXPECTED); if (mIsUnicode) CopyUTF16toUTF8(mArray->ElementAt(mIndex++), aResult); @@ -161,8 +160,8 @@ nsresult NS_NewStringEnumerator(nsIStringEnumerator** aResult, const nsTArray* aArray, nsISupports* aOwner) { - if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); *aResult = new nsStringEnumerator(aArray, aOwner); return StringEnumeratorTail(aResult); @@ -173,8 +172,8 @@ nsresult NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, const nsTArray* aArray, nsISupports* aOwner) { - if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); *aResult = new nsStringEnumerator(aArray, aOwner); return StringEnumeratorTail(aResult); @@ -184,8 +183,8 @@ nsresult NS_NewAdoptingStringEnumerator(nsIStringEnumerator** aResult, nsTArray* aArray) { - if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); *aResult = new nsStringEnumerator(aArray, true); return StringEnumeratorTail(aResult); @@ -195,8 +194,8 @@ nsresult NS_NewAdoptingUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, nsTArray* aArray) { - if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); *aResult = new nsStringEnumerator(aArray, true); return StringEnumeratorTail(aResult); @@ -207,8 +206,8 @@ nsresult NS_NewStringEnumerator(nsIStringEnumerator** aResult, const nsTArray* aArray) { - if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); *aResult = new nsStringEnumerator(aArray, false); return StringEnumeratorTail(aResult); @@ -218,8 +217,8 @@ nsresult NS_NewUTF8StringEnumerator(nsIUTF8StringEnumerator** aResult, const nsTArray* aArray) { - if (NS_WARN_IF(!aResult) || NS_WARN_IF(!aArray)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_ARG_POINTER(aArray); *aResult = new nsStringEnumerator(aArray, false); return StringEnumeratorTail(aResult); diff --git a/xpcom/ds/nsSupportsArray.cpp b/xpcom/ds/nsSupportsArray.cpp index 1c742f0eff6e..176c73cf28d5 100644 --- a/xpcom/ds/nsSupportsArray.cpp +++ b/xpcom/ds/nsSupportsArray.cpp @@ -585,8 +585,7 @@ nsSupportsArray::Clone(nsISupportsArray** aResult) { nsCOMPtr newArray; nsresult rv = NS_NewISupportsArray(getter_AddRefs(newArray)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); uint32_t count = 0; Count(&count); diff --git a/xpcom/ds/nsSupportsPrimitives.cpp b/xpcom/ds/nsSupportsPrimitives.cpp index fb6d61427fa8..a5c4f1d6146d 100644 --- a/xpcom/ds/nsSupportsPrimitives.cpp +++ b/xpcom/ds/nsSupportsPrimitives.cpp @@ -810,8 +810,7 @@ nsSupportsDependentCString::nsSupportsDependentCString(const char* aStr) NS_IMETHODIMP nsSupportsDependentCString::GetType(uint16_t *aType) { - if (NS_WARN_IF(!aType)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aType); *aType = TYPE_CSTRING; return NS_OK; @@ -827,8 +826,7 @@ nsSupportsDependentCString::GetData(nsACString& aData) NS_IMETHODIMP nsSupportsDependentCString::ToString(char **_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = ToNewCString(mData); if (!*_retval) diff --git a/xpcom/ds/nsWindowsRegKey.cpp b/xpcom/ds/nsWindowsRegKey.cpp index 25b51b4e79b9..524e382061b9 100644 --- a/xpcom/ds/nsWindowsRegKey.cpp +++ b/xpcom/ds/nsWindowsRegKey.cpp @@ -103,8 +103,7 @@ NS_IMETHODIMP nsWindowsRegKey::OpenChild(const nsAString &path, uint32_t mode, nsIWindowsRegKey **result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); nsCOMPtr child = new nsWindowsRegKey(); @@ -120,8 +119,7 @@ NS_IMETHODIMP nsWindowsRegKey::CreateChild(const nsAString &path, uint32_t mode, nsIWindowsRegKey **result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); nsCOMPtr child = new nsWindowsRegKey(); @@ -136,15 +134,13 @@ nsWindowsRegKey::CreateChild(const nsAString &path, uint32_t mode, NS_IMETHODIMP nsWindowsRegKey::GetChildCount(uint32_t *result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); DWORD numSubKeys; LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, &numSubKeys, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); - if (rv != ERROR_SUCCESS) - return NS_ERROR_FAILURE; + NS_ENSURE_STATE(rv == ERROR_SUCCESS); *result = numSubKeys; return NS_OK; @@ -153,8 +149,7 @@ nsWindowsRegKey::GetChildCount(uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::GetChildName(uint32_t index, nsAString &result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); FILETIME lastWritten; @@ -174,8 +169,7 @@ nsWindowsRegKey::GetChildName(uint32_t index, nsAString &result) NS_IMETHODIMP nsWindowsRegKey::HasChild(const nsAString &name, bool *result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); // Check for the existence of a child key by opening the key with minimal // rights. Perhaps there is a more efficient way to do this? @@ -193,15 +187,13 @@ nsWindowsRegKey::HasChild(const nsAString &name, bool *result) NS_IMETHODIMP nsWindowsRegKey::GetValueCount(uint32_t *result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); DWORD numValues; LONG rv = RegQueryInfoKeyW(mKey, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &numValues, nullptr, nullptr, nullptr, nullptr); - if (rv != ERROR_SUCCESS) - return NS_ERROR_FAILURE; + NS_ENSURE_STATE(rv == ERROR_SUCCESS); *result = numValues; return NS_OK; @@ -210,8 +202,7 @@ nsWindowsRegKey::GetValueCount(uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::GetValueName(uint32_t index, nsAString &result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); PRUnichar nameBuf[MAX_VALUE_NAME_LEN]; DWORD nameLen = sizeof(nameBuf) / sizeof(nameBuf[0]); @@ -229,8 +220,7 @@ nsWindowsRegKey::GetValueName(uint32_t index, nsAString &result) NS_IMETHODIMP nsWindowsRegKey::HasValue(const nsAString &name, bool *result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, nullptr, nullptr); @@ -242,8 +232,7 @@ nsWindowsRegKey::HasValue(const nsAString &name, bool *result) NS_IMETHODIMP nsWindowsRegKey::RemoveChild(const nsAString &name) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); LONG rv = RegDeleteKeyW(mKey, PromiseFlatString(name).get()); @@ -253,8 +242,7 @@ nsWindowsRegKey::RemoveChild(const nsAString &name) NS_IMETHODIMP nsWindowsRegKey::RemoveValue(const nsAString &name) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); LONG rv = RegDeleteValueW(mKey, PromiseFlatString(name).get()); @@ -264,8 +252,7 @@ nsWindowsRegKey::RemoveValue(const nsAString &name) NS_IMETHODIMP nsWindowsRegKey::GetValueType(const nsAString &name, uint32_t *result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, (LPDWORD) result, nullptr, nullptr); @@ -276,8 +263,7 @@ nsWindowsRegKey::GetValueType(const nsAString &name, uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); DWORD type, size; @@ -289,12 +275,12 @@ nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result) // This must be a string type in order to fetch the value as a string. // We're being a bit forgiving here by allowing types other than REG_SZ. - if (type != REG_SZ && type == REG_EXPAND_SZ && type == REG_MULTI_SZ) - return NS_ERROR_FAILURE; + NS_ENSURE_STATE(type == REG_SZ || + type == REG_EXPAND_SZ || + type == REG_MULTI_SZ); // The buffer size must be a multiple of 2. - if (size % 2 != 0) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(size % 2 == 0); if (size == 0) { result.Truncate(); @@ -351,8 +337,7 @@ nsWindowsRegKey::ReadStringValue(const nsAString &name, nsAString &result) NS_IMETHODIMP nsWindowsRegKey::ReadIntValue(const nsAString &name, uint32_t *result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); DWORD size = sizeof(*result); LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, @@ -364,8 +349,7 @@ nsWindowsRegKey::ReadIntValue(const nsAString &name, uint32_t *result) NS_IMETHODIMP nsWindowsRegKey::ReadInt64Value(const nsAString &name, uint64_t *result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); DWORD size = sizeof(*result); LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, nullptr, @@ -377,8 +361,7 @@ nsWindowsRegKey::ReadInt64Value(const nsAString &name, uint64_t *result) NS_IMETHODIMP nsWindowsRegKey::ReadBinaryValue(const nsAString &name, nsACString &result) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); DWORD size; LONG rv = RegQueryValueExW(mKey, PromiseFlatString(name).get(), 0, @@ -402,8 +385,7 @@ nsWindowsRegKey::ReadBinaryValue(const nsAString &name, nsACString &result) NS_IMETHODIMP nsWindowsRegKey::WriteStringValue(const nsAString &name, const nsAString &value) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); // Need to indicate complete size of buffer including null terminator. const nsString &flatValue = PromiseFlatString(value); @@ -418,8 +400,7 @@ nsWindowsRegKey::WriteStringValue(const nsAString &name, const nsAString &value) NS_IMETHODIMP nsWindowsRegKey::WriteIntValue(const nsAString &name, uint32_t value) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_DWORD, (const BYTE *) &value, sizeof(value)); @@ -430,8 +411,7 @@ nsWindowsRegKey::WriteIntValue(const nsAString &name, uint32_t value) NS_IMETHODIMP nsWindowsRegKey::WriteInt64Value(const nsAString &name, uint64_t value) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_QWORD, (const BYTE *) &value, sizeof(value)); @@ -442,8 +422,7 @@ nsWindowsRegKey::WriteInt64Value(const nsAString &name, uint64_t value) NS_IMETHODIMP nsWindowsRegKey::WriteBinaryValue(const nsAString &name, const nsACString &value) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); const nsCString &flatValue = PromiseFlatCString(value); LONG rv = RegSetValueExW(mKey, PromiseFlatString(name).get(), 0, REG_BINARY, @@ -455,8 +434,7 @@ nsWindowsRegKey::WriteBinaryValue(const nsAString &name, const nsACString &value NS_IMETHODIMP nsWindowsRegKey::StartWatching(bool recurse) { - if (NS_WARN_IF(!mKey)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mKey, NS_ERROR_NOT_INITIALIZED); if (mWatchEvent) return NS_OK; diff --git a/xpcom/glue/nsArrayEnumerator.cpp b/xpcom/glue/nsArrayEnumerator.cpp index 5c2588f59745..572fc665a437 100644 --- a/xpcom/glue/nsArrayEnumerator.cpp +++ b/xpcom/glue/nsArrayEnumerator.cpp @@ -180,6 +180,7 @@ nsCOMArrayEnumerator::operator new (size_t size, const nsCOMArray_base& aArray) // do the actual allocation nsCOMArrayEnumerator * result = static_cast(::operator new(size)); + NS_ENSURE_TRUE(result, nullptr); // now need to copy over the values, and addref each one // now this might seem like a lot of work, but we're actually just diff --git a/xpcom/glue/nsCOMArray.cpp b/xpcom/glue/nsCOMArray.cpp index 7b227a6c5a3a..99b1b5e481a6 100644 --- a/xpcom/glue/nsCOMArray.cpp +++ b/xpcom/glue/nsCOMArray.cpp @@ -57,8 +57,7 @@ int32_t nsCOMArray_base::IndexOfObject(nsISupports* aObject) const { nsCOMPtr supports = do_QueryInterface(aObject); - if (NS_WARN_IF(!supports)) - return -1; + NS_ENSURE_TRUE(supports, -1); uint32_t i, count; int32_t retval = -1; diff --git a/xpcom/glue/nsComponentManagerUtils.cpp b/xpcom/glue/nsComponentManagerUtils.cpp index 21decc4f4fab..f20d5e72e3b8 100644 --- a/xpcom/glue/nsComponentManagerUtils.cpp +++ b/xpcom/glue/nsComponentManagerUtils.cpp @@ -46,8 +46,7 @@ nsresult CallGetService(const nsCID &aCID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - if (NS_WARN_IF(!compMgr)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); return compMgr->nsComponentManagerImpl::GetService(aCID, aIID, aResult); } @@ -56,8 +55,7 @@ nsresult CallGetService(const char *aContractID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - if (NS_WARN_IF(!compMgr)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); return compMgr-> nsComponentManagerImpl::GetServiceByContractID(aContractID, @@ -121,8 +119,7 @@ CallCreateInstance(const nsCID &aCID, nsISupports *aDelegate, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - if (NS_WARN_IF(!compMgr)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); return compMgr-> nsComponentManagerImpl::CreateInstance(aCID, aDelegate, aIID, aResult); @@ -133,8 +130,7 @@ CallCreateInstance(const char *aContractID, nsISupports *aDelegate, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - if (NS_WARN_IF(!compMgr)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); return compMgr-> nsComponentManagerImpl::CreateInstanceByContractID(aContractID, @@ -146,8 +142,7 @@ nsresult CallGetClassObject(const nsCID &aCID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - if (NS_WARN_IF(!compMgr)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); return compMgr-> nsComponentManagerImpl::GetClassObject(aCID, aIID, aResult); @@ -157,8 +152,7 @@ nsresult CallGetClassObject(const char *aContractID, const nsIID &aIID, void **aResult) { nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager; - if (NS_WARN_IF(!compMgr)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(compMgr, NS_ERROR_NOT_INITIALIZED); return compMgr-> nsComponentManagerImpl::GetClassObjectByContractID(aContractID, aIID, diff --git a/xpcom/glue/nsDebug.h b/xpcom/glue/nsDebug.h index 8d3f543829c9..1e656c8127fc 100644 --- a/xpcom/glue/nsDebug.h +++ b/xpcom/glue/nsDebug.h @@ -12,7 +12,7 @@ #ifndef nsError_h__ #include "nsError.h" -#endif +#endif #include "nsXPCOM.h" #include "mozilla/Assertions.h" @@ -22,35 +22,7 @@ #include "prprf.h" #endif -/** - * Warn if the given condition is true. The condition is evaluated in both - * release and debug builds, and the result is an expression which can be - * used in subsequent expressions, such as: - * - * if (NS_WARN_IF(NS_FAILED(rv)) - * return rv; - * - * This explicit warning and return is preferred to the NS_ENSURE_* macros - * which hide the warning and the return control flow. - * - * @note This is C++-only - */ -#ifdef __cplusplus #ifdef DEBUG -inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, - int32_t line) -{ - if (MOZ_UNLIKELY(condition)) { - NS_DebugBreak(NS_DEBUG_WARNING, nullptr, expr, file, line); - } - return condition; -} -#define NS_WARN_IF(condition) \ - NS_warn_if_impl(condition, #condition, __FILE__, __LINE__) -#else -#define NS_WARN_IF(condition) (bool)(condition) -#endif -#endif /** * Abort the execution of the program if the expression evaluates to @@ -68,16 +40,12 @@ inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, * Note also that the non-debug version of this macro does not * evaluate the message argument. */ -#ifdef DEBUG #define NS_ABORT_IF_FALSE(_expr, _msg) \ do { \ if (!(_expr)) { \ NS_DebugBreak(NS_DEBUG_ABORT, _msg, #_expr, __FILE__, __LINE__); \ } \ } while(0) -#else -#define NS_ABORT_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) -#endif /** * Warn if a given condition is false. @@ -87,105 +55,103 @@ inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, * Note also that the non-debug version of this macro does not * evaluate the message argument. */ -#ifdef DEBUG #define NS_WARN_IF_FALSE(_expr,_msg) \ do { \ if (!(_expr)) { \ NS_DebugBreak(NS_DEBUG_WARNING, _msg, #_expr, __FILE__, __LINE__); \ } \ } while(0) -#else -#define NS_WARN_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) -#endif +/** + * Test a precondition for truth. If the expression is not true then + * trigger a program failure. + */ +#define NS_PRECONDITION(expr, str) \ + do { \ + if (!(expr)) { \ + NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ + } \ + } while(0) /** * Test an assertion for truth. If the expression is not true then * trigger a program failure. - * - * Note that the non-debug version of this macro does not - * evaluate the message argument. */ -#ifdef DEBUG #define NS_ASSERTION(expr, str) \ do { \ if (!(expr)) { \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ } \ } while(0) -#else -#define NS_ASSERTION(expr, str) do { /* nothing */ } while(0) -#endif /** - * NS_PRECONDITION/POSTCONDITION are synonyms for NS_ASSERTION. + * Test a post-condition for truth. If the expression is not true then + * trigger a program failure. */ -#define NS_PRECONDITION(expr, str) NS_ASSERTION(expr, str) -#define NS_POSTCONDITION(expr, str) NS_ASSERTION(expr, str) +#define NS_POSTCONDITION(expr, str) \ + do { \ + if (!(expr)) { \ + NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ + } \ + } while(0) /** * This macros triggers a program failure if executed. It indicates that * an attempt was made to execute some unimplemented functionality. */ -#ifdef DEBUG #define NS_NOTYETIMPLEMENTED(str) \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, "NotYetImplemented", __FILE__, __LINE__) -#else -#define NS_NOTYETIMPLEMENTED(str) do { /* nothing */ } while(0) -#endif /** * This macros triggers a program failure if executed. It indicates that - * an attempt was made to execute a codepath which should not be reachable. + * an attempt was made to execute some unimplemented functionality. */ -#ifdef DEBUG #define NS_NOTREACHED(str) \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Not Reached", __FILE__, __LINE__) -#else -#define NS_NOTREACHED(str) do { /* nothing */ } while(0) -#endif /** * Log an error message. */ -#ifdef DEBUG #define NS_ERROR(str) \ NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Error", __FILE__, __LINE__) -#else -#define NS_ERROR(str) do { /* nothing */ } while(0) -#endif /** * Log a warning message. */ -#ifdef DEBUG #define NS_WARNING(str) \ NS_DebugBreak(NS_DEBUG_WARNING, str, nullptr, __FILE__, __LINE__) -#else -#define NS_WARNING(str) do { /* nothing */ } while(0) -#endif /** - * Trigger an debug-only abort. - * - * @see NS_RUNTIMEABORT for release-mode asserts. + * Trigger an abort */ -#ifdef DEBUG #define NS_ABORT() \ NS_DebugBreak(NS_DEBUG_ABORT, nullptr, nullptr, __FILE__, __LINE__) -#else -#define NS_ABORT() do { /* nothing */ } while(0) -#endif /** - * Trigger a debugger breakpoint, only in debug builds. + * Cause a break */ -#ifdef DEBUG #define NS_BREAK() \ NS_DebugBreak(NS_DEBUG_BREAK, nullptr, nullptr, __FILE__, __LINE__) -#else + +#else /* DEBUG */ + +/** + * The non-debug version of these macros do not evaluate the + * expression or the message arguments to the macro. + */ +#define NS_ABORT_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) +#define NS_WARN_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) +#define NS_PRECONDITION(expr, str) do { /* nothing */ } while(0) +#define NS_ASSERTION(expr, str) do { /* nothing */ } while(0) +#define NS_POSTCONDITION(expr, str) do { /* nothing */ } while(0) +#define NS_NOTYETIMPLEMENTED(str) do { /* nothing */ } while(0) +#define NS_NOTREACHED(str) do { /* nothing */ } while(0) +#define NS_ERROR(str) do { /* nothing */ } while(0) +#define NS_WARNING(str) do { /* nothing */ } while(0) +#define NS_ABORT() do { /* nothing */ } while(0) #define NS_BREAK() do { /* nothing */ } while(0) -#endif + +#endif /* ! DEBUG */ /****************************************************************************** ** Macros for static assertions. These are used by the sixgill tool. @@ -264,7 +230,7 @@ inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, /****************************************************************************** ** Macros for terminating execution when an unrecoverable condition is -** reached. These need to be compiled regardless of the DEBUG flag. +** reached. These need to be compiled regardless of the DEBUG flag. ******************************************************************************/ /** @@ -276,11 +242,10 @@ inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, NS_DebugBreak(NS_DEBUG_ABORT, msg, nullptr, __FILE__, __LINE__) -/* Macros for checking the trueness of an expression passed in within an - * interface implementation. These need to be compiled regardless of the - * DEBUG flag. New code should use NS_WARN_IF(condition) instead! - * @status deprecated - */ +/* Macros for checking the trueness of an expression passed in within an + * interface implementation. These need to be compiled regardless of the */ +/* DEBUG flag +******************************************************************************/ #define NS_ENSURE_TRUE(x, ret) \ do { \ @@ -375,6 +340,9 @@ inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, #define NS_ENSURE_NO_AGGREGATION(outer) \ NS_ENSURE_FALSE(outer, NS_ERROR_NO_AGGREGATION) +#define NS_ENSURE_PROPER_AGGREGATION(outer, iid) \ + NS_ENSURE_FALSE(outer && !iid.Equals(NS_GET_IID(nsISupports)), NS_ERROR_INVALID_ARG) + /*****************************************************************************/ #ifdef XPCOM_GLUE diff --git a/xpcom/glue/nsINIParser.cpp b/xpcom/glue/nsINIParser.cpp index 9ce71aa9b0fd..918c2f2427d8 100644 --- a/xpcom/glue/nsINIParser.cpp +++ b/xpcom/glue/nsINIParser.cpp @@ -65,8 +65,7 @@ nsINIParser::Init(nsIFile* aFile) #ifdef XP_WIN nsAutoString path; nsresult rv = aFile->GetPath(path); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); fd = _wfopen(path.get(), READ_BINARYMODE); #else diff --git a/xpcom/glue/nsMemory.cpp b/xpcom/glue/nsMemory.cpp index f77567a3f686..6b63420c9ec6 100644 --- a/xpcom/glue/nsMemory.cpp +++ b/xpcom/glue/nsMemory.cpp @@ -19,8 +19,7 @@ nsMemory::HeapMinimize(bool aImmediate) { nsCOMPtr mem; nsresult rv = NS_GetMemoryManager(getter_AddRefs(mem)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return mem->HeapMinimize(aImmediate); } diff --git a/xpcom/glue/nsThreadUtils.cpp b/xpcom/glue/nsThreadUtils.cpp index c89faa4e7746..a99c2dea3ca7 100644 --- a/xpcom/glue/nsThreadUtils.cpp +++ b/xpcom/glue/nsThreadUtils.cpp @@ -70,18 +70,15 @@ NS_NewThread(nsIThread **result, nsIRunnable *event, uint32_t stackSize) nsresult rv; nsCOMPtr mgr = do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = mgr->NewThread(0, stackSize, getter_AddRefs(thread)); #endif - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); if (event) { rv = thread->Dispatch(event, NS_DISPATCH_NORMAL); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } *result = nullptr; @@ -98,8 +95,7 @@ NS_GetCurrentThread(nsIThread **result) nsresult rv; nsCOMPtr mgr = do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return mgr->GetCurrentThread(result); #endif } @@ -113,8 +109,7 @@ NS_GetMainThread(nsIThread **result) nsresult rv; nsCOMPtr mgr = do_GetService(NS_THREADMANAGER_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return mgr->GetMainThread(result); #endif } @@ -166,8 +161,7 @@ NS_DispatchToCurrentThread(nsIRunnable *event) #else nsCOMPtr thread; nsresult rv = NS_GetCurrentThread(getter_AddRefs(thread)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); #endif return thread->Dispatch(event, NS_DISPATCH_NORMAL); } @@ -177,8 +171,7 @@ NS_DispatchToMainThread(nsIRunnable *event, uint32_t dispatchFlags) { nsCOMPtr thread; nsresult rv = NS_GetMainThread(getter_AddRefs(thread)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return thread->Dispatch(event, dispatchFlags); } @@ -191,15 +184,13 @@ NS_ProcessPendingEvents(nsIThread *thread, PRIntervalTime timeout) #ifdef MOZILLA_INTERNAL_API if (!thread) { thread = NS_GetCurrentThread(); - if (NS_WARN_IF(!thread)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(thread); } #else nsCOMPtr current; if (!thread) { rv = NS_GetCurrentThread(getter_AddRefs(current)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); thread = current.get(); } #endif @@ -234,8 +225,7 @@ NS_HasPendingEvents(nsIThread *thread) return hasPendingEvents(current); #else thread = NS_GetCurrentThread(); - if (NS_WARN_IF(!thread)) - return false; + NS_ENSURE_TRUE(thread, false); #endif } return hasPendingEvents(thread); @@ -247,15 +237,13 @@ NS_ProcessNextEvent(nsIThread *thread, bool mayWait) #ifdef MOZILLA_INTERNAL_API if (!thread) { thread = NS_GetCurrentThread(); - if (NS_WARN_IF(!thread)) - return false; + NS_ENSURE_TRUE(thread, false); } #else nsCOMPtr current; if (!thread) { NS_GetCurrentThread(getter_AddRefs(current)); - if (NS_WARN_IF(!current)) - return false; + NS_ENSURE_TRUE(current, false); thread = current.get(); } #endif diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h index c567de3a4666..e53cc013153c 100644 --- a/xpcom/glue/nsThreadUtils.h +++ b/xpcom/glue/nsThreadUtils.h @@ -71,8 +71,7 @@ NS_NewNamedThread(const char (&name)[LEN], uint32_t stackSize = nsIThreadManager::DEFAULT_STACK_SIZE) { nsresult rv = NS_NewThread(result, nullptr, stackSize); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); NS_SetThreadName(*result, name); if (initialEvent) { rv = (*result)->Dispatch(initialEvent, NS_DISPATCH_NORMAL); diff --git a/xpcom/io/Base64.cpp b/xpcom/io/Base64.cpp index 4a6419eca57d..94fec02775ae 100644 --- a/xpcom/io/Base64.cpp +++ b/xpcom/io/Base64.cpp @@ -163,8 +163,7 @@ EncodeInputStream(nsIInputStream *aInputStream, if (!aCount) { rv = aInputStream->Available(&count64); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // if count64 is over 4GB, it will be failed at the below condition, // then will return NS_ERROR_OUT_OF_MEMORY aCount = (uint32_t)count64; diff --git a/xpcom/io/CocoaFileUtils.mm b/xpcom/io/CocoaFileUtils.mm index 3f6872745536..ca4e1b4fc3be 100644 --- a/xpcom/io/CocoaFileUtils.mm +++ b/xpcom/io/CocoaFileUtils.mm @@ -16,8 +16,7 @@ nsresult RevealFileInFinder(CFURLRef url) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - if (NS_WARN_IF(!url)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(url); NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; BOOL success = [[NSWorkspace sharedWorkspace] selectFile:[(NSURL*)url path] inFileViewerRootedAtPath:@""]; @@ -32,8 +31,7 @@ nsresult OpenURL(CFURLRef url) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - if (NS_WARN_IF(!url)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(url); NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; BOOL success = [[NSWorkspace sharedWorkspace] openURL:(NSURL*)url]; @@ -48,8 +46,8 @@ nsresult GetFileCreatorCode(CFURLRef url, OSType *creatorCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - if (NS_WARN_IF(!url) || NS_WARN_IF(!creatorCode)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(url); + NS_ENSURE_ARG_POINTER(creatorCode); nsAutoreleasePool localPool; @@ -78,8 +76,7 @@ nsresult SetFileCreatorCode(CFURLRef url, OSType creatorCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - if (NS_WARN_IF(!url)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(url); NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:creatorCode] forKey:NSFileHFSCreatorCode]; @@ -94,8 +91,8 @@ nsresult GetFileTypeCode(CFURLRef url, OSType *typeCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - if (NS_WARN_IF(!url) || NS_WARN_IF(!typeCode)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(url); + NS_ENSURE_ARG_POINTER(typeCode); nsAutoreleasePool localPool; @@ -124,8 +121,7 @@ nsresult SetFileTypeCode(CFURLRef url, OSType typeCode) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - if (NS_WARN_IF(!url)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(url); NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init]; NSDictionary* dict = [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:typeCode] forKey:NSFileHFSTypeCode]; diff --git a/xpcom/io/nsAnonymousTemporaryFile.cpp b/xpcom/io/nsAnonymousTemporaryFile.cpp index de0cc43caf23..aaac18958a22 100644 --- a/xpcom/io/nsAnonymousTemporaryFile.cpp +++ b/xpcom/io/nsAnonymousTemporaryFile.cpp @@ -50,23 +50,19 @@ using namespace mozilla; static nsresult GetTempDir(nsIFile** aTempDir) { - if (NS_WARN_IF(!aTempDir)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aTempDir); nsCOMPtr tmpFile; nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpFile)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv,rv); #ifdef XP_WIN // On windows DELETE_ON_CLOSE is unreliable, so we store temporary files // in a subdir of the temp dir and delete that in an idle service observer // to ensure it's been cleared. rv = tmpFile->AppendNative(nsDependentCString("mozilla-temp-files")); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv,rv); rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); - if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_TRUE(rv == NS_ERROR_FILE_ALREADY_EXISTS || NS_SUCCEEDED(rv), rv); #endif tmpFile.forget(aTempDir); @@ -77,14 +73,12 @@ GetTempDir(nsIFile** aTempDir) nsresult NS_OpenAnonymousTemporaryFile(PRFileDesc** aOutFileDesc) { - if (NS_WARN_IF(!aOutFileDesc)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aOutFileDesc); nsresult rv; nsCOMPtr tmpFile; rv = GetTempDir(getter_AddRefs(tmpFile)); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv,rv); // Give the temp file a name with a random element. CreateUnique will also // append a counter to the name if it encounters a name collision. Adding @@ -96,12 +90,10 @@ NS_OpenAnonymousTemporaryFile(PRFileDesc** aOutFileDesc) name.AppendInt(rand()); rv = tmpFile->AppendNative(name); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv,rv); rv = tmpFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0700); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv,rv); rv = tmpFile->OpenNSPRFileDesc(PR_RDWR | nsIFile::DELETE_ON_CLOSE, PR_IRWXU, aOutFileDesc); @@ -154,19 +146,16 @@ public: // service is installed when running in xpcshell, and this interferes with // the fake idle service, causing xpcshell-test failures. mTimer = do_CreateInstance(NS_TIMER_CONTRACTID); - if (NS_WARN_IF(!mTimer)) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(mTimer != nullptr, NS_ERROR_FAILURE); nsresult rv = mTimer->Init(this, SCHEDULE_TIMEOUT_MS, nsITimer::TYPE_ONE_SHOT); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Register shutdown observer so we can cancel the timer if we shutdown before // the timer runs. nsCOMPtr obsSrv = services::GetObserverService(); - if (NS_WARN_IF(!obsSrv)) - return NS_ERROR_FAILURE; + NS_ENSURE_TRUE(obsSrv != nullptr, NS_ERROR_FAILURE); return obsSrv->AddObserver(this, XPCOM_SHUTDOWN_TOPIC, false); } @@ -222,8 +211,7 @@ public: void RemoveAnonTempFileFiles() { nsCOMPtr tmpDir; nsresult rv = GetTempDir(getter_AddRefs(tmpDir)); - if (NS_WARN_IF(NS_FAILED(rv))) - return; + NS_ENSURE_SUCCESS_VOID(rv); // Remove the directory recursively. tmpDir->Remove(true); diff --git a/xpcom/io/nsAppFileLocationProvider.cpp b/xpcom/io/nsAppFileLocationProvider.cpp index c0f77437c7ac..b0243c514e7c 100644 --- a/xpcom/io/nsAppFileLocationProvider.cpp +++ b/xpcom/io/nsAppFileLocationProvider.cpp @@ -87,12 +87,10 @@ NS_IMPL_ISUPPORTS2(nsAppFileLocationProvider, nsIDirectoryServiceProvider, nsIDi NS_IMETHODIMP nsAppFileLocationProvider::GetFile(const char *prop, bool *persistent, nsIFile **_retval) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; - nsCOMPtr localFile; nsresult rv = NS_ERROR_FAILURE; + NS_ENSURE_ARG(prop); *_retval = nullptr; *persistent = true; @@ -252,8 +250,7 @@ nsAppFileLocationProvider::GetFile(const char *prop, bool *persistent, nsIFile * NS_METHOD nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile **aLocalFile) { - if (NS_WARN_IF(!aLocalFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aLocalFile); nsresult rv; if (!mMozBinDirectory) @@ -294,8 +291,7 @@ NS_METHOD nsAppFileLocationProvider::CloneMozBinDirectory(nsIFile **aLocalFile) //---------------------------------------------------------------------------------------- NS_METHOD nsAppFileLocationProvider::GetProductDirectory(nsIFile **aLocalFile, bool aLocal) { - if (NS_WARN_IF(!aLocalFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aLocalFile); nsresult rv; bool exists; @@ -356,8 +352,7 @@ NS_METHOD nsAppFileLocationProvider::GetProductDirectory(nsIFile **aLocalFile, b //---------------------------------------------------------------------------------------- NS_METHOD nsAppFileLocationProvider::GetDefaultUserProfileRoot(nsIFile **aLocalFile, bool aLocal) { - if (NS_WARN_IF(!aLocalFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aLocalFile); nsresult rv; nsCOMPtr localDir; @@ -421,8 +416,7 @@ class nsAppDirectoryEnumerator : public nsISimpleEnumerator NS_IMETHOD GetNext(nsISupports **result) { - if (NS_WARN_IF(!result)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(result); *result = nullptr; bool hasMore; @@ -517,8 +511,7 @@ class nsPathsDirectoryEnumerator : public nsAppDirectoryEnumerator NS_IMETHODIMP nsAppFileLocationProvider::GetFiles(const char *prop, nsISimpleEnumerator **_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = nullptr; nsresult rv = NS_ERROR_FAILURE; diff --git a/xpcom/io/nsBinaryStream.cpp b/xpcom/io/nsBinaryStream.cpp index 67784f9eea54..e3917845870c 100644 --- a/xpcom/io/nsBinaryStream.cpp +++ b/xpcom/io/nsBinaryStream.cpp @@ -34,24 +34,21 @@ NS_IMPL_ISUPPORTS3(nsBinaryOutputStream, nsIObjectOutputStream, nsIBinaryOutputS NS_IMETHODIMP nsBinaryOutputStream::Flush() { - if (NS_WARN_IF(!mOutputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mOutputStream); return mOutputStream->Flush(); } NS_IMETHODIMP nsBinaryOutputStream::Close() { - if (NS_WARN_IF(!mOutputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mOutputStream); return mOutputStream->Close(); } NS_IMETHODIMP nsBinaryOutputStream::Write(const char *aBuf, uint32_t aCount, uint32_t *aActualBytes) { - if (NS_WARN_IF(!mOutputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mOutputStream); return mOutputStream->Write(aBuf, aCount, aActualBytes); } @@ -72,16 +69,14 @@ nsBinaryOutputStream::WriteSegments(nsReadSegmentFun reader, void * closure, uin NS_IMETHODIMP nsBinaryOutputStream::IsNonBlocking(bool *aNonBlocking) { - if (NS_WARN_IF(!mOutputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mOutputStream); return mOutputStream->IsNonBlocking(aNonBlocking); } nsresult nsBinaryOutputStream::WriteFully(const char *aBuf, uint32_t aCount) { - if (NS_WARN_IF(!mOutputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mOutputStream); nsresult rv; uint32_t bytesWritten; @@ -96,8 +91,7 @@ nsBinaryOutputStream::WriteFully(const char *aBuf, uint32_t aCount) NS_IMETHODIMP nsBinaryOutputStream::SetOutputStream(nsIOutputStream *aOutputStream) { - if (NS_WARN_IF(!aOutputStream)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aOutputStream); mOutputStream = aOutputStream; mBufferAccess = do_QueryInterface(aOutputStream); return NS_OK; @@ -251,25 +245,23 @@ nsBinaryOutputStream::WriteCompoundObject(nsISupports* aObject, const nsIID& aIID, bool aIsStrongRef) { - nsCOMPtr classInfo = do_QueryInterface(aObject); - nsCOMPtr serializable = do_QueryInterface(aObject); - // Can't deal with weak refs - if (NS_WARN_IF(!aIsStrongRef)) - return NS_ERROR_UNEXPECTED; - if (NS_WARN_IF(!classInfo) || NS_WARN_IF(!serializable)) - return NS_ERROR_NOT_AVAILABLE; + NS_ENSURE_TRUE(aIsStrongRef, NS_ERROR_UNEXPECTED); + + nsCOMPtr classInfo = do_QueryInterface(aObject); + NS_ENSURE_TRUE(classInfo, NS_ERROR_NOT_AVAILABLE); + + nsCOMPtr serializable = do_QueryInterface(aObject); + NS_ENSURE_TRUE(serializable, NS_ERROR_NOT_AVAILABLE); nsCID cid; classInfo->GetClassIDNoAlloc(&cid); nsresult rv = WriteID(cid); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; - + NS_ENSURE_SUCCESS(rv, rv); + rv = WriteID(aIID); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return serializable->Write(this); } @@ -278,21 +270,17 @@ NS_IMETHODIMP nsBinaryOutputStream::WriteID(const nsIID& aIID) { nsresult rv = Write32(aIID.m0); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = Write16(aIID.m1); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = Write16(aIID.m2); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); for (int i = 0; i < 8; ++i) { rv = Write8(aIID.m3[i]); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; @@ -318,16 +306,14 @@ NS_IMPL_ISUPPORTS3(nsBinaryInputStream, nsIObjectInputStream, nsIBinaryInputStre NS_IMETHODIMP nsBinaryInputStream::Available(uint64_t* aResult) { - if (NS_WARN_IF(!mInputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mInputStream); return mInputStream->Available(aResult); } NS_IMETHODIMP nsBinaryInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t *aNumRead) { - if (NS_WARN_IF(!mInputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mInputStream); // mInputStream might give us short reads, so deal with that. uint32_t totalRead = 0; @@ -397,8 +383,7 @@ ReadSegmentForwardingThunk(nsIInputStream* aStream, NS_IMETHODIMP nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, uint32_t count, uint32_t *_retval) { - if (NS_WARN_IF(!mInputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mInputStream); ReadSegmentsClosure thunkClosure = { this, closure, writer, NS_OK, 0 }; @@ -431,24 +416,21 @@ nsBinaryInputStream::ReadSegments(nsWriteSegmentFun writer, void * closure, uint NS_IMETHODIMP nsBinaryInputStream::IsNonBlocking(bool *aNonBlocking) { - if (NS_WARN_IF(!mInputStream)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mInputStream); return mInputStream->IsNonBlocking(aNonBlocking); } NS_IMETHODIMP -nsBinaryInputStream::Close() -{ - if (NS_WARN_IF(!mInputStream)) - return NS_ERROR_UNEXPECTED; - return mInputStream->Close(); +nsBinaryInputStream::Close() +{ + NS_ENSURE_STATE(mInputStream); + return mInputStream->Close(); } NS_IMETHODIMP nsBinaryInputStream::SetInputStream(nsIInputStream *aInputStream) { - if (NS_WARN_IF(!aInputStream)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aInputStream); mInputStream = aInputStream; mBufferAccess = do_QueryInterface(aInputStream); return NS_OK; @@ -747,8 +729,7 @@ nsBinaryInputStream::ReadArrayBuffer(uint32_t aLength, const JS::Value& aBuffer, uint32_t bytesRead; nsresult rv = Read(reinterpret_cast(data), aLength, &bytesRead); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); if (bytesRead != aLength) { return NS_ERROR_FAILURE; } @@ -761,12 +742,10 @@ nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports* *aObject) nsCID cid; nsIID iid; nsresult rv = ReadID(&cid); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = ReadID(&iid); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // HACK: Intercept old (pre-gecko6) nsIURI IID, and replace with // the updated IID, so that we're QI'ing to an actual interface. @@ -795,16 +774,13 @@ nsBinaryInputStream::ReadObject(bool aIsStrongRef, nsISupports* *aObject) // END HACK nsCOMPtr object = do_CreateInstance(cid, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr serializable = do_QueryInterface(object); - if (NS_WARN_IF(!serializable)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(serializable, NS_ERROR_UNEXPECTED); rv = serializable->Read(this); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return object->QueryInterface(iid, reinterpret_cast(aObject)); } @@ -813,21 +789,17 @@ NS_IMETHODIMP nsBinaryInputStream::ReadID(nsID *aResult) { nsresult rv = Read32(&aResult->m0); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = Read16(&aResult->m1); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = Read16(&aResult->m2); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); for (int i = 0; i < 8; ++i) { rv = Read8(&aResult->m3[i]); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; diff --git a/xpcom/io/nsDirectoryService.cpp b/xpcom/io/nsDirectoryService.cpp index a1078d4dfb9a..603c9c015ca0 100644 --- a/xpcom/io/nsDirectoryService.cpp +++ b/xpcom/io/nsDirectoryService.cpp @@ -59,8 +59,7 @@ nsresult nsDirectoryService::GetCurrentProcessDirectory(nsIFile** aFile) //---------------------------------------------------------------------------------------- { - if (NS_WARN_IF(!aFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aFile); *aFile = nullptr; // Set the component registry location: @@ -226,10 +225,8 @@ nsDirectoryService::nsDirectoryService() nsresult nsDirectoryService::Create(nsISupports *outer, REFNSIID aIID, void **aResult) { - if (NS_WARN_IF(!aResult)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_ARG_POINTER(aResult); + NS_ENSURE_NO_AGGREGATION(outer); if (!gService) { @@ -287,8 +284,7 @@ NS_IMPL_ISUPPORTS4(nsDirectoryService, nsIProperties, nsIDirectoryService, nsIDi NS_IMETHODIMP nsDirectoryService::Undefine(const char* prop) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); nsDependentCString key(prop); if (!mHashtable.Get(key, nullptr)) @@ -364,8 +360,7 @@ static bool FindProviderFile(nsIDirectoryServiceProvider* aElement, NS_IMETHODIMP nsDirectoryService::Get(const char* prop, const nsIID & uuid, void* *result) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); nsDependentCString key(prop); @@ -414,8 +409,7 @@ nsDirectoryService::Get(const char* prop, const nsIID & uuid, void* *result) NS_IMETHODIMP nsDirectoryService::Set(const char* prop, nsISupports* value) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); nsDependentCString key(prop); if (mHashtable.Get(key, nullptr) || !value) { @@ -437,8 +431,7 @@ nsDirectoryService::Set(const char* prop, nsISupports* value) NS_IMETHODIMP nsDirectoryService::Has(const char *prop, bool *_retval) { - if (NS_WARN_IF(!prop)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(prop); *_retval = false; nsCOMPtr value; @@ -917,8 +910,7 @@ nsDirectoryService::GetFile(const char *prop, bool *persistent, nsIFile **_retva NS_IMETHODIMP nsDirectoryService::GetFiles(const char *prop, nsISimpleEnumerator **_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = nullptr; return NS_ERROR_FAILURE; diff --git a/xpcom/io/nsIOUtil.cpp b/xpcom/io/nsIOUtil.cpp index e4062793b0ba..4363355de1a9 100644 --- a/xpcom/io/nsIOUtil.cpp +++ b/xpcom/io/nsIOUtil.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -13,8 +13,7 @@ NS_IMPL_ISUPPORTS1(nsIOUtil, nsIIOUtil) NS_IMETHODIMP nsIOUtil::InputStreamIsBuffered(nsIInputStream* aStream, bool* _retval) { - if (NS_WARN_IF(!aStream)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aStream); *_retval = NS_InputStreamIsBuffered(aStream); return NS_OK; } @@ -22,8 +21,7 @@ nsIOUtil::InputStreamIsBuffered(nsIInputStream* aStream, bool* _retval) NS_IMETHODIMP nsIOUtil::OutputStreamIsBuffered(nsIOutputStream* aStream, bool* _retval) { - if (NS_WARN_IF(!aStream)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aStream); *_retval = NS_OutputStreamIsBuffered(aStream); return NS_OK; } diff --git a/xpcom/io/nsInputStreamTee.cpp b/xpcom/io/nsInputStreamTee.cpp index cebf04d20c7f..4ac153dfe217 100644 --- a/xpcom/io/nsInputStreamTee.cpp +++ b/xpcom/io/nsInputStreamTee.cpp @@ -164,6 +164,7 @@ nsInputStreamTee::TeeSegment(const char *buf, uint32_t count) } nsRefPtr event = new nsInputStreamTeeWriteEvent(buf, count, mSink, this); + NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); LOG(("nsInputStreamTee::TeeSegment [%p] dispatching write %u bytes\n", this, count)); return mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL); @@ -213,8 +214,7 @@ NS_IMPL_ISUPPORTS2(nsInputStreamTee, NS_IMETHODIMP nsInputStreamTee::Close() { - if (NS_WARN_IF(!mSource)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); nsresult rv = mSource->Close(); mSource = 0; mSink = 0; @@ -224,16 +224,14 @@ nsInputStreamTee::Close() NS_IMETHODIMP nsInputStreamTee::Available(uint64_t *avail) { - if (NS_WARN_IF(!mSource)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); return mSource->Available(avail); } NS_IMETHODIMP nsInputStreamTee::Read(char *buf, uint32_t count, uint32_t *bytesRead) { - if (NS_WARN_IF(!mSource)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); nsresult rv = mSource->Read(buf, count, bytesRead); if (NS_FAILED(rv) || (*bytesRead == 0)) @@ -248,8 +246,7 @@ nsInputStreamTee::ReadSegments(nsWriteSegmentFun writer, uint32_t count, uint32_t *bytesRead) { - if (NS_WARN_IF(!mSource)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); mWriter = writer; mClosure = closure; @@ -260,8 +257,7 @@ nsInputStreamTee::ReadSegments(nsWriteSegmentFun writer, NS_IMETHODIMP nsInputStreamTee::IsNonBlocking(bool *result) { - if (NS_WARN_IF(!mSource)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSource, NS_ERROR_NOT_INITIALIZED); return mSource->IsNonBlocking(result); } diff --git a/xpcom/io/nsLocalFileCommon.cpp b/xpcom/io/nsLocalFileCommon.cpp index 75c53483877f..5ec4bae22b3a 100644 --- a/xpcom/io/nsLocalFileCommon.cpp +++ b/xpcom/io/nsLocalFileCommon.cpp @@ -33,8 +33,7 @@ void NS_ShutdownLocalFile() NS_IMETHODIMP nsLocalFile::InitWithFile(nsIFile *aFile) { - if (NS_WARN_IF(!aFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aFile); nsAutoCString path; aFile->GetNativePath(path); @@ -190,8 +189,7 @@ static int32_t SplitPath(PRUnichar *path, PRUnichar **nodeArray, int32_t arrayLe NS_IMETHODIMP nsLocalFile::GetRelativeDescriptor(nsIFile *fromFile, nsACString& _retval) { - if (NS_WARN_IF(!fromFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(fromFile); const int32_t kMaxNodesInPath = 32; // diff --git a/xpcom/io/nsLocalFileUnix.cpp b/xpcom/io/nsLocalFileUnix.cpp index c0127e80949b..099bcea90280 100644 --- a/xpcom/io/nsLocalFileUnix.cpp +++ b/xpcom/io/nsLocalFileUnix.cpp @@ -243,10 +243,8 @@ nsLocalFile::nsLocalFileConstructor(nsISupports *outer, const nsIID &aIID, void **aInstancePtr) { - if (NS_WARN_IF(!aInstancePtr)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); *aInstancePtr = nullptr; @@ -1007,8 +1005,7 @@ NS_IMETHODIMP nsLocalFile::GetLastModifiedTime(PRTime *aLastModTime) { CHECK_mPath(); - if (NS_WARN_IF(!aLastModTime)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aLastModTime); PRFileInfo64 info; if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS) @@ -1046,8 +1043,7 @@ NS_IMETHODIMP nsLocalFile::GetLastModifiedTimeOfLink(PRTime *aLastModTimeOfLink) { CHECK_mPath(); - if (NS_WARN_IF(!aLastModTimeOfLink)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aLastModTimeOfLink); struct STAT sbuf; if (LSTAT(mPath.get(), &sbuf) == -1) @@ -1076,8 +1072,7 @@ nsLocalFile::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink) NS_IMETHODIMP nsLocalFile::GetPermissions(uint32_t *aPermissions) { - if (NS_WARN_IF(!aPermissions)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aPermissions); ENSURE_STAT_CACHE(); *aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode); return NS_OK; @@ -1087,8 +1082,7 @@ NS_IMETHODIMP nsLocalFile::GetPermissionsOfLink(uint32_t *aPermissionsOfLink) { CHECK_mPath(); - if (NS_WARN_IF(!aPermissionsOfLink)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aPermissionsOfLink); struct STAT sbuf; if (LSTAT(mPath.get(), &sbuf) == -1) @@ -1133,8 +1127,7 @@ nsLocalFile::SetPermissionsOfLink(uint32_t aPermissions) NS_IMETHODIMP nsLocalFile::GetFileSize(int64_t *aFileSize) { - if (NS_WARN_IF(!aFileSize)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aFileSize); *aFileSize = 0; ENSURE_STAT_CACHE(); @@ -1183,8 +1176,7 @@ NS_IMETHODIMP nsLocalFile::GetFileSizeOfLink(int64_t *aFileSize) { CHECK_mPath(); - if (NS_WARN_IF(!aFileSize)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aFileSize); struct STAT sbuf; if (LSTAT(mPath.get(), &sbuf) == -1) @@ -1249,8 +1241,7 @@ GetDeviceName(int deviceMajor, int deviceMinor, nsACString &deviceName) NS_IMETHODIMP nsLocalFile::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable) { - if (NS_WARN_IF(!aDiskSpaceAvailable)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); // These systems have the operations necessary to check disk space. @@ -1335,8 +1326,7 @@ NS_IMETHODIMP nsLocalFile::GetParent(nsIFile **aParent) { CHECK_mPath(); - if (NS_WARN_IF(!aParent)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aParent); *aParent = nullptr; // if '/' we are at the top of the volume, return null @@ -1382,8 +1372,7 @@ NS_IMETHODIMP nsLocalFile::Exists(bool *_retval) { CHECK_mPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = (access(mPath.get(), F_OK) == 0); return NS_OK; @@ -1394,8 +1383,7 @@ NS_IMETHODIMP nsLocalFile::IsWritable(bool *_retval) { CHECK_mPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = (access(mPath.get(), W_OK) == 0); if (*_retval || errno == EACCES) @@ -1407,8 +1395,7 @@ NS_IMETHODIMP nsLocalFile::IsReadable(bool *_retval) { CHECK_mPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = (access(mPath.get(), R_OK) == 0); if (*_retval || errno == EACCES) @@ -1420,8 +1407,7 @@ NS_IMETHODIMP nsLocalFile::IsExecutable(bool *_retval) { CHECK_mPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); // Check extension (bug 663899). On certain platforms, the file // extension may cause the OS to treat it as executable regardless of @@ -1510,8 +1496,7 @@ nsLocalFile::IsExecutable(bool *_retval) NS_IMETHODIMP nsLocalFile::IsDirectory(bool *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = false; ENSURE_STAT_CACHE(); *_retval = S_ISDIR(mCachedStat.st_mode); @@ -1521,8 +1506,7 @@ nsLocalFile::IsDirectory(bool *_retval) NS_IMETHODIMP nsLocalFile::IsFile(bool *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); *_retval = false; ENSURE_STAT_CACHE(); *_retval = S_ISREG(mCachedStat.st_mode); @@ -1532,8 +1516,7 @@ nsLocalFile::IsFile(bool *_retval) NS_IMETHODIMP nsLocalFile::IsHidden(bool *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); nsACString::const_iterator begin, end; LocateNativeLeafName(begin, end); *_retval = (*begin == '.'); @@ -1543,8 +1526,7 @@ nsLocalFile::IsHidden(bool *_retval) NS_IMETHODIMP nsLocalFile::IsSymlink(bool *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); CHECK_mPath(); struct STAT symStat; @@ -1557,8 +1539,7 @@ nsLocalFile::IsSymlink(bool *_retval) NS_IMETHODIMP nsLocalFile::IsSpecial(bool *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); ENSURE_STAT_CACHE(); *_retval = S_ISCHR(mCachedStat.st_mode) || S_ISBLK(mCachedStat.st_mode) || @@ -1573,10 +1554,8 @@ nsLocalFile::IsSpecial(bool *_retval) NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, bool *_retval) { - if (NS_WARN_IF(!inFile)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG_POINTER(_retval); *_retval = false; nsAutoCString inPath; @@ -1594,10 +1573,8 @@ NS_IMETHODIMP nsLocalFile::Contains(nsIFile *inFile, bool recur, bool *_retval) { CHECK_mPath(); - if (NS_WARN_IF(!inFile)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG_POINTER(_retval); nsAutoCString inPath; nsresult rv; @@ -1733,8 +1710,7 @@ NS_IMETHODIMP nsLocalFile::Load(PRLibrary **_retval) { CHECK_mPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); #ifdef NS_BUILD_REFCNT_LOGGING nsTraceRefcntImpl::SetActivityIsLegal(false); @@ -2145,8 +2121,7 @@ nsLocalFile::InitWithCFURL(CFURLRef aCFURL) NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef *aFSRef) { - if (NS_WARN_IF(!aFSRef)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aFSRef); CFURLRef newURLRef = ::CFURLCreateFromFSRef(kCFAllocatorDefault, aFSRef); if (newURLRef) { @@ -2176,8 +2151,7 @@ nsLocalFile::GetCFURL(CFURLRef *_retval) NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); nsresult rv = NS_ERROR_FAILURE; @@ -2195,8 +2169,7 @@ nsLocalFile::GetFSRef(FSRef *_retval) NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(_retval); FSRef fsRef; nsresult rv = GetFSRef(&fsRef); @@ -2211,8 +2184,7 @@ nsLocalFile::GetFSSpec(FSSpec *_retval) NS_IMETHODIMP nsLocalFile::GetFileSizeWithResFork(int64_t *aFileSizeWithResFork) { - if (NS_WARN_IF(!aFileSizeWithResFork)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aFileSizeWithResFork); FSRef fsRef; nsresult rv = GetFSRef(&fsRef); @@ -2371,8 +2343,7 @@ nsLocalFile::OpenDocWithApp(nsIFile *aAppToOpenWith, bool aLaunchInBackground) NS_IMETHODIMP nsLocalFile::IsPackage(bool *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(_retval); *_retval = false; CFURLRef url; @@ -2443,8 +2414,7 @@ NS_IMETHODIMP nsLocalFile::GetBundleContentsLastModifiedTime(int64_t *aLastModTime) { CHECK_mPath(); - if (NS_WARN_IF(!aLastModTime)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aLastModTime); bool isPackage = false; nsresult rv = IsPackage(&isPackage); @@ -2470,8 +2440,7 @@ nsLocalFile::GetBundleContentsLastModifiedTime(int64_t *aLastModTime) NS_IMETHODIMP nsLocalFile::InitWithFile(nsIFile *aFile) { - if (NS_WARN_IF(!aFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aFile); nsAutoCString nativePath; nsresult rv = aFile->GetNativePath(nativePath); diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 3d1e3e01ab0f..c8cd7911f159 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -725,8 +725,7 @@ struct nsDir static nsresult OpenDir(const nsAFlatString &name, nsDir * *dir) { - if (NS_WARN_IF(!dir)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(dir); *dir = nullptr; if (name.Length() + 3 >= MAX_PATH) @@ -766,8 +765,7 @@ static nsresult ReadDir(nsDir *dir, PRDirFlags flags, nsString& name) { name.Truncate(); - if (NS_WARN_IF(!dir)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(dir); while (1) { BOOL rv; @@ -811,8 +809,7 @@ ReadDir(nsDir *dir, PRDirFlags flags, nsString& name) static nsresult CloseDir(nsDir *&d) { - if (NS_WARN_IF(!d)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(d); BOOL isOk = FindClose(d->handle); // PR_DELETE also nulls out the passed in pointer. @@ -965,10 +962,8 @@ nsLocalFile::nsLocalFile() nsresult nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) { - if (NS_WARN_IF(!aInstancePtr)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_ARG_POINTER(aInstancePtr); + NS_ENSURE_NO_AGGREGATION(outer); nsLocalFile* inst = new nsLocalFile(); if (inst == nullptr) @@ -1154,8 +1149,7 @@ nsLocalFile::Clone(nsIFile **file) NS_IMETHODIMP nsLocalFile::InitWithFile(nsIFile *aFile) { - if (NS_WARN_IF(!aFile)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aFile); nsAutoString path; aFile->GetPath(path); @@ -2078,8 +2072,7 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow return NS_ERROR_FAILURE; rv = file->MoveTo(target, EmptyString()); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv,rv); } else { @@ -2087,8 +2080,7 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow rv = file->CopyToFollowingLinks(target, EmptyString()); else rv = file->CopyTo(target, EmptyString()); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv,rv); } } } @@ -2101,8 +2093,7 @@ nsLocalFile::CopyMove(nsIFile *aParentDir, const nsAString &newName, bool follow if (move) { rv = Remove(false /* recursive */); - if (NS_FAILED(rv)) - return rv; + NS_ENSURE_SUCCESS(rv,rv); } } @@ -2267,8 +2258,7 @@ nsLocalFile::GetLastModifiedTime(PRTime *aLastModifiedTime) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!aLastModifiedTime)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aLastModifiedTime); // get the modified time of the target as determined by mFollowSymlinks // If true, then this will be for the target of the shortcut file, @@ -2291,8 +2281,7 @@ nsLocalFile::GetLastModifiedTimeOfLink(PRTime *aLastModifiedTime) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!aLastModifiedTime)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aLastModifiedTime); // The caller is assumed to have already called IsSymlink // and to have found that this file is a link. @@ -2392,8 +2381,7 @@ nsLocalFile::SetModDate(PRTime aLastModifiedTime, const PRUnichar *filePath) NS_IMETHODIMP nsLocalFile::GetPermissions(uint32_t *aPermissions) { - if (NS_WARN_IF(!aPermissions)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aPermissions); // get the permissions of the target as determined by mFollowSymlinks // If true, then this will be for the target of the shortcut file, @@ -2422,8 +2410,7 @@ nsLocalFile::GetPermissionsOfLink(uint32_t *aPermissions) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!aPermissions)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aPermissions); // The caller is assumed to have already called IsSymlink // and to have found that this file is a link. It is not @@ -2492,8 +2479,7 @@ nsLocalFile::SetPermissionsOfLink(uint32_t aPermissions) NS_IMETHODIMP nsLocalFile::GetFileSize(int64_t *aFileSize) { - if (NS_WARN_IF(!aFileSize)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aFileSize); nsresult rv = ResolveAndStat(); if (NS_FAILED(rv)) @@ -2510,8 +2496,7 @@ nsLocalFile::GetFileSizeOfLink(int64_t *aFileSize) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!aFileSize)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aFileSize); // The caller is assumed to have already called IsSymlink // and to have found that this file is a link. @@ -2566,8 +2551,7 @@ nsLocalFile::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!aDiskSpaceAvailable)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aDiskSpaceAvailable); ResolveAndStat(); @@ -2596,8 +2580,7 @@ nsLocalFile::GetParent(nsIFile * *aParent) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!aParent)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aParent); // A two-character path must be a drive such as C:, so it has no parent if (mWorkingPath.Length() == 2) { @@ -2641,8 +2624,7 @@ nsLocalFile::Exists(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(_retval); *_retval = false; MakeDirty(); @@ -2712,8 +2694,7 @@ nsLocalFile::IsReadable(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(_retval); *_retval = false; nsresult rv = ResolveAndStat(); @@ -2731,8 +2712,7 @@ nsLocalFile::IsExecutable(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(_retval); *_retval = false; nsresult rv; @@ -2887,8 +2867,7 @@ nsLocalFile::IsHidden(bool *_retval) nsresult nsLocalFile::HasFileAttribute(DWORD fileAttrib, bool *_retval) { - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(_retval); nsresult rv = Resolve(); if (NS_FAILED(rv)) { @@ -2910,8 +2889,7 @@ nsLocalFile::IsSymlink(bool *_retval) // Check we are correctly initialized. CHECK_mWorkingPath(); - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(_retval); // unless it is a valid shortcut path it's not a symlink if (!IsShortcutPath(mWorkingPath)) { @@ -2942,10 +2920,8 @@ nsLocalFile::IsSpecial(bool *_retval) NS_IMETHODIMP nsLocalFile::Equals(nsIFile *inFile, bool *_retval) { - if (NS_WARN_IF(!inFile)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(!_retval)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(inFile); + NS_ENSURE_ARG(_retval); EnsureShortPath(); diff --git a/xpcom/io/nsMultiplexInputStream.cpp b/xpcom/io/nsMultiplexInputStream.cpp index 4d36fb90721f..2373cfaa737b 100644 --- a/xpcom/io/nsMultiplexInputStream.cpp +++ b/xpcom/io/nsMultiplexInputStream.cpp @@ -118,6 +118,7 @@ nsMultiplexInputStream::InsertStream(nsIInputStream *aStream, uint32_t aIndex) { NS_ASSERTION(SeekableStreamAtBeginning(aStream), "Inserted stream not at beginning."); bool result = mStreams.InsertElementAt(aIndex, aStream); + NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY); if (mCurrentStream > aIndex || (mCurrentStream == aIndex && mStartedReadingCurrent)) ++mCurrentStream; @@ -142,8 +143,7 @@ NS_IMETHODIMP nsMultiplexInputStream::GetStream(uint32_t aIndex, nsIInputStream **_retval) { *_retval = mStreams.SafeElementAt(aIndex, nullptr); - if (NS_WARN_IF(!*_retval)) - return NS_ERROR_NOT_AVAILABLE; + NS_ENSURE_TRUE(*_retval, NS_ERROR_NOT_AVAILABLE); NS_ADDREF(*_retval); return NS_OK; @@ -181,8 +181,7 @@ nsMultiplexInputStream::Available(uint64_t *_retval) for (uint32_t i = mCurrentStream; i < len; i++) { uint64_t streamAvail; rv = mStreams[i]->Available(&streamAvail); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); avail += streamAvail; } *_retval = avail; @@ -329,8 +328,7 @@ nsMultiplexInputStream::IsNonBlocking(bool *aNonBlocking) } for (uint32_t i = 0; i < len; ++i) { nsresult rv = mStreams[i]->IsNonBlocking(aNonBlocking); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // If one is non-blocking the entire stream becomes non-blocking // (except that we don't implement nsIAsyncInputStream, so there's // not much for the caller to do if Read returns "would block") @@ -369,8 +367,7 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) if (i < oldCurrentStream || (i == oldCurrentStream && oldStartedReadingCurrent)) { rv = stream->Seek(NS_SEEK_SET, 0); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); continue; } else { @@ -386,15 +383,13 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) } else { rv = stream->Tell(&streamPos); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } // See if we need to seek current stream forward or backward if (remaining < streamPos) { rv = stream->Seek(NS_SEEK_SET, remaining); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mCurrentStream = i; mStartedReadingCurrent = remaining != 0; @@ -410,14 +405,12 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) else { uint64_t avail; rv = mStreams[i]->Available(&avail); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); int64_t newPos = XPCOM_MIN(remaining, streamPos + (int64_t)avail); rv = stream->Seek(NS_SEEK_SET, newPos); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mCurrentStream = i; mStartedReadingCurrent = true; @@ -443,14 +436,12 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) uint64_t avail; rv = mStreams[i]->Available(&avail); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); int64_t seek = XPCOM_MIN((int64_t)avail, remaining); rv = stream->Seek(NS_SEEK_CUR, seek); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mCurrentStream = i; mStartedReadingCurrent = true; @@ -469,14 +460,12 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) int64_t pos; rv = stream->Tell(&pos); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); int64_t seek = XPCOM_MIN(pos, remaining); rv = stream->Seek(NS_SEEK_CUR, -seek); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mCurrentStream = i; mStartedReadingCurrent = seek != -pos; @@ -506,8 +495,7 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) if (remaining == 0) { if (i >= oldCurrentStream) { rv = stream->Seek(NS_SEEK_END, 0); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } else { break; @@ -521,8 +509,7 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) } else { uint64_t avail; rv = mStreams[i]->Available(&avail); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); streamPos = avail; } @@ -530,8 +517,7 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) // See if we have enough data in the current stream. if (DeprecatedAbs(remaining) < streamPos) { rv = stream->Seek(NS_SEEK_END, remaining); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mCurrentStream = i; mStartedReadingCurrent = true; @@ -545,14 +531,12 @@ nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) } else { int64_t avail; rv = stream->Tell(&avail); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); int64_t newPos = streamPos + XPCOM_MIN(avail, DeprecatedAbs(remaining)); rv = stream->Seek(NS_SEEK_END, -newPos); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mCurrentStream = i; mStartedReadingCurrent = true; @@ -586,13 +570,11 @@ nsMultiplexInputStream::Tell(int64_t *_retval) last = mStartedReadingCurrent ? mCurrentStream+1 : mCurrentStream; for (i = 0; i < last; ++i) { nsCOMPtr stream = do_QueryInterface(mStreams[i]); - if (NS_WARN_IF(!stream)) - return NS_ERROR_NO_INTERFACE; + NS_ENSURE_TRUE(stream, NS_ERROR_NO_INTERFACE); int64_t pos; rv = stream->Tell(&pos); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); ret64 += pos; } *_retval = ret64; diff --git a/xpcom/io/nsPipe3.cpp b/xpcom/io/nsPipe3.cpp index 4c988cf083bf..eb63ef92432f 100644 --- a/xpcom/io/nsPipe3.cpp +++ b/xpcom/io/nsPipe3.cpp @@ -356,8 +356,7 @@ nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream) NS_IMETHODIMP nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream) { - if (NS_WARN_IF(!mInited)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mInited, NS_ERROR_NOT_INITIALIZED); NS_ADDREF(*aOutputStream = &mOutput); return NS_OK; } diff --git a/xpcom/io/nsStorageStream.cpp b/xpcom/io/nsStorageStream.cpp index 5c745819b5b3..1bf82156757a 100644 --- a/xpcom/io/nsStorageStream.cpp +++ b/xpcom/io/nsStorageStream.cpp @@ -88,10 +88,8 @@ NS_IMETHODIMP nsStorageStream::GetOutputStream(int32_t aStartingOffset, nsIOutputStream * *aOutputStream) { - if (NS_WARN_IF(!aOutputStream)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(!mSegmentedBuffer)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_ARG(aOutputStream); + NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); if (mWriteInProgress) return NS_ERROR_NOT_AVAILABLE; @@ -118,8 +116,7 @@ nsStorageStream::GetOutputStream(int32_t aStartingOffset, NS_IMETHODIMP nsStorageStream::Close() { - if (NS_WARN_IF(!mSegmentedBuffer)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); mWriteInProgress = false; @@ -148,15 +145,15 @@ nsStorageStream::Flush() NS_IMETHODIMP nsStorageStream::Write(const char *aBuffer, uint32_t aCount, uint32_t *aNumWritten) { - if (NS_WARN_IF(!aNumWritten) || NS_WARN_IF(!aBuffer)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(!mSegmentedBuffer)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); const char* readCursor; uint32_t count, availableInSegment, remaining; nsresult rv = NS_OK; + NS_ENSURE_ARG_POINTER(aNumWritten); + NS_ENSURE_ARG(aBuffer); + LOG(("nsStorageStream [%p] Write mWriteCursor=%x mSegmentEnd=%x aCount=%d\n", this, mWriteCursor, mSegmentEnd, aCount)); @@ -226,6 +223,7 @@ nsStorageStream::IsNonBlocking(bool *aNonBlocking) NS_IMETHODIMP nsStorageStream::GetLength(uint32_t *aLength) { + NS_ENSURE_ARG(aLength); *aLength = mLogicalLength; return NS_OK; } @@ -234,8 +232,7 @@ nsStorageStream::GetLength(uint32_t *aLength) NS_IMETHODIMP nsStorageStream::SetLength(uint32_t aLength) { - if (NS_WARN_IF(!mSegmentedBuffer)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); if (mWriteInProgress) return NS_ERROR_NOT_AVAILABLE; @@ -260,6 +257,8 @@ nsStorageStream::SetLength(uint32_t aLength) NS_IMETHODIMP nsStorageStream::GetWriteInProgress(bool *aWriteInProgress) { + NS_ENSURE_ARG(aWriteInProgress); + *aWriteInProgress = mWriteInProgress; return NS_OK; } @@ -267,8 +266,7 @@ nsStorageStream::GetWriteInProgress(bool *aWriteInProgress) NS_METHOD nsStorageStream::Seek(int32_t aPosition) { - if (NS_WARN_IF(!mSegmentedBuffer)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); // An argument of -1 means "seek to end of stream" if (aPosition == -1) @@ -360,8 +358,7 @@ NS_IMPL_ISUPPORTS2(nsStorageInputStream, NS_IMETHODIMP nsStorageStream::NewInputStream(int32_t aStartingOffset, nsIInputStream* *aInputStream) { - if (NS_WARN_IF(!mSegmentedBuffer)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mSegmentedBuffer, NS_ERROR_NOT_INITIALIZED); nsStorageInputStream *inputStream = new nsStorageInputStream(this, mSegmentSize); if (!inputStream) @@ -527,6 +524,8 @@ nsStorageInputStream::Seek(uint32_t aPosition) nsresult NS_NewStorageStream(uint32_t segmentSize, uint32_t maxSize, nsIStorageStream **result) { + NS_ENSURE_ARG(result); + nsStorageStream* storageStream = new nsStorageStream(); if (!storageStream) return NS_ERROR_OUT_OF_MEMORY; diff --git a/xpcom/io/nsStringStream.cpp b/xpcom/io/nsStringStream.cpp index f6bfd18d9f72..f32817811921 100644 --- a/xpcom/io/nsStringStream.cpp +++ b/xpcom/io/nsStringStream.cpp @@ -112,8 +112,7 @@ nsStringInputStream::GetData(nsACString &data) // The stream doesn't have any data when it is closed. We could fake it // and return an empty string here, but it seems better to keep this return // value consistent with the behavior of the other 'getter' methods. - if (NS_WARN_IF(Closed())) - return NS_BASE_STREAM_CLOSED; + NS_ENSURE_TRUE(!Closed(), NS_BASE_STREAM_CLOSED); data.Assign(mData); return NS_OK; @@ -141,8 +140,7 @@ nsStringInputStream::ToString(char **result) NS_IMETHODIMP nsStringInputStream::SetData(const char *data, int32_t dataLen) { - if (NS_WARN_IF(!data)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(data); mData.Assign(data, dataLen); mOffset = 0; return NS_OK; @@ -151,8 +149,7 @@ nsStringInputStream::SetData(const char *data, int32_t dataLen) NS_IMETHODIMP nsStringInputStream::AdoptData(char *data, int32_t dataLen) { - if (NS_WARN_IF(!data)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(data); mData.Adopt(data, dataLen); mOffset = 0; return NS_OK; @@ -161,8 +158,7 @@ nsStringInputStream::AdoptData(char *data, int32_t dataLen) NS_IMETHODIMP nsStringInputStream::ShareData(const char *data, int32_t dataLen) { - if (NS_WARN_IF(!data)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(data); if (dataLen < 0) dataLen = strlen(data); @@ -266,8 +262,8 @@ nsStringInputStream::Seek(int32_t whence, int64_t offset) return NS_ERROR_INVALID_ARG; } - if (NS_WARN_IF(newPos < 0) || NS_WARN_IF(newPos > Length())) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(newPos >= 0); + NS_ENSURE_ARG(newPos <= Length()); mOffset = (uint32_t)newPos; return NS_OK; @@ -390,8 +386,7 @@ nsStringInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result) { *result = nullptr; - if (NS_WARN_IF(outer)) - return NS_ERROR_NO_AGGREGATION; + NS_ENSURE_TRUE(!outer, NS_ERROR_NO_AGGREGATION); nsStringInputStream *inst = new nsStringInputStream(); if (!inst) diff --git a/xpcom/reflect/xptcall/src/xptcall.cpp b/xpcom/reflect/xptcall/src/xptcall.cpp index a33b1e70051d..e46ddd559d3d 100644 --- a/xpcom/reflect/xptcall/src/xptcall.cpp +++ b/xpcom/reflect/xptcall/src/xptcall.cpp @@ -40,13 +40,11 @@ EXPORT_XPCOM_API(nsresult) NS_GetXPTCallStub(REFNSIID aIID, nsIXPTCProxy* aOuter, nsISomeInterface* *aResult) { - if (NS_WARN_IF(!aOuter) || NS_WARN_IF(!aResult)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG(aOuter && aResult); XPTInterfaceInfoManager *iim = XPTInterfaceInfoManager::GetSingleton(); - if (NS_WARN_IF(!iim)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(iim, NS_ERROR_NOT_INITIALIZED); xptiInterfaceEntry *iie = iim->GetInterfaceEntryForIID(&aIID); if (!iie || !iie->EnsureResolved() || iie->GetBuiltinClassFlag()) diff --git a/xpcom/threads/LazyIdleThread.cpp b/xpcom/threads/LazyIdleThread.cpp index 71bf2ea53718..0cf14ad0acd5 100644 --- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -147,26 +147,21 @@ LazyIdleThread::EnsureThread() if (mShutdownMethod == AutomaticShutdown && NS_IsMainThread()) { nsCOMPtr obs = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = obs->AddObserver(this, "xpcom-shutdown-threads", false); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } mIdleTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); - if (NS_WARN_IF(!mIdleTimer)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(mIdleTimer, NS_ERROR_FAILURE); nsCOMPtr runnable = NS_NewRunnableMethod(this, &LazyIdleThread::InitThread); - if (NS_WARN_IF(!runnable)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE); rv = NS_NewThread(getter_AddRefs(mThread), runnable); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -273,14 +268,12 @@ LazyIdleThread::ShutdownThread() nsCOMPtr runnable = NS_NewRunnableMethod(this, &LazyIdleThread::CleanupThread); - if (NS_WARN_IF(!runnable)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE); PreDispatch(); rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); // Put the temporary queue in place before calling Shutdown(). mQueuedRunnables = &queuedRunnables; @@ -306,8 +299,7 @@ LazyIdleThread::ShutdownThread() if (mIdleTimer) { rv = mIdleTimer->Cancel(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); mIdleTimer = nullptr; } @@ -384,8 +376,7 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent, ASSERT_OWNING_THREAD(); // LazyIdleThread can't always support synchronous dispatch currently. - if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) - return NS_ERROR_NOT_IMPLEMENTED; + NS_ENSURE_TRUE(aFlags == NS_DISPATCH_NORMAL, NS_ERROR_NOT_IMPLEMENTED); // If our thread is shutting down then we can't actually dispatch right now. // Queue this runnable for later. @@ -395,8 +386,7 @@ LazyIdleThread::Dispatch(nsIRunnable* aEvent, } nsresult rv = EnsureThread(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); PreDispatch(); @@ -437,8 +427,7 @@ LazyIdleThread::Shutdown() mIdleObserver = nullptr; - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -478,8 +467,7 @@ LazyIdleThread::Notify(nsITimer* aTimer) } nsresult rv = ShutdownThread(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } @@ -525,12 +513,10 @@ LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */, if (shouldNotifyIdle) { nsCOMPtr runnable = NS_NewRunnableMethod(this, &LazyIdleThread::ScheduleTimer); - if (NS_WARN_IF(!runnable)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_TRUE(runnable, NS_ERROR_FAILURE); nsresult rv = mOwningThread->Dispatch(runnable, NS_DISPATCH_NORMAL); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; diff --git a/xpcom/threads/nsEnvironment.cpp b/xpcom/threads/nsEnvironment.cpp index 53b207556735..f5c0656b4ed3 100644 --- a/xpcom/threads/nsEnvironment.cpp +++ b/xpcom/threads/nsEnvironment.cpp @@ -48,8 +48,7 @@ nsEnvironment::Exists(const nsAString& aName, bool *aOutValue) { nsAutoCString nativeName; nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsAutoCString nativeVal; #if defined(XP_UNIX) @@ -79,8 +78,7 @@ nsEnvironment::Get(const nsAString& aName, nsAString& aOutValue) { nsAutoCString nativeName; nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); nsAutoCString nativeVal; const char *value = PR_GetEnv(nativeName.get()); @@ -124,12 +122,10 @@ nsEnvironment::Set(const nsAString& aName, const nsAString& aValue) nsAutoCString nativeVal; nsresult rv = NS_CopyUnicodeToNative(aName, nativeName); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); rv = NS_CopyUnicodeToNative(aValue, nativeVal); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); MutexAutoLock lock(mLock); diff --git a/xpcom/threads/nsMemoryPressure.cpp b/xpcom/threads/nsMemoryPressure.cpp index 094d4c06ab04..0e1b556054ea 100644 --- a/xpcom/threads/nsMemoryPressure.cpp +++ b/xpcom/threads/nsMemoryPressure.cpp @@ -49,5 +49,6 @@ NS_DispatchMemoryPressure(MemoryPressureState state) { NS_DispatchEventualMemoryPressure(state); nsCOMPtr event = new nsRunnable; + NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY); return NS_DispatchToMainThread(event); } diff --git a/xpcom/threads/nsProcessCommon.cpp b/xpcom/threads/nsProcessCommon.cpp index d2d660bafb66..8a6345d11d35 100644 --- a/xpcom/threads/nsProcessCommon.cpp +++ b/xpcom/threads/nsProcessCommon.cpp @@ -88,8 +88,7 @@ nsProcess::Init(nsIFile* executable) if (mExecutable) return NS_ERROR_ALREADY_INITIALIZED; - if (NS_WARN_IF(!executable)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(executable); bool isFile; //First make sure the file exists @@ -409,10 +408,8 @@ nsresult nsProcess::RunProcess(bool blocking, char **my_argv, nsIObserver* observer, bool holdWeak, bool argsUTF8) { - if (NS_WARN_IF(!mExecutable)) - return NS_ERROR_NOT_INITIALIZED; - if (NS_WARN_IF(mThread)) - return NS_ERROR_ALREADY_INITIALIZED; + NS_ENSURE_TRUE(mExecutable, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_FALSE(mThread, NS_ERROR_ALREADY_INITIALIZED); if (observer) { if (holdWeak) { diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 9cc4e2528e8f..94e8a04da130 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -152,9 +152,9 @@ NS_IMPL_CI_INTERFACE_GETTER4(nsThread, nsIThread, nsIThreadInternal, class nsThreadStartupEvent : public nsRunnable { public: - nsThreadStartupEvent() - : mMon("nsThreadStartupEvent.mMon") - , mInitialized(false) { + // Create a new thread startup object. + static nsThreadStartupEvent *Create() { + return new nsThreadStartupEvent(); } // This method does not return until the thread startup object is in the @@ -180,6 +180,11 @@ private: return NS_OK; } + nsThreadStartupEvent() + : mMon("nsThreadStartupEvent.mMon") + , mInitialized(false) { + } + ReentrantMonitor mMon; bool mInitialized; }; @@ -305,7 +310,8 @@ nsresult nsThread::Init() { // spawn thread and wait until it is fully setup - nsRefPtr startup = new nsThreadStartupEvent(); + nsRefPtr startup = nsThreadStartupEvent::Create(); + NS_ENSURE_TRUE(startup, NS_ERROR_OUT_OF_MEMORY); NS_ADDREF_THIS(); @@ -371,8 +377,7 @@ nsThread::Dispatch(nsIRunnable *event, uint32_t flags) { LOG(("THRD(%p) Dispatch [%p %x]\n", this, event, flags)); - if (NS_WARN_IF(!event)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(event); if (gXPCOMThreadsShutDown && MAIN_THREAD != mIsMainThread) { return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; @@ -380,8 +385,7 @@ nsThread::Dispatch(nsIRunnable *event, uint32_t flags) if (flags & DISPATCH_SYNC) { nsThread *thread = nsThreadManager::get()->GetCurrentThread(); - if (NS_WARN_IF(!thread)) - return NS_ERROR_NOT_AVAILABLE; + NS_ENSURE_STATE(thread); // XXX we should be able to do something better here... we should // be able to monitor the slot occupied by this event and use @@ -433,8 +437,7 @@ nsThread::Shutdown() if (!mThread) return NS_OK; - if (NS_WARN_IF(mThread == PR_GetCurrentThread())) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(mThread != PR_GetCurrentThread()); // Prevent multiple calls to this method { @@ -487,8 +490,7 @@ nsThread::Shutdown() NS_IMETHODIMP nsThread::HasPendingEvents(bool *result) { - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) - return NS_ERROR_NOT_SAME_THREAD; + NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); *result = mEvents.GetEvent(false, nullptr); return NS_OK; @@ -546,8 +548,7 @@ nsThread::ProcessNextEvent(bool mayWait, bool *result) { LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, mayWait, mRunningEvent)); - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) - return NS_ERROR_NOT_SAME_THREAD; + NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); if (MAIN_THREAD == mIsMainThread && mayWait && !ShuttingDown()) HangMonitor::Suspend(); @@ -643,8 +644,7 @@ nsThread::GetPriority(int32_t *priority) NS_IMETHODIMP nsThread::SetPriority(int32_t priority) { - if (NS_WARN_IF(!mThread)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_STATE(mThread); // NSPR defines the following four thread priorities: // PR_PRIORITY_LOW @@ -690,8 +690,7 @@ nsThread::GetObserver(nsIThreadObserver **obs) NS_IMETHODIMP nsThread::SetObserver(nsIThreadObserver *obs) { - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) - return NS_ERROR_NOT_SAME_THREAD; + NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); MutexAutoLock lock(mLock); mObserver = obs; @@ -701,8 +700,8 @@ nsThread::SetObserver(nsIThreadObserver *obs) NS_IMETHODIMP nsThread::GetRecursionDepth(uint32_t *depth) { - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) - return NS_ERROR_NOT_SAME_THREAD; + NS_ENSURE_ARG_POINTER(depth); + NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); *depth = mRunningEvent; return NS_OK; @@ -711,10 +710,8 @@ nsThread::GetRecursionDepth(uint32_t *depth) NS_IMETHODIMP nsThread::AddObserver(nsIThreadObserver *observer) { - if (NS_WARN_IF(!observer)) - return NS_ERROR_INVALID_ARG; - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) - return NS_ERROR_NOT_SAME_THREAD; + NS_ENSURE_ARG_POINTER(observer); + NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); NS_WARN_IF_FALSE(!mEventObservers.Contains(observer), "Adding an observer twice!"); @@ -730,8 +727,7 @@ nsThread::AddObserver(nsIThreadObserver *observer) NS_IMETHODIMP nsThread::RemoveObserver(nsIThreadObserver *observer) { - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) - return NS_ERROR_NOT_SAME_THREAD; + NS_ENSURE_STATE(PR_GetCurrentThread() == mThread); if (observer && !mEventObservers.RemoveElement(observer)) { NS_WARNING("Removing an observer that was never added!"); diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index cf41dcdb49a9..52d1364f6953 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -217,8 +217,7 @@ nsThreadManager::NewThread(uint32_t creationFlags, nsIThread **result) { // No new threads during Shutdown - if (NS_WARN_IF(!mInitialized)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_INITIALIZED); nsThread *thr = new nsThread(nsThread::NOT_MAIN_THREAD, stackSize); if (!thr) @@ -243,10 +242,8 @@ NS_IMETHODIMP nsThreadManager::GetThreadFromPRThread(PRThread *thread, nsIThread **result) { // Keep this functioning during Shutdown - if (NS_WARN_IF(!mMainThread)) - return NS_ERROR_NOT_INITIALIZED; - if (NS_WARN_IF(!thread)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED); + NS_ENSURE_ARG_POINTER(thread); nsRefPtr temp; { @@ -262,8 +259,7 @@ NS_IMETHODIMP nsThreadManager::GetMainThread(nsIThread **result) { // Keep this functioning during Shutdown - if (NS_WARN_IF(!mMainThread)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED); NS_ADDREF(*result = mMainThread); return NS_OK; } @@ -272,8 +268,7 @@ NS_IMETHODIMP nsThreadManager::GetCurrentThread(nsIThread **result) { // Keep this functioning during Shutdown - if (NS_WARN_IF(!mMainThread)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(mMainThread, NS_ERROR_NOT_INITIALIZED); *result = GetCurrentThread(); if (!*result) return NS_ERROR_OUT_OF_MEMORY; diff --git a/xpcom/threads/nsThreadPool.cpp b/xpcom/threads/nsThreadPool.cpp index 6e3236db7a73..2ccc4b0142f2 100644 --- a/xpcom/threads/nsThreadPool.cpp +++ b/xpcom/threads/nsThreadPool.cpp @@ -92,8 +92,7 @@ nsThreadPool::PutEvent(nsIRunnable *event) nsThreadManager::get()->NewThread(0, nsIThreadManager::DEFAULT_STACK_SIZE, getter_AddRefs(thread)); - if (NS_WARN_IF(!thread)) - return NS_ERROR_UNEXPECTED; + NS_ENSURE_STATE(thread); bool killThread = false; { @@ -226,14 +225,12 @@ nsThreadPool::Dispatch(nsIRunnable *event, uint32_t flags) { LOG(("THRD-P(%p) dispatch [%p %x]\n", this, event, flags)); - if (NS_WARN_IF(mShutdown)) - return NS_ERROR_NOT_AVAILABLE; + NS_ENSURE_STATE(!mShutdown); if (flags & DISPATCH_SYNC) { nsCOMPtr thread; nsThreadManager::get()->GetCurrentThread(getter_AddRefs(thread)); - if (NS_WARN_IF(!thread)) - return NS_ERROR_NOT_AVAILABLE; + NS_ENSURE_STATE(thread); nsRefPtr wrapper = new nsThreadSyncDispatch(thread, event); diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index 3aa9e606e24c..bb59fc98bf10 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -317,16 +317,14 @@ nsresult nsTimerImpl::InitCommon(uint32_t aType, uint32_t aDelay) { nsresult rv; - if (NS_WARN_IF(!gThread)) - return NS_ERROR_NOT_INITIALIZED; + NS_ENSURE_TRUE(gThread, NS_ERROR_NOT_INITIALIZED); if (!mEventTarget) { NS_ERROR("mEventTarget is NULL"); return NS_ERROR_NOT_INITIALIZED; } rv = gThread->Init(); - if (NS_WARN_IF(NS_FAILED(rv))) - return rv; + NS_ENSURE_SUCCESS(rv, rv); /** * In case of re-Init, both with and without a preceding Cancel, clear the @@ -359,8 +357,7 @@ NS_IMETHODIMP nsTimerImpl::InitWithFuncCallback(nsTimerCallbackFunc aFunc, uint32_t aDelay, uint32_t aType) { - if (NS_WARN_IF(!aFunc)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aFunc); ReleaseCallback(); mCallbackType = CALLBACK_TYPE_FUNC; @@ -374,8 +371,7 @@ NS_IMETHODIMP nsTimerImpl::InitWithCallback(nsITimerCallback *aCallback, uint32_t aDelay, uint32_t aType) { - if (NS_WARN_IF(!aCallback)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aCallback); ReleaseCallback(); mCallbackType = CALLBACK_TYPE_INTERFACE; @@ -389,8 +385,7 @@ NS_IMETHODIMP nsTimerImpl::Init(nsIObserver *aObserver, uint32_t aDelay, uint32_t aType) { - if (NS_WARN_IF(!aObserver)) - return NS_ERROR_INVALID_ARG; + NS_ENSURE_ARG_POINTER(aObserver); ReleaseCallback(); mCallbackType = CALLBACK_TYPE_OBSERVER; @@ -486,8 +481,8 @@ NS_IMETHODIMP nsTimerImpl::GetTarget(nsIEventTarget** aTarget) NS_IMETHODIMP nsTimerImpl::SetTarget(nsIEventTarget* aTarget) { - if (NS_WARN_IF(mCallbackType != CALLBACK_TYPE_UNKNOWN)) - return NS_ERROR_ALREADY_INITIALIZED; + NS_ENSURE_TRUE(mCallbackType == CALLBACK_TYPE_UNKNOWN, + NS_ERROR_ALREADY_INITIALIZED); if (aTarget) mEventTarget = aTarget; From 12f55d2d13ce8722a0055fcc7caba4110593cee8 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Tue, 19 Nov 2013 18:20:48 -0500 Subject: [PATCH 024/268] Backed out changeset 6f476f02c21e (bug 940129) for build bustage on a CLOSED TREE --- widget/gonk/HwcComposer2D.cpp | 1 + widget/gonk/moz.build | 29 ++++++++--------------------- widget/gonk/nativewindow/moz.build | 4 ++-- 3 files changed, 11 insertions(+), 23 deletions(-) diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp index b00b3c0df8a1..13bd5fc88f9c 100644 --- a/widget/gonk/HwcComposer2D.cpp +++ b/widget/gonk/HwcComposer2D.cpp @@ -50,6 +50,7 @@ #define LAYER_COUNT_INCREMENTS 5 +using namespace android; using namespace mozilla::layers; namespace mozilla { diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build index fc0b96ff2ec1..6cbb987d4aa2 100644 --- a/widget/gonk/moz.build +++ b/widget/gonk/moz.build @@ -21,14 +21,18 @@ EXPORTS += [ DIRS += ['libdisplay', 'nativewindow'] # libui files -UNIFIED_SOURCES += ['libui/' + src for src in [ +SOURCES += ['libui/' + src for src in [ 'EventHub.cpp', 'Input.cpp', 'InputApplication.cpp', 'InputDevice.cpp', + 'InputDispatcher.cpp', 'InputListener.cpp', + 'InputReader.cpp', + 'InputTransport.cpp', 'InputWindow.cpp', 'Keyboard.cpp', + 'KeyCharacterMap.cpp', 'KeyLayoutMap.cpp', 'PointerController.cpp', 'SpriteController.cpp', @@ -38,38 +42,21 @@ UNIFIED_SOURCES += ['libui/' + src for src in [ 'VirtualKeyMap.cpp', ]] -# libui files that can't be UNIFIED_SOURCES because they define -# a symbol that's already defined in some above file. -# Could easily unify if it's OK to patch libui. -SOURCES += ['libui/' + src for src in [ - 'InputDispatcher.cpp', # because of toString in EventHub.cpp - 'InputReader.cpp', # because of toString in EventHub.cpp - 'InputTransport.cpp', # because of NANOS_PER_MS in VelocityTracker.cpp - 'KeyCharacterMap.cpp', # because of toString in EventHub.cpp -]] - -UNIFIED_SOURCES += [ +SOURCES += [ 'Framebuffer.cpp', 'GfxInfo.cpp', 'GonkMemoryPressureMonitoring.cpp', 'HwcComposer2D.cpp', 'HwcUtils.cpp', + 'nsAppShell.cpp', 'nsIdleServiceGonk.cpp', 'nsLookAndFeel.cpp', 'nsWidgetFactory.cpp', + 'nsWindow.cpp', 'OrientationObserver.cpp', 'ProcessOrientation.cpp' ] -# These files couldn't be added to UNIFIED_SOURCES for now: -SOURCES += [ - # nsAppShell has a 'using namespace android' that is very unfriendly to UNIFIED_SOURCES. - # Can unify if we're OK to add a lot of android:: in that file. - 'nsAppShell.cpp', - # nsWindow.cpp doesn't build in UNIFIED_SOURCES due to logging macros being redefined. - 'nsWindow.cpp', -] - LIBRARY_NAME = 'widget_gonk' include('/ipc/chromium/chromium-config.mozbuild') diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build index 6c27d5ecd7ec..88695c7349bd 100644 --- a/widget/gonk/nativewindow/moz.build +++ b/widget/gonk/nativewindow/moz.build @@ -34,14 +34,14 @@ elif CONFIG['ANDROID_VERSION'] == '15': if CONFIG['MOZ_B2G_CAMERA'] or CONFIG['MOZ_OMX_DECODER']: if CONFIG['ANDROID_VERSION'] in ('17', '18'): - UNIFIED_SOURCES += [ + SOURCES += [ 'GonkBufferQueue.cpp', 'GonkConsumerBase.cpp', 'GonkNativeWindowClientJB.cpp', 'GonkNativeWindowJB.cpp', ] elif CONFIG['ANDROID_VERSION'] == '15': - UNIFIED_SOURCES += [ + SOURCES += [ 'GonkNativeWindowClientICS.cpp', 'GonkNativeWindowICS.cpp', ] From 195dd4c06285d2ebfdf52fe473de8a4bfdb280a8 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 19 Nov 2013 21:59:10 -0800 Subject: [PATCH 025/268] Back out 4983f1debf4c (bug 918880) for b2g mochitest-3 bustage CLOSED TREE --- content/base/public/nsContentUtils.h | 2 +- content/base/src/nsContentSink.cpp | 2 +- content/base/src/nsContentUtils.cpp | 20 +++--- dom/ipc/PBrowser.ipdl | 7 --- dom/ipc/TabParent.cpp | 8 --- dom/ipc/TabParent.h | 1 - uriloader/prefetch/nsIOfflineCacheUpdate.idl | 9 +-- uriloader/prefetch/nsOfflineCacheUpdate.h | 5 -- .../prefetch/nsOfflineCacheUpdateService.cpp | 62 ------------------- 9 files changed, 15 insertions(+), 101 deletions(-) diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 9cdf562889d0..1e8b5825fe0f 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1456,7 +1456,7 @@ public: * If offline-apps.allow_by_default is true, we set offline-app permission * for the principal and return true. Otherwise false. */ - static bool MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, nsIDOMWindow *aWindow); + static bool MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal); /** * Increases the count of blockers preventing scripts from running. diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index 0f21846b1f45..3d1a140e2dd9 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -1064,7 +1064,7 @@ nsContentSink::ProcessOfflineManifest(const nsAString& aManifestSpec) // Only continue if the document has permission to use offline APIs or // when preferences indicate to permit it automatically. if (!nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal()) && - !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal(), mDocument->GetWindow()) && + !nsContentUtils::MaybeAllowOfflineAppByDefault(mDocument->NodePrincipal()) && !nsContentUtils::OfflineAppAllowed(mDocument->NodePrincipal())) { return; } diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 5ef9ecdfac33..787a1d5fd2c7 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -1426,8 +1426,7 @@ nsContentUtils::OfflineAppAllowed(nsIPrincipal *aPrincipal) } bool -nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, - nsIDOMWindow *aWindow) +nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal) { if (!Preferences::GetRootBranch()) return false; @@ -1443,14 +1442,19 @@ nsContentUtils::MaybeAllowOfflineAppByDefault(nsIPrincipal *aPrincipal, if (!allowedByDefault) return false; - nsCOMPtr updateService = - do_GetService(NS_OFFLINECACHEUPDATESERVICE_CONTRACTID); - if (!updateService) { + nsCOMPtr permissionManager = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + if (!permissionManager) return false; - } - rv = updateService->AllowOfflineApp(aWindow, aPrincipal); - return NS_SUCCEEDED(rv); + rv = permissionManager->AddFromPrincipal( + aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION, + nsIPermissionManager::EXPIRE_NEVER, 0); + if (NS_FAILED(rv)) + return false; + + // We have added the permission + return true; } // static diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 6e04131e71ed..53d350f39b87 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -258,13 +258,6 @@ parent: POfflineCacheUpdate(URIParams manifestURI, URIParams documentURI, bool stickDocument); - /** - * Sets "offline-app" permission for the principal. Called when we hit - * a web app with the manifest attribute in and - * offline-apps.allow_by_default is set to true. - */ - SetOfflinePermission(Principal principal); - sync PIndexedDB(nsCString group, nsCString asciiOrigin) returns (bool allowed); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 465d04b21729..9a06193e6890 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -1512,14 +1512,6 @@ TabParent::DeallocPOfflineCacheUpdateParent(mozilla::docshell::POfflineCacheUpda return true; } -bool -TabParent::RecvSetOfflinePermission(const IPC::Principal& aPrincipal) -{ - nsIPrincipal* principal = aPrincipal; - nsContentUtils::MaybeAllowOfflineAppByDefault(principal, nullptr); - return true; -} - bool TabParent::ShouldDelayDialogs() { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 87d43cc90026..eb67fbe060f6 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -234,7 +234,6 @@ public: const URIParams& aDocumentURI, const bool& stickDocument) MOZ_OVERRIDE; virtual bool DeallocPOfflineCacheUpdateParent(POfflineCacheUpdateParent* actor); - virtual bool RecvSetOfflinePermission(const IPC::Principal& principal); bool GetGlobalJSObject(JSContext* cx, JSObject** globalp); diff --git a/uriloader/prefetch/nsIOfflineCacheUpdate.idl b/uriloader/prefetch/nsIOfflineCacheUpdate.idl index adf202fad7f7..dddbf255eb61 100644 --- a/uriloader/prefetch/nsIOfflineCacheUpdate.idl +++ b/uriloader/prefetch/nsIOfflineCacheUpdate.idl @@ -197,7 +197,7 @@ interface nsIOfflineCacheUpdate : nsISupports { readonly attribute uint64_t byteProgress; }; -[scriptable, uuid(6ee353ba-11ea-4008-a78a-55b343fb2a49)] +[scriptable, uuid(cf362a31-4166-4994-8443-b68704ecdcc0)] interface nsIOfflineCacheUpdateService : nsISupports { /** * Constants for the offline-app permission. @@ -296,11 +296,4 @@ interface nsIOfflineCacheUpdateService : nsISupports { */ boolean offlineAppAllowedForURI(in nsIURI aURI, in nsIPrefBranch aPrefBranch); - - /** - * Sets the "offline-app" permission for the principal. - * In the single process model calls directly on permission manager. - * In the multi process model dispatches to the parent process. - */ - void allowOfflineApp(in nsIDOMWindow aWindow, in nsIPrincipal aPrincipal); }; diff --git a/uriloader/prefetch/nsOfflineCacheUpdate.h b/uriloader/prefetch/nsOfflineCacheUpdate.h index 36d410495d7f..6dd0eb175fa7 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdate.h +++ b/uriloader/prefetch/nsOfflineCacheUpdate.h @@ -32,8 +32,6 @@ #include "nsWeakReference.h" #include "nsICryptoHash.h" #include "mozilla/Attributes.h" -#include "nsTHashtable.h" -#include "nsHashKeys.h" class nsOfflineCacheUpdate; @@ -352,13 +350,10 @@ public: nsIPrefBranch *aPrefBranch, bool *aPinned); - static nsTHashtable* AllowedDomains(); - private: nsresult ProcessNextUpdate(); nsTArray > mUpdates; - static nsTHashtable* mAllowedDomains; bool mDisabled; bool mUpdateRunning; diff --git a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp index 2bec71550a3f..d3acc291c96c 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp @@ -47,28 +47,11 @@ #include "mozilla/Preferences.h" #include "mozilla/Attributes.h" #include "nsIDiskSpaceWatcher.h" -#include "nsIDocShell.h" -#include "nsIDocShellTreeItem.h" -#include "nsIDocShellTreeOwner.h" -#include "mozilla/dom/TabChild.h" -#include "mozilla/dom/PermissionMessageUtils.h" using namespace mozilla; -using namespace mozilla::dom; static nsOfflineCacheUpdateService *gOfflineCacheUpdateService = nullptr; -nsTHashtable* nsOfflineCacheUpdateService::mAllowedDomains = nullptr; - -nsTHashtable* nsOfflineCacheUpdateService::AllowedDomains() -{ - if (!mAllowedDomains) - mAllowedDomains = new nsTHashtable(); - - return mAllowedDomains; -} - - typedef mozilla::docshell::OfflineCacheUpdateParent OfflineCacheUpdateParent; typedef mozilla::docshell::OfflineCacheUpdateChild OfflineCacheUpdateChild; typedef mozilla::docshell::OfflineCacheUpdateGlue OfflineCacheUpdateGlue; @@ -705,15 +688,6 @@ OfflineAppPermForURI(nsIURI *aURI, } } - nsAutoCString domain; - rv = innerURI->GetAsciiHost(domain); - NS_ENSURE_SUCCESS(rv, rv); - - if (nsOfflineCacheUpdateService::AllowedDomains()->Contains(domain)) { - *aAllowed = true; - return NS_OK; - } - nsCOMPtr permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); if (!permissionManager) { @@ -750,39 +724,3 @@ nsOfflineCacheUpdateService::OfflineAppPinnedForURI(nsIURI *aDocumentURI, { return OfflineAppPermForURI(aDocumentURI, aPrefBranch, true, aPinned); } - -NS_IMETHODIMP -nsOfflineCacheUpdateService::AllowOfflineApp(nsIDOMWindow *aWindow, - nsIPrincipal *aPrincipal) -{ - nsresult rv; - - if (GeckoProcessType_Default != XRE_GetProcessType()) { - TabChild* child = TabChild::GetFrom(aWindow); - NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); - - if (!child->SendSetOfflinePermission(IPC::Principal(aPrincipal))) { - return NS_ERROR_FAILURE; - } - - nsAutoCString domain; - rv = aPrincipal->GetBaseDomain(domain); - NS_ENSURE_SUCCESS(rv, rv); - - nsOfflineCacheUpdateService::AllowedDomains()->PutEntry(domain); - } - else { - nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); - if (!permissionManager) - return NS_ERROR_NOT_AVAILABLE; - - rv = permissionManager->AddFromPrincipal( - aPrincipal, "offline-app", nsIPermissionManager::ALLOW_ACTION, - nsIPermissionManager::EXPIRE_NEVER, 0); - if (NS_FAILED(rv)) - return rv; - } - - return NS_OK; -} From cddea8f44c422c2a9a4d8838b7ce99ebd3c5a7f0 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 19 Nov 2013 22:27:56 -0800 Subject: [PATCH 026/268] Back out 00644e4b067d (bug 938124) for debug browser-chrome bustage, and probable debug ASan jit-test bustage CLOSED TREE --- js/src/builtin/Eval.cpp | 6 - js/src/builtin/Eval.h | 5 - js/src/gc/Barrier.h | 3 - js/src/gc/Heap.h | 42 +--- js/src/jit/BaselineFrame.h | 4 +- js/src/jit/BaselineInspector.h | 4 +- js/src/jit/BytecodeAnalysis.cpp | 20 +- js/src/jit/BytecodeAnalysis.h | 8 +- js/src/jit/CodeGenerator.cpp | 13 +- js/src/jit/CompileInfo.h | 18 +- js/src/jit/Ion.cpp | 22 +- js/src/jit/Ion.h | 6 - js/src/jit/IonBuilder.cpp | 219 ++++++++++---------- js/src/jit/IonCode.h | 1 - js/src/jit/IonMacroAssembler.cpp | 18 +- js/src/jit/MCallOptimize.cpp | 17 +- js/src/jit/MIR.cpp | 10 +- js/src/jit/MIR.h | 27 +-- js/src/jit/MIRGraph.h | 2 +- js/src/jit/ParallelFunctions.cpp | 6 +- js/src/jit/Snapshots.cpp | 10 +- js/src/jit/shared/CodeGenerator-shared.cpp | 1 - js/src/jsanalyze.h | 2 +- js/src/jsapi-tests/testConservativeGC.cpp | 1 + js/src/jsapi.h | 4 +- js/src/jsarray.cpp | 4 +- js/src/jsatominlines.h | 1 - js/src/jsbool.cpp | 2 +- js/src/jscntxt.cpp | 4 +- js/src/jscntxt.h | 2 +- js/src/jscompartmentinlines.h | 2 +- js/src/jsfun.h | 60 ++---- js/src/jsinfer.cpp | 34 +-- js/src/jsinfer.h | 35 +--- js/src/jsinferinlines.h | 23 +-- js/src/jsobj.cpp | 2 - js/src/jsobj.h | 19 +- js/src/jsopcode.cpp | 5 +- js/src/jsopcodeinlines.h | 8 +- js/src/jsscript.cpp | 16 +- js/src/jsscript.h | 228 ++------------------- js/src/jsscriptinlines.h | 5 +- js/src/jsstr.cpp | 11 +- js/src/jsstr.h | 16 +- js/src/shell/js.cpp | 14 +- js/src/vm/GlobalObject.h | 44 +--- js/src/vm/ObjectImpl.cpp | 19 -- js/src/vm/ObjectImpl.h | 42 +--- js/src/vm/RegExpObject.h | 8 +- js/src/vm/Runtime-inl.h | 7 +- js/src/vm/Runtime.cpp | 75 ------- js/src/vm/Runtime.h | 31 --- js/src/vm/ScopeObject-inl.h | 9 +- js/src/vm/ScopeObject.cpp | 4 +- js/src/vm/ScopeObject.h | 25 +-- js/src/vm/Shape.cpp | 2 +- js/src/vm/Shape.h | 68 +----- js/src/vm/String.h | 2 - js/src/vm/TypedArrayObject.h | 4 - 59 files changed, 340 insertions(+), 960 deletions(-) diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp index 8d2cdb7539e5..4923281c6720 100644 --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -431,12 +431,6 @@ js::IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v) return scopeChain->global().getOriginalEval() == v; } -bool -js::IsBuiltinEvalForScope(GlobalObject *global, const Value &v) -{ - return global->getOriginalEval() == v; -} - bool js::IsAnyBuiltinEval(JSFunction *fun) { diff --git a/js/src/builtin/Eval.h b/js/src/builtin/Eval.h index 6016d86270ed..1d15b00c04b5 100644 --- a/js/src/builtin/Eval.h +++ b/js/src/builtin/Eval.h @@ -38,11 +38,6 @@ DirectEvalFromIon(JSContext *cx, extern bool IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v); -class GlobalObject; - -extern bool -IsBuiltinEvalForScope(GlobalObject *global, const Value &v); - // True iff fun is a built-in eval function. extern bool IsAnyBuiltinEval(JSFunction *fun); diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 6f9d927668b1..dfbfc52ed8f6 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -159,9 +159,6 @@ class BarrieredCell : public gc::Cell static JS_ALWAYS_INLINE void readBarrier(T *thing) { #ifdef JSGC_INCREMENTAL - // Off thread Ion compilation never occurs when barriers are active. - AutoUnprotectCell unprotect(thing); - JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread(); if (shadowZone->needsBarrier()) { MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone)); diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index a398bd37aae6..8ec61d7cba08 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -993,6 +993,12 @@ Cell::shadowRuntimeFromAnyThread() const return reinterpret_cast(runtimeFromAnyThread()); } +AllocKind +Cell::tenuredGetAllocKind() const +{ + return arenaHeader()->getAllocKind(); +} + bool Cell::isMarked(uint32_t color /* = BLACK */) const { @@ -1108,42 +1114,6 @@ InFreeList(ArenaHeader *aheader, void *thing) } } /* namespace gc */ - -// Ion compilation mainly occurs off the main thread, and may run while the -// main thread is performing arbitrary VM operations, excepting GC activity. -// The below class is used to mark functions and other operations which can -// safely be performed off thread without racing. When running with thread -// safety checking on, any access to a GC thing outside of an AutoUnprotectCell -// will cause an access violation. -class AutoUnprotectCell -{ -public: -#if defined(DEBUG) && !defined(XP_WIN) - JSRuntime *runtime; - gc::ArenaHeader *arena; - - AutoUnprotectCell(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~AutoUnprotectCell(); -#else - AutoUnprotectCell(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - ~AutoUnprotectCell() {} -#endif - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - -typedef AutoUnprotectCell AutoUnprotectCellUnderCompilationLock; -typedef AutoUnprotectCell AutoUnprotectCellForWrite; - -gc::AllocKind -gc::Cell::tenuredGetAllocKind() const -{ - AutoUnprotectCell unprotect(this); - return arenaHeader()->getAllocKind(); -} - } /* namespace js */ #endif /* gc_Heap_h */ diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index b32bd098e3bb..6602991c3bb7 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -152,7 +152,7 @@ class BaselineFrame Value &unaliasedVar(unsigned i, MaybeCheckAliasing checkAliasing = CHECK_ALIASING) const { JS_ASSERT_IF(checkAliasing, !script()->varIsAliased(i)); - JS_ASSERT(i < script()->getNfixed()); + JS_ASSERT(i < script()->nfixed); return *valueSlot(i); } @@ -183,7 +183,7 @@ class BaselineFrame offsetOfNumActualArgs()); } unsigned numFormalArgs() const { - return script()->function()->getNargs(); + return script()->function()->nargs; } Value &thisValue() const { return *(Value *)(reinterpret_cast(this) + diff --git a/js/src/jit/BaselineInspector.h b/js/src/jit/BaselineInspector.h index dfc506bd0584..e488d5217334 100644 --- a/js/src/jit/BaselineInspector.h +++ b/js/src/jit/BaselineInspector.h @@ -67,14 +67,14 @@ class BaselineInspector private: #ifdef DEBUG bool isValidPC(jsbytecode *pc) { - return (pc >= script->getCode()) && (pc < script->getCode() + script->getLength()); + return (pc >= script->code) && (pc < script->code + script->length); } #endif ICEntry &icEntryFromPC(jsbytecode *pc) { JS_ASSERT(hasBaselineScript()); JS_ASSERT(isValidPC(pc)); - ICEntry &ent = baselineScript()->icEntryFromPCOffset(pc - script->getCode(), prevLookedUpEntry); + ICEntry &ent = baselineScript()->icEntryFromPCOffset(pc - script->code, prevLookedUpEntry); JS_ASSERT(ent.isForOp()); prevLookedUpEntry = &ent; return ent; diff --git a/js/src/jit/BytecodeAnalysis.cpp b/js/src/jit/BytecodeAnalysis.cpp index f9724bc7d189..e2295c9fb639 100644 --- a/js/src/jit/BytecodeAnalysis.cpp +++ b/js/src/jit/BytecodeAnalysis.cpp @@ -42,10 +42,10 @@ struct CatchFinallyRange bool BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) { - if (!infos_.growByUninitialized(script_->getLength())) + if (!infos_.growByUninitialized(script_->length)) return false; - jsbytecode *end = script_->getCode() + script_->getLength(); + jsbytecode *end = script_->code + script_->length; // Clear all BytecodeInfo. mozilla::PodZero(infos_.begin(), infos_.length()); @@ -53,12 +53,12 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) Vector catchFinallyRanges(alloc); - for (jsbytecode *pc = script_->getCode(); pc < end; pc += GetBytecodeLength(pc)) { + for (jsbytecode *pc = script_->code; pc < end; pc += GetBytecodeLength(pc)) { JSOp op = JSOp(*pc); - unsigned offset = pc - script_->getCode(); + unsigned offset = pc - script_->code; IonSpew(IonSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s", - int(pc - script_->getCode()), int(end - script_->getCode()), js_CodeName[op]); + int(pc - script_->code), int(end - script_->code), js_CodeName[op]); // If this bytecode info has not yet been initialized, it's not reachable. if (!infos_[offset].initialized) @@ -68,7 +68,7 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) unsigned stackDepth = infos_[offset].stackDepth; #ifdef DEBUG for (jsbytecode *chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++) - JS_ASSERT(!infos_[chkpc - script_->getCode()].initialized); + JS_ASSERT(!infos_[chkpc - script_->code].initialized); #endif unsigned nuses = GetUseCount(script_, offset); @@ -108,7 +108,7 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) JSTryNote *tn = script_->trynotes()->vector; JSTryNote *tnlimit = tn + script_->trynotes()->length; for (; tn < tnlimit; tn++) { - unsigned startOffset = script_->getMainOffset() + tn->start; + unsigned startOffset = script_->mainOffset + tn->start; if (startOffset == offset + 1) { unsigned catchOffset = startOffset + tn->length; @@ -134,7 +134,7 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) while (!catchFinallyRanges.empty() && catchFinallyRanges.back().end <= offset) catchFinallyRanges.popBack(); - CatchFinallyRange range(endOfTry - script_->getCode(), afterTry - script_->getCode()); + CatchFinallyRange range(endOfTry - script_->code, afterTry - script_->code); if (!catchFinallyRanges.append(range)) return false; break; @@ -191,14 +191,14 @@ BytecodeAnalysis::init(TempAllocator &alloc, GSNCache &gsn) infos_[targetOffset].jumpTarget = true; if (jumpBack) - pc = script_->getCode() + targetOffset; + pc = script_->code + targetOffset; } // Handle any fallthrough from this opcode. if (BytecodeFallsThrough(op)) { jsbytecode *nextpc = pc + GetBytecodeLength(pc); JS_ASSERT(nextpc < end); - unsigned nextOffset = nextpc - script_->getCode(); + unsigned nextOffset = nextpc - script_->code; infos_[nextOffset].init(stackDepth); diff --git a/js/src/jit/BytecodeAnalysis.h b/js/src/jit/BytecodeAnalysis.h index 44c836551042..30b3663ac580 100644 --- a/js/src/jit/BytecodeAnalysis.h +++ b/js/src/jit/BytecodeAnalysis.h @@ -50,13 +50,13 @@ class BytecodeAnalysis bool init(TempAllocator &alloc, GSNCache &gsn); BytecodeInfo &info(jsbytecode *pc) { - JS_ASSERT(infos_[pc - script_->getCode()].initialized); - return infos_[pc - script_->getCode()]; + JS_ASSERT(infos_[pc - script_->code].initialized); + return infos_[pc - script_->code]; } BytecodeInfo *maybeInfo(jsbytecode *pc) { - if (infos_[pc - script_->getCode()].initialized) - return &infos_[pc - script_->getCode()]; + if (infos_[pc - script_->code].initialized) + return &infos_[pc - script_->code]; return nullptr; } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 7d3689111752..4d7c0ef37f6f 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -822,7 +822,7 @@ CodeGenerator::emitLambdaInit(const Register &output, const Register &scopeChain } s; uint32_t word; } u; - u.s.nargs = info.nargs; + u.s.nargs = info.fun->nargs; u.s.flags = info.flags & ~JSFunction::EXTENDED; JS_STATIC_ASSERT(offsetof(JSFunction, flags) == offsetof(JSFunction, nargs) + 2); @@ -2036,7 +2036,7 @@ CodeGenerator::visitCallKnown(LCallKnown *call) // Native single targets are handled by LCallNative. JS_ASSERT(!target->isNative()); // Missing arguments must have been explicitly appended by the IonBuilder. - JS_ASSERT(target->getNargs() <= call->numStackArgs()); + JS_ASSERT(target->nargs <= call->numStackArgs()); JS_ASSERT_IF(call->mir()->isConstructing(), target->isInterpretedConstructor()); @@ -2280,7 +2280,7 @@ CodeGenerator::visitApplyArgsGeneric(LApplyArgsGeneric *apply) masm.cmp32(argcreg, copyreg); masm.j(Assembler::Below, &underflow); } else { - masm.cmp32(argcreg, Imm32(apply->getSingleTarget()->getNargs())); + masm.cmp32(argcreg, Imm32(apply->getSingleTarget()->nargs)); masm.j(Assembler::Below, &underflow); } @@ -3249,7 +3249,6 @@ CodeGenerator::visitNewCallObject(LNewCallObject *lir) Register obj = ToRegister(lir->output()); JSObject *templateObj = lir->mir()->templateObject(); - AutoUnprotectCell unprotect(templateObj); // If we have a template object, we can inline call object creation. OutOfLineCode *ool; @@ -5744,7 +5743,7 @@ CodeGenerator::generate() { IonSpew(IonSpew_Codegen, "# Emitting code for script %s:%d", gen->info().script()->filename(), - gen->info().script()->getLineno()); + gen->info().script()->lineno); if (!safepoints_.init(gen->alloc(), graph.totalSlotCount())) return false; @@ -6550,7 +6549,7 @@ CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir) pushArg(ImmGCPtr(lir->mir()->name())); pushArg(ToValue(lir, LCallDeleteProperty::Value)); - if (lir->mir()->block()->info().script()->getStrict()) + if (lir->mir()->block()->info().script()->strict) return callVM(DeletePropertyStrictInfo, lir); return callVM(DeletePropertyNonStrictInfo, lir); @@ -6568,7 +6567,7 @@ CodeGenerator::visitCallDeleteElement(LCallDeleteElement *lir) pushArg(ToValue(lir, LCallDeleteElement::Index)); pushArg(ToValue(lir, LCallDeleteElement::Value)); - if (lir->mir()->block()->info().script()->getStrict()) + if (lir->mir()->block()->info().script()->strict) return callVM(DeleteElementStrictInfo, lir); return callVM(DeleteElementNonStrictInfo, lir); diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index 6bfd4ab20f5e..2c190a4dfb26 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -15,7 +15,7 @@ namespace js { namespace jit { inline unsigned -StartArgSlot(JSScript *script) +StartArgSlot(JSScript *script, JSFunction *fun) { // Reserved slots: // Slot 0: Scope chain. @@ -37,7 +37,7 @@ CountArgSlots(JSScript *script, JSFunction *fun) // Slot x + n: Argument n. // Note: when updating this, please also update the assert in SnapshotWriter::startFrame - return StartArgSlot(script) + (fun ? fun->getNargs() + 1 : 0); + return StartArgSlot(script, fun) + (fun ? fun->nargs + 1 : 0); } // Contains information about the compilation source for IR being generated. @@ -58,11 +58,11 @@ class CompileInfo JS_ASSERT(fun_->isTenured()); } - nimplicit_ = StartArgSlot(script) /* scope chain and argument obj */ + nimplicit_ = StartArgSlot(script, fun) /* scope chain and argument obj */ + (fun ? 1 : 0); /* this */ - nargs_ = fun ? fun->getNargs() : 0; - nlocals_ = script->getNfixed(); - nstack_ = script->getNslots() - script->getNfixed(); + nargs_ = fun ? fun->nargs : 0; + nlocals_ = script->nfixed; + nstack_ = script->nslots - script->nfixed; nslots_ = nimplicit_ + nargs_ + nlocals_ + nstack_; } @@ -96,10 +96,10 @@ class CompileInfo } jsbytecode *startPC() const { - return script_->getCode(); + return script_->code; } jsbytecode *limitPC() const { - return script_->getCode() + script_->getLength(); + return script_->code + script_->length; } const char *filename() const { @@ -209,7 +209,7 @@ class CompileInfo uint32_t startArgSlot() const { JS_ASSERT(script()); - return StartArgSlot(script()); + return StartArgSlot(script(), fun()); } uint32_t endArgSlot() const { JS_ASSERT(script()); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 27785ed53237..e337353c68fe 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -46,8 +46,6 @@ #include "jsinferinlines.h" #include "jsobjinlines.h" -using mozilla::Maybe; - using namespace js; using namespace js::jit; @@ -1277,7 +1275,7 @@ OptimizeMIR(MIRGenerator *mir) // repeated bailouts. Disable it if this script is known to bailout // frequently. JSScript *script = mir->info().script(); - if (!script || !script->getHadFrequentBailouts()) { + if (!script || !script->hadFrequentBailouts) { LICM licm(mir, graph); if (!licm.analyze()) return false; @@ -1554,9 +1552,9 @@ OffThreadCompilationAvailable(JSContext *cx) // CodeGenerator::maybeCreateScriptCounts will not attach script profiles // when running off thread. // - // Skip off thread compilation if the SPS profiler is enabled, as it stores - // strings in the spsProfiler data structure, which is not protected by a - // lock. + // Also skip off thread compilation if the SPS profiler is enabled, as it + // stores strings in the spsProfiler data structure, which is not protected + // by a lock. return OffThreadIonCompilationEnabled(cx->runtime()) && cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL && !cx->runtime()->profilingScripts @@ -1659,15 +1657,6 @@ IonCompile(JSContext *cx, JSScript *script, RootedScript builderScript(cx, builder->script()); IonSpewNewFunction(graph, builderScript); - Maybe protect; - if (js_IonOptions.checkThreadSafety && - cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL && - !cx->runtime()->profilingScripts && - !cx->runtime()->spsProfiler.enabled()) - { - protect.construct(cx->runtime()); - } - bool succeeded = builder->build(); builder->clearForBackEnd(); @@ -1703,9 +1692,6 @@ IonCompile(JSContext *cx, JSScript *script, return AbortReason_Disable; } - if (!protect.empty()) - protect.destroy(); - bool success = codegen->link(cx, builder->constraints()); IonSpewEndFunction(); diff --git a/js/src/jit/Ion.h b/js/src/jit/Ion.h index 987e911a894a..3ccb0a856ecf 100644 --- a/js/src/jit/Ion.h +++ b/js/src/jit/Ion.h @@ -83,12 +83,6 @@ struct IonOptions // Default: false bool checkRangeAnalysis; - // Whether to protect the GC heap during Ion compilation and ensure that - // only threadsafe operations are performed on it. - // - // Default: false - bool checkThreadSafety; - // Whether to perform expensive graph-consistency DEBUG-only assertions. // It can be useful to disable this to reduce DEBUG-compile time of large // asm.js programs. diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 1559a0a6cfa3..3f59b68a839a 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -65,8 +65,8 @@ IonBuilder::IonBuilder(JSContext *analysisContext, CompileCompartment *comp, Tem inspector(inspector), inliningDepth_(inliningDepth), numLoopRestarts_(0), - failedBoundsCheck_(info->script()->getFailedBoundsCheck()), - failedShapeGuard_(info->script()->getFailedShapeGuard()), + failedBoundsCheck_(info->script()->failedBoundsCheck), + failedShapeGuard_(info->script()->failedShapeGuard), nonStringIteration_(false), lazyArguments_(nullptr), inlineCallInfo_(nullptr) @@ -218,12 +218,12 @@ IonBuilder::getPolyCallTargets(types::TemporaryTypeSet *calleeTypes, bool constr } else { types::TypeObject *typeObj = calleeTypes->getTypeObject(i); JS_ASSERT(typeObj); - if (!typeObj->getInterpretedFunction()) { + if (!typeObj->interpretedFunction) { targets.clear(); return true; } - fun = typeObj->getInterpretedFunction(); + fun = typeObj->interpretedFunction; *gotLambda = true; } @@ -254,13 +254,16 @@ IonBuilder::canEnterInlinedFunction(JSFunction *target) JSScript *targetScript = target->nonLazyScript(); - if (targetScript->getUninlineable()) + if (targetScript->uninlineable) + return false; + + if (!targetScript->analyzedArgsUsage()) return false; if (targetScript->needsArgsObj()) return false; - if (!targetScript->getCompileAndGo()) + if (!targetScript->compileAndGo) return false; types::TypeObjectKey *targetType = types::TypeObjectKey::get(target); @@ -278,6 +281,11 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) return false; } + if (target->getParent() != &script()->global()) { + IonSpew(IonSpew_Inlining, "Cannot inline due to scope mismatch"); + return false; + } + // Allow constructing lazy scripts when performing the definite properties // analysis, as baseline has not been used to warm the caller up yet. if (target->isInterpreted() && info().executionMode() == DefinitePropertiesAnalysis) { @@ -303,28 +311,29 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) } JSScript *inlineScript = target->nonLazyScript(); - - IonSpew(IonSpew_Inlining, "Trying to inline %s:%d", inlineScript->filename(), inlineScript->getLineno()); - ExecutionMode executionMode = info().executionMode(); if (!CanIonCompile(inlineScript, executionMode)) { - IonSpew(IonSpew_Inlining, "Cannot inline due to disable Ion compilation"); + IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to disable Ion compilation", + inlineScript->filename(), inlineScript->lineno); return false; } // Don't inline functions which don't have baseline scripts. if (!inlineScript->hasBaselineScript()) { - IonSpew(IonSpew_Inlining, "Cannot inline target with no baseline jitcode"); + IonSpew(IonSpew_Inlining, "%s:%d Cannot inline target with no baseline jitcode", + inlineScript->filename(), inlineScript->lineno); return false; } - if (TooManyArguments(target->getNargs())) { - IonSpew(IonSpew_Inlining, "Cannot inline too many args"); + if (TooManyArguments(target->nargs)) { + IonSpew(IonSpew_Inlining, "%s:%d Cannot inline too many args", + inlineScript->filename(), inlineScript->lineno); return false; } if (TooManyArguments(callInfo.argc())) { - IonSpew(IonSpew_Inlining, "Cannot inline too many args"); + IonSpew(IonSpew_Inlining, "%s:%d Cannot inline too many args", + inlineScript->filename(), inlineScript->lineno); return false; } @@ -332,14 +341,17 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo) IonBuilder *builder = callerBuilder_; while (builder) { if (builder->script() == inlineScript) { - IonSpew(IonSpew_Inlining, "Not inlining recursive call"); + IonSpew(IonSpew_Inlining, "%s:%d Not inlining recursive call", + inlineScript->filename(), inlineScript->lineno); return false; } builder = builder->callerBuilder_; } if (!canEnterInlinedFunction(target)) { - IonSpew(IonSpew_Inlining, "Cannot inline due to oracle veto %d"); + IonSpew(IonSpew_Inlining, "%s:%d Cannot inline due to oracle veto %d", + inlineScript->filename(), inlineScript->lineno, + script()->lineno); return false; } @@ -553,8 +565,7 @@ IonBuilder::build() return false; IonSpew(IonSpew_Scripts, "Analyzing script %s:%d (%p) (usecount=%d)", - script()->filename(), script()->getLineno(), - (void *)script(), (int)script()->getUseCount()); + script()->filename(), script()->lineno, (void *)script(), (int)script()->getUseCount()); if (!initParameters()) return false; @@ -696,7 +707,7 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi inlineCallInfo_ = &callInfo; IonSpew(IonSpew_Scripts, "Inlining script %s:%d (%p)", - script()->filename(), script()->getLineno(), (void *)script()); + script()->filename(), script()->lineno, (void *)script()); callerBuilder_ = callerBuilder; callerResumePoint_ = callerResumePoint; @@ -894,7 +905,7 @@ IonBuilder::initScopeChain(MDefinition *callee) // will try to access the scope. For other scripts, the scope instructions // will be held live by resume points and code will still be generated for // them, so just use a constant undefined value. - if (!script()->getCompileAndGo()) + if (!script()->compileAndGo) return abort("non-CNG global scripts are not supported"); if (JSFunction *fun = info().fun()) { @@ -930,7 +941,8 @@ IonBuilder::initScopeChain(MDefinition *callee) bool IonBuilder::initArgumentsObject() { - IonSpew(IonSpew_MIR, "Emitting code to initialize arguments object! block=%p", current); + IonSpew(IonSpew_MIR, "%s:%d - Emitting code to initialize arguments object! block=%p", + script()->filename(), script()->lineno, current); JS_ASSERT(info().needsArgsObj()); MCreateArgumentsObject *argsObj = MCreateArgumentsObject::New(alloc(), current->scopeChain()); current->add(argsObj); @@ -1175,7 +1187,7 @@ IonBuilder::traverseBytecode() // adding any SSA uses and doesn't call setFoldedUnchecked on it. Vector popped(alloc()); Vector poppedUses(alloc()); - unsigned nuses = GetUseCount(script_, pc - script_->getCode()); + unsigned nuses = GetUseCount(script_, pc - script_->code); for (unsigned i = 0; i < nuses; i++) { MDefinition *def = current->peek(-int32_t(i + 1)); @@ -1660,7 +1672,7 @@ IonBuilder::inspectOpcode(JSOp op) return jsop_in(); case JSOP_SETRVAL: - JS_ASSERT(!script()->getNoScriptRval()); + JS_ASSERT(!script()->noScriptRval); current->setSlot(info().returnValueSlot(), current->pop()); return true; @@ -3461,7 +3473,7 @@ IonBuilder::processReturn(JSOp op) case JSOP_RETRVAL: // Return undefined eagerly if script doesn't use return value. - if (script()->getNoScriptRval()) { + if (script()->noScriptRval) { MInstruction *ins = MConstant::New(alloc(), UndefinedValue()); current->add(ins); def = ins; @@ -3774,21 +3786,17 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) JSScript *calleeScript = target->nonLazyScript(); BaselineInspector inspector(calleeScript); + // Improve type information of |this| when not set. + if (callInfo.constructing() && + !callInfo.thisArg()->resultTypeSet() && + calleeScript->types) { - AutoUnprotectCellUnderCompilationLock unprotect(calleeScript); - - // Improve type information of |this| when not set. - if (callInfo.constructing() && - !callInfo.thisArg()->resultTypeSet() && - calleeScript->types) - { - types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript); - if (!types->unknown()) { - MTypeBarrier *barrier = - MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc().lifoAlloc())); - current->add(barrier); - callInfo.setThis(barrier); - } + types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript); + if (!types->unknown()) { + MTypeBarrier *barrier = + MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc())); + current->add(barrier); + callInfo.setThis(barrier); } } @@ -3818,7 +3826,6 @@ IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target) // Inlining the callee failed. Mark the callee as uninlineable only if // the inlining was aborted for a non-exception reason. if (inlineBuilder.abortReason_ == AbortReason_Disable) { - AutoUnprotectCellForWrite unprotect(calleeScript); calleeScript->uninlineable = true; abortReason_ = AbortReason_Inlining; } else if (inlineBuilder.abortReason_ == AbortReason_Inlining) { @@ -3924,7 +3931,7 @@ IonBuilder::patchInlinedReturns(CallInfo &callInfo, MIRGraphExits &exits, MBasic static bool IsSmallFunction(JSScript *script) { - return script->getLength() <= js_IonOptions.smallFunctionMaxBytecodeLength; + return script->length <= js_IonOptions.smallFunctionMaxBytecodeLength; } bool @@ -3949,33 +3956,34 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) // Heuristics! JSScript *targetScript = target->nonLazyScript(); - IonSpew(IonSpew_Inlining, "Deciding whether to inline %s:%d", - targetScript->filename(), targetScript->getLineno()); - // Skip heuristics if we have an explicit hint to inline. - if (!targetScript->getShouldInline()) { + if (!targetScript->shouldInline) { // Cap the inlining depth. if (IsSmallFunction(targetScript)) { if (inliningDepth_ >= js_IonOptions.smallFunctionMaxInlineDepth) { - IonSpew(IonSpew_Inlining, "Vetoed: exceeding allowed inline depth"); + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding allowed inline depth", + targetScript->filename(), targetScript->lineno); return false; } } else { if (inliningDepth_ >= js_IonOptions.maxInlineDepth) { - IonSpew(IonSpew_Inlining, "Vetoed: exceeding allowed inline depth"); + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: exceeding allowed inline depth", + targetScript->filename(), targetScript->lineno); return false; } if (targetScript->hasLoops()) { - IonSpew(IonSpew_Inlining, "Vetoed: big function that contains a loop"); + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: big function that contains a loop", + targetScript->filename(), targetScript->lineno); return false; } } // Callee must not be excessively large. // This heuristic also applies to the callsite as a whole. - if (targetScript->getLength() > js_IonOptions.inlineMaxTotalBytecodeLength) { - IonSpew(IonSpew_Inlining, "Vetoed: callee excessively large"); + if (targetScript->length > js_IonOptions.inlineMaxTotalBytecodeLength) { + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: callee excessively large.", + targetScript->filename(), targetScript->lineno); return false; } @@ -3985,7 +3993,8 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) if (callerUses < js_IonOptions.usesBeforeInlining() && info().executionMode() != DefinitePropertiesAnalysis) { - IonSpew(IonSpew_Inlining, "Vetoed: caller is insufficiently hot"); + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: caller is insufficiently hot.", + targetScript->filename(), targetScript->lineno); return false; } @@ -3993,7 +4002,8 @@ IonBuilder::makeInliningDecision(JSFunction *target, CallInfo &callInfo) if (targetScript->getUseCount() * js_IonOptions.inlineUseCountRatio < callerUses && info().executionMode() != DefinitePropertiesAnalysis) { - IonSpew(IonSpew_Inlining, "Vetoed: callee is not hot"); + IonSpew(IonSpew_Inlining, "%s:%d - Vetoed: callee is not hot.", + targetScript->filename(), targetScript->lineno); return false; } } @@ -4020,7 +4030,7 @@ IonBuilder::selectInliningTargets(ObjectVector &targets, CallInfo &callInfo, Boo // Enforce a maximum inlined bytecode limit at the callsite. if (inlineable && target->isInterpreted()) { - totalSize += target->nonLazyScript()->getLength(); + totalSize += target->nonLazyScript()->length; if (totalSize > js_IonOptions.inlineMaxTotalBytecodeLength) inlineable = false; } @@ -4521,7 +4531,6 @@ IonBuilder::createDeclEnvObject(MDefinition *callee, MDefinition *scope) // Get a template CallObject that we'll use to generate inline object // creation. DeclEnvObject *templateObj = inspector->templateDeclEnvObject(); - AutoUnprotectCell unprotect(templateObj); // One field is added to the function to handle its name. This cannot be a // dynamic slot because there is still plenty of room on the DeclEnv object. @@ -4549,14 +4558,12 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) // Get a template CallObject that we'll use to generate inline object // creation. CallObject *templateObj = inspector->templateCallObject(); - AutoUnprotectCell unprotect(templateObj); // If the CallObject needs dynamic slots, allocate those now. MInstruction *slots; if (templateObj->hasDynamicSlots()) { - AutoUnprotectCell unprotect(templateObj); - size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlotsForCompilation(), - templateObj->lastProperty()->slotSpan(templateObj->getClass())); + size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(), + templateObj->slotSpan()); slots = MNewSlots::New(alloc(), nslots); } else { slots = MConstant::New(alloc(), NullValue()); @@ -4567,7 +4574,7 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) // instructions could potentially bailout, thus leaking the dynamic slots // pointer. Run-once scripts need a singleton type, so always do a VM call // in such cases. - MInstruction *callObj = MNewCallObject::New(alloc(), templateObj, script()->getTreatAsRunOnce(), slots); + MInstruction *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce, slots); current->add(callObj); // Insert a post barrier to protect the following writes if we allocated @@ -4585,8 +4592,8 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope) unsigned slot = i.scopeSlot(); unsigned formal = i.frameIndex(); MDefinition *param = current->getSlot(info().argSlotUnchecked(formal)); - if (slot >= templateObj->numFixedSlotsForCompilation()) - current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlotsForCompilation(), param)); + if (slot >= templateObj->numFixedSlots()) + current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param)); else current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param)); } @@ -4651,20 +4658,17 @@ IonBuilder::createThisScriptedSingleton(JSFunction *target, MDefinition *callee) if (!proto) return nullptr; + if (!target->nonLazyScript()->types) + return nullptr; + JSObject *templateObject = inspector->getTemplateObject(pc); if (!templateObject || !templateObject->is()) return nullptr; if (templateObject->getProto() != proto) return nullptr; - { - AutoUnprotectCellUnderCompilationLock unprotect(target->nonLazyScript()); - if (!target->nonLazyScript()->types) - return nullptr; - - if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject))) - return nullptr; - } + if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject))) + return nullptr; // For template objects with NewScript info, the appropriate allocation // kind to use may change due to dynamic property adds. In these cases @@ -4962,7 +4966,7 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing) ObjectVector targets(alloc()); for (uint32_t i = 0; i < originals.length(); i++) { JSFunction *fun = &originals[i]->as(); - if (fun->hasScript() && fun->nonLazyScript()->getShouldCloneAtCallsite()) { + if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite) { if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment->callsiteClones(), fun, script(), pc)) { fun = clone; hasClones = true; @@ -5097,20 +5101,17 @@ IonBuilder::testNeedsArgumentCheck(JSFunction *target, CallInfo &callInfo) return true; JSScript *targetScript = target->nonLazyScript(); - - AutoUnprotectCellUnderCompilationLock lock(targetScript); - if (!targetScript->types) return true; if (!ArgumentTypesMatch(callInfo.thisArg(), types::TypeScript::ThisTypes(targetScript))) return true; - uint32_t expected_args = Min(callInfo.argc(), target->getNargs()); + uint32_t expected_args = Min(callInfo.argc(), target->nargs); for (size_t i = 0; i < expected_args; i++) { if (!ArgumentTypesMatch(callInfo.getArg(i), types::TypeScript::ArgTypes(targetScript, i))) return true; } - for (size_t i = callInfo.argc(); i < target->getNargs(); i++) { + for (size_t i = callInfo.argc(); i < target->nargs; i++) { if (!types::TypeScript::ArgTypes(targetScript, i)->mightBeType(JSVAL_TYPE_UNDEFINED)) return true; } @@ -5131,7 +5132,7 @@ IonBuilder::makeCallHelper(JSFunction *target, CallInfo &callInfo, bool cloneAtC // Collect number of missing arguments provided that the target is // scripted. Native functions are passed an explicit 'argc' parameter. if (target && !target->isNative()) - targetArgs = Max(target->getNargs(), callInfo.argc()); + targetArgs = Max(target->nargs, callInfo.argc()); MCall *call = MCall::New(alloc(), target, targetArgs + 1, callInfo.argc(), callInfo.constructing()); @@ -5317,10 +5318,9 @@ IonBuilder::jsop_eval(uint32_t argc) string->getOperand(1)->isConstant() && string->getOperand(1)->toConstant()->value().isString()) { - JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom(); - AutoUnprotectCell unprotect(atom); + JSString *str = string->getOperand(1)->toConstant()->value().toString(); - if (StringEqualsAscii(atom, "()")) { + if (str->isLinear() && StringEqualsAscii(&str->asLinear(), "()")) { MDefinition *name = string->getOperand(0); MInstruction *dynamicName = MGetDynamicName::New(alloc(), scopeChain, name); current->add(dynamicName); @@ -5373,7 +5373,7 @@ IonBuilder::jsop_compare(JSOp op) bool IonBuilder::jsop_newarray(uint32_t count) { - JS_ASSERT(script()->getCompileAndGo()); + JS_ASSERT(script()->compileAndGo); JSObject *templateObject = inspector->getTemplateObject(pc); if (!templateObject) @@ -5403,7 +5403,7 @@ bool IonBuilder::jsop_newobject() { // Don't bake in the TypeObject for non-CNG scripts. - JS_ASSERT(script()->getCompileAndGo()); + JS_ASSERT(script()->compileAndGo); JSObject *templateObject = inspector->getTemplateObject(pc); if (!templateObject) @@ -5470,10 +5470,7 @@ IonBuilder::jsop_initelem_array() MElements *elements = MElements::New(alloc(), obj); current->add(elements); - JSObject *templateObject = obj->toNewArray()->templateObject(); - AutoUnprotectCell unprotect(templateObject); - - if (templateObject->shouldConvertDoubleElementsForCompilation()) { + if (obj->toNewArray()->templateObject()->shouldConvertDoubleElements()) { MInstruction *valueDouble = MToDouble::New(alloc(), value); current->add(valueDouble); value = valueDouble; @@ -5500,11 +5497,8 @@ IonBuilder::jsop_initprop(PropertyName *name) MDefinition *obj = current->peek(-1); JSObject *templateObject = obj->toNewObject()->templateObject(); - Shape *shape; - { - AutoUnprotectCell unprotect(templateObject); - shape = templateObject->lastProperty()->searchLinear(NameToId(name)); - } + + Shape *shape = templateObject->nativeLookupPure(name); if (!shape) { // JSOP_NEWINIT becomes an MNewObject without preconfigured properties. @@ -5676,7 +5670,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry) // Initialize |return value| { MInstruction *returnValue; - if (!script()->getNoScriptRval()) + if (!script()->noScriptRval) returnValue = MOsrReturnValue::New(alloc(), entry); else returnValue = MConstant::New(alloc(), UndefinedValue()); @@ -5844,14 +5838,10 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool if (info().fun() && i == info().thisSlot()) { existingValue = baselineFrame_->thisValue(); } else if (arg < info().nargs()) { - if (info().needsArgsObj()) { - // Note: baseline frame contents need to be copied into temporary space - // when triggering an OSR off thread compilation. - AutoUnprotectCell unprotect(&baselineFrame_->argsObj()); + if (info().needsArgsObj()) existingValue = baselineFrame_->argsObj().arg(arg); - } else { + else existingValue = baselineFrame_->unaliasedFormal(arg); - } } else { existingValue = baselineFrame_->unaliasedVar(var); } @@ -6316,6 +6306,9 @@ IonBuilder::setStaticName(JSObject *staticObject, PropertyName *name) MDefinition *value = current->peek(-1); + if (staticObject->watched()) + return jsop_setprop(name); + types::TypeObjectKey *staticType = types::TypeObjectKey::get(staticObject); if (staticType->unknownProperties()) return jsop_setprop(name); @@ -6716,7 +6709,7 @@ IonBuilder::getElemTryTypedStatic(bool *emitted, MDefinition *obj, MDefinition * return true; TypedArrayObject *tarr = &tarrObj->as(); - ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type(); + ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(tarr); // LoadTypedArrayElementStatic currently treats uint32 arrays as int32. if (viewType == ArrayBufferView::TYPE_UINT32) @@ -7273,7 +7266,7 @@ IonBuilder::setElemTryTypedStatic(bool *emitted, MDefinition *object, return true; TypedArrayObject *tarr = &tarrObj->as(); - ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type(); + ArrayBufferView::ViewType viewType = JS_GetArrayBufferViewType(tarr); MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType); if (!ptr) @@ -7406,7 +7399,7 @@ IonBuilder::setElemTryCache(bool *emitted, MDefinition *object, current->add(MPostWriteBarrier::New(alloc(), object, value)); // Emit SetElementCache. - MInstruction *ins = MSetElementCache::New(alloc(), object, index, value, script()->getStrict(), guardHoles); + MInstruction *ins = MSetElementCache::New(alloc(), object, index, value, script()->strict, guardHoles); current->add(ins); current->push(value); @@ -7977,7 +7970,7 @@ IonBuilder::invalidatedIdempotentCache() { IonBuilder *builder = this; do { - if (builder->script()->getInvalidatedIdempotentCache()) + if (builder->script()->invalidatedIdempotentCache) return true; builder = builder->callerBuilder_; } while (builder); @@ -8013,6 +8006,9 @@ bool IonBuilder::loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType, bool barrier, types::TemporaryTypeSet *types) { + JS_ASSERT(shape->hasDefaultGetter()); + JS_ASSERT(shape->hasSlot()); + return loadSlot(obj, shape->slot(), shape->numFixedSlots(), rvalType, barrier, types); } @@ -8047,7 +8043,10 @@ bool IonBuilder::storeSlot(MDefinition *obj, Shape *shape, MDefinition *value, bool needsBarrier, MIRType slotType /* = MIRType_None */) { + JS_ASSERT(shape->hasDefaultSetter()); JS_ASSERT(shape->writable()); + JS_ASSERT(shape->hasSlot()); + return storeSlot(obj, shape->slot(), shape->numFixedSlots(), value, needsBarrier, slotType); } @@ -8555,7 +8554,7 @@ IonBuilder::jsop_setprop(PropertyName *name) // Always use a call if we are doing the definite properties analysis and // not actually emitting code, to simplify later analysis. if (info().executionMode() == DefinitePropertiesAnalysis) { - MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->getStrict()); + MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->strict); current->add(ins); current->push(value); return resumeAfter(ins); @@ -8590,7 +8589,7 @@ IonBuilder::jsop_setprop(PropertyName *name) return emitted; // Emit call. - MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->getStrict()); + MInstruction *ins = MCallSetProperty::New(alloc(), obj, value, name, script()->strict); current->add(ins); current->push(value); return resumeAfter(ins); @@ -8864,7 +8863,7 @@ IonBuilder::setPropTryCache(bool *emitted, MDefinition *obj, JS_ASSERT(*emitted == false); // Emit SetPropertyCache. - MSetPropertyCache *ins = MSetPropertyCache::New(alloc(), obj, value, name, script()->getStrict(), barrier); + MSetPropertyCache *ins = MSetPropertyCache::New(alloc(), obj, value, name, script()->strict, barrier); if (!objTypes || objTypes->propertyNeedsBarrier(constraints(), NameToId(name))) ins->setNeedsBarrier(); @@ -8908,6 +8907,11 @@ IonBuilder::jsop_delelem() bool IonBuilder::jsop_regexp(RegExpObject *reobj) { + JSObject *prototype = reobj->getProto(); + JS_ASSERT(prototype == script()->global().maybeGetRegExpPrototype()); + + JS_ASSERT(&reobj->JSObject::global() == &script()->global()); + // JS semantics require regular expression literals to create different // objects every time they execute. We only need to do this cloning if the // script could actually observe the effect of such cloning, for instance @@ -8917,9 +8921,6 @@ IonBuilder::jsop_regexp(RegExpObject *reobj) // then check if this regex object only flows into known natives and can // avoid cloning in this case. - // RegExpObjects embedded in scripts are immutable. - AutoUnprotectCell unprotect(reobj); - bool mustClone = true; types::TypeObjectKey *typeObj = types::TypeObjectKey::get(&script()->global()); if (!typeObj->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) { @@ -8933,8 +8934,6 @@ IonBuilder::jsop_regexp(RegExpObject *reobj) mustClone = false; } - JSObject *prototype = reobj->getProto(); - MRegExp *regexp = MRegExp::New(alloc(), reobj, prototype, mustClone); current->add(regexp); current->push(regexp); @@ -9094,7 +9093,7 @@ IonBuilder::jsop_this() if (!info().fun()) return abort("JSOP_THIS outside of a JSFunction."); - if (script()->getStrict() || info().fun()->isSelfHostedBuiltin()) { + if (script()->strict || info().fun()->isSelfHostedBuiltin()) { // No need to wrap primitive |this| in strict mode or self-hosted code. current->pushSlot(info().thisSlot()); return true; @@ -9247,7 +9246,7 @@ bool IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall) { JSScript *outerScript = ScopeCoordinateFunctionScript(script(), pc); - if (!outerScript || !outerScript->getTreatAsRunOnce()) + if (!outerScript || !outerScript->treatAsRunOnce) return false; types::TypeObjectKey *funType = types::TypeObjectKey::get(outerScript->function()); diff --git a/js/src/jit/IonCode.h b/js/src/jit/IonCode.h index 05a17154a2df..314cda55f2ae 100644 --- a/js/src/jit/IonCode.h +++ b/js/src/jit/IonCode.h @@ -88,7 +88,6 @@ class IonCode : public gc::BarrieredCell public: uint8_t *raw() const { - AutoUnprotectCell unprotect(this); return code_; } size_t instructionsSize() const { diff --git a/js/src/jit/IonMacroAssembler.cpp b/js/src/jit/IonMacroAssembler.cpp index 4c43af12fb98..8f2985905891 100644 --- a/js/src/jit/IonMacroAssembler.cpp +++ b/js/src/jit/IonMacroAssembler.cpp @@ -685,6 +685,7 @@ MacroAssembler::newGCThing(const Register &result, JSObject *templateObject, Lab { gc::AllocKind allocKind = templateObject->tenuredGetAllocKind(); JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); + JS_ASSERT(!templateObject->hasDynamicElements()); gc::InitialHeap initialHeap = templateObject->type()->initialHeapForJITAlloc(); newGCThing(result, allocKind, fail, initialHeap); @@ -757,6 +758,7 @@ MacroAssembler::newGCThingPar(const Register &result, const Register &slice, { gc::AllocKind allocKind = templateObject->tenuredGetAllocKind(); JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); + JS_ASSERT(!templateObject->hasDynamicElements()); newGCThingPar(result, slice, tempReg1, tempReg2, allocKind, fail); } @@ -782,17 +784,12 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) { // Fast initialization of an empty object returned by NewGCThing(). - // Template objects provided to the code generator should not be modified by the main thread. - AutoUnprotectCell unprotect(templateObject); - - JS_ASSERT(!templateObject->hasDynamicElements()); - storePtr(ImmGCPtr(templateObject->lastProperty()), Address(obj, JSObject::offsetOfShape())); storePtr(ImmGCPtr(templateObject->type()), Address(obj, JSObject::offsetOfType())); storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots())); if (templateObject->is()) { - JS_ASSERT(!templateObject->getDenseInitializedLengthForCompilation()); + JS_ASSERT(!templateObject->getDenseInitializedLength()); int elementsOffset = JSObject::offsetOfFixedElements(); @@ -801,13 +798,13 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) addPtr(Imm32(-elementsOffset), obj); // Fill in the elements header. - store32(Imm32(templateObject->getDenseCapacityForCompilation()), + store32(Imm32(templateObject->getDenseCapacity()), Address(obj, elementsOffset + ObjectElements::offsetOfCapacity())); - store32(Imm32(templateObject->getDenseInitializedLengthForCompilation()), + store32(Imm32(templateObject->getDenseInitializedLength()), Address(obj, elementsOffset + ObjectElements::offsetOfInitializedLength())); store32(Imm32(templateObject->as().length()), Address(obj, elementsOffset + ObjectElements::offsetOfLength())); - store32(Imm32(templateObject->shouldConvertDoubleElementsForCompilation() + store32(Imm32(templateObject->shouldConvertDoubleElements() ? ObjectElements::CONVERT_DOUBLE_ELEMENTS : 0), Address(obj, elementsOffset + ObjectElements::offsetOfFlags())); @@ -816,8 +813,7 @@ MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject) // Fixed slots of non-array objects are required to be initialized. // Use the values currently in the template object. - size_t nslots = Min(templateObject->numFixedSlotsForCompilation(), - templateObject->lastProperty()->slotSpan(templateObject->getClassImmutable())); + size_t nslots = Min(templateObject->numFixedSlots(), templateObject->slotSpan()); for (unsigned i = 0; i < nslots; i++) { storeValue(templateObject->getFixedSlot(i), Address(obj, JSObject::getFixedSlotOffset(i))); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 3bb5bded4bff..8e304d9b571a 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -248,10 +248,8 @@ IonBuilder::inlineArray(CallInfo &callInfo) types::TemporaryTypeSet::DoubleConversion conversion = getInlineReturnTypeSet()->convertDoubleElements(constraints()); - if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) { - AutoUnprotectCell unprotect(templateObject); + if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles) templateObject->setShouldConvertDoubleElements(); - } MNewArray *ins = MNewArray::New(alloc(), initLength, templateObject, allocating); current->add(ins); @@ -459,8 +457,11 @@ IonBuilder::inlineArrayConcat(CallInfo &callInfo) if (!baseThisType) return InliningStatus_NotInlined; types::TypeObjectKey *thisType = types::TypeObjectKey::get(baseThisType); - if (thisType->unknownProperties()) + if (thisType->unknownProperties() || + &thisType->proto().toObject()->global() != &script()->global()) + { return InliningStatus_NotInlined; + } // Don't inline if 'this' is packed and the argument may not be packed // (the result array will reuse the 'this' type). @@ -1264,7 +1265,7 @@ IonBuilder::inlineNewParallelArray(CallInfo &callInfo) JSFunction *target = nullptr; if (targetObj && targetObj->is()) target = &targetObj->as(); - if (target && target->isInterpreted() && target->nonLazyScript()->getShouldCloneAtCallsite()) { + if (target && target->isInterpreted() && target->nonLazyScript()->shouldCloneAtCallsite) { if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment->callsiteClones(), target, script(), pc)) target = clone; } @@ -1289,7 +1290,7 @@ IonBuilder::inlineParallelArray(CallInfo &callInfo) if (!target) return InliningStatus_NotInlined; - JS_ASSERT(target->nonLazyScript()->getShouldCloneAtCallsite()); + JS_ASSERT(target->nonLazyScript()->shouldCloneAtCallsite); if (JSFunction *clone = ExistingCloneFunctionAtCallsite(compartment->callsiteClones(), target, script(), pc)) target = clone; @@ -1323,7 +1324,7 @@ IonBuilder::inlineParallelArrayTail(CallInfo &callInfo, if (returnTypes->unknownObject() || returnTypes->getObjectCount() != 1) return InliningStatus_NotInlined; types::TypeObject *typeObject = returnTypes->getTypeObject(0); - if (!typeObject || typeObject->getClass() != &ParallelArrayObject::class_) + if (!typeObject || typeObject->clasp != &ParallelArrayObject::class_) return InliningStatus_NotInlined; JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native); @@ -1333,7 +1334,7 @@ IonBuilder::inlineParallelArrayTail(CallInfo &callInfo, // Create the call and add in the non-this arguments. uint32_t targetArgs = argc; if (target && !target->isNative()) - targetArgs = Max(target->getNargs(), argc); + targetArgs = Max(target->nargs, argc); MCall *call = MCall::New(alloc(), target, targetArgs + 1, argc, false); if (!call) diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index b8f21a9a9035..5b34080061ff 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -661,7 +661,6 @@ MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers) { if ((type() == MIRType_Int32) && (string()->isConstant())) { Value value = string()->toConstant()->value(); - AutoUnprotectCell unprotect(&value.toString()->asAtom()); size_t length = JS_GetStringLength(value.toString()); return MConstant::New(alloc, Int32Value(length)); @@ -2320,8 +2319,10 @@ MCompare::evaluateConstantOperands(bool *result) // Fold away some String equality comparisons. if (lhs.isString() && rhs.isString()) { int32_t comp = 0; // Default to equal. - if (left != right) - comp = CompareAtoms(&lhs.toString()->asAtom(), &rhs.toString()->asAtom()); + if (left != right) { + if (!CompareStrings(GetIonContext()->cx, lhs.toString(), rhs.toString(), &comp)) + return false; + } switch (jsop_) { case JSOP_LT: @@ -2502,7 +2503,6 @@ MBeta::printOpcode(FILE *fp) const bool MNewObject::shouldUseVM() const { - AutoUnprotectCell unprotect(templateObject()); return templateObject()->hasSingletonType() || templateObject()->hasDynamicSlots(); } @@ -2928,7 +2928,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx, JSObject *obj = object->singleton() ? object->singleton() : object->proto().toObjectOrNull(); while (obj) { - if (!obj->getClass()->isNative()) + if (!obj->isNative()) break; types::TypeObjectKey *typeObj = types::TypeObjectKey::get(obj); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index b920a845d4a1..849a65716207 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -966,18 +966,8 @@ class MConstant : public MNullaryInstruction return &value_; } const bool valueToBoolean() const { - if (value_.isString()) { - AutoUnprotectCell unprotect(&value_.toString()->asAtom()); - return ToBoolean(value_); - } - if (value_.isObject()) { - // Note: ToBoolean can't be called off thread as it will try to - // unwrap wrappers. IsWrapper goes through public API methods which - // don't unprotect the right pointers. Since wrappers don't have - // singleton type just ignore this case. - return !value_.toObject().getClass()->emulatesUndefined(); - } - return ToBoolean(value_); + // A hack to avoid this wordy pattern everywhere in the JIT. + return ToBoolean(HandleValue::fromMarkedLocation(&value_)); } void printOpcode(FILE *fp) const; @@ -4826,14 +4816,13 @@ struct LambdaFunctionInfo // the script, and are immutable except for delazification. Record this // information while still on the main thread to avoid races. CompilerRootFunction fun; - uint16_t nargs; uint16_t flags; gc::Cell *scriptOrLazyScript; bool singletonType; bool useNewTypeForClone; LambdaFunctionInfo(JSFunction *fun) - : fun(fun), nargs(fun->getNargs()), flags(fun->getFlags()), + : fun(fun), flags(fun->flags), scriptOrLazyScript(fun->hasScript() ? (gc::Cell *) fun->nonLazyScript() : (gc::Cell *) fun->lazyScript()), @@ -4842,7 +4831,7 @@ struct LambdaFunctionInfo {} LambdaFunctionInfo(const LambdaFunctionInfo &info) - : fun((JSFunction *) info.fun), nargs(info.nargs), flags(info.flags), + : fun((JSFunction *) info.fun), flags(info.flags), scriptOrLazyScript(info.scriptOrLazyScript), singletonType(info.singletonType), useNewTypeForClone(info.useNewTypeForClone) @@ -5970,9 +5959,7 @@ class MLoadTypedArrayElementStatic return new(alloc) MLoadTypedArrayElementStatic(typedArray, ptr); } - ArrayBufferView::ViewType viewType() const { - return (ArrayBufferView::ViewType) typedArray_->type(); - } + ArrayBufferView::ViewType viewType() const { return JS_GetArrayBufferViewType(typedArray_); } void *base() const; size_t length() const; @@ -6154,9 +6141,7 @@ class MStoreTypedArrayElementStatic : return this; } - ArrayBufferView::ViewType viewType() const { - return (ArrayBufferView::ViewType) typedArray_->type(); - } + ArrayBufferView::ViewType viewType() const { return JS_GetArrayBufferViewType(typedArray_); } bool isFloatArray() const { return (viewType() == ArrayBufferView::TYPE_FLOAT32 || viewType() == ArrayBufferView::TYPE_FLOAT64); diff --git a/js/src/jit/MIRGraph.h b/js/src/jit/MIRGraph.h index 420099eadee0..66fc665c8d1a 100644 --- a/js/src/jit/MIRGraph.h +++ b/js/src/jit/MIRGraph.h @@ -468,7 +468,7 @@ class MBasicBlock : public TempObject, public InlineListNode } bool strict() const { - return info_.script()->getStrict(); + return info_.script()->strict; } void dumpStack(FILE *fp); diff --git a/js/src/jit/ParallelFunctions.cpp b/js/src/jit/ParallelFunctions.cpp index ef16a54b5c04..aaa83df02ea9 100644 --- a/js/src/jit/ParallelFunctions.cpp +++ b/js/src/jit/ParallelFunctions.cpp @@ -258,9 +258,9 @@ CompareStringsPar(ForkJoinSlice *slice, JSString *left, JSString *right, int32_t if (!leftInspector.ensureChars(slice) || !rightInspector.ensureChars(slice)) return false; - *res = CompareChars(leftInspector.chars(), left->length(), - rightInspector.chars(), right->length()); - return true; + return CompareChars(leftInspector.chars(), left->length(), + rightInspector.chars(), right->length(), + res); } static bool diff --git a/js/src/jit/Snapshots.cpp b/js/src/jit/Snapshots.cpp index 917d38779c9e..1b30728c618f 100644 --- a/js/src/jit/Snapshots.cpp +++ b/js/src/jit/Snapshots.cpp @@ -306,18 +306,18 @@ SnapshotWriter::startFrame(JSFunction *fun, JSScript *script, jsbytecode *pc, ui // +4 to account for scope chain, return value, this value and maybe arguments_object. JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS + 4); - uint32_t implicit = StartArgSlot(script); + uint32_t implicit = StartArgSlot(script, fun); uint32_t formalArgs = CountArgSlots(script, fun); - nslots_ = formalArgs + script->getNfixed() + exprStack; + nslots_ = formalArgs + script->nfixed + exprStack; slotsWritten_ = 0; IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u", - implicit, formalArgs - implicit, script->getNfixed(), exprStack); + implicit, formalArgs - implicit, script->nfixed, exprStack); - JS_ASSERT(script->getCode() <= pc && pc <= script->getCode() + script->getLength()); + JS_ASSERT(script->code <= pc && pc <= script->code + script->length); - uint32_t pcoff = uint32_t(pc - script->getCode()); + uint32_t pcoff = uint32_t(pc - script->code); IonSpew(IonSpew_Snapshots, "Writing pc offset %u, nslots %u", pcoff, nslots_); writer_.writeUnsigned(pcoff); writer_.writeUnsigned(nslots_); diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index a591ba282c34..19bcca9ab128 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -279,7 +279,6 @@ CodeGeneratorShared::encode(LSnapshot *snapshot) #ifdef DEBUG if (GetIonContext()->cx) { - AutoUnprotectCell unprotect(script); uint32_t stackDepth; if (ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth)) { if (JSOp(*bailPC) == JSOP_FUNCALL) { diff --git a/js/src/jsanalyze.h b/js/src/jsanalyze.h index 30a43b0e4a58..bc6e6efa2c28 100644 --- a/js/src/jsanalyze.h +++ b/js/src/jsanalyze.h @@ -225,7 +225,7 @@ static inline uint32_t ArgSlot(uint32_t arg) { return 1 + arg; } static inline uint32_t LocalSlot(JSScript *script, uint32_t local) { - return 1 + (script->function() ? script->function()->getNargs() : 0) + local; + return 1 + (script->function() ? script->function()->nargs : 0) + local; } static inline uint32_t TotalSlots(JSScript *script) { return LocalSlot(script, 0) + script->nfixed; diff --git a/js/src/jsapi-tests/testConservativeGC.cpp b/js/src/jsapi-tests/testConservativeGC.cpp index 16c4456804f4..be33d5dd6cdb 100644 --- a/js/src/jsapi-tests/testConservativeGC.cpp +++ b/js/src/jsapi-tests/testConservativeGC.cpp @@ -60,6 +60,7 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj) { /* Ignore fields which are unstable across GCs. */ CHECK(savedCopy->lastProperty() == obj->lastProperty()); + CHECK(savedCopy->getProto() == obj->getProto()); return true; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index c3b80ec03da7..bee0b4f9abc3 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1056,7 +1056,7 @@ ToNumberSlow(JSContext *cx, JS::Value v, double *dp); * DO NOT CALL THIS. Use JS::ToBoolean */ extern JS_PUBLIC_API(bool) -ToBooleanSlow(const JS::Value &v); +ToBooleanSlow(JS::HandleValue v); /* * DO NOT CALL THIS. Use JS::ToString @@ -1085,7 +1085,7 @@ ToNumber(JSContext *cx, Handle v, double *out) } JS_ALWAYS_INLINE bool -ToBoolean(const Value &v) +ToBoolean(HandleValue v) { if (v.isBoolean()) return v.toBoolean(); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 8ce9b1cd50eb..1b05c9ef87ec 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -1491,10 +1491,10 @@ CompareSubStringValues(JSContext *cx, const jschar *s1, size_t l1, if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; - if (!s1 || !s2) + int32_t result; + if (!s1 || !s2 || !CompareChars(s1, l1, s2, l2, &result)) return false; - int32_t result = CompareChars(s1, l1, s2, l2); *lessOrEqualp = (result <= 0); return true; } diff --git a/js/src/jsatominlines.h b/js/src/jsatominlines.h index a7d916b017a9..f6ed26e39bda 100644 --- a/js/src/jsatominlines.h +++ b/js/src/jsatominlines.h @@ -31,7 +31,6 @@ namespace js { inline jsid AtomToId(JSAtom *atom) { - AutoUnprotectCell unprotect(atom); JS_STATIC_ASSERT(JSID_INT_MIN == 0); uint32_t index; diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index 0acfc41f743a..9c6c00f94d32 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -182,7 +182,7 @@ js_BooleanToString(ExclusiveContext *cx, bool b) } JS_PUBLIC_API(bool) -js::ToBooleanSlow(const Value &v) +js::ToBooleanSlow(HandleValue v) { if (v.isString()) return v.toString()->length() != 0; diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 98398ef203d2..07c22fe19fc5 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -113,7 +113,7 @@ JSFunction * js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun, JSScript *script, jsbytecode *pc) { - JS_ASSERT(fun->nonLazyScript()->getShouldCloneAtCallsite()); + JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite); JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope()); JS_ASSERT(types::UseNewTypeForClone(fun)); @@ -126,7 +126,7 @@ js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction if (!table.initialized()) return nullptr; - CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, pc - script->getCode())); + CallsiteCloneTable::Ptr p = table.lookup(CallsiteCloneKey(fun, script, pc - script->code)); if (p) return p->value; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 88860cf858d4..3c9d060cf5a2 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -51,7 +51,7 @@ struct CallsiteCloneKey { typedef CallsiteCloneKey Lookup; static inline uint32_t hash(CallsiteCloneKey key) { - return uint32_t(size_t(key.script->getCode() + key.offset) ^ size_t(key.original)); + return uint32_t(size_t(key.script->code + key.offset) ^ size_t(key.original)); } static inline bool match(const CallsiteCloneKey &a, const CallsiteCloneKey &b) { diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h index 303f7a4fc06d..c2a6c5ca1189 100644 --- a/js/src/jscompartmentinlines.h +++ b/js/src/jscompartmentinlines.h @@ -22,7 +22,7 @@ JSCompartment::initGlobal(js::GlobalObject &global) js::GlobalObject * JSCompartment::maybeGlobal() const { - JS_ASSERT_IF(global_ && !runtime_->heapProtected(), global_->compartment() == this); + JS_ASSERT_IF(global_, global_->compartment() == this); return global_; } diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 77afcfcce96f..4b2f0b6d659d 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -65,19 +65,7 @@ class JSFunction : public JSObject uint16_t nargs; /* number of formal arguments (including defaults and the rest parameter unlike f.length) */ - - uint16_t getNargs() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); - return nargs; - } - uint16_t flags; /* bitfield composed of the above Flags enum */ - - uint16_t getFlags() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); - return flags; - } - union U { class Native { friend class JSFunction; @@ -110,31 +98,31 @@ class JSFunction : public JSObject return false; // Note: this should be kept in sync with FunctionBox::isHeavyweight(). - return nonLazyScript()->getHasAnyAliasedBindings() || - nonLazyScript()->getFunHasExtensibleScope() || - nonLazyScript()->getFunNeedsDeclEnvObject(); + return nonLazyScript()->bindings.hasAnyAliasedBindings() || + nonLazyScript()->funHasExtensibleScope || + nonLazyScript()->funNeedsDeclEnvObject; } /* A function can be classified as either native (C++) or interpreted (JS): */ - bool isInterpreted() const { return getFlags() & (INTERPRETED | INTERPRETED_LAZY); } + bool isInterpreted() const { return flags & (INTERPRETED | INTERPRETED_LAZY); } bool isNative() const { return !isInterpreted(); } /* Possible attributes of a native function: */ - bool isNativeConstructor() const { return getFlags() & NATIVE_CTOR; } + bool isNativeConstructor() const { return flags & NATIVE_CTOR; } /* Possible attributes of an interpreted function: */ - bool isFunctionPrototype() const { return getFlags() & IS_FUN_PROTO; } - bool isInterpretedLazy() const { return getFlags() & INTERPRETED_LAZY; } - bool hasScript() const { return getFlags() & INTERPRETED; } - bool isExprClosure() const { return getFlags() & EXPR_CLOSURE; } - bool hasGuessedAtom() const { return getFlags() & HAS_GUESSED_ATOM; } - bool isLambda() const { return getFlags() & LAMBDA; } - bool isSelfHostedBuiltin() const { return getFlags() & SELF_HOSTED; } - bool isSelfHostedConstructor() const { return getFlags() & SELF_HOSTED_CTOR; } - bool hasRest() const { return getFlags() & HAS_REST; } + bool isFunctionPrototype() const { return flags & IS_FUN_PROTO; } + bool isInterpretedLazy() const { return flags & INTERPRETED_LAZY; } + bool hasScript() const { return flags & INTERPRETED; } + bool isExprClosure() const { return flags & EXPR_CLOSURE; } + bool hasGuessedAtom() const { return flags & HAS_GUESSED_ATOM; } + bool isLambda() const { return flags & LAMBDA; } + bool isSelfHostedBuiltin() const { return flags & SELF_HOSTED; } + bool isSelfHostedConstructor() const { return flags & SELF_HOSTED_CTOR; } + bool hasRest() const { return flags & HAS_REST; } bool isWrappable() const { - JS_ASSERT_IF(getFlags() & SH_WRAPPABLE, isSelfHostedBuiltin()); - return getFlags() & SH_WRAPPABLE; + JS_ASSERT_IF(flags & SH_WRAPPABLE, isSelfHostedBuiltin()); + return flags & SH_WRAPPABLE; } bool hasJITCode() const { @@ -155,7 +143,7 @@ class JSFunction : public JSObject // // isArrow() is true for all three of these Function objects. // isBoundFunction() is true only for the last one. - bool isArrow() const { return getFlags() & ARROW; } + bool isArrow() const { return flags & ARROW; } /* Compound attributes: */ bool isBuiltin() const { @@ -168,7 +156,7 @@ class JSFunction : public JSObject (!isSelfHostedBuiltin() || isSelfHostedConstructor()); } bool isNamedLambda() const { - return isLambda() && displayAtom() && !hasGuessedAtom(); + return isLambda() && atom_ && !hasGuessedAtom(); } bool hasParallelNative() const { return isNative() && jitInfo() && !!jitInfo()->parallelNative; @@ -220,11 +208,7 @@ class JSFunction : public JSObject JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); } js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); } void initAtom(JSAtom *atom) { atom_.init(atom); } - - JSAtom *displayAtom() const { - js::AutoUnprotectCell unprotect(this); - return atom_; - } + JSAtom *displayAtom() const { return atom_; } void setGuessedAtom(JSAtom *atom) { JS_ASSERT(atom_ == nullptr); @@ -243,7 +227,6 @@ class JSFunction : public JSObject */ JSObject *environment() const { JS_ASSERT(isInterpreted()); - js::AutoUnprotectCell unprotect(this); return u.i.env_; } @@ -316,7 +299,6 @@ class JSFunction : public JSObject } JSScript *nonLazyScript() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(hasScript()); return u.i.s.script_; } @@ -327,13 +309,11 @@ class JSFunction : public JSObject } js::LazyScript *lazyScript() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_); return u.i.s.lazy_; } js::LazyScript *lazyScriptOrNull() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(isInterpretedLazy()); return u.i.s.lazy_; } @@ -374,7 +354,6 @@ class JSFunction : public JSObject JSNative native() const { JS_ASSERT(isNative()); - js::AutoUnprotectCell unprotect(this); return u.n.native; } @@ -399,7 +378,6 @@ class JSFunction : public JSObject const JSJitInfo *jitInfo() const { JS_ASSERT(isNative()); - js::AutoUnprotectCell unprotect(this); return u.n.jitinfo; } diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 845aa438b7de..de5874f003ad 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -687,8 +687,6 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script TemporaryTypeSet **pArgTypes, TemporaryTypeSet **pBytecodeTypes) { - AutoUnprotectCellUnderCompilationLock unprotect(script); - LifoAlloc *alloc = IonAlloc(); StackTypeSet *existing = script->types->typeArray(); @@ -704,7 +702,7 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script } *pThisTypes = types + (ThisTypes(script) - existing); - *pArgTypes = (script->function() && script->function()->getNargs()) + *pArgTypes = (script->function() && script->function()->nargs) ? (types + (ArgTypes(script, 0) - existing)) : nullptr; *pBytecodeTypes = types; @@ -786,26 +784,29 @@ CompilerConstraintInstance::generateTypeConstraint(JSContext *cx, RecompileIn const Class * TypeObjectKey::clasp() { - return isTypeObject() ? asTypeObject()->getClass() : asSingleObject()->getClass(); + return isTypeObject() ? asTypeObject()->clasp : asSingleObject()->getClass(); } TaggedProto TypeObjectKey::proto() { - return isTypeObject() ? TaggedProto(asTypeObject()->getProto()) : asSingleObject()->getTaggedProto(); + return isTypeObject() ? TaggedProto(asTypeObject()->proto) : asSingleObject()->getTaggedProto(); } JSObject * TypeObjectKey::singleton() { - return isTypeObject() ? asTypeObject()->getSingleton() : asSingleObject(); + return isTypeObject() ? asTypeObject()->singleton : asSingleObject(); } TypeNewScript * TypeObjectKey::newScript() { - if (isTypeObject() && asTypeObject()->hasNewScript()) - return asTypeObject()->newScript(); + if (isTypeObject()) { + TypeObjectAddendum *addendum = asTypeObject()->addendum; + if (addendum && addendum->isNewScript()) + return addendum->asNewScript(); + } return nullptr; } @@ -1629,11 +1630,14 @@ TemporaryTypeSet::getCommonPrototype() unsigned count = getObjectCount(); for (unsigned i = 0; i < count; i++) { - TypeObjectKey *object = getObject(i); - if (!object) + TaggedProto nproto; + if (JSObject *object = getSingleObject(i)) + nproto = object->getProto(); + else if (TypeObject *object = getTypeObject(i)) + nproto = object->proto.get(); + else continue; - TaggedProto nproto = object->proto(); if (proto) { if (nproto != proto) return nullptr; @@ -3375,7 +3379,7 @@ types::UseNewTypeForClone(JSFunction *fun) if (!fun->isInterpreted()) return false; - if (fun->hasScript() && fun->nonLazyScript()->getShouldCloneAtCallsite()) + if (fun->hasScript() && fun->nonLazyScript()->shouldCloneAtCallsite) return true; if (fun->isArrow()) @@ -3410,10 +3414,10 @@ types::UseNewTypeForClone(JSFunction *fun) uint32_t begin, end; if (fun->hasScript()) { - if (!fun->nonLazyScript()->getUsesArgumentsAndApply()) + if (!fun->nonLazyScript()->usesArgumentsAndApply) return false; - begin = fun->nonLazyScript()->getSourceStart(); - end = fun->nonLazyScript()->getSourceEnd(); + begin = fun->nonLazyScript()->sourceStart; + end = fun->nonLazyScript()->sourceEnd; } else { if (!fun->lazyScript()->usesArgumentsAndApply()) return false; diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 94a0dfb853bd..c20fd739e78e 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -874,19 +874,9 @@ struct TypeObject : gc::BarrieredCell /* Class shared by objects using this type. */ const Class *clasp; - const Class *getClass() { - AutoUnprotectCell unprotect(this); - return clasp; - } - /* Prototype shared by objects using this type. */ HeapPtrObject proto; - JSObject *getProto() { - AutoUnprotectCellUnderCompilationLock unprotect(this); - return proto; - } - /* * Whether there is a singleton JS object with this type. That JS object * must appear in type sets instead of this; we include the back reference @@ -894,20 +884,12 @@ struct TypeObject : gc::BarrieredCell */ HeapPtrObject singleton; - JSObject *getSingleton() { - AutoUnprotectCell unprotect(this); - return singleton; - } - /* * Value held by singleton if this is a standin type for a singleton JS * object whose type has not been constructed yet. */ static const size_t LAZY_SINGLETON = 1; - bool lazy() const { - AutoUnprotectCellUnderCompilationLock unprotect(this); - return singleton == (JSObject *) LAZY_SINGLETON; - } + bool lazy() const { return singleton == (JSObject *) LAZY_SINGLETON; } /* Flags for this object. */ TypeObjectFlags flags; @@ -925,22 +907,18 @@ struct TypeObject : gc::BarrieredCell HeapPtr addendum; bool hasNewScript() const { - AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum && addendum->isNewScript(); } TypeNewScript *newScript() { - AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum->asNewScript(); } bool hasTypedObject() { - AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum && addendum->isTypedObject(); } TypeTypedObject *typedObject() { - AutoUnprotectCellUnderCompilationLock unprotect(this); return addendum->asTypedObject(); } @@ -988,11 +966,6 @@ struct TypeObject : gc::BarrieredCell /* If this is an interpreted function, the function object. */ HeapPtrFunction interpretedFunction; - JSFunction *getInterpretedFunction() { - AutoUnprotectCell unprotect(this); - return interpretedFunction; - } - #if JS_BITS_PER_WORD == 32 uint32_t padding; #endif @@ -1000,18 +973,15 @@ struct TypeObject : gc::BarrieredCell inline TypeObject(const Class *clasp, TaggedProto proto, bool unknown); bool hasAnyFlags(TypeObjectFlags flags) { - AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); return !!(this->flags & flags); } bool hasAllFlags(TypeObjectFlags flags) { - AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT((flags & OBJECT_FLAG_DYNAMIC_MASK) == flags); return (this->flags & flags) == flags; } bool unknownProperties() { - AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT_IF(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES, hasAllFlags(OBJECT_FLAG_DYNAMIC_MASK)); return !!(flags & OBJECT_FLAG_UNKNOWN_PROPERTIES); @@ -1046,10 +1016,7 @@ struct TypeObject : gc::BarrieredCell /* Returns true if the allocating script should be recompiled. */ bool incrementTenureCount(); - uint32_t tenureCount() const { - // Note: We ignore races when reading the tenure count of a type off thread. - AutoUnprotectCell unprotect(this); return (flags & OBJECT_FLAG_TENURE_COUNT_MASK) >> OBJECT_FLAG_TENURE_COUNT_SHIFT; } diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index 0a3ae267682c..f44b4c6c22d0 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -132,8 +132,8 @@ Type::ObjectType(JSObject *obj) /* static */ inline Type Type::ObjectType(TypeObject *obj) { - if (obj->getSingleton()) - return Type(uintptr_t(obj->getSingleton()) | 1); + if (obj->singleton) + return Type(uintptr_t(obj->singleton.get()) | 1); return Type(uintptr_t(obj)); } @@ -221,8 +221,7 @@ IdToTypeId(jsid id) * and overflowing integers. */ if (JSID_IS_STRING(id)) { - JSAtom *str = JSID_TO_ATOM(id); - AutoUnprotectCell unprotect(str); + JSFlatString *str = JSID_TO_FLAT_STRING(id); JS::TwoByteChars cp = str->range(); if (JS7_ISDEC(cp[0]) || cp[0] == '-') { for (size_t i = 1; i < cp.length(); ++i) { @@ -610,7 +609,7 @@ TypeScript::ThisTypes(JSScript *script) /* static */ inline StackTypeSet * TypeScript::ArgTypes(JSScript *script, unsigned i) { - JS_ASSERT(i < script->function()->getNargs()); + JS_ASSERT(i < script->function()->nargs); return script->types->typeArray() + script->nTypeSets + js::analyze::ArgSlot(i); } @@ -625,11 +624,11 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPE uint32_t *bytecodeMap = nullptr; MOZ_CRASH(); #endif - uint32_t offset = pc - script->getCode(); - JS_ASSERT(offset < script->getLength()); + uint32_t offset = pc - script->code; + JS_ASSERT(offset < script->length); // See if this pc is the next typeset opcode after the last one looked up. - if (bytecodeMap[*hint + 1] == offset && (*hint + 1) < script->getNumTypeSets()) { + if (bytecodeMap[*hint + 1] == offset && (*hint + 1) < script->nTypeSets) { (*hint)++; return typeArray + *hint; } @@ -640,7 +639,7 @@ TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPE // Fall back to a binary search. size_t bottom = 0; - size_t top = script->getNumTypeSets() - 1; + size_t top = script->nTypeSets - 1; size_t mid = bottom + (top - bottom) / 2; while (mid < top) { if (bytecodeMap[mid] < offset) @@ -1182,7 +1181,7 @@ TypeSet::addType(Type type, LifoAlloc *alloc, bool *padded) if (type.isTypeObject()) { TypeObject *nobject = type.typeObject(); - JS_ASSERT(!nobject->getSingleton()); + JS_ASSERT(!nobject->singleton); if (nobject->unknownProperties()) goto unknownObject; } @@ -1314,7 +1313,7 @@ TypeSet::getObjectClass(unsigned i) const if (JSObject *object = getSingleObject(i)) return object->getClass(); if (TypeObject *object = getTypeObject(i)) - return object->getClass(); + return object->clasp; return nullptr; } @@ -1403,8 +1402,6 @@ TypeObject::maybeGetProperty(jsid id) JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id)); JS_ASSERT(!unknownProperties()); - AutoUnprotectCellUnderCompilationLock unprotect(this); - Property *prop = HashSetLookup (propertySet, basePropertyCount(), id); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index a0c3630a3dfb..6ee71302c171 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -5554,8 +5554,6 @@ DumpProperty(JSObject *obj, Shape &shape) bool JSObject::uninlinedIsProxy() const { - AutoUnprotectCellUnderCompilationLock unprotect0(this); - AutoUnprotectCellUnderCompilationLock unprotect1(type_); return is(); } diff --git a/js/src/jsobj.h b/js/src/jsobj.h index d174ea73d8ad..8909ec0bae45 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -288,10 +288,6 @@ class JSObject : public js::ObjectImpl } bool isBoundFunction() const { - // Note: This function can race when it is called during off thread compilation. - js::AutoUnprotectCell unprotect0(this); - js::AutoUnprotectCell unprotect1(lastProperty()); - js::AutoUnprotectCell unprotect2(lastProperty()->base()); return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION); } @@ -353,10 +349,6 @@ class JSObject : public js::ObjectImpl return lastProperty()->entryCount(); } - uint32_t propertyCountForCompilation() const { - return lastProperty()->entryCountForCompilation(); - } - bool hasShapeTable() const { return lastProperty()->hasTable(); } @@ -373,13 +365,13 @@ class JSObject : public js::ObjectImpl /* Whether a slot is at a fixed offset from this object. */ bool isFixedSlot(size_t slot) { - return slot < numFixedSlotsForCompilation(); + return slot < numFixedSlots(); } /* Index into the dynamic slots array to use for a dynamic slot. */ size_t dynamicSlotIndex(size_t slot) { - JS_ASSERT(slot >= numFixedSlotsForCompilation()); - return slot - numFixedSlotsForCompilation(); + JS_ASSERT(slot >= numFixedSlots()); + return slot - numFixedSlots(); } /* @@ -748,11 +740,6 @@ class JSObject : public js::ObjectImpl return getElementsHeader()->shouldConvertDoubleElements(); } - bool shouldConvertDoubleElementsForCompilation() { - // Note: isNative() generally can't be safely called off thread. - return getElementsHeader()->shouldConvertDoubleElements(); - } - inline void setShouldConvertDoubleElements(); /* Packed information for this object's elements. */ diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 9ffef95337b9..00f9eecb48c6 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -126,10 +126,7 @@ NumBlockSlots(JSScript *script, jsbytecode *pc) JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET1_LENGTH); JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET2_LENGTH); - StaticBlockObject *block = &script->getObject(GET_UINT32_INDEX(pc))->as(); - AutoUnprotectCell unprotect(block); - - return block->propertyCountForCompilation(); + return script->getObject(GET_UINT32_INDEX(pc))->as().slotCount(); } unsigned diff --git a/js/src/jsopcodeinlines.h b/js/src/jsopcodeinlines.h index 4ce35ff87f68..71cea13f58f0 100644 --- a/js/src/jsopcodeinlines.h +++ b/js/src/jsopcodeinlines.h @@ -16,8 +16,8 @@ namespace js { static inline unsigned GetDefCount(JSScript *script, unsigned offset) { - JS_ASSERT(offset < script->getLength()); - jsbytecode *pc = script->getCode() + offset; + JS_ASSERT(offset < script->length); + jsbytecode *pc = script->code + offset; /* * Add an extra pushed value for OR/AND opcodes, so that they are included @@ -43,8 +43,8 @@ GetDefCount(JSScript *script, unsigned offset) static inline unsigned GetUseCount(JSScript *script, unsigned offset) { - JS_ASSERT(offset < script->getLength()); - jsbytecode *pc = script->getCode() + offset; + JS_ASSERT(offset < script->length); + jsbytecode *pc = script->code + offset; if (JSOp(*pc) == JSOP_PICK) return (pc[1] + 1); diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index a58470b38638..c83216d75330 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2092,11 +2092,11 @@ GSNCache::purge() jssrcnote * js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc) { - size_t target = pc - script->getCode(); - if (target >= size_t(script->getLength())) + size_t target = pc - script->code; + if (target >= size_t(script->length)) return nullptr; - if (cache.code == script->getCode()) { + if (cache.code == script->code) { JS_ASSERT(cache.map.initialized()); GSNCache::Map::Ptr p = cache.map.lookup(pc); return p ? p->value : nullptr; @@ -2116,7 +2116,7 @@ js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc) } } - if (cache.code != script->getCode() && script->getLength() >= GSN_CACHE_THRESHOLD) { + if (cache.code != script->code && script->length >= GSN_CACHE_THRESHOLD) { unsigned nsrcnotes = 0; for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { @@ -2129,14 +2129,14 @@ js::GetSrcNote(GSNCache &cache, JSScript *script, jsbytecode *pc) cache.code = nullptr; } if (cache.map.init(nsrcnotes)) { - pc = script->getCode(); + pc = script->code; for (jssrcnote *sn = script->notes(); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { pc += SN_DELTA(sn); if (SN_IS_GETTABLE(sn)) JS_ALWAYS_TRUE(cache.map.put(pc, sn)); } - cache.code = script->getCode(); + cache.code = script->code; } } @@ -2202,7 +2202,7 @@ js::PCToLineNumber(JSScript *script, jsbytecode *pc, unsigned *columnp) if (!pc) return 0; - return PCToLineNumber(script->getLineno(), script->notes(), script->getCode(), pc, columnp); + return PCToLineNumber(script->lineno, script->notes(), script->code, pc, columnp); } /* The line number limit is the same as the jssrcnote offset limit. */ @@ -2956,14 +2956,12 @@ JSScript::argumentsOptimizationFailed(JSContext *cx, HandleScript script) bool JSScript::varIsAliased(unsigned varSlot) { - AutoUnprotectCell unprotect(this); return bindings.bindingIsAliased(bindings.numArgs() + varSlot); } bool JSScript::formalIsAliased(unsigned argSlot) { - AutoUnprotectCell unprotect(this); return bindings.bindingIsAliased(argSlot); } diff --git a/js/src/jsscript.h b/js/src/jsscript.h index b6d596b48117..21e00a1af318 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -184,13 +184,11 @@ class Bindings bool bindingArrayUsingTemporaryStorage() const { return bindingArrayAndFlag_ & TEMPORARY_STORAGE_BIT; } - - public: - Binding *bindingArray() const { return reinterpret_cast(bindingArrayAndFlag_ & ~TEMPORARY_STORAGE_BIT); } + public: inline Bindings(); /* @@ -226,14 +224,7 @@ class Bindings bool bindingIsAliased(unsigned bindingIndex); /* Return whether this scope has any aliased bindings. */ - bool hasAnyAliasedBindings() const { - if (!callObjShape_) - return false; - - // Binding shapes are immutable once constructed. - AutoUnprotectCell unprotect(callObjShape_); - return !callObjShape_->isEmptyShape(); - } + bool hasAnyAliasedBindings() const { return callObjShape_ && !callObjShape_->isEmptyShape(); } void trace(JSTracer *trc); }; @@ -437,10 +428,6 @@ class ScriptSourceObject : public JSObject static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source); ScriptSource *source() { - // Script source objects are immutable. - AutoUnprotectCell unprotect0(this); - AutoUnprotectCell unprotect1(lastProperty()); - AutoUnprotectCell unprotect2(lastProperty()->base()); return static_cast(getReservedSlot(SOURCE_SLOT).toPrivate()); } @@ -482,31 +469,10 @@ class JSScript : public js::gc::BarrieredCell js::Bindings bindings; /* names of top-level variables in this script (and arguments if this is a function script) */ - bool getHasAnyAliasedBindings() const { - js::AutoUnprotectCell unprotect(this); - return bindings.hasAnyAliasedBindings(); - } - - js::Binding *bindingArray() const { - js::AutoUnprotectCell unprotect(this); - return bindings.bindingArray(); - } - - unsigned numArgs() const { - js::AutoUnprotectCell unprotect(this); - return bindings.numArgs(); - } - // Word-sized fields. public: jsbytecode *code; /* bytecodes and their immediate operands */ - - jsbytecode *getCode() { - js::AutoUnprotectCell unprotect(this); - return code; - } - uint8_t *data; /* pointer to variable-length data array (see comment above Create() for details) */ @@ -544,46 +510,20 @@ class JSScript : public js::gc::BarrieredCell public: uint32_t length; /* length of code vector */ - uint32_t getLength() { - js::AutoUnprotectCell unprotect(this); - return length; - } - uint32_t dataSize; /* size of the used part of the data array */ uint32_t lineno; /* base line number of script */ - - uint32_t getLineno() { - js::AutoUnprotectCell unprotect(this); - return lineno; - } - uint32_t column; /* base column of script, optionally set */ uint32_t mainOffset; /* offset of main entry point from code, after predef'ing prolog */ - uint32_t getMainOffset() { - js::AutoUnprotectCell unprotect(this); - return mainOffset; - } - uint32_t natoms; /* length of atoms array */ /* Range of characters in scriptSource which contains this script's source. */ uint32_t sourceStart; uint32_t sourceEnd; - uint32_t getSourceStart() { - js::AutoUnprotectCell unprotect(this); - return sourceStart; - } - - uint32_t getSourceEnd() { - js::AutoUnprotectCell unprotect(this); - return sourceEnd; - } - private: uint32_t useCount; /* Number of times the script has been called * or has had backedges taken. Reset if the @@ -609,26 +549,10 @@ class JSScript : public js::gc::BarrieredCell uint16_t nfixed; /* number of slots besides stack operands in slot array */ - uint16_t getNfixed() { - js::AutoUnprotectCell unprotect(this); - return nfixed; - } - uint16_t nTypeSets; /* number of type sets used in this script for dynamic type monitoring */ - uint16_t getNumTypeSets() { - js::AutoUnprotectCell unprotect(this); - return nTypeSets; - } - uint16_t nslots; /* vars plus maximum stack depth */ - - uint16_t getNslots() { - js::AutoUnprotectCell unprotect(this); - return nslots; - } - uint16_t staticLevel;/* static level for display maintenance */ // Bit fields. @@ -660,62 +584,20 @@ class JSScript : public js::gc::BarrieredCell public: bool noScriptRval:1; /* no need for result value of last expression statement */ - - bool getNoScriptRval() const { - js::AutoUnprotectCell unprotect(this); - return noScriptRval; - } - bool savedCallerFun:1; /* can call getCallerFunction() */ bool strict:1; /* code is in strict mode */ - - bool getStrict() const { - js::AutoUnprotectCell unprotect(this); - return strict; - } - bool explicitUseStrict:1; /* code has "use strict"; explicitly */ bool compileAndGo:1; /* see Parser::compileAndGo */ - - bool getCompileAndGo() const { - js::AutoUnprotectCell unprotect(this); - return compileAndGo; - } - bool selfHosted:1; /* see Parser::selfHostingMode */ bool bindingsAccessedDynamically:1; /* see FunctionContextFlags */ bool funHasExtensibleScope:1; /* see FunctionContextFlags */ - - bool getFunHasExtensibleScope() const { - js::AutoUnprotectCell unprotect(this); - return funHasExtensibleScope; - } - bool funNeedsDeclEnvObject:1; /* see FunctionContextFlags */ - - bool getFunNeedsDeclEnvObject() const { - js::AutoUnprotectCell unprotect(this); - return funNeedsDeclEnvObject; - } - bool funHasAnyAliasedFormal:1; /* true if any formalIsAliased(i) */ - - bool getFunHasAnyAliasedFormal() const { - js::AutoUnprotectCell unprotect(this); - return funHasAnyAliasedFormal; - } - bool warnedAboutUndefinedProp:1; /* have warned about uses of undefined properties in this script */ bool hasSingletons:1; /* script has singleton objects */ bool treatAsRunOnce:1; /* script is a lambda to treat as running once. */ - - bool getTreatAsRunOnce() const { - js::AutoUnprotectCell unprotect(this); - return treatAsRunOnce; - } - bool hasRunOnce:1; /* if treatAsRunOnce, whether script has executed. */ bool hasBeenCloned:1; /* script has been reused for a clone. */ bool isActiveEval:1; /* script came from eval(), and is still active */ @@ -727,65 +609,25 @@ class JSScript : public js::gc::BarrieredCell // Both 'arguments' and f.apply() are used. This is likely to be a wrapper. bool usesArgumentsAndApply:1; - bool getUsesArgumentsAndApply() const { - js::AutoUnprotectCell unprotect(this); - return usesArgumentsAndApply; - } - /* script is attempted to be cloned anew at each callsite. This is temporarily needed for ParallelArray selfhosted code until type information can be made context sensitive. See discussion in bug 826148. */ bool shouldCloneAtCallsite:1; - - bool getShouldCloneAtCallsite() const { - js::AutoUnprotectCell unprotect(this); - return shouldCloneAtCallsite; - } - bool isCallsiteClone:1; /* is a callsite clone; has a link to the original function */ bool shouldInline:1; /* hint to inline when possible */ - - bool getShouldInline() const { - js::AutoUnprotectCell unprotect(this); - return shouldInline; - } - bool uninlineable:1; /* explicitly marked as uninlineable */ - - bool getUninlineable() const { - js::AutoUnprotectCell unprotect(this); - return uninlineable; - } - +#ifdef JS_ION bool failedBoundsCheck:1; /* script has had hoisted bounds checks fail */ - - bool getFailedBoundsCheck() const { - js::AutoUnprotectCell unprotect(this); - return failedBoundsCheck; - } - bool failedShapeGuard:1; /* script has had hoisted shape guard fail */ - - bool getFailedShapeGuard() const { - js::AutoUnprotectCell unprotect(this); - return failedShapeGuard; - } - bool hadFrequentBailouts:1; - - bool getHadFrequentBailouts() const { - js::AutoUnprotectCell unprotect(this); - return hadFrequentBailouts; - } - +#else + bool failedBoundsCheckPad:1; + bool failedShapeGuardPad:1; + bool hadFrequentBailoutsPad:1; +#endif bool invalidatedIdempotentCache:1; /* idempotent cache has triggered invalidation */ - bool getInvalidatedIdempotentCache() const { - js::AutoUnprotectCell unprotect(this); - return invalidatedIdempotentCache; - } - // If the generator was created implicitly via a generator expression, // isGeneratorExp will be true. bool isGeneratorExp:1; @@ -836,14 +678,11 @@ class JSScript : public js::gc::BarrieredCell void setVersion(JSVersion v) { version = v; } /* See ContextFlags::funArgumentsHasLocalBinding comment. */ - bool argumentsHasVarBinding() const { - js::AutoUnprotectCell unprotect(this); - return argsHasVarBinding_; - } + bool argumentsHasVarBinding() const { return argsHasVarBinding_; } jsbytecode *argumentsBytecode() const { JS_ASSERT(code[0] == JSOP_ARGUMENTS); return code; } void setArgumentsHasVarBinding(); bool argumentsAliasesFormals() const { - return argumentsHasVarBinding() && !getStrict(); + return argumentsHasVarBinding() && !strict; } js::GeneratorKind generatorKind() const { @@ -870,10 +709,7 @@ class JSScript : public js::gc::BarrieredCell * that needsArgsObj is only called after the script has been analyzed. */ bool analyzedArgsUsage() const { return !needsArgsAnalysis_; } - bool needsArgsObj() const { - js::AutoUnprotectCell unprotect(this); - JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; - } + bool needsArgsObj() const { JS_ASSERT(analyzedArgsUsage()); return needsArgsObj_; } void setNeedsArgsObj(bool needsArgsObj); static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script); @@ -887,7 +723,7 @@ class JSScript : public js::gc::BarrieredCell * opcodes won't be emitted at all. */ bool argsObjAliasesFormals() const { - return needsArgsObj() && !getStrict(); + return needsArgsObj() && !strict; } bool hasAnyIonScript() const { @@ -898,7 +734,6 @@ class JSScript : public js::gc::BarrieredCell return ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT; } bool canIonCompile() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); return ion != ION_DISABLED_SCRIPT; } @@ -924,7 +759,6 @@ class JSScript : public js::gc::BarrieredCell } bool hasBaselineScript() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); return baseline && baseline != BASELINE_DISABLED_SCRIPT; } bool canBaselineCompile() const { @@ -932,7 +766,6 @@ class JSScript : public js::gc::BarrieredCell } js::jit::BaselineScript *baselineScript() const { JS_ASSERT(hasBaselineScript()); - js::AutoUnprotectCellUnderCompilationLock unprotect(this); return baseline; } inline void setBaselineScript(js::jit::BaselineScript *baselineScript); @@ -944,7 +777,6 @@ class JSScript : public js::gc::BarrieredCell } bool canParallelIonCompile() const { - js::AutoUnprotectCellUnderCompilationLock unprotect(this); return parallelIon != ION_DISABLED_SCRIPT; } @@ -985,10 +817,7 @@ class JSScript : public js::gc::BarrieredCell * Original compiled function for the script, if it has a function. * nullptr for global and eval scripts. */ - JSFunction *function() const { - js::AutoUnprotectCell unprotect(this); - return function_; - } + JSFunction *function() const { return function_; } inline void setFunction(JSFunction *fun); JSFunction *originalFunction() const; @@ -1002,10 +831,7 @@ class JSScript : public js::gc::BarrieredCell js::ScriptSourceObject *sourceObject() const; js::ScriptSource *scriptSource() const { return sourceObject()->source(); } JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); } - const char *filename() const { - js::AutoUnprotectCell unprotect(this); - return scriptSource()->filename(); - } + const char *filename() const { return scriptSource()->filename(); } public: @@ -1039,7 +865,6 @@ class JSScript : public js::gc::BarrieredCell /* See StaticScopeIter comment. */ JSObject *enclosingStaticScope() const { - js::AutoUnprotectCell unprotect(this); if (isCallsiteClone) return nullptr; return enclosingScopeOrOriginalFunction_; @@ -1062,11 +887,7 @@ class JSScript : public js::gc::BarrieredCell bool makeAnalysis(JSContext *cx); public: - uint32_t getUseCount() const { - // Note: We ignore races when reading the use count of a script off thread. - js::AutoUnprotectCell unprotect(this); - return useCount; - } + uint32_t getUseCount() const { return useCount; } uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; } uint32_t *addressOfUseCount() { return &useCount; } static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); } @@ -1096,14 +917,10 @@ class JSScript : public js::gc::BarrieredCell uint32_t numNotes(); /* Number of srcnote slots in the srcnotes section */ /* Script notes are allocated right after the code. */ - jssrcnote *notes() { return (jssrcnote *)(getCode() + getLength()); } + jssrcnote *notes() { return (jssrcnote *)(code + length); } - bool hasArray(ArrayKind kind) { - js::AutoUnprotectCell unprotect(this); - return (hasArrayBits & (1 << kind)); - } - - void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); } + bool hasArray(ArrayKind kind) { return (hasArrayBits & (1 << kind)); } + void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); } void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; } bool hasConsts() { return hasArray(CONSTS); } @@ -1122,25 +939,21 @@ class JSScript : public js::gc::BarrieredCell js::ConstArray *consts() { JS_ASSERT(hasConsts()); - js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + constsOffset()); } js::ObjectArray *objects() { JS_ASSERT(hasObjects()); - js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + objectsOffset()); } js::ObjectArray *regexps() { JS_ASSERT(hasRegexps()); - js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + regexpsOffset()); } js::TryNoteArray *trynotes() { JS_ASSERT(hasTrynotes()); - js::AutoUnprotectCell unprotect(this); return reinterpret_cast(data + trynotesOffset()); } @@ -1152,7 +965,6 @@ class JSScript : public js::gc::BarrieredCell bool hasLoops(); js::HeapPtrAtom &getAtom(size_t index) const { - js::AutoUnprotectCell unprotect(this); JS_ASSERT(index < natoms); return atoms[index]; } @@ -1172,7 +984,6 @@ class JSScript : public js::gc::BarrieredCell } JSObject *getObject(size_t index) { - js::AutoUnprotectCell unprotect(this); js::ObjectArray *arr = objects(); JS_ASSERT(index < arr->length); return arr->vector[index]; @@ -1505,7 +1316,6 @@ class LazyScript : public gc::BarrieredCell } bool usesArgumentsAndApply() const { - AutoUnprotectCell unprotect(this); return usesArgumentsAndApply_; } void setUsesArgumentsAndApply() { @@ -1530,11 +1340,9 @@ class LazyScript : public gc::BarrieredCell return sourceObject()->source(); } uint32_t begin() const { - AutoUnprotectCell unprotect(this); return begin_; } uint32_t end() const { - AutoUnprotectCell unprotect(this); return end_; } uint32_t lineno() const { diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index 0eb228519010..cce910b7863b 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -26,9 +26,9 @@ Bindings::Bindings() inline AliasedFormalIter::AliasedFormalIter(JSScript *script) - : begin_(script->bindingArray()), + : begin_(script->bindings.bindingArray()), p_(begin_), - end_(begin_ + (script->getFunHasAnyAliasedFormal() ? script->numArgs() : 0)), + end_(begin_ + (script->funHasAnyAliasedFormal ? script->bindings.numArgs() : 0)), slot_(CallObject::RESERVED_SLOTS) { settle(); @@ -98,7 +98,6 @@ JSScript::global() const * A JSScript always marks its compartment's global (via bindings) so we * can assert that maybeGlobal is non-null here. */ - js::AutoUnprotectCell unprotect(this); return *compartment()->maybeGlobal(); } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index a45a66fb1ef1..898035495fba 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -4093,8 +4093,7 @@ CompareStringsImpl(JSContext *cx, JSString *str1, JSString *str2, int32_t *resul if (!s2) return false; - *result = CompareChars(s1, str1->length(), s2, str2->length()); - return true; + return CompareChars(s1, str1->length(), s2, str2->length(), result); } bool @@ -4103,14 +4102,6 @@ js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *resul return CompareStringsImpl(cx, str1, str2, result); } -int32_t -js::CompareAtoms(JSAtom *atom1, JSAtom *atom2) -{ - AutoUnprotectCell unprotect1(atom1); - AutoUnprotectCell unprotect2(atom2); - return CompareChars(atom1->chars(), atom1->length(), atom2->chars(), atom2->length()); -} - bool js::StringEqualsAscii(JSLinearString *str, const char *asciiBytes) { diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 1f8286f9331d..504b7bd67a56 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -48,16 +48,19 @@ SkipSpace(const jschar *s, const jschar *end) // Return less than, equal to, or greater than zero depending on whether // s1 is less than, equal to, or greater than s2. -inline int32_t -CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2) +inline bool +CompareChars(const jschar *s1, size_t l1, const jschar *s2, size_t l2, int32_t *result) { size_t n = Min(l1, l2); for (size_t i = 0; i < n; i++) { - if (int32_t cmp = s1[i] - s2[i]) - return cmp; + if (int32_t cmp = s1[i] - s2[i]) { + *result = cmp; + return true; + } } - return (int32_t)(l1 - l2); + *result = (int32_t)(l1 - l2); + return true; } } /* namespace js */ @@ -207,9 +210,6 @@ EqualStrings(JSLinearString *str1, JSLinearString *str2); extern bool CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result); -int32_t -CompareAtoms(JSAtom *atom1, JSAtom *atom2); - /* * Return true if the string matches the given sequence of ASCII bytes. */ diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index c8b7ed6eb721..9d64c2575ccc 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5429,9 +5429,6 @@ ProcessArgs(JSContext *cx, JSObject *obj_, OptionParser *op) if (op->getBoolOption("ion-check-range-analysis")) jit::js_IonOptions.checkRangeAnalysis = true; - if (op->getBoolOption("ion-check-thread-safety")) - jit::js_IonOptions.checkThreadSafety = true; - if (const char *str = op->getStringOption("ion-inlining")) { if (strcmp(str, "on") == 0) jit::js_IonOptions.inlining = true; @@ -5743,8 +5740,6 @@ main(int argc, char **argv, char **envp) "Range analysis (default: on, off to disable)") || !op.addBoolOption('\0', "ion-check-range-analysis", "Range analysis checking") - || !op.addBoolOption('\0', "ion-check-thread-safety", - "Builder thread safety checking") || !op.addStringOption('\0', "ion-inlining", "on/off", "Inline methods where possible (default: on, off to disable)") || !op.addStringOption('\0', "ion-osr", "on/off", @@ -5838,15 +5833,8 @@ main(int argc, char **argv, char **envp) if (!JS_Init()) return 1; - // When doing thread safety checks for VM accesses made during Ion compilation, - // we rely on protected memory and only the main thread should be active. - JSUseHelperThreads useHelperThreads = - op.getBoolOption("ion-check-thread-safety") - ? JS_NO_HELPER_THREADS - : JS_USE_HELPER_THREADS; - /* Use the same parameters as the browser in xpcjsruntime.cpp. */ - rt = JS_NewRuntime(32L * 1024L * 1024L, useHelperThreads); + rt = JS_NewRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS); if (!rt) return 1; gTimeoutFunc = NullValue(); diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 8f83d8ecd812..cbe9ee03d224 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -153,9 +153,8 @@ class GlobalObject : public JSObject public: Value getConstructor(JSProtoKey key) const { - AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(key <= JSProto_LIMIT); - return getSlotRefForCompilation(APPLICATION_SLOTS + key); + return getSlot(APPLICATION_SLOTS + key); } void setConstructor(JSProtoKey key, const Value &v) { @@ -164,9 +163,8 @@ class GlobalObject : public JSObject } Value getPrototype(JSProtoKey key) const { - AutoUnprotectCellUnderCompilationLock unprotect(this); JS_ASSERT(key <= JSProto_LIMIT); - return getSlotRefForCompilation(APPLICATION_SLOTS + JSProto_LIMIT + key); + return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key); } void setPrototype(JSProtoKey key, const Value &value) { @@ -350,7 +348,6 @@ class GlobalObject : public JSObject } JSObject *maybeGetArrayPrototype() { - AutoUnprotectCellUnderCompilationLock unprotect(this); if (arrayClassInitialized()) return &getPrototype(JSProto_Array).toObject(); return nullptr; @@ -465,18 +462,6 @@ class GlobalObject : public JSObject return &self->getSlot(slot).toObject(); } - const HeapSlot &getSlotRefForCompilation(uint32_t slot) const { - // This method should only be used for slots that are either eagerly - // initialized on creation of the global or only change under the - // compilation lock. Note that the dynamic slots pointer for global - // objects can only change under the compilation lock. - JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(getClass())); - uint32_t fixed = numFixedSlotsForCompilation(); - if (slot < fixed) - return fixedSlots()[slot]; - return slots[slot - fixed]; - } - public: JSObject *getOrCreateIteratorPrototype(JSContext *cx) { return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_LIMIT + JSProto_Iterator, @@ -527,18 +512,12 @@ class GlobalObject : public JSObject } JSObject *intrinsicsHolder() { - AutoUnprotectCellUnderCompilationLock unprotect(this); - JS_ASSERT(!getSlotRefForCompilation(INTRINSICS).isUndefined()); - return &getSlotRefForCompilation(INTRINSICS).toObject(); + JS_ASSERT(!getSlotRef(INTRINSICS).isUndefined()); + return &getSlotRef(INTRINSICS).toObject(); } bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) { JSObject *holder = intrinsicsHolder(); - - AutoUnprotectCellUnderCompilationLock unprotect0(holder); - AutoUnprotectCellUnderCompilationLock unprotect1(holder->lastProperty()); - AutoUnprotectCellUnderCompilationLock unprotect2(holder->lastProperty()->base()); - if (Shape *shape = holder->nativeLookupPure(name)) { *vp = holder->getSlot(shape->slot()); return true; @@ -571,10 +550,8 @@ class GlobalObject : public JSObject unsigned nargs, MutableHandleValue funVal); RegExpStatics *getRegExpStatics() const { - AutoUnprotectCellUnderCompilationLock unprotect0(this); - JSObject &resObj = getSlotRefForCompilation(REGEXP_STATICS).toObject(); - AutoUnprotectCell unprotect1(&resObj); - return static_cast(resObj.getPrivate(/* nfixed = */ 1)); + JSObject &resObj = getSlot(REGEXP_STATICS).toObject(); + return static_cast(resObj.getPrivate()); } JSObject *getThrowTypeError() const { @@ -601,10 +578,9 @@ class GlobalObject : public JSObject // in which |obj| was created, if no prior warning was given. static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj); - Value getOriginalEval() const { - AutoUnprotectCellUnderCompilationLock unprotect(this); - JS_ASSERT(getSlotRefForCompilation(EVAL).isObject()); - return getSlotRefForCompilation(EVAL); + const Value &getOriginalEval() const { + JS_ASSERT(getSlot(EVAL).isObject()); + return getSlot(EVAL); } // Implemented in jsiter.cpp. @@ -789,7 +765,7 @@ template<> inline bool JSObject::is() const { - return !!(getClass()->flags & JSCLASS_IS_GLOBAL); + return !!(js::GetObjectClass(const_cast(this))->flags & JSCLASS_IS_GLOBAL); } #endif /* vm_GlobalObject_h */ diff --git a/js/src/vm/ObjectImpl.cpp b/js/src/vm/ObjectImpl.cpp index da57ba4a209e..00276cd204ea 100644 --- a/js/src/vm/ObjectImpl.cpp +++ b/js/src/vm/ObjectImpl.cpp @@ -334,25 +334,6 @@ js::ObjectImpl::nativeLookupPure(jsid id) return Shape::searchNoHashify(lastProperty(), id); } -uint32_t -js::ObjectImpl::numFixedSlotsForCompilation() const -{ - // This is an alternative method for getting the number of fixed slots - // in an object. It requires more logic and memory accesses than - // numFixedSlots() but is safe to be called from the compilation thread, - // even if the main thread is actively mutating the VM. - if (static_cast(this)->is()) - return 0; -#ifdef JSGC_GENERATIONAL - // The compiler does not have access to nursery things, so if this object - // is in the nursery we can fall back to numFixedSlots(). - if (!isTenured()) - return numFixedSlots(); -#endif - gc::AllocKind kind = tenuredGetAllocKind(); - return gc::GetGCKindSlots(kind, getClass()); -} - void js::ObjectImpl::markChildren(JSTracer *trc) { diff --git a/js/src/vm/ObjectImpl.h b/js/src/vm/ObjectImpl.h index 8319a8ca88ca..d4af46f472b7 100644 --- a/js/src/vm/ObjectImpl.h +++ b/js/src/vm/ObjectImpl.h @@ -980,19 +980,11 @@ class ObjectImpl : public gc::BarrieredCell public: JSObject * getProto() const { - AutoUnprotectCellUnderCompilationLock unprotect0(this); - return type_->getProto(); + return type_->proto; } const Class *getClass() const { - AutoUnprotectCellUnderCompilationLock unprotect0(this); - return type_->getClass(); - } - - const Class *getClassImmutable() { - // For use on objects which cannot be modified after construction. - AutoUnprotectCell unprotect(this); - return type_->getClass(); + return type_->clasp; } static inline bool @@ -1035,18 +1027,10 @@ class ObjectImpl : public gc::BarrieredCell JS_ASSERT(isNative()); return getElementsHeader()->initializedLength; } - uint32_t getDenseInitializedLengthForCompilation() { - // Note: isNative() generally can't be safely called off thread. - return getElementsHeader()->initializedLength; - } uint32_t getDenseCapacity() { JS_ASSERT(isNative()); return getElementsHeader()->capacity; } - uint32_t getDenseCapacityForCompilation() { - // Note: isNative() generally can't be safely called off thread. - return getElementsHeader()->capacity; - } bool makeElementsSparse(JSContext *cx) { JS_NEW_OBJECT_REPRESENTATION_ONLY(); @@ -1210,7 +1194,6 @@ class ObjectImpl : public gc::BarrieredCell types::TypeObject *type() const { MOZ_ASSERT(!hasLazyType()); - AutoUnprotectCellUnderCompilationLock unprotect(this); return type_; } @@ -1218,26 +1201,17 @@ class ObjectImpl : public gc::BarrieredCell return reinterpret_cast(this)->numFixedSlots(); } - uint32_t numFixedSlotsForCompilation() const; - /* * Whether this is the only object which has its specified type. This * object will have its type constructed lazily as needed by analysis. */ - bool hasSingletonType() const { - AutoUnprotectCellUnderCompilationLock unprotect0(this); - AutoUnprotectCellUnderCompilationLock unprotect1(type_); - return !!type_->singleton; - } + bool hasSingletonType() const { return !!type_->singleton; } /* * Whether the object's type has not been constructed yet. If an object * might have a lazy type, use getType() below, otherwise type(). */ - bool hasLazyType() const { - AutoUnprotectCellUnderCompilationLock unprotect(this); - return type_->lazy(); - } + bool hasLazyType() const { return type_->lazy(); } uint32_t slotSpan() const { if (inDictionaryMode()) @@ -1394,7 +1368,7 @@ class ObjectImpl : public gc::BarrieredCell } const Value &getFixedSlot(uint32_t slot) const { - MOZ_ASSERT(slot < numFixedSlotsForCompilation()); + MOZ_ASSERT(slot < numFixedSlots()); return fixedSlots()[slot]; } @@ -1491,7 +1465,7 @@ class ObjectImpl : public gc::BarrieredCell * Private pointers are stored immediately after the last fixed slot of * the object. */ - MOZ_ASSERT(nfixed == numFixedSlotsForCompilation()); + MOZ_ASSERT(nfixed == numFixedSlots()); MOZ_ASSERT(hasPrivate()); HeapSlot *end = &fixedSlots()[nfixed]; return *reinterpret_cast(end); @@ -1565,10 +1539,6 @@ JS_ALWAYS_INLINE Zone * BarrieredCell::zoneFromAnyThread() const { const ObjectImpl* obj = static_cast(this); - - // If accesses to this object are permitted then so are accesses to its zone. - AutoUnprotectCell unprotect(obj->shape_); - return obj->shape_->zoneFromAnyThread(); } diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index a4c492b4e158..41b569aac345 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -412,10 +412,10 @@ class RegExpObject : public JSObject setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled)); } - bool ignoreCase() const { return getFixedSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); } - bool global() const { return getFixedSlot(GLOBAL_FLAG_SLOT).toBoolean(); } - bool multiline() const { return getFixedSlot(MULTILINE_FLAG_SLOT).toBoolean(); } - bool sticky() const { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); } + bool ignoreCase() const { return getSlot(IGNORE_CASE_FLAG_SLOT).toBoolean(); } + bool global() const { return getSlot(GLOBAL_FLAG_SLOT).toBoolean(); } + bool multiline() const { return getSlot(MULTILINE_FLAG_SLOT).toBoolean(); } + bool sticky() const { return getSlot(STICKY_FLAG_SLOT).toBoolean(); } void shared(RegExpGuard *g) const { JS_ASSERT(maybeShared() != nullptr); diff --git a/js/src/vm/Runtime-inl.h b/js/src/vm/Runtime-inl.h index ca6e3484768c..cfae42c3acbf 100644 --- a/js/src/vm/Runtime-inl.h +++ b/js/src/vm/Runtime-inl.h @@ -47,12 +47,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi Entry *entry = &entries[entry_]; JSObject *templateObj = reinterpret_cast(&entry->templateObject); - - // Do an end run around JSObject::type() to avoid doing AutoUnprotectCell - // on the templateObj, which is not a GC thing and can't use runtimeFromAnyThread. - types::TypeObject *type = templateObj->type_; - - if (type->isLongLivedForCachedAlloc()) + if (templateObj->type()->isLongLivedForCachedAlloc()) heap = gc::TenuredHeap; JSObject *obj = js_NewGCObject(cx, entry->kind, heap); diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 0f5219db8247..64b294ea9026 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -15,10 +15,6 @@ #include #include -#if defined(DEBUG) && !defined(XP_WIN) -# include -#endif - #include "jsatom.h" #include "jsdtoa.h" #include "jsgc.h" @@ -266,7 +262,6 @@ JSRuntime::JSRuntime(JSUseHelperThreads useHelperThreads) decimalSeparator(0), numGrouping(0), #endif - heapProtected_(false), mathCache_(nullptr), activeCompilations_(0), keepAtoms_(0), @@ -793,76 +788,6 @@ JSRuntime::activeGCInAtomsZone() return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted(); } -#if defined(DEBUG) && !defined(XP_WIN) - -AutoProtectHeapForCompilation::AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) - : runtime(rt) -{ - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - - JS_ASSERT(!runtime->heapProtected_); - runtime->heapProtected_ = true; - - for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) { - Chunk *chunk = r.front(); - // Note: Don't protect the last page in the chunk, which stores - // immutable info and needs to be accessible for runtimeFromAnyThread() - // in AutoUnprotectCell. - if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_NONE)) - MOZ_CRASH(); - } -} - -AutoProtectHeapForCompilation::~AutoProtectHeapForCompilation() -{ - JS_ASSERT(runtime->heapProtected_); - JS_ASSERT(runtime->unprotectedArenas.empty()); - runtime->heapProtected_ = false; - - for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) { - Chunk *chunk = r.front(); - if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_READ | PROT_WRITE)) - MOZ_CRASH(); - } -} - -AutoUnprotectCell::AutoUnprotectCell(const Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) - : runtime(cell->runtimeFromAnyThread()), arena(nullptr) -{ - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - - if (!runtime->heapProtected_) - return; - - ArenaHeader *base = cell->arenaHeader(); - for (size_t i = 0; i < runtime->unprotectedArenas.length(); i++) { - if (base == runtime->unprotectedArenas[i]) - return; - } - - arena = base; - - if (mprotect(arena, sizeof(Arena), PROT_READ | PROT_WRITE)) - MOZ_CRASH(); - - if (!runtime->unprotectedArenas.append(arena)) - MOZ_CRASH(); -} - -AutoUnprotectCell::~AutoUnprotectCell() -{ - if (!arena) - return; - - if (mprotect(arena, sizeof(Arena), PROT_NONE)) - MOZ_CRASH(); - - JS_ASSERT(arena == runtime->unprotectedArenas.back()); - runtime->unprotectedArenas.popBack(); -} - -#endif // DEBUG && !XP_WIN - #ifdef JS_WORKER_THREADS void diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 7f5d6fad3e5e..eb76993eb61e 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -677,7 +677,6 @@ class MarkingValidator; typedef Vector ZoneVector; class AutoLockForExclusiveAccess; -class AutoProtectHeapForCompilation; void RecomputeStackLimit(JSRuntime *rt, StackKind kind); @@ -1431,19 +1430,6 @@ struct JSRuntime : public JS::shadow::Runtime, const char *numGrouping; #endif - private: - friend class js::AutoProtectHeapForCompilation; - friend class js::AutoUnprotectCell; - mozilla::DebugOnly heapProtected_; -#ifdef DEBUG - js::Vector unprotectedArenas; - - public: - bool heapProtected() { - return heapProtected_; - } -#endif - private: js::MathCache *mathCache_; js::MathCache *createMathCache(JSContext *cx); @@ -2030,23 +2016,6 @@ class RuntimeAllocPolicy extern const JSSecurityCallbacks NullSecurityCallbacks; -class AutoProtectHeapForCompilation -{ - public: -#if defined(DEBUG) && !defined(XP_WIN) - JSRuntime *runtime; - - AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM); - ~AutoProtectHeapForCompilation(); -#else - AutoProtectHeapForCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } -#endif - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - } /* namespace js */ #ifdef _MSC_VER diff --git a/js/src/vm/ScopeObject-inl.h b/js/src/vm/ScopeObject-inl.h index e72d0731df2d..cfb878a9038c 100644 --- a/js/src/vm/ScopeObject-inl.h +++ b/js/src/vm/ScopeObject-inl.h @@ -74,12 +74,9 @@ StaticScopeIter::scopeShape() const { JS_ASSERT(hasDynamicScopeObject()); JS_ASSERT(type() != NAMED_LAMBDA); - if (type() == BLOCK) { - AutoUnprotectCell unprotect(&block()); - return block().lastProperty(); - } - AutoUnprotectCell unprotect(funScript()); - return funScript()->bindings.callObjShape(); + return type() == BLOCK + ? block().lastProperty() + : funScript()->bindings.callObjShape(); } template diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index ddae036e96b3..7686b7121229 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -35,7 +35,7 @@ typedef Rooted RootedArgumentsObject; static JSObject * InnermostStaticScope(JSScript *script, jsbytecode *pc) { - JS_ASSERT(pc >= script->getCode() && pc < script->getCode() + script->getLength()); + JS_ASSERT(pc >= script->code && pc < script->code + script->length); JS_ASSERT(JOF_OPTYPE(*pc) == JOF_SCOPECOORD); uint32_t blockIndex = GET_UINT32_INDEX(pc + 2 * sizeof(uint16_t)); @@ -68,7 +68,7 @@ js::ScopeCoordinateName(JSScript *script, jsbytecode *pc) ScopeCoordinate sc(pc); while (r.front().slot() != sc.slot) r.popFront(); - jsid id = r.front().propidRaw(); + jsid id = r.front().propid(); /* Beware nameless destructuring formal. */ if (!JSID_IS_ATOM(id)) diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 6f50e88a854d..3c65f296e184 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -181,8 +181,7 @@ class ScopeObject : public JSObject * enclosing scope of a ScopeObject is necessarily non-null. */ inline JSObject &enclosingScope() const { - AutoUnprotectCell unprotect(this); - return getFixedSlot(SCOPE_CHAIN_SLOT).toObject(); + return getReservedSlot(SCOPE_CHAIN_SLOT).toObject(); } void setEnclosingScope(HandleObject obj); @@ -233,11 +232,10 @@ class CallObject : public ScopeObject /* True if this is for a strict mode eval frame. */ bool isForEval() const { - AutoUnprotectCell unprotect(this); - JS_ASSERT(getFixedSlot(CALLEE_SLOT).isObjectOrNull()); - JS_ASSERT_IF(getFixedSlot(CALLEE_SLOT).isObject(), - getFixedSlot(CALLEE_SLOT).toObject().is()); - return getFixedSlot(CALLEE_SLOT).isNull(); + JS_ASSERT(getReservedSlot(CALLEE_SLOT).isObjectOrNull()); + JS_ASSERT_IF(getReservedSlot(CALLEE_SLOT).isObject(), + getReservedSlot(CALLEE_SLOT).toObject().is()); + return getReservedSlot(CALLEE_SLOT).isNull(); } /* @@ -245,8 +243,7 @@ class CallObject : public ScopeObject * only be called if !isForEval.) */ JSFunction &callee() const { - AutoUnprotectCell unprotect(this); - return getFixedSlot(CALLEE_SLOT).toObject().as(); + return getReservedSlot(CALLEE_SLOT).toObject().as(); } /* Get/set the aliased variable referred to by 'bi'. */ @@ -336,7 +333,7 @@ class BlockObject : public NestedScopeObject /* Return the number of variables associated with this block. */ uint32_t slotCount() const { - return propertyCountForCompilation(); + return propertyCount(); } /* @@ -371,8 +368,7 @@ class StaticBlockObject : public BlockObject /* See StaticScopeIter comment. */ JSObject *enclosingStaticScope() const { - AutoUnprotectCell unprotect(this); - return getFixedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull(); + return getReservedSlot(SCOPE_CHAIN_SLOT).toObjectOrNull(); } /* @@ -402,10 +398,7 @@ class StaticBlockObject : public BlockObject * variable of the block isAliased. */ bool needsClone() { - // The first variable slot will always indicate whether the object has - // any aliased vars. Bypass slotValue() to allow testing this off thread. - AutoUnprotectCell unprotect(this); - return !getFixedSlot(RESERVED_SLOTS).isFalse(); + return !slotValue(0).isFalse(); } /* Frontend-only functions ***********************************************/ diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 111b452f91f7..6b2313b74623 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -194,7 +194,7 @@ ShapeTable::search(jsid id, bool adding) /* Hit: return entry. */ shape = SHAPE_CLEAR_COLLISION(stored); - if (shape && shape->propidRaw() == id) + if (shape && shape->propid() == id) return spp; /* Collision: double hash. */ diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 0cbf05452e35..975035b91424 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -1033,15 +1033,11 @@ class Shape : public gc::BarrieredCell void popFront() { JS_ASSERT(!empty()); - AutoUnprotectCell unprotect(cursor); cursor = cursor->parent; } }; - const Class *getObjectClass() const { - AutoUnprotectCell unprotect(base()); - return base()->clasp; - } + const Class *getObjectClass() const { return base()->clasp; } JSObject *getObjectParent() const { return base()->parent; } JSObject *getObjectMetadata() const { return base()->metadata; } @@ -1098,15 +1094,12 @@ class Shape : public gc::BarrieredCell PUBLIC_FLAGS = HAS_SHORTID }; - bool inDictionary() const { - AutoUnprotectCell unprotect(this); - return (flags & IN_DICTIONARY) != 0; - } + bool inDictionary() const { return (flags & IN_DICTIONARY) != 0; } unsigned getFlags() const { return flags & PUBLIC_FLAGS; } bool hasShortID() const { return (flags & HAS_SHORTID) != 0; } PropertyOp getter() const { return base()->rawGetter; } - bool hasDefaultGetter() const { return !base()->rawGetter; } + bool hasDefaultGetter() const { return !base()->rawGetter; } PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; } JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return base()->getterObj; } @@ -1164,33 +1157,19 @@ class Shape : public gc::BarrieredCell BaseShape *base() const { return base_.get(); } - bool hasSlot() const { - AutoUnprotectCell unprotect(this); - return (attrs & JSPROP_SHARED) == 0; - } + bool hasSlot() const { return (attrs & JSPROP_SHARED) == 0; } uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); } - uint32_t maybeSlot() const { - // Note: Reading a shape's slot off thread can race against main thread - // updates to the number of linear searches on the shape, which is - // stored in the same slotInfo field. We tolerate this. - AutoUnprotectCell unprotect(this); - return slotInfo & SLOT_MASK; - } + uint32_t maybeSlot() const { return slotInfo & SLOT_MASK; } bool isEmptyShape() const { - AutoUnprotectCell unprotect(this); JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot()); return JSID_IS_EMPTY(propid_); } - uint32_t slotSpan(const Class *clasp) const { - JS_ASSERT(!inDictionary()); - uint32_t free = JSSLOT_FREE(clasp); - return hasMissingSlot() ? free : Max(free, maybeSlot() + 1); - } - uint32_t slotSpan() const { - return slotSpan(getObjectClass()); + JS_ASSERT(!inDictionary()); + uint32_t free = JSSLOT_FREE(getObjectClass()); + return hasMissingSlot() ? free : Max(free, maybeSlot() + 1); } void setSlot(uint32_t slot) { @@ -1200,8 +1179,6 @@ class Shape : public gc::BarrieredCell } uint32_t numFixedSlots() const { - // Note: The same race applies here as in maybeSlot(). - AutoUnprotectCell unprotect(this); return (slotInfo >> FIXED_SLOTS_SHIFT); } @@ -1223,18 +1200,12 @@ class Shape : public gc::BarrieredCell } const EncapsulatedId &propid() const { - AutoUnprotectCell unprotect(this); JS_ASSERT(!isEmptyShape()); JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; } EncapsulatedId &propidRef() { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; } - jsid propidRaw() const { - AutoUnprotectCell unprotect(this); - return propid(); - } - int16_t shortid() const { JS_ASSERT(hasShortID()); return maybeShortid(); } int16_t maybeShortid() const { return shortid_; } @@ -1249,7 +1220,6 @@ class Shape : public gc::BarrieredCell bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; } bool writable() const { // JS_ASSERT(isDataDescriptor()); - AutoUnprotectCell unprotect(this); return (attrs & JSPROP_READONLY) == 0; } bool hasGetterValue() const { return attrs & JSPROP_GETTER; } @@ -1287,27 +1257,13 @@ class Shape : public gc::BarrieredCell if (hasTable()) return table().entryCount; + Shape *shape = this; uint32_t count = 0; - for (Shape::Range r(this); !r.empty(); r.popFront()) + for (Shape::Range r(shape); !r.empty(); r.popFront()) ++count; return count; } - uint32_t entryCountForCompilation() { - JS_ASSERT(!inDictionary()); - - uint32_t count = 0; - - for (Shape *shape = this; shape; ) { - AutoUnprotectCell unprotect(shape); - if (!shape->isEmptyShape()) - ++count; - shape = shape->parent; - } - - return count; - } - bool isBigEnoughForAShapeTable() { JS_ASSERT(!hasTable()); Shape *shape = this; @@ -1638,11 +1594,9 @@ Shape::searchLinear(jsid id) */ JS_ASSERT(!inDictionary()); - for (Shape *shape = this; shape; ) { - AutoUnprotectCell unprotect(shape); + for (Shape *shape = this; shape; shape = shape->parent) { if (shape->propidRef() == id) return shape; - shape = shape->parent; } return nullptr; diff --git a/js/src/vm/String.h b/js/src/vm/String.h index 2004abe7192b..ea4b7ca43638 100644 --- a/js/src/vm/String.h +++ b/js/src/vm/String.h @@ -394,7 +394,6 @@ class JSString : public js::gc::BarrieredCell JS_ALWAYS_INLINE JSAtom &asAtom() const { - js::AutoUnprotectCell unprotect(this); JS_ASSERT(isAtom()); return *(JSAtom *)this; } @@ -1130,7 +1129,6 @@ JSString::base() const inline js::PropertyName * JSAtom::asPropertyName() { - js::AutoUnprotectCell unprotect(this); #ifdef DEBUG uint32_t dummy; JS_ASSERT(!isIndex(&dummy)); diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index ecb471521b42..848512a43dfc 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -326,11 +326,9 @@ class TypedArrayObject : public ArrayBufferViewObject return tarr->getFixedSlot(BYTEOFFSET_SLOT); } static Value byteLengthValue(TypedArrayObject *tarr) { - AutoUnprotectCellUnderCompilationLock unprotect(tarr); return tarr->getFixedSlot(BYTELENGTH_SLOT); } static Value lengthValue(TypedArrayObject *tarr) { - AutoUnprotectCellUnderCompilationLock unprotect(tarr); return tarr->getFixedSlot(LENGTH_SLOT); } @@ -348,11 +346,9 @@ class TypedArrayObject : public ArrayBufferViewObject } uint32_t type() const { - AutoUnprotectCell unprotect(this); return getFixedSlot(TYPE_SLOT).toInt32(); } void *viewData() const { - AutoUnprotectCellUnderCompilationLock unprotect(this); return static_cast(getPrivate(DATA_SLOT)); } From b6196ef8b0b60358811b9fbe13b7dac4e70d27a7 Mon Sep 17 00:00:00 2001 From: Nicholas Cameron Date: Wed, 20 Nov 2013 20:27:23 +1300 Subject: [PATCH 027/268] Bug 939598. Always call BeginTransaction before EndTransaction. r=mattwoodrow --- gfx/layers/composite/LayerManagerComposite.cpp | 8 +++++--- gfx/layers/ipc/CompositorParent.cpp | 16 +++++++++++----- gfx/layers/ipc/CompositorParent.h | 3 ++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index 49d6a51a733a..cd4421f1cb97 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -168,10 +168,11 @@ LayerManagerComposite::BeginTransactionWithDrawTarget(DrawTarget* aTarget) bool LayerManagerComposite::EndEmptyTransaction(EndTransactionFlags aFlags) { - mInTransaction = false; - - if (!mRoot) + NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); + if (!mRoot) { + mInTransaction = false; return false; + } EndTransaction(nullptr, nullptr); return true; @@ -182,6 +183,7 @@ LayerManagerComposite::EndTransaction(DrawThebesLayerCallback aCallback, void* aCallbackData, EndTransactionFlags aFlags) { + NS_ASSERTION(mInTransaction, "Didn't call BeginTransaction?"); mInTransaction = false; #ifdef MOZ_LAYERS_HAVE_LOG diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index c1f4a32a33f3..60e708fe3f5e 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -500,6 +500,15 @@ CompositorParent::ScheduleComposition() void CompositorParent::Composite() +{ + if (CanComposite()) { + mLayerManager->BeginTransaction(); + } + CompositeInTransaction(); +} + +void +CompositorParent::CompositeInTransaction() { profiler_tracing("Paint", "Composite", TRACING_INTERVAL_START); PROFILER_LABEL("CompositorParent", "Composite"); @@ -564,7 +573,7 @@ CompositorParent::ComposeToTarget(DrawTarget* aTarget) mLayerManager->BeginTransactionWithDrawTarget(aTarget); // Since CanComposite() is true, Composite() must end the layers txn // we opened above. - Composite(); + CompositeInTransaction(); } bool @@ -629,10 +638,7 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, } } ScheduleComposition(); - LayerManagerComposite *layerComposite = mLayerManager->AsLayerManagerComposite(); - if (layerComposite) { - layerComposite->NotifyShadowTreeTransaction(); - } + mLayerManager->NotifyShadowTreeTransaction(); } void diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index be1fbfe5d87d..544500b8b720 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -230,7 +230,8 @@ protected: bool* aSuccess); virtual bool DeallocPLayerTransactionParent(PLayerTransactionParent* aLayers); virtual void ScheduleTask(CancelableTask*, int); - virtual void Composite(); + void Composite(); + void CompositeInTransaction(); virtual void ComposeToTarget(gfx::DrawTarget* aTarget); void SetEGLSurfaceSize(int width, int height); From 596ddb7c51c0b0eceec73e43d5a66bbc23c92a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kan-Ru=20Chen=20=28=E9=99=B3=E4=BE=83=E5=A6=82=29?= Date: Wed, 20 Nov 2013 11:04:36 +0800 Subject: [PATCH 028/268] Bug 940285 - Fix build with --disable-ion r=billm --HG-- extra : rebase_source : 91e9640d7bd41cc5054895cfa9656c93bdc03ba8 --- js/src/jsgc.cpp | 6 +++--- js/src/jsinfer.cpp | 8 +++++--- js/src/vm/Runtime.cpp | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index fffdd8040f7c..00988b1408e1 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1560,7 +1560,7 @@ ArenaLists::refillFreeList(ThreadSafeContext *cx, AllocKind thingKind) cx->asJSContext()->runtime()->gcHelperThread.waitBackgroundSweepEnd(); } } else { -#ifdef JS_THREADSAFE +#ifdef JS_WORKER_THREADS /* * If we're off the main thread, we try to allocate once and return * whatever value we get. First, though, we need to ensure the main @@ -4149,7 +4149,7 @@ AutoTraceSession::AutoTraceSession(JSRuntime *rt, js::HeapState heapState) if (rt->exclusiveThreadsPresent()) { // Lock the worker thread state when changing the heap state in the // presence of exclusive threads, to avoid racing with refillFreeList. -#ifdef JS_THREADSAFE +#ifdef JS_WORKER_THREADS AutoLockWorkerThreadState lock(*rt->workerThreadState); rt->heapState = heapState; #else @@ -4165,7 +4165,7 @@ AutoTraceSession::~AutoTraceSession() JS_ASSERT(runtime->isHeapBusy()); if (runtime->exclusiveThreadsPresent()) { -#ifdef JS_THREADSAFE +#ifdef JS_WORKER_THREADS AutoLockWorkerThreadState lock(*runtime->workerThreadState); runtime->heapState = prevState; diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index de5874f003ad..5c7f9e34d611 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -603,9 +603,11 @@ class types::CompilerConstraintList public: CompilerConstraintList(jit::TempAllocator &alloc) - : constraints(alloc), - frozenScripts(alloc), - failed_(false) + : failed_(false) +#ifdef JS_ION + , constraints(alloc) + , frozenScripts(alloc) +#endif {} void add(CompilerConstraint *constraint) { diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 64b294ea9026..d1c4774f1550 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -847,7 +847,7 @@ js::CurrentThreadCanAccessZone(Zone *zone) void JSRuntime::assertCanLock(RuntimeLock which) { -#ifdef JS_THREADSAFE +#ifdef JS_WORKER_THREADS // In the switch below, each case falls through to the one below it. None // of the runtime locks are reentrant, and when multiple locks are acquired // it must be done in the order below. From a0818a8b903cd76a78fce25110947a15b2a49ec3 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Sun, 17 Nov 2013 23:29:11 -0800 Subject: [PATCH 029/268] Bug 940215 - Build netwerk/cache2, ftp, and rtsp in unified mode. r=mcmanus --- netwerk/cache2/moz.build | 2 +- netwerk/protocol/ftp/moz.build | 2 +- netwerk/protocol/ftp/nsFtpConnectionThread.cpp | 6 +++--- netwerk/protocol/ftp/nsFtpControlConnection.cpp | 2 +- netwerk/protocol/rtsp/moz.build | 10 +++++++--- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/netwerk/cache2/moz.build b/netwerk/cache2/moz.build index a1983a4de769..acf93e81f909 100644 --- a/netwerk/cache2/moz.build +++ b/netwerk/cache2/moz.build @@ -20,7 +20,7 @@ EXPORTS += [ 'CacheStorageService.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'AppCacheStorage.cpp', 'CacheEntriesEnumerator.cpp', 'CacheEntry.cpp', diff --git a/netwerk/protocol/ftp/moz.build b/netwerk/protocol/ftp/moz.build index 366b32a6dfa4..566e08849c1a 100644 --- a/netwerk/protocol/ftp/moz.build +++ b/netwerk/protocol/ftp/moz.build @@ -19,7 +19,7 @@ EXPORTS.mozilla.net += [ 'FTPChannelParent.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'FTPChannelChild.cpp', 'FTPChannelParent.cpp', 'nsFTPChannel.cpp', diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp index 61c043c0ef3e..715392c4ebc1 100644 --- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp @@ -1556,12 +1556,12 @@ nsFtpState::R_pasv() { // nsIRequest methods: static inline -uint32_t NowInSeconds() +uint32_t GetFtpTime() { return uint32_t(PR_Now() / PR_USEC_PER_SEC); } -uint32_t nsFtpState::mSessionStartTime = NowInSeconds(); +uint32_t nsFtpState::mSessionStartTime = GetFtpTime(); /* Is this cache entry valid to use for reading? * Since we make up an expiration time for ftp, use the following rules: @@ -1620,7 +1620,7 @@ nsFtpState::CanReadCacheEntry() if (NS_FAILED(rv)) return false; - return (NowInSeconds() <= time); + return (GetFtpTime() <= time); } nsresult diff --git a/netwerk/protocol/ftp/nsFtpControlConnection.cpp b/netwerk/protocol/ftp/nsFtpControlConnection.cpp index ffaa555bed45..b9923c3a7d37 100644 --- a/netwerk/protocol/ftp/nsFtpControlConnection.cpp +++ b/netwerk/protocol/ftp/nsFtpControlConnection.cpp @@ -34,7 +34,7 @@ nsFtpControlConnection::OnInputStreamReady(nsIAsyncInputStream *stream) // Consume data whether we have a listener or not. uint64_t avail64; - uint32_t avail; + uint32_t avail = 0; nsresult rv = stream->Available(&avail64); if (NS_SUCCEEDED(rv)) { avail = (uint32_t)std::min(avail64, (uint64_t)sizeof(data)); diff --git a/netwerk/protocol/rtsp/moz.build b/netwerk/protocol/rtsp/moz.build index 91b4bbd57bb6..6997b795eafd 100644 --- a/netwerk/protocol/rtsp/moz.build +++ b/netwerk/protocol/rtsp/moz.build @@ -15,11 +15,17 @@ EXPORTS.mozilla.net += [ 'RtspHandler.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'controller/RtspController.cpp', 'controller/RtspControllerChild.cpp', 'controller/RtspControllerParent.cpp', 'controller/RtspMetaData.cpp', + 'RtspChannel.cpp', + 'RtspHandler.cpp', +] + +# Android sources +SOURCES += [ 'rtsp/AAMRAssembler.cpp', 'rtsp/AAVCAssembler.cpp', 'rtsp/AH263Assembler.cpp', @@ -34,8 +40,6 @@ SOURCES += [ 'rtsp/ARTSPConnection.cpp', 'rtsp/ASessionDescription.cpp', 'rtsp/RTSPSource.cpp', - 'RtspChannel.cpp', - 'RtspHandler.cpp', ] FAIL_ON_WARNINGS = True From 4be77ac908a01067255f51832b0e045476baa58d Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Sun, 17 Nov 2013 01:16:36 -0800 Subject: [PATCH 030/268] Bug 940218 - Build memory/jemalloc and friends in unified mode. r=glandium --- memory/build/moz.build | 6 +++--- memory/jemalloc/moz.build | 4 ++-- memory/mozalloc/moz.build | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/memory/build/moz.build b/memory/build/moz.build index f933a886a9c4..034f261adfef 100644 --- a/memory/build/moz.build +++ b/memory/build/moz.build @@ -14,18 +14,18 @@ if CONFIG['MOZ_REPLACE_MALLOC']: 'malloc_decls.h', 'replace_malloc.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'jemalloc_config.c', 'mozmemory_wrap.c', ] if CONFIG['MOZ_JEMALLOC3']: - SOURCES += [ + UNIFIED_SOURCES += [ 'mozjemalloc_compat.c', ] if CONFIG['MOZ_REPLACE_MALLOC']: - SOURCES += [ + UNIFIED_SOURCES += [ 'replace_malloc.c', ] diff --git a/memory/jemalloc/moz.build b/memory/jemalloc/moz.build index b40f981b4506..3e246c9fa326 100644 --- a/memory/jemalloc/moz.build +++ b/memory/jemalloc/moz.build @@ -4,7 +4,7 @@ # 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/. -SOURCES += [ +UNIFIED_SOURCES += [ 'src/src/arena.c', 'src/src/atomic.c', 'src/src/base.c', @@ -32,7 +32,7 @@ SOURCES += [ # Only OSX needs the zone allocation implementation, # but only if replace-malloc is not enabled. if CONFIG['OS_TARGET'] == 'Darwin' and not CONFIG['MOZ_REPLACE_MALLOC']: - SOURCES += [ + UNIFIED_SOURCES += [ 'src/src/zone.c', ] diff --git a/memory/mozalloc/moz.build b/memory/mozalloc/moz.build index 0f20f6d51ace..99cfff9630aa 100644 --- a/memory/mozalloc/moz.build +++ b/memory/mozalloc/moz.build @@ -32,7 +32,7 @@ if CONFIG['WRAP_STL_INCLUDES']: 'msvc_throw_wrapper.cpp', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'mozalloc.cpp', 'mozalloc_abort.cpp', 'mozalloc_oom.cpp', From 4084af6e4b8566105b4aee5f2e45093c1cd0a6d5 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Mon, 18 Nov 2013 21:39:08 -0800 Subject: [PATCH 031/268] Bug 940225 - Build docshell in unified mode. r=bz --- docshell/base/moz.build | 2 +- docshell/base/nsDocShellEnumerator.h | 7 +++++-- docshell/shistory/src/moz.build | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docshell/base/moz.build b/docshell/base/moz.build index 48f17f95e9f6..194cebba8d8c 100644 --- a/docshell/base/moz.build +++ b/docshell/base/moz.build @@ -47,7 +47,7 @@ EXPORTS.mozilla += [ 'LoadContext.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'LoadContext.cpp', 'nsAboutRedirector.cpp', 'nsDefaultURIFixup.cpp', diff --git a/docshell/base/nsDocShellEnumerator.h b/docshell/base/nsDocShellEnumerator.h index d3c3d9040619..523050218248 100644 --- a/docshell/base/nsDocShellEnumerator.h +++ b/docshell/base/nsDocShellEnumerator.h @@ -4,13 +4,15 @@ * 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 nsDocShellEnumerator_h___ +#define nsDocShellEnumerator_h___ + #include "nsISimpleEnumerator.h" #include "nsTArray.h" #include "nsIWeakReferenceUtils.h" class nsIDocShellTreeItem; - /* // {13cbc281-35ae-11d5-be5b-bde0edece43c} #define NS_DOCSHELL_FORWARDS_ENUMERATOR_CID \ @@ -105,5 +107,6 @@ public: protected: virtual nsresult BuildArrayRecursive(nsIDocShellTreeItem* inItem, nsTArray& inItemArray); - }; + +#endif // nsDocShellEnumerator_h___ diff --git a/docshell/shistory/src/moz.build b/docshell/shistory/src/moz.build index ce07450b34bd..462fce8f84c4 100644 --- a/docshell/shistory/src/moz.build +++ b/docshell/shistory/src/moz.build @@ -8,7 +8,7 @@ EXPORTS += [ 'nsSHEntryShared.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'nsSHEntry.cpp', 'nsSHEntryShared.cpp', 'nsSHistory.cpp', From fcb9c8238993cc68c2daacb930a8a6c29a5b181d Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Wed, 20 Nov 2013 10:15:56 +0900 Subject: [PATCH 032/268] Backed out changeset 4110a8986a2a (Bug 912371) due to Bug 940246 and Bug 940324 --- js/src/Makefile.in | 12 +-- js/src/aclocal.m4 | 1 - js/src/build/autoconf/codeset.m4 | 24 ----- js/src/configure.in | 155 +++++++------------------------ 4 files changed, 38 insertions(+), 154 deletions(-) delete mode 100644 js/src/build/autoconf/codeset.m4 diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 2268b20f8854..70cfacce2955 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -238,7 +238,7 @@ ifeq ($(OS_ARCH),WINNT) ICU_LIB_SUFFIX=d endif ICU_LIB_RENAME = $(foreach libname,$(ICU_LIB_NAMES),\ - cp -p intl/icu/target/lib/s$(libname)$(ICU_LIB_SUFFIX).lib intl/icu/target/lib/$(libname).lib;) + cp -p intl/icu/lib/s$(libname)$(ICU_LIB_SUFFIX).lib intl/icu/lib/$(libname).lib;) endif ifdef .PYMAKE @@ -254,17 +254,11 @@ endif # - Options for genrb: -k strict parsing; -R omit collation tailoring rules. buildicu: # ICU's build system is full of races, so force non-parallel build. -ifdef CROSS_COMPILE - +$(ICU_MAKE) -j1 -C intl/icu/host STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-k -R -C' -endif - +$(ICU_MAKE) -j1 -C intl/icu/target STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-k -R' + +$(ICU_MAKE) -j1 -C intl/icu STATIC_O=$(OBJ_SUFFIX) GENRBOPTS='-k -R' $(ICU_LIB_RENAME) distclean clean:: -ifdef CROSS_COMPILE - $(call SUBMAKE,$@,intl/icu/host) -endif - $(call SUBMAKE,$@,intl/icu/target) + $(call SUBMAKE,$@,intl/icu) endif endif diff --git a/js/src/aclocal.m4 b/js/src/aclocal.m4 index ef750a638da3..cf2063441ec2 100644 --- a/js/src/aclocal.m4 +++ b/js/src/aclocal.m4 @@ -11,7 +11,6 @@ builtin(include, build/autoconf/ccache.m4)dnl builtin(include, build/autoconf/wrapper.m4)dnl builtin(include, build/autoconf/pkg.m4)dnl builtin(include, build/autoconf/nspr.m4)dnl -builtin(include, build/autoconf/codeset.m4)dnl builtin(include, build/autoconf/altoptions.m4)dnl builtin(include, build/autoconf/mozprog.m4)dnl builtin(include, build/autoconf/mozheader.m4)dnl diff --git a/js/src/build/autoconf/codeset.m4 b/js/src/build/autoconf/codeset.m4 deleted file mode 100644 index 4dc1d50187c6..000000000000 --- a/js/src/build/autoconf/codeset.m4 +++ /dev/null @@ -1,24 +0,0 @@ -# codeset.m4 serial AM1 (gettext-0.10.40) -dnl Copyright (C) 2000-2002 Free Software Foundation, Inc. -dnl This file is free software, distributed under the terms of the GNU -dnl General Public License. As a special exception to the GNU General -dnl Public License, this file may be distributed as part of a program -dnl that contains a configuration script generated by Autoconf, under -dnl the same distribution terms as the rest of that program. - -dnl From Bruno Haible. - -AC_DEFUN([AM_LANGINFO_CODESET], -[ - AC_CACHE_CHECK([for nl_langinfo and CODESET], am_cv_langinfo_codeset, - [AC_TRY_LINK([#include ], - [char* cs = nl_langinfo(CODESET);], - am_cv_langinfo_codeset=yes, - am_cv_langinfo_codeset=no) - ]) - if test $am_cv_langinfo_codeset = yes; then - AC_DEFINE(HAVE_LANGINFO_CODESET, 1, - [Define if you have and nl_langinfo(CODESET).]) - HAVE_LANGINFO_CODESET=1 - fi -]) diff --git a/js/src/configure.in b/js/src/configure.in index a5596763dec8..f22895f078b6 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -2573,8 +2573,6 @@ dnl AC_CHECK_LIB(bind, res_ninit, AC_DEFINE(HAVE_RES_NINIT), dnl AC_CHECK_LIB(resolv, res_ninit, AC_DEFINE(HAVE_RES_NINIT))) fi -AM_LANGINFO_CODESET - AC_LANG_C dnl ********************** @@ -4198,7 +4196,7 @@ if test -n "$ENABLE_INTL_API"; then *) AC_MSG_ERROR([ECMAScript Internationalization API is not yet supported on this platform]) esac - MOZ_ICU_LIBS='$(call EXPAND_LIBNAME_PATH,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/target/lib)' + MOZ_ICU_LIBS='$(call EXPAND_LIBNAME_PATH,$(ICU_LIB_NAMES),$(DEPTH)/intl/icu/lib)' fi fi @@ -4228,94 +4226,33 @@ if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_REGULAR_EXPRESSIONS" ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_BREAK_ITERATION" - ICU_CROSS_BUILD_OPT="" ICU_SRCDIR="" - if test "$HOST_OS_ARCH" = "WINNT"; then - ICU_SRCDIR="--srcdir=$(cd $srcdir/../../intl/icu/source; pwd -W)" - fi - - if test "$CROSS_COMPILE"; then - # Building host tools. It is necessary to build target binary. - case "$HOST_OS_ARCH" in - Darwin) - ICU_TARGET=MacOSX - ;; - Linux) - ICU_TARGET=Linux - ;; - WINNT) - ICU_TARGET=MSYS/MSVC - ;; - *bsd*|dragonfly*) - ICU_TARGET=BSD - ;; - esac - - # Remove _DEPEND_CFLAGS from HOST_FLAGS to avoid configure error - HOST_ICU_CFLAGS="$HOST_CFLAGS" - HOST_ICU_CXXFLAGS="$HOST_CXXFLAGS" - - HOST_ICU_CFLAGS=`echo $HOST_ICU_CFLAGS | sed "s|$_DEPEND_CFLAGS||g"` - HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CFXXLAGS | sed "s|$_DEPEND_CFLAGS||g"` - - # ICU requires RTTI - if test "$GNU_CC"; then - HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CXXFLAGS | sed 's|-fno-rtti|-frtti|g'` - elif test "$_MSC_VER"; then - HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CXXFLAGS | sed 's|-GR-|-GR|g'` - fi - - HOST_ICU_BUILD_OPTS="" - if test -n "$MOZ_DEBUG"; then - HOST_ICU_BUILD_OPTS="$HOST_ICU_BUILD_OPTS --enable-debug" - fi - - abs_srcdir=`(cd $srcdir; pwd)` - mkdir -p $_objdir/intl/icu/host - (cd $_objdir/intl/icu/host - MOZ_SUBCONFIGURE_WRAP([.],[ - CC="$HOST_CC" CXX="$HOST_CXX" LD="$HOST_LD" \ - CFLAGS="$HOST_ICU_CFLAGS $HOST_OPTIMIZE_FLAGS" \ - CPPFLAGS="$ICU_CPPFLAGS" \ - CXXFLAGS="$HOST_ICU_CXXFLAGS $HOST_OPTIMZIE_FLAGS" \ - $SHELL $abs_srcdir/../../intl/icu/source/runConfigureICU \ - $HOST_ICU_BUILD_OPTS \ - $ICU_TARGET \ - dnl Shell quoting is fun. - ${ICU_SRCDIR+"$ICU_SRCDIR"} \ - --enable-static --disable-shared \ - --enable-extras=no --enable-icuio=no --enable-layout=no \ - --enable-tests=no --enable-samples=no || exit 1 - ]) - ) || exit 1 - - # generate config/icucross.mk - $GMAKE -C $_objdir/intl/icu/host/ config/icucross.mk - - # --with-cross-build requires absolute path - ICU_HOST_PATH=`cd $_objdir/intl/icu/host && pwd` - ICU_CROSS_BUILD_OPT="--with-cross-build=$ICU_HOST_PATH" - fi + # Set OS dependent options for ICU + case "$OS_TARGET" in + Darwin) + ICU_TARGET=MacOSX + ;; + Linux) + ICU_TARGET=Linux + ;; + WINNT) + ICU_TARGET=MSYS/MSVC + ICU_SRCDIR="--srcdir=$(cd $srcdir/../../intl/icu/source; pwd -W)" + ;; + DragonFly|FreeBSD|NetBSD|OpenBSD) + ICU_TARGET=BSD + ;; + esac # To reduce library size, use static linking ICU_LINK_OPTS="--enable-static --disable-shared" # Force the ICU static libraries to be position independent code - ICU_CFLAGS="$DSO_PIC_CFLAGS $CFLAGS" - ICU_CXXFLAGS="$DSO_PIC_CFLAGS $CXXFLAGS" + ICU_CFLAGS="$DSO_PIC_CFLAGS" + ICU_CXXFLAGS="$DSO_PIC_CFLAGS" ICU_BUILD_OPTS="" - if test -n "$MOZ_DEBUG" -o "MOZ_DEBUG_SYMBOLS"; then - ICU_CFLAGS="$ICU_CFLAGS $MOZ_DEBUG_FLAGS" - ICU_CXXFLAGS="$ICU_CXXFLAGS $MOZ_DEBUG_FLAGS" - ICU_LDFLAGS="$MOZ_DEBUG_LDFLAGS" - if test -z "$MOZ_DEBUG"; then - # To generate debug symbols, it requires MOZ_DEBUG_FLAGS. - # But, not debug build. - ICU_CFLAGS="$ICU_CFLAGS -UDEBUG -DNDEBUG" - ICU_CXXFLAGS="$ICU_CXXFLAGS -UDEBUG -DNDEBUG" - else - ICU_BUILD_OPTS="$ICU_BUILD_OPTS --enable-debug" - fi + if test -n "$MOZ_DEBUG"; then + ICU_BUILD_OPTS="$ICU_BUILD_OPTS --enable-debug" fi if test -z "$MOZ_OPTIMIZE"; then ICU_BUILD_OPTS="$ICU_BUILD_OPTS --disable-release" @@ -4324,43 +4261,21 @@ if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then ICU_CXXFLAGS="$ICU_CXXFLAGS $MOZ_OPTIMIZE_FLAGS" fi - if test "$am_cv_langinfo_codeset" = "no"; then - # ex. Android - ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_HAVE_NL_LANGINFO_CODESET=0" - fi - - # ICU requires RTTI - if test "$GNU_CC"; then - ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-fno-rtti|-frtti|g'` - else - if test "$_MSC_VER"; then - ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-GR-|-GR|g'` - fi - fi - - # We cannot use AC_OUTPUT_SUBDIRS since ICU tree is out of spidermonkey. - # When using AC_OUTPUT_SUBDIRS, objdir of ICU is out of objdir - # due to relative path. - # If building ICU moves into root of mozilla tree, we can use - # AC_OUTPUT_SUBDIR instead. - mkdir -p $_objdir/intl/icu/target - (cd $_objdir/intl/icu/target + abs_srcdir=`(cd $srcdir; pwd)` + mkdir -p $_objdir/intl/icu + (cd $_objdir/intl/icu MOZ_SUBCONFIGURE_WRAP([.],[ - AR="$AR" CC="$CC" CXX="$CXX" LD="$LD" \ - ARFLAGS="$ARFLAGS" \ - CPPFLAGS="$ICU_CPPFLAGS $CPPFLAGS" \ - CFLAGS="$ICU_CFLAGS" \ - CXXFLAGS="$ICU_CXXFLAGS" \ - LDFLAGS="$ICU_LDFLAGS $LDFLAGS" \ - $SHELL $_topsrcdir/../../intl/icu/source/configure \ - $ICU_BUILD_OPTS \ - $ICU_CROSS_BUILD_OPT \ - $ICU_LINK_OPTS \ - ${ICU_SRCDIR+"$ICU_SRCDIR"} \ - --build=$build --host=$target \ - --disable-extras --disable-icuio --disable-layout \ - --disable-tests --disable-samples || exit 1 - ]) + CC="$CC" CXX="$CXX" \ + CFLAGS="$ICU_CFLAGS" CPPFLAGS="$ICU_CPPFLAGS" CXXFLAGS="$ICU_CXXFLAGS" \ + $SHELL $abs_srcdir/../../intl/icu/source/runConfigureICU \ + $ICU_BUILD_OPTS \ + $ICU_TARGET \ + $ICU_LINK_OPTS \ +dnl Shell quoting is fun. + ${ICU_SRCDIR+"$ICU_SRCDIR"} \ + --enable-extras=no --enable-icuio=no --enable-layout=no \ + --enable-tests=no --enable-samples=no || exit 1 + ]) ) || exit 1 fi From 59af5cdce40b315035394b26545f2cd7a9f1adb9 Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Mon, 12 Aug 2013 13:27:53 -0400 Subject: [PATCH 033/268] Bug 902909 - Use fallible allocation when interfacing with Snappy. r=sicking,khuey (original patch by khuey, updated by janv) --- dom/indexedDB/IDBObjectStore.cpp | 12 +++++++++--- dom/indexedDB/OpenDatabaseHelper.cpp | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 6acdc5b299d7..177ca1b9efac 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -55,6 +55,7 @@ using namespace mozilla::dom; using namespace mozilla::dom::indexedDB::ipc; using mozilla::dom::quota::FileOutputStream; using mozilla::ErrorResult; +using mozilla::fallible_t; BEGIN_INDEXEDDB_NAMESPACE @@ -1220,6 +1221,8 @@ IDBObjectStore::GetStructuredCloneReadInfoFromStatement( const char* compressed = reinterpret_cast(blobData); size_t compressedLength = size_t(blobDataLength); + static const fallible_t fallible = fallible_t(); + size_t uncompressedLength; if (!snappy::GetUncompressedLength(compressed, compressedLength, &uncompressedLength)) { @@ -1227,7 +1230,8 @@ IDBObjectStore::GetStructuredCloneReadInfoFromStatement( return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } - nsAutoArrayPtr uncompressed(new char[uncompressedLength]); + nsAutoArrayPtr uncompressed(new (fallible) char[uncompressedLength]); + NS_ENSURE_TRUE(uncompressed, NS_ERROR_OUT_OF_MEMORY); if (!snappy::RawUncompress(compressed, compressedLength, uncompressed.get())) { @@ -1409,7 +1413,7 @@ StructuredCloneReadString(JSStructuredCloneReader* aReader, } length = SwapBytes(length); - if (!aString.SetLength(length, mozilla::fallible_t())) { + if (!aString.SetLength(length, fallible_t())) { NS_WARNING("Out of memory?"); return false; } @@ -3213,10 +3217,12 @@ AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) reinterpret_cast(mCloneWriteInfo.mCloneBuffer.data()); size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes(); + static const fallible_t fallible = fallible_t(); size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength); // This will hold our compressed data until the end of the method. The // BindBlobByName function will copy it. - nsAutoArrayPtr compressed(new char[compressedLength]); + nsAutoArrayPtr compressed(new (fallible) char[compressedLength]); + NS_ENSURE_TRUE(compressed, NS_ERROR_OUT_OF_MEMORY); snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(), &compressedLength); diff --git a/dom/indexedDB/OpenDatabaseHelper.cpp b/dom/indexedDB/OpenDatabaseHelper.cpp index 1dc369793c9a..8d62eb894e34 100644 --- a/dom/indexedDB/OpenDatabaseHelper.cpp +++ b/dom/indexedDB/OpenDatabaseHelper.cpp @@ -881,8 +881,10 @@ public: rv = aArguments->GetSharedBlob(0, &uncompressedLength, &uncompressed); NS_ENSURE_SUCCESS(rv, rv); + static const fallible_t fallible = fallible_t(); size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength); - nsAutoArrayPtr compressed(new char[compressedLength]); + nsAutoArrayPtr compressed(new (fallible) char[compressedLength]); + NS_ENSURE_TRUE(compressed, NS_ERROR_OUT_OF_MEMORY); snappy::RawCompress(reinterpret_cast(uncompressed), uncompressedLength, compressed.get(), From d7f090b746ec3e99849bd71be93052bf76db8335 Mon Sep 17 00:00:00 2001 From: John Daggett Date: Wed, 20 Nov 2013 17:14:13 +0900 Subject: [PATCH 034/268] Bug 940778 - disallow counter names named none, default or other css-wide keywords. r=dholbert --- layout/style/nsCSSParser.cpp | 10 ++++++++++ layout/style/test/property_database.js | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/layout/style/nsCSSParser.cpp b/layout/style/nsCSSParser.cpp index 6ee5359d85c9..92227cd7ab57 100644 --- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -8525,6 +8525,16 @@ CSSParserImpl::ParseCounterData(nsCSSProperty aPropID) nsCSSValuePairList *cur = value.SetPairListValue(); for (;;) { + // check for "none", "default" and the CSS-wide keywords, + // which can't be used as counter names + nsCSSKeyword keyword = nsCSSKeywords::LookupKeyword(mToken.mIdent); + if (keyword == eCSSKeyword_inherit || + keyword == eCSSKeyword_default || + keyword == eCSSKeyword_none || + keyword == eCSSKeyword_unset || + keyword == eCSSKeyword_initial) { + return false; + } cur->mXValue.SetStringValue(mToken.mIdent, eCSSUnit_Ident); if (!GetToken(true)) { break; diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 91d8e897ebb3..97de06a1964c 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -2321,7 +2321,7 @@ var gCSSProperties = { type: CSS_TYPE_LONGHAND, initial_values: [ "none" ], other_values: [ "foo 1", "bar", "foo 3 bar baz 2", "\\32 1", "-\\32 1", "-c 1", "\\32 1", "-\\32 1", "\\2 1", "-\\2 1", "-c 1", "\\2 1", "-\\2 1", "-\\7f \\9e 1" ], - invalid_values: [] + invalid_values: [ "none foo", "none foo 3", "foo none", "foo 3 none" ] }, "counter-reset": { domProp: "counterReset", @@ -2329,7 +2329,7 @@ var gCSSProperties = { type: CSS_TYPE_LONGHAND, initial_values: [ "none" ], other_values: [ "foo 1", "bar", "foo 3 bar baz 2", "\\32 1", "-\\32 1", "-c 1", "\\32 1", "-\\32 1", "\\2 1", "-\\2 1", "-c 1", "\\2 1", "-\\2 1", "-\\7f \\9e 1" ], - invalid_values: [] + invalid_values: [ "none foo", "none foo 3", "foo none", "foo 3 none" ] }, "cursor": { domProp: "cursor", From bd7840a8655bfd59df9a66415ce4ba403aff9421 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 11 Nov 2013 18:37:55 +1100 Subject: [PATCH 035/268] Bug 937012 - Replace the busted find_vanilla_new_calls script with the much better check_vanilla_allocations.py. r=evilpie,gps. --HG-- extra : rebase_source : 08f0cf236a1f4269685f38b510e26f76cbf56972 --- config/check_vanilla_allocations.py | 159 +++++++++++++++++++++ config/find_vanilla_new_calls | 80 ----------- js/src/Makefile.in | 16 ++- js/src/config/check_vanilla_allocations.py | 159 +++++++++++++++++++++ js/src/config/find_vanilla_new_calls | 80 ----------- js/src/jsutil.cpp | 43 ++++++ 6 files changed, 371 insertions(+), 166 deletions(-) create mode 100644 config/check_vanilla_allocations.py delete mode 100755 config/find_vanilla_new_calls create mode 100644 js/src/config/check_vanilla_allocations.py delete mode 100755 js/src/config/find_vanilla_new_calls diff --git a/config/check_vanilla_allocations.py b/config/check_vanilla_allocations.py new file mode 100644 index 000000000000..74ea5e61d0c0 --- /dev/null +++ b/config/check_vanilla_allocations.py @@ -0,0 +1,159 @@ +# vim: set ts=8 sts=4 et sw=4 tw=79: +# 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/. + +#---------------------------------------------------------------------------- +# All heap allocations in SpiderMonkey must go through js_malloc, js_calloc, +# js_realloc, and js_free. This is so that any embedder who uses a custom +# allocator (by defining JS_USE_CUSTOM_ALLOCATOR) will see all heap allocation +# go through that custom allocator. +# +# Therefore, the presence of any calls to "vanilla" allocation/free functions +# (e.g. malloc(), free()) is a bug. +# +# This script checks for the presence of such disallowed vanilla +# allocation/free function in SpiderMonkey when it's built as a library. It +# relies on |nm| from the GNU binutils, and so only works on Linux, but one +# platform is good enough to catch almost all violations. +# +# This checking is only 100% reliable in a JS_USE_CUSTOM_ALLOCATOR build in +# which the default definitions of js_malloc et al (in Utility.h) -- which call +# malloc et al -- are replaced with empty definitions. This is because the +# presence and possible inlining of the default js_malloc et al can cause +# malloc/calloc/realloc/free calls show up in unpredictable places. +# +# Unfortunately, that configuration cannot be tested on Mozilla's standard +# testing infrastructure. Instead, by default this script only tests that none +# of the other vanilla allocation/free functions (operator new, memalign, etc) +# are present. If given the --aggressive flag, it will also check for +# malloc/calloc/realloc/free. +# +# Note: We don't check for |operator delete| and |operator delete[]|. These +# can be present somehow due to virtual destructors, but this is not too +# because vanilla delete/delete[] calls don't make sense without corresponding +# vanilla new/new[] calls, and any explicit calls will be caught by Valgrind's +# mismatched alloc/free checking. +#---------------------------------------------------------------------------- + +from __future__ import print_function + +import argparse +import re +import subprocess +import sys + +# The obvious way to implement this script is to search for occurrences of +# malloc et al, succeed if none are found, and fail is some are found. +# However, "none are found" does not necessarily mean "none are present" -- +# this script could be buggy. (Or the output format of |nm| might change in +# the future.) +# +# So jsutil.cpp deliberately contains a (never-called) function that contains a +# single use of all the vanilla allocation/free functions. And this script +# fails if it (a) finds uses of those functions in files other than jsutil.cpp, +# *or* (b) fails to find them in jsutil.cpp. + +# Tracks overall success of the test. +has_failed = False + + +def fail(msg): + print('TEST-UNEXPECTED-FAIL | check_vanilla_allocations.py |', msg) + global has_failed + has_failed = True + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--aggressive', action='store_true', + help='also check for malloc, calloc, realloc and free') + parser.add_argument('file', type=str, + help='name of the file to check') + args = parser.parse_args() + + # Run |nm|. Options: + # -u: show only undefined symbols + # -C: demangle symbol names + # -l: show a filename and line number for each undefined symbol + cmd = ['nm', '-u', '-C', '-l', args.file] + lines = subprocess.check_output(cmd, universal_newlines=True, + stderr=subprocess.PIPE).split('\n') + + # alloc_fns contains all the vanilla allocation/free functions that we look + # for. Regexp chars are escaped appropriately. + + alloc_fns = [ + # Matches |operator new(unsigned T)|, where |T| is |int| or |long|. + r'operator new\(unsigned', + + # Matches |operator new[](unsigned T)|, where |T| is |int| or |long|. + r'operator new\[\]\(unsigned', + + r'memalign', + # These two aren't available on all Linux configurations. + #r'posix_memalign', + #r'aligned_alloc', + r'valloc', + r'strdup' + ] + + if args.aggressive: + alloc_fns += [ + r'malloc', + r'calloc', + r'realloc', + r'free' + ] + + # This is like alloc_fns, but regexp chars are not escaped. + alloc_fns_unescaped = [fn.translate(None, r'\\') for fn in alloc_fns] + + # This regexp matches the relevant lines in the output of |nm|, which look + # like the following. + # + # U malloc /path/to/objdir/dist/include/js/Utility.h:142 + # + alloc_fns_re = r'U (' + r'|'.join(alloc_fns) + r').*\/([\w\.]+):(\d+)$' + + # This tracks which allocation/free functions have been seen in jsutil.cpp. + jsutil_cpp = set([]) + + for line in lines: + m = re.search(alloc_fns_re, line) + if m is None: + continue + + fn = m.group(1) + filename = m.group(2) + linenum = m.group(3) + if filename == 'jsutil.cpp': + jsutil_cpp.add(fn) + else: + # An allocation is present in a non-special file. Fail! + fail("'" + fn + "' present at " + filename + ':' + linenum) + + + # Check that all functions we expect are used in jsutil.cpp. (This will + # fail if the function-detection code breaks at any point.) + for fn in alloc_fns_unescaped: + if fn not in jsutil_cpp: + fail("'" + fn + "' isn't used as expected in jsutil.cpp") + else: + jsutil_cpp.remove(fn) + + # This should never happen, but check just in case. + if jsutil_cpp: + fail('unexpected allocation fns used in jsutil.cpp: ' + + ', '.join(jsutil_cpp)) + + if has_failed: + sys.exit(1) + + print('TEST-PASS | check_vanilla_allocations.py | ok') + sys.exit(0) + + +if __name__ == '__main__': + main() + diff --git a/config/find_vanilla_new_calls b/config/find_vanilla_new_calls deleted file mode 100755 index 320abc1403eb..000000000000 --- a/config/find_vanilla_new_calls +++ /dev/null @@ -1,80 +0,0 @@ -# /bin/bash - -#---------------------------------------------------------------------------- -# We must avoid using the vanilla new/new[] operators (and consequently, the -# vanilla delete/delete[] operators) in SpiderMonkey, see bug 624878 for why. -# -# This script: -# - Detects if any of the vanilla new/new[] operators are used in a file. -# Its exit code is 1 if it found some, and 0 if it didn't. -# - Doesn't detect delete/delete[] because it appears they can be present -# somehow due to virtual destructors, but this is ok because vanilla -# delete/delete[] calls don't make sense without corresponding new/new[] -# calls, and any explicit calls will be caught by Valgrind's mismatched -# alloc/free checking. -# - Doesn't detect the 'nothrow' variants, which are ok but probably still -# best avoided. -# - Is designed to only run on Linux (though it may also work on Mac); one -# platform will be enough to catch any violations. -# -# If this script fails: -# - You need to find the uses of vanilla new/delete and replace them with -# {js::OffTheBooks,JSContext,JSRuntime}::{new_,/array_new}. -# - Run this script on each of the .o files, that should narrow it down. -# - After that, one way to find them is to run 'objdump -r -C' on the -# relevant .o files. For example, you might search for 'operator new' and -# find a record like this: -# -# RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]: -# OFFSET TYPE VALUE -# 00000009 R_386_PC32 __i686.get_pc_thunk.bx -# 0000000f R_386_GOTPC _GLOBAL_OFFSET_TABLE_ -# 0000001b R_386_PLT32 operator new(unsigned int) -# 0000002e R_386_PC32 JSC::ExecutablePool::ExecutablePool(unsigned int) -# 0000004a R_386_PC32 JSC::ExecutablePool::~ExecutablePool() -# 00000052 R_386_PLT32 operator delete(void*) -# -# This says that vanilla 'new' and 'delete' are both used in -# JSC::ExecutablePool::create(unsigned int). This doesn't always work, -# though. (Nb: use 'c++filt' to demangle names like -# _ZN3JSC14ExecutablePool6createEj.) -# -# If that doesn't work, use grep. -#---------------------------------------------------------------------------- - -if [ -z $1 ] ; then - echo "usage: find_vanilla_new_calls " - exit 1 -fi - -file=$1 - -if [ ! -f $file ] ; then - echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | file '$file' not found" - exit 1 -fi - -tmpfile1=`mktemp` -tmpfile2=`mktemp` -nm -C $file > $tmpfile1 - -# Need to double-escape '[' and ']' to stop grep from interpreting them -# specially. -grep '^operator new(unsigned int)' $tmpfile1 >> $tmpfile2 -grep '^operator new(unsigned long)' $tmpfile1 >> $tmpfile2 -grep '^operator new\\[\\](unsigned int)' $tmpfile1 >> $tmpfile2 -grep '^operator new\\[\\](unsigned long)' $tmpfile1 >> $tmpfile2 -rm -f $tmpfile1 - -if [ -s $tmpfile2 ] ; then - echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | found calls are listed below" - cat $tmpfile2 - echo - rm -f $tmpfile2 - exit 1 -fi - -echo "TEST-PASS | find_vanilla_new_calls | ok" -echo - -exit 0 diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 70cfacce2955..cc7e38adadc4 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -268,14 +268,18 @@ endif ############################################# -# The "find any vanilla new/new[] calls" script is tailored to Linux, so -# only run it there. That should be enough to catch any such calls that -# creep in. -check-vanilla-new: - $(srcdir)/config/find_vanilla_new_calls $(LIBRARY) +# check_vanilla_allocations.py is tailored to Linux, so only run it there. +# That should be enough to catch any problems. +check-vanilla-allocations: + $(PYTHON) $(srcdir)/config/check_vanilla_allocations.py $(REAL_LIBRARY) + +# The "aggressive" variant will likely fail on some compiler/platform +# combinations, but is worth running by hand every once in a while. +check-vanilla-allocations-aggressive: + $(PYTHON) $(srcdir)/config/check_vanilla_allocations.py --aggressive $(REAL_LIBRARY) ifeq ($(OS_ARCH),Linux) -check:: check-vanilla-new +check:: check-vanilla-allocations endif # Help ensure that the number of OOM errors in SpiderMonkey doesn't increase. diff --git a/js/src/config/check_vanilla_allocations.py b/js/src/config/check_vanilla_allocations.py new file mode 100644 index 000000000000..74ea5e61d0c0 --- /dev/null +++ b/js/src/config/check_vanilla_allocations.py @@ -0,0 +1,159 @@ +# vim: set ts=8 sts=4 et sw=4 tw=79: +# 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/. + +#---------------------------------------------------------------------------- +# All heap allocations in SpiderMonkey must go through js_malloc, js_calloc, +# js_realloc, and js_free. This is so that any embedder who uses a custom +# allocator (by defining JS_USE_CUSTOM_ALLOCATOR) will see all heap allocation +# go through that custom allocator. +# +# Therefore, the presence of any calls to "vanilla" allocation/free functions +# (e.g. malloc(), free()) is a bug. +# +# This script checks for the presence of such disallowed vanilla +# allocation/free function in SpiderMonkey when it's built as a library. It +# relies on |nm| from the GNU binutils, and so only works on Linux, but one +# platform is good enough to catch almost all violations. +# +# This checking is only 100% reliable in a JS_USE_CUSTOM_ALLOCATOR build in +# which the default definitions of js_malloc et al (in Utility.h) -- which call +# malloc et al -- are replaced with empty definitions. This is because the +# presence and possible inlining of the default js_malloc et al can cause +# malloc/calloc/realloc/free calls show up in unpredictable places. +# +# Unfortunately, that configuration cannot be tested on Mozilla's standard +# testing infrastructure. Instead, by default this script only tests that none +# of the other vanilla allocation/free functions (operator new, memalign, etc) +# are present. If given the --aggressive flag, it will also check for +# malloc/calloc/realloc/free. +# +# Note: We don't check for |operator delete| and |operator delete[]|. These +# can be present somehow due to virtual destructors, but this is not too +# because vanilla delete/delete[] calls don't make sense without corresponding +# vanilla new/new[] calls, and any explicit calls will be caught by Valgrind's +# mismatched alloc/free checking. +#---------------------------------------------------------------------------- + +from __future__ import print_function + +import argparse +import re +import subprocess +import sys + +# The obvious way to implement this script is to search for occurrences of +# malloc et al, succeed if none are found, and fail is some are found. +# However, "none are found" does not necessarily mean "none are present" -- +# this script could be buggy. (Or the output format of |nm| might change in +# the future.) +# +# So jsutil.cpp deliberately contains a (never-called) function that contains a +# single use of all the vanilla allocation/free functions. And this script +# fails if it (a) finds uses of those functions in files other than jsutil.cpp, +# *or* (b) fails to find them in jsutil.cpp. + +# Tracks overall success of the test. +has_failed = False + + +def fail(msg): + print('TEST-UNEXPECTED-FAIL | check_vanilla_allocations.py |', msg) + global has_failed + has_failed = True + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--aggressive', action='store_true', + help='also check for malloc, calloc, realloc and free') + parser.add_argument('file', type=str, + help='name of the file to check') + args = parser.parse_args() + + # Run |nm|. Options: + # -u: show only undefined symbols + # -C: demangle symbol names + # -l: show a filename and line number for each undefined symbol + cmd = ['nm', '-u', '-C', '-l', args.file] + lines = subprocess.check_output(cmd, universal_newlines=True, + stderr=subprocess.PIPE).split('\n') + + # alloc_fns contains all the vanilla allocation/free functions that we look + # for. Regexp chars are escaped appropriately. + + alloc_fns = [ + # Matches |operator new(unsigned T)|, where |T| is |int| or |long|. + r'operator new\(unsigned', + + # Matches |operator new[](unsigned T)|, where |T| is |int| or |long|. + r'operator new\[\]\(unsigned', + + r'memalign', + # These two aren't available on all Linux configurations. + #r'posix_memalign', + #r'aligned_alloc', + r'valloc', + r'strdup' + ] + + if args.aggressive: + alloc_fns += [ + r'malloc', + r'calloc', + r'realloc', + r'free' + ] + + # This is like alloc_fns, but regexp chars are not escaped. + alloc_fns_unescaped = [fn.translate(None, r'\\') for fn in alloc_fns] + + # This regexp matches the relevant lines in the output of |nm|, which look + # like the following. + # + # U malloc /path/to/objdir/dist/include/js/Utility.h:142 + # + alloc_fns_re = r'U (' + r'|'.join(alloc_fns) + r').*\/([\w\.]+):(\d+)$' + + # This tracks which allocation/free functions have been seen in jsutil.cpp. + jsutil_cpp = set([]) + + for line in lines: + m = re.search(alloc_fns_re, line) + if m is None: + continue + + fn = m.group(1) + filename = m.group(2) + linenum = m.group(3) + if filename == 'jsutil.cpp': + jsutil_cpp.add(fn) + else: + # An allocation is present in a non-special file. Fail! + fail("'" + fn + "' present at " + filename + ':' + linenum) + + + # Check that all functions we expect are used in jsutil.cpp. (This will + # fail if the function-detection code breaks at any point.) + for fn in alloc_fns_unescaped: + if fn not in jsutil_cpp: + fail("'" + fn + "' isn't used as expected in jsutil.cpp") + else: + jsutil_cpp.remove(fn) + + # This should never happen, but check just in case. + if jsutil_cpp: + fail('unexpected allocation fns used in jsutil.cpp: ' + + ', '.join(jsutil_cpp)) + + if has_failed: + sys.exit(1) + + print('TEST-PASS | check_vanilla_allocations.py | ok') + sys.exit(0) + + +if __name__ == '__main__': + main() + diff --git a/js/src/config/find_vanilla_new_calls b/js/src/config/find_vanilla_new_calls deleted file mode 100755 index 320abc1403eb..000000000000 --- a/js/src/config/find_vanilla_new_calls +++ /dev/null @@ -1,80 +0,0 @@ -# /bin/bash - -#---------------------------------------------------------------------------- -# We must avoid using the vanilla new/new[] operators (and consequently, the -# vanilla delete/delete[] operators) in SpiderMonkey, see bug 624878 for why. -# -# This script: -# - Detects if any of the vanilla new/new[] operators are used in a file. -# Its exit code is 1 if it found some, and 0 if it didn't. -# - Doesn't detect delete/delete[] because it appears they can be present -# somehow due to virtual destructors, but this is ok because vanilla -# delete/delete[] calls don't make sense without corresponding new/new[] -# calls, and any explicit calls will be caught by Valgrind's mismatched -# alloc/free checking. -# - Doesn't detect the 'nothrow' variants, which are ok but probably still -# best avoided. -# - Is designed to only run on Linux (though it may also work on Mac); one -# platform will be enough to catch any violations. -# -# If this script fails: -# - You need to find the uses of vanilla new/delete and replace them with -# {js::OffTheBooks,JSContext,JSRuntime}::{new_,/array_new}. -# - Run this script on each of the .o files, that should narrow it down. -# - After that, one way to find them is to run 'objdump -r -C' on the -# relevant .o files. For example, you might search for 'operator new' and -# find a record like this: -# -# RELOCATION RECORDS FOR [.text._ZN3JSC14ExecutablePool6createEj]: -# OFFSET TYPE VALUE -# 00000009 R_386_PC32 __i686.get_pc_thunk.bx -# 0000000f R_386_GOTPC _GLOBAL_OFFSET_TABLE_ -# 0000001b R_386_PLT32 operator new(unsigned int) -# 0000002e R_386_PC32 JSC::ExecutablePool::ExecutablePool(unsigned int) -# 0000004a R_386_PC32 JSC::ExecutablePool::~ExecutablePool() -# 00000052 R_386_PLT32 operator delete(void*) -# -# This says that vanilla 'new' and 'delete' are both used in -# JSC::ExecutablePool::create(unsigned int). This doesn't always work, -# though. (Nb: use 'c++filt' to demangle names like -# _ZN3JSC14ExecutablePool6createEj.) -# -# If that doesn't work, use grep. -#---------------------------------------------------------------------------- - -if [ -z $1 ] ; then - echo "usage: find_vanilla_new_calls " - exit 1 -fi - -file=$1 - -if [ ! -f $file ] ; then - echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | file '$file' not found" - exit 1 -fi - -tmpfile1=`mktemp` -tmpfile2=`mktemp` -nm -C $file > $tmpfile1 - -# Need to double-escape '[' and ']' to stop grep from interpreting them -# specially. -grep '^operator new(unsigned int)' $tmpfile1 >> $tmpfile2 -grep '^operator new(unsigned long)' $tmpfile1 >> $tmpfile2 -grep '^operator new\\[\\](unsigned int)' $tmpfile1 >> $tmpfile2 -grep '^operator new\\[\\](unsigned long)' $tmpfile1 >> $tmpfile2 -rm -f $tmpfile1 - -if [ -s $tmpfile2 ] ; then - echo "TEST-UNEXPECTED-FAIL | find_vanilla_new_calls | found calls are listed below" - cat $tmpfile2 - echo - rm -f $tmpfile2 - exit 1 -fi - -echo "TEST-PASS | find_vanilla_new_calls | ok" -echo - -exit 0 diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp index 5c3ef97aed92..2dcb8a2922ed 100644 --- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -161,6 +161,49 @@ JS_Assert(const char *s, const char *file, int ln) MOZ_CRASH(); } +#ifdef __linux__ + +#include +#include + +namespace js { + +// This function calls all the vanilla heap allocation functions. It is never +// called, and exists purely to help config/check_vanilla_allocations.py. See +// that script for more details. +extern void +AllTheNonBasicVanillaNewAllocations() +{ + // posix_memalign and aligned_alloc aren't available on all Linux + // configurations. + //char *q; + //posix_memalign((void**)&q, 16, 16); + + intptr_t p = + intptr_t(malloc(16)) + + intptr_t(calloc(1, 16)) + + intptr_t(realloc(nullptr, 16)) + + intptr_t(new char) + + intptr_t(new char) + + intptr_t(new char) + + intptr_t(new char[16]) + + intptr_t(memalign(16, 16)) + + //intptr_t(q) + + //intptr_t(aligned_alloc(16, 16)) + + intptr_t(valloc(4096)) + + intptr_t(strdup("dummy")); + + printf("%u\n", uint32_t(p)); // make sure |p| is not optimized away + + free((int*)p); // this would crash if ever actually called + + MOZ_CRASH(); +} + +} // namespace js + +#endif // __linux__ + #ifdef JS_BASIC_STATS #include From 7f645374b9b7d83a3a6fb0ffc45493a645a3da8a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 19 Nov 2013 20:05:44 -0800 Subject: [PATCH 036/268] Bug 939385 (part 5) - Test vsizeMaxContiguous. r=froydnj. --HG-- extra : rebase_source : cca51f0c5c3283d45c6f6c1d0e2ae9ae5f16f983 --- toolkit/components/aboutmemory/tests/test_memoryReporters.xul | 1 + 1 file changed, 1 insertion(+) diff --git a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul index 0f6deb4bf516..ed22ebb22578 100644 --- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul +++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul @@ -127,6 +127,7 @@ } let amounts = [ "vsize", + "vsizeMaxContiguous", "resident", "residentFast", "heapAllocated", From fd43eb5704af867c104be4c07adceafe290b2409 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Wed, 6 Nov 2013 10:05:18 +0000 Subject: [PATCH 037/268] Bug 926546 - Modify assertion in nsComputedDOMStyle::GetPropertyCSSValue to mention the pseudo-element concerned to aid debugging. r=dbaron --- layout/style/nsComputedDOMStyle.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 8ccf84b82c17..5a121ece5a2b 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -672,10 +672,15 @@ nsComputedDOMStyle::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorRes while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) { topWithPseudoElementData = topWithPseudoElementData->GetParent(); } - NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements( - topWithPseudoElementData->GetPseudoType()), - "we should be in a pseudo-element that is expected to " - "contain elements"); + nsCSSPseudoElements::Type pseudo = + topWithPseudoElementData->GetPseudoType(); + nsIAtom* pseudoAtom = nsCSSPseudoElements::GetPseudoAtom(pseudo); + nsAutoString assertMsg( + NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements (")); + assertMsg.Append(nsDependentString(pseudoAtom->GetUTF16String())); + assertMsg.Append(NS_LITERAL_STRING(")")); + NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo), + NS_LossyConvertUTF16toASCII(assertMsg).get()); } #endif // Need to resolve a style context From f1da82e63ea9ac2c17817fab48363014c23ced2a Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Wed, 20 Nov 2013 09:32:45 +0000 Subject: [PATCH 038/268] Bug 771561 - Make HTMLInputElement.stepUp()/stepDown() work when the input's value is NaN. r=smaug --- content/html/content/src/HTMLInputElement.cpp | 2 +- .../content/test/forms/test_stepup_stepdown.html | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/content/html/content/src/HTMLInputElement.cpp b/content/html/content/src/HTMLInputElement.cpp index bed1f3f52424..485a48c513fa 100644 --- a/content/html/content/src/HTMLInputElement.cpp +++ b/content/html/content/src/HTMLInputElement.cpp @@ -2061,7 +2061,7 @@ HTMLInputElement::ApplyStep(int32_t aStep) Decimal value = GetValueAsDecimal(); if (value.isNaN()) { - return NS_OK; + value = 0; } Decimal minimum = GetMinimum(); diff --git a/content/html/content/test/forms/test_stepup_stepdown.html b/content/html/content/test/forms/test_stepup_stepdown.html index aa14e23a901f..055fbd5b6a29 100644 --- a/content/html/content/test/forms/test_stepup_stepdown.html +++ b/content/html/content/test/forms/test_stepup_stepdown.html @@ -169,7 +169,7 @@ function checkStepDown() [ '10', '2', '0', '4', '10', '0', false ], [ '10', '2', '0', '4', '5', '0', false ], // value = "" (NaN). - [ '', null, null, null, null, '', false ], + [ '', null, null, null, null, '-1', false ], // With step = 'any'. [ '0', 'any', null, null, 1, null, true ], [ '0', 'ANY', null, null, 1, null, true ], @@ -304,7 +304,7 @@ function checkStepDown() [ '1970-03-08', '3', '1970-02-01', '1970-02-07', 15, '1970-02-01', false ], [ '1970-01-10', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ], // value = "" (NaN). - [ '', null, null, null, null, '', false ], + [ '', null, null, null, null, '1969-12-31', false ], // With step = 'any'. [ '2012-01-01', 'any', null, null, 1, null, true ], [ '2012-01-01', 'ANY', null, null, 1, null, true ], @@ -368,7 +368,7 @@ function checkStepDown() [ '17:22', '180', '17:00', '17:20', 15, '17:00', false ], [ '17:22', '180', '17:10', '17:20', 2, '17:16', false ], // value = "" (NaN). - [ '', null, null, null, null, '', false ], + [ '', null, null, null, null, '23:59', false ], // With step = 'any'. [ '17:26', 'any', null, null, 1, null, true ], [ '17:26', 'ANY', null, null, 1, null, true ], @@ -484,7 +484,7 @@ function checkStepUp() [ '-3', '2', '-6', '-2', null, '-2', false ], [ '-3', '2', '-6', '-1', null, '-2', false ], // value = "" (NaN). - [ '', null, null, null, null, '', false ], + [ '', null, null, null, null, '1', false ], // With step = 'any'. [ '0', 'any', null, null, 1, null, true ], [ '0', 'ANY', null, null, 1, null, true ], @@ -619,7 +619,7 @@ function checkStepUp() [ '1970-01-01', '3', '1970-02-01', '1970-02-07', 15, '1970-02-07', false ], [ '1970-01-01', '3', '1970-01-01', '1970-01-06', 2, '1970-01-04', false ], // value = "" (NaN). - [ '', null, null, null, null, '', false ], + [ '', null, null, null, null, '1970-01-02', false ], // With step = 'any'. [ '2012-01-01', 'any', null, null, 1, null, true ], [ '2012-01-01', 'ANY', null, null, 1, null, true ], @@ -683,7 +683,7 @@ function checkStepUp() [ '17:22', '180', '17:00', '17:20', 15, '17:22', false ], [ '17:22', '180', '17:10', '17:20', 2, '17:22', false ], // value = "" (NaN). - [ '', null, null, null, null, '', false ], + [ '', null, null, null, null, '00:01', false ], // With step = 'any'. [ '17:26', 'any', null, null, 1, null, true ], [ '17:26', 'ANY', null, null, 1, null, true ], From fd6a1d69b86c3022e098760249881681fa63da81 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Wed, 20 Nov 2013 09:32:45 +0000 Subject: [PATCH 039/268] Bug 940698 - Add an "ownerNumberControl" property to HTMLInputElement. r=smaug --- content/html/content/src/HTMLInputElement.cpp | 15 +++++++++++++++ content/html/content/src/HTMLInputElement.h | 2 ++ dom/webidl/HTMLInputElement.webidl | 12 ++++++++++++ 3 files changed, 29 insertions(+) diff --git a/content/html/content/src/HTMLInputElement.cpp b/content/html/content/src/HTMLInputElement.cpp index 485a48c513fa..cabbf2d01072 100644 --- a/content/html/content/src/HTMLInputElement.cpp +++ b/content/html/content/src/HTMLInputElement.cpp @@ -2244,6 +2244,21 @@ HTMLInputElement::MozIsTextField(bool aExcludePassword) return IsSingleLineTextControl(aExcludePassword); } +HTMLInputElement* +HTMLInputElement::GetOwnerNumberControl() +{ + if (IsInNativeAnonymousSubtree() && + mType == NS_FORM_INPUT_TEXT && + GetParent() && GetParent()->GetParent()) { + HTMLInputElement* grandparent = + HTMLInputElement::FromContentOrNull(GetParent()->GetParent()); + if (grandparent && grandparent->mType == NS_FORM_INPUT_NUMBER) { + return grandparent; + } + } + return nullptr; +} + NS_IMETHODIMP HTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult) { diff --git a/content/html/content/src/HTMLInputElement.h b/content/html/content/src/HTMLInputElement.h index bf2241d6424e..ff6f9ce1d625 100644 --- a/content/html/content/src/HTMLInputElement.h +++ b/content/html/content/src/HTMLInputElement.h @@ -668,6 +668,8 @@ public: void MozSetFileNameArray(const Sequence< nsString >& aFileNames); + HTMLInputElement* GetOwnerNumberControl(); + bool MozIsTextField(bool aExcludePassword); nsIEditor* GetEditor(); diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl index ba1bb610f2ee..3c6f9c8c04d7 100644 --- a/dom/webidl/HTMLInputElement.webidl +++ b/dom/webidl/HTMLInputElement.webidl @@ -154,6 +154,18 @@ partial interface HTMLInputElement { [ChromeOnly] void mozSetFileNameArray(sequence fileNames); + // Number controls () have an anonymous text control + // () in the anonymous shadow tree that they contain. On + // such an anonymous text control this property provides access to the + // number control that owns the text control. This is useful, for example, + // in code that looks at the currently focused element to make decisions + // about which IME to bring up. Such code needs to be able to check for any + // owning number control since it probably wants to bring up a number pad + // instead of the standard keyboard, even when the anonymous text control has + // focus. + [ChromeOnly] + readonly attribute HTMLInputElement? ownerNumberControl; + boolean mozIsTextField(boolean aExcludePassword); }; From 33b453a2a039a9de3d9838c07bb1c1ca31c903a9 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Wed, 20 Nov 2013 09:32:46 +0000 Subject: [PATCH 040/268] Bug 939635 - Make the IME code aware of the new implementation. r=masayuki --- content/events/src/nsIMEStateManager.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/content/events/src/nsIMEStateManager.cpp b/content/events/src/nsIMEStateManager.cpp index 83cb06658e02..7db3a042108c 100644 --- a/content/events/src/nsIMEStateManager.cpp +++ b/content/events/src/nsIMEStateManager.cpp @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIMEStateManager.h" + +#include "HTMLInputElement.h" #include "nsCOMPtr.h" #include "nsIPresShell.h" #include "nsISupports.h" @@ -35,6 +37,7 @@ #include "nsAsyncDOMEvent.h" using namespace mozilla; +using namespace mozilla::dom; using namespace mozilla::widget; // nsTextStateManager notifies widget of any text and selection changes @@ -457,8 +460,22 @@ nsIMEStateManager::SetIMEState(const IMEState &aState, (aContent->Tag() == nsGkAtoms::input || aContent->Tag() == nsGkAtoms::textarea)) { if (aContent->Tag() != nsGkAtoms::textarea) { - aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::type, - context.mHTMLInputType); + // has an anonymous descendant + // that gets focus whenever anyone tries to focus the number control. We + // need to check if aContent is one of those anonymous text controls and, + // if so, use the number control instead: + nsIContent* content = aContent; + HTMLInputElement* inputElement = + HTMLInputElement::FromContentOrNull(aContent); + if (inputElement) { + HTMLInputElement* ownerNumberControl = + inputElement->GetOwnerNumberControl(); + if (ownerNumberControl) { + content = ownerNumberControl; // an + } + } + content->GetAttr(kNameSpaceID_None, nsGkAtoms::type, + context.mHTMLInputType); } else { context.mHTMLInputType.Assign(nsGkAtoms::textarea->GetUTF16String()); } From c47ac7b46f8de88b3c89a58071a7f4dbd3952dd8 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Wed, 20 Nov 2013 09:32:46 +0000 Subject: [PATCH 041/268] Bug 940696 - Ensure that Firefox OS brings up the number pad when a user focuses an . r=fabrice --- dom/inputmethod/forms.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/dom/inputmethod/forms.js b/dom/inputmethod/forms.js index 8bd5b48daccf..78318ee62274 100644 --- a/dom/inputmethod/forms.js +++ b/dom/inputmethod/forms.js @@ -767,6 +767,12 @@ function isPlainTextField(element) { } function getJSON(element, focusCounter) { + // has a nested anonymous element that + // takes focus on behalf of the number control when someone tries to focus + // the number control. If |element| is such an anonymous text control then we + // need it's number control here in order to get the correct 'type' etc.: + element = element.ownerNumberControl || element; + let type = element.type || ""; let value = element.value || ""; let max = element.max || ""; From 365a141f9bdf1d794ca842fb682fb29e63dfd2b1 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Wed, 20 Nov 2013 00:21:16 +0200 Subject: [PATCH 042/268] Bug 847763, add a way to prevent an iframe to take focus, (pref'ed off by default), r=jst --HG-- extra : rebase_source : b2539bd99aebec59bc1d540e0502e1a5693f25ba --- content/base/public/nsContentUtils.h | 9 ++ content/base/public/nsIContent.h | 12 +- content/base/src/FragmentOrElement.cpp | 27 ++++ content/base/src/nsContentUtils.cpp | 25 +++ content/base/src/nsGkAtomList.h | 1 + content/events/src/nsEventStateManager.cpp | 4 + .../html/content/src/nsGenericHTMLElement.h | 2 +- .../content/src/nsGenericHTMLFrameElement.cpp | 17 +- .../content/src/nsGenericHTMLFrameElement.h | 1 + .../content/test/file_ignoreuserfocus.html | 10 ++ content/html/content/test/mochitest.ini | 2 + .../content/test/test_ignoreuserfocus.html | 146 ++++++++++++++++++ .../mathml/content/src/nsMathMLElement.cpp | 2 +- content/mathml/content/src/nsMathMLElement.h | 3 +- content/svg/content/src/SVGAElement.cpp | 2 +- content/svg/content/src/SVGAElement.h | 2 +- content/xul/content/src/nsXULElement.cpp | 2 +- content/xul/content/src/nsXULElement.h | 2 +- dom/base/nsFocusManager.cpp | 27 +++- 19 files changed, 272 insertions(+), 24 deletions(-) create mode 100644 content/html/content/test/file_ignoreuserfocus.html create mode 100644 content/html/content/test/test_ignoreuserfocus.html diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 1e8b5825fe0f..09275fb98ac4 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1886,6 +1886,15 @@ public: */ static bool IsSubDocumentTabbable(nsIContent* aContent); + /** + * Returns if aNode ignores user focus. + * + * @param aNode node to test + * + * @return Whether the node ignores user focus. + */ + static bool IsUserFocusIgnored(nsINode* aNode); + /** * Flushes the layout tree (recursively) * diff --git a/content/base/public/nsIContent.h b/content/base/public/nsIContent.h index a81dd3f656e4..a9a668e1ed57 100644 --- a/content/base/public/nsIContent.h +++ b/content/base/public/nsIContent.h @@ -34,8 +34,8 @@ enum nsLinkState { // IID for the nsIContent interface #define NS_ICONTENT_IID \ -{ 0x976f4cd1, 0xbdfc, 0x4a1e, \ - { 0x82, 0x46, 0x1c, 0x13, 0x9c, 0xd3, 0x73, 0x7f } } +{ 0x34117ca3, 0x45d0, 0x479e, \ + { 0x91, 0x30, 0x54, 0x49, 0xa9, 0x5f, 0x25, 0x99 } } /** * A node of content in a document's content model. This interface @@ -557,12 +557,8 @@ public: * > 0 can be tabbed to in the order specified by this value * @return whether the content is focusable via mouse, kbd or script. */ - virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false) - { - if (aTabIndex) - *aTabIndex = -1; // Default, not tabbable - return false; - } + bool IsFocusable(int32_t* aTabIndex = nullptr, bool aWithMouse = false); + virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse); /** * The method focuses (or activates) element that accesskey is bound to. It is diff --git a/content/base/src/FragmentOrElement.cpp b/content/base/src/FragmentOrElement.cpp index 5530891fa00b..702f62232600 100644 --- a/content/base/src/FragmentOrElement.cpp +++ b/content/base/src/FragmentOrElement.cpp @@ -838,6 +838,33 @@ nsIContent::AttrValueIs(int32_t aNameSpaceID, AsElement()->AttrValueIs(aNameSpaceID, aName, aValue, aCaseSensitive); } +bool +nsIContent::IsFocusable(int32_t* aTabIndex, bool aWithMouse) +{ + bool focusable = IsFocusableInternal(aTabIndex, aWithMouse); + // Ensure that the return value and aTabIndex are consistent in the case + // we're in userfocusignored context. + if (focusable || (aTabIndex && *aTabIndex != -1)) { + if (nsContentUtils::IsUserFocusIgnored(this)) { + if (aTabIndex) { + *aTabIndex = -1; + } + return false; + } + return focusable; + } + return false; +} + +bool +nsIContent::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) +{ + if (aTabIndex) { + *aTabIndex = -1; // Default, not tabbable + } + return false; +} + const nsAttrValue* FragmentOrElement::DoGetClasses() const { diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 787a1d5fd2c7..a60f693de745 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -74,6 +74,7 @@ #include "nsEventStateManager.h" #include "nsFocusManager.h" #include "nsGenericHTMLElement.h" +#include "nsGenericHTMLFrameElement.h" #include "nsGkAtoms.h" #include "nsHostObjectProtocolHandler.h" #include "nsHtml5Module.h" @@ -5898,6 +5899,30 @@ nsContentUtils::IsSubDocumentTabbable(nsIContent* aContent) return !zombieViewer; } +bool +nsContentUtils::IsUserFocusIgnored(nsINode* aNode) +{ + if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) { + return false; + } + + // Check if our mozbrowser iframe ancestors has ignoreuserfocus attribute. + while (aNode) { + nsCOMPtr browserFrame = do_QueryInterface(aNode); + if (browserFrame && + aNode->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::ignoreuserfocus) && + browserFrame->GetReallyIsBrowserOrApp()) { + return true; + } + nsPIDOMWindow* win = aNode->OwnerDoc()->GetWindow(); + if (win) { + aNode = win->GetFrameElementInternal(); + } + } + + return false; +} + void nsContentUtils::FlushLayoutForTree(nsIDOMWindow* aWindow) { diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 874280cca9ff..ecce986d7193 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -433,6 +433,7 @@ GK_ATOM(_if, "if") GK_ATOM(iframe, "iframe") GK_ATOM(ignorecase, "ignorecase") GK_ATOM(ignorekeys, "ignorekeys") +GK_ATOM(ignoreuserfocus, "ignoreuserfocus") GK_ATOM(ilayer, "ilayer") GK_ATOM(image, "image") GK_ATOM(imageClickedPoint, "image-clicked-point") diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index 582575095ad5..ba2a5cfd5474 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -3221,6 +3221,10 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext, } } + if (!suppressBlur) { + suppressBlur = nsContentUtils::IsUserFocusIgnored(activeContent); + } + nsIFrame* currFrame = mCurrentTarget; // When a root content which isn't editable but has an editable HTML diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h index 5598e58fb8dc..c0a682442f96 100644 --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -558,7 +558,7 @@ public: bool aNotify) MOZ_OVERRIDE; virtual nsresult UnsetAttr(int32_t aNameSpaceID, nsIAtom* aName, bool aNotify) MOZ_OVERRIDE; - virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false) MOZ_OVERRIDE + virtual bool IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse) MOZ_OVERRIDE { bool isFocusable = false; IsHTMLFocusable(aWithMouse, &isFocusable, aTabIndex); diff --git a/content/html/content/src/nsGenericHTMLFrameElement.cpp b/content/html/content/src/nsGenericHTMLFrameElement.cpp index dc3bacd392e3..d8aa0ac0fc90 100644 --- a/content/html/content/src/nsGenericHTMLFrameElement.cpp +++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp @@ -323,6 +323,21 @@ nsGenericHTMLFrameElement::IsHTMLFocusable(bool aWithMouse, return false; } +bool +nsGenericHTMLFrameElement::BrowserFramesEnabled() +{ + static bool sMozBrowserFramesEnabled = false; + static bool sBoolVarCacheInitialized = false; + + if (!sBoolVarCacheInitialized) { + sBoolVarCacheInitialized = true; + Preferences::AddBoolVarCache(&sMozBrowserFramesEnabled, + "dom.mozBrowserFramesEnabled"); + } + + return sMozBrowserFramesEnabled; +} + /** * Return true if this frame element really is a mozbrowser or mozapp. (It * needs to have the right attributes, and its creator must have the right @@ -334,7 +349,7 @@ nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp(bool *aOut) *aOut = false; // Fail if browser frames are globally disabled. - if (!Preferences::GetBool("dom.mozBrowserFramesEnabled")) { + if (!nsGenericHTMLFrameElement::BrowserFramesEnabled()) { return NS_OK; } diff --git a/content/html/content/src/nsGenericHTMLFrameElement.h b/content/html/content/src/nsGenericHTMLFrameElement.h index df599dc417dd..e4eb6b22bd6b 100644 --- a/content/html/content/src/nsGenericHTMLFrameElement.h +++ b/content/html/content/src/nsGenericHTMLFrameElement.h @@ -72,6 +72,7 @@ public: void SwapFrameLoaders(nsXULElement& aOtherOwner, mozilla::ErrorResult& aError); + static bool BrowserFramesEnabled(); protected: // This doesn't really ensure a frame loade in all cases, only when // it makes sense. diff --git a/content/html/content/test/file_ignoreuserfocus.html b/content/html/content/test/file_ignoreuserfocus.html new file mode 100644 index 000000000000..b9e33021249f --- /dev/null +++ b/content/html/content/test/file_ignoreuserfocus.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/content/html/content/test/mochitest.ini b/content/html/content/test/mochitest.ini index f4246a1ff634..fd8ffc6366fe 100644 --- a/content/html/content/test/mochitest.ini +++ b/content/html/content/test/mochitest.ini @@ -154,6 +154,7 @@ support-files = reflect.js wakelock.ogg wakelock.ogv + file_ignoreuserfocus.html [test_a_text.html] [test_anchor_href_cache_invalidation.html] @@ -416,3 +417,4 @@ support-files = [test_undoManager.html] [test_video_wakelock.html] [test_input_files_not_nsIFile.html] +[test_ignoreuserfocus.html] diff --git a/content/html/content/test/test_ignoreuserfocus.html b/content/html/content/test/test_ignoreuserfocus.html new file mode 100644 index 000000000000..64ce2c0c1466 --- /dev/null +++ b/content/html/content/test/test_ignoreuserfocus.html @@ -0,0 +1,146 @@ + + + + + + + + + + + diff --git a/content/mathml/content/src/nsMathMLElement.cpp b/content/mathml/content/src/nsMathMLElement.cpp index d7408a18fbae..7ec1c5e14a36 100644 --- a/content/mathml/content/src/nsMathMLElement.cpp +++ b/content/mathml/content/src/nsMathMLElement.cpp @@ -815,7 +815,7 @@ nsMathMLElement::SetIncrementScriptLevel(bool aIncrementScriptLevel, } bool -nsMathMLElement::IsFocusable(int32_t *aTabIndex, bool aWithMouse) +nsMathMLElement::IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) { nsCOMPtr uri; if (IsLink(getter_AddRefs(uri))) { diff --git a/content/mathml/content/src/nsMathMLElement.h b/content/mathml/content/src/nsMathMLElement.h index ffeffc2fa813..81240042979b 100644 --- a/content/mathml/content/src/nsMathMLElement.h +++ b/content/mathml/content/src/nsMathMLElement.h @@ -80,8 +80,7 @@ public: return mIncrementScriptLevel; } - virtual bool IsFocusable(int32_t *aTabIndex = nullptr, - bool aWithMouse = false) MOZ_OVERRIDE; + virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) MOZ_OVERRIDE; virtual bool IsLink(nsIURI** aURI) const MOZ_OVERRIDE; virtual void GetLinkTarget(nsAString& aTarget) MOZ_OVERRIDE; virtual already_AddRefed GetHrefURI() const MOZ_OVERRIDE; diff --git a/content/svg/content/src/SVGAElement.cpp b/content/svg/content/src/SVGAElement.cpp index 1c0500a08862..49d870980141 100644 --- a/content/svg/content/src/SVGAElement.cpp +++ b/content/svg/content/src/SVGAElement.cpp @@ -161,7 +161,7 @@ SVGAElement::IsAttributeMapped(const nsIAtom* name) const } bool -SVGAElement::IsFocusable(int32_t *aTabIndex, bool aWithMouse) +SVGAElement::IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse) { nsCOMPtr uri; if (IsLink(getter_AddRefs(uri))) { diff --git a/content/svg/content/src/SVGAElement.h b/content/svg/content/src/SVGAElement.h index 3984d9f9d5e3..29728f0c21f5 100644 --- a/content/svg/content/src/SVGAElement.h +++ b/content/svg/content/src/SVGAElement.h @@ -43,7 +43,7 @@ public: virtual void UnbindFromTree(bool aDeep = true, bool aNullParent = true) MOZ_OVERRIDE; NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const MOZ_OVERRIDE; - virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false) MOZ_OVERRIDE; + virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) MOZ_OVERRIDE; virtual bool IsLink(nsIURI** aURI) const MOZ_OVERRIDE; virtual void GetLinkTarget(nsAString& aTarget) MOZ_OVERRIDE; virtual already_AddRefed GetHrefURI() const MOZ_OVERRIDE; diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index edb0e1cd3331..4f158f2944ba 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -511,7 +511,7 @@ static bool IsNonList(nsINodeInfo* aNodeInfo) } bool -nsXULElement::IsFocusable(int32_t *aTabIndex, bool aWithMouse) +nsXULElement::IsFocusableInternal(int32_t *aTabIndex, bool aWithMouse) { /* * Returns true if an element may be focused, and false otherwise. The inout diff --git a/content/xul/content/src/nsXULElement.h b/content/xul/content/src/nsXULElement.h index de91e633dd2e..f9a6cc20d895 100644 --- a/content/xul/content/src/nsXULElement.h +++ b/content/xul/content/src/nsXULElement.h @@ -396,7 +396,7 @@ public: virtual nsIContent *GetBindingParent() const MOZ_OVERRIDE; virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE; - virtual bool IsFocusable(int32_t *aTabIndex = nullptr, bool aWithMouse = false) MOZ_OVERRIDE; + virtual bool IsFocusableInternal(int32_t* aTabIndex, bool aWithMouse) MOZ_OVERRIDE; NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) MOZ_OVERRIDE; virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute, diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index a3f7d1bccfa9..a71ac4ab401c 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -1396,10 +1396,12 @@ nsFocusManager::IsNonFocusableRoot(nsIContent* aContent) // focusable. // Also, if aContent is not editable but it isn't in designMode, it's not // focusable. + // And in userfocusignored context nothing is focusable. nsIDocument* doc = aContent->GetCurrentDoc(); NS_ASSERTION(doc, "aContent must have current document"); return aContent == doc->GetRootElement() && - (doc->HasFlag(NODE_IS_EDITABLE) || !aContent->IsEditable()); + (doc->HasFlag(NODE_IS_EDITABLE) || !aContent->IsEditable() || + nsContentUtils::IsUserFocusIgnored(aContent)); } nsIContent* @@ -1428,9 +1430,10 @@ nsFocusManager::CheckIfFocusable(nsIContent* aContent, uint32_t aFlags) if (!shell) return nullptr; - // the root content can always be focused + // the root content can always be focused, + // except in userfocusignored context. if (aContent == doc->GetRootElement()) - return aContent; + return nsContentUtils::IsUserFocusIgnored(aContent) ? nullptr : aContent; // cannot focus content in print preview mode. Only the root can be focused. nsPresContext* presContext = shell->GetPresContext(); @@ -1881,10 +1884,18 @@ nsFocusManager::SendFocusOrBlurEvent(uint32_t aType, nsCOMPtr eventTarget = do_QueryInterface(aTarget); + nsCOMPtr n = do_QueryInterface(aTarget); + if (!n) { + nsCOMPtr win = do_QueryInterface(aTarget); + n = win ? win->GetExtantDoc() : nullptr; + } + bool dontDispatchEvent = n && nsContentUtils::IsUserFocusIgnored(n); + // for focus events, if this event was from a mouse or key and event // handling on the document is suppressed, queue the event and fire it // later. For blur events, a non-zero value would be set for aFocusMethod. - if (aFocusMethod && aDocument && aDocument->EventHandlingSuppressed()) { + if (aFocusMethod && !dontDispatchEvent && + aDocument && aDocument->EventHandlingSuppressed()) { // aFlags is always 0 when aWindowRaised is true so this won't be called // on a window raise. NS_ASSERTION(!aWindowRaised, "aWindowRaised should not be set"); @@ -1914,9 +1925,11 @@ nsFocusManager::SendFocusOrBlurEvent(uint32_t aType, } #endif - nsContentUtils::AddScriptRunner( - new FocusBlurEvent(aTarget, aType, aPresShell->GetPresContext(), - aWindowRaised, aIsRefocus)); + if (!dontDispatchEvent) { + nsContentUtils::AddScriptRunner( + new FocusBlurEvent(aTarget, aType, aPresShell->GetPresContext(), + aWindowRaised, aIsRefocus)); + } } void From e96dc3e87f1b6dbffc4ff19419b9b9646d4f7765 Mon Sep 17 00:00:00 2001 From: Asaf Romano Date: Wed, 20 Nov 2013 12:00:02 +0200 Subject: [PATCH 043/268] Bug 896193 - Adopt Promises in mozIAsyncLivemarks. r=mak. sr=gavin. --- .../components/places/mozIAsyncLivemarks.idl | 20 +- .../components/places/nsLivemarkService.js | 101 ++- .../tests/unit/test_mozIAsyncLivemarks.js | 715 ++++++++++-------- 3 files changed, 473 insertions(+), 363 deletions(-) diff --git a/toolkit/components/places/mozIAsyncLivemarks.idl b/toolkit/components/places/mozIAsyncLivemarks.idl index 68aae9d104e9..07f62a34752e 100644 --- a/toolkit/components/places/mozIAsyncLivemarks.idl +++ b/toolkit/components/places/mozIAsyncLivemarks.idl @@ -12,7 +12,7 @@ interface mozILivemark; interface nsINavHistoryResultObserver; -[scriptable, uuid(1dbf174c-696e-4d9b-af0f-350da50d2249)] +[scriptable, uuid(5B48E5A2-F07A-4E64-A935-C722A3D60B65)] interface mozIAsyncLivemarks : nsISupports { /** @@ -24,12 +24,12 @@ interface mozIAsyncLivemarks : nsISupports * @param [optional] aCallback * Invoked when the creation process is done. In case of failure will * receive an error code. - * + * @return {Promise} * @throws NS_ERROR_INVALID_ARG if the supplied information is insufficient * for the creation. */ - void addLivemark(in jsval aLivemarkInfo, - [optional]in mozILivemarkCallback aCallback); + jsval addLivemark(in jsval aLivemarkInfo, + [optional] in mozILivemarkCallback aCallback); /** * Removes an existing livemark. @@ -41,10 +41,11 @@ interface mozIAsyncLivemarks : nsISupports * Invoked when the removal process is done. In case of failure will * receive an error code. * + * @return {Promise} * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid. */ - void removeLivemark(in jsval aLivemarkInfo, - [optional]in mozILivemarkCallback aCallback); + jsval removeLivemark(in jsval aLivemarkInfo, + [optional] in mozILivemarkCallback aCallback); /** * Gets an existing livemark. @@ -52,15 +53,16 @@ interface mozIAsyncLivemarks : nsISupports * @param aLivemarkInfo * mozILivemarkInfo object containing either an id or a guid of the * livemark to retrieve. - * @param aCallback + * @param [optioanl] aCallback * Invoked when the fetching process is done. In case of failure will * receive an error code. * + * @return {Promise} * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid or an invalid * callback is provided. */ - void getLivemark(in jsval aLivemarkInfo, - in mozILivemarkCallback aCallback); + jsval getLivemark(in jsval aLivemarkInfo, + [optional] in mozILivemarkCallback aCallback); /** * Reloads all livemarks if they are expired or if forced to do so. diff --git a/toolkit/components/places/nsLivemarkService.js b/toolkit/components/places/nsLivemarkService.js index aca937a8fce6..8e913318794c 100644 --- a/toolkit/components/places/nsLivemarkService.js +++ b/toolkit/components/places/nsLivemarkService.js @@ -16,6 +16,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Promise", + "resource://gre/modules/Promise.jsm"); //////////////////////////////////////////////////////////////////////////////// //// Services @@ -213,7 +215,8 @@ LivemarkService.prototype = { // The addition is done synchronously due to the fact importExport service // and JSON backups require that. The notification is async though. // Once bookmarks are async, this may be properly fixed. - let result = Cr.NS_OK; + let deferred = Promise.defer(); + let addLivemarkEx = null; let livemark = null; try { // Disallow adding a livemark inside another livemark. @@ -246,18 +249,33 @@ LivemarkService.prototype = { this._guids[aLivemarkInfo.guid] = livemark.id; } catch (ex) { - result = ex.result; + addLivemarkEx = ex; livemark = null; } finally { - if (aLivemarkCallback) { - this._onCacheReady(function LS_addLivemark_ETAT() { - try { - aLivemarkCallback.onCompletion(result, livemark); - } catch(ex2) {} - }, true); - } + this._onCacheReady(() => { + if (addLivemarkEx) { + if (aLivemarkCallback) { + try { + aLivemarkCallback.onCompletion(addLivemarkEx.result, livemark); + } + catch(ex2) { } + } + deferred.reject(addLivemarkEx); + } + else { + if (aLivemarkCallback) { + try { + aLivemarkCallback.onCompletion(Cr.NS_OK, livemark); + } + catch(ex2) { } + } + deferred.resolve(livemark); + } + }); } + + return deferred.promise; }, removeLivemark: function LS_removeLivemark(aLivemarkInfo, aLivemarkCallback) @@ -278,7 +296,9 @@ LivemarkService.prototype = { if (id in this._guids) { id = this._guids[id]; } - let result = Cr.NS_OK; + + let deferred = Promise.defer(); + let removeLivemarkEx = null; try { if (!(id in this._livemarks)) { throw new Components.Exception("", Cr.NS_ERROR_INVALID_ARG); @@ -286,18 +306,32 @@ LivemarkService.prototype = { this._livemarks[id].remove(); } catch (ex) { - result = ex.result; + removeLivemarkEx = ex; } finally { - if (aLivemarkCallback) { - // Enqueue the notification, per interface definition. - this._onCacheReady(function LS_removeLivemark_ETAT() { - try { - aLivemarkCallback.onCompletion(result, null); - } catch(ex2) {} - }); - } + this._onCacheReady( () => { + if (removeLivemarkEx) { + if (aLivemarkCallback) { + try { + aLivemarkCallback.onCompletion(removeLivemarkEx.result, null); + } + catch(ex2) { } + } + deferred.reject(removeLivemarkEx); + } + else { + if (aLivemarkCallback) { + try { + aLivemarkCallback.onCompletion(Cr.NS_OK, null); + } + catch(ex2) { } + } + deferred.resolve(); + } + }); } + + return deferred.promise; }, _reloaded: [], @@ -326,13 +360,13 @@ LivemarkService.prototype = { return; } - this._onCacheReady((function LS_reloadAllLivemarks_ETAT() { + this._onCacheReady( () => { this._forceUpdate = !!aForceUpdate; this._reloaded = []; // Livemarks reloads happen on a timer, and are delayed for performance // reasons. this._startReloadTimer(); - }).bind(this)); + }); }, getLivemark: function LS_getLivemark(aLivemarkInfo, aLivemarkCallback) @@ -348,22 +382,31 @@ LivemarkService.prototype = { throw Cr.NS_ERROR_INVALID_ARG; } - this._onCacheReady((function LS_getLivemark_ETAT() { + let deferred = Promise.defer(); + this._onCacheReady( () => { // Convert the guid to an id. if (id in this._guids) { id = this._guids[id]; } if (id in this._livemarks) { - try { - aLivemarkCallback.onCompletion(Cr.NS_OK, this._livemarks[id]); - } catch (ex) {} + if (aLivemarkCallback) { + try { + aLivemarkCallback.onCompletion(Cr.NS_OK, this._livemarks[id]); + } catch (ex) {} + } + deferred.resolve(this._livemarks[id]); } else { - try { - aLivemarkCallback.onCompletion(Cr.NS_ERROR_INVALID_ARG, null); - } catch (ex) {} + if (aLivemarkCallback) { + try { + aLivemarkCallback.onCompletion(Cr.NS_ERROR_INVALID_ARG, null); + } catch (ex) { } + } + deferred.reject(Components.Exception("", Cr.NS_ERROR_INVALID_ARG)); } - }).bind(this)); + }); + + return deferred.promise; }, ////////////////////////////////////////////////////////////////////////////// diff --git a/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js b/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js index fab3e2494a8f..429c23bfa109 100644 --- a/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js +++ b/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js @@ -6,201 +6,181 @@ const FEED_URI = NetUtil.newURI("http://feed.rss/"); const SITE_URI = NetUtil.newURI("http://site.org/"); -function run_test() -{ - run_next_test(); -} -add_test(function test_addLivemark_noArguments_throws() +add_task(function test_addLivemark_noArguments_throws() { try { - PlacesUtils.livemarks.addLivemark(); + yield PlacesUtils.livemarks.addLivemark(); do_throw("Invoking addLivemark with no arguments should throw"); } catch (ex) { // The error is actually generated by XPConnect. do_check_eq(ex.result, Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS); } - run_next_test(); }); -add_test(function test_addLivemark_emptyObject_throws() +add_task(function test_addLivemark_emptyObject_throws() { try { - PlacesUtils.livemarks.addLivemark({}); + yield PlacesUtils.livemarks.addLivemark({}); do_throw("Invoking addLivemark with empty object should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_badParentId_throws() +add_task(function test_addLivemark_badParentId_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: "test" }); + yield PlacesUtils.livemarks.addLivemark({ parentId: "test" }); do_throw("Invoking addLivemark with a bad parent id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_invalidParentId_throws() +add_task(function test_addLivemark_invalidParentId_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: -2 }); + yield PlacesUtils.livemarks.addLivemark({ parentId: -2 }); do_throw("Invoking addLivemark with an invalid parent id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_noIndex_throws() +add_task(function test_addLivemark_noIndex_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId }); + yield PlacesUtils.livemarks.addLivemark({ + parentId: PlacesUtils.unfiledBookmarksFolderId }); do_throw("Invoking addLivemark with no index should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_badIndex_throws() +add_task(function test_addLivemark_badIndex_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId - , index: "test" - }); + yield PlacesUtils.livemarks.addLivemark( + { parentId: PlacesUtils.unfiledBookmarksFolderId + , index: "test" }); do_throw("Invoking addLivemark with a bad index should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_invalidIndex_throws() +add_task(function test_addLivemark_invalidIndex_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId - , index: -2 - }); + yield PlacesUtils.livemarks.addLivemark( + { parentId: PlacesUtils.unfiledBookmarksFolderId + , index: -2 + }); do_throw("Invoking addLivemark with an invalid index should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_noFeedURI_throws() +add_task(function test_addLivemark_noFeedURI_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - }); + yield PlacesUtils.livemarks.addLivemark( + { parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX }); do_throw("Invoking addLivemark with no feedURI should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_badFeedURI_throws() +add_task(function test_addLivemark_badFeedURI_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: "test" - }); + yield PlacesUtils.livemarks.addLivemark( + { parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: "test" }); do_throw("Invoking addLivemark with a bad feedURI should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_badSiteURI_throws() +add_task(function test_addLivemark_badSiteURI_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , siteURI: "test" - }); + yield PlacesUtils.livemarks.addLivemark( + { parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: "test" }); do_throw("Invoking addLivemark with a bad siteURI should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_badGuid_throws() +add_task(function test_addLivemark_badGuid_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "123456" - }); + yield PlacesUtils.livemarks.addLivemark( + { parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "123456" }); do_throw("Invoking addLivemark with a bad guid should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_addLivemark_badCallback_throws() +add_task(function test_addLivemark_badCallback_throws() { try { - PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, "test"); + yield PlacesUtils.livemarks.addLivemark( + { parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, "test"); do_throw("Invoking addLivemark with a bad callback should throw"); } catch (ex) { // The error is actually generated by XPConnect. do_check_eq(ex.result, Cr.NS_ERROR_XPC_BAD_CONVERT_JS); } - run_next_test(); }); -add_test(function test_addLivemark_noCallback_succeeds() +add_task(function test_addLivemark_noCallback_succeeds() { + let onItemAddedCalled = false; PlacesUtils.bookmarks.addObserver({ + __proto__: NavBookmarkObserver.prototype, onItemAdded: function onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) { + onItemAddedCalled = true; PlacesUtils.bookmarks.removeObserver(this); do_check_eq(aParentId, PlacesUtils.unfiledBookmarksFolderId); do_check_eq(aIndex, 0); do_check_eq(aItemType, Ci.nsINavBookmarksService.TYPE_FOLDER); do_check_eq(aTitle, "test"); - run_next_test(); - }, - onBeginUpdateBatch: function onBeginUpdateBatch() {}, - onEndUpdateBatch: function onEndUpdateBatch() {}, - onItemRemoved: function onItemRemoved() {}, - onItemChanged: function onItemChanged() {}, - onItemVisited: function onItemVisited() {}, - onItemMoved: function onItemMoved() {}, + } }, false); - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }); + + yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI }); + do_check_true(onItemAddedCalled); }); -add_test(function test_addLivemark_noSiteURI_callback_succeeds() + +add_task(function test_addLivemark_noSiteURI_callback_succeeds() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); + let checkLivemark = aLivemark => { do_check_true(aLivemark.id > 0); do_check_valid_places_guid(aLivemark.guid); do_check_eq(aLivemark.title, "test"); @@ -209,20 +189,28 @@ add_test(function test_addLivemark_noSiteURI_callback_succeeds() do_check_eq(aLivemark.lastModified, PlacesUtils.bookmarks.getItemLastModified(aLivemark.id)); do_check_true(aLivemark.feedURI.equals(FEED_URI)); do_check_eq(aLivemark.siteURI, null); - run_next_test(); - }); + }; + + // The deprecated callback is called before resolving the promise. + let callbackCalled = false; + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + checkLivemark(aLivemark); + } ); + do_check_true(callbackCalled); + checkLivemark(livemark); }); -add_test(function test_addLivemark_callback_succeeds() +add_task(function test_addLivemark_callback_succeeds() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , siteURI: SITE_URI - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); + let checkLivemark = aLivemark => { do_check_true(aLivemark.id > 0); do_check_valid_places_guid(aLivemark.guid); do_check_eq(aLivemark.title, "test"); @@ -231,283 +219,351 @@ add_test(function test_addLivemark_callback_succeeds() do_check_eq(aLivemark.lastModified, PlacesUtils.bookmarks.getItemLastModified(aLivemark.id)); do_check_true(aLivemark.feedURI.equals(FEED_URI)); do_check_true(aLivemark.siteURI.equals(SITE_URI)); - do_check_true(PlacesUtils.annotations .itemHasAnnotation(aLivemark.id, PlacesUtils.LMANNO_FEEDURI)); do_check_true(PlacesUtils.annotations .itemHasAnnotation(aLivemark.id, PlacesUtils.LMANNO_SITEURI)); - run_next_test(); - }); + }; + + // The deprecated callback is called before resolving the promise. + let callbackCalled = false; + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: SITE_URI + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + checkLivemark(aLivemark); + } ); + do_check_true(callbackCalled); + checkLivemark(livemark); }); -add_test(function test_addLivemark_bogusid_callback_succeeds() +add_task(function test_addLivemark_bogusid_callback_succeeds() { - PlacesUtils.livemarks.addLivemark({ id: 100 // Should be ignored. - , title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , siteURI: SITE_URI - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); + let checkLivemark = aLivemark => { do_check_true(aLivemark.id > 0); do_check_neq(aLivemark.id, 100); + }; - run_next_test(); - }); + // The deprecated callback is called before resolving the promise. + let callbackCalled = false; + let livemark = yield PlacesUtils.livemarks.addLivemark( + { id: 100 // Should be ignored. + , title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: SITE_URI + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + checkLivemark(aLivemark); + } ); + do_check_true(callbackCalled); + checkLivemark(livemark); }); -add_test(function test_addLivemark_bogusParent_callback_fails() +add_task(function test_addLivemark_bogusParent_callback_fails() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: 187 - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function (aStatus, aLivemark) - { - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - run_next_test(); - }); + // The deprecated callback is called before resolving the promise. + let callbackCalled = false; + try { + yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: 187 + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + } ); + do_throw("Adding a livemark with a bogus parent should fail"); + } + catch(ex) { + do_check_true(callbackCalled); + } }); -add_test(function test_addLivemark_intoLivemark_callback_fails() +add_task(function test_addLivemark_intoLivemark_callback_fails() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); - - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: aLivemark.id - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function (aStatus, aLivemark) - { - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - run_next_test(); - }); - }); + // The deprecated callback is called before resolving the promise. + let callbackCalled = false; + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + } ); + do_check_true(callbackCalled); + do_check_true(Boolean(livemark)); + + callbackCalled = false; + try { + yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: livemark.id + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + } ); + do_throw("Adding a livemark into a livemark should fail"); + } + catch(ex) { + do_check_true(callbackCalled); + } }); -add_test(function test_addLivemark_forceGuid_callback_succeeds() +add_task(function test_addLivemark_forceGuid_callback_succeeds() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "1234567890AB" - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); + let checkLivemark = aLivemark => { do_check_eq(aLivemark.guid, "1234567890AB"); do_check_guid_for_bookmark(aLivemark.id, "1234567890AB"); + }; - run_next_test(); - }); + // The deprecated callback is called before resolving the promise. + let callbackCalled = false; + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "1234567890AB" + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + checkLivemark(aLivemark); + } ); + do_check_true(callbackCalled); + checkLivemark(livemark); }); -add_test(function test_addLivemark_lastModified_callback_succeeds() +add_task(function test_addLivemark_lastModified_callback_succeeds() { let now = Date.now() * 1000; - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , lastModified: now - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark.lastModified, now); - - run_next_test(); - }); + let callbackCalled = false; + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , lastModified: now + }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.lastModified, now); + } ); + do_check_true(callbackCalled); + do_check_eq(livemark.lastModified, now); }); -add_test(function test_removeLivemark_emptyObject_throws() +add_task(function test_removeLivemark_emptyObject_throws() { try { - PlacesUtils.livemarks.removeLivemark({}); + yield PlacesUtils.livemarks.removeLivemark({}); do_throw("Invoking removeLivemark with empty object should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_removeLivemark_noValidId_throws() +add_task(function test_removeLivemark_noValidId_throws() { try { - PlacesUtils.livemarks.removeLivemark({ id: -10, guid: "test"}); + yield PlacesUtils.livemarks.removeLivemark({ id: -10, guid: "test"}); do_throw("Invoking removeLivemark with no valid id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_removeLivemark_nonExistent_fails() +add_task(function test_removeLivemark_nonExistent_fails() { - PlacesUtils.livemarks.removeLivemark( - { id: 1337 }, - function (aStatus, aLivemark) { - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - run_next_test(); - } - ); + let callbackCalled = false; + try { + yield PlacesUtils.livemarks.removeLivemark( + { id: 1337 }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + } ); + do_throw("Removing a non-existent livemark should fail"); + } + catch(ex) { + do_check_true(callbackCalled); + } }); -add_test(function test_removeLivemark_guid_succeeds() +add_task(function test_removeLivemark_guid_succeeds() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "234567890ABC" - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark.guid, "234567890ABC"); - // invalid id to check the guid wins. - PlacesUtils.livemarks.removeLivemark( - { id: 789, guid: "234567890ABC" }, - function (aStatus, aRemovedLivemark) { - do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(PlacesUtils.bookmarks.getItemIndex(aLivemark.id), -1); - do_check_eq(aRemovedLivemark, null); - run_next_test(); - } - ); + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "234567890ABC" }); -}); -add_test(function test_removeLivemark_id_succeeds() -{ - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); - PlacesUtils.livemarks.removeLivemark( - { id: aLivemark.id }, - function (aStatus, aRemovedLivemark) { - do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(PlacesUtils.bookmarks.getItemIndex(aLivemark.id), -1); - do_check_eq(aRemovedLivemark, null); - run_next_test(); - } - ); + + do_check_eq(livemark.guid, "234567890ABC"); + + yield PlacesUtils.livemarks.removeLivemark({ + id: 789, guid: "234567890ABC" }); + + do_check_eq(PlacesUtils.bookmarks.getItemIndex(livemark.id), -1); }); -add_test(function test_getLivemark_emptyObject_throws() +add_task(function test_removeLivemark_id_succeeds() +{ + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }); + + yield PlacesUtils.livemarks.removeLivemark({ id: livemark.id }); + do_check_eq(PlacesUtils.bookmarks.getItemIndex(livemark.id), -1); +}); + +add_task(function test_getLivemark_emptyObject_throws() { try { - PlacesUtils.livemarks.getLivemark({}, function () {}); + yield PlacesUtils.livemarks.getLivemark({}); do_throw("Invoking getLivemark with empty object should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_getLivemark_noValidId_throws() +add_task(function test_getLivemark_noValidId_throws() { try { - PlacesUtils.livemarks.getLivemark({ id: -10, guid: "test"}, function () {}); + yield PlacesUtils.livemarks.getLivemark({ id: -10, guid: "test"}); do_throw("Invoking getLivemark with no valid id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } - run_next_test(); }); -add_test(function test_getLivemark_nonExistentId_fails() +add_task(function test_getLivemark_nonExistentId_fails() { - PlacesUtils.livemarks.getLivemark({ id: 1234 }, - function (aStatus, aLivemark){ - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - run_next_test(); - } - ); + let callbackCalled = false; + try { + yield PlacesUtils.livemarks.getLivemark({ id: 1234 }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + } ); + do_throw("getLivemark for a non existent id should fail"); + } + catch(ex) { + do_check_true(callbackCalled); + } }); -add_test(function test_getLivemark_nonExistentGUID_fails() +add_task(function test_getLivemark_nonExistentGUID_fails() { - PlacesUtils.livemarks.getLivemark({ guid: "34567890ABCD" }, - function (aStatus, aLivemark){ - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - run_next_test(); - } - ); + let callbackCalled = false; + try { + yield PlacesUtils.livemarks.getLivemark({ guid: "34567890ABCD" }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + } ); + do_throw("getLivemark for a non-existent guid should fail"); + } + catch(ex) { + do_check_true(callbackCalled); + } }); -add_test(function test_getLivemark_guid_succeeds() +add_task(function test_getLivemark_guid_succeeds() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "34567890ABCD" - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); + yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "34567890ABCD" }); - // invalid id to check the guid wins. - PlacesUtils.livemarks.getLivemark({ id: 789, guid: "34567890ABCD" }, - function(aStatus, aLivemark) { + let checkLivemark = aLivemark => { + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_eq(aLivemark.guid, "34567890ABCD"); + }; + + // invalid id to check the guid wins. + let livemark = + yield PlacesUtils.livemarks.getLivemark({ id: 789, guid: "34567890ABCD" }, + (aStatus, aLivemark) => { + callbackCalled = true; do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark.title, "test"); - do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); - do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); - do_check_true(aLivemark.feedURI.equals(FEED_URI)); - do_check_eq(aLivemark.siteURI, null); - do_check_eq(aLivemark.guid, "34567890ABCD"); - run_next_test(); - } - ); - }); + checkLivemark(aLivemark) + } ); + + do_check_true(callbackCalled); + checkLivemark(livemark); }); -add_test(function test_getLivemark_id_succeeds() +add_task(function test_getLivemark_id_succeeds() { - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function (aStatus, aLivemark) - { - do_check_true(Components.isSuccessCode(aStatus)); + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }); - // invalid id to check the guid wins. - PlacesUtils.livemarks.getLivemark({ id: aLivemark.id }, - function(aStatus, aLivemark) { - do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark.title, "test"); - do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); - do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); - do_check_true(aLivemark.feedURI.equals(FEED_URI)); - do_check_eq(aLivemark.siteURI, null); - do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); - run_next_test(); - } - ); - }); + let checkLivemark = aLivemark => { + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); + }; + + let callbackCalled = false; + livemark = yield PlacesUtils.livemarks.getLivemark( + { id: livemark.id }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + checkLivemark(aLivemark); + } ); + + do_check_true(callbackCalled); + checkLivemark(livemark); }); -add_test(function test_getLivemark_removeItem_contention() +add_task(function test_getLivemark_removeItem_contention() { PlacesUtils.livemarks.addLivemark({ title: "test" , parentId: PlacesUtils.unfiledBookmarksFolderId @@ -522,47 +578,56 @@ add_test(function test_getLivemark_removeItem_contention() }); let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, PlacesUtils.bookmarks.DEFAULT_INDEX); - - PlacesUtils.livemarks.getLivemark( - { id: id }, - function(aStatus, aLivemark) { - do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark.title, "test"); - do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); - do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); - do_check_true(aLivemark.feedURI.equals(FEED_URI)); - do_check_eq(aLivemark.siteURI, null); - do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); - run_next_test(); - } - ); -}); -add_test(function test_title_change() -{ - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function(aStatus, aLivemark) { - PlacesUtils.bookmarks.setItemTitle(aLivemark.id, "test2"); - do_check_eq(aLivemark.title, "test2"); - run_next_test(); - }); -}); - -add_test(function test_livemark_move() -{ - PlacesUtils.livemarks.addLivemark({ title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, function(aStatus, aLivemark) { - PlacesUtils.bookmarks.moveItem(aLivemark.id, - PlacesUtils.toolbarFolderId, - PlacesUtils.bookmarks.DEFAULT_INDEX); - do_check_eq(aLivemark.parentId, PlacesUtils.toolbarFolderId); + let checkLivemark = (aLivemark) => { + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); - run_next_test(); - }); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); + }; + + let callbackCalled = false; + let livemark = yield PlacesUtils.livemarks.getLivemark( + { id: id }, + (aStatus, aLivemark) => { + callbackCalled = true; + do_check_true(Components.isSuccessCode(aStatus)); + checkLivemark(aLivemark); + } ); + + do_check_true(callbackCalled); + checkLivemark(livemark); }); + +add_task(function test_title_change() +{ + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI }); + + PlacesUtils.bookmarks.setItemTitle(livemark.id, "test2"); + do_check_eq(livemark.title, "test2"); +}); + +add_task(function test_livemark_move() +{ + let livemark = yield PlacesUtils.livemarks.addLivemark( + { title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI } ); + + PlacesUtils.bookmarks.moveItem(livemark.id, + PlacesUtils.toolbarFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX); + do_check_eq(livemark.parentId, PlacesUtils.toolbarFolderId); + do_check_eq(livemark.index, PlacesUtils.bookmarks.getItemIndex(livemark.id)); +}); + +function run_test() { + run_next_test(); +} From b2be7a3862d5f5cadb355a570cab185f01a0eea1 Mon Sep 17 00:00:00 2001 From: Jan Gerber Date: Tue, 19 Nov 2013 03:45:00 +1300 Subject: [PATCH 044/268] Bug 938315 - Update nestegg to support Opus elements. r=kinetik Merge upstream changes to the WebM parser needed to properly support Opus. --- media/libnestegg/README_MOZILLA | 2 +- media/libnestegg/include/nestegg.h | 10 +++ media/libnestegg/src/nestegg.c | 107 +++++++++++++++++++++++------ 3 files changed, 98 insertions(+), 21 deletions(-) diff --git a/media/libnestegg/README_MOZILLA b/media/libnestegg/README_MOZILLA index ecfdfe06cc44..17dafbb5a27f 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 26d262114af191b6654cbd5d24ec02e4b6bdb1cd. +The git commit ID used was 0851279ab11f5b2e9e8154ce7880b687b564c760. diff --git a/media/libnestegg/include/nestegg.h b/media/libnestegg/include/nestegg.h index 6f307aa398bf..ff13728f32a3 100644 --- a/media/libnestegg/include/nestegg.h +++ b/media/libnestegg/include/nestegg.h @@ -140,6 +140,8 @@ typedef struct { double rate; /**< Sampling rate in Hz. */ unsigned int channels; /**< Number of audio channels. */ unsigned int depth; /**< Bits per sample. */ + uint64_t codec_delay; /**< Nanoseconds that must be discarded from the start. */ + uint64_t seek_preroll;/**< Nanoseconds that must be discarded after a seek. */ } nestegg_audio_params; /** Logging callback function pointer. */ @@ -321,6 +323,14 @@ 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); +/** Returns discard_padding for given packet + @param packet Packet initialized by #nestegg_read_packet. + @param discard_padding pointer to store discard padding in. + @retval 0 Success. + @retval -1 Error. */ +int nestegg_packet_discard_padding(nestegg_packet * packet, + int64_t * discard_padding); + /** Query the presence of cues. @param context Stream context initialized by #nestegg_init. @retval 0 The media has no cues. diff --git a/media/libnestegg/src/nestegg.c b/media/libnestegg/src/nestegg.c index b3bc9cb6dd0c..cd609c9e7b62 100644 --- a/media/libnestegg/src/nestegg.c +++ b/media/libnestegg/src/nestegg.c @@ -49,6 +49,7 @@ #define ID_BLOCK 0xa1 #define ID_BLOCK_DURATION 0x9b #define ID_REFERENCE_BLOCK 0xfb +#define ID_DISCARD_PADDING 0x75a2 /* Tracks Elements */ #define ID_TRACKS 0x1654ae6b @@ -63,6 +64,8 @@ #define ID_LANGUAGE 0x22b59c #define ID_CODEC_ID 0x86 #define ID_CODEC_PRIVATE 0x63a2 +#define ID_CODEC_DELAY 0x56aa +#define ID_SEEK_PREROLL 0x56bb /* Video Elements */ #define ID_VIDEO 0xe0 @@ -194,6 +197,7 @@ struct info { struct block_group { struct ebml_type duration; struct ebml_type reference_block; + struct ebml_type discard_padding; }; struct cluster { @@ -230,6 +234,8 @@ struct track_entry { struct ebml_type language; struct ebml_type codec_id; struct ebml_type codec_private; + struct ebml_type codec_delay; + struct ebml_type seek_preroll; struct video video; struct audio audio; }; @@ -305,6 +311,7 @@ struct nestegg_packet { uint64_t track; uint64_t timecode; struct frame * frame; + int64_t discard_padding; }; /* Element Descriptor */ @@ -368,6 +375,7 @@ 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_LAST }; @@ -409,6 +417,8 @@ static struct ebml_element_desc ne_track_entry_elements[] = { E_FIELD(ID_LANGUAGE, TYPE_STRING, struct track_entry, language), E_FIELD(ID_CODEC_ID, TYPE_STRING, struct track_entry, codec_id), E_FIELD(ID_CODEC_PRIVATE, TYPE_BINARY, struct track_entry, codec_private), + E_FIELD(ID_CODEC_DELAY, TYPE_UINT, struct track_entry, codec_delay), + E_FIELD(ID_SEEK_PREROLL, TYPE_UINT, struct track_entry, seek_preroll), E_SINGLE_MASTER(ID_VIDEO, TYPE_MASTER, struct track_entry, video), E_SINGLE_MASTER(ID_AUDIO, TYPE_MASTER, struct track_entry, audio), E_LAST @@ -1365,6 +1375,35 @@ ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_pac return 1; } +static int +ne_read_discard_padding(nestegg * ctx, nestegg_packet * pkt) +{ + int r; + uint64_t id, size; + struct ebml_element_desc * element; + struct ebml_type * storage; + + r = ne_peek_element(ctx, &id, &size); + if (r != 1) + return r; + + if (id != ID_DISCARD_PADDING) + return 1; + + element = ne_find_element(id, ctx->ancestor->node); + if (!element) + return 1; + + 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 uint64_t ne_buf_read_id(unsigned char const * p, size_t length) { @@ -1994,34 +2033,40 @@ nestegg_track_codec_data(nestegg * ctx, unsigned int track, unsigned int item, if (!entry) return -1; - if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS) + if (nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_VORBIS + && nestegg_track_codec_id(ctx, track) != NESTEGG_CODEC_OPUS) return -1; if (ne_get_binary(entry->codec_private, &codec_private) != 0) return -1; - p = codec_private.data; - count = *p++ + 1; + if (nestegg_track_codec_id(ctx, track) == NESTEGG_CODEC_VORBIS) { + p = codec_private.data; + count = *p++ + 1; - if (count > 3) - return -1; + if (count > 3) + return -1; - i = 0; - total = 0; - while (--count) { - sizes[i] = ne_xiph_lace_value(&p); - total += sizes[i]; - i += 1; + i = 0; + total = 0; + while (--count) { + sizes[i] = ne_xiph_lace_value(&p); + total += sizes[i]; + i += 1; + } + sizes[i] = codec_private.length - total - (p - codec_private.data); + + for (i = 0; i < item; ++i) { + if (sizes[i] > LIMIT_FRAME) + return -1; + p += sizes[i]; + } + *data = p; + *length = sizes[item]; + } else { + *data = codec_private.data; + *length = codec_private.length; } - sizes[i] = codec_private.length - total - (p - codec_private.data); - - for (i = 0; i < item; ++i) { - if (sizes[i] > LIMIT_FRAME) - return -1; - p += sizes[i]; - } - *data = p; - *length = sizes[item]; return 0; } @@ -2110,6 +2155,14 @@ nestegg_track_audio_params(nestegg * ctx, unsigned int track, ne_get_uint(entry->audio.bit_depth, &value); params->depth = value; + value = 0; + ne_get_uint(entry->codec_delay, &value); + params->codec_delay = value; + + value = 0; + ne_get_uint(entry->seek_preroll, &value); + params->seek_preroll = value; + return 0; } @@ -2135,6 +2188,13 @@ nestegg_read_packet(nestegg * ctx, nestegg_packet ** pkt) /* The only DESC_FLAG_SUSPEND fields are Blocks and SimpleBlocks, which we handle directly. */ r = ne_read_block(ctx, id, size, pkt); + if (r != 1) + return r; + + r = ne_read_discard_padding(ctx, *pkt); + if (r != 1) + return r; + return r; } @@ -2175,6 +2235,13 @@ nestegg_packet_tstamp(nestegg_packet * pkt, uint64_t * tstamp) return 0; } +int +nestegg_packet_discard_padding(nestegg_packet * pkt, int64_t * discard_padding) +{ + *discard_padding = pkt->discard_padding; + return 0; +} + int nestegg_packet_count(nestegg_packet * pkt, unsigned int * count) { From 7b9a9d912c5c1387d750e1b381c93d67f3ac1197 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 19 Nov 2013 14:28:09 -0500 Subject: [PATCH 045/268] Bug 940573 - make the global's ProtoAndIfaceArray an actual object; r=bz --- dom/bindings/BindingUtils.cpp | 2 +- dom/bindings/BindingUtils.h | 35 +++++++++++++++++++---------------- dom/bindings/Codegen.py | 5 +++-- dom/bindings/DOMJSClass.h | 6 ++++-- 4 files changed, 27 insertions(+), 21 deletions(-) diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index ece2aaed67d7..e76caf924df0 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1117,7 +1117,7 @@ ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle wrapper, JS::Rooted global(cx, js::GetGlobalForObjectCrossCompartment(obj)); { JSAutoCompartment ac(cx, global); - JS::Heap* protoAndIfaceArray = GetProtoAndIfaceArray(global); + ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(global); JSObject* protoOrIface = protoAndIfaceArray[protoAndIfaceArrayIndex]; if (!protoOrIface) { return false; diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 711c16a08f86..c37b5efba879 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -10,6 +10,7 @@ #include "jsfriendapi.h" #include "jswrapper.h" #include "mozilla/Alignment.h" +#include "mozilla/Array.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/CallbackObject.h" #include "mozilla/dom/DOMJSClass.h" @@ -280,21 +281,28 @@ static_assert((size_t)constructors::id::_ID_Start == "Overlapping or discontiguous indexes."); const size_t kProtoAndIfaceCacheCount = constructors::id::_ID_Count; +class ProtoAndIfaceArray : public Array, kProtoAndIfaceCacheCount> +{ +public: + ProtoAndIfaceArray() { + MOZ_COUNT_CTOR(ProtoAndIfaceArray); + } + + ~ProtoAndIfaceArray() { + MOZ_COUNT_DTOR(ProtoAndIfaceArray); + } +}; + inline void AllocateProtoAndIfaceCache(JSObject* obj) { MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL); MOZ_ASSERT(js::GetReservedSlot(obj, DOM_PROTOTYPE_SLOT).isUndefined()); - JS::Heap* protoAndIfaceArray = new JS::Heap[kProtoAndIfaceCacheCount]; + ProtoAndIfaceArray* protoAndIfaceArray = new ProtoAndIfaceArray(); js::SetReservedSlot(obj, DOM_PROTOTYPE_SLOT, JS::PrivateValue(protoAndIfaceArray)); - -#ifdef NS_BUILD_REFCNT_LOGGING - NS_LogCtor((void*)protoAndIfaceArray, "ProtoAndIfaceArray", - sizeof(JS::Heap) * kProtoAndIfaceCacheCount); -#endif } inline void @@ -304,8 +312,8 @@ TraceProtoAndIfaceCache(JSTracer* trc, JSObject* obj) if (!HasProtoAndIfaceArray(obj)) return; - JS::Heap* protoAndIfaceArray = GetProtoAndIfaceArray(obj); - for (size_t i = 0; i < kProtoAndIfaceCacheCount; ++i) { + ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(obj); + for (size_t i = 0; i < ArrayLength(protoAndIfaceArray); ++i) { if (protoAndIfaceArray[i]) { JS_CallHeapObjectTracer(trc, &protoAndIfaceArray[i], "protoAndIfaceArray[i]"); } @@ -317,14 +325,9 @@ DestroyProtoAndIfaceCache(JSObject* obj) { MOZ_ASSERT(js::GetObjectClass(obj)->flags & JSCLASS_DOM_GLOBAL); - JS::Heap* protoAndIfaceArray = GetProtoAndIfaceArray(obj); + ProtoAndIfaceArray* protoAndIfaceArray = GetProtoAndIfaceArray(obj); -#ifdef NS_BUILD_REFCNT_LOGGING - NS_LogDtor((void*)protoAndIfaceArray, "ProtoAndIfaceArray", - sizeof(JS::Heap) * kProtoAndIfaceCacheCount); -#endif - - delete [] protoAndIfaceArray; + delete protoAndIfaceArray; } /** @@ -2066,7 +2069,7 @@ ReportLenientThisUnwrappingFailure(JSContext* cx, JSObject* obj); inline JSObject* GetUnforgeableHolder(JSObject* aGlobal, prototypes::ID aId) { - JS::Heap* protoAndIfaceArray = GetProtoAndIfaceArray(aGlobal); + ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(aGlobal); JSObject* interfaceProto = protoAndIfaceArray[aId]; return &js::GetReservedSlot(interfaceProto, DOM_INTERFACE_PROTO_SLOTS_BASE).toObject(); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index b4d90639d45b..ef705099b859 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1800,7 +1800,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): def __init__(self, descriptor, properties): args = [Argument('JSContext*', 'aCx'), Argument('JS::Handle', 'aGlobal'), - Argument('JS::Heap*', 'aProtoAndIfaceArray'), + Argument('ProtoAndIfaceArray&', 'aProtoAndIfaceArray'), Argument('bool', 'aDefineOnGlobal')] CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args) self.properties = properties @@ -2012,7 +2012,7 @@ class CGGetPerInterfaceObject(CGAbstractMethod): return JS::NullPtr(); } /* Check to see whether the interface objects are already installed */ - JS::Heap* protoAndIfaceArray = GetProtoAndIfaceArray(aGlobal); + ProtoAndIfaceArray& protoAndIfaceArray = *GetProtoAndIfaceArray(aGlobal); if (!protoAndIfaceArray[%s]) { CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceArray, aDefineOnGlobal); } @@ -9068,6 +9068,7 @@ class CGForwardDeclarations(CGWrapper): # We just about always need NativePropertyHooks builder.addInMozillaDom("NativePropertyHooks") + builder.addInMozillaDom("ProtoAndIfaceArray") for callback in mainCallbacks: forwardDeclareForType(callback) diff --git a/dom/bindings/DOMJSClass.h b/dom/bindings/DOMJSClass.h index c0842317ebc6..9d79dfe2d0e3 100644 --- a/dom/bindings/DOMJSClass.h +++ b/dom/bindings/DOMJSClass.h @@ -216,6 +216,8 @@ struct DOMIfaceAndProtoJSClass const JSClass* ToJSClass() const { return &mBase; } }; +class ProtoAndIfaceArray; + inline bool HasProtoAndIfaceArray(JSObject* global) { @@ -224,11 +226,11 @@ HasProtoAndIfaceArray(JSObject* global) return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined(); } -inline JS::Heap* +inline ProtoAndIfaceArray* GetProtoAndIfaceArray(JSObject* global) { MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); - return static_cast*>( + return static_cast( js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate()); } From a6f016747de70778a472bbb8f50131406c85be04 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 20 Nov 2013 13:48:45 +0100 Subject: [PATCH 047/268] Bug 939194 - Bump iid of nsIXMLHttpRequestEventTarget. r=bz --- content/base/public/nsIXMLHttpRequest.idl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/base/public/nsIXMLHttpRequest.idl b/content/base/public/nsIXMLHttpRequest.idl index 5ea99210820e..9cab424bc3c7 100644 --- a/content/base/public/nsIXMLHttpRequest.idl +++ b/content/base/public/nsIXMLHttpRequest.idl @@ -16,7 +16,7 @@ interface nsIGlobalObject; interface nsIInputStream; interface nsIDOMBlob; -[scriptable, builtinclass, uuid(ac97e161-9f1d-4163-adc9-e9a59e18682c)] +[scriptable, builtinclass, uuid(5ced7e7a-e2c3-4563-a57d-31b97ce64dc5)] interface nsIXMLHttpRequestEventTarget : nsIDOMEventTarget { // event handler attributes }; From 8e269c2f4ca6b3e56b6e6fb7f88248f7fefd887f Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Wed, 20 Nov 2013 06:07:53 -0500 Subject: [PATCH 048/268] Bug 940928 - delete redundant entry for cgdb in the debuggers list; r=jmaher --- build/automationutils.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/automationutils.py b/build/automationutils.py index 367419a56b5c..e579a8d64fac 100644 --- a/build/automationutils.py +++ b/build/automationutils.py @@ -58,10 +58,6 @@ DEBUGGER_INFO = { "args": "-q --args" }, - "cgdb": { - "interactive": True, - "args": "-q --args" - }, "cgdb": { "interactive": True, "args": "-q --args" From b96e3cdf500a3a9086790d14ec796af653a61f54 Mon Sep 17 00:00:00 2001 From: Hasil Sharma Date: Tue, 12 Nov 2013 10:18:00 +0000 Subject: [PATCH 049/268] Bug 931367 - UnboundLocalError when generating an XML report with no results. r=dhunt --- testing/marionette/client/marionette/runtests.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testing/marionette/client/marionette/runtests.py b/testing/marionette/client/marionette/runtests.py index 1bd6a3570469..9b4cd6258760 100644 --- a/testing/marionette/client/marionette/runtests.py +++ b/testing/marionette/client/marionette/runtests.py @@ -708,8 +708,7 @@ class MarionetteTestRunner(object): for results in results_list]))) testsuite.setAttribute('errors', str(sum([len(results.errors) for results in results_list]))) - if hasattr(results, 'skipped'): - testsuite.setAttribute('skips', str(sum([len(results.skipped) + + testsuite.setAttribute('skips', str(sum([len(results.skipped) + len(results.expectedFailures) for results in results_list]))) From fea1d68c43ac772f522c7ea1e2c816db835fa5b4 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 20 Nov 2013 08:16:19 -0500 Subject: [PATCH 050/268] Bug 939835. Fix up performance regressions from bug 937772. r=h4writer There are two changes here. 1) When trying to eliminate type barriers, skip over infallible unboxes, not just barriered ones. 2) When we statically know a value is double or int but dynamically we've only observed integers, keep allowing TI to barrier and specialize to integer instead of forcing the value to be treatd as a double. --- js/src/jit/IonAnalysis.cpp | 7 ++--- js/src/jit/IonBuilder.cpp | 58 ++++++++++++++++++++++++-------------- js/src/jit/IonBuilder.h | 5 ++++ 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 42c1e5a3f917..f6ad33c1d84f 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -1576,7 +1576,7 @@ TryEliminateTypeBarrierFromTest(MTypeBarrier *barrier, bool filtersNull, bool fi // Disregard the possible unbox added before the Typebarrier for checking. MDefinition *input = barrier->input(); - if (input->isUnbox() && input->toUnbox()->mode() == MUnbox::TypeBarrier) + if (input->isUnbox() && input->toUnbox()->mode() != MUnbox::Fallible) input = input->toUnbox()->input(); if (test->getOperand(0) == input && direction == TRUE_BRANCH) { @@ -1626,11 +1626,8 @@ TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated) const types::TemporaryTypeSet *inputTypes = barrier->input()->resultTypeSet(); // Disregard the possible unbox added before the Typebarrier. - if (barrier->input()->isUnbox() && - barrier->input()->toUnbox()->mode() == MUnbox::TypeBarrier) - { + if (barrier->input()->isUnbox() && barrier->input()->toUnbox()->mode() != MUnbox::Fallible) inputTypes = barrier->input()->toUnbox()->input()->resultTypeSet(); - } if (!barrierTypes || !inputTypes) return true; diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index 3f59b68a839a..d4b24b6edc8b 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -5251,21 +5251,10 @@ IonBuilder::makeCall(JSFunction *target, CallInfo &callInfo, bool cloneAtCallsit types::TemporaryTypeSet *types = bytecodeTypes(pc); - bool barrier = true; - MDefinition *replace = call; - if (call->isDOMFunction()) { - JSFunction* target = call->getSingleTarget(); - JS_ASSERT(target && target->isNative() && target->jitInfo()); - const JSJitInfo *jitinfo = target->jitInfo(); - barrier = DOMCallNeedsBarrier(jitinfo, types); - replace = ensureDefiniteType(call, jitinfo->returnType); - if (replace != call) { - current->pop(); - current->push(replace); - } - } + if (call->isDOMFunction()) + return pushDOMTypeBarrier(call, types, call->getSingleTarget()); - return pushTypeBarrier(replace, types, barrier); + return pushTypeBarrier(call, types, true); } bool @@ -6147,6 +6136,38 @@ IonBuilder::pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, return true; } +bool +IonBuilder::pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func) +{ + JS_ASSERT(func && func->isNative() && func->jitInfo()); + + const JSJitInfo *jitinfo = func->jitInfo(); + bool barrier = DOMCallNeedsBarrier(jitinfo, observed); + // Need to be a bit careful: if jitinfo->returnType is JSVAL_TYPE_DOUBLE but + // types->getKnownTypeTag() is JSVAL_TYPE_INT32, then don't unconditionally + // unbox as a double. Instead, go ahead and barrier on having an int type, + // since we know we need a barrier anyway due to the type mismatch. This is + // the only situation in which TI actually has more information about the + // JSValueType than codegen can, short of jitinfo->returnType just being + // JSVAL_TYPE_UNKNOWN. + MDefinition* replace = ins; + if (jitinfo->returnType != JSVAL_TYPE_DOUBLE || + observed->getKnownTypeTag() != JSVAL_TYPE_INT32) { + JS_ASSERT(jitinfo->returnType == JSVAL_TYPE_UNKNOWN || + observed->getKnownTypeTag() == JSVAL_TYPE_UNKNOWN || + jitinfo->returnType == observed->getKnownTypeTag()); + replace = ensureDefiniteType(ins, jitinfo->returnType); + if (replace != ins) { + current->pop(); + current->push(replace); + } + } else { + JS_ASSERT(barrier); + } + + return pushTypeBarrier(replace, observed, barrier); +} + MDefinition * IonBuilder::ensureDefiniteType(MDefinition *def, JSValueType definiteType) { @@ -8341,13 +8362,8 @@ IonBuilder::getPropTryCommonGetter(bool *emitted, PropertyName *name, if (get->isEffectful() && !resumeAfter(get)) return false; - bool barrier = DOMCallNeedsBarrier(jitinfo, types); - MDefinition *replace = ensureDefiniteType(get, jitinfo->returnType); - if (replace != get) { - current->pop(); - current->push(replace); - } - if (!pushTypeBarrier(replace, types, barrier)) + + if (!pushDOMTypeBarrier(get, types, commonGetter)) return false; *emitted = true; diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index df6a2c1e50fb..7c44639f0504 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -334,6 +334,11 @@ class IonBuilder : public MIRGenerator // generated code correspond to the observed types for the bytecode. bool pushTypeBarrier(MDefinition *def, types::TemporaryTypeSet *observed, bool needBarrier); + // As pushTypeBarrier, but will compute the needBarrier boolean itself based + // on observed and the JSFunction that we're planning to call. The + // JSFunction must be a DOM method or getter. + bool pushDOMTypeBarrier(MInstruction *ins, types::TemporaryTypeSet *observed, JSFunction* func); + // If definiteType is not known or def already has the right type, just // returns def. Otherwise, returns an MInstruction that has that definite // type, infallibly unboxing ins as needed. The new instruction will be From e50efdc6a33804a8f949d8154f3e0c18c7956f50 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Wed, 20 Nov 2013 08:16:19 -0500 Subject: [PATCH 051/268] Bug 940686. When we eliminate a barrier, make its unbox infallible if it was a barrier-type unbox before. r=h4writer --- js/src/jit/IonAnalysis.cpp | 11 +++++++++-- js/src/jit/MIR.h | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index f6ad33c1d84f..999c38c2eae9 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -1576,11 +1576,16 @@ TryEliminateTypeBarrierFromTest(MTypeBarrier *barrier, bool filtersNull, bool fi // Disregard the possible unbox added before the Typebarrier for checking. MDefinition *input = barrier->input(); - if (input->isUnbox() && input->toUnbox()->mode() != MUnbox::Fallible) - input = input->toUnbox()->input(); + MUnbox *inputUnbox = nullptr; + if (input->isUnbox() && input->toUnbox()->mode() != MUnbox::Fallible) { + inputUnbox = input->toUnbox(); + input = inputUnbox->input(); + } if (test->getOperand(0) == input && direction == TRUE_BRANCH) { *eliminated = true; + if (inputUnbox) + inputUnbox->makeInfallible(); barrier->replaceAllUsesWith(barrier->input()); return; } @@ -1614,6 +1619,8 @@ TryEliminateTypeBarrierFromTest(MTypeBarrier *barrier, bool filtersNull, bool fi } *eliminated = true; + if (inputUnbox) + inputUnbox->makeInfallible(); barrier->replaceAllUsesWith(barrier->input()); } diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 849a65716207..25b8ca986bbc 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -2373,6 +2373,11 @@ class MUnbox : public MUnaryInstruction, public BoxInputsPolicy return AliasSet::None(); } void printOpcode(FILE *fp) const; + void makeInfallible() { + // Should only be called if we're already Infallible or TypeBarrier + JS_ASSERT(mode() != Fallible); + mode_ = Infallible; + } }; class MGuardObject : public MUnaryInstruction, public SingleObjectPolicy From 97c1353a692dd11cc7da41a0f844fd605ca4d0cd Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Fri, 18 Oct 2013 13:22:09 +0200 Subject: [PATCH 052/268] Bug 938131 - Simplify dom::ErrorResult::ReportJSExceptionFromJSImplementation. r=bz. --HG-- extra : rebase_source : db7b8edd1aec3aff7240b1323c00546d2e332112 --- dom/bindings/BindingUtils.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index e76caf924df0..cd688c7bedbe 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -214,16 +214,7 @@ ErrorResult::ReportJSExceptionFromJSImplementation(JSContext* aCx) nsString message; domError->GetMessage(message); - JSErrorReport errorReport; - memset(&errorReport, 0, sizeof(JSErrorReport)); - errorReport.errorNumber = JSMSG_USER_DEFINED_ERROR; - errorReport.ucmessage = message.get(); - errorReport.exnType = JSEXN_ERR; - JS::Rooted script(aCx); - if (JS_DescribeScriptedCaller(aCx, &script, &errorReport.lineno)) { - errorReport.filename = JS_GetScriptFilename(aCx, script); - } - JS_ThrowReportedError(aCx, nullptr, &errorReport); + JS_ReportError(aCx, "%hs", message.get()); JS_RemoveValueRoot(aCx, &mJSException); // We no longer have a useful exception but we do want to signal that an error From 794b2d6bd9121410d6ec40058a28f3e972d8ac87 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Mon, 12 Aug 2013 16:45:33 +0200 Subject: [PATCH 053/268] Bug 938544 - Add support for a Chrome-only constructor in WebIDL. r=bz. --HG-- extra : rebase_source : e36fef0090d57947ceae6c2fc11bea8b115423e4 --- dom/bindings/Codegen.py | 16 +++++--- dom/bindings/parser/WebIDL.py | 14 +++++-- dom/bindings/parser/tests/test_constructor.py | 38 ++++++++++++++++++- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index ef705099b859..4a9395e4af18 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -1141,6 +1141,11 @@ class CGClassConstructor(CGAbstractStaticMethod): JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::Rooted obj(cx, &args.callee()); """ + if isChromeOnly(self._ctor): + preamble += """ if (!%s) { + return ThrowingConstructor(cx, argc, vp); + } +""" % GetAccessCheck(self.descriptor, "cx", "obj") name = self._ctor.identifier.name nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name)) callGenerator = CGMethodCall(nativeName, True, self.descriptor, @@ -1957,7 +1962,7 @@ if (!unforgeableHolder) { else: properties = "nullptr" if self.properties.hasChromeOnly(): - accessCheck = GetAccessCheck(self.descriptor, "aGlobal") + accessCheck = GetAccessCheck(self.descriptor, "aCx", "aGlobal") chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr" else: chromeProperties = "nullptr" @@ -2143,7 +2148,7 @@ class CGConstructorEnabledChromeOnly(CGAbstractMethod): Argument("JS::Handle", "aObj")]) def definition_body(self): - return " return %s;" % GetAccessCheck(self.descriptor, "aObj") + return " return %s;" % GetAccessCheck(self.descriptor, "aCx", "aObj") class CGConstructorEnabledViaFunc(CGAbstractMethod): """ @@ -2211,13 +2216,14 @@ def CreateBindingJSObject(descriptor, properties, parent): """ return create % parent -def GetAccessCheck(descriptor, object): +def GetAccessCheck(descriptor, context, object): """ + context is the name of a JSContext* object is the name of a JSObject* returns a string """ - return "ThreadsafeCheckIsChrome(aCx, %s)" % object + return "ThreadsafeCheckIsChrome(%s, %s)" % (context, object) def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""): """ @@ -2241,7 +2247,7 @@ def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturn unforgeables.append( CGIfWrapper(CGGeneric(defineUnforgeables % unforgeableAttrs.variableName(True)), - GetAccessCheck(descriptor, obj))) + GetAccessCheck(descriptor, "aCx", obj))) return CGList(unforgeables, "\n") def InitUnforgeableProperties(descriptor, properties): diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 22842e70c282..0e3680aaf496 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -868,7 +868,7 @@ class IDLInterface(IDLObjectWithScope): [self.location]) self._noInterfaceObject = True - elif identifier == "Constructor" or identifier == "NamedConstructor": + elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor": if identifier == "Constructor" and not self.hasInterfaceObject(): raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", [self.location]) @@ -877,11 +877,15 @@ class IDLInterface(IDLObjectWithScope): raise WebIDLError("NamedConstructor must either take an identifier or take a named argument list", [attr.location]) + if identifier == "ChromeConstructor" and not self.hasInterfaceObject(): + raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", + [self.location]) + args = attr.args() if attr.hasArgs() else [] retType = IDLWrapperType(self.location, self) - if identifier == "Constructor": + if identifier == "Constructor" or identifier == "ChromeConstructor": name = "constructor" allowForbidden = True else: @@ -900,9 +904,11 @@ class IDLInterface(IDLObjectWithScope): method.addExtendedAttributes( [IDLExtendedAttribute(self.location, ("NewObject",)), IDLExtendedAttribute(self.location, ("Throws",))]) + if identifier == "ChromeConstructor": + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) - - if identifier == "Constructor": + if identifier == "Constructor" or identifier == "ChromeConstructor": method.resolve(self) else: # We need to detect conflicts for NamedConstructors across diff --git a/dom/bindings/parser/tests/test_constructor.py b/dom/bindings/parser/tests/test_constructor.py index 97ab90d4389e..348204c7dc12 100644 --- a/dom/bindings/parser/tests/test_constructor.py +++ b/dom/bindings/parser/tests/test_constructor.py @@ -12,7 +12,8 @@ def WebIDLTest(parser, harness): def checkMethod(method, QName, name, signatures, static=True, getter=False, setter=False, creator=False, - deleter=False, legacycaller=False, stringifier=False): + deleter=False, legacycaller=False, stringifier=False, + chromeOnly=False): harness.ok(isinstance(method, WebIDL.IDLMethod), "Should be an IDLMethod") harness.ok(method.isMethod(), "Method is a method") @@ -27,6 +28,7 @@ def WebIDLTest(parser, harness): harness.check(method.isDeleter(), deleter, "Method has the correct deleter value") harness.check(method.isLegacycaller(), legacycaller, "Method has the correct legacycaller value") harness.check(method.isStringifier(), stringifier, "Method has the correct stringifier value") + harness.check(method.getExtendedAttribute("ChromeOnly") is not None, chromeOnly, "Method has the correct value for ChromeOnly") harness.check(len(method.signatures()), len(signatures), "Method has the correct number of signatures") sigpairs = zip(method.signatures(), signatures) @@ -55,11 +57,13 @@ def WebIDLTest(parser, harness): }; """) results = parser.finish() - harness.check(len(results), 3, "Should be two productions") + harness.check(len(results), 3, "Should be three productions") harness.ok(isinstance(results[0], WebIDL.IDLInterface), "Should be an IDLInterface") harness.ok(isinstance(results[1], WebIDL.IDLInterface), "Should be an IDLInterface") + harness.ok(isinstance(results[2], WebIDL.IDLInterface), + "Should be an IDLInterface") checkMethod(results[0].ctor(), "::TestConstructorNoArgs::constructor", "constructor", [("TestConstructorNoArgs (Wrapper)", [])]) @@ -73,3 +77,33 @@ def WebIDLTest(parser, harness): [("::TestConstructorOverloads::constructor::foo", "foo", "Object", False, False)]), ("TestConstructorOverloads (Wrapper)", [("::TestConstructorOverloads::constructor::bar", "bar", "Boolean", False, False)])]) + + parser = parser.reset() + parser.parse(""" + [ChromeConstructor()] + interface TestChromeConstructor { + }; + """) + results = parser.finish() + harness.check(len(results), 1, "Should be one production") + harness.ok(isinstance(results[0], WebIDL.IDLInterface), + "Should be an IDLInterface") + + checkMethod(results[0].ctor(), "::TestChromeConstructor::constructor", + "constructor", [("TestChromeConstructor (Wrapper)", [])], + chromeOnly=True) + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [Constructor(), + ChromeConstructor(DOMString a)] + interface TestChromeConstructor { + }; + """) + results = parser.finish() + except: + threw = True + + harness.ok(threw, "Can't have both a Constructor and a ChromeConstructor") From ddad8f2f258ca8644b831c2f190e0abc418649fa Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Wed, 20 Nov 2013 13:54:58 +0000 Subject: [PATCH 054/268] Bug 936835 - Adding script runners or messing with mLinksToUpdate during FlushPendingLinkUpdates is not allowed. r=bz --- content/base/public/nsIDocument.h | 8 ++++++++ content/base/src/nsDocument.cpp | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 1e94bb1fea7b..56912b3b0bdd 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -2390,6 +2390,14 @@ protected: // caches. bool mDidDocumentOpen; +#ifdef DEBUG + /** + * This is true while FlushPendingLinkUpdates executes. Calls to + * [Un]RegisterPendingLinkUpdate will assert when this is true. + */ + bool mIsLinkUpdateRegistrationsForbidden; +#endif + // The document's script global object, the object from which the // document can get its script context and scope. This is the // *inner* window object. diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 6b5feb2e73ff..c4e87db6b68c 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -10,6 +10,7 @@ #include "nsDocument.h" +#include "mozilla/AutoRestore.h" #include "mozilla/DebugOnly.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Util.h" @@ -8812,6 +8813,7 @@ nsIDocument::EnumerateFreezableElements(FreezableElementEnumerator aEnumerator, void nsIDocument::RegisterPendingLinkUpdate(Link* aLink) { + MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden); mLinksToUpdate.PutEntry(aLink); mHasLinksToUpdate = true; } @@ -8819,6 +8821,7 @@ nsIDocument::RegisterPendingLinkUpdate(Link* aLink) void nsIDocument::UnregisterPendingLinkUpdate(Link* aLink) { + MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden); if (!mHasLinksToUpdate) return; @@ -8835,10 +8838,14 @@ EnumeratePendingLinkUpdates(nsPtrHashKey* aEntry, void* aData) void nsIDocument::FlushPendingLinkUpdates() { + MOZ_ASSERT(!mIsLinkUpdateRegistrationsForbidden); if (!mHasLinksToUpdate) return; - nsAutoScriptBlocker scriptBlocker; +#ifdef DEBUG + AutoRestore saved(mIsLinkUpdateRegistrationsForbidden); + mIsLinkUpdateRegistrationsForbidden = true; +#endif mLinksToUpdate.EnumerateEntries(EnumeratePendingLinkUpdates, nullptr); mLinksToUpdate.Clear(); mHasLinksToUpdate = false; From d5481a6e4030b1cf1f71baf96ddc0b297dfc9a66 Mon Sep 17 00:00:00 2001 From: Robert Bindar Date: Wed, 20 Nov 2013 09:29:01 -0500 Subject: [PATCH 055/268] Bug 923686 - Refactor about:networking return values. r=hurley --- dom/webidl/NetDashboard.webidl | 81 ++++--- netwerk/base/src/Dashboard.cpp | 229 +++++++----------- netwerk/test/unit/test_about_networking.js | 28 ++- .../test/unit/test_ping_aboutnetworking.js | 21 +- toolkit/content/aboutNetworking.js | 54 ++--- .../tests/chrome/test_about_networking.html | 10 +- 6 files changed, 206 insertions(+), 217 deletions(-) diff --git a/dom/webidl/NetDashboard.webidl b/dom/webidl/NetDashboard.webidl index 2e5e0c535470..12bbb01f084a 100644 --- a/dom/webidl/NetDashboard.webidl +++ b/dom/webidl/NetDashboard.webidl @@ -3,60 +3,75 @@ * 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/. */ -dictionary SocketsDict { - sequence host; - sequence port; - sequence active; - sequence tcp; - sequence socksent; - sequence sockreceived; +dictionary SocketElement { + DOMString host = ""; + unsigned long port = 0; + boolean active = false; + boolean tcp = false; double sent = 0; double received = 0; }; -dictionary HttpConnInfoDict { - sequence rtt; - sequence ttl; - sequence protocolVersion; +dictionary SocketsDict { + sequence sockets; + double sent = 0; + double received = 0; +}; + +dictionary HttpConnInfo { + unsigned long rtt = 0; + unsigned long ttl = 0; + DOMString protocolVersion = ""; }; dictionary HalfOpenInfoDict { - sequence speculative; + boolean speculative = false; +}; + +dictionary HttpConnectionElement { + DOMString host = ""; + unsigned long port = 0; + boolean spdy = false; + boolean ssl = false; + sequence active; + sequence idle; + sequence halfOpens; }; dictionary HttpConnDict { - sequence host; - sequence port; - sequence active; - sequence idle; - sequence halfOpens; - sequence spdy; - sequence ssl; + sequence connections; +}; + +dictionary WebSocketElement { + DOMString hostport = ""; + unsigned long msgsent = 0; + unsigned long msgreceived = 0; + double sentsize = 0; + double receivedsize = 0; + boolean encrypted = false; }; dictionary WebSocketDict { - sequence hostport; - sequence msgsent; - sequence msgreceived; - sequence sentsize; - sequence receivedsize; - sequence encrypted; + sequence websockets; +}; + +dictionary DnsCacheEntry { + DOMString hostname = ""; + sequence hostaddr; + DOMString family = ""; + double expiration = 0; }; dictionary DNSCacheDict { - sequence hostname; - sequence> hostaddr; - sequence family; - sequence expiration; + sequence entries; }; dictionary DNSLookupDict { sequence address; - DOMString error; - boolean answer; + DOMString error = ""; + boolean answer = false; }; dictionary ConnStatusDict { - DOMString status; + DOMString status = ""; }; - diff --git a/netwerk/base/src/Dashboard.cpp b/netwerk/base/src/Dashboard.cpp index a482d1ab941a..fb4ecb0b229b 100644 --- a/netwerk/base/src/Dashboard.cpp +++ b/netwerk/base/src/Dashboard.cpp @@ -74,26 +74,14 @@ Dashboard::GetSockets() AutoSafeJSContext cx; mozilla::dom::SocketsDict dict; - dict.mHost.Construct(); - dict.mPort.Construct(); - dict.mActive.Construct(); - dict.mTcp.Construct(); - dict.mSocksent.Construct(); - dict.mSockreceived.Construct(); + dict.mSockets.Construct(); dict.mSent = 0; dict.mReceived = 0; - Sequence &ports = dict.mPort.Value(); - Sequence &hosts = dict.mHost.Value(); - Sequence &active = dict.mActive.Value(); - Sequence &tcp = dict.mTcp.Value(); - Sequence &sent = dict.mSocksent.Value(); - Sequence &received = dict.mSockreceived.Value(); + Sequence &sockets = dict.mSockets.Value(); uint32_t length = mSock.data.Length(); - if (!ports.SetCapacity(length) || !hosts.SetCapacity(length) || - !active.SetCapacity(length) || !tcp.SetCapacity(length) || - !sent.SetCapacity(length) || !received.SetCapacity(length)) { + if (!sockets.SetCapacity(length)) { mSock.cb = nullptr; mSock.data.Clear(); JS_ReportOutOfMemory(cx); @@ -101,19 +89,19 @@ Dashboard::GetSockets() } for (uint32_t i = 0; i < mSock.data.Length(); i++) { - CopyASCIItoUTF16(mSock.data[i].host, *hosts.AppendElement()); - *ports.AppendElement() = mSock.data[i].port; - *active.AppendElement() = mSock.data[i].active; - *tcp.AppendElement() = mSock.data[i].tcp; - *sent.AppendElement() = (double) mSock.data[i].sent; - *received.AppendElement() = (double) mSock.data[i].received; + mozilla::dom::SocketElement &socket = *sockets.AppendElement(); + CopyASCIItoUTF16(mSock.data[i].host, socket.mHost); + socket.mPort = mSock.data[i].port; + socket.mActive = mSock.data[i].active; + socket.mTcp = mSock.data[i].tcp; + socket.mSent = (double) mSock.data[i].sent; + socket.mReceived = (double) mSock.data[i].received; dict.mSent += mSock.data[i].sent; dict.mReceived += mSock.data[i].received; } dict.mSent += mSock.totalSent; dict.mReceived += mSock.totalRecv; - JS::RootedValue val(cx); if (!dict.ToObject(cx, JS::NullPtr(), &val)) { mSock.cb = nullptr; @@ -155,29 +143,15 @@ Dashboard::GetHttpConnections() AutoSafeJSContext cx; mozilla::dom::HttpConnDict dict; - dict.mActive.Construct(); - dict.mHost.Construct(); - dict.mIdle.Construct(); - dict.mPort.Construct(); - dict.mSpdy.Construct(); - dict.mSsl.Construct(); - dict.mHalfOpens.Construct(); + dict.mConnections.Construct(); - using mozilla::dom::HttpConnInfoDict; using mozilla::dom::HalfOpenInfoDict; - Sequence &active = dict.mActive.Value(); - Sequence &hosts = dict.mHost.Value(); - Sequence &idle = dict.mIdle.Value(); - Sequence &halfOpens = dict.mHalfOpens.Value(); - Sequence &ports = dict.mPort.Value(); - Sequence &spdy = dict.mSpdy.Value(); - Sequence &ssl = dict.mSsl.Value(); + using mozilla::dom::HttpConnectionElement; + using mozilla::dom::HttpConnInfo; + Sequence &connections = dict.mConnections.Value(); uint32_t length = mHttp.data.Length(); - if (!active.SetCapacity(length) || !hosts.SetCapacity(length) || - !idle.SetCapacity(length) || !ports.SetCapacity(length) || - !spdy.SetCapacity(length) || !ssl.SetCapacity(length) || - !halfOpens.SetCapacity(length)) { + if (!connections.SetCapacity(length)) { mHttp.cb = nullptr; mHttp.data.Clear(); JS_ReportOutOfMemory(cx); @@ -185,64 +159,47 @@ Dashboard::GetHttpConnections() } for (uint32_t i = 0; i < mHttp.data.Length(); i++) { - CopyASCIItoUTF16(mHttp.data[i].host,*hosts.AppendElement()); - *ports.AppendElement() = mHttp.data[i].port; - *spdy.AppendElement() = mHttp.data[i].spdy; - *ssl.AppendElement() = mHttp.data[i].ssl; - HttpConnInfoDict &activeInfo = *active.AppendElement(); - activeInfo.mRtt.Construct(); - activeInfo.mTtl.Construct(); - activeInfo.mProtocolVersion.Construct(); - Sequence &active_rtt = activeInfo.mRtt.Value(); - Sequence &active_ttl = activeInfo.mTtl.Value(); - Sequence &active_protocolVersion = activeInfo.mProtocolVersion.Value(); - if (!active_rtt.SetCapacity(mHttp.data[i].active.Length()) || - !active_ttl.SetCapacity(mHttp.data[i].active.Length()) || - !active_protocolVersion.SetCapacity(mHttp.data[i].active.Length())) { + HttpConnectionElement &connection = *connections.AppendElement(); + + CopyASCIItoUTF16(mHttp.data[i].host, connection.mHost); + connection.mPort = mHttp.data[i].port; + connection.mSpdy = mHttp.data[i].spdy; + connection.mSsl = mHttp.data[i].ssl; + + connection.mActive.Construct(); + connection.mIdle.Construct(); + connection.mHalfOpens.Construct(); + + Sequence &active = connection.mActive.Value(); + Sequence &idle = connection.mIdle.Value(); + Sequence &halfOpens = connection.mHalfOpens.Value(); + + if (!active.SetCapacity(mHttp.data[i].active.Length()) || + !idle.SetCapacity(mHttp.data[i].idle.Length()) || + !halfOpens.SetCapacity(mHttp.data[i].halfOpens.Length())) { mHttp.cb = nullptr; mHttp.data.Clear(); JS_ReportOutOfMemory(cx); return NS_ERROR_OUT_OF_MEMORY; } + for (uint32_t j = 0; j < mHttp.data[i].active.Length(); j++) { - *active_rtt.AppendElement() = mHttp.data[i].active[j].rtt; - *active_ttl.AppendElement() = mHttp.data[i].active[j].ttl; - *active_protocolVersion.AppendElement() = mHttp.data[i].active[j].protocolVersion; + HttpConnInfo &info = *active.AppendElement(); + info.mRtt = mHttp.data[i].active[j].rtt; + info.mTtl = mHttp.data[i].active[j].ttl; + info.mProtocolVersion = mHttp.data[i].active[j].protocolVersion; } - HttpConnInfoDict &idleInfo = *idle.AppendElement(); - idleInfo.mRtt.Construct(); - idleInfo.mTtl.Construct(); - idleInfo.mProtocolVersion.Construct(); - Sequence &idle_rtt = idleInfo.mRtt.Value(); - Sequence &idle_ttl = idleInfo.mTtl.Value(); - Sequence &idle_protocolVersion = idleInfo.mProtocolVersion.Value(); - if (!idle_rtt.SetCapacity(mHttp.data[i].idle.Length()) || - !idle_ttl.SetCapacity(mHttp.data[i].idle.Length()) || - !idle_protocolVersion.SetCapacity(mHttp.data[i].idle.Length())) { - mHttp.cb = nullptr; - mHttp.data.Clear(); - JS_ReportOutOfMemory(cx); - return NS_ERROR_OUT_OF_MEMORY; - } for (uint32_t j = 0; j < mHttp.data[i].idle.Length(); j++) { - *idle_rtt.AppendElement() = mHttp.data[i].idle[j].rtt; - *idle_ttl.AppendElement() = mHttp.data[i].idle[j].ttl; - *idle_protocolVersion.AppendElement() = mHttp.data[i].idle[j].protocolVersion; + HttpConnInfo &info = *idle.AppendElement(); + info.mRtt = mHttp.data[i].idle[j].rtt; + info.mTtl = mHttp.data[i].idle[j].ttl; + info.mProtocolVersion = mHttp.data[i].idle[j].protocolVersion; } - HalfOpenInfoDict &allHalfOpens = *halfOpens.AppendElement(); - allHalfOpens.mSpeculative.Construct(); - Sequence allHalfOpens_speculative; - if(!allHalfOpens_speculative.SetCapacity(mHttp.data[i].halfOpens.Length())) { - mHttp.cb = nullptr; - mHttp.data.Clear(); - JS_ReportOutOfMemory(cx); - return NS_ERROR_OUT_OF_MEMORY; - } - allHalfOpens_speculative = allHalfOpens.mSpeculative.Value(); - for(uint32_t j = 0; j < mHttp.data[i].halfOpens.Length(); j++) { - *allHalfOpens_speculative.AppendElement() = mHttp.data[i].halfOpens[j].speculative; + for (uint32_t j = 0; j < mHttp.data[i].halfOpens.Length(); j++) { + HalfOpenInfoDict &info = *halfOpens.AppendElement(); + info.mSpeculative = mHttp.data[i].halfOpens[j].speculative; } } @@ -351,38 +308,26 @@ Dashboard::GetWebSocketConnections() AutoSafeJSContext cx; mozilla::dom::WebSocketDict dict; - dict.mEncrypted.Construct(); - dict.mHostport.Construct(); - dict.mMsgreceived.Construct(); - dict.mMsgsent.Construct(); - dict.mReceivedsize.Construct(); - dict.mSentsize.Construct(); - - Sequence &encrypted = dict.mEncrypted.Value(); - Sequence &hostport = dict.mHostport.Value(); - Sequence &received = dict.mMsgreceived.Value(); - Sequence &sent = dict.mMsgsent.Value(); - Sequence &receivedSize = dict.mReceivedsize.Value(); - Sequence &sentSize = dict.mSentsize.Value(); - - uint32_t length = mWs.data.Length(); - if (!encrypted.SetCapacity(length) || !hostport.SetCapacity(length) || - !received.SetCapacity(length) || !sent.SetCapacity(length) || - !receivedSize.SetCapacity(length) || !sentSize.SetCapacity(length)) { - mWs.cb = nullptr; - mWs.data.Clear(); - JS_ReportOutOfMemory(cx); - return NS_ERROR_OUT_OF_MEMORY; - } + dict.mWebsockets.Construct(); + Sequence &websockets = dict.mWebsockets.Value(); mozilla::MutexAutoLock lock(mWs.lock); + uint32_t length = mWs.data.Length(); + if (!websockets.SetCapacity(length)) { + mWs.cb = nullptr; + mWs.data.Clear(); + JS_ReportOutOfMemory(cx); + return NS_ERROR_OUT_OF_MEMORY; + } + for (uint32_t i = 0; i < mWs.data.Length(); i++) { - CopyASCIItoUTF16(mWs.data[i].mHost, *hostport.AppendElement()); - *sent.AppendElement() = mWs.data[i].mMsgSent; - *received.AppendElement() = mWs.data[i].mMsgReceived; - *receivedSize.AppendElement() = mWs.data[i].mSizeSent; - *sentSize.AppendElement() = mWs.data[i].mSizeReceived; - *encrypted.AppendElement() = mWs.data[i].mEncrypted; + mozilla::dom::WebSocketElement &websocket = *websockets.AppendElement(); + CopyASCIItoUTF16(mWs.data[i].mHost, websocket.mHostport); + websocket.mMsgsent = mWs.data[i].mMsgSent; + websocket.mMsgreceived = mWs.data[i].mMsgReceived; + websocket.mSentsize = mWs.data[i].mSizeSent; + websocket.mReceivedsize = mWs.data[i].mSizeReceived; + websocket.mEncrypted = mWs.data[i].mEncrypted; } JS::RootedValue val(cx); @@ -433,44 +378,40 @@ Dashboard::GetDNSCacheEntries() AutoSafeJSContext cx; mozilla::dom::DNSCacheDict dict; - dict.mExpiration.Construct(); - dict.mFamily.Construct(); - dict.mHostaddr.Construct(); - dict.mHostname.Construct(); - - Sequence &expiration = dict.mExpiration.Value(); - Sequence &family = dict.mFamily.Value(); - Sequence > &hostaddr = dict.mHostaddr.Value(); - Sequence &hostname = dict.mHostname.Value(); + dict.mEntries.Construct(); + Sequence &entries = dict.mEntries.Value(); uint32_t length = mDns.data.Length(); - if (!expiration.SetCapacity(length) || !family.SetCapacity(length) || - !hostaddr.SetCapacity(length) || !hostname.SetCapacity(length)) { - mDns.cb = nullptr; - mDns.data.Clear(); - JS_ReportOutOfMemory(cx); - return NS_ERROR_OUT_OF_MEMORY; + if (!entries.SetCapacity(length)) { + mDns.cb = nullptr; + mDns.data.Clear(); + JS_ReportOutOfMemory(cx); + return NS_ERROR_OUT_OF_MEMORY; } for (uint32_t i = 0; i < mDns.data.Length(); i++) { - CopyASCIItoUTF16(mDns.data[i].hostname, *hostname.AppendElement()); - *expiration.AppendElement() = mDns.data[i].expiration; + mozilla::dom::DnsCacheEntry &entry = *entries.AppendElement(); + entry.mHostaddr.Construct(); - Sequence &addrs = *hostaddr.AppendElement(); + Sequence &addrs = entry.mHostaddr.Value(); if (!addrs.SetCapacity(mDns.data[i].hostaddr.Length())) { mDns.cb = nullptr; mDns.data.Clear(); JS_ReportOutOfMemory(cx); return NS_ERROR_OUT_OF_MEMORY; } + + CopyASCIItoUTF16(mDns.data[i].hostname, entry.mHostname); + entry.mExpiration = mDns.data[i].expiration; + for (uint32_t j = 0; j < mDns.data[i].hostaddr.Length(); j++) { CopyASCIItoUTF16(mDns.data[i].hostaddr[j], *addrs.AppendElement()); } if (mDns.data[i].family == PR_AF_INET6) - CopyASCIItoUTF16("ipv6", *family.AppendElement()); + CopyASCIItoUTF16("ipv6", entry.mFamily); else - CopyASCIItoUTF16("ipv4", *family.AppendElement()); + CopyASCIItoUTF16("ipv4", entry.mFamily); } JS::RootedValue val(cx); @@ -518,15 +459,11 @@ Dashboard::OnLookupComplete(nsICancelable *aRequest, nsIDNSRecord *aRecord, nsre mozilla::dom::DNSLookupDict dict; dict.mAddress.Construct(); - dict.mError.Construct(); - dict.mAnswer.Construct(); Sequence &addresses = dict.mAddress.Value(); - nsString &error = dict.mError.Value(); - bool &answer = dict.mAnswer.Value(); if (NS_SUCCEEDED(aStatus)) { - answer = true; + dict.mAnswer = true; bool hasMore; aRecord->HasMore(&hasMore); while(hasMore) { @@ -536,8 +473,8 @@ Dashboard::OnLookupComplete(nsICancelable *aRequest, nsIDNSRecord *aRecord, nsre aRecord->HasMore(&hasMore); } } else { - answer = false; - CopyASCIItoUTF16(GetErrorString(aStatus), error); + dict.mAnswer = false; + CopyASCIItoUTF16(GetErrorString(aStatus), dict.mError); } JS::RootedValue val(cx); @@ -608,9 +545,7 @@ Dashboard::GetConnectionStatus(ConnStatus aStatus) AutoSafeJSContext cx; mozilla::dom::ConnStatusDict dict; - dict.mStatus.Construct(); - nsString &status = dict.mStatus.Value(); - status = aStatus.creationSts; + dict.mStatus = aStatus.creationSts; JS::RootedValue val(cx); if (!dict.ToObject(cx, JS::NullPtr(), &val)) { diff --git a/netwerk/test/unit/test_about_networking.js b/netwerk/test/unit/test_about_networking.js index e751b0d6a653..d084d85b8e26 100644 --- a/netwerk/test/unit/test_about_networking.js +++ b/netwerk/test/unit/test_about_networking.js @@ -14,7 +14,14 @@ const gHttpServer = new HttpServer(); add_test(function test_http() { gDashboard.requestHttpConnections(function(data) { - do_check_neq(data.host.indexOf("localhost"), -1); + let found = false; + for (let i = 0; i < data.connections.length; i++) { + if (data.connections[i].host == "localhost") { + found = true; + break; + } + } + do_check_eq(found, true); run_next_test(); }); @@ -22,7 +29,14 @@ add_test(function test_http() { add_test(function test_dns() { gDashboard.requestDNSInfo(function(data) { - do_check_neq(data.hostname.indexOf("localhost"), -1); + let found = false; + for (let i = 0; i < data.entries.length; i++) { + if (data.entries[i].hostname == "localhost") { + found = true; + break; + } + } + do_check_eq(found, true); do_test_pending(); gHttpServer.stop(do_test_finished); @@ -43,8 +57,14 @@ add_test(function test_sockets() { if (aStatus == Ci.nsISocketTransport.STATUS_CONNECTED_TO) { gDashboard.requestSockets(function(data) { gServerSocket.close(); - - do_check_neq(data.host.indexOf("127.0.0.1"), -1); + let found = false; + for (let i = 0; i < data.sockets.length; i++) { + if (data.sockets[i].host == "127.0.0.1") { + found = true; + break; + } + } + do_check_eq(found, true); run_next_test(); }); diff --git a/netwerk/test/unit/test_ping_aboutnetworking.js b/netwerk/test/unit/test_ping_aboutnetworking.js index 89c5b1a91ff9..eb72c7b46c60 100644 --- a/netwerk/test/unit/test_ping_aboutnetworking.js +++ b/netwerk/test/unit/test_ping_aboutnetworking.js @@ -34,17 +34,30 @@ function run_test() { if (connInfo.status == "NS_NET_STATUS_CONNECTED_TO") { do_test_pending(); gDashboard.requestDNSInfo(function(data) { - do_check_neq(data.hostname.indexOf("localhost"), -1); + let found = false; + for (let i = 0; i < data.entries.length; i++) { + if (data.entries[i].hostname == "localhost") { + found = true; + break; + } + } + do_check_eq(found, true); do_test_finished(); }); do_test_pending(); gDashboard.requestSockets(function(data) { - let index = data.host.indexOf("127.0.0.1"); + let index = -1; + for (let i = 0; i < data.sockets.length; i++) { + if (data.sockets[i].host == "127.0.0.1") { + index = i; + break; + } + } do_check_neq(index, -1); - do_check_eq(data.port[index], serverSocket.port); - do_check_eq(data.tcp[index], 1); + do_check_eq(data.sockets[index].port, serverSocket.port); + do_check_eq(data.sockets[index].tcp, 1); serverSocket.close(); diff --git a/toolkit/content/aboutNetworking.js b/toolkit/content/aboutNetworking.js index 1bfac7f246eb..73d5b96a9296 100644 --- a/toolkit/content/aboutNetworking.js +++ b/toolkit/content/aboutNetworking.js @@ -40,14 +40,14 @@ function displayHttp(data) { let new_cont = document.createElement('tbody'); new_cont.setAttribute('id', 'http_content'); - for (let i = 0; i < data.host.length; i++) { + for (let i = 0; i < data.connections.length; i++) { let row = document.createElement('tr'); - row.appendChild(col(data.host[i])); - row.appendChild(col(data.port[i])); - row.appendChild(col(data.spdy[i])); - row.appendChild(col(data.ssl[i])); - row.appendChild(col(data.active[i].rtt.length)); - row.appendChild(col(data.idle[i].rtt.length)); + row.appendChild(col(data.connections[i].host)); + row.appendChild(col(data.connections[i].port)); + row.appendChild(col(data.connections[i].spdy)); + row.appendChild(col(data.connections[i].ssl)); + row.appendChild(col(data.connections[i].active.length)); + row.appendChild(col(data.connections[i].idle.length)); new_cont.appendChild(row); } @@ -60,14 +60,14 @@ function displaySockets(data) { let new_cont = document.createElement('tbody'); new_cont.setAttribute('id', 'sockets_content'); - for (let i = 0; i < data.host.length; i++) { + for (let i = 0; i < data.sockets.length; i++) { let row = document.createElement('tr'); - row.appendChild(col(data.host[i])); - row.appendChild(col(data.port[i])); - row.appendChild(col(data.tcp[i])); - row.appendChild(col(data.active[i])); - row.appendChild(col(data.socksent[i])); - row.appendChild(col(data.sockreceived[i])); + row.appendChild(col(data.sockets[i].host)); + row.appendChild(col(data.sockets[i].port)); + row.appendChild(col(data.sockets[i].tcp)); + row.appendChild(col(data.sockets[i].active)); + row.appendChild(col(data.sockets[i].sent)); + row.appendChild(col(data.sockets[i].received)); new_cont.appendChild(row); } @@ -80,19 +80,19 @@ function displayDns(data) { let new_cont = document.createElement('tbody'); new_cont.setAttribute('id', 'dns_content'); - for (let i = 0; i < data.hostname.length; i++) { + for (let i = 0; i < data.entries.length; i++) { let row = document.createElement('tr'); - row.appendChild(col(data.hostname[i])); - row.appendChild(col(data.family[i])); + row.appendChild(col(data.entries[i].hostname)); + row.appendChild(col(data.entries[i].family)); let column = document.createElement('td'); - for (let j = 0; j< data.hostaddr[i].length; j++) { - column.appendChild(document.createTextNode(data.hostaddr[i][j])); + for (let j = 0; j < data.entries[i].hostaddr.length; j++) { + column.appendChild(document.createTextNode(data.entries[i].hostaddr[j])); column.appendChild(document.createElement('br')); } row.appendChild(column); - row.appendChild(col(data.expiration[i])); + row.appendChild(col(data.entries[i].expiration)); new_cont.appendChild(row); } @@ -105,14 +105,14 @@ function displayWebsockets(data) { let new_cont = document.createElement('tbody'); new_cont.setAttribute('id', 'websockets_content'); - for (let i = 0; i < data.hostport.length; i++) { + for (let i = 0; i < data.websockets.length; i++) { let row = document.createElement('tr'); - row.appendChild(col(data.hostport[i])); - row.appendChild(col(data.encrypted[i])); - row.appendChild(col(data.msgsent[i])); - row.appendChild(col(data.msgreceived[i])); - row.appendChild(col(data.sentsize[i])); - row.appendChild(col(data.receivedsize[i])); + row.appendChild(col(data.websockets[i].hostport)); + row.appendChild(col(data.websockets[i].encrypted)); + row.appendChild(col(data.websockets[i].msgsent)); + row.appendChild(col(data.websockets[i].msgreceived)); + row.appendChild(col(data.websockets[i].sentsize)); + row.appendChild(col(data.websockets[i].receivedsize)); new_cont.appendChild(row); } diff --git a/toolkit/content/tests/chrome/test_about_networking.html b/toolkit/content/tests/chrome/test_about_networking.html index 76471b342c7f..6ffaf2ba79e3 100644 --- a/toolkit/content/tests/chrome/test_about_networking.html +++ b/toolkit/content/tests/chrome/test_about_networking.html @@ -25,8 +25,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=912103 websocket.addEventListener("open", function() { dashboard.requestWebsocketConnections(function(data) { - isnot(data.hostport.indexOf("mochi.test:8888"), -1, - "tested websocket entry not found"); + var found = false; + for (var i = 0; i < data.websockets.length; i++) { + if (data.websockets[i].hostport == "mochi.test:8888") { + found = true; + break; + } + } + isnot(found, false, "tested websocket entry not found"); websocket.close(); SimpleTest.finish(); }); From e5caa83fa54523c814c44084acaf8c51a3e22690 Mon Sep 17 00:00:00 2001 From: Tareq Khandaker Date: Wed, 20 Nov 2013 09:29:01 -0500 Subject: [PATCH 056/268] Bug 925847 - WorkerNavigator does not implement all of NavigatorID. r=nsm --- dom/base/Navigator.h | 17 ----------------- dom/webidl/Navigator.webidl | 23 +++++++++++------------ dom/webidl/WorkerNavigator.webidl | 10 ++-------- dom/workers/Navigator.h | 12 ++++++++++++ dom/workers/test/navigator_worker.js | 5 ++++- dom/workers/test/test_navigator.html | 5 +++++ 6 files changed, 34 insertions(+), 38 deletions(-) diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 5b21ba15e33b..3278de16e49a 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -142,23 +142,6 @@ public: // Helper to initialize mMessagesManager. nsresult EnsureMessagesManager(); - // WebIDL API - void GetAppName(nsString& aAppName) - { - NS_GetNavigatorAppName(aAppName); - } - void GetAppVersion(nsString& aAppVersion, ErrorResult& aRv) - { - aRv = GetAppVersion(aAppVersion); - } - void GetPlatform(nsString& aPlatform, ErrorResult& aRv) - { - aRv = GetPlatform(aPlatform); - } - void GetUserAgent(nsString& aUserAgent, ErrorResult& aRv) - { - aRv = GetUserAgent(aUserAgent); - } // The XPCOM GetProduct is OK // The XPCOM GetLanguage is OK bool OnLine(); diff --git a/dom/webidl/Navigator.webidl b/dom/webidl/Navigator.webidl index eeb945e8a6fb..e838f4d88e43 100644 --- a/dom/webidl/Navigator.webidl +++ b/dom/webidl/Navigator.webidl @@ -32,18 +32,22 @@ Navigator implements NavigatorStorageUtils; [NoInterfaceObject] interface NavigatorID { + // WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla"). + [Constant] + readonly attribute DOMString appCodeName; // constant "Mozilla" + [Constant] readonly attribute DOMString appName; - [Throws] + [Constant] readonly attribute DOMString appVersion; - [Throws] + [Constant] readonly attribute DOMString platform; - [Throws] + [Constant] readonly attribute DOMString userAgent; + [Constant] + readonly attribute DOMString product; // constant "Gecko" - // Spec has this as a const, but that's wrong because it should not - // be on the interface object. - //const DOMString product = "Gecko"; // for historical reasons - readonly attribute DOMString product; + // Everyone but WebKit/Blink supports this. See bug 679971. + boolean taintEnabled(); // constant false }; [NoInterfaceObject] @@ -136,9 +140,6 @@ callback interface MozIdleObserver { // nsIDOMNavigator partial interface Navigator { - // WebKit/Blink/Trident/Presto support this (hardcoded "Mozilla"). - [Throws] - readonly attribute DOMString appCodeName; [Throws] readonly attribute DOMString oscpu; // WebKit/Blink support this; Trident/Presto do not. @@ -157,8 +158,6 @@ partial interface Navigator { // WebKit/Blink/Trident/Presto support this. [Throws] boolean javaEnabled(); - // Everyone but WebKit/Blink supports this. See bug 679971. - boolean taintEnabled(); /** * Navigator requests to add an idle observer to the existing window. diff --git a/dom/webidl/WorkerNavigator.webidl b/dom/webidl/WorkerNavigator.webidl index 5ddc1f443185..a29b53a11e0c 100644 --- a/dom/webidl/WorkerNavigator.webidl +++ b/dom/webidl/WorkerNavigator.webidl @@ -3,12 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ interface WorkerNavigator { - [Constant] - readonly attribute DOMString appName; - [Constant] - readonly attribute DOMString appVersion; - [Constant] - readonly attribute DOMString platform; - [Constant] - readonly attribute DOMString userAgent; }; + +WorkerNavigator implements NavigatorID; diff --git a/dom/workers/Navigator.h b/dom/workers/Navigator.h index ec143e4c20ae..80cd555fb712 100644 --- a/dom/workers/Navigator.h +++ b/dom/workers/Navigator.h @@ -52,6 +52,10 @@ public: MOZ_COUNT_DTOR(WorkerNavigator); } + void GetAppCodeName(nsString& aAppCodeName) const + { + aAppCodeName.AssignLiteral("Mozilla"); + } void GetAppName(nsString& aAppName) const { aAppName = mAppName; @@ -64,6 +68,14 @@ public: { aPlatform = mPlatform; } + void GetProduct(nsString& aProduct) const + { + aProduct.AssignLiteral("Gecko"); + } + bool TaintEnabled() const + { + return false; + } void GetUserAgent(nsString& aUserAgent) const { aUserAgent = mUserAgent; diff --git a/dom/workers/test/navigator_worker.js b/dom/workers/test/navigator_worker.js index 2ca3b6fdeadf..50934d92aef1 100644 --- a/dom/workers/test/navigator_worker.js +++ b/dom/workers/test/navigator_worker.js @@ -3,9 +3,12 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ var supportedProps = [ + "appCodeName", "appName", "appVersion", "platform", + "product", + "taintEnabled", "userAgent" ]; @@ -27,7 +30,7 @@ for (var index = 0; index < supportedProps.length; index++) { obj = { name: prop, - value: navigator[prop] + value: prop === "taintEnabled" ? navigator[prop]() : navigator[prop] }; postMessage(JSON.stringify(obj)); diff --git a/dom/workers/test/test_navigator.html b/dom/workers/test/test_navigator.html index ccace0e446d1..056f9bac0282 100644 --- a/dom/workers/test/test_navigator.html +++ b/dom/workers/test/test_navigator.html @@ -35,6 +35,11 @@ Tests of DOM Worker Navigator return; } + if (args.name === "taintEnabled") { + is(navigator[args.name](), args.value, args.name + "() returns false."); + return; + } + is(navigator[args.name], args.value, "Mismatched navigator string for " + args.name + "!"); }; From 3cdf321174b01fba8e7a7c6aba04e6300b43b2cf Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Wed, 20 Nov 2013 18:02:56 +1100 Subject: [PATCH 057/268] Bug 931882 - Correct the creation of the jit-test remote js-cache directory. r=dminor --- js/src/tests/lib/jittests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/tests/lib/jittests.py b/js/src/tests/lib/jittests.py index fd10c5c5c768..f7ddcb4d0095 100755 --- a/js/src/tests/lib/jittests.py +++ b/js/src/tests/lib/jittests.py @@ -659,7 +659,7 @@ def run_tests_remote(tests, prefix, options): dm.chmodDir(options.remote_test_root) Test.CacheDir = posixpath.join(options.remote_test_root, '.js-cache') - dm.mkDirs(Test.CacheDir) + dm.mkDir(Test.CacheDir) dm.pushDir(ECMA6_DIR, posixpath.join(jit_tests_dir, 'tests', 'ecma_6'), timeout=600) dm.pushDir(os.path.dirname(TEST_DIR), options.remote_test_root, timeout=600) From 64e253789503683ff9154feece0bb767c514472e Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Wed, 20 Nov 2013 18:03:19 +1100 Subject: [PATCH 058/268] Bug 931882 - Guard against passing a null js-cache in NestedShell. r=luke --- js/src/shell/js.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 9d64c2575ccc..36a581a8a9e8 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3604,7 +3604,7 @@ NestedShell(JSContext *cx, unsigned argc, jsval *vp) // As a special case, if the caller passes "--js-cache", replace that // with "--js-cache=$(jsCacheDir)" - if (!strcmp(argv.back(), "--js-cache")) { + if (!strcmp(argv.back(), "--js-cache") && jsCacheDir) { char *newArg = JS_smprintf("--js-cache=%s", jsCacheDir); if (!newArg) return false; From 0040598dda6a23543a0e6cc4f53c676665398b1c Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Wed, 20 Nov 2013 18:03:30 +1100 Subject: [PATCH 059/268] Bug 931882 - Avoid invoking a nested shell when running jit-test bug710947.js. r=luke --- js/src/jit-test/tests/basic/bug908915.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/jit-test/tests/basic/bug908915.js b/js/src/jit-test/tests/basic/bug908915.js index dbdbff98e266..86d1a514aff5 100644 --- a/js/src/jit-test/tests/basic/bug908915.js +++ b/js/src/jit-test/tests/basic/bug908915.js @@ -1,7 +1,8 @@ // |jit-test| error: 42 function f(y) {} for each(let e in newGlobal()) { - if (e.name === "quit" || e.name == "readline" || e.name == "terminate") + if (e.name === "quit" || e.name == "readline" || e.name == "terminate" || + e.name == "nestedShell") continue; try { e(); @@ -13,7 +14,8 @@ for each(let e in newGlobal()) { y() } for each(b in []) { - if (b.name === "quit" || b.name == "readline" || b.name == "terminate") + if (b.name === "quit" || b.name == "readline" || b.name == "terminate" || + b.name == "nestedShell") continue; try { f(b) From 62bf7e97e941e7b13d6a81115b6d9fd73f39386a Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Wed, 20 Nov 2013 09:29:02 -0500 Subject: [PATCH 060/268] Bug 936169 - Don't ignore failure to sandbox a non-preallocated child. r=bent --- dom/ipc/ContentParent.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 96ab9f7b7864..596da8ed662f 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1470,7 +1470,9 @@ ContentParent::ContentParent(mozIApplication* aApp, // which is otherwise a no-op, to sandbox it at an appropriate point // during startup. if (aOSPrivileges != base::PRIVILEGES_INHERIT) { - SendSetProcessPrivileges(base::PRIVILEGES_INHERIT); + if (!SendSetProcessPrivileges(base::PRIVILEGES_INHERIT)) { + KillHard(); + } } #endif } From 678a38a634d5dd743b12c8c0d9d8ba1db5deefce Mon Sep 17 00:00:00 2001 From: Douglas Crosher Date: Sat, 16 Nov 2013 00:44:23 +1100 Subject: [PATCH 061/268] Bug 938468 - ARM backtracking allocator backend fixes. r=sunfish --- js/src/jit/arm/CodeGenerator-arm.cpp | 5 ++-- js/src/jit/arm/LIR-arm.h | 43 +++++++++++++++++----------- js/src/jit/arm/Lowering-arm.cpp | 16 +++++------ 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index 5543a94d2ac3..7a9f64cda1fa 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -722,7 +722,7 @@ CodeGeneratorARM::visitModI(LModI *ins) Register lhs = ToRegister(ins->lhs()); Register rhs = ToRegister(ins->rhs()); Register output = ToRegister(ins->output()); - Register callTemp = ToRegister(ins->getTemp(0)); + Register callTemp = ToRegister(ins->callTemp()); MMod *mir = ins->mir(); // save the lhs in case we end up with a 0 that should be a -0.0 because lhs < 0. @@ -758,9 +758,10 @@ CodeGeneratorARM::visitSoftModI(LSoftModI *ins) Register lhs = ToRegister(ins->lhs()); Register rhs = ToRegister(ins->rhs()); Register output = ToRegister(ins->output()); - Register callTemp = ToRegister(ins->getTemp(2)); + Register callTemp = ToRegister(ins->callTemp()); MMod *mir = ins->mir(); Label done; + // save the lhs in case we end up with a 0 that should be a -0.0 because lhs < 0. JS_ASSERT(callTemp.code() > r3.code() && callTemp.code() < r12.code()); masm.ma_mov(lhs, callTemp); diff --git a/js/src/jit/arm/LIR-arm.h b/js/src/jit/arm/LIR-arm.h index faa1385ef3be..5bf6b90dae4a 100644 --- a/js/src/jit/arm/LIR-arm.h +++ b/js/src/jit/arm/LIR-arm.h @@ -139,25 +139,27 @@ class LDivI : public LBinaryMath<1> // LSoftDivI is a software divide for ARM cores that don't support a hardware // divide instruction. // -// It is implemented as a proper C function so it trashes r0, r1, r2 and r3. The -// call also trashes lr, and has the ability to trash ip. The function also +// It is implemented as a proper C function so it trashes r0, r1, r2 and r3. +// The call also trashes lr, and has the ability to trash ip. The function also // takes two arguments (dividend in r0, divisor in r1). The LInstruction gets // encoded such that the divisor and dividend are passed in their apropriate -// registers, and are marked as copy so we can modify them (and the function -// will). The other thre registers that can be trashed are marked as such. For -// the time being, the link register is not marked as trashed because we never -// allocate to the link register. -class LSoftDivI : public LBinaryMath<2> +// registers and end their life at the start of the instruction by the use of +// useFixedAtStart. The result is returned in r0 and the other three registers +// that can be trashed are marked as temps. For the time being, the link +// register is not marked as trashed because we never allocate to the link +// register. The FP registers are not trashed. +class LSoftDivI : public LBinaryMath<3> { public: LIR_HEADER(SoftDivI); LSoftDivI(const LAllocation &lhs, const LAllocation &rhs, - const LDefinition &temp1, const LDefinition &temp2) { + const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) { setOperand(0, lhs); setOperand(1, rhs); setTemp(0, temp1); setTemp(1, temp2); + setTemp(2, temp3); } MDiv *mir() const { @@ -204,25 +206,34 @@ class LModI : public LBinaryMath<1> setTemp(0, callTemp); } + const LDefinition *callTemp() { + return getTemp(0); + } + MMod *mir() const { return mir_->toMod(); } }; -class LSoftModI : public LBinaryMath<3> +class LSoftModI : public LBinaryMath<4> { public: LIR_HEADER(SoftModI); LSoftModI(const LAllocation &lhs, const LAllocation &rhs, - const LDefinition &temp1, const LDefinition &temp2, + const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3, const LDefinition &callTemp) { setOperand(0, lhs); setOperand(1, rhs); setTemp(0, temp1); setTemp(1, temp2); - setTemp(2, callTemp); + setTemp(2, temp3); + setTemp(3, callTemp); + } + + const LDefinition *callTemp() { + return getTemp(3); } MMod *mir() const { @@ -414,20 +425,18 @@ class LUMod : public LBinaryMath<0> // This class performs a simple x86 'div', yielding either a quotient or remainder depending on // whether this instruction is defined to output eax (quotient) or edx (remainder). -class LSoftUDivOrMod : public LBinaryMath<2> +class LSoftUDivOrMod : public LBinaryMath<3> { public: LIR_HEADER(SoftUDivOrMod); - LSoftUDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp1, const LDefinition &temp2) { + LSoftUDivOrMod(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp1, + const LDefinition &temp2, const LDefinition &temp3) { setOperand(0, lhs); setOperand(1, rhs); setTemp(0, temp1); setTemp(1, temp2); - } - // this is incorrect, it is returned in r1, getTemp(0) is r2. - const LDefinition *remainder() { - return getTemp(0); + setTemp(2, temp3); } }; diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index 9bf9092a0f3f..e236138be5bd 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -290,8 +290,8 @@ LIRGeneratorARM::lowerDivI(MDiv *div) return define(lir, div); } - LSoftDivI *lir = new LSoftDivI(useFixed(div->lhs(), r0), use(div->rhs(), r1), - tempFixed(r2), tempFixed(r3)); + LSoftDivI *lir = new LSoftDivI(useFixedAtStart(div->lhs(), r0), useFixedAtStart(div->rhs(), r1), + tempFixed(r1), tempFixed(r2), tempFixed(r3)); if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) return false; return defineFixed(lir, div, LAllocation(AnyRegister(r0))); @@ -335,8 +335,8 @@ LIRGeneratorARM::lowerModI(MMod *mod) return define(lir, mod); } - LSoftModI *lir = new LSoftModI(useFixed(mod->lhs(), r0), use(mod->rhs(), r1), - tempFixed(r2), tempFixed(r3), temp(LDefinition::GENERAL)); + LSoftModI *lir = new LSoftModI(useFixedAtStart(mod->lhs(), r0), useFixedAtStart(mod->rhs(), r1), + tempFixed(r0), tempFixed(r2), tempFixed(r3), temp(LDefinition::GENERAL)); if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo)) return false; return defineFixed(lir, mod, LAllocation(AnyRegister(r1))); @@ -427,8 +427,8 @@ LIRGeneratorARM::lowerUDiv(MInstruction *div) lir->setOperand(1, useRegister(rhs)); return define(lir, div); } else { - LSoftUDivOrMod *lir = new LSoftUDivOrMod(useFixed(lhs, r0), useFixed(rhs, r1), - tempFixed(r2), tempFixed(r3)); + LSoftUDivOrMod *lir = new LSoftUDivOrMod(useFixedAtStart(lhs, r0), useFixedAtStart(rhs, r1), + tempFixed(r1), tempFixed(r2), tempFixed(r3)); return defineFixed(lir, div, LAllocation(AnyRegister(r0))); } } @@ -451,8 +451,8 @@ LIRGeneratorARM::lowerUMod(MInstruction *mod) lir->setOperand(1, useRegister(rhs)); return define(lir, mod); } else { - LSoftUDivOrMod *lir = new LSoftUDivOrMod(useFixed(lhs, r0), useFixed(rhs, r1), - tempFixed(r2), tempFixed(r3)); + LSoftUDivOrMod *lir = new LSoftUDivOrMod(useFixedAtStart(lhs, r0), useFixedAtStart(rhs, r1), + tempFixed(r0), tempFixed(r2), tempFixed(r3)); return defineFixed(lir, mod, LAllocation(AnyRegister(r1))); } } From c488443f8516b16ef63c9f8c55e6f8d59a1828de Mon Sep 17 00:00:00 2001 From: Michael Shuen Date: Wed, 20 Nov 2013 09:29:03 -0500 Subject: [PATCH 062/268] Bug 940189 - Build dom/time in unified mode. r=bzbarsky --- dom/time/moz.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/time/moz.build b/dom/time/moz.build index e7bdd99411a6..c7888cde018c 100644 --- a/dom/time/moz.build +++ b/dom/time/moz.build @@ -17,7 +17,7 @@ EXPORTS.mozilla.dom.time += [ 'TimeService.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'DateCacheCleaner.cpp', 'TimeChangeObserver.cpp', 'TimeManager.cpp', From 6e72abd49fe4a1474e10862ac05542fe787754d4 Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Tue, 19 Nov 2013 23:55:27 -0500 Subject: [PATCH 063/268] Bug 936566 - Print mask layers in layers dump. r=nrc --- gfx/layers/Layers.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gfx/layers/Layers.cpp b/gfx/layers/Layers.cpp index 39fcbd4eb8b0..1ed1b033100a 100644 --- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -1261,6 +1261,12 @@ Layer::LogSelf(const char* aPrefix) nsAutoCString str; PrintInfo(str, aPrefix); MOZ_LAYERS_LOG(("%s", str.get())); + + if (mMaskLayer) { + nsAutoCString pfx(aPrefix); + pfx += " \\ MaskLayer "; + mMaskLayer->LogSelf(pfx.get()); + } } nsACString& @@ -1305,6 +1311,9 @@ Layer::PrintInfo(nsACString& aTo, const char* aPrefix) mStickyPositionData->mInner.x, mStickyPositionData->mInner.y, mStickyPositionData->mInner.width, mStickyPositionData->mInner.height); } + if (mMaskLayer) { + aTo.AppendPrintf(" [mMaskLayer=%p]", mMaskLayer.get()); + } return aTo; } From f4ba8ed7192325d3f76d39ccd468d36c2af0eaf5 Mon Sep 17 00:00:00 2001 From: Michael Shuen Date: Wed, 20 Nov 2013 09:40:32 -0500 Subject: [PATCH 064/268] Bug 939475 - Mention markStackLimit in gcparam() help and error. r=luke --- js/src/builtin/TestingFunctions.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 149392002ded..9d8df6ac7e71 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -268,6 +268,9 @@ static const struct ParamPair { {"markStackLimit", JSGC_MARK_STACK_LIMIT} }; +// Keep this in sync with above params. +#define GC_PARAMETER_ARGS_LIST "maxBytes, maxMallocBytes, gcBytes, gcNumber, sliceTimeBudget, or markStackLimit" + static bool GCParameter(JSContext *cx, unsigned argc, Value *vp) { @@ -285,9 +288,7 @@ GCParameter(JSContext *cx, unsigned argc, Value *vp) for (;; paramIndex++) { if (paramIndex == ArrayLength(paramMap)) { JS_ReportError(cx, - "the first argument must be maxBytes, " - "maxMallocBytes, gcStackpoolLifespan, gcBytes or " - "gcNumber"); + "the first argument must be one of " GC_PARAMETER_ARGS_LIST); return false; } if (JS_FlatStringEqualsAscii(flatStr, paramMap[paramIndex].name)) @@ -1368,8 +1369,7 @@ static const JSFunctionSpecWithHelp TestingFunctions[] = { JS_FN_HELP("gcparam", GCParameter, 2, 0, "gcparam(name [, value])", -" Wrapper for JS_[GS]etGCParameter. The name is either maxBytes,\n" -" maxMallocBytes, gcBytes, gcNumber, or sliceTimeBudget."), +" Wrapper for JS_[GS]etGCParameter. The name is one of " GC_PARAMETER_ARGS_LIST), JS_FN_HELP("getBuildConfiguration", GetBuildConfiguration, 0, 0, "getBuildConfiguration()", From 716b04b9a88a0b9a52a01ad3e0ceacda4edff56d Mon Sep 17 00:00:00 2001 From: Michael Shuen Date: Wed, 20 Nov 2013 09:40:32 -0500 Subject: [PATCH 065/268] Bug 940207 - Build dom/quota in unified mode. r=bzbarsky --- dom/quota/moz.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/quota/moz.build b/dom/quota/moz.build index 2e88d564f760..94dc67cdd0b6 100644 --- a/dom/quota/moz.build +++ b/dom/quota/moz.build @@ -31,7 +31,7 @@ EXPORTS.mozilla.dom.quota += [ 'Utilities.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'CheckQuotaHelper.cpp', 'FileStreams.cpp', 'QuotaManager.cpp', From efc93e36c855acf783d16375f3f80bc821ac1719 Mon Sep 17 00:00:00 2001 From: Dongie Agnir Date: Wed, 20 Nov 2013 09:40:32 -0500 Subject: [PATCH 066/268] Bug 940825 - Initialize dialogsWereEnabled to false. r=roc --- layout/base/nsDocumentViewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 0035a2f0c665..42be4d5fc297 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1094,7 +1094,7 @@ nsDocumentViewer::PermitUnload(bool aCallerClosesWindow, bool *aPermitUnload) // Never permit dialogs from the beforeunload handler nsCOMPtr utils = do_GetInterface(window); - bool dialogsWereEnabled; + bool dialogsWereEnabled = false; utils->AreDialogsEnabled(&dialogsWereEnabled); utils->DisableDialogs(); From 70733a3d4c4cb08f4901461c1d0f2309c1e4b590 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 14 Nov 2013 09:55:13 -0600 Subject: [PATCH 067/268] Bug 938390 - don't create a string to hold chars in ScriptSource::chars (r=benjamin) --HG-- extra : rebase_source : 44698608d7adc45fce0a40b9a400b0e0ef922a82 --- js/src/jsscript.cpp | 65 ++++++++++++++++++++++++++------------------- js/src/vm/Runtime.h | 6 ++--- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index c83216d75330..acbb4cd19fc2 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1032,7 +1032,7 @@ JSScript::sourceData(JSContext *cx) return scriptSource()->substring(cx, sourceStart, sourceEnd); } -JSStableString * +const jschar * SourceDataCache::lookup(ScriptSource *ss) { if (!map_) @@ -1042,25 +1042,33 @@ SourceDataCache::lookup(ScriptSource *ss) return nullptr; } -void -SourceDataCache::put(ScriptSource *ss, JSStableString *str) +bool +SourceDataCache::put(ScriptSource *ss, const jschar *str) { if (!map_) { map_ = js_new(); if (!map_) - return; + return false; + if (!map_->init()) { - purge(); - return; + js_delete(map_); + map_ = nullptr; + return false; } } - (void) map_->put(ss, str); + return map_->put(ss, str); } void SourceDataCache::purge() { + if (!map_) + return; + + for (Map::Range r = map_->all(); !r.empty(); r.popFront()) + js_delete(const_cast(r.front().value)); + js_delete(map_); map_ = nullptr; } @@ -1074,27 +1082,30 @@ ScriptSource::chars(JSContext *cx) #ifdef USE_ZLIB if (compressed()) { - JSStableString *cached = cx->runtime()->sourceDataCache.lookup(this); - if (!cached) { - const size_t nbytes = sizeof(jschar) * (length_ + 1); - jschar *decompressed = static_cast(js_malloc(nbytes)); - if (!decompressed) - return nullptr; - if (!DecompressString(data.compressed, compressedLength_, - reinterpret_cast(decompressed), nbytes)) { - JS_ReportOutOfMemory(cx); - js_free(decompressed); - return nullptr; - } - decompressed[length_] = 0; - cached = js_NewString(cx, decompressed, length_); - if (!cached) { - js_free(decompressed); - return nullptr; - } - cx->runtime()->sourceDataCache.put(this, cached); + if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this)) + return decompressed; + + const size_t nbytes = sizeof(jschar) * (length_ + 1); + jschar *decompressed = static_cast(js_malloc(nbytes)); + if (!decompressed) + return nullptr; + + if (!DecompressString(data.compressed, compressedLength_, + reinterpret_cast(decompressed), nbytes)) { + JS_ReportOutOfMemory(cx); + js_free(decompressed); + return nullptr; } - return cached->chars().get(); + + decompressed[length_] = 0; + + if (!cx->runtime()->sourceDataCache.put(this, decompressed)) { + JS_ReportOutOfMemory(cx); + js_free(decompressed); + return nullptr; + } + + return decompressed; } #endif return data.source; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index eb76993eb61e..7d924362221d 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -170,15 +170,15 @@ struct ConservativeGCData class SourceDataCache { typedef HashMap, SystemAllocPolicy> Map; Map *map_; public: SourceDataCache() : map_(nullptr) {} - JSStableString *lookup(ScriptSource *ss); - void put(ScriptSource *ss, JSStableString *); + const jschar *lookup(ScriptSource *ss); + bool put(ScriptSource *ss, const jschar *chars); void purge(); }; From 7230dc5679bbdd5abe5de8e28f9e4d9919b69434 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 14 Nov 2013 14:57:11 -0600 Subject: [PATCH 068/268] Bug 938615 - Simplify usage of ScriptSource::chars (r=benjamin) --HG-- extra : rebase_source : ae8644e441bd99e08c1743c5dc47517bae479f78 --- js/src/jsfun.cpp | 15 ++++++++------- js/src/jsscript.cpp | 39 +++++++++++++++++++++++++++------------ js/src/jsscript.h | 32 +++++++++++++++++++++++++++++++- js/src/vm/Runtime.h | 15 --------------- 4 files changed, 66 insertions(+), 35 deletions(-) diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 65eeb42153e4..f29a1a632172 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -1119,14 +1119,15 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti if (cx->zone()->needsBarrier()) LazyScript::writeBarrierPre(lazy); - // Suppress GC when lazily compiling functions, to preserve source - // character buffers. + // Suppress GC for now although we should be able to remove this by + // making 'lazy' a Rooted (which requires adding a + // THING_ROOT_LAZY_SCRIPT). AutoSuppressGC suppressGC(cx); fun->flags &= ~INTERPRETED_LAZY; fun->flags |= INTERPRETED; - JSScript *script = lazy->maybeScript(); + RootedScript script(cx, lazy->maybeScript()); if (script) { fun->initScript(script); @@ -1155,13 +1156,12 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti // has started. if (!lazy->numInnerFunctions() && !JS::IsIncrementalGCInProgress(cx->runtime())) { LazyScriptCache::Lookup lookup(cx, lazy); - cx->runtime()->lazyScriptCache.lookup(lookup, &script); + cx->runtime()->lazyScriptCache.lookup(lookup, script.address()); } if (script) { RootedObject enclosingScope(cx, lazy->enclosingScope()); - RootedScript scriptRoot(cx, script); - RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, scriptRoot)); + RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, fun, script)); if (!clonedScript) { fun->initLazyScript(lazy); return false; @@ -1182,7 +1182,8 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti JS_ASSERT(lazy->source()->hasSourceData()); // Parse and compile the script from source. - const jschar *chars = lazy->source()->chars(cx); + SourceDataCache::AutoSuppressPurge asp(cx); + const jschar *chars = lazy->source()->chars(cx, asp); if (!chars) { fun->initLazyScript(lazy); return false; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index acbb4cd19fc2..1ee0a6f8061d 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1032,9 +1032,22 @@ JSScript::sourceData(JSContext *cx) return scriptSource()->substring(cx, sourceStart, sourceEnd); } -const jschar * -SourceDataCache::lookup(ScriptSource *ss) +SourceDataCache::AutoSuppressPurge::AutoSuppressPurge(JSContext *cx) + : cache_(cx->runtime()->sourceDataCache) { + oldValue_ = cache_.numSuppressPurges_++; +} + +SourceDataCache::AutoSuppressPurge::~AutoSuppressPurge() +{ + cache_.numSuppressPurges_--; + JS_ASSERT(cache_.numSuppressPurges_ == oldValue_); +} + +const jschar * +SourceDataCache::lookup(ScriptSource *ss, const AutoSuppressPurge &asp) +{ + JS_ASSERT(this == &asp.cache()); if (!map_) return nullptr; if (Map::Ptr p = map_->lookup(ss)) @@ -1043,8 +1056,10 @@ SourceDataCache::lookup(ScriptSource *ss) } bool -SourceDataCache::put(ScriptSource *ss, const jschar *str) +SourceDataCache::put(ScriptSource *ss, const jschar *str, const AutoSuppressPurge &asp) { + JS_ASSERT(this == &asp.cache()); + if (!map_) { map_ = js_new(); if (!map_) @@ -1063,7 +1078,7 @@ SourceDataCache::put(ScriptSource *ss, const jschar *str) void SourceDataCache::purge() { - if (!map_) + if (!map_ || numSuppressPurges_ > 0) return; for (Map::Range r = map_->all(); !r.empty(); r.popFront()) @@ -1074,7 +1089,7 @@ SourceDataCache::purge() } const jschar * -ScriptSource::chars(JSContext *cx) +ScriptSource::chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp) { if (const jschar *chars = getOffThreadCompressionChars(cx)) return chars; @@ -1082,7 +1097,7 @@ ScriptSource::chars(JSContext *cx) #ifdef USE_ZLIB if (compressed()) { - if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this)) + if (const jschar *decompressed = cx->runtime()->sourceDataCache.lookup(this, asp)) return decompressed; const size_t nbytes = sizeof(jschar) * (length_ + 1); @@ -1099,7 +1114,7 @@ ScriptSource::chars(JSContext *cx) decompressed[length_] = 0; - if (!cx->runtime()->sourceDataCache.put(this, decompressed)) { + if (!cx->runtime()->sourceDataCache.put(this, decompressed, asp)) { JS_ReportOutOfMemory(cx); js_free(decompressed); return nullptr; @@ -1115,7 +1130,8 @@ JSStableString * ScriptSource::substring(JSContext *cx, uint32_t start, uint32_t stop) { JS_ASSERT(start <= stop); - const jschar *chars = this->chars(cx); + SourceDataCache::AutoSuppressPurge asp(cx); + const jschar *chars = this->chars(cx, asp); if (!chars) return nullptr; JSFlatString *flatStr = js_NewStringCopyN(cx, chars + start, stop - start); @@ -3150,14 +3166,13 @@ LazyScriptHashPolicy::match(JSScript *script, const Lookup &lookup) return false; } - // GC activity may destroy the character pointers being compared below. - AutoSuppressGC suppress(cx); + SourceDataCache::AutoSuppressPurge asp(cx); - const jschar *scriptChars = script->scriptSource()->chars(cx); + const jschar *scriptChars = script->scriptSource()->chars(cx, asp); if (!scriptChars) return false; - const jschar *lazyChars = lazy->source()->chars(cx); + const jschar *lazyChars = lazy->source()->chars(cx, asp); if (!lazyChars) return false; diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 21e00a1af318..3809069e4c0a 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -297,6 +297,36 @@ typedef HashMap, SystemAllocPolicy> DebugScriptMap; +class ScriptSource; + +class SourceDataCache +{ + typedef HashMap, + SystemAllocPolicy> Map; + Map *map_; + size_t numSuppressPurges_; + + public: + SourceDataCache() : map_(nullptr), numSuppressPurges_(0) {} + + class AutoSuppressPurge + { + SourceDataCache &cache_; + mozilla::DebugOnly oldValue_; + public: + explicit AutoSuppressPurge(JSContext *cx); + ~AutoSuppressPurge(); + SourceDataCache &cache() const { return cache_; } + }; + + const jschar *lookup(ScriptSource *ss, const AutoSuppressPurge &asp); + bool put(ScriptSource *ss, const jschar *chars, const AutoSuppressPurge &asp); + + void purge(); +}; + class ScriptSource { friend class SourceCompressionTask; @@ -369,7 +399,7 @@ class ScriptSource JS_ASSERT(hasSourceData()); return argumentsNotIncluded_; } - const jschar *chars(JSContext *cx); + const jschar *chars(JSContext *cx, const SourceDataCache::AutoSuppressPurge &asp); JSStableString *substring(JSContext *cx, uint32_t start, uint32_t stop); size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 7d924362221d..f1ae76a8cd1b 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -167,21 +167,6 @@ struct ConservativeGCData } }; -class SourceDataCache -{ - typedef HashMap, - SystemAllocPolicy> Map; - Map *map_; - - public: - SourceDataCache() : map_(nullptr) {} - const jschar *lookup(ScriptSource *ss); - bool put(ScriptSource *ss, const jschar *chars); - void purge(); -}; - struct EvalCacheEntry { JSScript *script; From b30d52161e7285fd1a93d0b1620cf4192df653ef Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 18 Nov 2013 12:55:54 -0600 Subject: [PATCH 069/268] Bug 933932 - OdinMonkey: provide a better warning message for uncoerced calls (r=bbouvier) --HG-- extra : rebase_source : 48b02eb62e0b829b57ca6caef1d922643afab791 --- js/src/jit/AsmJS.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index de05a9c56020..a4a6e03ef048 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -4339,16 +4339,18 @@ CheckExpr(FunctionCompiler &f, ParseNode *expr, MDefinition **def, Type *type) case PNK_NAME: return CheckVarRef(f, expr, def, type); case PNK_ELEM: return CheckArrayLoad(f, expr, def, type); case PNK_ASSIGN: return CheckAssign(f, expr, def, type); - case PNK_CALL: return f.fail(expr, "non-expression-statement call must be coerced"); case PNK_POS: return CheckPos(f, expr, def, type); case PNK_NOT: return CheckNot(f, expr, def, type); case PNK_NEG: return CheckNeg(f, expr, def, type); case PNK_BITNOT: return CheckBitNot(f, expr, def, type); case PNK_COMMA: return CheckComma(f, expr, def, type); case PNK_CONDITIONAL: return CheckConditional(f, expr, def, type); - case PNK_STAR: return CheckMultiply(f, expr, def, type); + case PNK_CALL: return f.fail(expr, "all function calls must either be ignored (via " + "f(); or comma-expression), coerced to signed " + "(via f()|0) or coerced to double (via +f())"); + case PNK_ADD: case PNK_SUB: return CheckAddOrSub(f, expr, def, type); From 8a49a2c44b4933161ebafbbbb08ebeed49aa7515 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Mon, 18 Nov 2013 12:56:32 -0600 Subject: [PATCH 070/268] Bug 933807 - Allow easily disabling TriggerOperationCallbackFor(Ion|AsmJS)Code (r=bhackett) --HG-- extra : rebase_source : bcf49d894252af53a24aa08a0db25c99dedd26d9 --- js/src/vm/Runtime.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index d1c4774f1550..0d5c6e6a44b5 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -591,6 +591,14 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim rtSizes->scriptData += mallocSizeOf(r.front()); } +static bool +SignalBasedTriggersDisabled() +{ + // Don't bother trying to cache the getenv lookup; this should be called + // infrequently. + return !!getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS"); +} + void JSRuntime::triggerOperationCallback(OperationCallbackTrigger trigger) { @@ -611,8 +619,10 @@ JSRuntime::triggerOperationCallback(OperationCallbackTrigger trigger) * asm.js and, optionally, normal Ion code use memory protection and signal * handlers to halt running code. */ - TriggerOperationCallbackForAsmJSCode(this); - jit::TriggerOperationCallbackForIonCode(this, trigger); + if (!SignalBasedTriggersDisabled()) { + TriggerOperationCallbackForAsmJSCode(this); + jit::TriggerOperationCallbackForIonCode(this, trigger); + } #endif } From aea36afc634317377be4bada6b158a14850f8bc8 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Wed, 20 Nov 2013 09:57:56 -0500 Subject: [PATCH 071/268] bug 802649 network priority for ocsp r=bsmith r=honzab --HG-- extra : rebase_source : 17554ab7627e1d42a4736078254f94f36cf9c48b --- security/manager/ssl/src/nsNSSCallbacks.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/security/manager/ssl/src/nsNSSCallbacks.cpp b/security/manager/ssl/src/nsNSSCallbacks.cpp index 0205c7f8997f..b699402bac8d 100644 --- a/security/manager/ssl/src/nsNSSCallbacks.cpp +++ b/security/manager/ssl/src/nsNSSCallbacks.cpp @@ -20,6 +20,7 @@ #include "ScopedNSSTypes.h" #include "nsContentUtils.h" #include "nsIHttpChannelInternal.h" +#include "nsISupportsPriority.h" #include "nsNetUtil.h" #include "SharedSSLState.h" #include "ssl.h" @@ -76,6 +77,13 @@ nsHTTPDownloadEvent::Run() ios->NewChannel(mRequestSession->mURL, nullptr, nullptr, getter_AddRefs(chan)); NS_ENSURE_STATE(chan); + // Security operations scheduled through normal HTTP channels are given + // high priority to accommodate real time OCSP transactions. Background CRL + // fetches happen through a different path (CRLDownloadEvent). + nsCOMPtr priorityChannel = do_QueryInterface(chan); + if (priorityChannel) + priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST); + chan->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS); // Create a loadgroup for this new channel. This way if the channel From ea691b049e1839925941412dca698413eb6a1bb8 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 19 Nov 2013 22:53:32 +0000 Subject: [PATCH 072/268] Bug 939993 - Check that AddPtrs are used only with matching Lookup values r=sfink --- js/public/HashTable.h | 1 + js/src/vm/Shape.cpp | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 03265f5d1b88..2855f78b185f 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -1511,6 +1511,7 @@ class HashTable : private AllocPolicy p.mutationCount = mutationCount; { mozilla::ReentrancyGuard g(*this); + JS_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed p.entry_ = &lookup(l, p.keyHash, sCollisionBit); } return p.found() || add(p, mozilla::Forward(u)); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 6b2313b74623..7b33479f5cf3 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1466,6 +1466,7 @@ BaseShape::getUnowned(ExclusiveContext *cx, const StackBaseShape &base) if (!table.initialized() && !table.init()) return nullptr; + uint64_t originalGcNumber = cx->zone()->gcNumber(); BaseShapeSet::AddPtr p = table.lookupForAdd(&base); if (p) @@ -1481,7 +1482,14 @@ BaseShape::getUnowned(ExclusiveContext *cx, const StackBaseShape &base) UnownedBaseShape *nbase = static_cast(nbase_); - if (!table.relookupOrAdd(p, &base, nbase)) + /* + * If a GC has occurred then the hash we calculated may be invalid, as it is + * based on the objects inside StackBaseShape, which may have been moved. + */ + bool gcHappened = cx->zone()->gcNumber() != originalGcNumber; + bool added = gcHappened ? table.putNew(&base, nbase) + : table.relookupOrAdd(p, &base, nbase); + if (!added) return nullptr; return nbase; @@ -1593,6 +1601,7 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, const Class *clasp, TaggedProt return nullptr; typedef InitialShapeEntry::Lookup Lookup; + uint64_t originalGcNumber = cx->zone()->gcNumber(); InitialShapeSet::AddPtr p = table.lookupForAdd(Lookup(clasp, proto, parent, metadata, nfixed, objectFlags)); @@ -1614,11 +1623,17 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, const Class *clasp, TaggedProt return nullptr; new (shape) EmptyShape(nbase, nfixed); - if (!table.relookupOrAdd(p, Lookup(clasp, protoRoot, parentRoot, metadataRoot, nfixed, objectFlags), - InitialShapeEntry(shape, protoRoot))) - { + /* + * If a GC has occurred, then the hash we calculated may be invalid, as it + * is based on objects which may have been moved. + */ + Lookup lookup(clasp, protoRoot, parentRoot, metadataRoot, nfixed, objectFlags); + InitialShapeEntry entry(shape, protoRoot); + bool gcHappened = cx->zone()->gcNumber() != originalGcNumber; + bool added = gcHappened ? table.putNew(lookup, entry) + : table.relookupOrAdd(p, lookup, entry); + if (!added) return nullptr; - } return shape; } From c9dde06da329ed7ccd5994931b88d72704f67a51 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 19 Nov 2013 22:53:36 +0000 Subject: [PATCH 073/268] Bug 935136 - Remove the now unnecessary UnbarrieredMutableValueOperations r=terrence --- js/public/Value.h | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/js/public/Value.h b/js/public/Value.h index 0beabd8fff3e..dc8225b6dfd9 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1520,7 +1520,6 @@ template <> struct GCMethods #endif }; -template class UnbarrieredMutableValueOperations; template class MutableValueOperations; /* @@ -1532,7 +1531,6 @@ template class MutableValueOperations; template class ValueOperations { - friend class UnbarrieredMutableValueOperations; friend class MutableValueOperations; const JS::Value * value() const { return static_cast(this)->extract(); } @@ -1573,16 +1571,14 @@ class ValueOperations }; /* - * A class designed for CRTP use in implementing the mutating parts of the Value - * interface in Value-like classes that don't need post barriers. Outer must be - * a class inheriting UnbarrieredMutableValueOperations with visible - * extractMutable() and extract() methods returning the const Value* and Value* - * abstracted by Outer. + * A class designed for CRTP use in implementing all the mutating parts of the + * Value interface in Value-like classes. Outer must be a class inheriting + * MutableValueOperations with visible extractMutable() and extract() + * methods returning the const Value* and Value* abstracted by Outer. */ template -class UnbarrieredMutableValueOperations : public ValueOperations +class MutableValueOperations : public ValueOperations { - friend class MutableValueOperations; JS::Value * value() { return static_cast(this)->extractMutable(); } public: @@ -1595,18 +1591,6 @@ class UnbarrieredMutableValueOperations : public ValueOperations void setMagic(JSWhyMagic why) { value()->setMagic(why); } bool setNumber(uint32_t ui) { return value()->setNumber(ui); } bool setNumber(double d) { return value()->setNumber(d); } -}; - -/* - * A class designed for CRTP use in implementing all the mutating parts of the - * Value interface in Value-like classes. Outer must be a class inheriting - * MutableValueOperations with visible extractMutable() and extract() - * methods returning the const Value* and Value* abstracted by Outer. - */ -template -class MutableValueOperations : public UnbarrieredMutableValueOperations -{ - public: void setString(JSString *str) { this->value()->setString(str); } void setString(const JS::Anchor &str) { this->value()->setString(str); } void setObject(JSObject &obj) { this->value()->setObject(obj); } @@ -1696,7 +1680,6 @@ class MutableHandleBase : public MutableValueOperations*>(this)->address(); } - friend class UnbarrieredMutableValueOperations >; friend class MutableValueOperations >; JS::Value * extractMutable() { return static_cast*>(this)->address(); @@ -1715,7 +1698,6 @@ class RootedBase : public MutableValueOperations*>(this)->address(); } - friend class UnbarrieredMutableValueOperations >; friend class MutableValueOperations >; JS::Value * extractMutable() { return static_cast*>(this)->address(); From f463fd7786e5212c8d7347a3db4ddba5dfc8bff1 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 19 Nov 2013 22:53:36 +0000 Subject: [PATCH 074/268] Bug 934421 - Postbarrier the keys of the plugin wrapper table r=terrence r=jschoenick --- dom/plugins/base/nsJSNPRuntime.cpp | 192 +++++++++++++---------------- dom/plugins/base/nsJSNPRuntime.h | 16 ++- 2 files changed, 96 insertions(+), 112 deletions(-) diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 53b97e9a98f8..d602e91f9974 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -23,8 +23,10 @@ #include "prmem.h" #include "nsIContent.h" #include "nsPluginInstanceOwner.h" -#include "mozilla/HashFunctions.h" #include "nsWrapperCacheInlines.h" +#include "js/HashTable.h" +#include "mozilla/HashFunctions.h" + #define NPRUNTIME_JSCLASS_NAME "NPObject JS wrapper class" @@ -35,6 +37,21 @@ using namespace mozilla; using mozilla::plugins::PluginScriptableObjectParent; using mozilla::plugins::ParentNPObject; +struct JSObjWrapperHasher : public js::DefaultHasher +{ + typedef nsJSObjWrapperKey Key; + typedef Key Lookup; + + static uint32_t hash(const Lookup &l) { + return HashGeneric(l.mJSObj, l.mNpp); + } + + static void rekey(Key &k, const Key& newKey) { + MOZ_ASSERT(k.mNpp == newKey.mNpp); + k.mJSObj = newKey.mJSObj; + } +}; + // Hash of JSObject wrappers that wraps JSObjects as NPObjects. There // will be one wrapper per JSObject per plugin instance, i.e. if two // plugins access the JSObject x, two wrappers for x will be @@ -42,7 +59,11 @@ using mozilla::plugins::ParentNPObject; // when a plugin is torn down in case there's a leak in the plugin (we // don't want to leak the world just because a plugin leaks an // NPObject). -static PLDHashTable sJSObjWrappers; +typedef js::HashMap JSObjWrapperTable; +static JSObjWrapperTable sJSObjWrappers; // Hash of NPObject wrappers that wrap NPObjects as JSObjects. static PLDHashTable sNPObjWrappers; @@ -237,18 +258,16 @@ OnWrapperDestroyed() NS_ASSERTION(sWrapperCount, "Whaaa, unbalanced created/destroyed calls!"); if (--sWrapperCount == 0) { - if (sJSObjWrappers.ops) { - NS_ASSERTION(sJSObjWrappers.entryCount == 0, "Uh, hash not empty?"); + if (sJSObjWrappers.initialized()) { + MOZ_ASSERT(sJSObjWrappers.count() == 0); // No more wrappers, and our hash was initialized. Finish the // hash to prevent leaking it. - PL_DHashTableFinish(&sJSObjWrappers); - - sJSObjWrappers.ops = nullptr; + sJSObjWrappers.finish(); } if (sNPObjWrappers.ops) { - NS_ASSERTION(sNPObjWrappers.entryCount == 0, "Uh, hash not empty?"); + MOZ_ASSERT(sNPObjWrappers.entryCount == 0); // No more wrappers, and our hash was initialized. Finish the // hash to prevent leaking it. @@ -480,9 +499,8 @@ ReportExceptionIfPending(JSContext *cx) return false; } - nsJSObjWrapper::nsJSObjWrapper(NPP npp) - : nsJSObjWrapperKey(nullptr, npp) + : mNpp(npp) { MOZ_COUNT_CTOR(nsJSObjWrapper); OnWrapperCreated(); @@ -498,6 +516,15 @@ nsJSObjWrapper::~nsJSObjWrapper() OnWrapperDestroyed(); } +void +nsJSObjWrapper::ClearJSObject() { + // Unroot the object's JSObject + JS_RemoveObjectRootRT(sJSRuntime, &mJSObj); + + // Forget our reference to the JSObject. + mJSObj = nullptr; +} + // static NPObject * nsJSObjWrapper::NP_Allocate(NPP npp, NPClass *aClass) @@ -523,18 +550,13 @@ nsJSObjWrapper::NP_Invalidate(NPObject *npobj) nsJSObjWrapper *jsnpobj = (nsJSObjWrapper *)npobj; if (jsnpobj && jsnpobj->mJSObj) { - // Unroot the object's JSObject - JS_RemoveObjectRootRT(sJSRuntime, &jsnpobj->mJSObj); - if (sJSObjWrappers.ops) { - // Remove the wrapper from the hash + // Remove the wrapper from the hash + MOZ_ASSERT(sJSObjWrappers.initialized()); + nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp); + sJSObjWrappers.remove(key); - nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp); - PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_REMOVE); - } - - // Forget our reference to the JSObject. - jsnpobj->mJSObj = nullptr; + jsnpobj->ClearJSObject(); } } @@ -915,34 +937,23 @@ nsJSObjWrapper::NP_Construct(NPObject *npobj, const NPVariant *args, } -class JSObjWrapperHashEntry : public PLDHashEntryHdr -{ -public: - nsJSObjWrapper *mJSObjWrapper; -}; - -static PLDHashNumber -JSObjWrapperHash(PLDHashTable *table, const void *key) -{ - const nsJSObjWrapperKey *e = static_cast(key); - return HashGeneric(e->mJSObj, e->mNpp); +/* + * This function is called during minor GCs for each key in the sJSObjWrappers + * table that has been moved. + */ +static void +JSObjWrapperKeyMarkCallback(JSTracer *trc, void *key, void *data) { + JSObject *obj = static_cast(key); + nsJSObjWrapper* wrapper = static_cast(data); + JSObject *prior = obj; + JS_CallObjectTracer(trc, &obj, "sJSObjWrappers key object"); + NPP npp = wrapper->mNpp; + nsJSObjWrapperKey oldKey(prior, npp); + nsJSObjWrapperKey newKey(obj, npp); + sJSObjWrappers.rekeyIfMoved(oldKey, newKey); } -static bool -JSObjWrapperHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, - const void *key) -{ - const nsJSObjWrapperKey *objWrapperKey = - static_cast(key); - const JSObjWrapperHashEntry *e = - static_cast(entry); - - return (e->mJSObjWrapper->mJSObj == objWrapperKey->mJSObj && - e->mJSObjWrapper->mNpp == objWrapperKey->mNpp); -} - - // Look up or create an NPObject that wraps the JSObject obj. // static @@ -990,22 +1001,9 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) return _retainobject(npobj); } - if (!sJSObjWrappers.ops) { + if (!sJSObjWrappers.initialized()) { // No hash yet (or any more), initialize it. - - static const PLDHashTableOps ops = - { - PL_DHashAllocTable, - PL_DHashFreeTable, - JSObjWrapperHash, - JSObjWrapperHashMatchEntry, - PL_DHashMoveEntryStub, - PL_DHashClearEntryStub, - PL_DHashFinalizeStub - }; - - if (!PL_DHashTableInit(&sJSObjWrappers, &ops, nullptr, - sizeof(JSObjWrapperHashEntry), 16)) { + if (!sJSObjWrappers.init(16)) { NS_ERROR("Error initializing PLDHashTable!"); return nullptr; @@ -1014,18 +1012,13 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) nsJSObjWrapperKey key(obj, npp); - JSObjWrapperHashEntry *entry = static_cast - (PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_ADD)); + JSObjWrapperTable::AddPtr p = sJSObjWrappers.lookupForAdd(key); - if (!entry) { - // Out of memory. - return nullptr; - } - - if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObjWrapper) { + if (p/* && p->value*/) { + MOZ_ASSERT(p->value); // Found a live nsJSObjWrapper, return it. - return _retainobject(entry->mJSObjWrapper); + return _retainobject(p->value); } // No existing nsJSObjWrapper, create one. @@ -1034,16 +1027,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) (nsJSObjWrapper *)_createobject(npp, &sJSObjWrapperNPClass); if (!wrapper) { - // OOM? Remove the stale entry from the hash. - - PL_DHashTableRawRemove(&sJSObjWrappers, entry); - + // Out of memory, entry not yet added to table. return nullptr; } wrapper->mJSObj = obj; - entry->mJSObjWrapper = wrapper; + if (!sJSObjWrappers.add(p, key, wrapper)) { + // Out of memory, free the wrapper we created. + _releaseobject(wrapper); + return nullptr; + } NS_ASSERTION(wrapper->mNpp == npp, "nsJSObjWrapper::mNpp not initialized!"); @@ -1052,13 +1046,15 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) if (!::JS_AddNamedObjectRoot(cx, &wrapper->mJSObj, "nsJSObjWrapper::mJSObject")) { NS_ERROR("Failed to root JSObject!"); + sJSObjWrappers.remove(key); _releaseobject(wrapper); - PL_DHashTableRawRemove(&sJSObjWrappers, entry); - return nullptr; } + // Add postbarrier for the hashtable key + JS_StoreObjectPostBarrierCallback(cx, JSObjWrapperKeyMarkCallback, obj, wrapper); + return wrapper; } @@ -1812,35 +1808,6 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj) } -// PLDHashTable enumeration callbacks for destruction code. -static PLDHashOperator -JSObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, - uint32_t number, void *arg) -{ - JSObjWrapperHashEntry *entry = (JSObjWrapperHashEntry *)hdr; - - nsJSObjWrapper *npobj = entry->mJSObjWrapper; - - if (npobj->mNpp == arg) { - // Prevent invalidate() and _releaseobject() from touching the hash - // we're enumerating. - const PLDHashTableOps *ops = table->ops; - table->ops = nullptr; - - if (npobj->_class && npobj->_class->invalidate) { - npobj->_class->invalidate(npobj); - } - - _releaseobject(npobj); - - table->ops = ops; - - return PL_DHASH_REMOVE; - } - - return PL_DHASH_NEXT; -} - // Struct for passing an NPP and a JSContext to // NPObjWrapperPluginDestroyedCallback struct NppAndCx @@ -1888,7 +1855,7 @@ NPObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, ::JS_SetPrivate(entry->mJSObj, nullptr); - table->ops = ops; + table->ops = ops; if (sDelayedReleases && sDelayedReleases->RemoveElement(npobj)) { OnWrapperDestroyed(); @@ -1904,9 +1871,16 @@ NPObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, void nsJSNPRuntime::OnPluginDestroy(NPP npp) { - if (sJSObjWrappers.ops) { - PL_DHashTableEnumerate(&sJSObjWrappers, - JSObjWrapperPluginDestroyedCallback, npp); + if (sJSObjWrappers.initialized()) { + for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) { + nsJSObjWrapper *npobj = e.front().value; + MOZ_ASSERT(npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass); + if (npobj->mNpp == npp) { + npobj->ClearJSObject(); + _releaseobject(npobj); + e.removeFront(); + } + } } // Use the safe JSContext here as we're not always able to find the diff --git a/dom/plugins/base/nsJSNPRuntime.h b/dom/plugins/base/nsJSNPRuntime.h index ba20f30c25b7..30869dbbdcac 100644 --- a/dom/plugins/base/nsJSNPRuntime.h +++ b/dom/plugins/base/nsJSNPRuntime.h @@ -25,20 +25,30 @@ public: { } - JSObject *mJSObj; + bool operator==(const nsJSObjWrapperKey& other) const { + return mJSObj == other.mJSObj && mNpp == other.mNpp; + } + bool operator!=(const nsJSObjWrapperKey& other) const { + return !(*this == other); + } + JSObject * mJSObj; const NPP mNpp; }; extern const JSClass sNPObjectJSWrapperClass; -class nsJSObjWrapper : public NPObject, - public nsJSObjWrapperKey +class nsJSObjWrapper : public NPObject { public: + JSObject *mJSObj; /* Added as a GC root. */ + const NPP mNpp; + static NPObject *GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj); + void ClearJSObject(); + protected: nsJSObjWrapper(NPP npp); ~nsJSObjWrapper(); From 68dfd0e9594b7b1ee51e75956e108d7eb7dde5fb Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 075/268] Bug 939476 - Only use separate GC stats phase for markDelayedChildren() in mark phase r=billm --- js/src/gc/Statistics.cpp | 1 - js/src/gc/Statistics.h | 25 ++++++++++++++++++++++++- js/src/jsgc.cpp | 17 ++++++++++------- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 7fa0093bea84..7744b61d53f5 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -281,7 +281,6 @@ static const PhaseInfo phases[] = { { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT }, { PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP }, { PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK }, - { PHASE_SWEEP_MARK_DELAYED, "Mark Delayed During Sweeping", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK }, diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 301292fcf836..3240fd238f53 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -33,7 +33,6 @@ enum Phase { PHASE_SWEEP, PHASE_SWEEP_MARK, PHASE_SWEEP_MARK_TYPES, - PHASE_SWEEP_MARK_DELAYED, PHASE_SWEEP_MARK_INCOMING_BLACK, PHASE_SWEEP_MARK_WEAK, PHASE_SWEEP_MARK_INCOMING_GRAY, @@ -207,6 +206,30 @@ struct AutoPhase MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; +struct MaybeAutoPhase +{ + MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) + : stats(nullptr) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + void construct(Statistics &statsArg, Phase phaseArg) + { + JS_ASSERT(!stats); + stats = &statsArg; + phase = phaseArg; + stats->beginPhase(phase); + } + ~MaybeAutoPhase() { + if (stats) + stats->endPhase(phase); + } + + Statistics *stats; + Phase phase; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + struct AutoSCC { AutoSCC(Statistics &stats, unsigned scc diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 00988b1408e1..d7b80e5730cc 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1800,10 +1800,9 @@ GCMarker::markDelayedChildren(ArenaHeader *aheader) bool GCMarker::markDelayedChildren(SliceBudget &budget) { - gcstats::Phase phase = runtime->gcIncrementalState == MARK - ? gcstats::PHASE_MARK_DELAYED - : gcstats::PHASE_SWEEP_MARK_DELAYED; - gcstats::AutoPhase ap(runtime->gcStats, phase); + gcstats::MaybeAutoPhase ap; + if (runtime->gcIncrementalState == MARK) + ap.construct(runtime->gcStats, gcstats::PHASE_MARK_DELAYED); JS_ASSERT(unmarkedArenaStackTop); do { @@ -3177,10 +3176,14 @@ js::gc::MarkingValidator::nonIncrementalMark() MarkRuntime(gcmarker, true); } - SliceBudget budget; - runtime->gcIncrementalState = MARK; - runtime->gcMarker.drainMarkStack(budget); + { + gcstats::AutoPhase ap1(runtime->gcStats, gcstats::PHASE_MARK); + SliceBudget budget; + runtime->gcIncrementalState = MARK; + runtime->gcMarker.drainMarkStack(budget); + } + runtime->gcIncrementalState = SWEEP; { gcstats::AutoPhase ap(runtime->gcStats, gcstats::PHASE_SWEEP); MarkAllWeakReferences(runtime, gcstats::PHASE_SWEEP_MARK_WEAK); From 61a883fc886f526055555d8b96b5bda84015c9e7 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 076/268] Bug 940505 - Fix rooting hazard in JSObject2JSObjectMap::Add() r=bholley --- js/xpconnect/src/XPCMaps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h index 77bb18f3f947..0cc7c358eaea 100644 --- a/js/xpconnect/src/XPCMaps.h +++ b/js/xpconnect/src/XPCMaps.h @@ -646,7 +646,7 @@ public: return p->value; if (!mTable.add(p, key, value)) return nullptr; - MOZ_ASSERT(xpc::GetObjectScope(key)->mWaiverWrapperMap == this); + MOZ_ASSERT(xpc::GetCompartmentPrivate(key)->scope->mWaiverWrapperMap == this); JS_StoreObjectPostBarrierCallback(cx, KeyMarkCallback, key, this); return value; } From 0cfe740846305a6758c4ba28bb3680cae9d24a96 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 077/268] Bug 940639 - Fix rooting hazard in nsXPCComponents_Utils::(Un)blockScriptForGlobal() r=bholley --- js/xpconnect/src/XPCComponents.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 16f0aaf52bcb..59616b7b004a 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3381,8 +3381,8 @@ nsXPCComponents_Utils::BlockScriptForGlobal(const JS::Value &globalArg, JSContext *cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); - JSObject *global = UncheckedUnwrap(&globalArg.toObject(), - /* stopAtOuter = */ false); + RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), + /* stopAtOuter = */ false)); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) { JS_ReportError(cx, "Script may not be disabled for system globals"); @@ -3397,8 +3397,8 @@ nsXPCComponents_Utils::UnblockScriptForGlobal(const JS::Value &globalArg, JSContext *cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); - JSObject *global = UncheckedUnwrap(&globalArg.toObject(), - /* stopAtOuter = */ false); + RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), + /* stopAtOuter = */ false)); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) { JS_ReportError(cx, "Script may not be disabled for system globals"); From 10cbc20ba920971213fca12dad38a51f88957da8 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 078/268] Bug 940692 - Fix rooting hazard in CheckForOutdatedParent() r=smaug --- content/base/src/nsINode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/base/src/nsINode.cpp b/content/base/src/nsINode.cpp index 0586b02146e4..76a766869d30 100644 --- a/content/base/src/nsINode.cpp +++ b/content/base/src/nsINode.cpp @@ -1331,15 +1331,15 @@ AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode) static nsresult CheckForOutdatedParent(nsINode* aParent, nsINode* aNode) { - if (JSObject* existingObj = aNode->GetWrapper()) { + if (JSObject* existingObjUnrooted = aNode->GetWrapper()) { + AutoJSContext cx; + JS::Rooted existingObj(cx, existingObjUnrooted); nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); if (js::GetGlobalForObjectCrossCompartment(existingObj) != global->GetGlobalJSObject()) { - AutoJSContext cx; - JS::Rooted rooted(cx, existingObj); - nsresult rv = ReparentWrapper(cx, rooted); + nsresult rv = ReparentWrapper(cx, existingObj); NS_ENSURE_SUCCESS(rv, rv); } } From 6a9fcb306c56cb85f03920ef18185d6ea091e9da Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 079/268] Bug 940727 - Fix rooting hazard in DOMProxyHandler::GetAndClearExpandoObject() r=bholley --- dom/bindings/DOMJSProxyHandler.cpp | 5 ++++- js/xpconnect/src/XPCJSRuntime.cpp | 14 ++++++++++++++ js/xpconnect/src/xpcprivate.h | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index edcf55a9b584..ca4189f069d5 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -80,7 +80,10 @@ DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) if (v.isObject()) { js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue()); - xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj); + XPCWrappedNativeScope* scope = xpc::MaybeGetObjectScope(obj); + if (scope) { + scope->RemoveDOMExpandoObject(obj); + } } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast(v.toPrivate()); diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 5513a149f495..2070d185e604 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -384,6 +384,20 @@ EnsureCompartmentPrivate(JSCompartment *c) return priv; } +XPCWrappedNativeScope* +MaybeGetObjectScope(JSObject *obj) +{ + MOZ_ASSERT(obj); + JSCompartment *compartment = js::GetObjectCompartment(obj); + + MOZ_ASSERT(compartment); + CompartmentPrivate *priv = GetCompartmentPrivate(compartment); + if (!priv) + return nullptr; + + return priv->scope; +} + static bool PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal) { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 4985bc16ac57..d0cc03c42b21 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3786,6 +3786,9 @@ GetObjectScope(JSObject *obj) return EnsureCompartmentPrivate(obj)->scope; } +// This returns null if a scope doesn't already exist. +XPCWrappedNativeScope* MaybeGetObjectScope(JSObject *obj); + extern bool gDebugMode; extern bool gDesiredDebugMode; From b65c8ff5ed7cb008e56776000fdda3bdcf98cde8 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 080/268] Bug 940754 - Fix rooting hazard in WorkerPrivateParent::WrapObject() r=bent --- dom/workers/WorkerPrivate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 33f945724630..cb5bc13d4ee0 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2159,7 +2159,8 @@ WorkerPrivateParent::WrapObject(JSContext* aCx, AssertIsOnParentThread(); - JSObject* obj = WorkerBinding::Wrap(aCx, aScope, ParentAsWorkerPrivate()); + JS::Rooted obj(aCx, WorkerBinding::Wrap(aCx, aScope, + ParentAsWorkerPrivate())); if (mRooted) { PreserveWrapper(this); From 639970686cd178641b3bf3d22b4f4cf362ff4d58 Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 20 Nov 2013 16:03:38 +0000 Subject: [PATCH 081/268] bug 940934 - build gfx/graphite2 in unified mode. r=ehsan --- gfx/graphite2/src/moz.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gfx/graphite2/src/moz.build b/gfx/graphite2/src/moz.build index acbe4d2dad5d..f75fe45bc1b9 100644 --- a/gfx/graphite2/src/moz.build +++ b/gfx/graphite2/src/moz.build @@ -13,16 +13,16 @@ EXPORTS.graphite2 += [ ] if CONFIG['GNU_CC']: - SOURCES += [ + UNIFIED_SOURCES += [ 'direct_machine.cpp' ] else: - SOURCES += [ + UNIFIED_SOURCES += [ 'call_machine.cpp' ] # This should contain all of the _SOURCES from files.mk, except *_machine.cpp -SOURCES += [ +UNIFIED_SOURCES += [ 'Bidi.cpp', 'CachedFace.cpp', 'CmapCache.cpp', From b8680805ea7c03a75a8caf1a8c9265089fda9c1e Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Tue, 19 Nov 2013 16:09:18 -0800 Subject: [PATCH 082/268] Bug 935111 - Enable seccomp-bpf for Linux. r=jld --- security/sandbox/linux/seccomp_filter.h | 123 ++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 7 deletions(-) diff --git a/security/sandbox/linux/seccomp_filter.h b/security/sandbox/linux/seccomp_filter.h index fb934165bafb..a1904e457c45 100644 --- a/security/sandbox/linux/seccomp_filter.h +++ b/security/sandbox/linux/seccomp_filter.h @@ -91,6 +91,116 @@ #define SECCOMP_WHITELIST_ARCH_TOREMOVE #endif +/* Architecture-specific syscalls for desktop linux */ +#if defined(__arm__) +#define SECCOMP_WHITELIST_ARCH_DESKTOP_LINUX +#elif defined(__i386__) +#define SECCOMP_WHITELIST_ARCH_DESKTOP_LINUX +#elif defined(__x86_64__) +#define SECCOMP_WHITELIST_ARCH_DESKTOP_LINUX +#else +#define SECCOMP_WHITELIST_ARCH_DESKTOP_LINUX +#endif + +/* B2G specific syscalls */ +#if defined(MOZ_B2G) + +#define SECCOMP_WHITELIST_B2G_HIGH \ + ALLOW_SYSCALL(gettimeofday), + +#define SECCOMP_WHITELIST_B2G_MED \ + ALLOW_SYSCALL(clock_gettime), \ + ALLOW_SYSCALL(getpid), \ + ALLOW_SYSCALL(rt_sigreturn), \ + ALLOW_SYSCALL(epoll_wait), + +#define SECCOMP_WHITELIST_B2G_LOW \ + ALLOW_SYSCALL(getdents64), \ + ALLOW_SYSCALL(sched_setscheduler), + +#else +#define SECCOMP_WHITELIST_B2G_HIGH +#define SECCOMP_WHITELIST_B2G_MED +#define SECCOMP_WHITELIST_B2G_LOW +#endif +/* End of B2G specific syscalls */ + + +/* Desktop Linux specific syscalls */ +#if defined(MOZ_CONTENT_SANDBOX) && !defined(MOZ_B2G) && defined(XP_UNIX) && !defined(XP_MACOSX) + +/* We should remove all of the following in the future (possibly even more) */ +#define SECCOMP_WHITELIST_DESKTOP_LINUX_TO_REMOVE \ + ALLOW_SYSCALL(socket), \ + ALLOW_SYSCALL(chmod), \ + ALLOW_SYSCALL(execve), \ + ALLOW_SYSCALL(rename), \ + ALLOW_SYSCALL(symlink), \ + ALLOW_SYSCALL(connect), \ + ALLOW_SYSCALL(quotactl), \ + ALLOW_SYSCALL(kill), \ + ALLOW_SYSCALL(sendto), + +#define SECCOMP_WHITELIST_DESKTOP_LINUX \ + SECCOMP_WHITELIST_ARCH_DESKTOP_LINUX \ + ALLOW_SYSCALL(stat), \ + ALLOW_SYSCALL(getdents), \ + ALLOW_SYSCALL(lstat), \ + ALLOW_SYSCALL(mmap), \ + ALLOW_SYSCALL(openat), \ + ALLOW_SYSCALL(fcntl), \ + ALLOW_SYSCALL(fstat), \ + ALLOW_SYSCALL(readlink), \ + ALLOW_SYSCALL(getsockname), \ + ALLOW_SYSCALL(recvmsg), \ + ALLOW_SYSCALL(uname), \ + /* duplicate rt_sigaction in SECCOMP_WHITELIST_PROFILING */ \ + ALLOW_SYSCALL(rt_sigaction), \ + ALLOW_SYSCALL(getuid), \ + ALLOW_SYSCALL(geteuid), \ + ALLOW_SYSCALL(mkdir), \ + ALLOW_SYSCALL(getcwd), \ + ALLOW_SYSCALL(readahead), \ + ALLOW_SYSCALL(pread64), \ + ALLOW_SYSCALL(statfs), \ + ALLOW_SYSCALL(pipe), \ + ALLOW_SYSCALL(ftruncate), \ + ALLOW_SYSCALL(getrlimit), \ + ALLOW_SYSCALL(shutdown), \ + ALLOW_SYSCALL(getpeername), \ + ALLOW_SYSCALL(eventfd2), \ + ALLOW_SYSCALL(clock_getres), \ + ALLOW_SYSCALL(sysinfo), \ + ALLOW_SYSCALL(getresuid), \ + ALLOW_SYSCALL(umask), \ + ALLOW_SYSCALL(getresgid), \ + ALLOW_SYSCALL(poll), \ + ALLOW_SYSCALL(getegid), \ + ALLOW_SYSCALL(inotify_init1), \ + ALLOW_SYSCALL(wait4), \ + ALLOW_SYSCALL(shmctl), \ + ALLOW_SYSCALL(set_robust_list), \ + ALLOW_SYSCALL(rmdir), \ + ALLOW_SYSCALL(recvfrom), \ + ALLOW_SYSCALL(shmdt), \ + ALLOW_SYSCALL(pipe2), \ + ALLOW_SYSCALL(setsockopt), \ + ALLOW_SYSCALL(shmat), \ + ALLOW_SYSCALL(set_tid_address), \ + ALLOW_SYSCALL(inotify_add_watch), \ + ALLOW_SYSCALL(rt_sigprocmask), \ + ALLOW_SYSCALL(shmget), \ + ALLOW_SYSCALL(getgid), \ + ALLOW_SYSCALL(utime), \ + ALLOW_SYSCALL(arch_prctl), \ + ALLOW_SYSCALL(sched_getaffinity), \ + SECCOMP_WHITELIST_DESKTOP_LINUX_TO_REMOVE +#else +#define SECCOMP_WHITELIST_DESKTOP_LINUX +#endif +/* End of Desktop Linux specific syscalls */ + + /* Most used system calls should be at the top of the whitelist * for performance reasons. The whitelist BPF filter exits after * processing any ALLOW_SYSCALL macro. @@ -110,7 +220,7 @@ #define SECCOMP_WHITELIST \ /* These are calls we're ok to allow */ \ SECCOMP_WHITELIST_ARCH_HIGH \ - ALLOW_SYSCALL(gettimeofday), \ + SECCOMP_WHITELIST_B2G_HIGH \ ALLOW_SYSCALL(read), \ ALLOW_SYSCALL(write), \ ALLOW_SYSCALL(lseek), \ @@ -124,13 +234,10 @@ ALLOW_SYSCALL(writev), \ ALLOW_SYSCALL(clone), \ ALLOW_SYSCALL(brk), \ - ALLOW_SYSCALL(clock_gettime), \ - ALLOW_SYSCALL(getpid), \ + SECCOMP_WHITELIST_B2G_MED \ ALLOW_SYSCALL(gettid), \ ALLOW_SYSCALL(getrusage), \ ALLOW_SYSCALL(madvise), \ - ALLOW_SYSCALL(rt_sigreturn), \ - ALLOW_SYSCALL(epoll_wait), \ ALLOW_SYSCALL(futex), \ ALLOW_SYSCALL(dup), \ ALLOW_SYSCALL(nanosleep), \ @@ -142,7 +249,6 @@ ALLOW_SYSCALL(open), \ ALLOW_SYSCALL(prctl), \ ALLOW_SYSCALL(access), \ - ALLOW_SYSCALL(getdents64), \ ALLOW_SYSCALL(unlink), \ ALLOW_SYSCALL(fsync), \ ALLOW_SYSCALL(socketpair), \ @@ -150,12 +256,15 @@ /* Should remove all of the following in the future, if possible */ \ ALLOW_SYSCALL(getpriority), \ ALLOW_SYSCALL(setpriority), \ - ALLOW_SYSCALL(sched_setscheduler), \ SECCOMP_WHITELIST_PROFILING \ + SECCOMP_WHITELIST_B2G_LOW \ /* Always last and always OK calls */ \ SECCOMP_WHITELIST_ARCH_LAST \ /* restart_syscall is called internally, generally when debugging */ \ ALLOW_SYSCALL(restart_syscall), \ + /* linux desktop is not as performance critical as B2G */ \ + /* we can place desktop syscalls at the end */ \ + SECCOMP_WHITELIST_DESKTOP_LINUX \ ALLOW_SYSCALL(exit_group), \ ALLOW_SYSCALL(exit) From 9d9e92c46904ba9fd114809fb3d6fa7e1bca33e7 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:37:52 +0000 Subject: [PATCH 083/268] Backed out changeset db0f8a5eeb33 (bug 940754) --- dom/workers/WorkerPrivate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index cb5bc13d4ee0..33f945724630 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2159,8 +2159,7 @@ WorkerPrivateParent::WrapObject(JSContext* aCx, AssertIsOnParentThread(); - JS::Rooted obj(aCx, WorkerBinding::Wrap(aCx, aScope, - ParentAsWorkerPrivate())); + JSObject* obj = WorkerBinding::Wrap(aCx, aScope, ParentAsWorkerPrivate()); if (mRooted) { PreserveWrapper(this); From 799cc7ec2d20f34a0569a25463c26416fec4e821 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:37:55 +0000 Subject: [PATCH 084/268] Backed out changeset 17ca97e65aa5 (bug 940727) --- dom/bindings/DOMJSProxyHandler.cpp | 5 +---- js/xpconnect/src/XPCJSRuntime.cpp | 14 -------------- js/xpconnect/src/xpcprivate.h | 3 --- 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index ca4189f069d5..edcf55a9b584 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -80,10 +80,7 @@ DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) if (v.isObject()) { js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue()); - XPCWrappedNativeScope* scope = xpc::MaybeGetObjectScope(obj); - if (scope) { - scope->RemoveDOMExpandoObject(obj); - } + xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj); } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast(v.toPrivate()); diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 2070d185e604..5513a149f495 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -384,20 +384,6 @@ EnsureCompartmentPrivate(JSCompartment *c) return priv; } -XPCWrappedNativeScope* -MaybeGetObjectScope(JSObject *obj) -{ - MOZ_ASSERT(obj); - JSCompartment *compartment = js::GetObjectCompartment(obj); - - MOZ_ASSERT(compartment); - CompartmentPrivate *priv = GetCompartmentPrivate(compartment); - if (!priv) - return nullptr; - - return priv->scope; -} - static bool PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal) { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index d0cc03c42b21..4985bc16ac57 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3786,9 +3786,6 @@ GetObjectScope(JSObject *obj) return EnsureCompartmentPrivate(obj)->scope; } -// This returns null if a scope doesn't already exist. -XPCWrappedNativeScope* MaybeGetObjectScope(JSObject *obj); - extern bool gDebugMode; extern bool gDesiredDebugMode; From 1a279bcd872c5e12e8ed8cdff795feac596015f7 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:37:58 +0000 Subject: [PATCH 085/268] Backed out changeset 2522a5bca61a (bug 940692) --- content/base/src/nsINode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/base/src/nsINode.cpp b/content/base/src/nsINode.cpp index 76a766869d30..0586b02146e4 100644 --- a/content/base/src/nsINode.cpp +++ b/content/base/src/nsINode.cpp @@ -1331,15 +1331,15 @@ AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode) static nsresult CheckForOutdatedParent(nsINode* aParent, nsINode* aNode) { - if (JSObject* existingObjUnrooted = aNode->GetWrapper()) { - AutoJSContext cx; - JS::Rooted existingObj(cx, existingObjUnrooted); + if (JSObject* existingObj = aNode->GetWrapper()) { nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); if (js::GetGlobalForObjectCrossCompartment(existingObj) != global->GetGlobalJSObject()) { - nsresult rv = ReparentWrapper(cx, existingObj); + AutoJSContext cx; + JS::Rooted rooted(cx, existingObj); + nsresult rv = ReparentWrapper(cx, rooted); NS_ENSURE_SUCCESS(rv, rv); } } From 8ee66047fc2cf0fd610859bd5307ff6e303d6513 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:38:01 +0000 Subject: [PATCH 086/268] Backed out changeset ee2544f18623 (bug 940639) --- js/xpconnect/src/XPCComponents.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 59616b7b004a..16f0aaf52bcb 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3381,8 +3381,8 @@ nsXPCComponents_Utils::BlockScriptForGlobal(const JS::Value &globalArg, JSContext *cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); - RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), - /* stopAtOuter = */ false)); + JSObject *global = UncheckedUnwrap(&globalArg.toObject(), + /* stopAtOuter = */ false); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) { JS_ReportError(cx, "Script may not be disabled for system globals"); @@ -3397,8 +3397,8 @@ nsXPCComponents_Utils::UnblockScriptForGlobal(const JS::Value &globalArg, JSContext *cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); - RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), - /* stopAtOuter = */ false)); + JSObject *global = UncheckedUnwrap(&globalArg.toObject(), + /* stopAtOuter = */ false); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) { JS_ReportError(cx, "Script may not be disabled for system globals"); From c5bde79421e424274c2f169a3aff2dd72f503a50 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:38:04 +0000 Subject: [PATCH 087/268] Backed out changeset 017d3e4e80bf (bug 940505) --- js/xpconnect/src/XPCMaps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h index 0cc7c358eaea..77bb18f3f947 100644 --- a/js/xpconnect/src/XPCMaps.h +++ b/js/xpconnect/src/XPCMaps.h @@ -646,7 +646,7 @@ public: return p->value; if (!mTable.add(p, key, value)) return nullptr; - MOZ_ASSERT(xpc::GetCompartmentPrivate(key)->scope->mWaiverWrapperMap == this); + MOZ_ASSERT(xpc::GetObjectScope(key)->mWaiverWrapperMap == this); JS_StoreObjectPostBarrierCallback(cx, KeyMarkCallback, key, this); return value; } From 5ad13921b68b514a8120b48b0f6649631ead018b Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:38:07 +0000 Subject: [PATCH 088/268] Backed out changeset 915744e45b57 (bug 939476) --- js/src/gc/Statistics.cpp | 1 + js/src/gc/Statistics.h | 25 +------------------------ js/src/jsgc.cpp | 17 +++++++---------- 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 7744b61d53f5..7fa0093bea84 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -281,6 +281,7 @@ static const PhaseInfo phases[] = { { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT }, { PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP }, { PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK }, + { PHASE_SWEEP_MARK_DELAYED, "Mark Delayed During Sweeping", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK }, diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 3240fd238f53..301292fcf836 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -33,6 +33,7 @@ enum Phase { PHASE_SWEEP, PHASE_SWEEP_MARK, PHASE_SWEEP_MARK_TYPES, + PHASE_SWEEP_MARK_DELAYED, PHASE_SWEEP_MARK_INCOMING_BLACK, PHASE_SWEEP_MARK_WEAK, PHASE_SWEEP_MARK_INCOMING_GRAY, @@ -206,30 +207,6 @@ struct AutoPhase MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; -struct MaybeAutoPhase -{ - MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) - : stats(nullptr) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - } - void construct(Statistics &statsArg, Phase phaseArg) - { - JS_ASSERT(!stats); - stats = &statsArg; - phase = phaseArg; - stats->beginPhase(phase); - } - ~MaybeAutoPhase() { - if (stats) - stats->endPhase(phase); - } - - Statistics *stats; - Phase phase; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - struct AutoSCC { AutoSCC(Statistics &stats, unsigned scc diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index d7b80e5730cc..00988b1408e1 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1800,9 +1800,10 @@ GCMarker::markDelayedChildren(ArenaHeader *aheader) bool GCMarker::markDelayedChildren(SliceBudget &budget) { - gcstats::MaybeAutoPhase ap; - if (runtime->gcIncrementalState == MARK) - ap.construct(runtime->gcStats, gcstats::PHASE_MARK_DELAYED); + gcstats::Phase phase = runtime->gcIncrementalState == MARK + ? gcstats::PHASE_MARK_DELAYED + : gcstats::PHASE_SWEEP_MARK_DELAYED; + gcstats::AutoPhase ap(runtime->gcStats, phase); JS_ASSERT(unmarkedArenaStackTop); do { @@ -3176,14 +3177,10 @@ js::gc::MarkingValidator::nonIncrementalMark() MarkRuntime(gcmarker, true); } - { - gcstats::AutoPhase ap1(runtime->gcStats, gcstats::PHASE_MARK); - SliceBudget budget; - runtime->gcIncrementalState = MARK; - runtime->gcMarker.drainMarkStack(budget); - } + SliceBudget budget; + runtime->gcIncrementalState = MARK; + runtime->gcMarker.drainMarkStack(budget); - runtime->gcIncrementalState = SWEEP; { gcstats::AutoPhase ap(runtime->gcStats, gcstats::PHASE_SWEEP); MarkAllWeakReferences(runtime, gcstats::PHASE_SWEEP_MARK_WEAK); From eda817791be8781f0144bcbe8396a386f46a1b44 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:38:10 +0000 Subject: [PATCH 089/268] Backed out changeset 0a641abef602 (bug 934421) --- dom/plugins/base/nsJSNPRuntime.cpp | 192 ++++++++++++++++------------- dom/plugins/base/nsJSNPRuntime.h | 16 +-- 2 files changed, 112 insertions(+), 96 deletions(-) diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index d602e91f9974..53b97e9a98f8 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -23,10 +23,8 @@ #include "prmem.h" #include "nsIContent.h" #include "nsPluginInstanceOwner.h" -#include "nsWrapperCacheInlines.h" -#include "js/HashTable.h" #include "mozilla/HashFunctions.h" - +#include "nsWrapperCacheInlines.h" #define NPRUNTIME_JSCLASS_NAME "NPObject JS wrapper class" @@ -37,21 +35,6 @@ using namespace mozilla; using mozilla::plugins::PluginScriptableObjectParent; using mozilla::plugins::ParentNPObject; -struct JSObjWrapperHasher : public js::DefaultHasher -{ - typedef nsJSObjWrapperKey Key; - typedef Key Lookup; - - static uint32_t hash(const Lookup &l) { - return HashGeneric(l.mJSObj, l.mNpp); - } - - static void rekey(Key &k, const Key& newKey) { - MOZ_ASSERT(k.mNpp == newKey.mNpp); - k.mJSObj = newKey.mJSObj; - } -}; - // Hash of JSObject wrappers that wraps JSObjects as NPObjects. There // will be one wrapper per JSObject per plugin instance, i.e. if two // plugins access the JSObject x, two wrappers for x will be @@ -59,11 +42,7 @@ struct JSObjWrapperHasher : public js::DefaultHasher // when a plugin is torn down in case there's a leak in the plugin (we // don't want to leak the world just because a plugin leaks an // NPObject). -typedef js::HashMap JSObjWrapperTable; -static JSObjWrapperTable sJSObjWrappers; +static PLDHashTable sJSObjWrappers; // Hash of NPObject wrappers that wrap NPObjects as JSObjects. static PLDHashTable sNPObjWrappers; @@ -258,16 +237,18 @@ OnWrapperDestroyed() NS_ASSERTION(sWrapperCount, "Whaaa, unbalanced created/destroyed calls!"); if (--sWrapperCount == 0) { - if (sJSObjWrappers.initialized()) { - MOZ_ASSERT(sJSObjWrappers.count() == 0); + if (sJSObjWrappers.ops) { + NS_ASSERTION(sJSObjWrappers.entryCount == 0, "Uh, hash not empty?"); // No more wrappers, and our hash was initialized. Finish the // hash to prevent leaking it. - sJSObjWrappers.finish(); + PL_DHashTableFinish(&sJSObjWrappers); + + sJSObjWrappers.ops = nullptr; } if (sNPObjWrappers.ops) { - MOZ_ASSERT(sNPObjWrappers.entryCount == 0); + NS_ASSERTION(sNPObjWrappers.entryCount == 0, "Uh, hash not empty?"); // No more wrappers, and our hash was initialized. Finish the // hash to prevent leaking it. @@ -499,8 +480,9 @@ ReportExceptionIfPending(JSContext *cx) return false; } + nsJSObjWrapper::nsJSObjWrapper(NPP npp) - : mNpp(npp) + : nsJSObjWrapperKey(nullptr, npp) { MOZ_COUNT_CTOR(nsJSObjWrapper); OnWrapperCreated(); @@ -516,15 +498,6 @@ nsJSObjWrapper::~nsJSObjWrapper() OnWrapperDestroyed(); } -void -nsJSObjWrapper::ClearJSObject() { - // Unroot the object's JSObject - JS_RemoveObjectRootRT(sJSRuntime, &mJSObj); - - // Forget our reference to the JSObject. - mJSObj = nullptr; -} - // static NPObject * nsJSObjWrapper::NP_Allocate(NPP npp, NPClass *aClass) @@ -550,13 +523,18 @@ nsJSObjWrapper::NP_Invalidate(NPObject *npobj) nsJSObjWrapper *jsnpobj = (nsJSObjWrapper *)npobj; if (jsnpobj && jsnpobj->mJSObj) { + // Unroot the object's JSObject + JS_RemoveObjectRootRT(sJSRuntime, &jsnpobj->mJSObj); - // Remove the wrapper from the hash - MOZ_ASSERT(sJSObjWrappers.initialized()); - nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp); - sJSObjWrappers.remove(key); + if (sJSObjWrappers.ops) { + // Remove the wrapper from the hash - jsnpobj->ClearJSObject(); + nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp); + PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_REMOVE); + } + + // Forget our reference to the JSObject. + jsnpobj->mJSObj = nullptr; } } @@ -937,23 +915,34 @@ nsJSObjWrapper::NP_Construct(NPObject *npobj, const NPVariant *args, } +class JSObjWrapperHashEntry : public PLDHashEntryHdr +{ +public: + nsJSObjWrapper *mJSObjWrapper; +}; -/* - * This function is called during minor GCs for each key in the sJSObjWrappers - * table that has been moved. - */ -static void -JSObjWrapperKeyMarkCallback(JSTracer *trc, void *key, void *data) { - JSObject *obj = static_cast(key); - nsJSObjWrapper* wrapper = static_cast(data); - JSObject *prior = obj; - JS_CallObjectTracer(trc, &obj, "sJSObjWrappers key object"); - NPP npp = wrapper->mNpp; - nsJSObjWrapperKey oldKey(prior, npp); - nsJSObjWrapperKey newKey(obj, npp); - sJSObjWrappers.rekeyIfMoved(oldKey, newKey); + +static PLDHashNumber +JSObjWrapperHash(PLDHashTable *table, const void *key) +{ + const nsJSObjWrapperKey *e = static_cast(key); + return HashGeneric(e->mJSObj, e->mNpp); } +static bool +JSObjWrapperHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, + const void *key) +{ + const nsJSObjWrapperKey *objWrapperKey = + static_cast(key); + const JSObjWrapperHashEntry *e = + static_cast(entry); + + return (e->mJSObjWrapper->mJSObj == objWrapperKey->mJSObj && + e->mJSObjWrapper->mNpp == objWrapperKey->mNpp); +} + + // Look up or create an NPObject that wraps the JSObject obj. // static @@ -1001,9 +990,22 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) return _retainobject(npobj); } - if (!sJSObjWrappers.initialized()) { + if (!sJSObjWrappers.ops) { // No hash yet (or any more), initialize it. - if (!sJSObjWrappers.init(16)) { + + static const PLDHashTableOps ops = + { + PL_DHashAllocTable, + PL_DHashFreeTable, + JSObjWrapperHash, + JSObjWrapperHashMatchEntry, + PL_DHashMoveEntryStub, + PL_DHashClearEntryStub, + PL_DHashFinalizeStub + }; + + if (!PL_DHashTableInit(&sJSObjWrappers, &ops, nullptr, + sizeof(JSObjWrapperHashEntry), 16)) { NS_ERROR("Error initializing PLDHashTable!"); return nullptr; @@ -1012,13 +1014,18 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) nsJSObjWrapperKey key(obj, npp); - JSObjWrapperTable::AddPtr p = sJSObjWrappers.lookupForAdd(key); + JSObjWrapperHashEntry *entry = static_cast + (PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_ADD)); - if (p/* && p->value*/) { - MOZ_ASSERT(p->value); + if (!entry) { + // Out of memory. + return nullptr; + } + + if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObjWrapper) { // Found a live nsJSObjWrapper, return it. - return _retainobject(p->value); + return _retainobject(entry->mJSObjWrapper); } // No existing nsJSObjWrapper, create one. @@ -1027,17 +1034,16 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) (nsJSObjWrapper *)_createobject(npp, &sJSObjWrapperNPClass); if (!wrapper) { - // Out of memory, entry not yet added to table. + // OOM? Remove the stale entry from the hash. + + PL_DHashTableRawRemove(&sJSObjWrappers, entry); + return nullptr; } wrapper->mJSObj = obj; - if (!sJSObjWrappers.add(p, key, wrapper)) { - // Out of memory, free the wrapper we created. - _releaseobject(wrapper); - return nullptr; - } + entry->mJSObjWrapper = wrapper; NS_ASSERTION(wrapper->mNpp == npp, "nsJSObjWrapper::mNpp not initialized!"); @@ -1046,15 +1052,13 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) if (!::JS_AddNamedObjectRoot(cx, &wrapper->mJSObj, "nsJSObjWrapper::mJSObject")) { NS_ERROR("Failed to root JSObject!"); - sJSObjWrappers.remove(key); _releaseobject(wrapper); + PL_DHashTableRawRemove(&sJSObjWrappers, entry); + return nullptr; } - // Add postbarrier for the hashtable key - JS_StoreObjectPostBarrierCallback(cx, JSObjWrapperKeyMarkCallback, obj, wrapper); - return wrapper; } @@ -1808,6 +1812,35 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj) } +// PLDHashTable enumeration callbacks for destruction code. +static PLDHashOperator +JSObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, + uint32_t number, void *arg) +{ + JSObjWrapperHashEntry *entry = (JSObjWrapperHashEntry *)hdr; + + nsJSObjWrapper *npobj = entry->mJSObjWrapper; + + if (npobj->mNpp == arg) { + // Prevent invalidate() and _releaseobject() from touching the hash + // we're enumerating. + const PLDHashTableOps *ops = table->ops; + table->ops = nullptr; + + if (npobj->_class && npobj->_class->invalidate) { + npobj->_class->invalidate(npobj); + } + + _releaseobject(npobj); + + table->ops = ops; + + return PL_DHASH_REMOVE; + } + + return PL_DHASH_NEXT; +} + // Struct for passing an NPP and a JSContext to // NPObjWrapperPluginDestroyedCallback struct NppAndCx @@ -1855,7 +1888,7 @@ NPObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, ::JS_SetPrivate(entry->mJSObj, nullptr); - table->ops = ops; + table->ops = ops; if (sDelayedReleases && sDelayedReleases->RemoveElement(npobj)) { OnWrapperDestroyed(); @@ -1871,16 +1904,9 @@ NPObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, void nsJSNPRuntime::OnPluginDestroy(NPP npp) { - if (sJSObjWrappers.initialized()) { - for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) { - nsJSObjWrapper *npobj = e.front().value; - MOZ_ASSERT(npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass); - if (npobj->mNpp == npp) { - npobj->ClearJSObject(); - _releaseobject(npobj); - e.removeFront(); - } - } + if (sJSObjWrappers.ops) { + PL_DHashTableEnumerate(&sJSObjWrappers, + JSObjWrapperPluginDestroyedCallback, npp); } // Use the safe JSContext here as we're not always able to find the diff --git a/dom/plugins/base/nsJSNPRuntime.h b/dom/plugins/base/nsJSNPRuntime.h index 30869dbbdcac..ba20f30c25b7 100644 --- a/dom/plugins/base/nsJSNPRuntime.h +++ b/dom/plugins/base/nsJSNPRuntime.h @@ -25,30 +25,20 @@ public: { } - bool operator==(const nsJSObjWrapperKey& other) const { - return mJSObj == other.mJSObj && mNpp == other.mNpp; - } - bool operator!=(const nsJSObjWrapperKey& other) const { - return !(*this == other); - } + JSObject *mJSObj; - JSObject * mJSObj; const NPP mNpp; }; extern const JSClass sNPObjectJSWrapperClass; -class nsJSObjWrapper : public NPObject +class nsJSObjWrapper : public NPObject, + public nsJSObjWrapperKey { public: - JSObject *mJSObj; /* Added as a GC root. */ - const NPP mNpp; - static NPObject *GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj); - void ClearJSObject(); - protected: nsJSObjWrapper(NPP npp); ~nsJSObjWrapper(); From bc86ea8de48c74daf4ca89b7614390448dd2e918 Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:38:13 +0000 Subject: [PATCH 090/268] Backed out changeset b75c703f2e7e (bug 935136) --- js/public/Value.h | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/js/public/Value.h b/js/public/Value.h index dc8225b6dfd9..0beabd8fff3e 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1520,6 +1520,7 @@ template <> struct GCMethods #endif }; +template class UnbarrieredMutableValueOperations; template class MutableValueOperations; /* @@ -1531,6 +1532,7 @@ template class MutableValueOperations; template class ValueOperations { + friend class UnbarrieredMutableValueOperations; friend class MutableValueOperations; const JS::Value * value() const { return static_cast(this)->extract(); } @@ -1571,14 +1573,16 @@ class ValueOperations }; /* - * A class designed for CRTP use in implementing all the mutating parts of the - * Value interface in Value-like classes. Outer must be a class inheriting - * MutableValueOperations with visible extractMutable() and extract() - * methods returning the const Value* and Value* abstracted by Outer. + * A class designed for CRTP use in implementing the mutating parts of the Value + * interface in Value-like classes that don't need post barriers. Outer must be + * a class inheriting UnbarrieredMutableValueOperations with visible + * extractMutable() and extract() methods returning the const Value* and Value* + * abstracted by Outer. */ template -class MutableValueOperations : public ValueOperations +class UnbarrieredMutableValueOperations : public ValueOperations { + friend class MutableValueOperations; JS::Value * value() { return static_cast(this)->extractMutable(); } public: @@ -1591,6 +1595,18 @@ class MutableValueOperations : public ValueOperations void setMagic(JSWhyMagic why) { value()->setMagic(why); } bool setNumber(uint32_t ui) { return value()->setNumber(ui); } bool setNumber(double d) { return value()->setNumber(d); } +}; + +/* + * A class designed for CRTP use in implementing all the mutating parts of the + * Value interface in Value-like classes. Outer must be a class inheriting + * MutableValueOperations with visible extractMutable() and extract() + * methods returning the const Value* and Value* abstracted by Outer. + */ +template +class MutableValueOperations : public UnbarrieredMutableValueOperations +{ + public: void setString(JSString *str) { this->value()->setString(str); } void setString(const JS::Anchor &str) { this->value()->setString(str); } void setObject(JSObject &obj) { this->value()->setObject(obj); } @@ -1680,6 +1696,7 @@ class MutableHandleBase : public MutableValueOperations*>(this)->address(); } + friend class UnbarrieredMutableValueOperations >; friend class MutableValueOperations >; JS::Value * extractMutable() { return static_cast*>(this)->address(); @@ -1698,6 +1715,7 @@ class RootedBase : public MutableValueOperations*>(this)->address(); } + friend class UnbarrieredMutableValueOperations >; friend class MutableValueOperations >; JS::Value * extractMutable() { return static_cast*>(this)->address(); From 8291c4ed9ecc85ece054fc22a7aee35b097e45be Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Wed, 20 Nov 2013 16:38:41 +0000 Subject: [PATCH 091/268] Backed out changeset 1b720320ccf4 (bug 939993) for rootanalysis assertions on a CLOSED TREE --- js/public/HashTable.h | 1 - js/src/vm/Shape.cpp | 25 +++++-------------------- 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 2855f78b185f..03265f5d1b88 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -1511,7 +1511,6 @@ class HashTable : private AllocPolicy p.mutationCount = mutationCount; { mozilla::ReentrancyGuard g(*this); - JS_ASSERT(prepareHash(l) == p.keyHash); // l has not been destroyed p.entry_ = &lookup(l, p.keyHash, sCollisionBit); } return p.found() || add(p, mozilla::Forward(u)); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 7b33479f5cf3..6b2313b74623 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1466,7 +1466,6 @@ BaseShape::getUnowned(ExclusiveContext *cx, const StackBaseShape &base) if (!table.initialized() && !table.init()) return nullptr; - uint64_t originalGcNumber = cx->zone()->gcNumber(); BaseShapeSet::AddPtr p = table.lookupForAdd(&base); if (p) @@ -1482,14 +1481,7 @@ BaseShape::getUnowned(ExclusiveContext *cx, const StackBaseShape &base) UnownedBaseShape *nbase = static_cast(nbase_); - /* - * If a GC has occurred then the hash we calculated may be invalid, as it is - * based on the objects inside StackBaseShape, which may have been moved. - */ - bool gcHappened = cx->zone()->gcNumber() != originalGcNumber; - bool added = gcHappened ? table.putNew(&base, nbase) - : table.relookupOrAdd(p, &base, nbase); - if (!added) + if (!table.relookupOrAdd(p, &base, nbase)) return nullptr; return nbase; @@ -1601,7 +1593,6 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, const Class *clasp, TaggedProt return nullptr; typedef InitialShapeEntry::Lookup Lookup; - uint64_t originalGcNumber = cx->zone()->gcNumber(); InitialShapeSet::AddPtr p = table.lookupForAdd(Lookup(clasp, proto, parent, metadata, nfixed, objectFlags)); @@ -1623,17 +1614,11 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, const Class *clasp, TaggedProt return nullptr; new (shape) EmptyShape(nbase, nfixed); - /* - * If a GC has occurred, then the hash we calculated may be invalid, as it - * is based on objects which may have been moved. - */ - Lookup lookup(clasp, protoRoot, parentRoot, metadataRoot, nfixed, objectFlags); - InitialShapeEntry entry(shape, protoRoot); - bool gcHappened = cx->zone()->gcNumber() != originalGcNumber; - bool added = gcHappened ? table.putNew(lookup, entry) - : table.relookupOrAdd(p, lookup, entry); - if (!added) + if (!table.relookupOrAdd(p, Lookup(clasp, protoRoot, parentRoot, metadataRoot, nfixed, objectFlags), + InitialShapeEntry(shape, protoRoot))) + { return nullptr; + } return shape; } From 60cda03b251b31018d27f8b70274e065d907a866 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 20 Nov 2013 11:29:03 -0500 Subject: [PATCH 092/268] Bug 940191 - Build dom/base in unified mode - r=ehsan --- dom/base/DOMError.cpp | 7 +------ dom/base/moz.build | 18 +++++++++++++----- dom/base/nsQueryContentEventResult.h | 5 +++++ dom/camera/DOMCameraManager.h | 2 +- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/dom/base/DOMError.cpp b/dom/base/DOMError.cpp index e1b101d39460..8da1b9ab7918 100644 --- a/dom/base/DOMError.cpp +++ b/dom/base/DOMError.cpp @@ -6,14 +6,9 @@ #include "mozilla/dom/DOMError.h" #include "mozilla/dom/DOMErrorBinding.h" +#include "mozilla/dom/DOMException.h" #include "nsPIDOMWindow.h" -// Implemented in DOMException.cpp -nsresult -NS_GetNameAndMessageForDOMNSResult(nsresult aNSResult, const char** aName, - const char** aMessage, - uint16_t* aCode = nullptr); - namespace mozilla { namespace dom { diff --git a/dom/base/moz.build b/dom/base/moz.build index 333a95984830..2f4a58e0fead 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -63,7 +63,7 @@ EXPORTS.mozilla.dom += [ 'URL.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'BarProps.cpp', 'CompositionStringSynthesizer.cpp', 'Crypto.cpp', @@ -72,7 +72,6 @@ SOURCES += [ 'DOMException.cpp', 'DOMRequest.cpp', 'MessageChannel.cpp', - 'MessagePort.cpp', 'MessagePortList.cpp', 'Navigator.cpp', 'nsContentPermissionHelper.cpp', @@ -80,9 +79,7 @@ SOURCES += [ 'nsDOMNavigationTiming.cpp', 'nsDOMScriptObjectFactory.cpp', 'nsDOMWindowList.cpp', - 'nsDOMWindowUtils.cpp', 'nsFocusManager.cpp', - 'nsGlobalWindow.cpp', 'nsGlobalWindowCommands.cpp', 'nsHistory.cpp', 'nsJSEnvironment.cpp', @@ -91,7 +88,6 @@ SOURCES += [ 'nsLocation.cpp', 'nsMimeTypeArray.cpp', 'nsPerformance.cpp', - 'nsPluginArray.cpp', 'nsQueryContentEventResult.cpp', 'nsScreen.cpp', 'nsScriptNameSpaceManager.cpp', @@ -103,6 +99,18 @@ SOURCES += [ 'WindowNamedPropertiesHandler.cpp', ] +# these files couldn't be in UNIFIED_SOURCES for now for reasons given below: +SOURCES += [ + # this file doesn't like windows.h + 'MessagePort.cpp', + # this file doesn't like windows.h + 'nsDOMWindowUtils.cpp', + # This file has a #error "Never include windows.h in this file!" + 'nsGlobalWindow.cpp', + # nsPluginArray.cpp includes npapi.h indirectly, and that includes a lot of system headers + 'nsPluginArray.cpp', +] + EXTRA_COMPONENTS += [ 'ConsoleAPI.js', 'ConsoleAPI.manifest', diff --git a/dom/base/nsQueryContentEventResult.h b/dom/base/nsQueryContentEventResult.h index 26a494289ab9..a9b9ff1f79d5 100644 --- a/dom/base/nsQueryContentEventResult.h +++ b/dom/base/nsQueryContentEventResult.h @@ -3,6 +3,9 @@ * 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 mozilla_dom_nsQueryContentEventResult_h +#define mozilla_dom_nsQueryContentEventResult_h + #include "nsIQueryContentEventResult.h" #include "nsString.h" #include "nsRect.h" @@ -32,3 +35,5 @@ protected: bool mSucceeded; bool mReversed; }; + +#endif // mozilla_dom_nsQueryContentEventResult_h \ No newline at end of file diff --git a/dom/camera/DOMCameraManager.h b/dom/camera/DOMCameraManager.h index ad5890c9538a..5758a475fd42 100644 --- a/dom/camera/DOMCameraManager.h +++ b/dom/camera/DOMCameraManager.h @@ -85,7 +85,7 @@ protected: * 'mActiveWindows' is only ever accessed while in the main thread, * so it is not otherwise protected. */ - static WindowTable* sActiveWindows; + static ::WindowTable* sActiveWindows; }; class GetCameraTask : public nsRunnable From cfc2209999ac02c6c3ef277ad1f2e688904699b6 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 20 Nov 2013 11:29:03 -0500 Subject: [PATCH 093/268] Bug 940717 - Unify the IsChromeURI functions we have in various places - r=ehsan --- chrome/src/nsChromeRegistry.cpp | 10 ++-------- content/xbl/src/nsXBLDocumentInfo.cpp | 12 +++--------- content/xbl/src/nsXBLPrototypeResources.cpp | 11 +++-------- content/xul/document/src/XULDocument.cpp | 9 +-------- dom/base/URL.cpp | 8 ++++++++ dom/base/URL.h | 2 ++ layout/style/Loader.cpp | 11 +---------- 7 files changed, 20 insertions(+), 43 deletions(-) diff --git a/chrome/src/nsChromeRegistry.cpp b/chrome/src/nsChromeRegistry.cpp index d7dabde70631..1601fe88e29e 100644 --- a/chrome/src/nsChromeRegistry.cpp +++ b/chrome/src/nsChromeRegistry.cpp @@ -27,8 +27,10 @@ #include "nsIPresShell.h" #include "nsIScriptError.h" #include "nsIWindowMediator.h" +#include "mozilla/dom/URL.h" nsChromeRegistry* nsChromeRegistry::gChromeRegistry; +using mozilla::dom::IsChromeURI; //////////////////////////////////////////////////////////////////////////////// @@ -371,14 +373,6 @@ nsChromeRegistry::FlushSkinCaches() NS_CHROME_FLUSH_SKINS_TOPIC, nullptr); } -static bool IsChromeURI(nsIURI* aURI) -{ - bool isChrome=false; - if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) - return true; - return false; -} - // XXXbsmedberg: move this to windowmediator nsresult nsChromeRegistry::RefreshWindow(nsIDOMWindow* aWindow) { diff --git a/content/xbl/src/nsXBLDocumentInfo.cpp b/content/xbl/src/nsXBLDocumentInfo.cpp index b5932f9ce89b..5c304c26566e 100644 --- a/content/xbl/src/nsXBLDocumentInfo.cpp +++ b/content/xbl/src/nsXBLDocumentInfo.cpp @@ -33,9 +33,11 @@ #include "mozilla/scache/StartupCacheUtils.h" #include "nsCCUncollectableMarker.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/URL.h" -using namespace mozilla::scache; using namespace mozilla; +using namespace mozilla::scache; +using namespace mozilla::dom; static const char kXBLCachePrefix[] = "xblcache"; @@ -282,14 +284,6 @@ nsXBLDocGlobalObject::GetPrincipal() return document->NodePrincipal(); } -static bool IsChromeURI(nsIURI* aURI) -{ - bool isChrome = false; - if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome))) - return isChrome; - return false; -} - /* Implementation file */ static bool diff --git a/content/xbl/src/nsXBLPrototypeResources.cpp b/content/xbl/src/nsXBLPrototypeResources.cpp index 51ff4235b81c..d68d21ecba33 100644 --- a/content/xbl/src/nsXBLPrototypeResources.cpp +++ b/content/xbl/src/nsXBLPrototypeResources.cpp @@ -16,6 +16,9 @@ #include "nsLayoutCID.h" #include "nsCSSRuleProcessor.h" #include "nsStyleSet.h" +#include "mozilla/dom/URL.h" + +using mozilla::dom::IsChromeURI; nsXBLPrototypeResources::nsXBLPrototypeResources(nsXBLPrototypeBinding* aBinding) { @@ -57,14 +60,6 @@ nsXBLPrototypeResources::AddResourceListener(nsIContent* aBoundElement) mLoader->AddResourceListener(aBoundElement); } -static bool IsChromeURI(nsIURI* aURI) -{ - bool isChrome=false; - if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) - return true; - return false; -} - nsresult nsXBLPrototypeResources::FlushSkinSheets() { diff --git a/content/xul/document/src/XULDocument.cpp b/content/xul/document/src/XULDocument.cpp index 88b7d9d5588c..39cf5815d7e9 100644 --- a/content/xul/document/src/XULDocument.cpp +++ b/content/xul/document/src/XULDocument.cpp @@ -90,6 +90,7 @@ #include "mozilla/Preferences.h" #include "nsTextNode.h" #include "nsJSUtils.h" +#include "mozilla/dom/URL.h" using namespace mozilla; using namespace mozilla::dom; @@ -101,14 +102,6 @@ using namespace mozilla::dom; static NS_DEFINE_CID(kParserCID, NS_PARSER_CID); -static bool IsChromeURI(nsIURI* aURI) -{ - bool isChrome = false; - if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) - return true; - return false; -} - static bool IsOverlayAllowed(nsIURI* aURI) { bool canOverlay = false; diff --git a/dom/base/URL.cpp b/dom/base/URL.cpp index 3dbafcaf9f4b..f9f521e98942 100644 --- a/dom/base/URL.cpp +++ b/dom/base/URL.cpp @@ -409,5 +409,13 @@ URL::SetHash(const nsAString& aHash) mURI->SetRef(NS_ConvertUTF16toUTF8(aHash)); } +bool IsChromeURI(nsIURI* aURI) +{ + bool isChrome = false; + if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome))) + return isChrome; + return false; +} + } } diff --git a/dom/base/URL.h b/dom/base/URL.h index 1c80d6f6f184..762f4e292e67 100644 --- a/dom/base/URL.h +++ b/dom/base/URL.h @@ -130,6 +130,8 @@ private: friend class mozilla::dom::workers::URLProxy; }; +bool IsChromeURI(nsIURI* aURI); + } } diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index b16afe4751e3..7e4de5d0972c 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -48,6 +48,7 @@ #include "nsIThreadInternal.h" #include "nsCrossSiteListenerProxy.h" #include "nsINetworkSeer.h" +#include "mozilla/dom/URL.h" #ifdef MOZ_XUL #include "nsXULPrototypeCache.h" @@ -942,16 +943,6 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader, return result; } -#ifdef MOZ_XUL -static bool IsChromeURI(nsIURI* aURI) -{ - NS_ASSERTION(aURI, "Have to pass in a URI"); - bool isChrome = false; - aURI->SchemeIs("chrome", &isChrome); - return isChrome; -} -#endif - bool Loader::IsAlternate(const nsAString& aTitle, bool aHasAlternateRel) { From f16a5fb6b5a5867d765aca64f3a85b1edd50c4d1 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 20 Nov 2013 11:29:04 -0500 Subject: [PATCH 094/268] Bug 940719 - Build content/xbl in unified mode - r=ehsan --- content/xbl/src/moz.build | 2 +- content/xbl/src/nsXBLResourceLoader.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/content/xbl/src/moz.build b/content/xbl/src/moz.build index 1d7e0e900ef5..e8a93d589343 100644 --- a/content/xbl/src/moz.build +++ b/content/xbl/src/moz.build @@ -14,7 +14,7 @@ EXPORTS.mozilla.dom += [ 'XBLChildrenElement.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'nsBindingManager.cpp', 'nsXBLBinding.cpp', 'nsXBLContentSink.cpp', diff --git a/content/xbl/src/nsXBLResourceLoader.h b/content/xbl/src/nsXBLResourceLoader.h index 114fcd2fab03..ab7fe285232f 100644 --- a/content/xbl/src/nsXBLResourceLoader.h +++ b/content/xbl/src/nsXBLResourceLoader.h @@ -3,6 +3,9 @@ * 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 nsXBLResourceLoader_h +#define nsXBLResourceLoader_h + #include "mozilla/Attributes.h" #include "nsCOMPtr.h" #include "nsICSSLoaderObserver.h" @@ -62,3 +65,4 @@ public: nsCOMArray mBoundElements; }; +#endif From e8d0b5ec026c7250de199a039ca8c48610c28b19 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 20 Nov 2013 11:29:04 -0500 Subject: [PATCH 095/268] Bug 940720 - Build content/xul/templates in unified mode - r=ehsan --- content/xul/templates/src/moz.build | 2 +- content/xul/templates/src/nsXULSortService.h | 5 +++++ content/xul/templates/src/nsXULTemplateBuilder.cpp | 7 ++----- .../xul/templates/src/nsXULTemplateQueryProcessorRDF.cpp | 5 ++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/content/xul/templates/src/moz.build b/content/xul/templates/src/moz.build index 672f61178562..722d3a812ccd 100644 --- a/content/xul/templates/src/moz.build +++ b/content/xul/templates/src/moz.build @@ -4,7 +4,7 @@ # 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/. -SOURCES += [ +UNIFIED_SOURCES += [ 'nsContentSupportMap.cpp', 'nsContentTestNode.cpp', 'nsInstantiationNode.cpp', diff --git a/content/xul/templates/src/nsXULSortService.h b/content/xul/templates/src/nsXULSortService.h index 18ca34e656a1..c003974ead8b 100644 --- a/content/xul/templates/src/nsXULSortService.h +++ b/content/xul/templates/src/nsXULSortService.h @@ -20,6 +20,9 @@ This sort service is used to sort template built content or content by attribute. */ +#ifndef nsXULTemplateResultSetRDF_h +#define nsXULTemplateResultSetRDF_h + #include "nsCOMPtr.h" #include "nsCOMArray.h" #include "nsTArray.h" @@ -179,3 +182,5 @@ public: const nsAString& aRight, uint32_t aSortHints); }; + +#endif diff --git a/content/xul/templates/src/nsXULTemplateBuilder.cpp b/content/xul/templates/src/nsXULTemplateBuilder.cpp index ff7ff8ee505b..8b63f8ad4ce0 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -73,11 +73,6 @@ using namespace mozilla::dom; using namespace mozilla; -//---------------------------------------------------------------------- - -static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); -static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); - //---------------------------------------------------------------------- // // nsXULTemplateBuilder @@ -144,10 +139,12 @@ nsXULTemplateBuilder::InitGlobals() if (gRefCnt++ == 0) { // Initialize the global shared reference to the service // manager and get some shared resource objects. + NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); rv = CallGetService(kRDFServiceCID, &gRDFService); if (NS_FAILED(rv)) return rv; + NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils); if (NS_FAILED(rv)) return rv; diff --git a/content/xul/templates/src/nsXULTemplateQueryProcessorRDF.cpp b/content/xul/templates/src/nsXULTemplateQueryProcessorRDF.cpp index 3909840aebad..6f02e0c3c5ec 100644 --- a/content/xul/templates/src/nsXULTemplateQueryProcessorRDF.cpp +++ b/content/xul/templates/src/nsXULTemplateQueryProcessorRDF.cpp @@ -37,9 +37,6 @@ //---------------------------------------------------------------------- -static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); -static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); - #define PARSE_TYPE_INTEGER "Integer" nsrefcnt nsXULTemplateQueryProcessorRDF::gRefCnt = 0; @@ -145,12 +142,14 @@ nsXULTemplateQueryProcessorRDF::InitGlobals() // Initialize the global shared reference to the service // manager and get some shared resource objects. if (!gRDFService) { + NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); rv = CallGetService(kRDFServiceCID, &gRDFService); if (NS_FAILED(rv)) return rv; } if (!gRDFContainerUtils) { + NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); rv = CallGetService(kRDFContainerUtilsCID, &gRDFContainerUtils); if (NS_FAILED(rv)) return rv; From cc693c12409c6de987a93e40f9b7fa849366ecbd Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 20 Nov 2013 11:29:04 -0500 Subject: [PATCH 096/268] Bug 940721 - Build content/smil in unified mode - r=ehsan --- content/smil/moz.build | 2 +- content/smil/nsSMILRepeatCount.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/content/smil/moz.build b/content/smil/moz.build index edf016dbe776..df5109727bda 100644 --- a/content/smil/moz.build +++ b/content/smil/moz.build @@ -32,7 +32,7 @@ EXPORTS += [ 'nsSMILValue.h', ] -SOURCES += [ +UNIFIED_SOURCES += [ 'nsDOMTimeEvent.cpp', 'nsSMILAnimationController.cpp', 'nsSMILAnimationFunction.cpp', diff --git a/content/smil/nsSMILRepeatCount.h b/content/smil/nsSMILRepeatCount.h index d57f06db4639..18c6d66db618 100644 --- a/content/smil/nsSMILRepeatCount.h +++ b/content/smil/nsSMILRepeatCount.h @@ -3,6 +3,9 @@ * 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 nsSMILRepeatCount_h +#define nsSMILRepeatCount_h + #include "nsDebug.h" #include @@ -50,3 +53,5 @@ private: double mCount; }; + +#endif From 2317b71a7fd390d866535643b4fbe3426e65d4be Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 20 Nov 2013 17:20:50 +0100 Subject: [PATCH 097/268] Bug 935923 - Rename AlphaMode helper function to D2DAlphaModeForFormat and replace most of its uses with D2DPixelFormat. r=Bas --HG-- extra : rebase_source : c01334a631fae221d474c89502057892c9f540fd --- gfx/2d/DrawTargetD2D.cpp | 6 ++---- gfx/2d/HelpersD2D.h | 4 ++-- gfx/2d/SourceSurfaceD2D.cpp | 6 ++---- gfx/2d/SourceSurfaceD2DTarget.cpp | 8 +++----- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/gfx/2d/DrawTargetD2D.cpp b/gfx/2d/DrawTargetD2D.cpp index c209c80788dc..163c9ebbe547 100644 --- a/gfx/2d/DrawTargetD2D.cpp +++ b/gfx/2d/DrawTargetD2D.cpp @@ -85,9 +85,7 @@ public: } mDT->mDevice->CopyResource(tmpTexture, mDT->mTexture); - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(format), - AlphaMode(format))); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(format)); RefPtr surf; @@ -306,7 +304,7 @@ DrawTargetD2D::GetBitmapForSurface(SourceSurface *aSurface, (uint32_t)aSource.x * BytesPerPixel(srcSurf->GetFormat()); D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(srcSurf->GetFormat()), AlphaMode(srcSurf->GetFormat()))); + D2D1::BitmapProperties(D2DPixelFormat(srcSurf->GetFormat())); mRT->CreateBitmap(D2D1::SizeU(UINT32(aSource.width), UINT32(aSource.height)), data, stride, props, byRef(bitmap)); // subtract the integer part leaving the fractional part diff --git a/gfx/2d/HelpersD2D.h b/gfx/2d/HelpersD2D.h index 802a4e1b9a55..2e10643e1be0 100644 --- a/gfx/2d/HelpersD2D.h +++ b/gfx/2d/HelpersD2D.h @@ -162,7 +162,7 @@ static inline DXGI_FORMAT DXGIFormat(SurfaceFormat aFormat) } } -static inline D2D1_ALPHA_MODE AlphaMode(SurfaceFormat aFormat) +static inline D2D1_ALPHA_MODE D2DAlphaModeForFormat(SurfaceFormat aFormat) { switch (aFormat) { case FORMAT_B8G8R8X8: @@ -174,7 +174,7 @@ static inline D2D1_ALPHA_MODE AlphaMode(SurfaceFormat aFormat) static inline D2D1_PIXEL_FORMAT D2DPixelFormat(SurfaceFormat aFormat) { - return D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat)); + return D2D1::PixelFormat(DXGIFormat(aFormat), D2DAlphaModeForFormat(aFormat)); } #ifdef USE_D2D1_1 diff --git a/gfx/2d/SourceSurfaceD2D.cpp b/gfx/2d/SourceSurfaceD2D.cpp index 005a6901e5f7..9704f1103925 100644 --- a/gfx/2d/SourceSurfaceD2D.cpp +++ b/gfx/2d/SourceSurfaceD2D.cpp @@ -68,8 +68,7 @@ SourceSurfaceD2D::InitFromData(unsigned char *aData, return false; } - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat))); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat)); hr = aRT->CreateBitmap(D2DIntSize(aSize), aData, aStride, props, byRef(mBitmap)); if (FAILED(hr)) { @@ -105,8 +104,7 @@ SourceSurfaceD2D::InitFromTexture(ID3D10Texture2D *aTexture, mSize = IntSize(desc.Width, desc.Height); mFormat = aFormat; - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(aFormat), AlphaMode(aFormat))); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(aFormat)); hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); if (FAILED(hr)) { diff --git a/gfx/2d/SourceSurfaceD2DTarget.cpp b/gfx/2d/SourceSurfaceD2DTarget.cpp index 4f7e484cb0c1..a7ba9f710e8a 100644 --- a/gfx/2d/SourceSurfaceD2DTarget.cpp +++ b/gfx/2d/SourceSurfaceD2DTarget.cpp @@ -138,15 +138,13 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) return nullptr; } - D2D1_BITMAP_PROPERTIES props = - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat))); + D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2DPixelFormat(mFormat)); hr = aRT->CreateSharedBitmap(IID_IDXGISurface, surf, &props, byRef(mBitmap)); if (FAILED(hr)) { // This seems to happen for FORMAT_A8 sometimes... aRT->CreateBitmap(D2D1::SizeU(desc.Width, desc.Height), - D2D1::BitmapProperties(D2D1::PixelFormat(DXGIFormat(mFormat), - AlphaMode(mFormat))), + D2D1::BitmapProperties(D2DPixelFormat(mFormat)), byRef(mBitmap)); RefPtr rt; @@ -169,7 +167,7 @@ SourceSurfaceD2DTarget::GetBitmap(ID2D1RenderTarget *aRT) } D2D1_RENDER_TARGET_PROPERTIES props = - D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGIFormat(mFormat), AlphaMode(mFormat))); + D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2DPixelFormat(mFormat)); hr = DrawTargetD2D::factory()->CreateDxgiSurfaceRenderTarget(surface, props, byRef(rt)); if (FAILED(hr)) { From 45f70aba6a8571009e29472ef3044cda4774ccab Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 20 Nov 2013 17:20:50 +0100 Subject: [PATCH 098/268] Bug 936458 - Use MOZ_ASSERT instead of NS_ABORT_IF_FALSE in BasePoint3D.h and BasePoint4D.h because NS_ABORT_IF_FALSE is not in mfbt and can't be used in standalone moz2d. r=Bas --HG-- extra : rebase_source : 6ce1149a1c99feb0892a858851350b0e5119fc1a --- gfx/2d/BasePoint3D.h | 6 +++--- gfx/2d/BasePoint4D.h | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gfx/2d/BasePoint3D.h b/gfx/2d/BasePoint3D.h index 0312e425b8c8..c64ea247a5a2 100644 --- a/gfx/2d/BasePoint3D.h +++ b/gfx/2d/BasePoint3D.h @@ -6,7 +6,7 @@ #ifndef MOZILLA_BASEPOINT3D_H_ #define MOZILLA_BASEPOINT3D_H_ -#include "nsDebug.h" +#include "mozilla/Assertions.h" namespace mozilla { namespace gfx { @@ -31,12 +31,12 @@ struct BasePoint3D { // compiler generated default assignment operator T& operator[](int aIndex) { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 2, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 2); return *((&x)+aIndex); } const T& operator[](int aIndex) const { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 2, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 2); return *((&x)+aIndex); } diff --git a/gfx/2d/BasePoint4D.h b/gfx/2d/BasePoint4D.h index ab9fa452328e..a35deeed88b8 100644 --- a/gfx/2d/BasePoint4D.h +++ b/gfx/2d/BasePoint4D.h @@ -6,6 +6,8 @@ #ifndef MOZILLA_BASEPOINT4D_H_ #define MOZILLA_BASEPOINT4D_H_ +#include "mozilla/Assertions.h" + namespace mozilla { namespace gfx { @@ -86,12 +88,12 @@ struct BasePoint4D { } T& operator[](int aIndex) { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid array index"); return *((&x)+aIndex); } const T& operator[](int aIndex) const { - NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid array index"); + MOZ_ASSERT(aIndex >= 0 && aIndex <= 3, "Invalid array index"); return *((&x)+aIndex); } From 31ee17e9d5553fb396ef3eccde1d54c16edb098d Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 20 Nov 2013 17:20:51 +0100 Subject: [PATCH 099/268] Bug 936459 - Move Tools.h include into the right file. r=Bas --HG-- extra : rebase_source : 9c976b595a2dd22511184f1341a4d4192e375b50 --- gfx/2d/SourceSurfaceRawData.cpp | 1 - gfx/2d/SourceSurfaceRawData.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/2d/SourceSurfaceRawData.cpp b/gfx/2d/SourceSurfaceRawData.cpp index eca819cafa66..12c04b87b69a 100644 --- a/gfx/2d/SourceSurfaceRawData.cpp +++ b/gfx/2d/SourceSurfaceRawData.cpp @@ -5,7 +5,6 @@ #include "SourceSurfaceRawData.h" #include "Logging.h" -#include "Tools.h" namespace mozilla { namespace gfx { diff --git a/gfx/2d/SourceSurfaceRawData.h b/gfx/2d/SourceSurfaceRawData.h index 3a3e10a7cb57..60333432b778 100644 --- a/gfx/2d/SourceSurfaceRawData.h +++ b/gfx/2d/SourceSurfaceRawData.h @@ -7,6 +7,7 @@ #define MOZILLA_GFX_SOURCESURFACERAWDATA_H_ #include "2D.h" +#include "Tools.h" namespace mozilla { namespace gfx { From 9161db21c962058dcbfa26feb34827738e2a25ab Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 20 Nov 2013 17:20:51 +0100 Subject: [PATCH 100/268] Bug 923840 - Mark -moz-appearance:toolbar as opaque on Mac. r=roc --HG-- extra : rebase_source : 6f7ba3357c3d24c6c273270b25627dcab8298d47 --- widget/cocoa/nsNativeThemeCocoa.mm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm index d250bbd4382c..5ece8b31c180 100644 --- a/widget/cocoa/nsNativeThemeCocoa.mm +++ b/widget/cocoa/nsNativeThemeCocoa.mm @@ -3255,6 +3255,10 @@ nsNativeThemeCocoa::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType) // performance, because we create layers for them. return eOpaque; + case NS_THEME_TOOLBAR: + case NS_THEME_MOZ_MAC_UNIFIED_TOOLBAR: + return eOpaque; + default: return eUnknownTransparency; } From db3e318af646719164d4bbf3d16ae6095e63487f Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Wed, 20 Nov 2013 17:21:24 +0100 Subject: [PATCH 101/268] Bug 934023 - Use the correct cell rect when drawing the window buttons. r=smichaud --HG-- extra : rebase_source : 02a43c9e84c3f796bb8dc547734dc2169915ce86 --- widget/cocoa/nsChildView.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index f81bfbb17437..6f8bfa6df932 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -2198,7 +2198,8 @@ nsChildView::UpdateTitlebarImageBuffer() if (dirtyTitlebarRegion.IsEmpty()) return; - ClearRegion(mTitlebarImageBuffer, dirtyTitlebarRegion); + gfxUtils::ClipToRegion(mTitlebarImageBuffer, dirtyTitlebarRegion); + mTitlebarImageBuffer->ClearRect(gfx::Rect(0, 0, titlebarBufferSize.width, titlebarBufferSize.height)); gfx::BorrowedCGContext borrow(mTitlebarImageBuffer); CGContextRef ctx = borrow.cg; @@ -2222,9 +2223,7 @@ nsChildView::UpdateTitlebarImageBuffer() for (id view in [window titlebarControls]) { NSRect viewFrame = [view frame]; nsIntRect viewRect = CocoaPointsToDevPixels([mView convertRect:viewFrame fromView:frameView]); - nsIntRegion intersection; - intersection.And(dirtyTitlebarRegion, viewRect); - if (intersection.IsEmpty()) { + if (!dirtyTitlebarRegion.Intersects(viewRect)) { continue; } // All of the titlebar controls we're interested in are subclasses of @@ -2249,8 +2248,7 @@ nsChildView::UpdateTitlebarImageBuffer() [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:[view isFlipped]]]; - NSRect intersectRect = DevPixelsToCocoaPoints(intersection.GetBounds()); - [cell drawWithFrame:[view convertRect:intersectRect fromView:mView] inView:button]; + [cell drawWithFrame:[button bounds] inView:button]; [NSGraphicsContext setCurrentContext:context]; CGContextRestoreGState(ctx); @@ -2264,6 +2262,8 @@ nsChildView::UpdateTitlebarImageBuffer() [NSGraphicsContext setCurrentContext:oldContext]; borrow.Finish(); + mTitlebarImageBuffer->PopClip(); + mUpdatedTitlebarRegion.Or(mUpdatedTitlebarRegion, dirtyTitlebarRegion); } From d63f28c1f9fa6b152fffa2cf26ac69b9206b0dbd Mon Sep 17 00:00:00 2001 From: EKR Date: Tue, 19 Nov 2013 16:06:08 -0800 Subject: [PATCH 102/268] Bug 940709 - Upgrade ICE state change log level. r=bwc --- media/mtransport/nricectx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/media/mtransport/nricectx.cpp b/media/mtransport/nricectx.cpp index 6efdb175c633..e3bb621110d5 100644 --- a/media/mtransport/nricectx.cpp +++ b/media/mtransport/nricectx.cpp @@ -675,7 +675,7 @@ void NrIceCtx::SetState(State state) { if (state == state_) return; - MOZ_MTLOG(ML_DEBUG, "NrIceCtx(" << name_ << "): state " << + MOZ_MTLOG(ML_INFO, "NrIceCtx(" << name_ << "): state " << state_ << "->" << state); state_ = state; From cf59f0d8069006aeec81d299086835ebc1750146 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 20 Nov 2013 08:47:59 -0800 Subject: [PATCH 103/268] Bug 940783 - Throw when accessing properties and methods on history objects in non-active documents. r=bz --- dom/base/nsHistory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/dom/base/nsHistory.cpp b/dom/base/nsHistory.cpp index 0d0f768fc48b..6660790e487e 100644 --- a/dom/base/nsHistory.cpp +++ b/dom/base/nsHistory.cpp @@ -70,7 +70,7 @@ uint32_t nsHistory::GetLength(ErrorResult& aRv) const { nsCOMPtr win(do_QueryReferent(mInnerWindow)); - if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) { + if (!win || !win->IsCurrentInnerWindow()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return 0; @@ -106,7 +106,7 @@ nsHistory::GetState(JSContext* aCx, ErrorResult& aRv) const return JS::UndefinedValue(); } - if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow())) { + if (!win->IsCurrentInnerWindow()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return JS::UndefinedValue(); @@ -146,7 +146,7 @@ void nsHistory::Go(int32_t aDelta, ErrorResult& aRv) { nsCOMPtr win(do_QueryReferent(mInnerWindow)); - if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) { + if (!win || !win->IsCurrentInnerWindow()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; @@ -202,7 +202,7 @@ void nsHistory::Back(ErrorResult& aRv) { nsCOMPtr win(do_QueryReferent(mInnerWindow)); - if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) { + if (!win || !win->IsCurrentInnerWindow()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; @@ -223,7 +223,7 @@ void nsHistory::Forward(ErrorResult& aRv) { nsCOMPtr win(do_QueryReferent(mInnerWindow)); - if (!win || !nsContentUtils::CanCallerAccess(win->GetOuterWindow())) { + if (!win || !win->IsCurrentInnerWindow()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; @@ -268,7 +268,7 @@ nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle aData, return; } - if (!nsContentUtils::CanCallerAccess(win->GetOuterWindow())) { + if (!win->IsCurrentInnerWindow()) { aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); return; From 3c8589a040b9a65072a06689dc4a58ce0d6cf672 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 20 Nov 2013 08:47:59 -0800 Subject: [PATCH 104/268] Bug 940783 - Tests. r=bz --- js/xpconnect/tests/mochitest/mochitest.ini | 1 + .../tests/mochitest/test_bug940783.html | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 js/xpconnect/tests/mochitest/test_bug940783.html diff --git a/js/xpconnect/tests/mochitest/mochitest.ini b/js/xpconnect/tests/mochitest/mochitest.ini index bdc7e14af654..b5fea37b91ec 100644 --- a/js/xpconnect/tests/mochitest/mochitest.ini +++ b/js/xpconnect/tests/mochitest/mochitest.ini @@ -89,6 +89,7 @@ skip-if = os == 'android' [test_bug912322.html] [test_bug916945.html] [test_bug92773.html] +[test_bug940783.html] [test_crosscompartment_weakmap.html] [test_frameWrapping.html] [test_nac.xhtml] diff --git a/js/xpconnect/tests/mochitest/test_bug940783.html b/js/xpconnect/tests/mochitest/test_bug940783.html new file mode 100644 index 000000000000..9e9e4908423d --- /dev/null +++ b/js/xpconnect/tests/mochitest/test_bug940783.html @@ -0,0 +1,62 @@ + + + + + + Test for Bug 940783 + + + + + +Mozilla Bug 940783 +

+ +
+
+ + From bbb497880f7d6ace4ee4a2e07136575cbcc0c61c Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 20 Nov 2013 08:48:00 -0800 Subject: [PATCH 105/268] Bug 939166 - Be more direct in GetStaticScriptGlobal. r=bz This can all collapse because of the following facts: * Ever since we introduced SandboxPrivate, we never actually use a Window as an SOP for a sandbox. * nsGlobalWindow is actually the only thing that implements nsIScriptGlobalObject. --- dom/base/nsJSUtils.cpp | 42 +++---------------------------- js/xpconnect/src/XPCJSRuntime.cpp | 23 +++++++++++++++++ js/xpconnect/src/xpcpublic.h | 7 ++++++ 3 files changed, 33 insertions(+), 39 deletions(-) diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index abf4c8e8cb3d..ebdc7711f1b4 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -26,6 +26,7 @@ #include "nsJSPrincipals.h" #include "xpcpublic.h" #include "nsContentUtils.h" +#include "nsGlobalWindow.h" bool nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename, @@ -47,46 +48,9 @@ nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename, nsIScriptGlobalObject * nsJSUtils::GetStaticScriptGlobal(JSObject* aObj) { - const JSClass* clazz; - JSObject* glob = aObj; // starting point for search - - if (!glob) + if (!aObj) return nullptr; - - glob = js::GetGlobalForObjectCrossCompartment(glob); - NS_ABORT_IF_FALSE(glob, "Infallible returns null"); - - clazz = JS_GetClass(glob); - - // Whenever we end up with globals that are JSCLASS_IS_DOMJSCLASS - // and have an nsISupports DOM object, we will need to modify this - // check here. - MOZ_ASSERT(!(clazz->flags & JSCLASS_IS_DOMJSCLASS)); - nsISupports* supports; - if (!(clazz->flags & JSCLASS_HAS_PRIVATE) || - !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) || - !(supports = (nsISupports*)::JS_GetPrivate(glob))) { - return nullptr; - } - - // We might either have a window directly (e.g. if the global is a - // sandbox whose script object principal pointer is a window), or an - // XPCWrappedNative for a window. We could also have other - // sandbox-related script object principals, but we can't do much - // about those short of trying to walk the proto chain of |glob| - // looking for a window or something. - nsCOMPtr sgo(do_QueryInterface(supports)); - if (!sgo) { - nsCOMPtr wrapper(do_QueryInterface(supports)); - if (!wrapper) { - return nullptr; - } - sgo = do_QueryWrappedNative(wrapper); - } - - // We're returning a pointer to something that's about to be - // released, but that's ok here. - return sgo; + return xpc::WindowGlobalOrNull(aObj); } nsIScriptContext * diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 5513a149f495..1cc8a34213c3 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -37,6 +37,7 @@ #include "mozilla/dom/GeneratedAtomList.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/Element.h" +#include "mozilla/dom/WindowBinding.h" #include "mozilla/Attributes.h" #include "AccessCheck.h" #include "nsGlobalWindow.h" @@ -566,6 +567,28 @@ GetJunkScopeGlobal() return GetNativeForGlobal(junkScope); } +nsGlobalWindow* +WindowGlobalOrNull(JSObject *aObj) +{ + MOZ_ASSERT(aObj); + JSObject *glob = js::GetGlobalForObjectCrossCompartment(aObj); + MOZ_ASSERT(glob); + + // This will always return null until we have Window on WebIDL bindings, + // at which point it will do the right thing. + if (!IS_WN_CLASS(js::GetObjectClass(glob))) { + nsGlobalWindow* win = nullptr; + UNWRAP_OBJECT(Window, nullptr, glob, win); + return win; + } + + nsISupports* supports = XPCWrappedNative::Get(glob)->GetIdentityObject(); + nsCOMPtr piWin = do_QueryInterface(supports); + if (!piWin) + return nullptr; + return static_cast(piWin.get()); +} + } static void diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 5b279f05976b..9b43aa7dbaeb 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -404,6 +404,13 @@ GetJunkScope(); nsIGlobalObject * GetJunkScopeGlobal(); +/** + * If |aObj| has a window for a global, returns the associated nsGlobalWindow. + * Otherwise, returns null. + */ +nsGlobalWindow* +WindowGlobalOrNull(JSObject *aObj); + // Error reporter used when there is no associated DOM window on to which to // report errors and warnings. void From d14923552742e803df594898cf4ebdaaeba6bfb0 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 20 Nov 2013 08:48:00 -0800 Subject: [PATCH 106/268] Bug 939166 - Stop going through nsIScriptGlobalObject in CallSetup. r=bz --- dom/bindings/CallbackObject.cpp | 41 ++++++++++++--------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/dom/bindings/CallbackObject.cpp b/dom/bindings/CallbackObject.cpp index 9cc3708edf0c..2d70de0f0a0f 100644 --- a/dom/bindings/CallbackObject.cpp +++ b/dom/bindings/CallbackObject.cpp @@ -18,6 +18,7 @@ #include "nsIScriptSecurityManager.h" #include "xpcprivate.h" #include "WorkerPrivate.h" +#include "nsGlobalWindow.h" namespace mozilla { namespace dom { @@ -66,38 +67,26 @@ CallbackObject::CallSetup::CallSetup(JS::Handle aCallback, JSContext* cx = nullptr; if (mIsMainThread) { - // Now get the nsIScriptGlobalObject for this callback. - nsIScriptContext* ctx = nullptr; - nsIScriptGlobalObject* sgo = nsJSUtils::GetStaticScriptGlobal(realCallback); - if (sgo) { + // Now get the global and JSContext for this callback. + nsGlobalWindow* win = xpc::WindowGlobalOrNull(realCallback); + if (win) { // Make sure that if this is a window it's the current inner, since the // nsIScriptContext and hence JSContext are associated with the outer // window. Which means that if someone holds on to a function from a // now-unloaded document we'd have the new document as the script entry // point... - nsCOMPtr win = do_QueryInterface(sgo); - if (win) { - MOZ_ASSERT(win->IsInnerWindow()); - nsPIDOMWindow* outer = win->GetOuterWindow(); - if (!outer || win != outer->GetCurrentInnerWindow()) { - // Just bail out from here - return; - } + MOZ_ASSERT(win->IsInnerWindow()); + nsPIDOMWindow* outer = win->GetOuterWindow(); + if (!outer || win != outer->GetCurrentInnerWindow()) { + // Just bail out from here + return; } - // if not a window at all, just press on - - ctx = sgo->GetContext(); - if (ctx) { - // We don't check whether scripts are enabled on ctx, because - // CheckFunctionAccess will do that anyway... and because we ignore them - // being disabled if the callee is system. - cx = ctx->GetNativeContext(); - } - } - - if (!cx) { - // We didn't manage to hunt down a script global to work with. Just fall - // back on using the safe context. + cx = win->GetContext() ? win->GetContext()->GetNativeContext() + // This happens - Removing it causes + // test_bug293235.xul to go orange. + : nsContentUtils::GetSafeJSContext(); + } else { + // No DOM Window. Use the SafeJSContext. cx = nsContentUtils::GetSafeJSContext(); } From 854d8c604e870ff5686a8a6cedc35fec63cc9347 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Wed, 20 Nov 2013 17:54:29 +0100 Subject: [PATCH 107/268] Bug 895390 - Intermittent browser_privatebrowsing_cache.js | Disk cache reports 0KB and has no entries - Got 1, expected 0, r=emorley --- browser/components/privatebrowsing/test/browser/browser.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/browser/components/privatebrowsing/test/browser/browser.ini b/browser/components/privatebrowsing/test/browser/browser.ini index 493e3e1a333d..2b71c0723132 100644 --- a/browser/components/privatebrowsing/test/browser/browser.ini +++ b/browser/components/privatebrowsing/test/browser/browser.ini @@ -17,8 +17,7 @@ support-files = [browser_privatebrowsing_DownloadLastDirWithCPS.js] [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js] [browser_privatebrowsing_aboutSessionRestore.js] -# [browser_privatebrowsing_cache.js] -# Disabled for too many intermittent failures (bug 895390) +[browser_privatebrowsing_cache.js] [browser_privatebrowsing_certexceptionsui.js] [browser_privatebrowsing_concurrent.js] [browser_privatebrowsing_cookieacceptdialog.js] From e91fbfe720eb0b6c24b546cba3427b932bfb79d5 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 20 Nov 2013 18:40:57 +0100 Subject: [PATCH 108/268] Bug 940925 - Don't inspect Baseline binary arithmetic IC if it had unoptimizable operands. r=bhackett --- js/src/jit/BaselineIC.cpp | 8 +++++--- js/src/jit/BaselineIC.h | 15 ++++++++++++--- js/src/jit/BaselineInspector.cpp | 8 ++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 50223fd56fc3..fc8e480b1c09 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2537,8 +2537,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac // Check to see if a new stub should be generated. if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) { - // TODO: Discard all stubs in this IC and replace with inert megamorphic stub. - // But for now we just bail. + stub->noteUnoptimizableOperands(); return true; } @@ -2585,8 +2584,10 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac } // Handle only int32 or double. - if (!lhs.isNumber() || !rhs.isNumber()) + if (!lhs.isNumber() || !rhs.isNumber()) { + stub->noteUnoptimizableOperands(); return true; + } JS_ASSERT(ret.isNumber()); @@ -2653,6 +2654,7 @@ DoBinaryArithFallback(JSContext *cx, BaselineFrame *frame, ICBinaryArith_Fallbac } } + stub->noteUnoptimizableOperands(); return true; } #if defined(_MSC_VER) diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 1e96b8178365..665ce2576f87 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -2419,6 +2419,9 @@ class ICBinaryArith_Fallback : public ICFallbackStub extra_ = 0; } + static const uint16_t SAW_DOUBLE_RESULT_BIT = 0x1; + static const uint16_t UNOPTIMIZABLE_OPERANDS_BIT = 0x2; + public: static const uint32_t MAX_OPTIMIZED_STUBS = 8; @@ -2428,11 +2431,17 @@ class ICBinaryArith_Fallback : public ICFallbackStub return space->allocate(code); } - bool sawDoubleResult() { - return extra_; + bool sawDoubleResult() const { + return extra_ & SAW_DOUBLE_RESULT_BIT; } void setSawDoubleResult() { - extra_ = 1; + extra_ |= SAW_DOUBLE_RESULT_BIT; + } + bool hadUnoptimizableOperands() const { + return extra_ & UNOPTIMIZABLE_OPERANDS_BIT; + } + void noteUnoptimizableOperands() { + extra_ |= UNOPTIMIZABLE_OPERANDS_BIT; } // Compiler for this stub kind. diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index ea996156d33d..4768ced51887 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -295,6 +295,14 @@ BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc) MIRType result; ICStub *stubs[2]; + const ICEntry &entry = icEntryFromPC(pc); + ICStub *stub = entry.fallbackStub(); + if (stub->isBinaryArith_Fallback() && + stub->toBinaryArith_Fallback()->hadUnoptimizableOperands()) + { + return MIRType_None; + } + stubs[0] = monomorphicStub(pc); if (stubs[0]) { if (TryToSpecializeBinaryArithOp(stubs, 1, &result)) From f104f1d5ca249a985ece0e411ff61b75a16598b7 Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Wed, 20 Nov 2013 12:51:36 -0500 Subject: [PATCH 109/268] Bug 941053 - upload a new talos.zip to capture fix for ts_paint. r=jlund --- testing/talos/talos.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/talos/talos.json b/testing/talos/talos.json index 77f292d4b9c6..28a2d5275a0c 100644 --- a/testing/talos/talos.json +++ b/testing/talos/talos.json @@ -1,11 +1,11 @@ { "talos.zip": { - "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.0987e4cbd219.zip", + "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.635c822fd27e.zip", "path": "" }, "global": { "talos_repo": "http://hg.mozilla.org/build/talos", - "talos_revision": "0987e4cbd219" + "talos_revision": "635c822fd27e" }, "suites": { "chromez": { From b14289762c18428f9bd80ae7f09890d563d95de1 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 19 Nov 2013 12:32:33 -0800 Subject: [PATCH 110/268] Bug 940629 - Root StackShape across getChildPropertyOnDictionary calls, r=bhackett --HG-- extra : rebase_source : 57b54ad4f448107a323cf2810eb0231f5e1a1513 --- js/src/vm/Shape.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 6b2313b74623..a86e483727de 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -393,6 +393,7 @@ JSObject::getChildPropertyOnDictionary(ThreadSafeContext *cx, JS::HandleObject o JSObject::getChildProperty(ExclusiveContext *cx, HandleObject obj, HandleShape parent, StackShape &child) { + StackShape::AutoRooter childRoot(cx, &child); RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, child)); if (!shape) { @@ -412,6 +413,7 @@ JSObject::getChildProperty(ExclusiveContext *cx, JSObject::lookupChildProperty(ThreadSafeContext *cx, HandleObject obj, HandleShape parent, StackShape &child) { + StackShape::AutoRooter childRoot(cx, &child); JS_ASSERT(cx->isThreadLocal(obj)); RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, child)); From d0c6d79dcb24d068ca39f03a11d59d97f6324994 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Mon, 18 Nov 2013 14:50:14 -0800 Subject: [PATCH 111/268] Bug 939472 - Remove buffer from multiview list when neutered, r=billm --HG-- extra : rebase_source : 0f010d15b90486f3b16c540a5eaf9a237d3c563b --- js/src/vm/TypedArrayObject.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index e67cce905ac0..7977ad388844 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -335,7 +335,9 @@ bool ArrayBufferObject::neuterViews(JSContext *cx) { ArrayBufferViewObject *view; + size_t numViews = 0; for (view = GetViewList(this); view; view = view->nextView()) { + numViews++; view->neuter(); // Notify compiled jit code that the base pointer has moved. @@ -349,6 +351,25 @@ ArrayBufferObject::neuterViews(JSContext *cx) return false; } + // Remove buffer from the list of buffers with > 1 view. + if (numViews > 1 && GetViewList(this)->bufferLink() != UNSET_BUFFER_LINK) { + ArrayBufferObject *prev = compartment()->gcLiveArrayBuffers; + if (prev == this) { + compartment()->gcLiveArrayBuffers = GetViewList(prev)->bufferLink(); + } else { + for (ArrayBufferObject *buf = GetViewList(prev)->bufferLink(); + buf; + buf = GetViewList(buf)->bufferLink()) + { + if (buf == this) { + GetViewList(prev)->setBufferLink(GetViewList(buf)->bufferLink()); + break; + } + prev = buf; + } + } + } + return true; } From 6a91947708822f0dcb1684c06cb85479320ef99a Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 19 Nov 2013 23:03:32 -0800 Subject: [PATCH 112/268] Bug 940779 - Restrict the scope of a MessageEventInit so it cannot be live across a GC call, r=bent --HG-- extra : rebase_source : 2db09dc1eaab090b94f210bd2478be8d45c976a2 --- dom/workers/WorkerPrivate.cpp | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 33f945724630..af3c3a1bed18 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -5259,16 +5259,23 @@ WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial) return false; } - MessageEventInit init; - init.mBubbles = false; - init.mCancelable = false; - init.mSource = &jsPort.toObject(); + nsRefPtr event; + { + // Bug 940779 - MessageEventInit contains unrooted JS objects, and + // ~nsRefPtr can GC, so make sure 'init' is no longer live before ~nsRefPtr + // runs (or the nsRefPtr is even created) to avoid a rooting hazard. Note + // that 'init' is live until its destructor runs, not just until its final + // use. + MessageEventInit init; + init.mBubbles = false; + init.mCancelable = false; + init.mSource = &jsPort.toObject(); - ErrorResult rv; - - nsRefPtr event = - nsDOMMessageEvent::Constructor(globalObject, aCx, - NS_LITERAL_STRING("connect"), init, rv); + ErrorResult rv; + event = nsDOMMessageEvent::Constructor(globalObject, aCx, + NS_LITERAL_STRING("connect"), + init, rv); + } event->SetTrusted(true); From 2a7a17ae2a9edb2461d10e37cb60bae30aabb248 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 19 Nov 2013 15:27:00 -0800 Subject: [PATCH 113/268] Bug 940724 - Move XMLHttpRequest off of the stack to silence analysis, r=bent --HG-- extra : rebase_source : 591b96238eddbeb88ef3f1df3728fc5d02b9229a --- dom/workers/XMLHttpRequest.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 36308377817a..2265be93af2a 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -682,19 +682,19 @@ public: } } - XMLHttpRequest::StateData state; - StateDataAutoRooter rooter(aCx, &state); + nsAutoPtr state(new XMLHttpRequest::StateData()); + StateDataAutoRooter rooter(aCx, state); - state.mResponseTextResult = mResponseTextResult; - state.mResponseText = mResponseText; + state->mResponseTextResult = mResponseTextResult; + state->mResponseText = mResponseText; if (NS_SUCCEEDED(mResponseTextResult)) { MOZ_ASSERT(JSVAL_IS_VOID(mResponse) || JSVAL_IS_NULL(mResponse)); - state.mResponseResult = mResponseTextResult; - state.mResponse = mResponse; + state->mResponseResult = mResponseTextResult; + state->mResponse = mResponse; } else { - state.mResponseResult = mResponseResult; + state->mResponseResult = mResponseResult; if (NS_SUCCEEDED(mResponseResult)) { if (mResponseBuffer.data()) { @@ -716,23 +716,23 @@ public: return false; } - state.mResponse = response; + state->mResponse = response; } else { - state.mResponse = mResponse; + state->mResponse = mResponse; } } } - state.mStatusResult = mStatusResult; - state.mStatus = mStatus; + state->mStatusResult = mStatusResult; + state->mStatus = mStatus; - state.mStatusText = mStatusText; + state->mStatusText = mStatusText; - state.mReadyState = mReadyState; + state->mReadyState = mReadyState; XMLHttpRequest* xhr = mProxy->mXMLHttpRequestPrivate; - xhr->UpdateState(state); + xhr->UpdateState(*state); if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) { return true; From 376cffac55cb982e16eac15d620dd272a3e61306 Mon Sep 17 00:00:00 2001 From: Steve Fink Date: Tue, 19 Nov 2013 23:22:54 -0800 Subject: [PATCH 114/268] Bug 940765 - pref_HashTableLookup cannot GC, r=terrence DONTBUILD because this only affects the analysis, and that'll get rebuilt soon enough --- js/src/devtools/rootAnalysis/annotations.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index 45a7e0473603..53ff34a2de77 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -160,6 +160,9 @@ var ignoreFunctions = { // FIXME! "NS_DebugBreak": true, + // Bug 940765 - fetching preferences should not GC + "PrefHashEntry* pref_HashTableLookup(void*)": true, + // These are a little overzealous -- these destructors *can* GC if they end // up wrapping a pending exception. See bug 898815 for the heavyweight fix. "void js::AutoCompartment::~AutoCompartment(int32)" : true, From e8f47db8f471ff5a51dd577dbab633c96ebc1fc8 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 19 Nov 2013 22:53:36 +0000 Subject: [PATCH 115/268] Bug 935136 - Remove the now unnecessary UnbarrieredMutableValueOperations r=terrence --- js/public/Value.h | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/js/public/Value.h b/js/public/Value.h index 0beabd8fff3e..dc8225b6dfd9 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1520,7 +1520,6 @@ template <> struct GCMethods #endif }; -template class UnbarrieredMutableValueOperations; template class MutableValueOperations; /* @@ -1532,7 +1531,6 @@ template class MutableValueOperations; template class ValueOperations { - friend class UnbarrieredMutableValueOperations; friend class MutableValueOperations; const JS::Value * value() const { return static_cast(this)->extract(); } @@ -1573,16 +1571,14 @@ class ValueOperations }; /* - * A class designed for CRTP use in implementing the mutating parts of the Value - * interface in Value-like classes that don't need post barriers. Outer must be - * a class inheriting UnbarrieredMutableValueOperations with visible - * extractMutable() and extract() methods returning the const Value* and Value* - * abstracted by Outer. + * A class designed for CRTP use in implementing all the mutating parts of the + * Value interface in Value-like classes. Outer must be a class inheriting + * MutableValueOperations with visible extractMutable() and extract() + * methods returning the const Value* and Value* abstracted by Outer. */ template -class UnbarrieredMutableValueOperations : public ValueOperations +class MutableValueOperations : public ValueOperations { - friend class MutableValueOperations; JS::Value * value() { return static_cast(this)->extractMutable(); } public: @@ -1595,18 +1591,6 @@ class UnbarrieredMutableValueOperations : public ValueOperations void setMagic(JSWhyMagic why) { value()->setMagic(why); } bool setNumber(uint32_t ui) { return value()->setNumber(ui); } bool setNumber(double d) { return value()->setNumber(d); } -}; - -/* - * A class designed for CRTP use in implementing all the mutating parts of the - * Value interface in Value-like classes. Outer must be a class inheriting - * MutableValueOperations with visible extractMutable() and extract() - * methods returning the const Value* and Value* abstracted by Outer. - */ -template -class MutableValueOperations : public UnbarrieredMutableValueOperations -{ - public: void setString(JSString *str) { this->value()->setString(str); } void setString(const JS::Anchor &str) { this->value()->setString(str); } void setObject(JSObject &obj) { this->value()->setObject(obj); } @@ -1696,7 +1680,6 @@ class MutableHandleBase : public MutableValueOperations*>(this)->address(); } - friend class UnbarrieredMutableValueOperations >; friend class MutableValueOperations >; JS::Value * extractMutable() { return static_cast*>(this)->address(); @@ -1715,7 +1698,6 @@ class RootedBase : public MutableValueOperations*>(this)->address(); } - friend class UnbarrieredMutableValueOperations >; friend class MutableValueOperations >; JS::Value * extractMutable() { return static_cast*>(this)->address(); From a09f80631cadd75b66e2e7279a39b94b4bb3af91 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 116/268] Bug 940505 - Fix rooting hazard in JSObject2JSObjectMap::Add() r=bholley --- js/xpconnect/src/XPCMaps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h index 77bb18f3f947..0cc7c358eaea 100644 --- a/js/xpconnect/src/XPCMaps.h +++ b/js/xpconnect/src/XPCMaps.h @@ -646,7 +646,7 @@ public: return p->value; if (!mTable.add(p, key, value)) return nullptr; - MOZ_ASSERT(xpc::GetObjectScope(key)->mWaiverWrapperMap == this); + MOZ_ASSERT(xpc::GetCompartmentPrivate(key)->scope->mWaiverWrapperMap == this); JS_StoreObjectPostBarrierCallback(cx, KeyMarkCallback, key, this); return value; } From e37996118d08a5ca371bda58af23e895f13ece8c Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 117/268] Bug 940692 - Fix rooting hazard in CheckForOutdatedParent() r=smaug --- content/base/src/nsINode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/base/src/nsINode.cpp b/content/base/src/nsINode.cpp index 0586b02146e4..76a766869d30 100644 --- a/content/base/src/nsINode.cpp +++ b/content/base/src/nsINode.cpp @@ -1331,15 +1331,15 @@ AdoptNodeIntoOwnerDoc(nsINode *aParent, nsINode *aNode) static nsresult CheckForOutdatedParent(nsINode* aParent, nsINode* aNode) { - if (JSObject* existingObj = aNode->GetWrapper()) { + if (JSObject* existingObjUnrooted = aNode->GetWrapper()) { + AutoJSContext cx; + JS::Rooted existingObj(cx, existingObjUnrooted); nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject(); MOZ_ASSERT(global); if (js::GetGlobalForObjectCrossCompartment(existingObj) != global->GetGlobalJSObject()) { - AutoJSContext cx; - JS::Rooted rooted(cx, existingObj); - nsresult rv = ReparentWrapper(cx, rooted); + nsresult rv = ReparentWrapper(cx, existingObj); NS_ENSURE_SUCCESS(rv, rv); } } From 4d65d888cb3283b1ddaf85c9ae01efa934eb9647 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 118/268] Bug 940639 - Fix rooting hazard in nsXPCComponents_Utils::(Un)blockScriptForGlobal() r=bholley --- js/xpconnect/src/XPCComponents.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 16f0aaf52bcb..59616b7b004a 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3381,8 +3381,8 @@ nsXPCComponents_Utils::BlockScriptForGlobal(const JS::Value &globalArg, JSContext *cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); - JSObject *global = UncheckedUnwrap(&globalArg.toObject(), - /* stopAtOuter = */ false); + RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), + /* stopAtOuter = */ false)); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) { JS_ReportError(cx, "Script may not be disabled for system globals"); @@ -3397,8 +3397,8 @@ nsXPCComponents_Utils::UnblockScriptForGlobal(const JS::Value &globalArg, JSContext *cx) { NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG); - JSObject *global = UncheckedUnwrap(&globalArg.toObject(), - /* stopAtOuter = */ false); + RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(), + /* stopAtOuter = */ false)); NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG); if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) { JS_ReportError(cx, "Script may not be disabled for system globals"); From dd160d493c53f9b0909c4c24fdb8dc352507360d Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 119/268] Bug 940727 - Fix rooting hazard in DOMProxyHandler::GetAndClearExpandoObject() r=bholley --- dom/bindings/DOMJSProxyHandler.cpp | 5 ++++- js/xpconnect/src/XPCJSRuntime.cpp | 14 ++++++++++++++ js/xpconnect/src/xpcprivate.h | 3 +++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index edcf55a9b584..ca4189f069d5 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -80,7 +80,10 @@ DOMProxyHandler::GetAndClearExpandoObject(JSObject* obj) if (v.isObject()) { js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, UndefinedValue()); - xpc::GetObjectScope(obj)->RemoveDOMExpandoObject(obj); + XPCWrappedNativeScope* scope = xpc::MaybeGetObjectScope(obj); + if (scope) { + scope->RemoveDOMExpandoObject(obj); + } } else { js::ExpandoAndGeneration* expandoAndGeneration = static_cast(v.toPrivate()); diff --git a/js/xpconnect/src/XPCJSRuntime.cpp b/js/xpconnect/src/XPCJSRuntime.cpp index 1cc8a34213c3..64690a415618 100644 --- a/js/xpconnect/src/XPCJSRuntime.cpp +++ b/js/xpconnect/src/XPCJSRuntime.cpp @@ -385,6 +385,20 @@ EnsureCompartmentPrivate(JSCompartment *c) return priv; } +XPCWrappedNativeScope* +MaybeGetObjectScope(JSObject *obj) +{ + MOZ_ASSERT(obj); + JSCompartment *compartment = js::GetObjectCompartment(obj); + + MOZ_ASSERT(compartment); + CompartmentPrivate *priv = GetCompartmentPrivate(compartment); + if (!priv) + return nullptr; + + return priv->scope; +} + static bool PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal) { diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 4985bc16ac57..d0cc03c42b21 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3786,6 +3786,9 @@ GetObjectScope(JSObject *obj) return EnsureCompartmentPrivate(obj)->scope; } +// This returns null if a scope doesn't already exist. +XPCWrappedNativeScope* MaybeGetObjectScope(JSObject *obj); + extern bool gDebugMode; extern bool gDesiredDebugMode; From ad638e6d4aef520cc4d9e8755dd89d4bc7216537 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 120/268] Bug 940754 - Fix rooting hazard in WorkerPrivateParent::WrapObject() r=bent --- dom/workers/WorkerPrivate.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index af3c3a1bed18..f4dd03f2bdbc 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -2159,7 +2159,8 @@ WorkerPrivateParent::WrapObject(JSContext* aCx, AssertIsOnParentThread(); - JSObject* obj = WorkerBinding::Wrap(aCx, aScope, ParentAsWorkerPrivate()); + JS::Rooted obj(aCx, WorkerBinding::Wrap(aCx, aScope, + ParentAsWorkerPrivate())); if (mRooted) { PreserveWrapper(this); From dbf205582ef417bd8c1102d9f8f8ec9e00d49046 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Tue, 19 Nov 2013 22:53:36 +0000 Subject: [PATCH 121/268] Bug 934421 - Postbarrier the keys of the plugin wrapper table r=terrence r=jschoenick --- dom/plugins/base/nsJSNPRuntime.cpp | 192 +++++++++++++---------------- dom/plugins/base/nsJSNPRuntime.h | 16 ++- 2 files changed, 96 insertions(+), 112 deletions(-) diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 53b97e9a98f8..d602e91f9974 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -23,8 +23,10 @@ #include "prmem.h" #include "nsIContent.h" #include "nsPluginInstanceOwner.h" -#include "mozilla/HashFunctions.h" #include "nsWrapperCacheInlines.h" +#include "js/HashTable.h" +#include "mozilla/HashFunctions.h" + #define NPRUNTIME_JSCLASS_NAME "NPObject JS wrapper class" @@ -35,6 +37,21 @@ using namespace mozilla; using mozilla::plugins::PluginScriptableObjectParent; using mozilla::plugins::ParentNPObject; +struct JSObjWrapperHasher : public js::DefaultHasher +{ + typedef nsJSObjWrapperKey Key; + typedef Key Lookup; + + static uint32_t hash(const Lookup &l) { + return HashGeneric(l.mJSObj, l.mNpp); + } + + static void rekey(Key &k, const Key& newKey) { + MOZ_ASSERT(k.mNpp == newKey.mNpp); + k.mJSObj = newKey.mJSObj; + } +}; + // Hash of JSObject wrappers that wraps JSObjects as NPObjects. There // will be one wrapper per JSObject per plugin instance, i.e. if two // plugins access the JSObject x, two wrappers for x will be @@ -42,7 +59,11 @@ using mozilla::plugins::ParentNPObject; // when a plugin is torn down in case there's a leak in the plugin (we // don't want to leak the world just because a plugin leaks an // NPObject). -static PLDHashTable sJSObjWrappers; +typedef js::HashMap JSObjWrapperTable; +static JSObjWrapperTable sJSObjWrappers; // Hash of NPObject wrappers that wrap NPObjects as JSObjects. static PLDHashTable sNPObjWrappers; @@ -237,18 +258,16 @@ OnWrapperDestroyed() NS_ASSERTION(sWrapperCount, "Whaaa, unbalanced created/destroyed calls!"); if (--sWrapperCount == 0) { - if (sJSObjWrappers.ops) { - NS_ASSERTION(sJSObjWrappers.entryCount == 0, "Uh, hash not empty?"); + if (sJSObjWrappers.initialized()) { + MOZ_ASSERT(sJSObjWrappers.count() == 0); // No more wrappers, and our hash was initialized. Finish the // hash to prevent leaking it. - PL_DHashTableFinish(&sJSObjWrappers); - - sJSObjWrappers.ops = nullptr; + sJSObjWrappers.finish(); } if (sNPObjWrappers.ops) { - NS_ASSERTION(sNPObjWrappers.entryCount == 0, "Uh, hash not empty?"); + MOZ_ASSERT(sNPObjWrappers.entryCount == 0); // No more wrappers, and our hash was initialized. Finish the // hash to prevent leaking it. @@ -480,9 +499,8 @@ ReportExceptionIfPending(JSContext *cx) return false; } - nsJSObjWrapper::nsJSObjWrapper(NPP npp) - : nsJSObjWrapperKey(nullptr, npp) + : mNpp(npp) { MOZ_COUNT_CTOR(nsJSObjWrapper); OnWrapperCreated(); @@ -498,6 +516,15 @@ nsJSObjWrapper::~nsJSObjWrapper() OnWrapperDestroyed(); } +void +nsJSObjWrapper::ClearJSObject() { + // Unroot the object's JSObject + JS_RemoveObjectRootRT(sJSRuntime, &mJSObj); + + // Forget our reference to the JSObject. + mJSObj = nullptr; +} + // static NPObject * nsJSObjWrapper::NP_Allocate(NPP npp, NPClass *aClass) @@ -523,18 +550,13 @@ nsJSObjWrapper::NP_Invalidate(NPObject *npobj) nsJSObjWrapper *jsnpobj = (nsJSObjWrapper *)npobj; if (jsnpobj && jsnpobj->mJSObj) { - // Unroot the object's JSObject - JS_RemoveObjectRootRT(sJSRuntime, &jsnpobj->mJSObj); - if (sJSObjWrappers.ops) { - // Remove the wrapper from the hash + // Remove the wrapper from the hash + MOZ_ASSERT(sJSObjWrappers.initialized()); + nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp); + sJSObjWrappers.remove(key); - nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp); - PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_REMOVE); - } - - // Forget our reference to the JSObject. - jsnpobj->mJSObj = nullptr; + jsnpobj->ClearJSObject(); } } @@ -915,34 +937,23 @@ nsJSObjWrapper::NP_Construct(NPObject *npobj, const NPVariant *args, } -class JSObjWrapperHashEntry : public PLDHashEntryHdr -{ -public: - nsJSObjWrapper *mJSObjWrapper; -}; - -static PLDHashNumber -JSObjWrapperHash(PLDHashTable *table, const void *key) -{ - const nsJSObjWrapperKey *e = static_cast(key); - return HashGeneric(e->mJSObj, e->mNpp); +/* + * This function is called during minor GCs for each key in the sJSObjWrappers + * table that has been moved. + */ +static void +JSObjWrapperKeyMarkCallback(JSTracer *trc, void *key, void *data) { + JSObject *obj = static_cast(key); + nsJSObjWrapper* wrapper = static_cast(data); + JSObject *prior = obj; + JS_CallObjectTracer(trc, &obj, "sJSObjWrappers key object"); + NPP npp = wrapper->mNpp; + nsJSObjWrapperKey oldKey(prior, npp); + nsJSObjWrapperKey newKey(obj, npp); + sJSObjWrappers.rekeyIfMoved(oldKey, newKey); } -static bool -JSObjWrapperHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, - const void *key) -{ - const nsJSObjWrapperKey *objWrapperKey = - static_cast(key); - const JSObjWrapperHashEntry *e = - static_cast(entry); - - return (e->mJSObjWrapper->mJSObj == objWrapperKey->mJSObj && - e->mJSObjWrapper->mNpp == objWrapperKey->mNpp); -} - - // Look up or create an NPObject that wraps the JSObject obj. // static @@ -990,22 +1001,9 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) return _retainobject(npobj); } - if (!sJSObjWrappers.ops) { + if (!sJSObjWrappers.initialized()) { // No hash yet (or any more), initialize it. - - static const PLDHashTableOps ops = - { - PL_DHashAllocTable, - PL_DHashFreeTable, - JSObjWrapperHash, - JSObjWrapperHashMatchEntry, - PL_DHashMoveEntryStub, - PL_DHashClearEntryStub, - PL_DHashFinalizeStub - }; - - if (!PL_DHashTableInit(&sJSObjWrappers, &ops, nullptr, - sizeof(JSObjWrapperHashEntry), 16)) { + if (!sJSObjWrappers.init(16)) { NS_ERROR("Error initializing PLDHashTable!"); return nullptr; @@ -1014,18 +1012,13 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) nsJSObjWrapperKey key(obj, npp); - JSObjWrapperHashEntry *entry = static_cast - (PL_DHashTableOperate(&sJSObjWrappers, &key, PL_DHASH_ADD)); + JSObjWrapperTable::AddPtr p = sJSObjWrappers.lookupForAdd(key); - if (!entry) { - // Out of memory. - return nullptr; - } - - if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObjWrapper) { + if (p/* && p->value*/) { + MOZ_ASSERT(p->value); // Found a live nsJSObjWrapper, return it. - return _retainobject(entry->mJSObjWrapper); + return _retainobject(p->value); } // No existing nsJSObjWrapper, create one. @@ -1034,16 +1027,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) (nsJSObjWrapper *)_createobject(npp, &sJSObjWrapperNPClass); if (!wrapper) { - // OOM? Remove the stale entry from the hash. - - PL_DHashTableRawRemove(&sJSObjWrappers, entry); - + // Out of memory, entry not yet added to table. return nullptr; } wrapper->mJSObj = obj; - entry->mJSObjWrapper = wrapper; + if (!sJSObjWrappers.add(p, key, wrapper)) { + // Out of memory, free the wrapper we created. + _releaseobject(wrapper); + return nullptr; + } NS_ASSERTION(wrapper->mNpp == npp, "nsJSObjWrapper::mNpp not initialized!"); @@ -1052,13 +1046,15 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj) if (!::JS_AddNamedObjectRoot(cx, &wrapper->mJSObj, "nsJSObjWrapper::mJSObject")) { NS_ERROR("Failed to root JSObject!"); + sJSObjWrappers.remove(key); _releaseobject(wrapper); - PL_DHashTableRawRemove(&sJSObjWrappers, entry); - return nullptr; } + // Add postbarrier for the hashtable key + JS_StoreObjectPostBarrierCallback(cx, JSObjWrapperKeyMarkCallback, obj, wrapper); + return wrapper; } @@ -1812,35 +1808,6 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj) } -// PLDHashTable enumeration callbacks for destruction code. -static PLDHashOperator -JSObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, - uint32_t number, void *arg) -{ - JSObjWrapperHashEntry *entry = (JSObjWrapperHashEntry *)hdr; - - nsJSObjWrapper *npobj = entry->mJSObjWrapper; - - if (npobj->mNpp == arg) { - // Prevent invalidate() and _releaseobject() from touching the hash - // we're enumerating. - const PLDHashTableOps *ops = table->ops; - table->ops = nullptr; - - if (npobj->_class && npobj->_class->invalidate) { - npobj->_class->invalidate(npobj); - } - - _releaseobject(npobj); - - table->ops = ops; - - return PL_DHASH_REMOVE; - } - - return PL_DHASH_NEXT; -} - // Struct for passing an NPP and a JSContext to // NPObjWrapperPluginDestroyedCallback struct NppAndCx @@ -1888,7 +1855,7 @@ NPObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, ::JS_SetPrivate(entry->mJSObj, nullptr); - table->ops = ops; + table->ops = ops; if (sDelayedReleases && sDelayedReleases->RemoveElement(npobj)) { OnWrapperDestroyed(); @@ -1904,9 +1871,16 @@ NPObjWrapperPluginDestroyedCallback(PLDHashTable *table, PLDHashEntryHdr *hdr, void nsJSNPRuntime::OnPluginDestroy(NPP npp) { - if (sJSObjWrappers.ops) { - PL_DHashTableEnumerate(&sJSObjWrappers, - JSObjWrapperPluginDestroyedCallback, npp); + if (sJSObjWrappers.initialized()) { + for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) { + nsJSObjWrapper *npobj = e.front().value; + MOZ_ASSERT(npobj->_class == &nsJSObjWrapper::sJSObjWrapperNPClass); + if (npobj->mNpp == npp) { + npobj->ClearJSObject(); + _releaseobject(npobj); + e.removeFront(); + } + } } // Use the safe JSContext here as we're not always able to find the diff --git a/dom/plugins/base/nsJSNPRuntime.h b/dom/plugins/base/nsJSNPRuntime.h index ba20f30c25b7..30869dbbdcac 100644 --- a/dom/plugins/base/nsJSNPRuntime.h +++ b/dom/plugins/base/nsJSNPRuntime.h @@ -25,20 +25,30 @@ public: { } - JSObject *mJSObj; + bool operator==(const nsJSObjWrapperKey& other) const { + return mJSObj == other.mJSObj && mNpp == other.mNpp; + } + bool operator!=(const nsJSObjWrapperKey& other) const { + return !(*this == other); + } + JSObject * mJSObj; const NPP mNpp; }; extern const JSClass sNPObjectJSWrapperClass; -class nsJSObjWrapper : public NPObject, - public nsJSObjWrapperKey +class nsJSObjWrapper : public NPObject { public: + JSObject *mJSObj; /* Added as a GC root. */ + const NPP mNpp; + static NPObject *GetNewOrUsed(NPP npp, JSContext *cx, JS::Handle obj); + void ClearJSObject(); + protected: nsJSObjWrapper(NPP npp); ~nsJSObjWrapper(); From d31039039bab074a9844499fd3e0635bbb997068 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 20 Nov 2013 15:37:30 +0000 Subject: [PATCH 122/268] Bug 939476 - Only use separate GC stats phase for markDelayedChildren() in mark phase r=billm --- js/src/gc/Statistics.cpp | 1 - js/src/gc/Statistics.h | 25 ++++++++++++++++++++++++- js/src/jsgc.cpp | 17 ++++++++++------- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 7fa0093bea84..7744b61d53f5 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -281,7 +281,6 @@ static const PhaseInfo phases[] = { { PHASE_SWEEP, "Sweep", PHASE_NO_PARENT }, { PHASE_SWEEP_MARK, "Mark During Sweeping", PHASE_SWEEP }, { PHASE_SWEEP_MARK_TYPES, "Mark Types During Sweeping", PHASE_SWEEP_MARK }, - { PHASE_SWEEP_MARK_DELAYED, "Mark Delayed During Sweeping", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_INCOMING_BLACK, "Mark Incoming Black Pointers", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_WEAK, "Mark Weak", PHASE_SWEEP_MARK }, { PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK }, diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 301292fcf836..3240fd238f53 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -33,7 +33,6 @@ enum Phase { PHASE_SWEEP, PHASE_SWEEP_MARK, PHASE_SWEEP_MARK_TYPES, - PHASE_SWEEP_MARK_DELAYED, PHASE_SWEEP_MARK_INCOMING_BLACK, PHASE_SWEEP_MARK_WEAK, PHASE_SWEEP_MARK_INCOMING_GRAY, @@ -207,6 +206,30 @@ struct AutoPhase MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER }; +struct MaybeAutoPhase +{ + MaybeAutoPhase(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) + : stats(nullptr) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + } + void construct(Statistics &statsArg, Phase phaseArg) + { + JS_ASSERT(!stats); + stats = &statsArg; + phase = phaseArg; + stats->beginPhase(phase); + } + ~MaybeAutoPhase() { + if (stats) + stats->endPhase(phase); + } + + Statistics *stats; + Phase phase; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + struct AutoSCC { AutoSCC(Statistics &stats, unsigned scc diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 00988b1408e1..d7b80e5730cc 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1800,10 +1800,9 @@ GCMarker::markDelayedChildren(ArenaHeader *aheader) bool GCMarker::markDelayedChildren(SliceBudget &budget) { - gcstats::Phase phase = runtime->gcIncrementalState == MARK - ? gcstats::PHASE_MARK_DELAYED - : gcstats::PHASE_SWEEP_MARK_DELAYED; - gcstats::AutoPhase ap(runtime->gcStats, phase); + gcstats::MaybeAutoPhase ap; + if (runtime->gcIncrementalState == MARK) + ap.construct(runtime->gcStats, gcstats::PHASE_MARK_DELAYED); JS_ASSERT(unmarkedArenaStackTop); do { @@ -3177,10 +3176,14 @@ js::gc::MarkingValidator::nonIncrementalMark() MarkRuntime(gcmarker, true); } - SliceBudget budget; - runtime->gcIncrementalState = MARK; - runtime->gcMarker.drainMarkStack(budget); + { + gcstats::AutoPhase ap1(runtime->gcStats, gcstats::PHASE_MARK); + SliceBudget budget; + runtime->gcIncrementalState = MARK; + runtime->gcMarker.drainMarkStack(budget); + } + runtime->gcIncrementalState = SWEEP; { gcstats::AutoPhase ap(runtime->gcStats, gcstats::PHASE_SWEEP); MarkAllWeakReferences(runtime, gcstats::PHASE_SWEEP_MARK_WEAK); From 51a40576c1e72012097b8b5becc845983d635ded Mon Sep 17 00:00:00 2001 From: Alexander Surkov Date: Wed, 20 Nov 2013 13:24:30 -0500 Subject: [PATCH 123/268] Bug 926812 - State change event not fired when both disabled and aria-disabled are toggled, r=tbsaunde --- accessible/src/generic/Accessible.h | 10 +++++ accessible/src/generic/DocAccessible.cpp | 25 +++++++---- accessible/src/generic/DocAccessible.h | 12 +++-- accessible/tests/mochitest/events.js | 7 ++- .../mochitest/events/test_statechange.html | 44 ++++++++++++++++++- 5 files changed, 83 insertions(+), 15 deletions(-) diff --git a/accessible/src/generic/Accessible.h b/accessible/src/generic/Accessible.h index 61468f9abfdd..279745603305 100644 --- a/accessible/src/generic/Accessible.h +++ b/accessible/src/generic/Accessible.h @@ -244,6 +244,16 @@ public: return state; } + /** + * Return if accessible is unavailable. + */ + bool Unavailable() const + { + uint64_t state = NativelyUnavailable() ? states::UNAVAILABLE : 0; + ApplyARIAState(&state); + return state & states::UNAVAILABLE; + } + /** * Return the states of accessible, not taking into account ARIA states. * Use State() to get complete set of states. diff --git a/accessible/src/generic/DocAccessible.cpp b/accessible/src/generic/DocAccessible.cpp index 909c41ab1ba7..ad16ceef5bde 100644 --- a/accessible/src/generic/DocAccessible.cpp +++ b/accessible/src/generic/DocAccessible.cpp @@ -870,7 +870,12 @@ DocAccessible::AttributeWillChange(nsIDocument* aDocument, aAttribute == nsGkAtoms::aria_pressed) { mARIAAttrOldValue = (aModType != nsIDOMMutationEvent::ADDITION) ? nsAccUtils::GetARIAToken(aElement, aAttribute) : nullptr; + return; } + + if (aAttribute == nsGkAtoms::aria_disabled || + aAttribute == nsGkAtoms::disabled) + mStateBitWasOn = accessible->Unavailable(); } void @@ -938,22 +943,24 @@ DocAccessible::AttributeChangedImpl(Accessible* aAccessible, // Universal boolean properties that don't require a role. Fire the state // change when disabled or aria-disabled attribute is set. + // Note. Checking the XUL or HTML namespace would not seem to gain us + // anything, because disabled attribute really is going to mean the same + // thing in any namespace. + // Note. We use the attribute instead of the disabled state bit because + // ARIA's aria-disabled does not affect the disabled state bit. if (aAttribute == nsGkAtoms::disabled || aAttribute == nsGkAtoms::aria_disabled) { - - // Note. Checking the XUL or HTML namespace would not seem to gain us - // anything, because disabled attribute really is going to mean the same - // thing in any namespace. - - // Note. We use the attribute instead of the disabled state bit because - // ARIA's aria-disabled does not affect the disabled state bit. + // Do nothing if state wasn't changed (like @aria-disabled was removed but + // @disabled is still presented). + if (aAccessible->Unavailable() == mStateBitWasOn) + return; nsRefPtr enabledChangeEvent = - new AccStateChangeEvent(aAccessible, states::ENABLED); + new AccStateChangeEvent(aAccessible, states::ENABLED, mStateBitWasOn); FireDelayedEvent(enabledChangeEvent); nsRefPtr sensitiveChangeEvent = - new AccStateChangeEvent(aAccessible, states::SENSITIVE); + new AccStateChangeEvent(aAccessible, states::SENSITIVE, mStateBitWasOn); FireDelayedEvent(sensitiveChangeEvent); return; } diff --git a/accessible/src/generic/DocAccessible.h b/accessible/src/generic/DocAccessible.h index 6de2c3d7cc2e..b17737d43077 100644 --- a/accessible/src/generic/DocAccessible.h +++ b/accessible/src/generic/DocAccessible.h @@ -533,10 +533,16 @@ protected: nsCOMPtr mAnchorJumpElm; /** - * Keep the ARIA attribute old value that is initialized by - * AttributeWillChange and used by AttributeChanged notifications. + * A generic state (see items below) before the attribute value was changed. + * @see AttributeWillChange and AttributeChanged notifications. */ - nsIAtom* mARIAAttrOldValue; + union { + // ARIA attribute value + nsIAtom* mARIAAttrOldValue; + + // True if the accessible state bit was on + bool mStateBitWasOn; + }; nsTArray > mChildDocuments; diff --git a/accessible/tests/mochitest/events.js b/accessible/tests/mochitest/events.js index 2676a8187826..525d56d6631d 100644 --- a/accessible/tests/mochitest/events.js +++ b/accessible/tests/mochitest/events.js @@ -1959,7 +1959,12 @@ var gA11yEventObserver = var type = eventTypeToString(event.eventType); var info = "Event type: " + type; - if (event instanceof nsIAccessibleTextChangeEvent) { + if (event instanceof nsIAccessibleStateChangeEvent) { + var stateStr = statesToString(event.isExtraState ? 0 : event.state, + event.isExtraState ? event.state : 0); + info += ", state: " + stateStr + ", is enabled: " + event.isEnabled; + + } else if (event instanceof nsIAccessibleTextChangeEvent) { info += ", start: " + event.start + ", length: " + event.length + ", " + (event.isInserted ? "inserted" : "removed") + " text: " + event.modifiedText; diff --git a/accessible/tests/mochitest/events/test_statechange.html b/accessible/tests/mochitest/events/test_statechange.html index d877f6dd4b86..f4557376b548 100644 --- a/accessible/tests/mochitest/events/test_statechange.html +++ b/accessible/tests/mochitest/events/test_statechange.html @@ -143,18 +143,46 @@ new stateChangeChecker(aState, aIsExtraState, true, getNode(aID)) ]; - this.invoke = function dupeStateChange_invoke() + this.invoke = function oppositeStateChange_invoke() { getNode(aID).setAttribute(aAttr, "false"); getNode(aID).setAttribute(aAttr, "true"); } - this.getID = function dupeStateChange_getID() + this.getID = function oppositeStateChange_getID() { return "opposite state change events"; } } + /** + * Change concomitant ARIA and native attribute at once. + */ + function echoingStateChange(aID, aARIAAttr, aAttr, aValue, + aState, aIsExtraState, aIsEnabled) + { + this.eventSeq = [ + new stateChangeChecker(aState, aIsExtraState, aIsEnabled, getNode(aID)) + ]; + + this.invoke = function echoingStateChange_invoke() + { + if (aValue == null) { + getNode(aID).removeAttribute(aARIAAttr); + getNode(aID).removeAttribute(aAttr); + + } else { + getNode(aID).setAttribute(aARIAAttr, aValue); + getNode(aID).setAttribute(aAttr, aValue); + } + } + + this.getID = function echoingStateChange_getID() + { + return "enchoing ARIA and native attributes change"; + } + } + //////////////////////////////////////////////////////////////////////////// // Do tests @@ -193,6 +221,11 @@ gQueue.push(new oppositeStateChange("div", "aria-busy", STATE_BUSY, false)); + gQueue.push(new echoingStateChange("text1", "aria-disabled", "disabled", "true", + EXT_STATE_ENABLED, true, false)); + gQueue.push(new echoingStateChange("text1", "aria-disabled", "disabled", null, + EXT_STATE_ENABLED, true, true)); + gQueue.invoke(); // Will call SimpleTest.finish(); } @@ -223,6 +256,11 @@ title="Fire statechange event whenever checked state is changed not depending on focused state"> Bug 788389 + + Bug 926812 +

@@ -242,6 +280,8 @@
+ +
From 3bcd5725f405ba25073d1b61e5d88175b8468ff7 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 20 Nov 2013 13:44:05 -0500 Subject: [PATCH 124/268] Backed out changeset 0879fec4cfc3 (bug 896193) for frequent Linux xpcshell failures. CLOSED TREE --- .../components/places/mozIAsyncLivemarks.idl | 20 +- .../components/places/nsLivemarkService.js | 101 +-- .../tests/unit/test_mozIAsyncLivemarks.js | 699 ++++++++---------- 3 files changed, 355 insertions(+), 465 deletions(-) diff --git a/toolkit/components/places/mozIAsyncLivemarks.idl b/toolkit/components/places/mozIAsyncLivemarks.idl index 07f62a34752e..68aae9d104e9 100644 --- a/toolkit/components/places/mozIAsyncLivemarks.idl +++ b/toolkit/components/places/mozIAsyncLivemarks.idl @@ -12,7 +12,7 @@ interface mozILivemark; interface nsINavHistoryResultObserver; -[scriptable, uuid(5B48E5A2-F07A-4E64-A935-C722A3D60B65)] +[scriptable, uuid(1dbf174c-696e-4d9b-af0f-350da50d2249)] interface mozIAsyncLivemarks : nsISupports { /** @@ -24,12 +24,12 @@ interface mozIAsyncLivemarks : nsISupports * @param [optional] aCallback * Invoked when the creation process is done. In case of failure will * receive an error code. - * @return {Promise} + * * @throws NS_ERROR_INVALID_ARG if the supplied information is insufficient * for the creation. */ - jsval addLivemark(in jsval aLivemarkInfo, - [optional] in mozILivemarkCallback aCallback); + void addLivemark(in jsval aLivemarkInfo, + [optional]in mozILivemarkCallback aCallback); /** * Removes an existing livemark. @@ -41,11 +41,10 @@ interface mozIAsyncLivemarks : nsISupports * Invoked when the removal process is done. In case of failure will * receive an error code. * - * @return {Promise} * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid. */ - jsval removeLivemark(in jsval aLivemarkInfo, - [optional] in mozILivemarkCallback aCallback); + void removeLivemark(in jsval aLivemarkInfo, + [optional]in mozILivemarkCallback aCallback); /** * Gets an existing livemark. @@ -53,16 +52,15 @@ interface mozIAsyncLivemarks : nsISupports * @param aLivemarkInfo * mozILivemarkInfo object containing either an id or a guid of the * livemark to retrieve. - * @param [optioanl] aCallback + * @param aCallback * Invoked when the fetching process is done. In case of failure will * receive an error code. * - * @return {Promise} * @throws NS_ERROR_INVALID_ARG if the id/guid is invalid or an invalid * callback is provided. */ - jsval getLivemark(in jsval aLivemarkInfo, - [optional] in mozILivemarkCallback aCallback); + void getLivemark(in jsval aLivemarkInfo, + in mozILivemarkCallback aCallback); /** * Reloads all livemarks if they are expired or if forced to do so. diff --git a/toolkit/components/places/nsLivemarkService.js b/toolkit/components/places/nsLivemarkService.js index 8e913318794c..aca937a8fce6 100644 --- a/toolkit/components/places/nsLivemarkService.js +++ b/toolkit/components/places/nsLivemarkService.js @@ -16,8 +16,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Promise", - "resource://gre/modules/Promise.jsm"); //////////////////////////////////////////////////////////////////////////////// //// Services @@ -215,8 +213,7 @@ LivemarkService.prototype = { // The addition is done synchronously due to the fact importExport service // and JSON backups require that. The notification is async though. // Once bookmarks are async, this may be properly fixed. - let deferred = Promise.defer(); - let addLivemarkEx = null; + let result = Cr.NS_OK; let livemark = null; try { // Disallow adding a livemark inside another livemark. @@ -249,33 +246,18 @@ LivemarkService.prototype = { this._guids[aLivemarkInfo.guid] = livemark.id; } catch (ex) { - addLivemarkEx = ex; + result = ex.result; livemark = null; } finally { - this._onCacheReady(() => { - if (addLivemarkEx) { - if (aLivemarkCallback) { - try { - aLivemarkCallback.onCompletion(addLivemarkEx.result, livemark); - } - catch(ex2) { } - } - deferred.reject(addLivemarkEx); - } - else { - if (aLivemarkCallback) { - try { - aLivemarkCallback.onCompletion(Cr.NS_OK, livemark); - } - catch(ex2) { } - } - deferred.resolve(livemark); - } - }); + if (aLivemarkCallback) { + this._onCacheReady(function LS_addLivemark_ETAT() { + try { + aLivemarkCallback.onCompletion(result, livemark); + } catch(ex2) {} + }, true); + } } - - return deferred.promise; }, removeLivemark: function LS_removeLivemark(aLivemarkInfo, aLivemarkCallback) @@ -296,9 +278,7 @@ LivemarkService.prototype = { if (id in this._guids) { id = this._guids[id]; } - - let deferred = Promise.defer(); - let removeLivemarkEx = null; + let result = Cr.NS_OK; try { if (!(id in this._livemarks)) { throw new Components.Exception("", Cr.NS_ERROR_INVALID_ARG); @@ -306,32 +286,18 @@ LivemarkService.prototype = { this._livemarks[id].remove(); } catch (ex) { - removeLivemarkEx = ex; + result = ex.result; } finally { - this._onCacheReady( () => { - if (removeLivemarkEx) { - if (aLivemarkCallback) { - try { - aLivemarkCallback.onCompletion(removeLivemarkEx.result, null); - } - catch(ex2) { } - } - deferred.reject(removeLivemarkEx); - } - else { - if (aLivemarkCallback) { - try { - aLivemarkCallback.onCompletion(Cr.NS_OK, null); - } - catch(ex2) { } - } - deferred.resolve(); - } - }); + if (aLivemarkCallback) { + // Enqueue the notification, per interface definition. + this._onCacheReady(function LS_removeLivemark_ETAT() { + try { + aLivemarkCallback.onCompletion(result, null); + } catch(ex2) {} + }); + } } - - return deferred.promise; }, _reloaded: [], @@ -360,13 +326,13 @@ LivemarkService.prototype = { return; } - this._onCacheReady( () => { + this._onCacheReady((function LS_reloadAllLivemarks_ETAT() { this._forceUpdate = !!aForceUpdate; this._reloaded = []; // Livemarks reloads happen on a timer, and are delayed for performance // reasons. this._startReloadTimer(); - }); + }).bind(this)); }, getLivemark: function LS_getLivemark(aLivemarkInfo, aLivemarkCallback) @@ -382,31 +348,22 @@ LivemarkService.prototype = { throw Cr.NS_ERROR_INVALID_ARG; } - let deferred = Promise.defer(); - this._onCacheReady( () => { + this._onCacheReady((function LS_getLivemark_ETAT() { // Convert the guid to an id. if (id in this._guids) { id = this._guids[id]; } if (id in this._livemarks) { - if (aLivemarkCallback) { - try { - aLivemarkCallback.onCompletion(Cr.NS_OK, this._livemarks[id]); - } catch (ex) {} - } - deferred.resolve(this._livemarks[id]); + try { + aLivemarkCallback.onCompletion(Cr.NS_OK, this._livemarks[id]); + } catch (ex) {} } else { - if (aLivemarkCallback) { - try { - aLivemarkCallback.onCompletion(Cr.NS_ERROR_INVALID_ARG, null); - } catch (ex) { } - } - deferred.reject(Components.Exception("", Cr.NS_ERROR_INVALID_ARG)); + try { + aLivemarkCallback.onCompletion(Cr.NS_ERROR_INVALID_ARG, null); + } catch (ex) {} } - }); - - return deferred.promise; + }).bind(this)); }, ////////////////////////////////////////////////////////////////////////////// diff --git a/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js b/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js index 429c23bfa109..fab3e2494a8f 100644 --- a/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js +++ b/toolkit/components/places/tests/unit/test_mozIAsyncLivemarks.js @@ -6,181 +6,201 @@ const FEED_URI = NetUtil.newURI("http://feed.rss/"); const SITE_URI = NetUtil.newURI("http://site.org/"); +function run_test() +{ + run_next_test(); +} -add_task(function test_addLivemark_noArguments_throws() +add_test(function test_addLivemark_noArguments_throws() { try { - yield PlacesUtils.livemarks.addLivemark(); + PlacesUtils.livemarks.addLivemark(); do_throw("Invoking addLivemark with no arguments should throw"); } catch (ex) { // The error is actually generated by XPConnect. do_check_eq(ex.result, Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS); } + run_next_test(); }); -add_task(function test_addLivemark_emptyObject_throws() +add_test(function test_addLivemark_emptyObject_throws() { try { - yield PlacesUtils.livemarks.addLivemark({}); + PlacesUtils.livemarks.addLivemark({}); do_throw("Invoking addLivemark with empty object should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_badParentId_throws() +add_test(function test_addLivemark_badParentId_throws() { try { - yield PlacesUtils.livemarks.addLivemark({ parentId: "test" }); + PlacesUtils.livemarks.addLivemark({ parentId: "test" }); do_throw("Invoking addLivemark with a bad parent id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_invalidParentId_throws() +add_test(function test_addLivemark_invalidParentId_throws() { try { - yield PlacesUtils.livemarks.addLivemark({ parentId: -2 }); + PlacesUtils.livemarks.addLivemark({ parentId: -2 }); do_throw("Invoking addLivemark with an invalid parent id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_noIndex_throws() +add_test(function test_addLivemark_noIndex_throws() { try { - yield PlacesUtils.livemarks.addLivemark({ - parentId: PlacesUtils.unfiledBookmarksFolderId }); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId }); do_throw("Invoking addLivemark with no index should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_badIndex_throws() +add_test(function test_addLivemark_badIndex_throws() { try { - yield PlacesUtils.livemarks.addLivemark( - { parentId: PlacesUtils.unfiledBookmarksFolderId - , index: "test" }); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: "test" + }); do_throw("Invoking addLivemark with a bad index should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_invalidIndex_throws() +add_test(function test_addLivemark_invalidIndex_throws() { try { - yield PlacesUtils.livemarks.addLivemark( - { parentId: PlacesUtils.unfiledBookmarksFolderId - , index: -2 - }); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: -2 + }); do_throw("Invoking addLivemark with an invalid index should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_noFeedURI_throws() +add_test(function test_addLivemark_noFeedURI_throws() { try { - yield PlacesUtils.livemarks.addLivemark( - { parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX }); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + }); do_throw("Invoking addLivemark with no feedURI should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_badFeedURI_throws() +add_test(function test_addLivemark_badFeedURI_throws() { try { - yield PlacesUtils.livemarks.addLivemark( - { parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: "test" }); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: "test" + }); do_throw("Invoking addLivemark with a bad feedURI should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_badSiteURI_throws() +add_test(function test_addLivemark_badSiteURI_throws() { try { - yield PlacesUtils.livemarks.addLivemark( - { parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , siteURI: "test" }); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: "test" + }); do_throw("Invoking addLivemark with a bad siteURI should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_badGuid_throws() +add_test(function test_addLivemark_badGuid_throws() { try { - yield PlacesUtils.livemarks.addLivemark( - { parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "123456" }); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "123456" + }); do_throw("Invoking addLivemark with a bad guid should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_addLivemark_badCallback_throws() +add_test(function test_addLivemark_badCallback_throws() { try { - yield PlacesUtils.livemarks.addLivemark( - { parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, "test"); + PlacesUtils.livemarks.addLivemark({ parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, "test"); do_throw("Invoking addLivemark with a bad callback should throw"); } catch (ex) { // The error is actually generated by XPConnect. do_check_eq(ex.result, Cr.NS_ERROR_XPC_BAD_CONVERT_JS); } + run_next_test(); }); -add_task(function test_addLivemark_noCallback_succeeds() +add_test(function test_addLivemark_noCallback_succeeds() { - let onItemAddedCalled = false; PlacesUtils.bookmarks.addObserver({ - __proto__: NavBookmarkObserver.prototype, onItemAdded: function onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI, aTitle) { - onItemAddedCalled = true; PlacesUtils.bookmarks.removeObserver(this); do_check_eq(aParentId, PlacesUtils.unfiledBookmarksFolderId); do_check_eq(aIndex, 0); do_check_eq(aItemType, Ci.nsINavBookmarksService.TYPE_FOLDER); do_check_eq(aTitle, "test"); - } + run_next_test(); + }, + onBeginUpdateBatch: function onBeginUpdateBatch() {}, + onEndUpdateBatch: function onEndUpdateBatch() {}, + onItemRemoved: function onItemRemoved() {}, + onItemChanged: function onItemChanged() {}, + onItemVisited: function onItemVisited() {}, + onItemMoved: function onItemMoved() {}, }, false); - - yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI }); - do_check_true(onItemAddedCalled); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }); }); - -add_task(function test_addLivemark_noSiteURI_callback_succeeds() +add_test(function test_addLivemark_noSiteURI_callback_succeeds() { - let checkLivemark = aLivemark => { + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); do_check_true(aLivemark.id > 0); do_check_valid_places_guid(aLivemark.guid); do_check_eq(aLivemark.title, "test"); @@ -189,28 +209,20 @@ add_task(function test_addLivemark_noSiteURI_callback_succeeds() do_check_eq(aLivemark.lastModified, PlacesUtils.bookmarks.getItemLastModified(aLivemark.id)); do_check_true(aLivemark.feedURI.equals(FEED_URI)); do_check_eq(aLivemark.siteURI, null); - }; - - // The deprecated callback is called before resolving the promise. - let callbackCalled = false; - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_true(Components.isSuccessCode(aStatus)); - checkLivemark(aLivemark); - } ); - do_check_true(callbackCalled); - checkLivemark(livemark); + run_next_test(); + }); }); -add_task(function test_addLivemark_callback_succeeds() +add_test(function test_addLivemark_callback_succeeds() { - let checkLivemark = aLivemark => { + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: SITE_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); do_check_true(aLivemark.id > 0); do_check_valid_places_guid(aLivemark.guid); do_check_eq(aLivemark.title, "test"); @@ -219,351 +231,283 @@ add_task(function test_addLivemark_callback_succeeds() do_check_eq(aLivemark.lastModified, PlacesUtils.bookmarks.getItemLastModified(aLivemark.id)); do_check_true(aLivemark.feedURI.equals(FEED_URI)); do_check_true(aLivemark.siteURI.equals(SITE_URI)); + do_check_true(PlacesUtils.annotations .itemHasAnnotation(aLivemark.id, PlacesUtils.LMANNO_FEEDURI)); do_check_true(PlacesUtils.annotations .itemHasAnnotation(aLivemark.id, PlacesUtils.LMANNO_SITEURI)); - }; - - // The deprecated callback is called before resolving the promise. - let callbackCalled = false; - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , siteURI: SITE_URI - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_true(Components.isSuccessCode(aStatus)); - checkLivemark(aLivemark); - } ); - do_check_true(callbackCalled); - checkLivemark(livemark); + run_next_test(); + }); }); -add_task(function test_addLivemark_bogusid_callback_succeeds() +add_test(function test_addLivemark_bogusid_callback_succeeds() { - let checkLivemark = aLivemark => { + PlacesUtils.livemarks.addLivemark({ id: 100 // Should be ignored. + , title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , siteURI: SITE_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); do_check_true(aLivemark.id > 0); do_check_neq(aLivemark.id, 100); - }; - // The deprecated callback is called before resolving the promise. - let callbackCalled = false; - let livemark = yield PlacesUtils.livemarks.addLivemark( - { id: 100 // Should be ignored. - , title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , siteURI: SITE_URI - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_true(Components.isSuccessCode(aStatus)); - checkLivemark(aLivemark); - } ); - do_check_true(callbackCalled); - checkLivemark(livemark); + run_next_test(); + }); }); -add_task(function test_addLivemark_bogusParent_callback_fails() +add_test(function test_addLivemark_bogusParent_callback_fails() { - // The deprecated callback is called before resolving the promise. - let callbackCalled = false; - try { - yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: 187 - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - } ); - do_throw("Adding a livemark with a bogus parent should fail"); - } - catch(ex) { - do_check_true(callbackCalled); - } + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: 187 + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + }); }); -add_task(function test_addLivemark_intoLivemark_callback_fails() +add_test(function test_addLivemark_intoLivemark_callback_fails() { - // The deprecated callback is called before resolving the promise. - let callbackCalled = false; - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_true(Components.isSuccessCode(aStatus)); - } ); - do_check_true(callbackCalled); - do_check_true(Boolean(livemark)); - - callbackCalled = false; - try { - yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: livemark.id - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - } ); - do_throw("Adding a livemark into a livemark should fail"); - } - catch(ex) { - do_check_true(callbackCalled); - } + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: aLivemark.id + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + }); + }); }); -add_task(function test_addLivemark_forceGuid_callback_succeeds() +add_test(function test_addLivemark_forceGuid_callback_succeeds() { - let checkLivemark = aLivemark => { + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "1234567890AB" + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); do_check_eq(aLivemark.guid, "1234567890AB"); do_check_guid_for_bookmark(aLivemark.id, "1234567890AB"); - }; - // The deprecated callback is called before resolving the promise. - let callbackCalled = false; - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "1234567890AB" - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_true(Components.isSuccessCode(aStatus)); - checkLivemark(aLivemark); - } ); - do_check_true(callbackCalled); - checkLivemark(livemark); + run_next_test(); + }); }); -add_task(function test_addLivemark_lastModified_callback_succeeds() +add_test(function test_addLivemark_lastModified_callback_succeeds() { let now = Date.now() * 1000; - let callbackCalled = false; - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , lastModified: now - }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_true(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark.lastModified, now); - } ); - do_check_true(callbackCalled); - do_check_eq(livemark.lastModified, now); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , lastModified: now + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.lastModified, now); + + run_next_test(); + }); }); -add_task(function test_removeLivemark_emptyObject_throws() +add_test(function test_removeLivemark_emptyObject_throws() { try { - yield PlacesUtils.livemarks.removeLivemark({}); + PlacesUtils.livemarks.removeLivemark({}); do_throw("Invoking removeLivemark with empty object should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_removeLivemark_noValidId_throws() +add_test(function test_removeLivemark_noValidId_throws() { try { - yield PlacesUtils.livemarks.removeLivemark({ id: -10, guid: "test"}); + PlacesUtils.livemarks.removeLivemark({ id: -10, guid: "test"}); do_throw("Invoking removeLivemark with no valid id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_removeLivemark_nonExistent_fails() +add_test(function test_removeLivemark_nonExistent_fails() { - let callbackCalled = false; - try { - yield PlacesUtils.livemarks.removeLivemark( - { id: 1337 }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - } ); - do_throw("Removing a non-existent livemark should fail"); - } - catch(ex) { - do_check_true(callbackCalled); - } + PlacesUtils.livemarks.removeLivemark( + { id: 1337 }, + function (aStatus, aLivemark) { + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + } + ); }); -add_task(function test_removeLivemark_guid_succeeds() +add_test(function test_removeLivemark_guid_succeeds() { - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "234567890ABC" + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "234567890ABC" + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.guid, "234567890ABC"); + // invalid id to check the guid wins. + PlacesUtils.livemarks.removeLivemark( + { id: 789, guid: "234567890ABC" }, + function (aStatus, aRemovedLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(PlacesUtils.bookmarks.getItemIndex(aLivemark.id), -1); + do_check_eq(aRemovedLivemark, null); + run_next_test(); + } + ); }); - - - do_check_eq(livemark.guid, "234567890ABC"); - - yield PlacesUtils.livemarks.removeLivemark({ - id: 789, guid: "234567890ABC" - }); - - do_check_eq(PlacesUtils.bookmarks.getItemIndex(livemark.id), -1); }); -add_task(function test_removeLivemark_id_succeeds() +add_test(function test_removeLivemark_id_succeeds() { - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); + PlacesUtils.livemarks.removeLivemark( + { id: aLivemark.id }, + function (aStatus, aRemovedLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(PlacesUtils.bookmarks.getItemIndex(aLivemark.id), -1); + do_check_eq(aRemovedLivemark, null); + run_next_test(); + } + ); }); - - yield PlacesUtils.livemarks.removeLivemark({ id: livemark.id }); - do_check_eq(PlacesUtils.bookmarks.getItemIndex(livemark.id), -1); }); -add_task(function test_getLivemark_emptyObject_throws() +add_test(function test_getLivemark_emptyObject_throws() { try { - yield PlacesUtils.livemarks.getLivemark({}); + PlacesUtils.livemarks.getLivemark({}, function () {}); do_throw("Invoking getLivemark with empty object should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_getLivemark_noValidId_throws() +add_test(function test_getLivemark_noValidId_throws() { try { - yield PlacesUtils.livemarks.getLivemark({ id: -10, guid: "test"}); + PlacesUtils.livemarks.getLivemark({ id: -10, guid: "test"}, function () {}); do_throw("Invoking getLivemark with no valid id should throw"); } catch (ex) { do_check_eq(ex.result, Cr.NS_ERROR_INVALID_ARG); } + run_next_test(); }); -add_task(function test_getLivemark_nonExistentId_fails() +add_test(function test_getLivemark_nonExistentId_fails() { - let callbackCalled = false; - try { - yield PlacesUtils.livemarks.getLivemark({ id: 1234 }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - } ); - do_throw("getLivemark for a non existent id should fail"); - } - catch(ex) { - do_check_true(callbackCalled); - } + PlacesUtils.livemarks.getLivemark({ id: 1234 }, + function (aStatus, aLivemark){ + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + } + ); }); -add_task(function test_getLivemark_nonExistentGUID_fails() +add_test(function test_getLivemark_nonExistentGUID_fails() { - let callbackCalled = false; - try { - yield PlacesUtils.livemarks.getLivemark({ guid: "34567890ABCD" }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_false(Components.isSuccessCode(aStatus)); - do_check_eq(aLivemark, null); - } ); - do_throw("getLivemark for a non-existent guid should fail"); - } - catch(ex) { - do_check_true(callbackCalled); - } + PlacesUtils.livemarks.getLivemark({ guid: "34567890ABCD" }, + function (aStatus, aLivemark){ + do_check_false(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark, null); + run_next_test(); + } + ); }); -add_task(function test_getLivemark_guid_succeeds() +add_test(function test_getLivemark_guid_succeeds() { - yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - , guid: "34567890ABCD" }); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + , guid: "34567890ABCD" + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); - let checkLivemark = aLivemark => { - do_check_eq(aLivemark.title, "test"); - do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); - do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); - do_check_true(aLivemark.feedURI.equals(FEED_URI)); - do_check_eq(aLivemark.siteURI, null); - do_check_eq(aLivemark.guid, "34567890ABCD"); - }; - - // invalid id to check the guid wins. - let livemark = - yield PlacesUtils.livemarks.getLivemark({ id: 789, guid: "34567890ABCD" }, - (aStatus, aLivemark) => { - callbackCalled = true; + // invalid id to check the guid wins. + PlacesUtils.livemarks.getLivemark({ id: 789, guid: "34567890ABCD" }, + function(aStatus, aLivemark) { do_check_true(Components.isSuccessCode(aStatus)); - checkLivemark(aLivemark) - } ); - - do_check_true(callbackCalled); - checkLivemark(livemark); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_eq(aLivemark.guid, "34567890ABCD"); + run_next_test(); + } + ); + }); }); -add_task(function test_getLivemark_id_succeeds() +add_test(function test_getLivemark_id_succeeds() { - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI - }); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function (aStatus, aLivemark) + { + do_check_true(Components.isSuccessCode(aStatus)); - let checkLivemark = aLivemark => { - do_check_eq(aLivemark.title, "test"); - do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); - do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); - do_check_true(aLivemark.feedURI.equals(FEED_URI)); - do_check_eq(aLivemark.siteURI, null); - do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); - }; - - let callbackCalled = false; - livemark = yield PlacesUtils.livemarks.getLivemark( - { id: livemark.id }, - (aStatus, aLivemark) => { - callbackCalled = true; - do_check_true(Components.isSuccessCode(aStatus)); - checkLivemark(aLivemark); - } ); - - do_check_true(callbackCalled); - checkLivemark(livemark); + // invalid id to check the guid wins. + PlacesUtils.livemarks.getLivemark({ id: aLivemark.id }, + function(aStatus, aLivemark) { + do_check_true(Components.isSuccessCode(aStatus)); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); + run_next_test(); + } + ); + }); }); -add_task(function test_getLivemark_removeItem_contention() +add_test(function test_getLivemark_removeItem_contention() { PlacesUtils.livemarks.addLivemark({ title: "test" , parentId: PlacesUtils.unfiledBookmarksFolderId @@ -578,56 +522,47 @@ add_task(function test_getLivemark_removeItem_contention() }); let id = PlacesUtils.bookmarks.getIdForItemAt(PlacesUtils.unfiledBookmarksFolderId, PlacesUtils.bookmarks.DEFAULT_INDEX); - - let checkLivemark = (aLivemark) => { - do_check_eq(aLivemark.title, "test"); - do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); - do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); - do_check_true(aLivemark.feedURI.equals(FEED_URI)); - do_check_eq(aLivemark.siteURI, null); - do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); - }; - - let callbackCalled = false; - let livemark = yield PlacesUtils.livemarks.getLivemark( + + PlacesUtils.livemarks.getLivemark( { id: id }, - (aStatus, aLivemark) => { - callbackCalled = true; + function(aStatus, aLivemark) { do_check_true(Components.isSuccessCode(aStatus)); - checkLivemark(aLivemark); - } ); - - do_check_true(callbackCalled); - checkLivemark(livemark); + do_check_eq(aLivemark.title, "test"); + do_check_eq(aLivemark.parentId, PlacesUtils.unfiledBookmarksFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + do_check_true(aLivemark.feedURI.equals(FEED_URI)); + do_check_eq(aLivemark.siteURI, null); + do_check_guid_for_bookmark(aLivemark.id, aLivemark.guid); + run_next_test(); + } + ); }); -add_task(function test_title_change() +add_test(function test_title_change() { - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI }); - - PlacesUtils.bookmarks.setItemTitle(livemark.id, "test2"); - do_check_eq(livemark.title, "test2"); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function(aStatus, aLivemark) { + PlacesUtils.bookmarks.setItemTitle(aLivemark.id, "test2"); + do_check_eq(aLivemark.title, "test2"); + run_next_test(); + }); }); -add_task(function test_livemark_move() +add_test(function test_livemark_move() { - let livemark = yield PlacesUtils.livemarks.addLivemark( - { title: "test" - , parentId: PlacesUtils.unfiledBookmarksFolderId - , index: PlacesUtils.bookmarks.DEFAULT_INDEX - , feedURI: FEED_URI } ); - - PlacesUtils.bookmarks.moveItem(livemark.id, - PlacesUtils.toolbarFolderId, - PlacesUtils.bookmarks.DEFAULT_INDEX); - do_check_eq(livemark.parentId, PlacesUtils.toolbarFolderId); - do_check_eq(livemark.index, PlacesUtils.bookmarks.getItemIndex(livemark.id)); + PlacesUtils.livemarks.addLivemark({ title: "test" + , parentId: PlacesUtils.unfiledBookmarksFolderId + , index: PlacesUtils.bookmarks.DEFAULT_INDEX + , feedURI: FEED_URI + }, function(aStatus, aLivemark) { + PlacesUtils.bookmarks.moveItem(aLivemark.id, + PlacesUtils.toolbarFolderId, + PlacesUtils.bookmarks.DEFAULT_INDEX); + do_check_eq(aLivemark.parentId, PlacesUtils.toolbarFolderId); + do_check_eq(aLivemark.index, PlacesUtils.bookmarks.getItemIndex(aLivemark.id)); + run_next_test(); + }); }); - -function run_test() { - run_next_test(); -} From 0ebc97f5b82dfb3c027080f3b9e74c2eea1b42b5 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Wed, 20 Nov 2013 10:52:48 -0800 Subject: [PATCH 125/268] NO BUG - Build docs for supported build configurations DONTBUILD (NPOTB) --HG-- extra : rebase_source : 9d1ba5ca4568739c557410b20034671093e439c7 --- build/docs/index.rst | 1 + build/docs/supported-configurations.rst | 55 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 build/docs/supported-configurations.rst diff --git a/build/docs/index.rst b/build/docs/index.rst index 0dd663db96af..8a7cb973b782 100644 --- a/build/docs/index.rst +++ b/build/docs/index.rst @@ -16,6 +16,7 @@ Important Concepts :maxdepth: 1 build-overview + supported-configurations Mozconfig Files mozbuild-files mozbuild-symbols diff --git a/build/docs/supported-configurations.rst b/build/docs/supported-configurations.rst new file mode 100644 index 000000000000..cc2c1ea7282d --- /dev/null +++ b/build/docs/supported-configurations.rst @@ -0,0 +1,55 @@ +.. _build_supported_configurations: + +======================== +Supported Configurations +======================== + +This page attempts to document supported build configurations. + +Windows +======= + +We support building on Windows XP and newer operating systems using +Visual Studio 2010 and newer. + +The following are not fully supported by Mozilla (but may work): + +* Building without the latest *MozillaBuild* Windows development + environment +* Building with Mingw or any other non-Visual Studio toolchain. + +OS X +==== + +We support building on OS X 10.6 and newer with the OS X 10.6 SDK. + +The tree should build with the following OS X releases and SDK versions: + +* 10.6 Snow Leopard +* 10.7 Lion +* 10.8 Mountain Lion +* 10.9 Mavericks + +The tree requires building with Clang 3.3 and newer. This corresponds to +version of 4.2 of Apple's Clang that ships with Xcode. This corresponds +to Xcode 4.6 and newer. Xcode 4.6 only runs on OS X 10.7.4 and newer. +So, OS X 10.6 users will need to install a non-Apple toolchain. Running +``mach bootstrap`` should install an appropriate toolchain from Homebrew +or MacPorts automatically. + +The tree should build with GCC 4.4 and newer on OS X. However, this +build configuration isn't as widely used (and differs from what Mozilla +uses to produce OS X builds), so it's recommended to stick with Clang. + +Linux +===== + +Linux 2.6 and later kernels are supported. + +Most distributions are supported as long as the proper package +dependencies are in place. Running ``mach bootstrap`` should install +packages for popular Linux distributions. ``configure`` will typically +detect missing dependencies and inform you how to disable features to +work around unsatisfied dependencies. + +Clang 3.3 or GCC 4.4 is required to build the tree. From d98412c52104c0d4271f541014a9082c21e84d8a Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Wed, 20 Nov 2013 14:06:56 -0500 Subject: [PATCH 126/268] Bug 924307 - Disable browser_aboutHealthReport.js due to intermittent failures. --- browser/base/content/test/general/browser.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 4d5472c2230f..963364dcf0a1 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -108,6 +108,7 @@ run-if = crashreporter [browser_CTP_resize.js] [browser_URLBarSetURI.js] [browser_aboutHealthReport.js] +skip-if = os == "linux" # Bug 924307 [browser_aboutHome.js] [browser_aboutSyncProgress.js] [browser_addKeywordSearch.js] From 1961aa2ab239637f96ad03b392ea3746624659e3 Mon Sep 17 00:00:00 2001 From: Kai Engert Date: Wed, 20 Nov 2013 20:25:12 +0100 Subject: [PATCH 127/268] Bug 938730 - avoid mix of memory allocators (crashes) when using system sqlite, r=asuth --- storage/src/Makefile.in | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/storage/src/Makefile.in b/storage/src/Makefile.in index 941864015325..c7391edbc342 100644 --- a/storage/src/Makefile.in +++ b/storage/src/Makefile.in @@ -6,14 +6,21 @@ # Don't use the jemalloc allocator on Android, because we can't guarantee # that Gecko will configure sqlite before it is first used (bug 730495). # +# Don't use the jemalloc allocator when using system sqlite. Linked in libraries +# (such as NSS) might trigger an initialization of sqlite and allocation +# of memory using the default allocator, prior to the storage service +# registering its allocator, causing memory management failures (bug 938730). +# # Note: On Windows our sqlite build assumes we use jemalloc. If you disable # MOZ_STORAGE_MEMORY on Windows, you will also need to change the "ifdef # MOZ_MEMORY" options in db/sqlite3/src/Makefile.in. ifdef MOZ_MEMORY +ifndef MOZ_NATIVE_SQLITE ifneq ($(OS_TARGET), Android) DEFINES += -DMOZ_STORAGE_MEMORY endif endif +endif # For nsDependentJSString LOCAL_INCLUDES = \ From 22f3deb912b76a28247084184d3b139656a51f52 Mon Sep 17 00:00:00 2001 From: Vladan Djeric Date: Wed, 20 Nov 2013 14:39:23 -0500 Subject: [PATCH 128/268] Bug 940806 - Gfx info was not being properly reported in Telemetry. r=dteller --- toolkit/components/telemetry/TelemetryPing.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/toolkit/components/telemetry/TelemetryPing.js b/toolkit/components/telemetry/TelemetryPing.js index c2eca6adb067..a67c6425ce66 100644 --- a/toolkit/components/telemetry/TelemetryPing.js +++ b/toolkit/components/telemetry/TelemetryPing.js @@ -374,10 +374,13 @@ TelemetryPing.prototype = { if (gfxInfo) { for each (let field in gfxfields) { try { - let value = ""; - value = gfxInfo[field]; - if (value != "") + let value = gfxInfo[field]; + // bug 940806: We need to do a strict equality comparison here, + // otherwise a type conversion will occur and boolean false values + // will get filtered out + if (value !== "") { ret[field] = value; + } } catch (e) { continue } From 1e13d8499d5b3d16ef55c7eadf1f9d01216f70a7 Mon Sep 17 00:00:00 2001 From: "Nicholas D. Matsakis" Date: Thu, 12 Sep 2013 12:29:40 -0400 Subject: [PATCH 129/268] Bug 917454 - Add objectType function r=till --- js/src/builtin/TypedObject.cpp | 17 +++++++++ js/src/builtin/TypedObject.h | 11 ++++++ js/src/builtin/TypedObject.js | 25 ++++++++++++ js/src/jsprototypes.h | 2 +- js/src/tests/ecma_6/TypedObject/objecttype.js | 38 +++++++++++++++++++ .../ecma_6/TypedObject/referencetypetrace.js | 5 +++ js/src/vm/GlobalObject.h | 7 ++++ js/src/vm/SelfHosting.cpp | 3 ++ 8 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 js/src/tests/ecma_6/TypedObject/objecttype.js diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 63b6aecf7d6f..4da2c76d402e 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -41,6 +41,11 @@ const Class js::TypedObjectClass = { JS_ConvertStub }; +static const JSFunctionSpec TypedObjectMethods[] = { + JS_SELF_HOSTED_FN("objectType", "TypeOfTypedDatum", 1, 0), + JS_FS_END +}; + static void ReportCannotConvertTo(JSContext *cx, HandleValue fromValue, const char *toType) { @@ -1349,6 +1354,9 @@ js_InitTypedObjectClass(JSContext *cx, HandleObject obj) if (!module) return nullptr; + if (!JS_DefineFunctions(cx, module, TypedObjectMethods)) + return nullptr; + // Define TypedObject global. RootedValue moduleValue(cx, ObjectValue(*module)); @@ -2518,6 +2526,15 @@ const JSJitInfo js::MemcpyJitInfo = JS_JITINFO_NATIVE_PARALLEL( JSParallelNativeThreadSafeWrapper); +bool +js::StandardTypeObjectDescriptors(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + Rooted global(cx, cx->global()); + args.rval().setObject(global->getTypedObject()); + return true; +} + #define JS_STORE_SCALAR_CLASS_IMPL(_constant, T, _name) \ bool \ js::StoreScalar##T::Func(ThreadSafeContext *, unsigned argc, Value *vp) \ diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index a8391055ac7c..d99c9efb3c34 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -426,6 +426,17 @@ extern const JSJitInfo ClampToUint8JitInfo; bool Memcpy(ThreadSafeContext *cx, unsigned argc, Value *vp); extern const JSJitInfo MemcpyJitInfo; +/* + * Usage: StandardTypeObjectDescriptors() + * + * Returns the global "typed object" object, which provides access + * to the various builtin type descriptors. These are currently + * exported as immutable properties so it is safe for self-hosted code + * to access them; eventually this should be linked into the module + * system. + */ +bool StandardTypeObjectDescriptors(JSContext *cx, unsigned argc, Value *vp); + /* * Usage: Store_int8(targetDatum, targetOffset, value) * ... diff --git a/js/src/builtin/TypedObject.js b/js/src/builtin/TypedObject.js index 3ebd50b65008..052acb0bb896 100644 --- a/js/src/builtin/TypedObject.js +++ b/js/src/builtin/TypedObject.js @@ -608,6 +608,31 @@ function HandleTest(obj) { /////////////////////////////////////////////////////////////////////////// // Miscellaneous +// This is the `objectType()` function defined in the spec. +// It returns the type of its argument. +// +// Warning: user exposed! +function TypeOfTypedDatum(obj) { + if (IsObject(obj) && ObjectIsTypedDatum(obj)) + return DATUM_TYPE_OBJ(obj); + + // Note: Do not create bindings for `Any`, `String`, etc in + // Utilities.js, but rather access them through + // `StandardTypeObjectDescriptors()`. The reason is that bindings + // you create in Utilities.js are part of the self-hosted global, + // vs the user-accessible global, and hence should not escape to + // user script. + var T = StandardTypeObjectDescriptors(); + switch (typeof obj) { + case "object": return T.Object; + case "function": return T.Object; + case "string": return T.String; + case "number": return T.float64; + case "undefined": return T.Any; + default: return T.Any; + } +} + function ObjectIsTypedDatum(obj) { assert(IsObject(obj), "ObjectIsTypedDatum invoked with non-object") return ObjectIsTypedObject(obj) || ObjectIsTypedHandle(obj); diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index b0fee8c468fa..00401a0fbe8a 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -54,7 +54,7 @@ macro(DataView, 35, js_InitTypedArrayClasses) \ macro(ParallelArray, 36, js_InitParallelArrayClass) \ macro(Intl, 37, js_InitIntlClass) \ - macro(TypedObject, 38, js_InitTypedObjectDummy) \ + macro(TypedObject, 38, js_InitTypedObjectClass) \ macro(GeneratorFunction, 39, js_InitIteratorClasses) \ #endif /* jsprototypes_h */ diff --git a/js/src/tests/ecma_6/TypedObject/objecttype.js b/js/src/tests/ecma_6/TypedObject/objecttype.js new file mode 100644 index 000000000000..7a8f0a1f7118 --- /dev/null +++ b/js/src/tests/ecma_6/TypedObject/objecttype.js @@ -0,0 +1,38 @@ +// |reftest| skip-if(!this.hasOwnProperty("TypedObject")) +var BUGNUMBER = 917454; +var summary = 'objecttype'; + +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + +var T = TypedObject; + +function runTests() { + var Point = new T.ArrayType(T.float32, 3); + var Line = new T.StructType({from: Point, to: Point}); + var Lines = new T.ArrayType(Line, 3); + + var lines = new Lines([ + {from: [1, 2, 3], to: [4, 5, 6]}, + {from: [7, 8, 9], to: [10, 11, 12]}, + {from: [13, 14, 15], to: [16, 17, 18]} + ]); + + assertEq(T.objectType(lines), Lines); + assertEq(T.objectType(lines[0]), Line); + assertEq(T.objectType(lines[0].from[0]), T.float64); + assertEq(T.objectType(""), T.String); + assertEq(T.objectType({}), T.Object); + assertEq(T.objectType([]), T.Object); + assertEq(T.objectType(function() { }), T.Object); + assertEq(T.objectType(undefined), T.Any); + + reportCompare(true, true); + print("Tests complete"); +} + +runTests(); + + diff --git a/js/src/tests/ecma_6/TypedObject/referencetypetrace.js b/js/src/tests/ecma_6/TypedObject/referencetypetrace.js index e1b90399d8cb..e0fa221716ec 100644 --- a/js/src/tests/ecma_6/TypedObject/referencetypetrace.js +++ b/js/src/tests/ecma_6/TypedObject/referencetypetrace.js @@ -4,6 +4,11 @@ var summary = 'TypedObjects reference type trace'; var actual = ''; var expect = ''; +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + */ + var ArrayType = TypedObject.ArrayType; var StructType = TypedObject.StructType; var Any = TypedObject.Any; diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index cbe9ee03d224..6cebb57bd068 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -418,6 +418,13 @@ class GlobalObject : public JSObject return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject); } + JSObject &getTypedObject() { + Value v = getConstructor(JSProto_TypedObject); + // only gets called from contexts where TypedObject must be initialized + JS_ASSERT(v.isObject()); + return v.toObject(); + } + JSObject *getIteratorPrototype() { return &getPrototype(JSProto_Iterator).toObject(); } diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index d5122bb506c4..48a2f44546e9 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -658,6 +658,9 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FNINFO("Memcpy", JSNativeThreadSafeWrapper, &js::MemcpyJitInfo, 5, 0), + JS_FN("StandardTypeObjectDescriptors", + js::StandardTypeObjectDescriptors, + 0, 0), #define LOAD_AND_STORE_SCALAR_FN_DECLS(_constant, _type, _name) \ JS_FNINFO("Store_" #_name, \ From df5b9e6f9a3e51c7e70c5f346e1be651cd5677ac Mon Sep 17 00:00:00 2001 From: Jonathan Griffin Date: Tue, 19 Nov 2013 16:33:57 -0800 Subject: [PATCH 130/268] Bug 937684 - Hack to prevent B2G mochitest stdout mangling, r=ahal --- testing/mochitest/runtestsb2g.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testing/mochitest/runtestsb2g.py b/testing/mochitest/runtestsb2g.py index e5260e088d16..af1dbbdc40ee 100644 --- a/testing/mochitest/runtestsb2g.py +++ b/testing/mochitest/runtestsb2g.py @@ -9,6 +9,7 @@ import shutil import sys import tempfile import threading +import time import traceback here = os.path.abspath(os.path.dirname(__file__)) @@ -143,11 +144,16 @@ class B2GMochitest(MochitestUtilsMixin): log.info("runtests.py | Received keyboard interrupt.\n"); status = -1 except: + # XXX Bug 937684 + time.sleep(5) traceback.print_exc() log.error("Automation Error: Received unexpected exception while running application\n") self.runner.check_for_crashes() status = 1 + # XXX Bug 937684 + time.sleep(5) + self.stopWebServer(options) self.stopWebSocketServer(options) From 5a9fbe50eb2764b0ce6fcd6325c68e68ebf89a65 Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 19 Nov 2013 17:35:36 -0800 Subject: [PATCH 131/268] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ======== https://hg.mozilla.org/integration/gaia-central/rev/2d81ea943bc1 Author: Mihai Cîrlănaru Desc: Merge pull request #13726 from mihai/bug_937970 Bug 937970 - [Settings] Move 'Sample Format' section below language... ======== https://hg.mozilla.org/integration/gaia-central/rev/7e3a76a2cf94 Author: Mihai Cirlanaru Desc: Bug 937970 - [Settings] Move 'Sample Format' section below language selector. r=arthurcc --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index eeace1170aaa..2663d8080bd9 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "14a570c0af0ad29420a47318576fc365ebf7b10a", + "revision": "2d81ea943bc1cfa75f7fd49c9b4c64095e666491", "repo_path": "/integration/gaia-central" } From 4968c7d3f1e5d46eb1d2d481039e95d0b70bed0d Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Wed, 9 Oct 2013 16:02:59 +0800 Subject: [PATCH 132/268] Bug 814637 - Part 1: Interface changes for iccManager support multiple sim. r=allstars.chh,hsinyi,smaug --- dom/bindings/Bindings.conf | 3 +- dom/icc/interfaces/nsIDOMIccManager.idl | 407 +++--------------- .../mochitest/general/test_interfaces.html | 1 + dom/webidl/MozIcc.webidl | 368 ++++++++++++++++ dom/webidl/moz.build | 1 + 5 files changed, 422 insertions(+), 358 deletions(-) create mode 100644 dom/webidl/MozIcc.webidl diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 54c53404f1ee..8d6b92ebd9a0 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -1855,7 +1855,8 @@ addExternalIface('MozConnection', headerFile='nsIDOMConnection.h') addExternalIface('MozControllers', nativeType='nsIControllers') addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True) addExternalIface('MozFrameRequestCallback', nativeType='nsIFrameRequestCallback', - notflattened=True); + notflattened=True) +addExternalIface('MozIccInfo', headerFile='nsIDOMIccInfo.h') addExternalIface('MozIccManager', headerFile='nsIDOMIccManager.h') addExternalIface('MozMobileConnection', headerFile='nsIDOMMobileConnection.h') addExternalIface('MozMobileMessageManager', headerFile='nsIDOMMobileMessageManager.h') diff --git a/dom/icc/interfaces/nsIDOMIccManager.idl b/dom/icc/interfaces/nsIDOMIccManager.idl index e717c063b191..f1c8ec69dab8 100644 --- a/dom/icc/interfaces/nsIDOMIccManager.idl +++ b/dom/icc/interfaces/nsIDOMIccManager.idl @@ -3,17 +3,14 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsIDOMEventTarget.idl" -#include "SimToolKit.idl" -interface nsIDOMDOMRequest; -interface nsIDOMEventListener; -interface nsIDOMMozIccInfo; +interface nsIDOMMozIcc; -[scriptable, builtinclass, uuid(50782fe0-4185-4471-a374-e362b73febdb)] +[scriptable, builtinclass, uuid(23067d6f-e0cb-4f34-8648-77c2b25a11f5)] interface nsIDOMMozIccManager : nsIDOMEventTarget { /** - * STK Menu Presentation types. + * STK menu presentation types. */ const unsigned short STK_MENU_TYPE_NOT_SPECIFIED = 0x00; const unsigned short STK_MENU_TYPE_DATA_VALUES = 0x01; @@ -27,7 +24,7 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget const unsigned short STK_BROWSER_MODE_USING_NEW_BROWSER = 0x03; /** - * STK Proactive commands. + * STK proactive commands. * * @see TS 11.14, clause 13.4 */ @@ -56,7 +53,7 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget const unsigned short STK_CMD_SEND_DATA = 0x33; /** - * STK Result code. + * STK result code. * * @see TS 11.14, clause 12.12 * @@ -128,7 +125,7 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget /** Command number not known by terminal */ const unsigned short STK_RESULT_CMD_NUM_NOT_KNOWN = 0x33; - /** SS Return Error */ + /** SS return error */ const unsigned short STK_RESULT_SS_RETURN_ERROR = 0x34; /** SMS RP-ERROR */ @@ -137,7 +134,7 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget /** Error, required values are missing */ const unsigned short STK_RESULT_REQUIRED_VALUES_MISSING = 0x36; - /** USSD Return Error */ + /** USSD return error */ const unsigned short STK_RESULT_USSD_RETURN_ERROR = 0x37; /** MultipleCard commands error */ @@ -145,40 +142,40 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget /** * Interaction with call control by USIM or MO short message control by - * USIM, permanent problem + * USIM, permanent problem. */ const unsigned short STK_RESULT_USIM_CALL_CONTROL_PERMANENT = 0x39; - /** Bearer Independent Protocol error */ + /** Bearer independent protocol error */ const unsigned short STK_RESULT_BIP_ERROR = 0x3a; /** - * STK Event List + * STK event list. */ - const unsigned short STK_EVENT_TYPE_MT_CALL = 0x00; - const unsigned short STK_EVENT_TYPE_CALL_CONNECTED = 0x01; - const unsigned short STK_EVENT_TYPE_CALL_DISCONNECTED = 0x02; - const unsigned short STK_EVENT_TYPE_LOCATION_STATUS = 0x03; - const unsigned short STK_EVENT_TYPE_USER_ACTIVITY = 0x04; - const unsigned short STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE = 0x05; - const unsigned short STK_EVENT_TYPE_CARD_READER_STATUS = 0x06; - const unsigned short STK_EVENT_TYPE_LANGUAGE_SELECTION = 0x07; - const unsigned short STK_EVENT_TYPE_BROWSER_TERMINATION = 0x08; - const unsigned short STK_EVENT_TYPE_DATA_AVAILABLE = 0x09; - const unsigned short STK_EVENT_TYPE_CHANNEL_STATUS = 0x0a; - const unsigned short STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED = 0x0b; - const unsigned short STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED = 0x0c; - const unsigned short STK_EVENT_TYPE_LOCAL_CONNECTION = 0x0d; - const unsigned short STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e; - const unsigned short STK_EVENT_TYPE_BROWSING_STATUS = 0x0f; - const unsigned short STK_EVENT_TYPE_FRAMES_INFORMATION_CHANGED = 0x10; + const unsigned short STK_EVENT_TYPE_MT_CALL = 0x00; + const unsigned short STK_EVENT_TYPE_CALL_CONNECTED = 0x01; + const unsigned short STK_EVENT_TYPE_CALL_DISCONNECTED = 0x02; + const unsigned short STK_EVENT_TYPE_LOCATION_STATUS = 0x03; + const unsigned short STK_EVENT_TYPE_USER_ACTIVITY = 0x04; + const unsigned short STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE = 0x05; + const unsigned short STK_EVENT_TYPE_CARD_READER_STATUS = 0x06; + const unsigned short STK_EVENT_TYPE_LANGUAGE_SELECTION = 0x07; + const unsigned short STK_EVENT_TYPE_BROWSER_TERMINATION = 0x08; + const unsigned short STK_EVENT_TYPE_DATA_AVAILABLE = 0x09; + const unsigned short STK_EVENT_TYPE_CHANNEL_STATUS = 0x0a; + const unsigned short STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED = 0x0b; + const unsigned short STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED = 0x0c; + const unsigned short STK_EVENT_TYPE_LOCAL_CONNECTION = 0x0d; + const unsigned short STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e; + const unsigned short STK_EVENT_TYPE_BROWSING_STATUS = 0x0f; + const unsigned short STK_EVENT_TYPE_FRAMES_INFORMATION_CHANGED = 0x10; - /** - * The service state of STK Location Status. - */ - const unsigned short STK_SERVICE_STATE_NORMAL = 0x00; - const unsigned short STK_SERVICE_STATE_LIMITED = 0x01; - const unsigned short STK_SERVICE_STATE_UNAVAILABLE = 0x02; + /** + * The service state of STK location status. + */ + const unsigned short STK_SERVICE_STATE_NORMAL = 0x00; + const unsigned short STK_SERVICE_STATE_LIMITED = 0x01; + const unsigned short STK_SERVICE_STATE_UNAVAILABLE = 0x02; /** * Tone type. @@ -196,14 +193,14 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget const unsigned short STK_TONE_TYPE_NEGATIVE_ACK_TONE = 0x12; /** - * Time unit + * Time unit. */ const unsigned short STK_TIME_UNIT_MINUTE = 0x00; const unsigned short STK_TIME_UNIT_SECOND = 0x01; const unsigned short STK_TIME_UNIT_TENTH_SECOND = 0x02; /** - * Local Information list + * Local Information list. * * @see TS 102.223, clause 8.6 */ @@ -212,345 +209,41 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget const unsigned short STK_LOCAL_INFO_DATE_TIME_ZONE = 0x03; const unsigned short STK_LOCAL_INFO_LANGUAGE = 0x04; - /** - * Timer Management + /** + * Timer management. */ const unsigned short STK_TIMER_START = 0x00; const unsigned short STK_TIMER_DEACTIVATE = 0x01; const unsigned short STK_TIMER_GET_CURRENT_VALUE = 0x02; /** - * Browser Termination Cause + * Browser termination cause. */ const unsigned short STK_BROWSER_TERMINATION_CAUSE_USER = 0x00; const unsigned short STK_BROWSER_TERMINATION_CAUSE_ERROR = 0x01; /** - * Send the response back to ICC after an attempt to execute STK Proactive - * Command. - * - * @param command - * Command received from ICC. See MozStkCommand. - * @param response - * The response that will be sent to ICC. - * @see MozStkResponse for the detail of response. + * Array of iccIds that are currently detected. */ - void sendStkResponse(in jsval command, in jsval response); + readonly attribute jsval iccIds; // DOMString[] /** - * Send the "Menu Selection" Envelope command to ICC for menu selection. + * Get ICC object by iccId. * - * @param itemIdentifier - * The identifier of the item selected by user. - * @param helpRequested - * true if user requests to provide help information, false otherwise. + * @param iccId + * The identifier of the ICC. + * + * @return see MozIcc.webidl for the detail. */ - void sendStkMenuSelection(in unsigned short itemIdentifier, - in boolean helpRequested); + nsISupports getIccById(in DOMString iccId); /** - * Send the "Timer Expiration" Envelope command to ICC for TIMER MANAGEMENT. - * - * @param timer - * The identifier and value for a timer. - * timerId: Identifier of the timer that has expired. - * timerValue: Different between the time when this command is issued - * and when the timer was initially started. - * @see MozStkTimer + * 'oniccdetected' event is notified whenever a new ICC is detected. */ - void sendStkTimerExpiration(in jsval timer); + [implicit_jscontext] attribute jsval oniccdetected; /** - * Send "Event Download" Envelope command to ICC. - * ICC will not respond with any data for this command. - * - * @param event - * one of events below: - * - MozStkLocationEvent - * - MozStkCallEvent - * - MozStkLanguageSelectionEvent - * - MozStkGeneralEvent - * - MozStkBrowserTerminationEvent + * 'oniccundetected' event is notified whenever an ICC becomes undetected. */ - void sendStkEventDownload(in jsval event); - - /** - * The 'stkcommand' event is notified whenever STK Proactive Command is - * issued from ICC. - */ - [implicit_jscontext] attribute jsval onstkcommand; - - /** - * 'stksessionend' event is notified whenever STK Session is terminated by - * ICC. - */ - [implicit_jscontext] attribute jsval onstksessionend; - - // UICC Card Information. - - /** - * Information stored in the device's ICC card. - * - * Null if the card is not detected. - */ - readonly attribute nsIDOMMozIccInfo iccInfo; - - /** - * The 'iccinfochange' event is notified whenever the icc info object - * changes. - */ - [implicit_jscontext] attribute jsval oniccinfochange; - - // UICC Card State. - - /** - * Indicates the state of the device's ICC card. - * - * Possible values: null, 'illegal', 'unknown', 'absent', 'pinRequired', - * 'pukRequired', 'personalizationInProgress', 'networkLocked', - * 'corporateLocked', 'serviceProviderLocked', 'networkPukRequired', - * 'corporatePukRequired', 'serviceProviderPukRequired', - * 'personalizationReady', 'ready', 'permanentBlocked'. - */ - readonly attribute DOMString cardState; - - /** - * The 'cardstatechange' event is notified when the 'cardState' attribute - * changes value. - */ - [implicit_jscontext] attribute jsval oncardstatechange; - - // UICC Card Lock interfaces. - - /** - * Find out about the status of an ICC lock (e.g. the PIN lock). - * - * @param lockType - * Identifies the lock type, e.g. "pin" for the PIN lock, "fdn" for - * the FDN lock. - * - * @return a DOM Request. - * The request's result will be an object containing - * information about the specified lock's status, - * e.g. {lockType: "pin", enabled: true}. - */ - nsIDOMDOMRequest getCardLock(in DOMString lockType); - - /** - * Unlock a card lock. - * - * @param info - * An object containing the information necessary to unlock - * the given lock. At a minimum, this object must have a - * "lockType" attribute which specifies the type of lock, e.g. - * "pin" for the PIN lock. Other attributes are dependent on - * the lock type. - * - * Examples: - * - * (1) Unlocking the PIN: - * - * unlockCardLock({lockType: "pin", - * pin: "..."}); - * - * (2) Unlocking the PUK and supplying a new PIN: - * - * unlockCardLock({lockType: "puk", - * puk: "...", - * newPin: "..."}); - * - * (3) Network depersonalization. Unlocking the network control key (NCK). - * - * unlockCardLock({lockType: "nck", - * pin: "..."}); - * - * (4) Corporate depersonalization. Unlocking the corporate control key (CCK). - * - * unlockCardLock({lockType: "cck", - * pin: "..."}); - * - * (5) Service Provider depersonalization. Unlocking the service provider - * control key (SPCK). - * - * unlockCardLock({lockType: "spck", - * pin: "..."}); - * - * (6) Network PUK depersonalization. Unlocking the network control key (NCK). - * - * unlockCardLock({lockType: "nckPuk", - * puk: "..."}); - * - * (7) Corporate PUK depersonalization. Unlocking the corporate control key - * (CCK). - * - * unlockCardLock({lockType: "cckPuk", - * puk: "..."}); - * - * (8) Service Provider PUK depersonalization. Unlocking the service provider - * control key (SPCK). - * - * unlockCardLock({lockType: "spckPuk", - * puk: "..."}); - * - * @return a nsIDOMDOMRequest. - * The request's result will be an object containing - * information about the unlock operation. - * - * Examples: - * - * (1) Unlocking failed: - * - * { - * lockType: "pin", - * success: false, - * retryCount: 2 - * } - * - * (2) Unlocking succeeded: - * - * { - * lockType: "pin", - * success: true - * } - */ - nsIDOMDOMRequest unlockCardLock(in jsval info); - - /** - * Modify the state of a card lock. - * - * @param info - * An object containing information about the lock and - * how to modify its state. At a minimum, this object - * must have a "lockType" attribute which specifies the - * type of lock, e.g. "pin" for the PIN lock. Other - * attributes are dependent on the lock type. - * - * Examples: - * - * (1a) Disabling the PIN lock: - * - * setCardLock({lockType: "pin", - * pin: "...", - * enabled: false}); - * - * (1b) Disabling the FDN lock: - * - * setCardLock({lockType: "fdn", - * pin2: "...", - * enabled: false}); - * - * (2) Changing the PIN: - * - * setCardLock({lockType: "pin", - * pin: "...", - * newPin: "..."}); - * - * @return a nsIDOMDOMRequest. - * The request's result will be an object containing - * information about the operation. - * - * Examples: - * - * (1) Enabling/Disabling card lock failed or change card lock failed. - * - * { - * lockType: "pin", - * success: false, - * retryCount: 2 - * } - * - * (2) Enabling/Disabling card lock succeed or change card lock succeed. - * - * { - * lockType: "pin", - * success: true - * } - */ - nsIDOMDOMRequest setCardLock(in jsval info); - - /** - * Retrieve the number of remaining tries for unlocking the card. - * - * @param lockType - * Identifies the lock type, e.g. "pin" for the PIN lock, "puk" for - * the PUK lock. - * - * @return a DOM Request. - * If the lock type is "pin", or "puk", the request's result will be - * an object containing the number of retries for the specified - * lock. For any other lock type, the result is undefined. - */ - nsIDOMDOMRequest getCardLockRetryCount(in DOMString lockType); - - // UICC Phonebook Interfaces. - - /** - * Read ICC contacts. - * - * @param contactType - * One of type as below, - * - 'adn': Abbreviated Dialling Number - * - 'fdn': Fixed Dialling Number - */ - nsIDOMDOMRequest readContacts(in DOMString contactType); - - /** - * Update ICC Phonebook contact. - * - * @param contactType - * One of type as below, - * - 'adn': Abbreviated Dialling Number - * - 'fdn': Fixed Dialling Number - * @param contact - * The contact will be updated in ICC - * @param [optional] pin2 - * PIN2 is only required for 'fdn'. - */ - nsIDOMDOMRequest updateContact(in DOMString contactType, - in jsval contact, - [optional] in DOMString pin2); - - // End of UICC Phonebook Interfaces. - - // UICC Secure Element Interfaces - - /** - * A secure element is a smart card chip that can hold - * several different applications with the necessary security. - * The most known secure element is the Universal Integrated Circuit Card (UICC) - */ - - /** - * Send request to open a logical channel defined by its - * application identifier (AID) - * - * @param aid - * The Application Identifier of the Applet to be selected on this channel - * return value : An instance of Channel (channelID) if available or null. - */ - nsIDOMDOMRequest iccOpenChannel(in DOMString aid); - - /** - * Interface, used to communicate with an applet through the - * Application Data Protocol Units (APDUs) and is - * used for all data that is exchanged between the UICC card and the terminal (ME). - * - * @param channel - * The Application Identifier of the Applet to which APDU is directed - * @param apdu - * Application Protocol Data Unit - * return value : Response APDU - */ - nsIDOMDOMRequest iccExchangeAPDU(in long channel, in jsval apdu); - - /** - * Send request to close the selected logical channel identified by its - * application identifier (AID) - * - * @param aid - * The Application Identifier of the Applet , to be closed - */ - nsIDOMDOMRequest iccCloseChannel(in long channel); - - // End of UICC Secure Element Interfaces + [implicit_jscontext] attribute jsval oniccundetected; }; diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 57e13a6b4495..abb52add1f0a 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -345,6 +345,7 @@ var interfaceNamesInGlobalScope = "MozCSSKeyframeRule", "MozCSSKeyframesRule", {name: "MozEmergencyCbModeEvent", b2g: true, pref: "dom.mobileconnection.enabled"}, + {name: "MozIcc", b2g: true, pref: "dom.icc.enabled"}, {name: "MozIccManager", b2g: true, pref: "dom.icc.enabled"}, {name: "MozInputContext", b2g: true}, {name: "MozInputMethodManager", b2g: true}, diff --git a/dom/webidl/MozIcc.webidl b/dom/webidl/MozIcc.webidl new file mode 100644 index 000000000000..98b735c1b0e6 --- /dev/null +++ b/dom/webidl/MozIcc.webidl @@ -0,0 +1,368 @@ +/* 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/. */ + +interface MozIccInfo; + +[Pref="dom.icc.enabled"] +interface MozIcc : EventTarget +{ + // Integrated Circuit Card Information. + + /** + * Information stored in the device's ICC. + * + * Once the ICC becomes undetectable, iccinfochange event will be notified. + * Also, the attribute is set to null and this MozIcc object becomes invalid. + * Calling asynchronous functions raises exception then. + */ + readonly attribute MozIccInfo? iccInfo; + + /** + * The 'iccinfochange' event is notified whenever the icc info object + * changes. + */ + attribute EventHandler oniccinfochange; + + // Integrated Circuit Card State. + + /** + * Indicates the state of the device's ICC. + * + * Possible values: 'illegal', 'unknown', 'pinRequired', + * 'pukRequired', 'personalizationInProgress', 'networkLocked', + * 'corporateLocked', 'serviceProviderLocked', 'networkPukRequired', + * 'corporatePukRequired', 'serviceProviderPukRequired', + * 'personalizationReady', 'ready', 'permanentBlocked'. + * + * Once the ICC becomes undetectable, cardstatechange event will be notified. + * Also, the attribute is set to null and this MozIcc object becomes invalid. + * Calling asynchronous functions raises exception then. + */ + readonly attribute DOMString? cardState; + + /** + * The 'cardstatechange' event is notified when the 'cardState' attribute + * changes value. + */ + attribute EventHandler oncardstatechange; + + // Integrated Circuit Card STK. + + /** + * Send the response back to ICC after an attempt to execute STK proactive + * Command. + * + * @param command + * Command received from ICC. See MozStkCommand. + * @param response + * The response that will be sent to ICC. + * @see MozStkResponse for the detail of response. + */ + [Throws] + void sendStkResponse(any command, any response); + + /** + * Send the "Menu Selection" envelope command to ICC for menu selection. + * + * @param itemIdentifier + * The identifier of the item selected by user. + * @param helpRequested + * true if user requests to provide help information, false otherwise. + */ + [Throws] + void sendStkMenuSelection(unsigned short itemIdentifier, + boolean helpRequested); + + /** + * Send the "Timer Expiration" envelope command to ICC for TIMER MANAGEMENT. + * + * @param timer + * The identifier and value for a timer. + * timerId: Identifier of the timer that has expired. + * timerValue: Different between the time when this command is issued + * and when the timer was initially started. + * @see MozStkTimer + */ + [Throws] + void sendStkTimerExpiration(any timer); + + /** + * Send "Event Download" envelope command to ICC. + * ICC will not respond with any data for this command. + * + * @param event + * one of events below: + * - MozStkLocationEvent + * - MozStkCallEvent + * - MozStkLanguageSelectionEvent + * - MozStkGeneralEvent + * - MozStkBrowserTerminationEvent + */ + [Throws] + void sendStkEventDownload(any event); + + /** + * The 'stkcommand' event is notified whenever STK proactive command is + * issued from ICC. + */ + attribute EventHandler onstkcommand; + + /** + * 'stksessionend' event is notified whenever STK session is terminated by + * ICC. + */ + attribute EventHandler onstksessionend; + + // Integrated Circuit Card Lock interfaces. + + /** + * Find out about the status of an ICC lock (e.g. the PIN lock). + * + * @param lockType + * Identifies the lock type, e.g. "pin" for the PIN lock, "fdn" for + * the FDN lock. + * + * @return a DOMRequest. + * The request's result will be an object containing + * information about the specified lock's status, + * e.g. {lockType: "pin", enabled: true}. + */ + [Throws] + nsISupports getCardLock(DOMString lockType); + + /** + * Unlock a card lock. + * + * @param info + * An object containing the information necessary to unlock + * the given lock. At a minimum, this object must have a + * "lockType" attribute which specifies the type of lock, e.g. + * "pin" for the PIN lock. Other attributes are dependent on + * the lock type. + * + * Examples: + * + * (1) Unlocking the PIN: + * + * unlockCardLock({lockType: "pin", + * pin: "..."}); + * + * (2) Unlocking the PUK and supplying a new PIN: + * + * unlockCardLock({lockType: "puk", + * puk: "...", + * newPin: "..."}); + * + * (3) Network depersonalization. Unlocking the network control key (NCK). + * + * unlockCardLock({lockType: "nck", + * pin: "..."}); + * + * (4) Corporate depersonalization. Unlocking the corporate control key (CCK). + * + * unlockCardLock({lockType: "cck", + * pin: "..."}); + * + * (5) Service Provider depersonalization. Unlocking the service provider + * control key (SPCK). + * + * unlockCardLock({lockType: "spck", + * pin: "..."}); + * + * (6) Network PUK depersonalization. Unlocking the network control key (NCK). + * + * unlockCardLock({lockType: "nckPuk", + * puk: "..."}); + * + * (7) Corporate PUK depersonalization. Unlocking the corporate control key + * (CCK). + * + * unlockCardLock({lockType: "cckPuk", + * puk: "..."}); + * + * (8) Service Provider PUK depersonalization. Unlocking the service provider + * control key (SPCK). + * + * unlockCardLock({lockType: "spckPuk", + * puk: "..."}); + * + * @return a DOMRequest. + * The request's result will be an object containing + * information about the unlock operation. + * + * Examples: + * + * (1) Unlocking failed: + * + * { + * lockType: "pin", + * success: false, + * retryCount: 2 + * } + * + * (2) Unlocking succeeded: + * + * { + * lockType: "pin", + * success: true + * } + */ + [Throws] + nsISupports unlockCardLock(any info); + + /** + * Modify the state of a card lock. + * + * @param info + * An object containing information about the lock and + * how to modify its state. At a minimum, this object + * must have a "lockType" attribute which specifies the + * type of lock, e.g. "pin" for the PIN lock. Other + * attributes are dependent on the lock type. + * + * Examples: + * + * (1a) Disabling the PIN lock: + * + * setCardLock({lockType: "pin", + * pin: "...", + * enabled: false}); + * + * (1b) Disabling the FDN lock: + * + * setCardLock({lockType: "fdn", + * pin2: "...", + * enabled: false}); + * + * (2) Changing the PIN: + * + * setCardLock({lockType: "pin", + * pin: "...", + * newPin: "..."}); + * + * @return a DOMRequest. + * The request's result will be an object containing + * information about the operation. + * + * Examples: + * + * (1) Enabling/Disabling card lock failed or change card lock failed. + * + * { + * lockType: "pin", + * success: false, + * retryCount: 2 + * } + * + * (2) Enabling/Disabling card lock succeed or change card lock succeed. + * + * { + * lockType: "pin", + * success: true + * } + */ + [Throws] + nsISupports setCardLock(any info); + + /** + * Retrieve the number of remaining tries for unlocking the card. + * + * @param lockType + * Identifies the lock type, e.g. "pin" for the PIN lock, "puk" for + * the PUK lock. + * + * @return a DOMRequest. + * If the lock type is "pin", or "puk", the request's result will be + * an object containing the number of retries for the specified + * lock. For any other lock type, the result is undefined. + */ + [Throws] + nsISupports getCardLockRetryCount(DOMString lockType); + + // Integrated Circuit Card Phonebook Interfaces. + + /** + * Read ICC contacts. + * + * @param contactType + * One of type as below, + * - 'adn': Abbreviated Dialling Number. + * - 'fdn': Fixed Dialling Number. + * + * @return a DOMRequest. + */ + [Throws] + nsISupports readContacts(DOMString contactType); + + /** + * Update ICC Phonebook contact. + * + * @param contactType + * One of type as below, + * - 'adn': Abbreviated Dialling Number. + * - 'fdn': Fixed Dialling Number. + * @param contact + * The contact will be updated in ICC. + * @param [optional] pin2 + * PIN2 is only required for 'fdn'. + * + * @return a DOMRequest. + */ + [Throws] + nsISupports updateContact(DOMString contactType, + any contact, + optional DOMString? pin2 = null); + + // Integrated Circuit Card Secure Element Interfaces. + + /** + * A secure element is a smart card chip that can hold + * several different applications with the necessary security. + * The most known secure element is the Universal Integrated Circuit Card + * (UICC). + */ + + /** + * Send request to open a logical channel defined by its + * application identifier (AID). + * + * @param aid + * The application identifier of the applet to be selected on this + * channel. + * + * @return a DOMRequest. + * The request's result will be an instance of channel (channelID) + * if available or null. + */ + [Throws] + nsISupports iccOpenChannel(DOMString aid); + + /** + * Interface, used to communicate with an applet through the + * application data protocol units (APDUs) and is + * used for all data that is exchanged between the UICC and the terminal (ME). + * + * @param channel + * The application identifier of the applet to which APDU is directed. + * @param apdu + * Application protocol data unit. + * + * @return a DOMRequest. + * The request's result will be response APDU. + */ + [Throws] + nsISupports iccExchangeAPDU(long channel, any apdu); + + /** + * Send request to close the selected logical channel identified by its + * application identifier (AID). + * + * @param aid + * The application identifier of the applet, to be closed. + * + * @return a DOMRequest. + */ + [Throws] + nsISupports iccCloseChannel(long channel); +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index e3db21266b89..cee67f9f6b28 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -513,6 +513,7 @@ if CONFIG['MOZ_B2G_RIL']: 'MozCellBroadcast.webidl', 'MozCellBroadcastEvent.webidl', 'MozEmergencyCbModeEvent.webidl', + 'MozIcc.webidl', 'MozMobileConnectionArray.webidl', 'MozOtaStatusEvent.webidl', 'MozVoicemail.webidl', From fab68d299c7c59d3404f13f449a78feaf4b2ffb3 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Wed, 30 Oct 2013 14:05:30 +0800 Subject: [PATCH 133/268] Bug 814637 - Part 2: Add iccChangeEvent using event generator. f=hsinyi. r=smaug --- .../events/test/test_all_synthetic_events.html | 4 ++++ .../mochitest/general/test_interfaces.html | 1 + dom/webidl/IccChangeEvent.webidl | 17 +++++++++++++++++ dom/webidl/moz.build | 1 + 4 files changed, 23 insertions(+) create mode 100644 dom/webidl/IccChangeEvent.webidl diff --git a/content/events/test/test_all_synthetic_events.html b/content/events/test/test_all_synthetic_events.html index 4655a3a3200f..0a696f1bfc0d 100644 --- a/content/events/test/test_all_synthetic_events.html +++ b/content/events/test/test_all_synthetic_events.html @@ -171,6 +171,10 @@ const kEventConstructors = { return new HashChangeEvent(aName, aProps); }, }, + IccChangeEvent: { create: function (aName, aProps) { + return new IccChangeEvent(aName, aProps); + }, + }, IDBVersionChangeEvent: { create: function (aName, aProps) { return new IDBVersionChangeEvent(aName, aProps); }, diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index abb52add1f0a..94509d340ccc 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -296,6 +296,7 @@ var interfaceNamesInGlobalScope = "HTMLUListElement", "HTMLUnknownElement", "HTMLVideoElement", + {name: "IccChangeEvent", b2g: true, pref: "dom.icc.enabled"}, {name: "IccCardLockError", b2g: true, pref: "dom.icc.enabled"}, "IDBCursor", "IDBCursorWithValue", diff --git a/dom/webidl/IccChangeEvent.webidl b/dom/webidl/IccChangeEvent.webidl new file mode 100644 index 000000000000..e3dab2f7db13 --- /dev/null +++ b/dom/webidl/IccChangeEvent.webidl @@ -0,0 +1,17 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +[Pref="dom.icc.enabled", + Constructor(DOMString type, optional IccChangeEventInit eventInitDict)] +interface IccChangeEvent : Event +{ + readonly attribute DOMString iccId; +}; + +dictionary IccChangeEventInit : EventInit +{ + DOMString iccId = ""; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index cee67f9f6b28..275234304bd5 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -565,6 +565,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'DeviceLightEvent.webidl', 'DeviceProximityEvent.webidl', 'ErrorEvent.webidl', + 'IccChangeEvent.webidl', 'MediaStreamEvent.webidl', 'MozContactChangeEvent.webidl', 'MozInterAppMessageEvent.webidl', From 32a51f2f8c1ef7e1f3432bfe4dcfca7488d1e5dc Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Wed, 9 Oct 2013 17:40:12 +0800 Subject: [PATCH 134/268] Bug 814637 - Part 3: DOM changes for IccManager support multiple sim. f=hsinyi. r=smaug --- content/base/src/nsGkAtomList.h | 2 + dom/base/Navigator.cpp | 3 +- dom/bindings/Bindings.conf | 4 + dom/icc/src/Icc.cpp | 358 ++++++++++++++++++++++++++++ dom/icc/src/Icc.h | 117 ++++++++++ dom/icc/src/IccListener.cpp | 130 +++++++++++ dom/icc/src/IccListener.h | 52 +++++ dom/icc/src/IccManager.cpp | 398 +++++++++++--------------------- dom/icc/src/IccManager.h | 48 ++-- dom/icc/src/moz.build | 5 + 10 files changed, 830 insertions(+), 287 deletions(-) create mode 100644 dom/icc/src/Icc.cpp create mode 100644 dom/icc/src/Icc.h create mode 100644 dom/icc/src/IccListener.cpp create mode 100644 dom/icc/src/IccListener.h diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index 874280cca9ff..ede9dc62f660 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -719,7 +719,9 @@ GK_ATOM(onheld, "onheld") GK_ATOM(onhfpstatuschanged, "onhfpstatuschanged") GK_ATOM(onholding, "onholding") GK_ATOM(oniccchange, "oniccchange") +GK_ATOM(oniccdetected, "oniccdetected") GK_ATOM(oniccinfochange, "oniccinfochange") +GK_ATOM(oniccundetected, "oniccundetected") GK_ATOM(onincoming, "onincoming") GK_ATOM(oninput, "oninput") GK_ATOM(oninvalid, "oninvalid") diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 81263a7bd02e..a74da5d17a38 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -1236,8 +1236,7 @@ Navigator::GetMozIccManager(ErrorResult& aRv) } NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr); - mIccManager = new IccManager(); - mIccManager->Init(mWindow); + mIccManager = new IccManager(mWindow); } return mIccManager; diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 8d6b92ebd9a0..73ea860569e7 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -789,6 +789,10 @@ DOMInterfaces = { 'nativeType': 'mozilla::dom::CellBroadcast', }, +'MozIcc': { + 'nativeType': 'mozilla::dom::Icc', +}, + 'MozMobileConnectionArray': { 'nativeType': 'mozilla::dom::network::MobileConnectionArray', 'resultNotAddRefed': [ 'item' ] diff --git a/dom/icc/src/Icc.cpp b/dom/icc/src/Icc.cpp new file mode 100644 index 000000000000..f757826af3d6 --- /dev/null +++ b/dom/icc/src/Icc.cpp @@ -0,0 +1,358 @@ +/* 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 "Icc.h" + +#include "mozilla/dom/MozIccBinding.h" +#include "mozilla/dom/MozStkCommandEvent.h" +#include "nsIDOMDOMRequest.h" +#include "nsIDOMIccInfo.h" +#include "nsJSON.h" +#include "nsRadioInterfaceLayer.h" +#include "nsServiceManagerUtils.h" + +using namespace mozilla::dom; + +Icc::Icc(nsPIDOMWindow* aWindow, long aClientId, const nsAString& aIccId) + : mLive(true) + , mClientId(aClientId) + , mIccId(aIccId) +{ + SetIsDOMBinding(); + BindToOwner(aWindow); + + mProvider = do_GetService(NS_RILCONTENTHELPER_CONTRACTID); + + // Not being able to acquire the provider isn't fatal since we check + // for it explicitly below. + if (!mProvider) { + NS_WARNING("Could not acquire nsIIccProvider!"); + } +} + +void +Icc::Shutdown() +{ + mProvider = nullptr; + mLive = false; +} + +nsresult +Icc::NotifyEvent(const nsAString& aName) +{ + return DispatchTrustedEvent(aName); +} + +nsresult +Icc::NotifyStkEvent(const nsAString& aName, const nsAString& aMessage) +{ + nsresult rv; + nsIScriptContext* sc = GetContextForEventHandlers(&rv); + NS_ENSURE_SUCCESS(rv, rv); + + AutoPushJSContext cx(sc->GetNativeContext()); + JS::Rooted value(cx); + + if (!aMessage.IsEmpty()) { + nsCOMPtr json(new nsJSON()); + nsresult rv = json->DecodeToJSVal(aMessage, cx, value.address()); + NS_ENSURE_SUCCESS(rv, rv); + } else { + value = JS::NullValue(); + } + + MozStkCommandEventInit init; + init.mBubbles = false; + init.mCancelable = false; + init.mCommand = value; + + nsRefPtr event = + MozStkCommandEvent::Constructor(this, aName, init); + + return DispatchTrustedEvent(event); +} + +// WrapperCache + +JSObject* +Icc::WrapObject(JSContext* aCx, JS::Handle aScope) +{ + return MozIccBinding::Wrap(aCx, aScope, this); +} + +// MozIcc WebIDL + +already_AddRefed +Icc::GetIccInfo() const +{ + if (!mProvider) { + return nullptr; + } + + nsCOMPtr iccInfo; + nsresult rv = mProvider->GetIccInfo(mClientId, getter_AddRefs(iccInfo)); + if (NS_FAILED(rv)) { + return nullptr; + } + + return iccInfo.forget(); +} + +void +Icc::GetCardState(nsString& aCardState) const +{ + aCardState.SetIsVoid(true); + + if (!mProvider) { + return; + } + + nsresult rv = mProvider->GetCardState(mClientId, aCardState); + if (NS_FAILED(rv)) { + aCardState.SetIsVoid(true); + } +} + +void +Icc::SendStkResponse(const JSContext* aCx, const JS::Value& aCommand, + const JS::Value& aResponse, ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + nsresult rv = mProvider->SendStkResponse(mClientId, GetOwner(), aCommand, + aResponse); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } +} + +void +Icc::SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested, + ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + nsresult rv = mProvider->SendStkMenuSelection(mClientId, + GetOwner(), + aItemIdentifier, + aHelpRequested); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } +} + +void +Icc::SendStkTimerExpiration(const JSContext* aCx, const JS::Value& aTimer, + ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + nsresult rv = mProvider->SendStkTimerExpiration(mClientId, GetOwner(), + aTimer); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } +} + +void +Icc::SendStkEventDownload(const JSContext* aCx, const JS::Value& aEvent, + ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + nsresult rv = mProvider->SendStkEventDownload(mClientId, GetOwner(), aEvent); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + } +} + +already_AddRefed +Icc::GetCardLock(const nsAString& aLockType, ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->GetCardLockState(mClientId, GetOwner(), aLockType, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::UnlockCardLock(const JSContext* aCx, const JS::Value& aInfo, + ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->UnlockCardLock(mClientId, GetOwner(), aInfo, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::SetCardLock(const JSContext* aCx, const JS::Value& aInfo, ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->SetCardLock(mClientId, GetOwner(), aInfo, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::GetCardLockRetryCount(const nsAString& aLockType, ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->GetCardLockRetryCount(mClientId, + GetOwner(), + aLockType, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::ReadContacts(const nsAString& aContactType, ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->ReadContacts(mClientId, GetOwner(), aContactType, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::UpdateContact(const JSContext* aCx, const nsAString& aContactType, + const JS::Value& aContact, const nsAString& aPin2, + ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->UpdateContact(mClientId, GetOwner(), aContactType, + aContact, aPin2, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::IccOpenChannel(const nsAString& aAid, ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->IccOpenChannel(mClientId, GetOwner(), aAid, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::IccExchangeAPDU(const JSContext* aCx, int32_t aChannel, const jsval& aApdu, + ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->IccExchangeAPDU(mClientId, GetOwner(), aChannel, + aApdu, getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} + +already_AddRefed +Icc::IccCloseChannel(int32_t aChannel, ErrorResult& aRv) +{ + if (!mProvider) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr request; + nsresult rv = mProvider->IccCloseChannel(mClientId, GetOwner(), aChannel, + getter_AddRefs(request)); + if (NS_FAILED(rv)) { + aRv.Throw(rv); + return nullptr; + } + + return request.forget(); +} diff --git a/dom/icc/src/Icc.h b/dom/icc/src/Icc.h new file mode 100644 index 000000000000..0c3fc0285261 --- /dev/null +++ b/dom/icc/src/Icc.h @@ -0,0 +1,117 @@ +/* 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 mozilla_dom_Icc_h +#define mozilla_dom_Icc_h + +#include "nsDOMEventTargetHelper.h" +#include "nsIIccProvider.h" + +namespace mozilla { +namespace dom { + +class Icc MOZ_FINAL : public nsDOMEventTargetHelper +{ +public: + NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper) + + Icc(nsPIDOMWindow* aWindow, long aClientId, const nsAString& aIccId); + + void + Shutdown(); + + nsresult + NotifyEvent(const nsAString& aName); + + nsresult + NotifyStkEvent(const nsAString& aName, const nsAString& aMessage); + + nsString + GetIccId() + { + return mIccId; + } + + nsPIDOMWindow* + GetParentObject() const + { + return GetOwner(); + } + + // WrapperCache + virtual JSObject* + WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE; + + // MozIcc WebIDL + already_AddRefed + GetIccInfo() const; + + void + GetCardState(nsString& aCardState) const; + + void + SendStkResponse(const JSContext* aCx, const JS::Value& aCommand, + const JS::Value& aResponse, ErrorResult& aRv); + + void + SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested, + ErrorResult& aRv); + + void + SendStkTimerExpiration(const JSContext* aCx, const JS::Value& aTimer, + ErrorResult& aRv); + + void + SendStkEventDownload(const JSContext* aCx, const JS::Value& aEvent, + ErrorResult& aRv); + + already_AddRefed + GetCardLock(const nsAString& aLockType, ErrorResult& aRv); + + already_AddRefed + UnlockCardLock(const JSContext* aCx, const JS::Value& aInfo, + ErrorResult& aRv); + + already_AddRefed + SetCardLock(const JSContext* aCx, const JS::Value& aInfo, ErrorResult& aRv); + + already_AddRefed + GetCardLockRetryCount(const nsAString& aLockType, ErrorResult& aRv); + + already_AddRefed + ReadContacts(const nsAString& aContactType, ErrorResult& aRv); + + already_AddRefed + UpdateContact(const JSContext* aCx, const nsAString& aContactType, + const JS::Value& aContact, const nsAString& aPin2, + ErrorResult& aRv); + + already_AddRefed + IccOpenChannel(const nsAString& aAid, ErrorResult& aRv); + + already_AddRefed + IccExchangeAPDU(const JSContext* aCx, int32_t aChannel, const jsval& aApdu, + ErrorResult& aRv); + + already_AddRefed + IccCloseChannel(int32_t aChannel, ErrorResult& aRv); + + IMPL_EVENT_HANDLER(iccinfochange) + IMPL_EVENT_HANDLER(cardstatechange) + IMPL_EVENT_HANDLER(stkcommand) + IMPL_EVENT_HANDLER(stksessionend) + +private: + bool mLive; + uint32_t mClientId; + nsString mIccId; + // mProvider is a xpcom service and will be released at shutdown, so it + // doesn't need to be cycle collected. + nsCOMPtr mProvider; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_icc_Icc_h diff --git a/dom/icc/src/IccListener.cpp b/dom/icc/src/IccListener.cpp new file mode 100644 index 000000000000..303aacdad918 --- /dev/null +++ b/dom/icc/src/IccListener.cpp @@ -0,0 +1,130 @@ +/* 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 "IccListener.h" + +#include "Icc.h" +#include "IccManager.h" +#include "nsIDOMClassInfo.h" +#include "nsIDOMIccInfo.h" +#include "nsRadioInterfaceLayer.h" + +using namespace mozilla::dom; + +NS_IMPL_ISUPPORTS1(IccListener, nsIIccListener) + +IccListener::IccListener(IccManager* aIccManager, uint32_t aClientId) + : mClientId(aClientId) + , mIccManager(aIccManager) +{ + MOZ_ASSERT(mIccManager); + + mProvider = do_GetService(NS_RILCONTENTHELPER_CONTRACTID); + + if (!mProvider) { + NS_WARNING("Could not acquire nsIIccProvider!"); + return; + } + + nsCOMPtr iccInfo; + mProvider->GetIccInfo(mClientId, getter_AddRefs(iccInfo)); + if (iccInfo) { + nsString iccId; + iccInfo->GetIccid(iccId); + if (!iccId.IsEmpty()) { + mIcc = new Icc(mIccManager->GetOwner(), mClientId, iccId); + } + } + + DebugOnly rv = mProvider->RegisterIccMsg(mClientId, this); + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), + "Failed registering icc messages with provider"); +} + +IccListener::~IccListener() +{ + Shutdown(); +} + +void +IccListener::Shutdown() +{ + if (mProvider) { + mProvider->UnregisterIccMsg(mClientId, this); + mProvider = nullptr; + } + + if (mIcc) { + mIcc->Shutdown(); + mIcc = nullptr; + } + + mIccManager = nullptr; +} + +// nsIIccListener + +NS_IMETHODIMP +IccListener::NotifyStkCommand(const nsAString& aMessage) +{ + if (!mIcc) { + return NS_OK; + } + + return mIcc->NotifyStkEvent(NS_LITERAL_STRING("stkcommand"), aMessage); +} + +NS_IMETHODIMP +IccListener::NotifyStkSessionEnd() +{ + if (!mIcc) { + return NS_OK; + } + + return mIcc->NotifyEvent(NS_LITERAL_STRING("stksessionend")); +} + +NS_IMETHODIMP +IccListener::NotifyCardStateChanged() +{ + if (!mIcc) { + return NS_OK; + } + + return mIcc->NotifyEvent(NS_LITERAL_STRING("cardstatechange")); +} + +NS_IMETHODIMP +IccListener::NotifyIccInfoChanged() +{ + nsCOMPtr iccInfo; + mProvider->GetIccInfo(mClientId, getter_AddRefs(iccInfo)); + + // Create/delete icc object based on current iccInfo. + // 1. If the mIcc is nullptr and iccInfo has valid data, create icc object and + // notify mIccManager a new icc is added. + // 2. If the mIcc is not nullptr and iccInfo becomes to null, delete existed + // icc object and notify mIccManager the icc is removed. + if (!mIcc) { + if (iccInfo) { + nsString iccId; + iccInfo->GetIccid(iccId); + if (!iccId.IsEmpty()) { + mIcc = new Icc(mIccManager->GetOwner(), mClientId, iccId); + mIccManager->NotifyIccAdd(iccId); + mIcc->NotifyEvent(NS_LITERAL_STRING("iccinfochange")); + } + } + } else { + mIcc->NotifyEvent(NS_LITERAL_STRING("iccinfochange")); + if (!iccInfo) { + nsString iccId = mIcc->GetIccId(); + mIcc->Shutdown(); + mIcc = nullptr; + mIccManager->NotifyIccRemove(iccId); + } + } + + return NS_OK; +} diff --git a/dom/icc/src/IccListener.h b/dom/icc/src/IccListener.h new file mode 100644 index 000000000000..cc82155524ea --- /dev/null +++ b/dom/icc/src/IccListener.h @@ -0,0 +1,52 @@ +/* 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 mozilla_dom_IccListener_h +#define mozilla_dom_IccListener_h + +#include "nsAutoPtr.h" +#include "nsIIccProvider.h" + +namespace mozilla { +namespace dom { + +class IccManager; +class Icc; + +class IccListener : public nsIIccListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIICCLISTENER + + IccListener(IccManager* aIccManager, uint32_t aClientId); + ~IccListener(); + + void + Shutdown(); + + already_AddRefed + GetIcc() + { + nsRefPtr icc = mIcc; + return icc.forget(); + } + +private: + uint32_t mClientId; + // We did not setup 'mIcc' and 'mIccManager' being a participant of cycle + // collection is because in Navigator->Invalidate() it will call + // mIccManager->Shutdown(), then IccManager will call Shutdown() of each + // IccListener, this will release the reference and break the cycle. + nsRefPtr mIcc; + nsRefPtr mIccManager; + // mProvider is a xpcom service and will be released at shutdown, so it + // doesn't need to be cycle collected. + nsCOMPtr mProvider; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_IccListener_h \ No newline at end of file diff --git a/dom/icc/src/IccManager.cpp b/dom/icc/src/IccManager.cpp index 5a9e72187496..b15ee1101e20 100644 --- a/dom/icc/src/IccManager.cpp +++ b/dom/icc/src/IccManager.cpp @@ -2,47 +2,42 @@ * 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 "mozilla/dom/IccManager.h" +#include "IccManager.h" #include "GeneratedEvents.h" -#include "mozilla/dom/MozStkCommandEvent.h" +#include "Icc.h" +#include "IccListener.h" +#include "mozilla/dom/IccChangeEvent.h" +#include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsIDOMClassInfo.h" #include "nsIDOMIccInfo.h" -#include "nsJSON.h" -#include "SimToolKit.h" - -#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1" using namespace mozilla::dom; -class IccManager::Listener : public nsIIccListener -{ - IccManager* mIccManager; - -public: - NS_DECL_ISUPPORTS - NS_FORWARD_SAFE_NSIICCLISTENER(mIccManager) - - Listener(IccManager* aIccManager) - : mIccManager(aIccManager) - { - MOZ_ASSERT(mIccManager); - } - - void - Disconnect() - { - MOZ_ASSERT(mIccManager); - mIccManager = nullptr; - } -}; - -NS_IMPL_ISUPPORTS1(IccManager::Listener, nsIIccListener) - DOMCI_DATA(MozIccManager, IccManager) -NS_INTERFACE_MAP_BEGIN(IccManager) +NS_IMPL_CYCLE_COLLECTION_CLASS(IccManager) + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(IccManager, + nsDOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsIccIds) + // We did not setup 'mIccListeners' being a participant of cycle collection is + // because in Navigator->Invalidate() it will call mIccManager->Shutdown(), + // then IccManager will call Shutdown() of each IccListener, this will release + // the reference that held by each mIccListener and break the cycle. +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IccManager, + nsDOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IccManager, + nsDOMEventTargetHelper) + tmp->Unroot(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IccManager) NS_INTERFACE_MAP_ENTRY(nsIDOMMozIccManager) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozIccManager) NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) @@ -50,261 +45,134 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(IccManager, nsDOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(IccManager, nsDOMEventTargetHelper) -IccManager::IccManager() -{ - mProvider = do_GetService(NS_RILCONTENTHELPER_CONTRACTID); - - // Not being able to acquire the provider isn't fatal since we check - // for it explicitly below. - if (!mProvider) { - NS_WARNING("Could not acquire nsIIccProvider!"); - return; - } - - // TODO: Bug 814637 - WebIccManager API: support multiple sim cards - // In Multi-sim, there is more than one client in iccProvider. Each client - // represents a icc service. To maintain the backward compatibility with - // single sim, we always use client 0 for now. Adding support for multiple sim - // will be addressed in bug 814637. - mClientId = 0; - - mListener = new Listener(this); - DebugOnly rv = mProvider->RegisterIccMsg(mClientId, mListener); - NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), - "Failed registering icc messages with provider"); -} - -void -IccManager::Init(nsPIDOMWindow* aWindow) +IccManager::IccManager(nsPIDOMWindow* aWindow) + : mJsIccIds(nullptr) + , mRooted(false) { BindToOwner(aWindow); + + uint32_t numberOfServices = + mozilla::Preferences::GetUint("ril.numRadioInterfaces", 1); + + for (uint32_t i = 0; i < numberOfServices; i++) { + nsRefPtr iccListener = new IccListener(this, i); + mIccListeners.AppendElement(iccListener); + } +} + +IccManager::~IccManager() +{ + Shutdown(); + Unroot(); } void IccManager::Shutdown() { - if (mProvider && mListener) { - mListener->Disconnect(); - mProvider->UnregisterIccMsg(mClientId, mListener); - mProvider = nullptr; - mListener = nullptr; + for (uint32_t i = 0; i < mIccListeners.Length(); i++) { + mIccListeners[i]->Shutdown(); + mIccListeners[i] = nullptr; + } + mIccListeners.Clear(); +} + +nsresult +IccManager::NotifyIccAdd(const nsAString& aIccId) +{ + mJsIccIds = nullptr; + + IccChangeEventInit init; + init.mBubbles = false; + init.mCancelable = false; + init.mIccId = aIccId; + + nsRefPtr event = + IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccdetected"), init); + + return DispatchTrustedEvent(event); +} + +nsresult +IccManager::NotifyIccRemove(const nsAString& aIccId) +{ + mJsIccIds = nullptr; + + IccChangeEventInit init; + init.mBubbles = false; + init.mCancelable = false; + init.mIccId = aIccId; + + nsRefPtr event = + IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccundetected"), init); + + return DispatchTrustedEvent(event); +} + +void +IccManager::Root() +{ + if (!mRooted) { + mozilla::HoldJSObjects(this); + mRooted = true; + } +} + +void +IccManager::Unroot() +{ + if (mRooted) { + mJsIccIds = nullptr; + mozilla::DropJSObjects(this); + mRooted = false; } } // nsIDOMMozIccManager NS_IMETHODIMP -IccManager::SendStkResponse(const JS::Value& aCommand, - const JS::Value& aResponse) +IccManager::GetIccIds(JS::Value* aIccIds) { - if (!mProvider) { - return NS_ERROR_FAILURE; - } + if (!mJsIccIds) { + nsTArray iccIds; + for (uint32_t i = 0; i < mIccListeners.Length(); i++) { + nsRefPtr icc = mIccListeners[i]->GetIcc(); + if (icc) { + iccIds.AppendElement(icc->GetIccId()); + } + } - mProvider->SendStkResponse(mClientId, GetOwner(), aCommand, aResponse); - return NS_OK; -} - -NS_IMETHODIMP -IccManager::SendStkMenuSelection(uint16_t aItemIdentifier, bool aHelpRequested) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - mProvider->SendStkMenuSelection(mClientId, GetOwner(), aItemIdentifier, aHelpRequested); - return NS_OK; -} - -NS_IMETHODIMP -IccManager::SendStkTimerExpiration(const JS::Value& aTimer) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - mProvider->SendStkTimerExpiration(mClientId, GetOwner(), aTimer); - return NS_OK; -} - -NS_IMETHODIMP -IccManager::SendStkEventDownload(const JS::Value& aEvent) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - mProvider->SendStkEventDownload(mClientId, GetOwner(), aEvent); - return NS_OK; -} - -NS_IMETHODIMP -IccManager::GetIccInfo(nsIDOMMozIccInfo** aIccInfo) -{ - *aIccInfo = nullptr; - - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->GetIccInfo(mClientId, aIccInfo); -} - -NS_IMETHODIMP -IccManager::GetCardState(nsAString& cardState) -{ - cardState.SetIsVoid(true); - - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->GetCardState(mClientId, cardState); -} - -NS_IMETHODIMP -IccManager::GetCardLock(const nsAString& aLockType, nsIDOMDOMRequest** aDomRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->GetCardLockState(mClientId, GetOwner(), aLockType, aDomRequest); -} - -NS_IMETHODIMP -IccManager::SetCardLock(const JS::Value& aInfo, nsIDOMDOMRequest** aDomRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->SetCardLock(mClientId, GetOwner(), aInfo, aDomRequest); -} - -NS_IMETHODIMP -IccManager::UnlockCardLock(const JS::Value& aInfo, nsIDOMDOMRequest** aDomRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->UnlockCardLock(mClientId, GetOwner(), aInfo, aDomRequest); -} - -NS_IMETHODIMP -IccManager::GetCardLockRetryCount(const nsAString& aLockType, nsIDOMDOMRequest** aDomRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->GetCardLockRetryCount(mClientId, GetOwner(), aLockType, aDomRequest); -} - -NS_IMETHODIMP -IccManager::IccOpenChannel(const nsAString& aAid, nsIDOMDOMRequest** aRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->IccOpenChannel(mClientId, GetOwner(), aAid, aRequest); -} - -NS_IMETHODIMP -IccManager::IccExchangeAPDU(int32_t aChannel, const jsval& aApdu, nsIDOMDOMRequest** aRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->IccExchangeAPDU(mClientId, GetOwner(), aChannel, aApdu, aRequest); -} - -NS_IMETHODIMP -IccManager::IccCloseChannel(int32_t aChannel, nsIDOMDOMRequest** aRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->IccCloseChannel(mClientId, GetOwner(), aChannel, aRequest); -} - -NS_IMETHODIMP -IccManager::ReadContacts(const nsAString& aContactType, nsIDOMDOMRequest** aRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->ReadContacts(mClientId, GetOwner(), aContactType, aRequest); -} - -NS_IMETHODIMP -IccManager::UpdateContact(const nsAString& aContactType, - const JS::Value& aContact, - const nsAString& aPin2, - nsIDOMDOMRequest** aRequest) -{ - if (!mProvider) { - return NS_ERROR_FAILURE; - } - - return mProvider->UpdateContact(mClientId, GetOwner(), aContactType, aContact, aPin2, aRequest); -} - -NS_IMPL_EVENT_HANDLER(IccManager, stkcommand) -NS_IMPL_EVENT_HANDLER(IccManager, stksessionend) -NS_IMPL_EVENT_HANDLER(IccManager, cardstatechange) -NS_IMPL_EVENT_HANDLER(IccManager, iccinfochange) - -// nsIIccListener - -NS_IMETHODIMP -IccManager::NotifyStkCommand(const nsAString& aMessage) -{ - nsresult rv; - nsIScriptContext* sc = GetContextForEventHandlers(&rv); - NS_ENSURE_SUCCESS(rv, rv); - - AutoPushJSContext cx(sc->GetNativeContext()); - JS::Rooted value(cx); - - if (!aMessage.IsEmpty()) { - nsCOMPtr json(new nsJSON()); - nsresult rv = json->DecodeToJSVal(aMessage, cx, value.address()); + nsresult rv; + nsIScriptContext* sc = GetContextForEventHandlers(&rv); NS_ENSURE_SUCCESS(rv, rv); - } else { - value = JSVAL_VOID; + + AutoPushJSContext cx(sc->GetNativeContext()); + JS::Rooted jsIccIds(cx); + rv = nsTArrayToJSArray(cx, iccIds, jsIccIds.address()); + NS_ENSURE_SUCCESS(rv, rv); + + mJsIccIds = jsIccIds; + Root(); } - MozStkCommandEventInit init; - init.mBubbles = false; - init.mCancelable = false; - init.mCommand = value; - - nsRefPtr event = - MozStkCommandEvent::Constructor(this, NS_LITERAL_STRING("stkcommand"), init); - - return DispatchTrustedEvent(event); + aIccIds->setObject(*mJsIccIds); + return NS_OK; } NS_IMETHODIMP -IccManager::NotifyStkSessionEnd() +IccManager::GetIccById(const nsAString& aIccId, nsISupports** aIcc) { - return DispatchTrustedEvent(NS_LITERAL_STRING("stksessionend")); + *aIcc = nullptr; + + for (uint32_t i = 0; i < mIccListeners.Length(); i++) { + nsRefPtr icc = mIccListeners[i]->GetIcc(); + if (icc && aIccId == icc->GetIccId()) { + icc.forget(aIcc); + return NS_OK; + } + } + + return NS_OK; } -NS_IMETHODIMP -IccManager::NotifyCardStateChanged() -{ - return DispatchTrustedEvent(NS_LITERAL_STRING("cardstatechange")); -} - -NS_IMETHODIMP -IccManager::NotifyIccInfoChanged() -{ - return DispatchTrustedEvent(NS_LITERAL_STRING("iccinfochange")); -} +NS_IMPL_EVENT_HANDLER(IccManager, iccdetected) +NS_IMPL_EVENT_HANDLER(IccManager, iccundetected) diff --git a/dom/icc/src/IccManager.h b/dom/icc/src/IccManager.h index 20f8029794ae..15f4aa5b8a25 100644 --- a/dom/icc/src/IccManager.h +++ b/dom/icc/src/IccManager.h @@ -9,40 +9,48 @@ #include "nsDOMEventTargetHelper.h" #include "nsIDOMIccManager.h" #include "nsIIccProvider.h" +#include "nsTArrayHelpers.h" namespace mozilla { namespace dom { -class IccManager : public nsDOMEventTargetHelper - , public nsIDOMMozIccManager -{ - /** - * Class IccManager doesn't actually inherit nsIIccListener. Instead, it owns - * an nsIIccListener derived instance mListener and passes it to - * nsIIccProvider. The onreceived events are first delivered to mListener and - * then forwarded to its owner, IccManager. See also bug 775997 comment #51. - */ - class Listener; +class IccListener; +class IccManager MOZ_FINAL : public nsDOMEventTargetHelper + , public nsIDOMMozIccManager +{ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIDOMMOZICCMANAGER - NS_DECL_NSIICCLISTENER NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper) - IccManager(); + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(IccManager, + nsDOMEventTargetHelper) - void Init(nsPIDOMWindow *aWindow); - void Shutdown(); + IccManager(nsPIDOMWindow* aWindow); + ~IccManager(); + + void + Shutdown(); + + nsresult + NotifyIccAdd(const nsAString& aIccId); + + nsresult + NotifyIccRemove(const nsAString& aIccId); private: - // TODO: Bug 814637 - WebIccManager API: support multiple sim cards - // The private member, mClient, will be moved to other proper place for - // supporting multiple sim cards. - uint32_t mClientId; - nsCOMPtr mProvider; - nsRefPtr mListener; + nsTArray> mIccListeners; + + // Cached iccIds js array object. Cleared whenever the NotifyIccAdd() or + // NotifyIccRemove() is called, and then rebuilt once a page looks for the + // iccIds attribute. + JS::Heap mJsIccIds; + bool mRooted; + + void Root(); + void Unroot(); }; } // namespace dom diff --git a/dom/icc/src/moz.build b/dom/icc/src/moz.build index c79d58fee172..a03423bc4349 100644 --- a/dom/icc/src/moz.build +++ b/dom/icc/src/moz.build @@ -5,10 +5,13 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS.mozilla.dom += [ + 'Icc.h', 'IccManager.h', ] SOURCES += [ + 'Icc.cpp', + 'IccListener.cpp', 'IccManager.cpp', ] @@ -17,7 +20,9 @@ FAIL_ON_WARNINGS = True include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'gklayout' + LOCAL_INCLUDES += [ + '../../system/gonk', '/content/events/src', ] From c2e59b8502d6269d20b5c4fee9b439b7ef8d5878 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Fri, 27 Sep 2013 19:05:41 +0800 Subject: [PATCH 135/268] Bug 814637 - Part 4: RIL implementation changes for iccManager multi-sim. r=hsinyi,allstars.chh --- dom/system/gonk/RILContentHelper.js | 2 +- dom/system/gonk/ril_consts.js | 3 +- dom/system/gonk/ril_worker.js | 61 ++++++++++------------------- 3 files changed, 23 insertions(+), 43 deletions(-) diff --git a/dom/system/gonk/RILContentHelper.js b/dom/system/gonk/RILContentHelper.js index 13b206f02441..c5476967f92d 100644 --- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -556,7 +556,7 @@ RILContentHelper.prototype = { let rilContext = this.rilContexts[clientId]; // Card is not detected, clear iccInfo to null. - if (!newInfo || !newInfo.iccType) { + if (!newInfo || !newInfo.iccType || !newInfo.iccid) { if (rilContext.iccInfo) { rilContext.iccInfo = null; this._deliverEvent(clientId, diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js index 07c2f7f34a47..ee09e3810dd6 100644 --- a/dom/system/gonk/ril_consts.js +++ b/dom/system/gonk/ril_consts.js @@ -2379,10 +2379,9 @@ this.GECKO_RADIOSTATE_UNAVAILABLE = null; this.GECKO_RADIOSTATE_OFF = "off"; this.GECKO_RADIOSTATE_READY = "ready"; -this.GECKO_CARDSTATE_NOT_READY = null; +this.GECKO_CARDSTATE_UNDETECTED = null; this.GECKO_CARDSTATE_ILLEGAL = "illegal"; this.GECKO_CARDSTATE_UNKNOWN = "unknown"; -this.GECKO_CARDSTATE_ABSENT = "absent"; this.GECKO_CARDSTATE_PIN_REQUIRED = "pinRequired"; this.GECKO_CARDSTATE_PUK_REQUIRED = "pukRequired"; this.GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS = "personalizationInProgress"; diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 8e309176724f..fa8f98f0eb55 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -278,7 +278,7 @@ let RIL = { /** * Card state */ - this.cardState = GECKO_CARDSTATE_UNKNOWN; + this.cardState = GECKO_CARDSTATE_UNDETECTED; /** * Strings @@ -2954,51 +2954,36 @@ let RIL = { _processICCStatus: function _processICCStatus(iccStatus) { this.iccStatus = iccStatus; let newCardState; - - if ((!iccStatus) || (iccStatus.cardState == CARD_STATE_ABSENT)) { - switch (this.radioState) { - case GECKO_RADIOSTATE_UNAVAILABLE: - newCardState = GECKO_CARDSTATE_UNKNOWN; - break; - case GECKO_RADIOSTATE_OFF: - newCardState = GECKO_CARDSTATE_NOT_READY; - break; - case GECKO_RADIOSTATE_READY: - if (DEBUG) { - debug("ICC absent"); - } - newCardState = GECKO_CARDSTATE_ABSENT; - break; - } - if (newCardState == this.cardState) { - return; - } - this.iccInfo = {iccType: null}; - ICCUtilsHelper.handleICCInfoChange(); - - this.cardState = newCardState; - this.sendChromeMessage({rilMessageType: "cardstatechange", - cardState: this.cardState}); - return; - } - let index = this._isCdma ? iccStatus.cdmaSubscriptionAppIndex : iccStatus.gsmUmtsSubscriptionAppIndex; let app = iccStatus.apps[index]; - if (iccStatus.cardState == CARD_STATE_ERROR || !app) { - if (this.cardState == GECKO_CARDSTATE_UNKNOWN) { + + // When |iccStatus.cardState| is not CARD_STATE_PRESENT or have incorrect + // app information, we can not get iccId. So treat ICC as undetected. + if (iccStatus.cardState !== CARD_STATE_PRESENT || !app) { + if (this.cardState !== GECKO_CARDSTATE_UNDETECTED) { this.operator = null; - return; + // We should send |cardstatechange| before |iccinfochange|, otherwise we + // may lost cardstatechange event when icc card becomes undetected. + this.cardState = GECKO_CARDSTATE_UNDETECTED; + this.sendChromeMessage({rilMessageType: "cardstatechange", + cardState: this.cardState}); + + this.iccInfo = {iccType: null}; + ICCUtilsHelper.handleICCInfoChange(); } - this.operator = null; - this.cardState = GECKO_CARDSTATE_UNKNOWN; - this.sendChromeMessage({rilMessageType: "cardstatechange", - cardState: this.cardState}); return; } + // fetchICCRecords will need to read aid, so read aid here. this.aid = app.aid; this.appType = app.app_type; + this.iccInfo.iccType = GECKO_CARD_TYPE[this.appType]; + // Try to get iccId only when cardState left GECKO_CARDSTATE_UNDETECTED. + if (this.cardState === GECKO_CARDSTATE_UNDETECTED && + iccStatus.cardState === CARD_STATE_PRESENT) { + ICCRecordHelper.readICCID(); + } switch (app.app_state) { case CARD_APPSTATE_ILLEGAL: @@ -3036,8 +3021,6 @@ let RIL = { // This was moved down from CARD_APPSTATE_READY this.requestNetworkInfo(); if (newCardState == GECKO_CARDSTATE_READY) { - this.iccInfo.iccType = GECKO_CARD_TYPE[this.appType]; - // For type SIM, we need to check EF_phase first. // Other types of ICC we can send Terminal_Profile immediately. if (this.appType == CARD_APPTYPE_SIM) { @@ -11205,7 +11188,6 @@ let ICCRecordHelper = { * Fetch ICC records. */ fetchICCRecords: function fetchICCRecords() { - this.readICCID(); RIL.getIMSI(); this.readAD(); this.readSST(); @@ -13181,7 +13163,6 @@ let ICCContactHelper = { let RuimRecordHelper = { fetchRuimRecords: function fetchRuimRecords() { - ICCRecordHelper.readICCID(); this.getIMSI_M(); this.readCST(); this.readCDMAHome(); From 849a9230e38326350b8ebbcad612a99e0fe285e7 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Mon, 11 Nov 2013 15:47:35 +0800 Subject: [PATCH 136/268] Bug 814637 - Part 5: Refactor Marionette tests. r=hsinyi --- dom/icc/tests/marionette/icc_header.js | 52 +++++ .../tests/marionette/test_icc_card_lock.js | 101 +++------ .../tests/marionette/test_icc_card_state.js | 76 +++---- dom/icc/tests/marionette/test_icc_contact.js | 69 +++--- dom/icc/tests/marionette/test_icc_info.js | 203 +++++++----------- 5 files changed, 225 insertions(+), 276 deletions(-) create mode 100644 dom/icc/tests/marionette/icc_header.js diff --git a/dom/icc/tests/marionette/icc_header.js b/dom/icc/tests/marionette/icc_header.js new file mode 100644 index 000000000000..9b72ab68f026 --- /dev/null +++ b/dom/icc/tests/marionette/icc_header.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +SpecialPowers.addPermission("mobileconnection", true, document); + +let icc = navigator.mozIccManager; +ok(icc instanceof MozIccManager, + "icc is instanceof " + icc.constructor); + +/* Remove permission and execute finish() */ +let cleanUp = function () { + SpecialPowers.removePermission("mobileconnection", document); + finish(); +}; + +/* Helper for tasks */ +let taskHelper = { + tasks: [], + + push: function(task) { + this.tasks.push(task); + }, + + runNext: function() { + let task = this.tasks.shift(); + if (!task) { + cleanUp(); + return; + } + + if (typeof task === "function") { + task(); + } + }, +}; + +/* Helper for emulator console command */ +let emulatorHelper = { + pendingCommandCount: 0, + + sendCommand: function(cmd, callback) { + this.pendingCommandCount++; + runEmulatorCmd(cmd, function(result) { + this.pendingCommandCount--; + is(result[result.length - 1], "OK"); + + if (callback && typeof callback === "function") { + callback(result); + } + }); + }, +}; diff --git a/dom/icc/tests/marionette/test_icc_card_lock.js b/dom/icc/tests/marionette/test_icc_card_lock.js index cc47c81a22f7..29dd3b782c1f 100644 --- a/dom/icc/tests/marionette/test_icc_card_lock.js +++ b/dom/icc/tests/marionette/test_icc_card_lock.js @@ -2,31 +2,10 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ MARIONETTE_TIMEOUT = 30000; - -SpecialPowers.addPermission("mobileconnection", true, document); - -let icc = navigator.mozIccManager; -ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor); - -/* Reset pin retries by passing correct pin code. */ -function resetPinRetries(pin, callback) { - let request = icc.setCardLock( - {lockType: "pin", - pin: pin, - newPin: pin}); - - request.onsuccess = function onsuccess() { - callback(); - }; - - request.onerror = function onerror() { - is(false, "Reset pin retries got error: " + request.error.name); - callback(); - }; -} +MARIONETTE_HEAD_JS = "icc_header.js"; /* Test PIN code changes fail */ -function testPinChangeFailed() { +taskHelper.push(function testPinChangeFailed() { // The default pin is '0000' in emulator let request = icc.setCardLock( {lockType: "pin", @@ -42,12 +21,25 @@ function testPinChangeFailed() { // The default pin retries is 3, failed once becomes to 2 is(request.error.retryCount, 2); - resetPinRetries("0000", runNextTest); + // Reset pin retries by passing correct pin code. + let resetRequest = icc.setCardLock( + {lockType: "pin", + pin: "0000", + newPin: "0000"}); + + resetRequest.onsuccess = function onsuccess() { + taskHelper.runNext(); + }; + + resetRequest.onerror = function onerror() { + ok(false, "Reset pin retries got error: " + request.error.name); + taskHelper.runNext(); + }; }; -} +}); /* Test PIN code changes success */ -function testPinChangeSuccess() { +taskHelper.push(function testPinChangeSuccess() { // The default pin is '0000' in emulator let request = icc.setCardLock( {lockType: "pin", @@ -60,19 +52,19 @@ function testPinChangeSuccess() { request.onerror = function onerror() { ok(false, "Should not fail, got error: " + request.error.name); - runNextTest(); + taskHelper.runNext(); }; request.onsuccess = function onsuccess() { is(request.result.lockType, "pin"); is(request.result.success, true); - runNextTest(); + taskHelper.runNext(); }; -} +}); /* Read PIN-lock retry count */ -function testPinCardLockRetryCount() { +taskHelper.push(function testPinCardLockRetryCount() { let request = icc.getCardLockRetryCount('pin'); ok(request instanceof DOMRequest, @@ -83,7 +75,7 @@ function testPinCardLockRetryCount() { 'lockType is ' + request.result.lockType); ok(request.result.retryCount >= 0, 'retryCount is ' + request.result.retryCount); - runNextTest(); + taskHelper.runNext(); }; request.onerror = function onerror() { // The operation is optional any might not be supported for all @@ -91,12 +83,12 @@ function testPinCardLockRetryCount() { // the valid lock types. is(request.error.name, 'RequestNotSupported', 'error name is ' + request.error.name); - runNextTest(); + taskHelper.runNext(); }; -} +}); /* Read PUK-lock retry count */ -function testPukCardLockRetryCount() { +taskHelper.push(function testPukCardLockRetryCount() { let request = icc.getCardLockRetryCount('puk'); ok(request instanceof DOMRequest, @@ -107,7 +99,7 @@ function testPukCardLockRetryCount() { 'lockType is ' + request.result.lockType); ok(request.result.retryCount >= 0, 'retryCount is ' + request.result.retryCount); - runNextTest(); + taskHelper.runNext(); }; request.onerror = function onerror() { // The operation is optional any might not be supported for all @@ -115,12 +107,12 @@ function testPukCardLockRetryCount() { // the valid lock types. is(request.error.name, 'RequestNotSupported', 'error name is ' + request.error.name); - runNextTest(); + taskHelper.runNext(); }; -} +}); /* Read lock retry count for an invalid entries */ -function testInvalidCardLockRetryCount() { +taskHelper.push(function testInvalidCardLockRetryCount() { let request = icc.getCardLockRetryCount('invalid-lock-type'); ok(request instanceof DOMRequest, @@ -129,37 +121,14 @@ function testInvalidCardLockRetryCount() { request.onsuccess = function onsuccess() { ok(false, 'request should never return success for an invalid lock type'); - runNextTest(); + taskHelper.runNext(); }; request.onerror = function onerror() { is(request.error.name, 'GenericFailure', 'error name is ' + request.error.name); - runNextTest(); + taskHelper.runNext(); }; -} +}); -let tests = [ - testPinChangeFailed, - testPinChangeSuccess, - testPinCardLockRetryCount, - testPukCardLockRetryCount, - testInvalidCardLockRetryCount -]; - -function runNextTest() { - let test = tests.shift(); - if (!test) { - cleanUp(); - return; - } - - test(); -} - -function cleanUp() { - SpecialPowers.removePermission("mobileconnection", document); - - finish(); -} - -runNextTest(); +// Start test +taskHelper.runNext(); diff --git a/dom/icc/tests/marionette/test_icc_card_state.js b/dom/icc/tests/marionette/test_icc_card_state.js index 535ff77412af..5524cea630f3 100644 --- a/dom/icc/tests/marionette/test_icc_card_state.js +++ b/dom/icc/tests/marionette/test_icc_card_state.js @@ -2,40 +2,19 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ MARIONETTE_TIMEOUT = 30000; +MARIONETTE_HEAD_JS = "icc_header.js"; -SpecialPowers.addPermission("mobileconnection", true, document); -SpecialPowers.addPermission("settings-write", true, document); +function setRadioEnabled(enabled) { + SpecialPowers.addPermission("settings-write", true, document); -// Permission changes can't change existing Navigator.prototype -// objects, so grab our objects from a new Navigator -let ifr = document.createElement("iframe"); -let icc; -ifr.onload = function() { - icc = ifr.contentWindow.navigator.mozIccManager; - - ok(icc instanceof ifr.contentWindow.MozIccManager, - "icc is instanceof " + icc.constructor); - - is(icc.cardState, "ready"); - - // Enable Airplane mode, expect got cardstatechange to null - testCardStateChange(true, null, - // Disable Airplane mode, expect got cardstatechange to 'ready' - testCardStateChange.bind(window, false, "ready", cleanUp) - ); -}; -document.body.appendChild(ifr); - -function setAirplaneModeEnabled(enabled) { - let settings = ifr.contentWindow.navigator.mozSettings; + // TODO: Bug 856553 - [B2G] RIL: need an API to enable/disable radio + let settings = navigator.mozSettings; let setLock = settings.createLock(); let obj = { - "ril.radio.disabled": enabled + "ril.radio.disabled": !enabled }; let setReq = setLock.set(obj); - log("set airplane mode to " + enabled); - setReq.addEventListener("success", function onSetSuccess() { log("set 'ril.radio.disabled' to " + enabled); }); @@ -43,28 +22,37 @@ function setAirplaneModeEnabled(enabled) { setReq.addEventListener("error", function onSetError() { ok(false, "cannot set 'ril.radio.disabled' to " + enabled); }); + + SpecialPowers.removePermission("settings-write", document); } -function waitCardStateChangedEvent(expectedCardState, callback) { +/* Basic test */ +taskHelper.push(function basicTest() { + is(icc.cardState, "ready", "card state is " + icc.cardState); + taskHelper.runNext(); +}); + +/* Test cardstatechange event by switching radio off */ +taskHelper.push(function testCardStateChange() { + // Turn off radio. + setRadioEnabled(false); icc.addEventListener("cardstatechange", function oncardstatechange() { log("card state changes to " + icc.cardState); - if (icc.cardState === expectedCardState) { - log("got expected card state: " + icc.cardState); + // Expect to get card state changing to null. + if (icc.cardState === null) { icc.removeEventListener("cardstatechange", oncardstatechange); - callback(); + // We should restore radio status and wait for the cardstatechange event. + setRadioEnabled(true); + icc.addEventListener("cardstatechange", function oncardstatechange(evt) { + log("card state changes to " + icc.cardState); + if (icc.cardState === 'ready') { + icc.removeEventListener("cardstatechange", oncardstatechange); + taskHelper.runNext(); + } + }); } }); -} +}); -// Test cardstatechange event by switching airplane mode -function testCardStateChange(airplaneMode, expectedCardState, callback) { - setAirplaneModeEnabled(airplaneMode); - waitCardStateChangedEvent(expectedCardState, callback); -} - -function cleanUp() { - SpecialPowers.removePermission("mobileconnection", document); - SpecialPowers.removePermission("settings-write", document); - - finish(); -} +// Start test +taskHelper.runNext(); diff --git a/dom/icc/tests/marionette/test_icc_contact.js b/dom/icc/tests/marionette/test_icc_contact.js index 9ebd89dc684c..9ecd518b544f 100644 --- a/dom/icc/tests/marionette/test_icc_contact.js +++ b/dom/icc/tests/marionette/test_icc_contact.js @@ -2,11 +2,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ MARIONETTE_TIMEOUT = 60000; - -SpecialPowers.addPermission("mobileconnection", true, document); - -let icc = navigator.mozIccManager; -ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor); +MARIONETTE_HEAD_JS = "icc_header.js"; function testReadContacts(type) { let request = icc.readContacts(type); @@ -31,14 +27,14 @@ function testReadContacts(type) { is(contacts[3].tel[0].value, "15555218204"); is(contacts[3].id, "890141032111185107204"); - runNextTest(); + taskHelper.runNext(); }; request.onerror = function onerror() { ok(false, "Cannot get " + type + " contacts"); - runNextTest(); + taskHelper.runNext(); }; -}; +} function testAddContact(type, pin2) { let contact = new mozContact({ @@ -63,12 +59,12 @@ function testAddContact(type, pin2) { is(contacts[4].name[0], "add"); is(contacts[4].tel[0].value, "0912345678"); - runNextTest(); + taskHelper.runNext(); }; getRequest.onerror = function onerror() { ok(false, "Cannot get " + type + " contacts: " + getRequest.error.name); - runNextTest(); + taskHelper.runNext(); }; }; @@ -79,47 +75,34 @@ function testAddContact(type, pin2) { } else { ok(false, "Cannot add " + type + " contact: " + updateRequest.error.name); } - runNextTest(); + taskHelper.runNext(); }; -}; +} -function testReadAdnContacts() { +/* Test read adn contacts */ +taskHelper.push(function testReadAdnContacts() { testReadContacts("adn"); -} +}); -function testAddAdnContact() { +/* Test add adn contacts */ +taskHelper.push(function testAddAdnContact() { testAddContact("adn"); -} +}); -function testReadFdnContacts() { +/* Test read fdn contacts */ +taskHelper.push(function testReadAdnContacts() { testReadContacts("fdn"); -} +}); -function testAddFdnContact() { +/* Test add fdn contacts */ +taskHelper.push(function testReadAdnContacts() { testAddContact("fdn", "0000"); +}); + +/* Test add fdn contacts without passing pin2 */ +taskHelper.push(function testReadAdnContacts() { testAddContact("fdn"); -} +}); -let tests = [ - testReadAdnContacts, - testAddAdnContact, - testReadFdnContacts, - testAddFdnContact -]; - -function runNextTest() { - let test = tests.pop(); - if (!test) { - cleanUp(); - return; - } - - test(); -} - -function cleanUp() { - SpecialPowers.removePermission("mobileconnection", document); - finish(); -} - -runNextTest(); +// Start test +taskHelper.runNext(); diff --git a/dom/icc/tests/marionette/test_icc_info.js b/dom/icc/tests/marionette/test_icc_info.js index 3ef9e1a933a3..3940ccae2f3f 100644 --- a/dom/icc/tests/marionette/test_icc_info.js +++ b/dom/icc/tests/marionette/test_icc_info.js @@ -2,27 +2,46 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ MARIONETTE_TIMEOUT = 30000; +MARIONETTE_HEAD_JS = "icc_header.js"; -SpecialPowers.addPermission("mobileconnection", true, document); +function setRadioEnabled(enabled) { + SpecialPowers.addPermission("settings-write", true, document); -// Permission changes can't change existing Navigator.prototype -// objects, so grab our objects from a new Navigator -let ifr = document.createElement("iframe"); -let icc; -let iccInfo; -ifr.onload = function() { - icc = ifr.contentWindow.navigator.mozIccManager; - ok(icc instanceof ifr.contentWindow.MozIccManager, - "icc is instanceof " + icc.constructor); + // TODO: Bug 856553 - [B2G] RIL: need an API to enable/disable radio + let settings = navigator.mozSettings; + let setLock = settings.createLock(); + let obj = { + "ril.radio.disabled": !enabled + }; + let setReq = setLock.set(obj); - iccInfo = icc.iccInfo; + setReq.addEventListener("success", function onSetSuccess() { + log("set 'ril.radio.disabled' to " + enabled); + }); + + setReq.addEventListener("error", function onSetError() { + ok(false, "cannot set 'ril.radio.disabled' to " + enabled); + }); + + SpecialPowers.removePermission("settings-write", document); +} + +function setEmulatorMccMnc(mcc, mnc) { + let cmd = "operator set 0 Android,Android," + mcc + mnc; + emulatorHelper.sendCommand(cmd, function (result) { + let re = new RegExp("" + mcc + mnc + "$"); + ok(result[0].match(re), "MCC/MNC should be changed."); + }); +} + +/* Basic test */ +taskHelper.push(function basicTest() { + let iccInfo = icc.iccInfo; is(iccInfo.iccType, "sim"); - // The emulator's hard coded iccid value. // See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299. is(iccInfo.iccid, 89014103211118510720); - // The emulator's hard coded mcc and mnc codes. // See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465. is(iccInfo.mcc, 310); @@ -32,103 +51,27 @@ ifr.onload = function() { // See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io() is(iccInfo.msisdn, "15555215554"); - runNextTest(); -}; -document.body.appendChild(ifr); + taskHelper.runNext(); +}); -let emulatorCmdPendingCount = 0; -function sendEmulatorCommand(cmd, callback) { - emulatorCmdPendingCount++; - runEmulatorCmd(cmd, function (result) { - emulatorCmdPendingCount--; - is(result[result.length - 1], "OK"); - callback(result); - }); -} +/* Test display condition change */ +taskHelper.push(function testDisplayConditionChange() { + function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired, + expectedIsDisplaySpnRequired, callback) { + icc.addEventListener("iccinfochange", function handler() { + icc.removeEventListener("iccinfochange", handler); + is(icc.iccInfo.isDisplayNetworkNameRequired, + expectedIsDisplayNetworkNameRequired); + is(icc.iccInfo.isDisplaySpnRequired, + expectedIsDisplaySpnRequired); + // operatorchange will be ignored if we send commands too soon. + window.setTimeout(callback, 100); + }); + // Send emulator command to change network mcc and mnc. + setEmulatorMccMnc(mcc, mnc); + } -function setEmulatorMccMnc(mcc, mnc) { - let cmd = "operator set 0 Android,Android," + mcc + mnc; - sendEmulatorCommand(cmd, function (result) { - let re = new RegExp("" + mcc + mnc + "$"); - ok(result[0].match(re), "MCC/MNC should be changed."); - }); -} - -function setAirplaneModeEnabled(enabled) { - let settings = ifr.contentWindow.navigator.mozSettings; - let setLock = settings.createLock(); - let obj = { - "ril.radio.disabled": enabled - }; - let setReq = setLock.set(obj); - - log("set airplane mode to " + enabled); - - setReq.addEventListener("success", function onSetSuccess() { - log("set 'ril.radio.disabled' to " + enabled); - }); - - setReq.addEventListener("error", function onSetError() { - ok(false, "cannot set 'ril.radio.disabled' to " + enabled); - }); -} - -function waitForIccInfoChange(callback) { - icc.addEventListener("iccinfochange", function handler() { - icc.removeEventListener("iccinfochange", handler); - callback(); - }); -} - -function waitForCardStateChange(expectedCardState, callback) { - icc.addEventListener("cardstatechange", function oncardstatechange() { - log("card state changes to " + icc.cardState); - if (icc.cardState === expectedCardState) { - log("got expected card state: " + icc.cardState); - icc.removeEventListener("cardstatechange", oncardstatechange); - callback(); - } - }); -} - -// Test display condition change. -function testDisplayConditionChange(func, caseArray, oncomplete) { - (function do_call(index) { - let next = index < (caseArray.length - 1) ? do_call.bind(null, index + 1) : oncomplete; - caseArray[index].push(next); - func.apply(null, caseArray[index]); - })(0); -} - -function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired, - expectedIsDisplaySpnRequired, callback) { - waitForIccInfoChange(function() { - is(iccInfo.isDisplayNetworkNameRequired, - expectedIsDisplayNetworkNameRequired); - is(iccInfo.isDisplaySpnRequired, - expectedIsDisplaySpnRequired); - // operatorchange will be ignored if we send commands too soon. - window.setTimeout(callback, 100); - }); - setEmulatorMccMnc(mcc, mnc); -} - -// Test iccInfo when card is not ready -function testCardIsNotReady() { - // Enable airplane mode - setAirplaneModeEnabled(true); - - waitForCardStateChange(null, function callback() { - is(icc.iccInfo, null); - - // Disable airplane mode - setAirplaneModeEnabled(false); - waitForCardStateChange("ready", runNextTest); - }); -} - -let tests = [ - testDisplayConditionChange.bind(this, testSPN, [ + let testCases = [ // [MCC, MNC, isDisplayNetworkNameRequired, isDisplaySpnRequired] [123, 456, false, true], // Not in HPLMN. [234, 136, true, true], // Not in HPLMN, but in PLMN specified in SPDI. @@ -136,21 +79,35 @@ let tests = [ [466, 92, true, true], // Not in HPLMN, but in another PLMN specified in SPDI. [123, 456, false, true], // Not in HPLMN. Triggering iccinfochange [310, 260, true, true], // inside HPLMN. - ], runNextTest), - testCardIsNotReady -]; + ]; -function runNextTest() { - let test = tests.shift(); - if (!test) { - finalize(); - return; - } + (function do_call(index) { + let next = index < (testCases.length - 1) ? do_call.bind(null, index + 1) : taskHelper.runNext.bind(taskHelper); + testCases[index].push(next); + testSPN.apply(null, testCases[index]); + })(0); +}); - test(); -} +/* Test iccInfo when card becomes undetected */ +taskHelper.push(function testCardIsNotReady() { + // Turn off radio. + setRadioEnabled(false); + icc.addEventListener("iccinfochange", function oniccinfochange() { + // Expect iccInfo changes to null + if (icc.iccInfo === null) { + icc.removeEventListener("iccinfochange", oniccinfochange); + // We should restore radio status and wait for the cardstatechange event. + setRadioEnabled(true); + icc.addEventListener("cardstatechange", function oncardstatechange(evt) { + log("card state changes to " + icc.cardState); + if (icc.cardState === 'ready') { + icc.removeEventListener("cardstatechange", oncardstatechange); + taskHelper.runNext(); + } + }); + } + }); +}); -function finalize() { - SpecialPowers.removePermission("mobileconnection", document); - finish(); -} +// Start test +taskHelper.runNext(); From 5a7cba4ad2d2d85cd8d0ed5b52e869e4ced81550 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 31 Oct 2013 12:14:45 +0800 Subject: [PATCH 137/268] Bug 814637 - Part 6: Marionette tests changes for new IccManager API. r=hsinyi --- dom/icc/tests/marionette/icc_header.js | 21 ++- dom/icc/tests/marionette/manifest.ini | 4 + dom/icc/tests/marionette/stk_helper.js | 20 ++- .../test_icc_access_invalid_object.js | 121 ++++++++++++++++++ .../tests/marionette/test_icc_card_state.js | 12 +- .../test_icc_detected_undetected_event.js | 72 +++++++++++ dom/icc/tests/marionette/test_icc_info.js | 12 +- .../tests/marionette/test_stk_display_text.js | 4 +- .../tests/marionette/test_stk_get_inkey.js | 4 +- .../tests/marionette/test_stk_get_input.js | 2 +- .../marionette/test_stk_launch_browser.js | 2 +- dom/icc/tests/marionette/test_stk_poll_off.js | 2 +- .../marionette/test_stk_proactive_command.js | 44 +++---- dom/icc/tests/marionette/test_stk_refresh.js | 2 +- .../tests/marionette/test_stk_select_item.js | 2 +- .../tests/marionette/test_stk_send_dtmf.js | 2 +- dom/icc/tests/marionette/test_stk_send_sms.js | 2 +- dom/icc/tests/marionette/test_stk_send_ss.js | 2 +- .../tests/marionette/test_stk_send_ussd.js | 2 +- .../tests/marionette/test_stk_setup_call.js | 6 +- .../marionette/test_stk_setup_event_list.js | 2 +- .../test_stk_setup_idle_mode_text.js | 2 +- .../tests/marionette/test_stk_setup_menu.js | 6 +- .../marionette/test_outgoing_radio_off.js | 15 +-- 24 files changed, 293 insertions(+), 70 deletions(-) create mode 100644 dom/icc/tests/marionette/test_icc_access_invalid_object.js create mode 100644 dom/icc/tests/marionette/test_icc_detected_undetected_event.js diff --git a/dom/icc/tests/marionette/icc_header.js b/dom/icc/tests/marionette/icc_header.js index 9b72ab68f026..670d624eae34 100644 --- a/dom/icc/tests/marionette/icc_header.js +++ b/dom/icc/tests/marionette/icc_header.js @@ -3,9 +3,24 @@ SpecialPowers.addPermission("mobileconnection", true, document); -let icc = navigator.mozIccManager; -ok(icc instanceof MozIccManager, - "icc is instanceof " + icc.constructor); +let iccManager = navigator.mozIccManager; +ok(iccManager instanceof MozIccManager, + "iccManager is instanceof " + iccManager.constructor); + +// TODO: Bug 932650 - B2G RIL: WebIccManager API - add marionette tests for +// multi-sim +// In single sim scenario, there is only one sim card, we can use below way to +// check iccId and get icc object. But in multi-sim, the index of iccIds may +// not map to sim slot directly, we should have a better way to handle this. +let iccIds = iccManager.iccIds; +ok(Array.isArray(iccIds), "iccIds is an array"); +is(iccIds.length, 1, "iccIds.length is " + iccIds.length); + +let iccId = iccIds[0]; +is(iccId, "89014103211118510720", "iccId is " + iccId); + +let icc = iccManager.getIccById(iccId); +ok(icc instanceof MozIcc, "icc is instanceof " + icc.constructor); /* Remove permission and execute finish() */ let cleanUp = function () { diff --git a/dom/icc/tests/marionette/manifest.ini b/dom/icc/tests/marionette/manifest.ini index 480ce3b3bd79..f336e0cb22b1 100644 --- a/dom/icc/tests/marionette/manifest.ini +++ b/dom/icc/tests/marionette/manifest.ini @@ -22,3 +22,7 @@ qemu = true [test_stk_select_item.js] [test_stk_setup_menu.js] [test_stk_setup_idle_mode_text.js] +[test_icc_access_invalid_object.js] +disabled = Bug 933654 +[test_icc_detected_undetected_event.js] +disabled = Bug 933654 diff --git a/dom/icc/tests/marionette/stk_helper.js b/dom/icc/tests/marionette/stk_helper.js index f29f153d8fb3..09f20f64d712 100644 --- a/dom/icc/tests/marionette/stk_helper.js +++ b/dom/icc/tests/marionette/stk_helper.js @@ -5,8 +5,24 @@ MARIONETTE_TIMEOUT = 30000; SpecialPowers.addPermission("mobileconnection", true, document); -let icc = navigator.mozIccManager; -ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor); +let iccManager = navigator.mozIccManager; +ok(iccManager instanceof MozIccManager, + "iccManager is instanceof " + iccManager.constructor); + +// TODO: Bug 932650 - B2G RIL: WebIccManager API - add marionette tests for +// multi-sim +// In single sim scenario, there is only one sim card, we can use below way to +// check iccId and get icc object. But in multi-sim, the index of iccIds may +// not map to sim slot directly, we should have a better way to handle this. +let iccIds = iccManager.iccIds; +ok(Array.isArray(iccIds), "iccIds is an array"); +is(iccIds.length, 1, "iccIds.length is " + iccIds.length); + +let iccId = iccIds[0]; +is(iccId, "89014103211118510720", "iccId is " + iccId); + +let icc = iccManager.getIccById(iccId); +ok(icc instanceof MozIcc, "icc is instanceof " + icc.constructor); let pendingEmulatorCmdCount = 0; function sendStkPduToEmulator(command, func, expect) { diff --git a/dom/icc/tests/marionette/test_icc_access_invalid_object.js b/dom/icc/tests/marionette/test_icc_access_invalid_object.js new file mode 100644 index 000000000000..98628ac2196f --- /dev/null +++ b/dom/icc/tests/marionette/test_icc_access_invalid_object.js @@ -0,0 +1,121 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 30000; +MARIONETTE_HEAD_JS = "icc_header.js"; + +function setRadioEnabled(enabled) { + SpecialPowers.addPermission("settings-write", true, document); + + // TODO: Bug 856553 - [B2G] RIL: need an API to enable/disable radio + let settings = navigator.mozSettings; + let setLock = settings.createLock(); + let obj = { + "ril.radio.disabled": !enabled + }; + let setReq = setLock.set(obj); + + setReq.addEventListener("success", function onSetSuccess() { + log("set 'ril.radio.disabled' to " + enabled); + }); + + setReq.addEventListener("error", function onSetError() { + ok(false, "cannot set 'ril.radio.disabled' to " + enabled); + }); + + SpecialPowers.removePermission("settings-write", document); +} + +/* Test access invalid icc object */ +taskHelper.push(function testAccessRemovedIccObject() { + setRadioEnabled(false); + iccManager.addEventListener("iccundetected", function oniccundetected(evt) { + log("got icc undetected event"); + iccManager.removeEventListener("iccundetected", oniccundetected); + is(evt.iccId, iccId, "icc " + evt.iccId + " becomes undetected"); + + // Test access iccInfo. + try { + is(icc.iccInfo, null, "iccInfo: expect to get null"); + } catch(e) { + ok(false, "access iccInfo should not get exception"); + } + + // Test access cardState. + try { + is(icc.cardState, null, "cardState: expect to get null"); + } catch(e) { + ok(false, "access cardState should not get exception"); + } + + // Test STK related function. + try { + icc.sendStkResponse({}, {}); + ok(false, "sendStkResponse() should get exception"); + } catch(e) {} + try { + icc.sendStkMenuSelection(0, false); + ok(false, "sendStkMenuSelection() should get exception"); + } catch(e) {} + try { + icc.sendStkTimerExpiration({}); + ok(false, "sendStkTimerExpiration() should get exception"); + } catch(e) {} + try { + icc.sendStkEventDownload({}); + ok(false, "sendStkEventDownload() should get exception"); + } catch(e) {} + + // Test card lock related function. + try { + icc.getCardLock(""); + ok(false, "getCardLock() should get exception"); + } catch(e) {} + try { + icc.unlockCardLock({}); + ok(false, "unlockCardLock() should get exception"); + } catch(e) {} + try { + icc.setCardLock({}); + ok(false, "setCardLock() should get exception"); + } catch(e) {} + try { + icc.getCardLockRetryCount(""); + ok(false, "getCardLockRetryCount() should get exception"); + } catch(e) {} + + // Test contact related function. + try { + icc.readContacts(""); + ok(false, "readContacts() should get exception"); + } catch(e) {} + try { + icc.updateContact("", {}); + ok(false, "updateContact() should get exception"); + } catch(e) {} + + // Test secure element related function. + try { + icc.iccOpenChannel(""); + ok(false, "iccOpenChannel() should get exception"); + } catch(e) {} + try { + icc.iccExchangeAPDU(0, {}); + ok(false, "iccExchangeAPDU() should get exception"); + } catch(e) {} + try { + icc.iccCloseChannel(0); + ok(false, "iccCloseChannel() should get exception"); + } catch(e) {} + + // We should restore the radio status. + setRadioEnabled(true); + iccManager.addEventListener("iccdetected", function oniccdetected(evt) { + iccManager.removeEventListener("iccdetected", oniccdetected); + taskHelper.runNext(); + }); + }); +}); + +// Start test +taskHelper.runNext(); diff --git a/dom/icc/tests/marionette/test_icc_card_state.js b/dom/icc/tests/marionette/test_icc_card_state.js index 5524cea630f3..adbed3346e77 100644 --- a/dom/icc/tests/marionette/test_icc_card_state.js +++ b/dom/icc/tests/marionette/test_icc_card_state.js @@ -41,14 +41,12 @@ taskHelper.push(function testCardStateChange() { // Expect to get card state changing to null. if (icc.cardState === null) { icc.removeEventListener("cardstatechange", oncardstatechange); - // We should restore radio status and wait for the cardstatechange event. + // We should restore radio status and expect to get iccdetected event. setRadioEnabled(true); - icc.addEventListener("cardstatechange", function oncardstatechange(evt) { - log("card state changes to " + icc.cardState); - if (icc.cardState === 'ready') { - icc.removeEventListener("cardstatechange", oncardstatechange); - taskHelper.runNext(); - } + iccManager.addEventListener("iccdetected", function oniccdetected(evt) { + log("icc iccdetected: " + evt.iccId); + iccManager.removeEventListener("iccdetected", oniccdetected); + taskHelper.runNext(); }); } }); diff --git a/dom/icc/tests/marionette/test_icc_detected_undetected_event.js b/dom/icc/tests/marionette/test_icc_detected_undetected_event.js new file mode 100644 index 000000000000..a8e270569c94 --- /dev/null +++ b/dom/icc/tests/marionette/test_icc_detected_undetected_event.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 30000; +MARIONETTE_HEAD_JS = "icc_header.js"; + +function setRadioEnabled(enabled) { + SpecialPowers.addPermission("settings-write", true, document); + + // TODO: Bug 856553 - [B2G] RIL: need an API to enable/disable radio + let settings = navigator.mozSettings; + let setLock = settings.createLock(); + let obj = { + "ril.radio.disabled": !enabled + }; + let setReq = setLock.set(obj); + + setReq.addEventListener("success", function onSetSuccess() { + log("set 'ril.radio.disabled' to " + enabled); + }); + + setReq.addEventListener("error", function onSetError() { + ok(false, "cannot set 'ril.radio.disabled' to " + enabled); + }); + + SpecialPowers.removePermission("settings-write", document); +} + +/* Test iccundetected event */ +taskHelper.push(function testIccUndetectedEvent() { + setRadioEnabled(false); + iccManager.addEventListener("iccundetected", function oniccundetected(evt) { + log("got icc undetected event"); + iccManager.removeEventListener("iccundetected", oniccundetected); + + // TODO: Bug 932650 - B2G RIL: WebIccManager API - add marionette tests for + // multi-sim + // In single sim scenario, there is only one sim card, we can use below way + // to check iccIds. + is(evt.iccId, iccId, "icc " + evt.iccId + " becomes undetected"); + is(iccManager.iccIds.length, 0, + "iccIds.length becomes to " + iccManager.iccIds.length); + is(iccManager.getIccById(evt.iccId), null, + "should not get a valid icc object here"); + + taskHelper.runNext(); + }); +}); + +/* Test iccdetected event */ +taskHelper.push(function testIccDetectedEvent() { + setRadioEnabled(true); + iccManager.addEventListener("iccdetected", function oniccdetected(evt) { + log("got icc detected event"); + iccManager.removeEventListener("iccdetected", oniccdetected); + + // TODO: Bug 932650 - B2G RIL: WebIccManager API - add marionette tests for + // multi-sim + // In single sim scenario, there is only one sim card, we can use below way + // to check iccIds. + is(evt.iccId, iccId, "icc " + evt.iccId + " is detected"); + is(iccManager.iccIds.length, 1, + "iccIds.length becomes to " + iccManager.iccIds.length); + ok(iccManager.getIccById(evt.iccId) instanceof MozIcc, + "should get a valid icc object here"); + + taskHelper.runNext(); + }); +}); + +// Start test +taskHelper.runNext(); diff --git a/dom/icc/tests/marionette/test_icc_info.js b/dom/icc/tests/marionette/test_icc_info.js index 3940ccae2f3f..16619bd6bad1 100644 --- a/dom/icc/tests/marionette/test_icc_info.js +++ b/dom/icc/tests/marionette/test_icc_info.js @@ -96,14 +96,12 @@ taskHelper.push(function testCardIsNotReady() { // Expect iccInfo changes to null if (icc.iccInfo === null) { icc.removeEventListener("iccinfochange", oniccinfochange); - // We should restore radio status and wait for the cardstatechange event. + // We should restore radio status and expect to get iccdetected event. setRadioEnabled(true); - icc.addEventListener("cardstatechange", function oncardstatechange(evt) { - log("card state changes to " + icc.cardState); - if (icc.cardState === 'ready') { - icc.removeEventListener("cardstatechange", oncardstatechange); - taskHelper.runNext(); - } + iccManager.addEventListener("iccdetected", function oniccdetected(evt) { + log("icc detected: " + evt.iccId); + iccManager.removeEventListener("iccdetected", oniccdetected); + taskHelper.runNext(); }); } }); diff --git a/dom/icc/tests/marionette/test_stk_display_text.js b/dom/icc/tests/marionette/test_stk_display_text.js index d8ce3cf50339..61f76054f241 100644 --- a/dom/icc/tests/marionette/test_stk_display_text.js +++ b/dom/icc/tests/marionette/test_stk_display_text.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testDisplayText(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_DISPLAY_TEXT, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_DISPLAY_TEXT, expect.name); is(command.options.text, expect.text, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.userClear, expect.userClear, expect.name); @@ -87,7 +87,7 @@ let tests = [ commandQualifier: 0x80, text: "10 Second", userClear: true, - duration: {timeUnit: icc.STK_TIME_UNIT_SECOND, + duration: {timeUnit: iccManager.STK_TIME_UNIT_SECOND, timeInterval: 0x0A}}}, ]; diff --git a/dom/icc/tests/marionette/test_stk_get_inkey.js b/dom/icc/tests/marionette/test_stk_get_inkey.js index 7620262c0d1f..f74f1075116e 100644 --- a/dom/icc/tests/marionette/test_stk_get_inkey.js +++ b/dom/icc/tests/marionette/test_stk_get_inkey.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testGetInKey(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_GET_INKEY, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_GET_INKEY, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.text, expect.text, expect.name); is(command.options.isAlphabet, expect.isAlphabet, expect.name); @@ -98,7 +98,7 @@ let tests = [ expect: {name: "get_inkey_cmd_14", commandQualifier: 0x00, text: "Enter \"+\"", - duration: {timeUnit: icc.STK_TIME_UNIT_SECOND, + duration: {timeUnit: iccManager.STK_TIME_UNIT_SECOND, timeInterval: 0x0A}}}, ]; diff --git a/dom/icc/tests/marionette/test_stk_get_input.js b/dom/icc/tests/marionette/test_stk_get_input.js index 2de92e5fe140..ef44880776bb 100644 --- a/dom/icc/tests/marionette/test_stk_get_input.js +++ b/dom/icc/tests/marionette/test_stk_get_input.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testGetInput(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_GET_INPUT, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_GET_INPUT, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.text, expect.text, expect.name); is(command.options.minLength, expect.minLength, expect.name); diff --git a/dom/icc/tests/marionette/test_stk_launch_browser.js b/dom/icc/tests/marionette/test_stk_launch_browser.js index 416b7112c301..0888f42ca75a 100644 --- a/dom/icc/tests/marionette/test_stk_launch_browser.js +++ b/dom/icc/tests/marionette/test_stk_launch_browser.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testLaunchBrowser(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_LAUNCH_BROWSER, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_LAUNCH_BROWSER, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.url, expect.url, expect.name); if (command.options.confirmMessage) { diff --git a/dom/icc/tests/marionette/test_stk_poll_off.js b/dom/icc/tests/marionette/test_stk_poll_off.js index 166007d9f9a7..8f3d32abef39 100644 --- a/dom/icc/tests/marionette/test_stk_poll_off.js +++ b/dom/icc/tests/marionette/test_stk_poll_off.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testPollOff(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_POLL_OFF, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_POLL_OFF, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); runNextTest(); diff --git a/dom/icc/tests/marionette/test_stk_proactive_command.js b/dom/icc/tests/marionette/test_stk_proactive_command.js index b10e2be0fe94..c78093327df2 100644 --- a/dom/icc/tests/marionette/test_stk_proactive_command.js +++ b/dom/icc/tests/marionette/test_stk_proactive_command.js @@ -5,47 +5,47 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testLocalInfoLocation(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO); + is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO); is(cmd.commandNumber, 0x01); - is(cmd.commandQualifier, icc.STK_LOCAL_INFO_LOCATION_INFO); - is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_LOCATION_INFO); + is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_LOCATION_INFO); + is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_LOCATION_INFO); runNextTest(); } function testLocalInfoImei(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO); + is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO); is(cmd.commandNumber, 0x01); - is(cmd.commandQualifier, icc.STK_LOCAL_INFO_IMEI); - is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_IMEI); + is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_IMEI); + is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_IMEI); runNextTest(); } function testLocalInfoDate(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO); + is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO); is(cmd.commandNumber, 0x01); - is(cmd.commandQualifier, icc.STK_LOCAL_INFO_DATE_TIME_ZONE); - is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_DATE_TIME_ZONE); + is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_DATE_TIME_ZONE); + is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_DATE_TIME_ZONE); runNextTest(); } function testLocalInfoLanguage(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_PROVIDE_LOCAL_INFO); + is(cmd.typeOfCommand, iccManager.STK_CMD_PROVIDE_LOCAL_INFO); is(cmd.commandNumber, 0x01); - is(cmd.commandQualifier, icc.STK_LOCAL_INFO_LANGUAGE); - is(cmd.options.localInfoType, icc.STK_LOCAL_INFO_LANGUAGE); + is(cmd.commandQualifier, iccManager.STK_LOCAL_INFO_LANGUAGE); + is(cmd.options.localInfoType, iccManager.STK_LOCAL_INFO_LANGUAGE); runNextTest(); } function testRefresh(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_REFRESH); + is(cmd.typeOfCommand, iccManager.STK_CMD_REFRESH); is(cmd.commandNumber, 0x01); is(cmd.commandQualifier, 0x01); is(cmd.options, null); @@ -55,10 +55,10 @@ function testRefresh(cmd) { function testTimerManagementStart(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_TIMER_MANAGEMENT); + is(cmd.typeOfCommand, iccManager.STK_CMD_TIMER_MANAGEMENT); is(cmd.commandNumber, 0x01); - is(cmd.commandQualifier, icc.STK_TIMER_START); - is(cmd.options.timerAction, icc.STK_TIMER_START); + is(cmd.commandQualifier, iccManager.STK_TIMER_START); + is(cmd.options.timerAction, iccManager.STK_TIMER_START); is(cmd.options.timerId, 0x01); is(cmd.options.timerValue, (0x01 * 60 * 60) + (0x02 * 60) + 0x03); @@ -67,10 +67,10 @@ function testTimerManagementStart(cmd) { function testTimerManagementDeactivate(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_TIMER_MANAGEMENT); + is(cmd.typeOfCommand, iccManager.STK_CMD_TIMER_MANAGEMENT); is(cmd.commandNumber, 0x01); - is(cmd.commandQualifier, icc.STK_TIMER_DEACTIVATE); - is(cmd.options.timerAction, icc.STK_TIMER_DEACTIVATE); + is(cmd.commandQualifier, iccManager.STK_TIMER_DEACTIVATE); + is(cmd.options.timerAction, iccManager.STK_TIMER_DEACTIVATE); is(cmd.options.timerId, 0x04); runNextTest(); @@ -78,10 +78,10 @@ function testTimerManagementDeactivate(cmd) { function testTimerManagementGetCurrentValue(cmd) { log("STK CMD " + JSON.stringify(cmd)); - is(cmd.typeOfCommand, icc.STK_CMD_TIMER_MANAGEMENT); + is(cmd.typeOfCommand, iccManager.STK_CMD_TIMER_MANAGEMENT); is(cmd.commandNumber, 0x01); - is(cmd.commandQualifier, icc.STK_TIMER_GET_CURRENT_VALUE); - is(cmd.options.timerAction, icc.STK_TIMER_GET_CURRENT_VALUE); + is(cmd.commandQualifier, iccManager.STK_TIMER_GET_CURRENT_VALUE); + is(cmd.options.timerAction, iccManager.STK_TIMER_GET_CURRENT_VALUE); is(cmd.options.timerId, 0x08); runNextTest(); diff --git a/dom/icc/tests/marionette/test_stk_refresh.js b/dom/icc/tests/marionette/test_stk_refresh.js index 5a137a672275..bd1add02af18 100644 --- a/dom/icc/tests/marionette/test_stk_refresh.js +++ b/dom/icc/tests/marionette/test_stk_refresh.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testRefresh(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_REFRESH, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_REFRESH, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); runNextTest(); diff --git a/dom/icc/tests/marionette/test_stk_select_item.js b/dom/icc/tests/marionette/test_stk_select_item.js index 413b09c23a61..9150a8a6e45c 100644 --- a/dom/icc/tests/marionette/test_stk_select_item.js +++ b/dom/icc/tests/marionette/test_stk_select_item.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSelectItem(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SELECT_ITEM, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SELECT_ITEM, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.title, expect.title, expect.name); for (let index in command.options.items) { diff --git a/dom/icc/tests/marionette/test_stk_send_dtmf.js b/dom/icc/tests/marionette/test_stk_send_dtmf.js index f12e7cb540fa..9760b5849bd3 100644 --- a/dom/icc/tests/marionette/test_stk_send_dtmf.js +++ b/dom/icc/tests/marionette/test_stk_send_dtmf.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSendDTMF(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SEND_DTMF, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SEND_DTMF, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); if (command.options.text) { is(command.options.text, expect.text, expect.name); diff --git a/dom/icc/tests/marionette/test_stk_send_sms.js b/dom/icc/tests/marionette/test_stk_send_sms.js index ec428cdc9fe8..dd12cb9cf11b 100644 --- a/dom/icc/tests/marionette/test_stk_send_sms.js +++ b/dom/icc/tests/marionette/test_stk_send_sms.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSendSMS(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SEND_SMS, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SEND_SMS, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); if (command.options.text) { is(command.options.text, expect.title, expect.name); diff --git a/dom/icc/tests/marionette/test_stk_send_ss.js b/dom/icc/tests/marionette/test_stk_send_ss.js index 8385d082f122..48dfcdc047d4 100644 --- a/dom/icc/tests/marionette/test_stk_send_ss.js +++ b/dom/icc/tests/marionette/test_stk_send_ss.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSendSS(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SEND_SS, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SEND_SS, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); if (command.options.text) { is(command.options.text, expect.title, expect.name); diff --git a/dom/icc/tests/marionette/test_stk_send_ussd.js b/dom/icc/tests/marionette/test_stk_send_ussd.js index b2cfa81b39a5..41812a63056c 100644 --- a/dom/icc/tests/marionette/test_stk_send_ussd.js +++ b/dom/icc/tests/marionette/test_stk_send_ussd.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSendUSSD(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SEND_USSD, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SEND_USSD, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); if (command.options.text) { is(command.options.text, expect.title, expect.name); diff --git a/dom/icc/tests/marionette/test_stk_setup_call.js b/dom/icc/tests/marionette/test_stk_setup_call.js index c4c278fdf7b2..e70f1a76e6f0 100644 --- a/dom/icc/tests/marionette/test_stk_setup_call.js +++ b/dom/icc/tests/marionette/test_stk_setup_call.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSetupCall(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SET_UP_CALL, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SET_UP_CALL, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.confirmMessage, expect.confirmMessage, expect.name); is(command.options.address, expect.address, expect.name); @@ -68,7 +68,7 @@ let tests = [ commandQualifier: 0x01, confirmMessage: "Duration", address: "+012340123456,1,2", - duration: {timeUnit: icc.STK_TIME_UNIT_SECOND, + duration: {timeUnit: iccManager.STK_TIME_UNIT_SECOND, timeInterval: 0x0A}}}, {command: "d028810301100082028183850c434f4e4649524d4154494f4e8609911032042143651c2c850443414c4c", func: testSetupCall, @@ -336,7 +336,7 @@ let tests = [ commandQualifier: 0x00, confirmMessage: "Not busy", address: "+012340123456,1,2", - duration: {timeUnit: icc.STK_TIME_UNIT_SECOND, + duration: {timeUnit: iccManager.STK_TIME_UNIT_SECOND, timeInterval: 0x0A}}}, ]; diff --git a/dom/icc/tests/marionette/test_stk_setup_event_list.js b/dom/icc/tests/marionette/test_stk_setup_event_list.js index 24eff85cfe44..ac3033776f08 100644 --- a/dom/icc/tests/marionette/test_stk_setup_event_list.js +++ b/dom/icc/tests/marionette/test_stk_setup_event_list.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSetupEventList(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SET_UP_EVENT_LIST, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SET_UP_EVENT_LIST, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); for (let index in command.options.eventList) { is(command.options.eventList[index], expect.eventList[index], expect.name); diff --git a/dom/icc/tests/marionette/test_stk_setup_idle_mode_text.js b/dom/icc/tests/marionette/test_stk_setup_idle_mode_text.js index ae513cb1713e..6e4b5c912a1e 100644 --- a/dom/icc/tests/marionette/test_stk_setup_idle_mode_text.js +++ b/dom/icc/tests/marionette/test_stk_setup_idle_mode_text.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSetupIdleModeText(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SET_UP_IDLE_MODE_TEXT, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SET_UP_IDLE_MODE_TEXT, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.text, expect.text, expect.name); diff --git a/dom/icc/tests/marionette/test_stk_setup_menu.js b/dom/icc/tests/marionette/test_stk_setup_menu.js index 11074590d0d5..d42e9ff346a6 100644 --- a/dom/icc/tests/marionette/test_stk_setup_menu.js +++ b/dom/icc/tests/marionette/test_stk_setup_menu.js @@ -5,7 +5,7 @@ MARIONETTE_HEAD_JS = "stk_helper.js"; function testSetupMenu(command, expect) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SET_UP_MENU, expect.name); + is(command.typeOfCommand, iccManager.STK_CMD_SET_UP_MENU, expect.name); is(command.commandQualifier, expect.commandQualifier, expect.name); is(command.options.title, expect.title, expect.name); for (let index in command.options.items) { @@ -22,14 +22,14 @@ function isFirstMenuItemNull(command) { function testInitialSetupMenu(command) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SET_UP_MENU); + is(command.typeOfCommand, iccManager.STK_CMD_SET_UP_MENU); is(isFirstMenuItemNull(command), false); runNextTest(); } function testRemoveSetupMenu(command) { log("STK CMD " + JSON.stringify(command)); - is(command.typeOfCommand, icc.STK_CMD_SET_UP_MENU); + is(command.typeOfCommand, iccManager.STK_CMD_SET_UP_MENU); is(isFirstMenuItemNull(command), true); runNextTest(); diff --git a/dom/telephony/test/marionette/test_outgoing_radio_off.js b/dom/telephony/test/marionette/test_outgoing_radio_off.js index 28bd699e1aec..35faa87e2e90 100644 --- a/dom/telephony/test/marionette/test_outgoing_radio_off.js +++ b/dom/telephony/test/marionette/test_outgoing_radio_off.js @@ -26,14 +26,13 @@ function changeSetting(key, value, callback) { function setRadioEnabled(enabled, callback) { changeSetting("ril.radio.disabled", !enabled, function() { - icc.addEventListener("cardstatechange", function handler() { - // Wait until card state changes to "ready" after turning on radio. - // Wait until card state changes to "not-ready" after turning off radio. - if ((enabled && icc.cardState == "ready") || - (!enabled && icc.cardState != "ready")) { - icc.removeEventListener("cardstatechange", handler); - callback(); - } + // Wait for iccdetected event after turning on radio. + // Wait for iccundetected event after turning off radio. + let event = (enabled) ? "iccdetected" : "iccundetected"; + icc.addEventListener(event, function handler(evt) { + log(event + ": " + evt.iccId); + icc.removeEventListener(event, handler); + callback(); }); }); } From 8aad6ad8480cd2580d016d858fcb0f79a5e2aafd Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Mon, 11 Nov 2013 12:18:51 +0800 Subject: [PATCH 138/268] Bug 814637 - Part 7: Xpcshell test changes. r=hsinyi,allstars.chh --- dom/system/gonk/tests/test_ril_worker_icc.js | 9 +++++++++ dom/system/gonk/tests/test_ril_worker_ruim.js | 6 +----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/dom/system/gonk/tests/test_ril_worker_icc.js b/dom/system/gonk/tests/test_ril_worker_icc.js index 4aed5a3cb748..7201b84e2f3d 100644 --- a/dom/system/gonk/tests/test_ril_worker_icc.js +++ b/dom/system/gonk/tests/test_ril_worker_icc.js @@ -1719,8 +1719,11 @@ add_test(function test_personalization_state() { let worker = newUint8Worker(); let ril = worker.RIL; + worker.ICCRecordHelper.readICCID = function fakeReadICCID() {}; + function testPersonalization(cardPersoState, geckoCardState) { let iccStatus = { + cardState: CARD_STATE_PRESENT, gsmUmtsSubscriptionAppIndex: 0, apps: [ { @@ -1758,8 +1761,11 @@ add_test(function test_card_app_state() { let worker = newUint8Worker(); let ril = worker.RIL; + worker.ICCRecordHelper.readICCID = function fakeReadICCID() {}; + function testCardAppState(cardAppState, geckoCardState) { let iccStatus = { + cardState: CARD_STATE_PRESENT, gsmUmtsSubscriptionAppIndex: 0, apps: [ { @@ -1794,8 +1800,11 @@ add_test(function test_icc_permanent_blocked() { let worker = newUint8Worker(); let ril = worker.RIL; + worker.ICCRecordHelper.readICCID = function fakeReadICCID() {}; + function testPermanentBlocked(pin1_replaced, universalPINState, pin1) { let iccStatus = { + cardState: CARD_STATE_PRESENT, gsmUmtsSubscriptionAppIndex: 0, universalPINState: universalPINState, apps: [ diff --git a/dom/system/gonk/tests/test_ril_worker_ruim.js b/dom/system/gonk/tests/test_ril_worker_ruim.js index c80ed4014eac..47fb987a973e 100644 --- a/dom/system/gonk/tests/test_ril_worker_ruim.js +++ b/dom/system/gonk/tests/test_ril_worker_ruim.js @@ -78,10 +78,6 @@ add_test(function test_fetch_ruim_recodes() { function testFetchRuimRecordes(expectCalled) { let ifCalled = []; - iccHelper.readICCID = function () { - ifCalled.push("readICCID"); - }; - ruimHelper.getIMSI_M = function () { ifCalled.push("getIMSI_M"); }; @@ -108,7 +104,7 @@ add_test(function test_fetch_ruim_recodes() { } } - let expectCalled = ["readICCID", "getIMSI_M", "readCST", "readCDMAHome", + let expectCalled = ["getIMSI_M", "readCST", "readCDMAHome", "getCdmaSubscription"]; testFetchRuimRecordes(expectCalled); From 7a9dd721044fdf888436575d2617e12b7f2000f1 Mon Sep 17 00:00:00 2001 From: Shu-yu Guo Date: Wed, 20 Nov 2013 12:08:07 -0800 Subject: [PATCH 139/268] Bug 939414 - Dump memory stats for browser-chrome. (r=ted) --- testing/mochitest/browser-test.js | 10 ++++ testing/mochitest/harness.xul | 2 + testing/mochitest/jar.mn | 1 + testing/mochitest/server.js | 2 + .../mochitest/tests/SimpleTest/Makefile.in | 1 + .../mochitest/tests/SimpleTest/MemoryStats.js | 49 +++++++++++++++++++ .../mochitest/tests/SimpleTest/TestRunner.js | 44 +---------------- testing/mochitest/tests/index.html | 1 + 8 files changed, 67 insertions(+), 43 deletions(-) create mode 100644 testing/mochitest/tests/SimpleTest/MemoryStats.js diff --git a/testing/mochitest/browser-test.js b/testing/mochitest/browser-test.js index 0ba9c0830f56..de89ad757274 100644 --- a/testing/mochitest/browser-test.js +++ b/testing/mochitest/browser-test.js @@ -71,8 +71,10 @@ function Tester(aTests, aDumper, aCallback) { this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js", simpleTestScope); this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromePowers.js", simpleTestScope); this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/SimpleTest.js", simpleTestScope); + this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/MemoryStats.js", simpleTestScope); this._scriptLoader.loadSubScript("chrome://mochikit/content/chrome-harness.js", simpleTestScope); this.SimpleTest = simpleTestScope.SimpleTest; + this.MemoryStats = simpleTestScope.MemoryStats; this.Task = Components.utils.import("resource://gre/modules/Task.jsm", null).Task; this.Promise = Components.utils.import("resource://gre/modules/commonjs/sdk/core/promise.js", null).Promise; } @@ -352,6 +354,14 @@ Tester.prototype = { } } + // Dump memory stats for main thread. + if (Cc["@mozilla.org/xre/runtime;1"] + .getService(Ci.nsIXULRuntime) + .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) + { + this.MemoryStats.dump((l) => { this.dumper.dump(l + "\n"); }); + } + // Note the test run time let time = Date.now() - this.lastStartTime; this.dumper.dump("INFO TEST-END | " + this.currentTest.path + " | finished in " + time + "ms\n"); diff --git a/testing/mochitest/harness.xul b/testing/mochitest/harness.xul index 90bd73ab9628..aee10cd95369 100644 --- a/testing/mochitest/harness.xul +++ b/testing/mochitest/harness.xul @@ -15,6 +15,8 @@ src="chrome://mochikit/content/tests/SimpleTest/SpecialPowersObserverAPI.js"/> + From 3e39fd6fda0e42a6b7f75f67eacf3473090d4e6d Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 19 Nov 2013 15:50:25 -0800 Subject: [PATCH 140/268] Bug 940755 - Add an exact rooting suppression for AutoAssertNoGC; r=sfink --HG-- extra : rebase_source : 01ce5a48daa53c46138256daf0bf814356b3ca4e --- js/src/devtools/rootAnalysis/annotations.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index 53ff34a2de77..05de1e4f3239 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -228,5 +228,6 @@ function isRootedPointerTypeName(name) function isSuppressConstructor(name) { return /::AutoSuppressGC/.test(name) - || /::AutoEnterAnalysis/.test(name); + || /::AutoEnterAnalysis/.test(name) + || /::AutoAssertNoGC/.test(name); } From e609612139fab42fc28364e9897659e332310a5e Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 20 Nov 2013 12:12:11 -0800 Subject: [PATCH 141/268] Bug 940718 - Create the first safe JSContext in a GC safe location; r=bholley --HG-- extra : rebase_source : fa6e43d8e194e21e1a5231050aa7a959d844edd5 --- content/base/src/nsContentUtils.cpp | 5 ++++- js/xpconnect/idl/nsIXPConnect.idl | 4 +++- js/xpconnect/src/XPCJSContextStack.cpp | 10 ++++++++-- js/xpconnect/src/nsCxPusher.cpp | 1 + js/xpconnect/src/nsXPConnect.cpp | 7 +++++++ js/xpconnect/src/xpcprivate.h | 1 + 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index a60f693de745..03b922a50c33 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -379,6 +379,9 @@ nsContentUtils::Init() return NS_ERROR_FAILURE; NS_ADDREF(sSecurityManager); + // Getting the first context can trigger GC, so do this non-lazily. + sXPConnect->InitSafeJSContext(); + rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService); if (NS_FAILED(rv)) { // This makes life easier, but we can live without it. @@ -388,7 +391,7 @@ nsContentUtils::Init() rv = CallGetService(NS_LBRK_CONTRACTID, &sLineBreaker); NS_ENSURE_SUCCESS(rv, rv); - + rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker); NS_ENSURE_SUCCESS(rv, rv); diff --git a/js/xpconnect/idl/nsIXPConnect.idl b/js/xpconnect/idl/nsIXPConnect.idl index f30e1fb4656d..4b476725baca 100644 --- a/js/xpconnect/idl/nsIXPConnect.idl +++ b/js/xpconnect/idl/nsIXPConnect.idl @@ -273,6 +273,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports /***************************************************************************/ + %{ C++ // For use with the service manager // {CB6593E0-F9B2-11d2-BDD6-000064657374} @@ -281,7 +282,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } %} -[uuid(c4d0187c-6a78-4bdf-9cd9-d218644b715a)] +[uuid(880be309-88a1-4e98-8621-7f7e42681b20)] interface nsIXPConnect : nsISupports { %{ C++ @@ -446,6 +447,7 @@ interface nsIXPConnect : nsISupports [noscript,notxpcom,nostdcall] JSContextPtr getCurrentJSContext(); + [noscript,notxpcom,nostdcall] JSContextPtr initSafeJSContext(); [noscript,notxpcom,nostdcall] JSContextPtr getSafeJSContext(); readonly attribute nsIStackFrame CurrentJSStack; diff --git a/js/xpconnect/src/XPCJSContextStack.cpp b/js/xpconnect/src/XPCJSContextStack.cpp index 7171c37c0198..22ae79ee956b 100644 --- a/js/xpconnect/src/XPCJSContextStack.cpp +++ b/js/xpconnect/src/XPCJSContextStack.cpp @@ -134,8 +134,14 @@ const JSClass xpc::SafeJSContextGlobalClass = { JSContext* XPCJSContextStack::GetSafeJSContext() { - if (mSafeJSContext) - return mSafeJSContext; + MOZ_ASSERT(mSafeJSContext); + return mSafeJSContext; +} + +JSContext* +XPCJSContextStack::InitSafeJSContext() +{ + MOZ_ASSERT(!mSafeJSContext); // Start by getting the principal holder and principal for this // context. If we can't manage that, don't bother with the rest. diff --git a/js/xpconnect/src/nsCxPusher.cpp b/js/xpconnect/src/nsCxPusher.cpp index 83db41ac962a..2215a2a5f489 100644 --- a/js/xpconnect/src/nsCxPusher.cpp +++ b/js/xpconnect/src/nsCxPusher.cpp @@ -177,6 +177,7 @@ AutoJSContext::AutoJSContext(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) void AutoJSContext::Init(bool aSafe MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) { + JS::AutoAssertNoGC nogc; MOZ_ASSERT(!mCx, "mCx should not be initialized!"); MOZ_GUARD_OBJECT_NOTIFIER_INIT; diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index f730f7e2fea0..675fe6e8709b 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -1280,6 +1280,13 @@ nsXPConnect::GetCurrentJSContext() return GetRuntime()->GetJSContextStack()->Peek(); } +/* virtual */ +JSContext* +nsXPConnect::InitSafeJSContext() +{ + return GetRuntime()->GetJSContextStack()->InitSafeJSContext(); +} + /* virtual */ JSContext* nsXPConnect::GetSafeJSContext() diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index d0cc03c42b21..381245bd65e5 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -3033,6 +3033,7 @@ public: return mStack.IsEmpty() ? nullptr : mStack[mStack.Length() - 1].cx; } + JSContext *InitSafeJSContext(); JSContext *GetSafeJSContext(); bool HasJSContext(JSContext *cx); From b1b4271ebea4a4b0b8c9a38f73d200c751dfea0d Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Wed, 20 Nov 2013 15:14:31 -0500 Subject: [PATCH 142/268] Bug 941120 - Stop running make check twice in js/src. r=gps --- Makefile.in | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Makefile.in b/Makefile.in index 6ae7359f5a2b..fba5cd3b3881 100644 --- a/Makefile.in +++ b/Makefile.in @@ -253,13 +253,6 @@ endif ifdef BUILD_JS js/src/Makefile: subsrcdir := js/src -ifdef ENABLE_TESTS -# Incorporate static tier directories into tests. This should be incorporated -# into moz.build files someday. -check:: - $(call SUBMAKE,$@,js/src) -endif - ifdef MOZ_PSEUDO_DERECURSE # Interdependencies for parallel export. js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export From 4ba80f0f477fa47e9d1540bb9a42d8b3fb0242b1 Mon Sep 17 00:00:00 2001 From: Gregory Szorc Date: Wed, 20 Nov 2013 11:41:08 -0800 Subject: [PATCH 143/268] Bug 924307 - Intermittent "reporter is null at abouthealth.js:27"; r=rnewman The error message comes from abouthealth.js not checking if a variable is null before access. That bug is fixed. However, the underlying issue of "the reporter is null" still remains. Logging has been added to hopefully catch issues. The signature of the failure will change. --HG-- extra : rebase_source : bc887406a3570a767bae5407b5836314157ac421 extra : amend_source : f22cad2eae46bd08ae25a7d376fbf8e2d1d0ea92 --- browser/base/content/abouthealthreport/abouthealth.js | 5 +++++ browser/base/content/test/general/browser.ini | 1 - services/datareporting/DataReportingService.js | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/browser/base/content/abouthealthreport/abouthealth.js b/browser/base/content/abouthealthreport/abouthealth.js index 84c054bca44b..1475ce3599ed 100644 --- a/browser/base/content/abouthealthreport/abouthealth.js +++ b/browser/base/content/abouthealthreport/abouthealth.js @@ -24,6 +24,11 @@ const prefs = new Preferences("datareporting.healthreport."); let healthReportWrapper = { init: function () { + if (!reporter) { + healthReportWrapper.handleInitFailure(); + return; + } + reporter.onInit().then(healthReportWrapper.refreshPayload, healthReportWrapper.handleInitFailure); diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 963364dcf0a1..4d5472c2230f 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -108,7 +108,6 @@ run-if = crashreporter [browser_CTP_resize.js] [browser_URLBarSetURI.js] [browser_aboutHealthReport.js] -skip-if = os == "linux" # Bug 924307 [browser_aboutHome.js] [browser_aboutSyncProgress.js] [browser_addKeywordSearch.js] diff --git a/services/datareporting/DataReportingService.js b/services/datareporting/DataReportingService.js index 27a1679aeff0..f7e3db0a2e26 100644 --- a/services/datareporting/DataReportingService.js +++ b/services/datareporting/DataReportingService.js @@ -212,6 +212,8 @@ DataReportingService.prototype = Object.freeze({ this._loadHealthReporter(); } catch (ex) { this._healthReporter = null; + Cu.reportError("Exception when obtaining health reporter: " + + CommonUtils.exceptionStr(ex)); } return this._healthReporter; From 72d3b879107b556cbf1c1e98c098a43ab9c7c33a Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 20 Nov 2013 20:40:14 +0000 Subject: [PATCH 144/268] bug 941090 - build most of gfx/ots in unified mode. r=ehsan --- gfx/ots/src/moz.build | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/gfx/ots/src/moz.build b/gfx/ots/src/moz.build index 5a6e489a9ae1..ab39e428e64e 100644 --- a/gfx/ots/src/moz.build +++ b/gfx/ots/src/moz.build @@ -10,25 +10,31 @@ EXPORTS += [ ] SOURCES += [ + # don't unify sources that use a (file-specific) DROP_THIS_TABLE macro + 'gasp.cc', + 'gdef.cc', + 'gpos.cc', + 'gsub.cc', + 'hdmx.cc', + 'kern.cc', + 'ltsh.cc', + 'vdmx.cc', + 'vorg.cc', +] + +UNIFIED_SOURCES += [ 'cff.cc', 'cff_type2_charstring.cc', 'cmap.cc', 'cvt.cc', 'fpgm.cc', - 'gasp.cc', - 'gdef.cc', 'glyf.cc', - 'gpos.cc', 'graphite.cc', - 'gsub.cc', - 'hdmx.cc', 'head.cc', 'hhea.cc', 'hmtx.cc', - 'kern.cc', 'layout.cc', 'loca.cc', - 'ltsh.cc', 'maxp.cc', 'metrics.cc', 'name.cc', @@ -37,10 +43,8 @@ SOURCES += [ 'post.cc', 'prep.cc', 'svg.cc', - 'vdmx.cc', 'vhea.cc', 'vmtx.cc', - 'vorg.cc', ] MSVC_ENABLE_PGO = True From 3441f8f6d6c7b49f2567402a1442b45af92bbd6b Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 19 Nov 2013 11:21:00 -0500 Subject: [PATCH 145/268] Bug 940426 - part 1 - properly stop observing all the sources in nsXULTemplateBuilder; r=bz --- .../templates/src/nsXULTemplateBuilder.cpp | 36 ++++++++++++------- .../xul/templates/src/nsXULTemplateBuilder.h | 14 ++++++++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/content/xul/templates/src/nsXULTemplateBuilder.cpp b/content/xul/templates/src/nsXULTemplateBuilder.cpp index 8b63f8ad4ce0..96e6cdae26de 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -171,6 +171,25 @@ nsXULTemplateBuilder::InitGlobals() return NS_OK; } +void +nsXULTemplateBuilder::StartObserving(nsIDocument* aDocument) +{ + aDocument->AddObserver(this); + mObservedDocument = aDocument; + gObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); + gObserverService->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, false); +} + +void +nsXULTemplateBuilder::StopObserving() +{ + MOZ_ASSERT(mObservedDocument); + mObservedDocument->RemoveObserver(this); + mObservedDocument = nullptr; + gObserverService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + gObserverService->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC); +} + void nsXULTemplateBuilder::CleanUp(bool aIsFinal) { @@ -193,10 +212,7 @@ void nsXULTemplateBuilder::Uninit(bool aIsFinal) { if (mObservedDocument && aIsFinal) { - gObserverService->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC); - gObserverService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - mObservedDocument->RemoveObserver(this); - mObservedDocument = nullptr; + StopObserving(); } if (mQueryProcessor) @@ -428,14 +444,7 @@ nsXULTemplateBuilder::Init(nsIContent* aElement) nsresult rv = LoadDataSources(doc, &shouldDelay); if (NS_SUCCEEDED(rv)) { - // Add ourselves as a document observer - doc->AddObserver(this); - - mObservedDocument = doc; - gObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, - false); - gObserverService->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, - false); + StartObserving(doc); } return rv; @@ -1124,7 +1133,8 @@ nsXULTemplateBuilder::ContentRemoved(nsIDocument* aDocument, nsContentUtils::AddScriptRunner( NS_NewRunnableMethod(this, &nsXULTemplateBuilder::UninitFalse)); - aDocument->RemoveObserver(this); + MOZ_ASSERT(aDocument == mObservedDocument); + StopObserving(); nsCOMPtr xuldoc = do_QueryInterface(aDocument); if (xuldoc) diff --git a/content/xul/templates/src/nsXULTemplateBuilder.h b/content/xul/templates/src/nsXULTemplateBuilder.h index f72b190f7b0d..9f3d839b98f6 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.h +++ b/content/xul/templates/src/nsXULTemplateBuilder.h @@ -480,6 +480,20 @@ protected: { } + /** + * Start observing events from the observer service and the given + * document. + * + * @param aDocument the document to observe + */ + void StartObserving(nsIDocument* aDocument); + + /** + * Stop observing events from the observer service and any associated + * document. + */ + void StopObserving(); + /** * Document that we're observing. Weak ref! */ From c0280fee2bb0213f59b2f9dfb139b413dae720cb Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Tue, 19 Nov 2013 20:04:15 -0500 Subject: [PATCH 146/268] Bug 940426 - part 2 - don't observe xpcom-shutdown in nsXULTemplateBuilder; r=bz --- content/xul/templates/src/nsXULTemplateBuilder.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/content/xul/templates/src/nsXULTemplateBuilder.cpp b/content/xul/templates/src/nsXULTemplateBuilder.cpp index 96e6cdae26de..f21d84073971 100644 --- a/content/xul/templates/src/nsXULTemplateBuilder.cpp +++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp @@ -102,6 +102,7 @@ nsXULTemplateBuilder::nsXULTemplateBuilder(void) mTop(nullptr), mObservedDocument(nullptr) { + MOZ_COUNT_CTOR(nsXULTemplateBuilder); } static PLDHashOperator @@ -128,6 +129,8 @@ nsXULTemplateBuilder::~nsXULTemplateBuilder(void) NS_IF_RELEASE(gScriptSecurityManager); NS_IF_RELEASE(gObserverService); } + + MOZ_COUNT_DTOR(nsXULTemplateBuilder); } @@ -176,7 +179,6 @@ nsXULTemplateBuilder::StartObserving(nsIDocument* aDocument) { aDocument->AddObserver(this); mObservedDocument = aDocument; - gObserverService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); gObserverService->AddObserver(this, DOM_WINDOW_DESTROYED_TOPIC, false); } @@ -186,7 +188,6 @@ nsXULTemplateBuilder::StopObserving() MOZ_ASSERT(mObservedDocument); mObservedDocument->RemoveObserver(this); mObservedDocument = nullptr; - gObserverService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); gObserverService->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC); } @@ -1082,8 +1083,6 @@ nsXULTemplateBuilder::Observe(nsISupports* aSubject, if (doc && doc == mObservedDocument) NodeWillBeDestroyed(doc); } - } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { - UninitTrue(); } return NS_OK; } From 02b93b6f1a2b7d1a83cf530fb66f018b00157b0d Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Wed, 20 Nov 2013 16:01:59 -0500 Subject: [PATCH 147/268] Follow-up to bug 936912: Fix a compiler warning --- xpcom/io/nsInputStreamTee.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpcom/io/nsInputStreamTee.cpp b/xpcom/io/nsInputStreamTee.cpp index 4ac153dfe217..08202d410041 100644 --- a/xpcom/io/nsInputStreamTee.cpp +++ b/xpcom/io/nsInputStreamTee.cpp @@ -348,3 +348,5 @@ NS_NewInputStreamTee(nsIInputStream **result, { return NS_NewInputStreamTeeAsync(result, source, sink, nullptr); } + +#undef LOG From 863750a7ce852e1fea9271c1a6b1ec28a1bd23da Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 21 Nov 2013 10:04:32 +1300 Subject: [PATCH 148/268] Bug 886196 - Configure option and pref for fragmented mp4 parser. r=glandium --- configure.in | 22 ++++++++++++++++++++++ modules/libpref/src/init/all.js | 3 +++ 2 files changed, 25 insertions(+) diff --git a/configure.in b/configure.in index b5f39812ad6f..6e983105fa3d 100644 --- a/configure.in +++ b/configure.in @@ -3942,6 +3942,7 @@ MOZ_OPUS=1 MOZ_WEBM=1 MOZ_DIRECTSHOW= MOZ_WMF= +MOZ_FMP4= MOZ_WEBRTC=1 MOZ_PEERCONNECTION= MOZ_SRTP= @@ -5275,6 +5276,26 @@ if test -n "$MOZ_WMF"; then MOZ_CUBEB=1 fi; +dnl ======================================================== +dnl = Built-in fragmented MP4 support. +dnl ======================================================== +if test -n "$MOZ_WMF"; then + dnl Enable fragmented MP4 parser on Windows by default. + dnl We will also need to enable it on other platforms as we implement + dnl platform decoder support there too. + MOZ_FMP4=1 +fi + +MOZ_ARG_DISABLE_BOOL(fmp4, +[ --disable-fmp4 Disable support for in built Fragmented MP4 parsing], + MOZ_FMP4=, + MOZ_FMP4=1) + +if test -n "$MOZ_FMP4"; then + AC_DEFINE(MOZ_FMP4) +fi; + + dnl ======================================================== dnl = Enable media plugin support dnl ======================================================== @@ -8627,6 +8648,7 @@ AC_SUBST(MOZ_TREMOR) AC_SUBST(MOZ_OPUS) AC_SUBST(MOZ_WEBM) AC_SUBST(MOZ_WMF) +AC_SUBST(MOZ_FMP4) AC_SUBST(MOZ_DIRECTSHOW) AC_SUBST(MOZ_MEDIA_PLUGINS) AC_SUBST(MOZ_APPLEMEDIA) diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index e87d35c72a58..d2a49fc5df4b 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -196,6 +196,9 @@ pref("media.windows-media-foundation.play-stand-alone", true); #ifdef MOZ_DIRECTSHOW pref("media.directshow.enabled", true); #endif +#ifdef MOZ_FMP4 +pref("media.fragmented-mp4.enabled", true); +#endif #ifdef MOZ_RAW pref("media.raw.enabled", true); #endif From 9772f912c9467f2d5f57f8ce0269fc457099bd22 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 21 Nov 2013 10:04:32 +1300 Subject: [PATCH 149/268] Bug 886196 - Import Chromium's MSE MP4 demuxer code. r=kinetik --- content/media/fmp4/Makefile.in | 7 + content/media/fmp4/demuxer/LICENSE | 27 + content/media/fmp4/demuxer/Streams.h | 21 + content/media/fmp4/demuxer/aac.cc | 273 +++++++ content/media/fmp4/demuxer/aac.h | 81 ++ .../fmp4/demuxer/audio_decoder_config.cc | 108 +++ .../media/fmp4/demuxer/audio_decoder_config.h | 127 +++ content/media/fmp4/demuxer/avc.cc | 89 +++ content/media/fmp4/demuxer/avc.h | 27 + content/media/fmp4/demuxer/basictypes.h | 166 ++++ content/media/fmp4/demuxer/bit_reader.cc | 56 ++ content/media/fmp4/demuxer/bit_reader.h | 69 ++ content/media/fmp4/demuxer/box_definitions.cc | 754 ++++++++++++++++++ content/media/fmp4/demuxer/box_definitions.h | 349 ++++++++ content/media/fmp4/demuxer/box_reader.cc | 263 ++++++ content/media/fmp4/demuxer/box_reader.h | 216 +++++ content/media/fmp4/demuxer/cenc.cc | 51 ++ content/media/fmp4/demuxer/cenc.h | 29 + content/media/fmp4/demuxer/channel_layout.cc | 186 +++++ content/media/fmp4/demuxer/channel_layout.h | 134 ++++ content/media/fmp4/demuxer/decrypt_config.cc | 25 + content/media/fmp4/demuxer/decrypt_config.h | 78 ++ content/media/fmp4/demuxer/es_descriptor.cc | 106 +++ content/media/fmp4/demuxer/es_descriptor.h | 53 ++ content/media/fmp4/demuxer/fourccs.h | 97 +++ content/media/fmp4/demuxer/mp4_demuxer.cc | 535 +++++++++++++ content/media/fmp4/demuxer/mp4_demuxer.h | 159 ++++ .../media/fmp4/demuxer/track_run_iterator.cc | 451 +++++++++++ .../media/fmp4/demuxer/track_run_iterator.h | 107 +++ .../fmp4/demuxer/video_decoder_config.cc | 158 ++++ .../media/fmp4/demuxer/video_decoder_config.h | 171 ++++ content/media/fmp4/demuxer/video_util.cc | 299 +++++++ content/media/fmp4/demuxer/video_util.h | 86 ++ content/media/fmp4/moz.build | 49 ++ content/media/moz.build | 3 + 35 files changed, 5410 insertions(+) create mode 100644 content/media/fmp4/Makefile.in create mode 100644 content/media/fmp4/demuxer/LICENSE create mode 100644 content/media/fmp4/demuxer/Streams.h create mode 100644 content/media/fmp4/demuxer/aac.cc create mode 100644 content/media/fmp4/demuxer/aac.h create mode 100644 content/media/fmp4/demuxer/audio_decoder_config.cc create mode 100644 content/media/fmp4/demuxer/audio_decoder_config.h create mode 100644 content/media/fmp4/demuxer/avc.cc create mode 100644 content/media/fmp4/demuxer/avc.h create mode 100644 content/media/fmp4/demuxer/basictypes.h create mode 100644 content/media/fmp4/demuxer/bit_reader.cc create mode 100644 content/media/fmp4/demuxer/bit_reader.h create mode 100644 content/media/fmp4/demuxer/box_definitions.cc create mode 100644 content/media/fmp4/demuxer/box_definitions.h create mode 100644 content/media/fmp4/demuxer/box_reader.cc create mode 100644 content/media/fmp4/demuxer/box_reader.h create mode 100644 content/media/fmp4/demuxer/cenc.cc create mode 100644 content/media/fmp4/demuxer/cenc.h create mode 100644 content/media/fmp4/demuxer/channel_layout.cc create mode 100644 content/media/fmp4/demuxer/channel_layout.h create mode 100644 content/media/fmp4/demuxer/decrypt_config.cc create mode 100644 content/media/fmp4/demuxer/decrypt_config.h create mode 100644 content/media/fmp4/demuxer/es_descriptor.cc create mode 100644 content/media/fmp4/demuxer/es_descriptor.h create mode 100644 content/media/fmp4/demuxer/fourccs.h create mode 100644 content/media/fmp4/demuxer/mp4_demuxer.cc create mode 100644 content/media/fmp4/demuxer/mp4_demuxer.h create mode 100644 content/media/fmp4/demuxer/track_run_iterator.cc create mode 100644 content/media/fmp4/demuxer/track_run_iterator.h create mode 100644 content/media/fmp4/demuxer/video_decoder_config.cc create mode 100644 content/media/fmp4/demuxer/video_decoder_config.h create mode 100644 content/media/fmp4/demuxer/video_util.cc create mode 100644 content/media/fmp4/demuxer/video_util.h create mode 100644 content/media/fmp4/moz.build diff --git a/content/media/fmp4/Makefile.in b/content/media/fmp4/Makefile.in new file mode 100644 index 000000000000..642256452251 --- /dev/null +++ b/content/media/fmp4/Makefile.in @@ -0,0 +1,7 @@ +# 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/. + +ifeq ($(OS_ARCH),WINNT) +OS_CXXFLAGS += -DNOMINMAX +endif diff --git a/content/media/fmp4/demuxer/LICENSE b/content/media/fmp4/demuxer/LICENSE new file mode 100644 index 000000000000..3d0f7d3edfd8 --- /dev/null +++ b/content/media/fmp4/demuxer/LICENSE @@ -0,0 +1,27 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/content/media/fmp4/demuxer/Streams.h b/content/media/fmp4/demuxer/Streams.h new file mode 100644 index 000000000000..0274433cc09e --- /dev/null +++ b/content/media/fmp4/demuxer/Streams.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace mp4_demuxer { + +class Stream { +public: + + // Returns true on success, false on failure. + // Writes number of bytes read into out_bytes_read, or 0 on EOS. + // Returns true on EOS. + virtual bool ReadAt(int64_t offset, + uint8_t* buffer, + uint32_t count, + uint32_t* out_bytes_read) = 0; + + virtual int64_t Length() const = 0; +}; + +} // namespace mp4_demuxer \ No newline at end of file diff --git a/content/media/fmp4/demuxer/aac.cc b/content/media/fmp4/demuxer/aac.cc new file mode 100644 index 000000000000..f0b6203ca739 --- /dev/null +++ b/content/media/fmp4/demuxer/aac.cc @@ -0,0 +1,273 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/aac.h" + +#include + +#include "mp4_demuxer/bit_reader.h" + +namespace mp4_demuxer { + +// The following conversion table is extracted from ISO 14496 Part 3 - +// Table 1.16 - Sampling Frequency Index. +static const int kFrequencyMap[] = { + 96000, 88200, 64000, 48000, 44100, 32000, 24000, + 22050, 16000, 12000, 11025, 8000, 7350 +}; + +static ChannelLayout ConvertChannelConfigToLayout(uint8_t channel_config) { + switch (channel_config) { + case 1: + return CHANNEL_LAYOUT_MONO; + case 2: + return CHANNEL_LAYOUT_STEREO; + case 3: + return CHANNEL_LAYOUT_SURROUND; + case 4: + return CHANNEL_LAYOUT_4_0; + case 5: + return CHANNEL_LAYOUT_5_0; + case 6: + return CHANNEL_LAYOUT_5_1; + case 8: + return CHANNEL_LAYOUT_7_1; + default: + break; + } + + return CHANNEL_LAYOUT_UNSUPPORTED; +} + +AAC::AAC() + : profile_(0), frequency_index_(0), channel_config_(0), frequency_(0), + extension_frequency_(0), channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED) { +} + +AAC::~AAC() { +} + +bool AAC::Parse(const std::vector& data) { + if (data.empty()) + return false; + + BitReader reader(&data[0], data.size()); + uint8_t extension_type = 0; + bool ps_present = false; + uint8_t extension_frequency_index = 0xff; + + frequency_ = 0; + extension_frequency_ = 0; + + // The following code is written according to ISO 14496 Part 3 Table 1.13 - + // Syntax of AudioSpecificConfig. + + // Read base configuration + RCHECK(reader.ReadBits(5, &profile_)); + RCHECK(reader.ReadBits(4, &frequency_index_)); + if (frequency_index_ == 0xf) + RCHECK(reader.ReadBits(24, &frequency_)); + RCHECK(reader.ReadBits(4, &channel_config_)); + + // Read extension configuration. + if (profile_ == 5 || profile_ == 29) { + ps_present = (profile_ == 29); + extension_type = 5; + RCHECK(reader.ReadBits(4, &extension_frequency_index)); + if (extension_frequency_index == 0xf) + RCHECK(reader.ReadBits(24, &extension_frequency_)); + RCHECK(reader.ReadBits(5, &profile_)); + } + + RCHECK(SkipDecoderGASpecificConfig(&reader)); + RCHECK(SkipErrorSpecificConfig()); + + // Read extension configuration again + // Note: The check for 16 available bits comes from the AAC spec. + if (extension_type != 5 && reader.bits_available() >= 16) { + uint16_t sync_extension_type; + uint8_t sbr_present_flag; + uint8_t ps_present_flag; + + if (reader.ReadBits(11, &sync_extension_type) && + sync_extension_type == 0x2b7) { + if (reader.ReadBits(5, &extension_type) && extension_type == 5) { + RCHECK(reader.ReadBits(1, &sbr_present_flag)); + + if (sbr_present_flag) { + RCHECK(reader.ReadBits(4, &extension_frequency_index)); + + if (extension_frequency_index == 0xf) + RCHECK(reader.ReadBits(24, &extension_frequency_)); + + // Note: The check for 12 available bits comes from the AAC spec. + if (reader.bits_available() >= 12) { + RCHECK(reader.ReadBits(11, &sync_extension_type)); + if (sync_extension_type == 0x548) { + RCHECK(reader.ReadBits(1, &ps_present_flag)); + ps_present = ps_present_flag != 0; + } + } + } + } + } + } + + if (frequency_ == 0) { + RCHECK(frequency_index_ < arraysize(kFrequencyMap)); + frequency_ = kFrequencyMap[frequency_index_]; + } + + if (extension_frequency_ == 0 && extension_frequency_index != 0xff) { + RCHECK(extension_frequency_index < arraysize(kFrequencyMap)); + extension_frequency_ = kFrequencyMap[extension_frequency_index]; + } + + // When Parametric Stereo is on, mono will be played as stereo. + if (ps_present && channel_config_ == 1) + channel_layout_ = CHANNEL_LAYOUT_STEREO; + else + channel_layout_ = ConvertChannelConfigToLayout(channel_config_); + + audio_specific_config_.insert(audio_specific_config_.begin(), data.begin(), data.end()); + + return frequency_ != 0 && channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED && + profile_ >= 1 && profile_ <= 4 && frequency_index_ != 0xf && + channel_config_ <= 7; +} + +const std::vector& AAC::AudioSpecificConfig() const +{ + return audio_specific_config_; +} + +int AAC::GetOutputSamplesPerSecond(bool sbr_in_mimetype) const { + if (extension_frequency_ > 0) + return extension_frequency_; + + if (!sbr_in_mimetype) + return frequency_; + + // The following code is written according to ISO 14496 Part 3 Table 1.11 and + // Table 1.22. (Table 1.11 refers to the capping to 48000, Table 1.22 refers + // to SBR doubling the AAC sample rate.) + // TODO(acolwell) : Extend sample rate cap to 96kHz for Level 5 content. + DCHECK_GT(frequency_, 0); + return std::min(2 * frequency_, 48000); +} + +ChannelLayout AAC::GetChannelLayout(bool sbr_in_mimetype) const { + // Check for implicit signalling of HE-AAC and indicate stereo output + // if the mono channel configuration is signalled. + // See ISO-14496-3 Section 1.6.6.1.2 for details about this special casing. + if (sbr_in_mimetype && channel_config_ == 1) + return CHANNEL_LAYOUT_STEREO; + + return channel_layout_; +} + +bool AAC::ConvertEsdsToADTS(std::vector* buffer) const { + size_t size = buffer->size() + kADTSHeaderSize; + + DCHECK(profile_ >= 1 && profile_ <= 4 && frequency_index_ != 0xf && + channel_config_ <= 7); + + // ADTS header uses 13 bits for packet size. + if (size >= (1 << 13)) + return false; + + std::vector& adts = *buffer; + + adts.insert(buffer->begin(), kADTSHeaderSize, 0); + adts[0] = 0xff; + adts[1] = 0xf1; + adts[2] = ((profile_ - 1) << 6) + (frequency_index_ << 2) + + (channel_config_ >> 2); + adts[3] = ((channel_config_ & 0x3) << 6) + (size >> 11); + adts[4] = (size & 0x7ff) >> 3; + adts[5] = ((size & 7) << 5) + 0x1f; + adts[6] = 0xfc; + + return true; +} + +// Currently this function only support GASpecificConfig defined in +// ISO 14496 Part 3 Table 4.1 - Syntax of GASpecificConfig() +bool AAC::SkipDecoderGASpecificConfig(BitReader* bit_reader) const { + switch (profile_) { + case 1: + case 2: + case 3: + case 4: + case 6: + case 7: + case 17: + case 19: + case 20: + case 21: + case 22: + case 23: + return SkipGASpecificConfig(bit_reader); + default: + break; + } + + return false; +} + +bool AAC::SkipErrorSpecificConfig() const { + switch (profile_) { + case 17: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + return false; + default: + break; + } + + return true; +} + +// The following code is written according to ISO 14496 part 3 Table 4.1 - +// GASpecificConfig. +bool AAC::SkipGASpecificConfig(BitReader* bit_reader) const { + uint8_t extension_flag = 0; + uint8_t depends_on_core_coder; + uint16_t dummy; + + RCHECK(bit_reader->ReadBits(1, &dummy)); // frameLengthFlag + RCHECK(bit_reader->ReadBits(1, &depends_on_core_coder)); + if (depends_on_core_coder == 1) + RCHECK(bit_reader->ReadBits(14, &dummy)); // coreCoderDelay + + RCHECK(bit_reader->ReadBits(1, &extension_flag)); + RCHECK(channel_config_ != 0); + + if (profile_ == 6 || profile_ == 20) + RCHECK(bit_reader->ReadBits(3, &dummy)); // layerNr + + if (extension_flag) { + if (profile_ == 22) { + RCHECK(bit_reader->ReadBits(5, &dummy)); // numOfSubFrame + RCHECK(bit_reader->ReadBits(11, &dummy)); // layer_length + } + + if (profile_ == 17 || profile_ == 19 || profile_ == 20 || profile_ == 23) { + RCHECK(bit_reader->ReadBits(3, &dummy)); // resilience flags + } + + RCHECK(bit_reader->ReadBits(1, &dummy)); // extensionFlag3 + } + + return true; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/aac.h b/content/media/fmp4/demuxer/aac.h new file mode 100644 index 000000000000..e3f4b92f74e8 --- /dev/null +++ b/content/media/fmp4/demuxer/aac.h @@ -0,0 +1,81 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_AAC_H_ +#define MEDIA_MP4_AAC_H_ + +#include + +#include "mp4_demuxer/basictypes.h" +#include "mp4_demuxer/channel_layout.h" + +namespace mp4_demuxer { + +class BitReader; + +// This class parses the AAC information from decoder specific information +// embedded in the esds box in an ISO BMFF file. +// Please refer to ISO 14496 Part 3 Table 1.13 - Syntax of AudioSpecificConfig +// for more details. +class AAC { + public: + AAC(); + ~AAC(); + + // Parse the AAC config from the raw binary data embedded in esds box. + // The function will parse the data and get the ElementaryStreamDescriptor, + // then it will parse the ElementaryStreamDescriptor to get audio stream + // configurations. + bool Parse(const std::vector& data); + + // Gets the output sample rate for the AAC stream. + // |sbr_in_mimetype| should be set to true if the SBR mode is + // signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter). + // Returns the samples_per_second value that should used in an + // AudioDecoderConfig. + int GetOutputSamplesPerSecond(bool sbr_in_mimetype) const; + + // Gets the channel layout for the AAC stream. + // |sbr_in_mimetype| should be set to true if the SBR mode is + // signalled in the mimetype. (ie mp4a.40.5 in the codecs parameter). + // Returns the channel_layout value that should used in an + // AudioDecoderConfig. + ChannelLayout GetChannelLayout(bool sbr_in_mimetype) const; + + // This function converts a raw AAC frame into an AAC frame with an ADTS + // header. On success, the function returns true and stores the converted data + // in the buffer. The function returns false on failure and leaves the buffer + // unchanged. + bool ConvertEsdsToADTS(std::vector* buffer) const; + + // Size in bytes of the ADTS header added by ConvertEsdsToADTS(). + static const size_t kADTSHeaderSize = 7; + + const std::vector& AudioSpecificConfig() const; + + private: + bool SkipDecoderGASpecificConfig(BitReader* bit_reader) const; + bool SkipErrorSpecificConfig() const; + bool SkipGASpecificConfig(BitReader* bit_reader) const; + + // The following variables store the AAC specific configuration information + // that are used to generate the ADTS header. + uint8_t profile_; + uint8_t frequency_index_; + uint8_t channel_config_; + + // The following variables store audio configuration information that + // can be used by Chromium. They are based on the AAC specific + // configuration but can be overridden by extensions in elementary + // stream descriptor. + int frequency_; + int extension_frequency_; + ChannelLayout channel_layout_; + + std::vector audio_specific_config_; +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_AAC_H_ diff --git a/content/media/fmp4/demuxer/audio_decoder_config.cc b/content/media/fmp4/demuxer/audio_decoder_config.cc new file mode 100644 index 000000000000..f73b23e8bedc --- /dev/null +++ b/content/media/fmp4/demuxer/audio_decoder_config.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/audio_decoder_config.h" + +#include + +namespace mp4_demuxer { + +static int SampleFormatToBitsPerChannel(SampleFormat sample_format) { + switch (sample_format) { + case kUnknownSampleFormat: + return 0; + case kSampleFormatU8: + return 8; + case kSampleFormatS16: + case kSampleFormatPlanarS16: + return 16; + case kSampleFormatS32: + case kSampleFormatF32: + case kSampleFormatPlanarF32: + return 32; + case kSampleFormatMax: + break; + } + + //NOTREACHED() << "Invalid sample format provided: " << sample_format; + return 0; +} + +AudioDecoderConfig::AudioDecoderConfig() + : codec_(kUnknownAudioCodec), + sample_format_(kUnknownSampleFormat), + bits_per_channel_(0), + channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED), + samples_per_second_(0), + bytes_per_frame_(0), + is_encrypted_(false) { +} + +AudioDecoderConfig::AudioDecoderConfig(AudioCodec codec, + SampleFormat sample_format, + ChannelLayout channel_layout, + int samples_per_second, + const uint8_t* extra_data, + size_t extra_data_size, + bool is_encrypted) { + Initialize(codec, sample_format, channel_layout, samples_per_second, + extra_data, extra_data_size, is_encrypted); +} + +void AudioDecoderConfig::Initialize(AudioCodec codec, + SampleFormat sample_format, + ChannelLayout channel_layout, + int samples_per_second, + const uint8_t* extra_data, + size_t extra_data_size, + bool is_encrypted) { + CHECK((extra_data_size != 0) == (extra_data != NULL)); + + codec_ = codec; + channel_layout_ = channel_layout; + samples_per_second_ = samples_per_second; + sample_format_ = sample_format; + bits_per_channel_ = SampleFormatToBitsPerChannel(sample_format); + extra_data_.assign(extra_data, extra_data + extra_data_size); + is_encrypted_ = is_encrypted; + + int channels = ChannelLayoutToChannelCount(channel_layout_); + bytes_per_frame_ = channels * bits_per_channel_ / 8; +} + +AudioDecoderConfig::~AudioDecoderConfig() {} + +bool AudioDecoderConfig::IsValidConfig() const { + return codec_ != kUnknownAudioCodec && + channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED && + bits_per_channel_ > 0 && + bits_per_channel_ <= kMaxBitsPerSample && + samples_per_second_ > 0 && + samples_per_second_ <= kMaxSampleRate && + sample_format_ != kUnknownSampleFormat; +} + +bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const { + return ((codec() == config.codec()) && + (bits_per_channel() == config.bits_per_channel()) && + (channel_layout() == config.channel_layout()) && + (samples_per_second() == config.samples_per_second()) && + (extra_data_size() == config.extra_data_size()) && + (!extra_data() || !memcmp(extra_data(), config.extra_data(), + extra_data_size())) && + (is_encrypted() == config.is_encrypted()) && + (sample_format() == config.sample_format())); +} + +std::string AudioDecoderConfig::AsHumanReadableString() const { + std::ostringstream s; + s << "codec: " << codec() + << " bits/channel: " << bits_per_channel() + << " samples/s: " << samples_per_second() + << " has extra data? " << (extra_data() ? "true" : "false") + << " encrypted? " << (is_encrypted() ? "true" : "false"); + return s.str(); +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/audio_decoder_config.h b/content/media/fmp4/demuxer/audio_decoder_config.h new file mode 100644 index 000000000000..8318ecf899a3 --- /dev/null +++ b/content/media/fmp4/demuxer/audio_decoder_config.h @@ -0,0 +1,127 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_AUDIO_DECODER_CONFIG_H_ +#define MEDIA_BASE_AUDIO_DECODER_CONFIG_H_ + +#include + +#include "mp4_demuxer/basictypes.h" +#include "mp4_demuxer/channel_layout.h" + +namespace mp4_demuxer { + +enum AudioCodec { + // These values are histogrammed over time; do not change their ordinal + // values. When deleting a codec replace it with a dummy value; when adding a + // codec, do so at the bottom before kAudioCodecMax. + kUnknownAudioCodec = 0, + kCodecAAC, + kCodecMP3, + kCodecPCM, + kCodecVorbis, + kCodecFLAC, + kCodecAMR_NB, + kCodecAMR_WB, + kCodecPCM_MULAW, + kCodecGSM_MS, + kCodecPCM_S16BE, + kCodecPCM_S24BE, + kCodecOpus, + // DO NOT ADD RANDOM AUDIO CODECS! + // + // The only acceptable time to add a new codec is if there is production code + // that uses said codec in the same CL. + + // Must always be last! + kAudioCodecMax +}; + +enum SampleFormat { + // These values are histogrammed over time; do not change their ordinal + // values. When deleting a sample format replace it with a dummy value; when + // adding a sample format, do so at the bottom before kSampleFormatMax. + kUnknownSampleFormat = 0, + kSampleFormatU8, // Unsigned 8-bit w/ bias of 128. + kSampleFormatS16, // Signed 16-bit. + kSampleFormatS32, // Signed 32-bit. + kSampleFormatF32, // Float 32-bit. + kSampleFormatPlanarS16, // Signed 16-bit planar. + kSampleFormatPlanarF32, // Float 32-bit planar. + + // Must always be last! + kSampleFormatMax +}; + +// TODO(dalecurtis): FFmpeg API uses |bytes_per_channel| instead of +// |bits_per_channel|, we should switch over since bits are generally confusing +// to work with. +class AudioDecoderConfig { + public: + // Constructs an uninitialized object. Clients should call Initialize() with + // appropriate values before using. + AudioDecoderConfig(); + + // Constructs an initialized object. It is acceptable to pass in NULL for + // |extra_data|, otherwise the memory is copied. + AudioDecoderConfig(AudioCodec codec, SampleFormat sample_format, + ChannelLayout channel_layout, int samples_per_second, + const uint8_t* extra_data, size_t extra_data_size, + bool is_encrypted); + + ~AudioDecoderConfig(); + + // Resets the internal state of this object. + void Initialize(AudioCodec codec, SampleFormat sample_format, + ChannelLayout channel_layout, int samples_per_second, + const uint8_t* extra_data, size_t extra_data_size, + bool is_encrypted); + + // Returns true if this object has appropriate configuration values, false + // otherwise. + bool IsValidConfig() const; + + // Returns true if all fields in |config| match this config. + // Note: The contents of |extra_data_| are compared not the raw pointers. + bool Matches(const AudioDecoderConfig& config) const; + + AudioCodec codec() const { return codec_; } + int bits_per_channel() const { return bits_per_channel_; } + ChannelLayout channel_layout() const { return channel_layout_; } + int samples_per_second() const { return samples_per_second_; } + SampleFormat sample_format() const { return sample_format_; } + int bytes_per_frame() const { return bytes_per_frame_; } + + // Optional byte data required to initialize audio decoders such as Vorbis + // codebooks. + const uint8_t* extra_data() const { + return extra_data_.empty() ? NULL : &extra_data_[0]; + } + size_t extra_data_size() const { return extra_data_.size(); } + + // Whether the audio stream is potentially encrypted. + // Note that in a potentially encrypted audio stream, individual buffers + // can be encrypted or not encrypted. + bool is_encrypted() const { return is_encrypted_; } + + std::string AsHumanReadableString() const; + + private: + AudioCodec codec_; + SampleFormat sample_format_; + int bits_per_channel_; + ChannelLayout channel_layout_; + int samples_per_second_; + int bytes_per_frame_; + std::vector extra_data_; + bool is_encrypted_; + + // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler + // generated copy constructor and assignment operator. Since the extra data is + // typically small, the performance impact is minimal. +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_BASE_AUDIO_DECODER_CONFIG_H_ diff --git a/content/media/fmp4/demuxer/avc.cc b/content/media/fmp4/demuxer/avc.cc new file mode 100644 index 000000000000..d03790860860 --- /dev/null +++ b/content/media/fmp4/demuxer/avc.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/avc.h" + +#include +#include + +#include "mp4_demuxer/box_definitions.h" +#include "mp4_demuxer/box_reader.h" + +namespace mp4_demuxer { + +static const uint8_t kAnnexBStartCode[] = {0, 0, 0, 1}; +static const int kAnnexBStartCodeSize = 4; + +static bool ConvertAVCToAnnexBInPlaceForLengthSize4(std::vector* buf) { + const int kLengthSize = 4; + size_t pos = 0; + while (pos + kLengthSize < buf->size()) { + int nal_size = (*buf)[pos]; + nal_size = (nal_size << 8) + (*buf)[pos+1]; + nal_size = (nal_size << 8) + (*buf)[pos+2]; + nal_size = (nal_size << 8) + (*buf)[pos+3]; + std::copy(kAnnexBStartCode, kAnnexBStartCode + kAnnexBStartCodeSize, + buf->begin() + pos); + pos += kLengthSize + nal_size; + } + return pos == buf->size(); +} + +// static +bool AVC::ConvertFrameToAnnexB(int length_size, std::vector* buffer) { + RCHECK(length_size == 1 || length_size == 2 || length_size == 4); + + if (length_size == 4) + return ConvertAVCToAnnexBInPlaceForLengthSize4(buffer); + + std::vector temp; + temp.swap(*buffer); + buffer->reserve(temp.size() + 32); + + size_t pos = 0; + while (pos + length_size < temp.size()) { + int nal_size = temp[pos]; + if (length_size == 2) nal_size = (nal_size << 8) + temp[pos+1]; + pos += length_size; + + RCHECK(pos + nal_size <= temp.size()); + buffer->insert(buffer->end(), kAnnexBStartCode, + kAnnexBStartCode + kAnnexBStartCodeSize); + buffer->insert(buffer->end(), temp.begin() + pos, + temp.begin() + pos + nal_size); + pos += nal_size; + } + return pos == temp.size(); +} + +// static +bool AVC::ConvertConfigToAnnexB( + const AVCDecoderConfigurationRecord& avc_config, + std::vector* buffer) { + DCHECK(buffer->empty()); + buffer->clear(); + int total_size = 0; + for (size_t i = 0; i < avc_config.sps_list.size(); i++) + total_size += avc_config.sps_list[i].size() + kAnnexBStartCodeSize; + for (size_t i = 0; i < avc_config.pps_list.size(); i++) + total_size += avc_config.pps_list[i].size() + kAnnexBStartCodeSize; + buffer->reserve(total_size); + + for (size_t i = 0; i < avc_config.sps_list.size(); i++) { + buffer->insert(buffer->end(), kAnnexBStartCode, + kAnnexBStartCode + kAnnexBStartCodeSize); + buffer->insert(buffer->end(), avc_config.sps_list[i].begin(), + avc_config.sps_list[i].end()); + } + + for (size_t i = 0; i < avc_config.pps_list.size(); i++) { + buffer->insert(buffer->end(), kAnnexBStartCode, + kAnnexBStartCode + kAnnexBStartCodeSize); + buffer->insert(buffer->end(), avc_config.pps_list[i].begin(), + avc_config.pps_list[i].end()); + } + return true; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/avc.h b/content/media/fmp4/demuxer/avc.h new file mode 100644 index 000000000000..150a4e10975d --- /dev/null +++ b/content/media/fmp4/demuxer/avc.h @@ -0,0 +1,27 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_AVC_H_ +#define MEDIA_MP4_AVC_H_ + +#include + +#include "mp4_demuxer/basictypes.h" + +namespace mp4_demuxer { + +struct AVCDecoderConfigurationRecord; + +class AVC { + public: + static bool ConvertFrameToAnnexB(int length_size, std::vector* buffer); + + static bool ConvertConfigToAnnexB( + const AVCDecoderConfigurationRecord& avc_config, + std::vector* buffer); +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_AVC_H_ diff --git a/content/media/fmp4/demuxer/basictypes.h b/content/media/fmp4/demuxer/basictypes.h new file mode 100644 index 000000000000..ad77f0a9dc3a --- /dev/null +++ b/content/media/fmp4/demuxer/basictypes.h @@ -0,0 +1,166 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_BASIC_TYPES_H_ +#define MEDIA_MP4_BASIC_TYPES_H_ + +#include +#include + +namespace mp4_demuxer { + +// Define to enable logging. +//#define LOG_DEMUXER + +#define kint32max std::numeric_limits::max() +#define kuint64max std::numeric_limits::max() +#define kint64max std::numeric_limits::max() + + + +#define OVERRIDE override +#define WARN_UNUSED_RESULT + +#define DCHECK(condition) \ +{ \ + if (!(condition)) {\ + DMX_LOG("DCHECK Failed (%s) %s:%d\n", #condition, __FILE__, __LINE__); \ + } \ +} + +#define CHECK(condition) { \ + if (!(condition)) {\ + DMX_LOG("CHECK Failed %s %s:%d\n", #condition, __FILE__, __LINE__); \ + } \ +} + +#define DCHECK_LE(variable, value) DCHECK(variable <= value) +#define DCHECK_LT(variable, value) DCHECK(variable < value) +#define DCHECK_EQ(variable, value) DCHECK(variable == value) +#define DCHECK_GT(variable, value) DCHECK(variable > value) +#define DCHECK_GE(variable, value) DCHECK(variable >= value) + +#define RCHECK(x) \ + do { \ + if (!(x)) { \ + DMX_LOG("Failure while parsing MP4: %s %s:%d\n", #x, __FILE__, __LINE__); \ + return false; \ + } \ + } while (0) + +#define arraysize(f) (sizeof(f) / sizeof(*f)) + +#ifdef LOG_DEMUXER +#define DMX_LOG(...) printf(__VA_ARGS__) +#else +// define DMX_LOG as 0, so that if(condition){DMX_LOG(...)} branches don't elicit +// a warning-as-error. +#define DMX_LOG(...) 0 +#endif + +// A macro to disallow the evil copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +typedef int64_t Microseconds; +typedef int64_t Milliseconds; + +#define MicrosecondsPerSecond (int64_t(1000000)) +#define InfiniteMicroseconds (int64_t(-1)) +#define InfiniteMilliseconds (int64_t(-1)) + +inline Microseconds MicrosecondsFromRational(int64_t numer, int64_t denom) { + DCHECK_LT((numer > 0 ? numer : -numer), + kint64max / MicrosecondsPerSecond); + return MicrosecondsPerSecond * numer / denom; +} + +inline Milliseconds ToMilliseconds(Microseconds us) { + return (us == InfiniteMicroseconds) ? InfiniteMilliseconds : us / 1000; +} + +class IntSize { +public: + IntSize() : w_(0), h_(0) {} + IntSize(const IntSize& i) : w_(i.w_), h_(i.h_) {} + IntSize(int32_t w, int32_t h) : w_(w), h_(h) {} + ~IntSize() {}; + int32_t width() const { return w_; } + int32_t height() const { return h_; } + int32_t GetArea() const { return w_ * h_; } + bool IsEmpty() const { return (w_ == 0) || (h_ == 0); } +private: + int32_t w_; + int32_t h_; +}; + +inline bool operator==(const IntSize& lhs, const IntSize& rhs) { + return lhs.width() == rhs.width() && + lhs.height() == rhs.height(); +} + +class IntRect { +public: + IntRect() : x_(0), y_(0), w_(0), h_(0) {} + IntRect(const IntRect& i) : x_(i.x_), y_(i.y_), w_(i.w_), h_(i.h_) {} + IntRect(int32_t x, int32_t y, int32_t w, int32_t h) : x_(x), y_(y), w_(w), h_(h) {} + ~IntRect() {}; + IntSize size() const { return IntSize(w_, h_); } + int32_t x() const { return x_; } + int32_t y() const { return y_; } + int32_t width() const { return w_; } + int32_t height() const { return h_; } + int32_t GetArea() const { return w_ * h_; } + bool IsEmpty() const { return (w_ == 0) || (h_ == 0); } + int32_t right() const { return x() + width(); } + int32_t bottom() const { return y() + height(); } +private: + int32_t x_; + int32_t y_; + int32_t w_; + int32_t h_; +}; + +inline bool operator==(const IntRect& lhs, const IntRect& rhs) { + return lhs.x() == rhs.x() && + lhs.y() == rhs.y() && + lhs.width() == rhs.width() && + lhs.height() == rhs.height(); +} + +enum { + // Maximum possible dimension (width or height) for any video. + kMaxDimension = (1 << 15) - 1, // 32767 + + // Maximum possible canvas size (width multiplied by height) for any video. + kMaxCanvas = (1 << (14 * 2)), // 16384 x 16384 + + // Total number of video frames which are populating in the pipeline. + kMaxVideoFrames = 4, + + // The following limits are used by AudioParameters::IsValid(). + // + // A few notes on sample rates of common formats: + // - AAC files are limited to 96 kHz. + // - MP3 files are limited to 48 kHz. + // - Vorbis used to be limited to 96 KHz, but no longer has that + // restriction. + // - Most PC audio hardware is limited to 192 KHz. + kMaxSampleRate = 192000, + kMinSampleRate = 3000, + kMaxChannels = 32, + kMaxBitsPerSample = 32, + kMaxSamplesPerPacket = kMaxSampleRate, + kMaxPacketSizeInBytes = + (kMaxBitsPerSample / 8) * kMaxChannels * kMaxSamplesPerPacket, + + // This limit is used by ParamTraits. + kMaxFramesPerSecond = 1000, +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_BASIC_TYPES_H_ diff --git a/content/media/fmp4/demuxer/bit_reader.cc b/content/media/fmp4/demuxer/bit_reader.cc new file mode 100644 index 000000000000..3677021a589e --- /dev/null +++ b/content/media/fmp4/demuxer/bit_reader.cc @@ -0,0 +1,56 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/bit_reader.h" + +namespace mp4_demuxer { + +BitReader::BitReader(const uint8_t* data, off_t size) + : data_(data), bytes_left_(size), num_remaining_bits_in_curr_byte_(0) { + DCHECK(data_ != nullptr && bytes_left_ > 0); + + UpdateCurrByte(); +} + +BitReader::~BitReader() {} + +int BitReader::bits_available() const { + return 8 * bytes_left_ + num_remaining_bits_in_curr_byte_; +} + +bool BitReader::ReadBitsInternal(int num_bits, uint64_t* out) { + DCHECK_LE(num_bits, 64); + + *out = 0; + + while (num_remaining_bits_in_curr_byte_ != 0 && num_bits != 0) { + int bits_to_take = std::min(num_remaining_bits_in_curr_byte_, num_bits); + + *out <<= bits_to_take; + *out += curr_byte_ >> (num_remaining_bits_in_curr_byte_ - bits_to_take); + num_bits -= bits_to_take; + num_remaining_bits_in_curr_byte_ -= bits_to_take; + curr_byte_ &= (1 << num_remaining_bits_in_curr_byte_) - 1; + + if (num_remaining_bits_in_curr_byte_ == 0) + UpdateCurrByte(); + } + + return num_bits == 0; +} + +void BitReader::UpdateCurrByte() { + DCHECK_EQ(num_remaining_bits_in_curr_byte_, 0); + + if (bytes_left_ == 0) + return; + + // Load a new byte and advance pointers. + curr_byte_ = *data_; + ++data_; + --bytes_left_; + num_remaining_bits_in_curr_byte_ = 8; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/bit_reader.h b/content/media/fmp4/demuxer/bit_reader.h new file mode 100644 index 000000000000..0657c25397df --- /dev/null +++ b/content/media/fmp4/demuxer/bit_reader.h @@ -0,0 +1,69 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_BIT_READER_H_ +#define MEDIA_BASE_BIT_READER_H_ + +#include + +#include "mp4_demuxer/basictypes.h" + +namespace mp4_demuxer { + +// A class to read bit streams. +class BitReader { + public: + // Initialize the reader to start reading at |data|, |size| being size + // of |data| in bytes. + BitReader(const uint8_t* data, off_t size); + ~BitReader(); + + // Read |num_bits| next bits from stream and return in |*out|, first bit + // from the stream starting at |num_bits| position in |*out|. + // |num_bits| cannot be larger than the bits the type can hold. + // Return false if the given number of bits cannot be read (not enough + // bits in the stream), true otherwise. When return false, the stream will + // enter a state where further ReadBits/SkipBits operations will always + // return false unless |num_bits| is 0. The type |T| has to be a primitive + // integer type. + template bool ReadBits(int num_bits, T *out) { + DCHECK_LE(num_bits, static_cast(sizeof(T) * 8)); + uint64_t temp; + bool ret = ReadBitsInternal(num_bits, &temp); + *out = static_cast(temp); + return ret; + } + + // Returns the number of bits available for reading. + int bits_available() const; + + private: + // Help function used by ReadBits to avoid inlining the bit reading logic. + bool ReadBitsInternal(int num_bits, uint64_t* out); + + // Advance to the next byte, loading it into curr_byte_. + // If the num_remaining_bits_in_curr_byte_ is 0 after this function returns, + // the stream has reached the end. + void UpdateCurrByte(); + + // Pointer to the next unread (not in curr_byte_) byte in the stream. + const uint8_t* data_; + + // Bytes left in the stream (without the curr_byte_). + off_t bytes_left_; + + // Contents of the current byte; first unread bit starting at position + // 8 - num_remaining_bits_in_curr_byte_ from MSB. + uint8_t curr_byte_; + + // Number of bits remaining in curr_byte_ + int num_remaining_bits_in_curr_byte_; + + private: + DISALLOW_COPY_AND_ASSIGN(BitReader); +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_BASE_BIT_READER_H_ diff --git a/content/media/fmp4/demuxer/box_definitions.cc b/content/media/fmp4/demuxer/box_definitions.cc new file mode 100644 index 000000000000..7dfb53fced65 --- /dev/null +++ b/content/media/fmp4/demuxer/box_definitions.cc @@ -0,0 +1,754 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/box_definitions.h" +#include "mp4_demuxer/es_descriptor.h" + +#include + +namespace mp4_demuxer { + +FileType::FileType() {} +FileType::~FileType() {} +FourCC FileType::BoxType() const { return FOURCC_FTYP; } + +bool FileType::Parse(BoxReader* reader) { + RCHECK(reader->ReadFourCC(&major_brand) && reader->Read4(&minor_version)); + size_t num_brands = (reader->size() - reader->pos()) / sizeof(FourCC); + return reader->SkipBytes(sizeof(FourCC) * num_brands); // compatible_brands +} + +ProtectionSystemSpecificHeader::ProtectionSystemSpecificHeader() {} +ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {} +FourCC ProtectionSystemSpecificHeader::BoxType() const { return FOURCC_PSSH; } + +bool ProtectionSystemSpecificHeader::Parse(BoxReader* reader) { + // Validate the box's contents and hang on to the system ID. + uint32_t size; + RCHECK(reader->ReadFullBoxHeader() && + reader->ReadVec(&system_id, 16) && + reader->Read4(&size) && + reader->HasBytes(size)); + + // Copy the entire box, including the header, for passing to EME as initData. + DCHECK(raw_box.empty()); + reader->ReadVec(&raw_box, size); + //raw_box.assign(reader->data(), reader->data() + size); + return true; +} + +SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {} +SampleAuxiliaryInformationOffset::~SampleAuxiliaryInformationOffset() {} +FourCC SampleAuxiliaryInformationOffset::BoxType() const { return FOURCC_SAIO; } + +bool SampleAuxiliaryInformationOffset::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader()); + if (reader->flags() & 1) + RCHECK(reader->SkipBytes(8)); + + uint32_t count; + RCHECK(reader->Read4(&count) && + reader->HasBytes(count * (reader->version() == 1 ? 8 : 4))); + offsets.resize(count); + + for (uint32_t i = 0; i < count; i++) { + if (reader->version() == 1) { + RCHECK(reader->Read8(&offsets[i])); + } else { + RCHECK(reader->Read4Into8(&offsets[i])); + } + } + return true; +} + +SampleAuxiliaryInformationSize::SampleAuxiliaryInformationSize() + : default_sample_info_size(0), sample_count(0) { +} +SampleAuxiliaryInformationSize::~SampleAuxiliaryInformationSize() {} +FourCC SampleAuxiliaryInformationSize::BoxType() const { return FOURCC_SAIZ; } + +bool SampleAuxiliaryInformationSize::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader()); + if (reader->flags() & 1) + RCHECK(reader->SkipBytes(8)); + + RCHECK(reader->Read1(&default_sample_info_size) && + reader->Read4(&sample_count)); + if (default_sample_info_size == 0) + return reader->ReadVec(&sample_info_sizes, sample_count); + return true; +} + +OriginalFormat::OriginalFormat() : format(FOURCC_NULL) {} +OriginalFormat::~OriginalFormat() {} +FourCC OriginalFormat::BoxType() const { return FOURCC_FRMA; } + +bool OriginalFormat::Parse(BoxReader* reader) { + return reader->ReadFourCC(&format); +} + +SchemeType::SchemeType() : type(FOURCC_NULL), version(0) {} +SchemeType::~SchemeType() {} +FourCC SchemeType::BoxType() const { return FOURCC_SCHM; } + +bool SchemeType::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader() && + reader->ReadFourCC(&type) && + reader->Read4(&version)); + return true; +} + +TrackEncryption::TrackEncryption() + : is_encrypted(false), default_iv_size(0) { +} +TrackEncryption::~TrackEncryption() {} +FourCC TrackEncryption::BoxType() const { return FOURCC_TENC; } + +bool TrackEncryption::Parse(BoxReader* reader) { + uint8_t flag; + RCHECK(reader->ReadFullBoxHeader() && + reader->SkipBytes(2) && + reader->Read1(&flag) && + reader->Read1(&default_iv_size) && + reader->ReadVec(&default_kid, 16)); + is_encrypted = (flag != 0); + if (is_encrypted) { + RCHECK(default_iv_size == 8 || default_iv_size == 16); + } else { + RCHECK(default_iv_size == 0); + } + return true; +} + +SchemeInfo::SchemeInfo() {} +SchemeInfo::~SchemeInfo() {} +FourCC SchemeInfo::BoxType() const { return FOURCC_SCHI; } + +bool SchemeInfo::Parse(BoxReader* reader) { + return reader->ScanChildren() && reader->ReadChild(&track_encryption); +} + +ProtectionSchemeInfo::ProtectionSchemeInfo() {} +ProtectionSchemeInfo::~ProtectionSchemeInfo() {} +FourCC ProtectionSchemeInfo::BoxType() const { return FOURCC_SINF; } + +bool ProtectionSchemeInfo::Parse(BoxReader* reader) { + RCHECK(reader->ScanChildren() && + reader->ReadChild(&format) && + reader->ReadChild(&type)); + if (type.type == FOURCC_CENC) + RCHECK(reader->ReadChild(&info)); + // Other protection schemes are silently ignored. Since the protection scheme + // type can't be determined until this box is opened, we return 'true' for + // non-CENC protection scheme types. It is the parent box's responsibility to + // ensure that this scheme type is a supported one. + return true; +} + +MovieHeader::MovieHeader() + : creation_time(0), + modification_time(0), + timescale(0), + duration(0), + rate(-1), + volume(-1), + next_track_id(0) {} +MovieHeader::~MovieHeader() {} +FourCC MovieHeader::BoxType() const { return FOURCC_MVHD; } + +bool MovieHeader::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader()); + + if (reader->version() == 1) { + RCHECK(reader->Read8(&creation_time) && + reader->Read8(&modification_time) && + reader->Read4(×cale) && + reader->Read8(&duration)); + } else { + RCHECK(reader->Read4Into8(&creation_time) && + reader->Read4Into8(&modification_time) && + reader->Read4(×cale) && + reader->Read4Into8(&duration)); + } + + RCHECK(reader->Read4s(&rate) && + reader->Read2s(&volume) && + reader->SkipBytes(10) && // reserved + reader->SkipBytes(36) && // matrix + reader->SkipBytes(24) && // predefined zero + reader->Read4(&next_track_id)); + return true; +} + +TrackHeader::TrackHeader() + : creation_time(0), + modification_time(0), + track_id(0), + duration(0), + layer(-1), + alternate_group(-1), + volume(-1), + width(0), + height(0) {} +TrackHeader::~TrackHeader() {} +FourCC TrackHeader::BoxType() const { return FOURCC_TKHD; } + +bool TrackHeader::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader()); + if (reader->version() == 1) { + RCHECK(reader->Read8(&creation_time) && + reader->Read8(&modification_time) && + reader->Read4(&track_id) && + reader->SkipBytes(4) && // reserved + reader->Read8(&duration)); + } else { + RCHECK(reader->Read4Into8(&creation_time) && + reader->Read4Into8(&modification_time) && + reader->Read4(&track_id) && + reader->SkipBytes(4) && // reserved + reader->Read4Into8(&duration)); + } + + RCHECK(reader->SkipBytes(8) && // reserved + reader->Read2s(&layer) && + reader->Read2s(&alternate_group) && + reader->Read2s(&volume) && + reader->SkipBytes(2) && // reserved + reader->SkipBytes(36) && // matrix + reader->Read4(&width) && + reader->Read4(&height)); + width >>= 16; + height >>= 16; + return true; +} + +SampleDescription::SampleDescription() : type(kInvalid) {} +SampleDescription::~SampleDescription() {} +FourCC SampleDescription::BoxType() const { return FOURCC_STSD; } + +bool SampleDescription::Parse(BoxReader* reader) { + uint32_t count; + RCHECK(reader->SkipBytes(4) && + reader->Read4(&count)); + video_entries.clear(); + audio_entries.clear(); + + // Note: this value is preset before scanning begins. See comments in the + // Parse(Media*) function. + if (type == kVideo) { + RCHECK(reader->ReadAllChildren(&video_entries)); + } else if (type == kAudio) { + RCHECK(reader->ReadAllChildren(&audio_entries)); + } + return true; +} + +SampleTable::SampleTable() {} +SampleTable::~SampleTable() {} +FourCC SampleTable::BoxType() const { return FOURCC_STBL; } + +bool SampleTable::Parse(BoxReader* reader) { + return reader->ScanChildren() && + reader->ReadChild(&description); +} + +EditList::EditList() {} +EditList::~EditList() {} +FourCC EditList::BoxType() const { return FOURCC_ELST; } + +bool EditList::Parse(BoxReader* reader) { + uint32_t count; + RCHECK(reader->ReadFullBoxHeader() && reader->Read4(&count)); + + if (reader->version() == 1) { + RCHECK(reader->HasBytes(count * 20)); + } else { + RCHECK(reader->HasBytes(count * 12)); + } + edits.resize(count); + + for (std::vector::iterator edit = edits.begin(); + edit != edits.end(); ++edit) { + if (reader->version() == 1) { + RCHECK(reader->Read8(&edit->segment_duration) && + reader->Read8s(&edit->media_time)); + } else { + RCHECK(reader->Read4Into8(&edit->segment_duration) && + reader->Read4sInto8s(&edit->media_time)); + } + RCHECK(reader->Read2s(&edit->media_rate_integer) && + reader->Read2s(&edit->media_rate_fraction)); + } + return true; +} + +Edit::Edit() {} +Edit::~Edit() {} +FourCC Edit::BoxType() const { return FOURCC_EDTS; } + +bool Edit::Parse(BoxReader* reader) { + return reader->ScanChildren() && reader->ReadChild(&list); +} + +HandlerReference::HandlerReference() : type(kInvalid) {} +HandlerReference::~HandlerReference() {} +FourCC HandlerReference::BoxType() const { return FOURCC_HDLR; } + +bool HandlerReference::Parse(BoxReader* reader) { + FourCC hdlr_type; + RCHECK(reader->SkipBytes(8) && reader->ReadFourCC(&hdlr_type)); + // Note: remaining fields in box ignored + if (hdlr_type == FOURCC_VIDE) { + type = kVideo; + } else if (hdlr_type == FOURCC_SOUN) { + type = kAudio; + } else { + type = kInvalid; + } + return true; +} + +AVCDecoderConfigurationRecord::AVCDecoderConfigurationRecord() + : version(0), + profile_indication(0), + profile_compatibility(0), + avc_level(0), + length_size(0) {} + +AVCDecoderConfigurationRecord::~AVCDecoderConfigurationRecord() {} +FourCC AVCDecoderConfigurationRecord::BoxType() const { return FOURCC_AVCC; } + +bool AVCDecoderConfigurationRecord::Parse(BoxReader* reader) { + RCHECK(reader->Read1(&version) && version == 1 && + reader->Read1(&profile_indication) && + reader->Read1(&profile_compatibility) && + reader->Read1(&avc_level)); + + uint8_t length_size_minus_one; + RCHECK(reader->Read1(&length_size_minus_one) && + (length_size_minus_one & 0xfc) == 0xfc); + length_size = (length_size_minus_one & 0x3) + 1; + + uint8_t num_sps; + RCHECK(reader->Read1(&num_sps) && (num_sps & 0xe0) == 0xe0); + num_sps &= 0x1f; + + sps_list.resize(num_sps); + for (int i = 0; i < num_sps; i++) { + uint16_t sps_length; + RCHECK(reader->Read2(&sps_length) && + reader->ReadVec(&sps_list[i], sps_length)); + } + + uint8_t num_pps; + RCHECK(reader->Read1(&num_pps)); + + pps_list.resize(num_pps); + for (int i = 0; i < num_pps; i++) { + uint16_t pps_length; + RCHECK(reader->Read2(&pps_length) && + reader->ReadVec(&pps_list[i], pps_length)); + } + + return true; +} + +PixelAspectRatioBox::PixelAspectRatioBox() : h_spacing(1), v_spacing(1) {} +PixelAspectRatioBox::~PixelAspectRatioBox() {} +FourCC PixelAspectRatioBox::BoxType() const { return FOURCC_PASP; } + +bool PixelAspectRatioBox::Parse(BoxReader* reader) { + RCHECK(reader->Read4(&h_spacing) && + reader->Read4(&v_spacing)); + return true; +} + +VideoSampleEntry::VideoSampleEntry() + : format(FOURCC_NULL), + data_reference_index(0), + width(0), + height(0) {} + +VideoSampleEntry::~VideoSampleEntry() {} +FourCC VideoSampleEntry::BoxType() const { + DMX_LOG("VideoSampleEntry should be parsed according to the " + "handler type recovered in its Media ancestor.\n"); + return FOURCC_NULL; +} + +bool VideoSampleEntry::Parse(BoxReader* reader) { + format = reader->type(); + RCHECK(reader->SkipBytes(6) && + reader->Read2(&data_reference_index) && + reader->SkipBytes(16) && + reader->Read2(&width) && + reader->Read2(&height) && + reader->SkipBytes(50)); + + RCHECK(reader->ScanChildren() && + reader->MaybeReadChild(&pixel_aspect)); + + if (format == FOURCC_ENCV) { + // Continue scanning until a recognized protection scheme is found, or until + // we run out of protection schemes. + while (sinf.type.type != FOURCC_CENC) { + if (!reader->ReadChild(&sinf)) + return false; + } + } + + if (format == FOURCC_AVC1 || + (format == FOURCC_ENCV && sinf.format.format == FOURCC_AVC1)) { + RCHECK(reader->ReadChild(&avcc)); + } + return true; +} + +ElementaryStreamDescriptor::ElementaryStreamDescriptor() + : object_type(kForbidden) {} + +ElementaryStreamDescriptor::~ElementaryStreamDescriptor() {} + +FourCC ElementaryStreamDescriptor::BoxType() const { + return FOURCC_ESDS; +} + +bool ElementaryStreamDescriptor::Parse(BoxReader* reader) { + std::vector data; + ESDescriptor es_desc; + + RCHECK(reader->ReadFullBoxHeader()); + RCHECK(reader->ReadVec(&data, reader->size() - reader->pos())); + RCHECK(es_desc.Parse(data)); + + object_type = es_desc.object_type(); + + RCHECK(aac.Parse(es_desc.decoder_specific_info())); + + return true; +} + +AudioSampleEntry::AudioSampleEntry() + : format(FOURCC_NULL), + data_reference_index(0), + channelcount(0), + samplesize(0), + samplerate(0) {} + +AudioSampleEntry::~AudioSampleEntry() {} + +FourCC AudioSampleEntry::BoxType() const { + DMX_LOG("AudioSampleEntry should be parsed according to the " + "handler type recovered in its Media ancestor.\n"); + return FOURCC_NULL; +} + +bool AudioSampleEntry::Parse(BoxReader* reader) { + format = reader->type(); + RCHECK(reader->SkipBytes(6) && + reader->Read2(&data_reference_index) && + reader->SkipBytes(8) && + reader->Read2(&channelcount) && + reader->Read2(&samplesize) && + reader->SkipBytes(4) && + reader->Read4(&samplerate)); + // Convert from 16.16 fixed point to integer + samplerate >>= 16; + + RCHECK(reader->ScanChildren()); + if (format == FOURCC_ENCA) { + // Continue scanning until a recognized protection scheme is found, or until + // we run out of protection schemes. + while (sinf.type.type != FOURCC_CENC) { + if (!reader->ReadChild(&sinf)) + return false; + } + } + + RCHECK(reader->ReadChild(&esds)); + return true; +} + +MediaHeader::MediaHeader() + : creation_time(0), + modification_time(0), + timescale(0), + duration(0) {} +MediaHeader::~MediaHeader() {} +FourCC MediaHeader::BoxType() const { return FOURCC_MDHD; } + +bool MediaHeader::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader()); + + if (reader->version() == 1) { + RCHECK(reader->Read8(&creation_time) && + reader->Read8(&modification_time) && + reader->Read4(×cale) && + reader->Read8(&duration)); + } else { + RCHECK(reader->Read4Into8(&creation_time) && + reader->Read4Into8(&modification_time) && + reader->Read4(×cale) && + reader->Read4Into8(&duration)); + } + // Skip language information + return reader->SkipBytes(4); +} + +MediaInformation::MediaInformation() {} +MediaInformation::~MediaInformation() {} +FourCC MediaInformation::BoxType() const { return FOURCC_MINF; } + +bool MediaInformation::Parse(BoxReader* reader) { + return reader->ScanChildren() && + reader->ReadChild(&sample_table); +} + +Media::Media() {} +Media::~Media() {} +FourCC Media::BoxType() const { return FOURCC_MDIA; } + +bool Media::Parse(BoxReader* reader) { + RCHECK(reader->ScanChildren() && + reader->ReadChild(&header) && + reader->ReadChild(&handler)); + + // Maddeningly, the HandlerReference box specifies how to parse the + // SampleDescription box, making the latter the only box (of those that we + // support) which cannot be parsed correctly on its own (or even with + // information from its strict ancestor tree). We thus copy the handler type + // to the sample description box *before* parsing it to provide this + // information while parsing. + information.sample_table.description.type = handler.type; + RCHECK(reader->ReadChild(&information)); + return true; +} + +Track::Track() {} +Track::~Track() {} +FourCC Track::BoxType() const { return FOURCC_TRAK; } + +bool Track::Parse(BoxReader* reader) { + RCHECK(reader->ScanChildren() && + reader->ReadChild(&header) && + reader->ReadChild(&media) && + reader->MaybeReadChild(&edit)); + return true; +} + +MovieExtendsHeader::MovieExtendsHeader() : fragment_duration(0) {} +MovieExtendsHeader::~MovieExtendsHeader() {} +FourCC MovieExtendsHeader::BoxType() const { return FOURCC_MEHD; } + +bool MovieExtendsHeader::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader()); + if (reader->version() == 1) { + RCHECK(reader->Read8(&fragment_duration)); + } else { + RCHECK(reader->Read4Into8(&fragment_duration)); + } + return true; +} + +TrackExtends::TrackExtends() + : track_id(0), + default_sample_description_index(0), + default_sample_duration(0), + default_sample_size(0), + default_sample_flags(0) {} +TrackExtends::~TrackExtends() {} +FourCC TrackExtends::BoxType() const { return FOURCC_TREX; } + +bool TrackExtends::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader() && + reader->Read4(&track_id) && + reader->Read4(&default_sample_description_index) && + reader->Read4(&default_sample_duration) && + reader->Read4(&default_sample_size) && + reader->Read4(&default_sample_flags)); + return true; +} + +MovieExtends::MovieExtends() {} +MovieExtends::~MovieExtends() {} +FourCC MovieExtends::BoxType() const { return FOURCC_MVEX; } + +bool MovieExtends::Parse(BoxReader* reader) { + header.fragment_duration = 0; + return reader->ScanChildren() && + reader->MaybeReadChild(&header) && + reader->ReadChildren(&tracks); +} + +Movie::Movie() : fragmented(false) {} +Movie::~Movie() {} +FourCC Movie::BoxType() const { return FOURCC_MOOV; } + +bool Movie::Parse(BoxReader* reader) { + return reader->ScanChildren() && + reader->ReadChild(&header) && + reader->ReadChildren(&tracks) && + // Media Source specific: 'mvex' required + reader->ReadChild(&extends) && + reader->MaybeReadChildren(&pssh); +} + +TrackFragmentDecodeTime::TrackFragmentDecodeTime() : decode_time(0) {} +TrackFragmentDecodeTime::~TrackFragmentDecodeTime() {} +FourCC TrackFragmentDecodeTime::BoxType() const { return FOURCC_TFDT; } + +bool TrackFragmentDecodeTime::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader()); + if (reader->version() == 1) + return reader->Read8(&decode_time); + else + return reader->Read4Into8(&decode_time); +} + +MovieFragmentHeader::MovieFragmentHeader() : sequence_number(0) {} +MovieFragmentHeader::~MovieFragmentHeader() {} +FourCC MovieFragmentHeader::BoxType() const { return FOURCC_MFHD; } + +bool MovieFragmentHeader::Parse(BoxReader* reader) { + return reader->SkipBytes(4) && reader->Read4(&sequence_number); +} + +TrackFragmentHeader::TrackFragmentHeader() + : track_id(0), + sample_description_index(0), + default_sample_duration(0), + default_sample_size(0), + default_sample_flags(0), + has_default_sample_flags(false) {} + +TrackFragmentHeader::~TrackFragmentHeader() {} +FourCC TrackFragmentHeader::BoxType() const { return FOURCC_TFHD; } + +bool TrackFragmentHeader::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader() && reader->Read4(&track_id)); + + // Media Source specific: reject tracks that set 'base-data-offset-present'. + // Although the Media Source requires that 'default-base-is-moof' (14496-12 + // Amendment 2) be set, we omit this check as many otherwise-valid files in + // the wild don't set it. + // + // RCHECK((flags & 0x020000) && !(flags & 0x1)); + RCHECK(!(reader->flags() & 0x1)); + + if (reader->flags() & 0x2) { + RCHECK(reader->Read4(&sample_description_index)); + } else { + sample_description_index = 0; + } + + if (reader->flags() & 0x8) { + RCHECK(reader->Read4(&default_sample_duration)); + } else { + default_sample_duration = 0; + } + + if (reader->flags() & 0x10) { + RCHECK(reader->Read4(&default_sample_size)); + } else { + default_sample_size = 0; + } + + if (reader->flags() & 0x20) { + RCHECK(reader->Read4(&default_sample_flags)); + has_default_sample_flags = true; + } else { + has_default_sample_flags = false; + } + + return true; +} + +TrackFragmentRun::TrackFragmentRun() + : sample_count(0), data_offset(0) {} +TrackFragmentRun::~TrackFragmentRun() {} +FourCC TrackFragmentRun::BoxType() const { return FOURCC_TRUN; } + +bool TrackFragmentRun::Parse(BoxReader* reader) { + RCHECK(reader->ReadFullBoxHeader() && + reader->Read4(&sample_count)); + const uint32_t flags = reader->flags(); + + bool data_offset_present = (flags & 0x1) != 0; + bool first_sample_flags_present = (flags & 0x4) != 0; + bool sample_duration_present = (flags & 0x100) != 0; + bool sample_size_present = (flags & 0x200) != 0; + bool sample_flags_present = (flags & 0x400) != 0; + bool sample_composition_time_offsets_present = (flags & 0x800) != 0; + + if (data_offset_present) { + RCHECK(reader->Read4(&data_offset)); + } else { + data_offset = 0; + } + + uint32_t first_sample_flags; + if (first_sample_flags_present) + RCHECK(reader->Read4(&first_sample_flags)); + + int fields = sample_duration_present + sample_size_present + + sample_flags_present + sample_composition_time_offsets_present; + RCHECK(reader->HasBytes(fields * sample_count)); + + if (sample_duration_present) + sample_durations.resize(sample_count); + if (sample_size_present) + sample_sizes.resize(sample_count); + if (sample_flags_present) + sample_flags.resize(sample_count); + if (sample_composition_time_offsets_present) + sample_composition_time_offsets.resize(sample_count); + + for (uint32_t i = 0; i < sample_count; ++i) { + if (sample_duration_present) + RCHECK(reader->Read4(&sample_durations[i])); + if (sample_size_present) + RCHECK(reader->Read4(&sample_sizes[i])); + if (sample_flags_present) + RCHECK(reader->Read4(&sample_flags[i])); + if (sample_composition_time_offsets_present) + RCHECK(reader->Read4s(&sample_composition_time_offsets[i])); + } + + if (first_sample_flags_present) { + if (sample_flags.size() == 0) { + sample_flags.push_back(first_sample_flags); + } else { + sample_flags[0] = first_sample_flags; + } + } + return true; +} + +TrackFragment::TrackFragment() {} +TrackFragment::~TrackFragment() {} +FourCC TrackFragment::BoxType() const { return FOURCC_TRAF; } + +bool TrackFragment::Parse(BoxReader* reader) { + return reader->ScanChildren() && + reader->ReadChild(&header) && + // Media Source specific: 'tfdt' required + reader->ReadChild(&decode_time) && + reader->MaybeReadChildren(&runs) && + reader->MaybeReadChild(&auxiliary_offset) && + reader->MaybeReadChild(&auxiliary_size); +} + +MovieFragment::MovieFragment() {} +MovieFragment::~MovieFragment() {} +FourCC MovieFragment::BoxType() const { return FOURCC_MOOF; } + +bool MovieFragment::Parse(BoxReader* reader) { + RCHECK(reader->ScanChildren() && + reader->ReadChild(&header) && + reader->ReadChildren(&tracks) && + reader->MaybeReadChildren(&pssh)); + return true; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/box_definitions.h b/content/media/fmp4/demuxer/box_definitions.h new file mode 100644 index 000000000000..d82c7269fbda --- /dev/null +++ b/content/media/fmp4/demuxer/box_definitions.h @@ -0,0 +1,349 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_BOX_DEFINITIONS_H_ +#define MEDIA_MP4_BOX_DEFINITIONS_H_ + +#include +#include + +#include "mp4_demuxer/box_reader.h" + +#include "mp4_demuxer/basictypes.h" +#include "mp4_demuxer/aac.h" +#include "mp4_demuxer/avc.h" +#include "mp4_demuxer/box_reader.h" +#include "mp4_demuxer/fourccs.h" + +namespace mp4_demuxer { + +enum TrackType { + kInvalid = 0, + kVideo, + kAudio, + kHint +}; + +#define DECLARE_BOX_METHODS(T) \ + T(); \ + virtual ~T(); \ + virtual bool Parse(BoxReader* reader) OVERRIDE; \ + virtual FourCC BoxType() const OVERRIDE; \ + +struct FileType : Box { + DECLARE_BOX_METHODS(FileType); + + FourCC major_brand; + uint32_t minor_version; +}; + +struct ProtectionSystemSpecificHeader : Box { + DECLARE_BOX_METHODS(ProtectionSystemSpecificHeader); + + std::vector system_id; + std::vector raw_box; +}; + +struct SampleAuxiliaryInformationOffset : Box { + DECLARE_BOX_METHODS(SampleAuxiliaryInformationOffset); + + std::vector offsets; +}; + +struct SampleAuxiliaryInformationSize : Box { + DECLARE_BOX_METHODS(SampleAuxiliaryInformationSize); + + uint8_t default_sample_info_size; + uint32_t sample_count; + std::vector sample_info_sizes; +}; + +struct OriginalFormat : Box { + DECLARE_BOX_METHODS(OriginalFormat); + + FourCC format; +}; + +struct SchemeType : Box { + DECLARE_BOX_METHODS(SchemeType); + + FourCC type; + uint32_t version; +}; + +struct TrackEncryption : Box { + DECLARE_BOX_METHODS(TrackEncryption); + + // Note: this definition is specific to the CENC protection type. + bool is_encrypted; + uint8_t default_iv_size; + std::vector default_kid; +}; + +struct SchemeInfo : Box { + DECLARE_BOX_METHODS(SchemeInfo); + + TrackEncryption track_encryption; +}; + +struct ProtectionSchemeInfo : Box { + DECLARE_BOX_METHODS(ProtectionSchemeInfo); + + OriginalFormat format; + SchemeType type; + SchemeInfo info; +}; + +struct MovieHeader : Box { + DECLARE_BOX_METHODS(MovieHeader); + + uint64_t creation_time; + uint64_t modification_time; + uint32_t timescale; + uint64_t duration; + int32_t rate; + int16_t volume; + uint32_t next_track_id; +}; + +struct TrackHeader : Box { + DECLARE_BOX_METHODS(TrackHeader); + + uint64_t creation_time; + uint64_t modification_time; + uint32_t track_id; + uint64_t duration; + int16_t layer; + int16_t alternate_group; + int16_t volume; + uint32_t width; + uint32_t height; +}; + +struct EditListEntry { + uint64_t segment_duration; + int64_t media_time; + int16_t media_rate_integer; + int16_t media_rate_fraction; +}; + +struct EditList : Box { + DECLARE_BOX_METHODS(EditList); + + std::vector edits; +}; + +struct Edit : Box { + DECLARE_BOX_METHODS(Edit); + + EditList list; +}; + +struct HandlerReference : Box { + DECLARE_BOX_METHODS(HandlerReference); + + TrackType type; +}; + +struct AVCDecoderConfigurationRecord : Box { + DECLARE_BOX_METHODS(AVCDecoderConfigurationRecord); + + uint8_t version; + uint8_t profile_indication; + uint8_t profile_compatibility; + uint8_t avc_level; + uint8_t length_size; + + typedef std::vector SPS; + typedef std::vector PPS; + + std::vector sps_list; + std::vector pps_list; +}; + +struct PixelAspectRatioBox : Box { + DECLARE_BOX_METHODS(PixelAspectRatioBox); + + uint32_t h_spacing; + uint32_t v_spacing; +}; + +struct VideoSampleEntry : Box { + DECLARE_BOX_METHODS(VideoSampleEntry); + + FourCC format; + uint16_t data_reference_index; + uint16_t width; + uint16_t height; + + PixelAspectRatioBox pixel_aspect; + ProtectionSchemeInfo sinf; + + // Currently expected to be present regardless of format. + AVCDecoderConfigurationRecord avcc; +}; + +struct ElementaryStreamDescriptor : Box { + DECLARE_BOX_METHODS(ElementaryStreamDescriptor); + + uint8_t object_type; + AAC aac; +}; + +struct AudioSampleEntry : Box { + DECLARE_BOX_METHODS(AudioSampleEntry); + + FourCC format; + uint16_t data_reference_index; + uint16_t channelcount; + uint16_t samplesize; + uint32_t samplerate; + + ProtectionSchemeInfo sinf; + ElementaryStreamDescriptor esds; +}; + +struct SampleDescription : Box { + DECLARE_BOX_METHODS(SampleDescription); + + TrackType type; + std::vector video_entries; + std::vector audio_entries; +}; + +struct SampleTable : Box { + DECLARE_BOX_METHODS(SampleTable); + + // Media Source specific: we ignore many of the sub-boxes in this box, + // including some that are required to be present in the BMFF spec. This + // includes the 'stts', 'stsc', and 'stco' boxes, which must contain no + // samples in order to be compliant files. + SampleDescription description; +}; + +struct MediaHeader : Box { + DECLARE_BOX_METHODS(MediaHeader); + + uint64_t creation_time; + uint64_t modification_time; + uint32_t timescale; + uint64_t duration; +}; + +struct MediaInformation : Box { + DECLARE_BOX_METHODS(MediaInformation); + + SampleTable sample_table; +}; + +struct Media : Box { + DECLARE_BOX_METHODS(Media); + + MediaHeader header; + HandlerReference handler; + MediaInformation information; +}; + +struct Track : Box { + DECLARE_BOX_METHODS(Track); + + TrackHeader header; + Media media; + Edit edit; +}; + +struct MovieExtendsHeader : Box { + DECLARE_BOX_METHODS(MovieExtendsHeader); + + uint64_t fragment_duration; +}; + +struct TrackExtends : Box { + DECLARE_BOX_METHODS(TrackExtends); + + uint32_t track_id; + uint32_t default_sample_description_index; + uint32_t default_sample_duration; + uint32_t default_sample_size; + uint32_t default_sample_flags; +}; + +struct MovieExtends : Box { + DECLARE_BOX_METHODS(MovieExtends); + + MovieExtendsHeader header; + std::vector tracks; +}; + +struct Movie : Box { + DECLARE_BOX_METHODS(Movie); + + bool fragmented; + MovieHeader header; + MovieExtends extends; + std::vector tracks; + std::vector pssh; +}; + +struct TrackFragmentDecodeTime : Box { + DECLARE_BOX_METHODS(TrackFragmentDecodeTime); + + uint64_t decode_time; +}; + +struct MovieFragmentHeader : Box { + DECLARE_BOX_METHODS(MovieFragmentHeader); + + uint32_t sequence_number; +}; + +struct TrackFragmentHeader : Box { + DECLARE_BOX_METHODS(TrackFragmentHeader); + + uint32_t track_id; + + uint32_t sample_description_index; + uint32_t default_sample_duration; + uint32_t default_sample_size; + uint32_t default_sample_flags; + + // As 'flags' might be all zero, we cannot use zeroness alone to identify + // when default_sample_flags wasn't specified, unlike the other values. + bool has_default_sample_flags; +}; + +struct TrackFragmentRun : Box { + DECLARE_BOX_METHODS(TrackFragmentRun); + + uint32_t sample_count; + uint32_t data_offset; + std::vector sample_flags; + std::vector sample_sizes; + std::vector sample_durations; + std::vector sample_composition_time_offsets; +}; + +struct TrackFragment : Box { + DECLARE_BOX_METHODS(TrackFragment); + + TrackFragmentHeader header; + std::vector runs; + TrackFragmentDecodeTime decode_time; + SampleAuxiliaryInformationOffset auxiliary_offset; + SampleAuxiliaryInformationSize auxiliary_size; +}; + +struct MovieFragment : Box { + DECLARE_BOX_METHODS(MovieFragment); + + MovieFragmentHeader header; + std::vector tracks; + std::vector pssh; +}; + +#undef DECLARE_BOX + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_BOX_DEFINITIONS_H_ diff --git a/content/media/fmp4/demuxer/box_reader.cc b/content/media/fmp4/demuxer/box_reader.cc new file mode 100644 index 000000000000..8b72e01e0eb9 --- /dev/null +++ b/content/media/fmp4/demuxer/box_reader.cc @@ -0,0 +1,263 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/box_reader.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "mp4_demuxer/box_definitions.h" + +#include "mp4_demuxer/Streams.h" + +using namespace std; + +namespace mp4_demuxer { + +Box::~Box() {} + +bool StreamReader::Read1(uint8_t* v) { + RCHECK(HasBytes(1)); + assert(start_ + pos_ <= stream_->Length()); + uint32_t bytesRead = 0; + if (!stream_->ReadAt(start_ + pos_, v, 1, &bytesRead) || bytesRead != 1) { + return false; + } + pos_ += bytesRead; + return true; +} + +// Internal implementation of multi-byte reads +template bool StreamReader::Read(T* v) { + RCHECK(HasBytes(sizeof(T))); + + T tmp = 0; + for (size_t i = 0; i < sizeof(T); i++) { + tmp <<= 8; + uint8_t byte; + Read1(&byte); + tmp += byte; + } + *v = tmp; + return true; +} + +bool StreamReader::Read2(uint16_t* v) { return Read(v); } +bool StreamReader::Read2s(int16_t* v) { return Read(v); } +bool StreamReader::Read4(uint32_t* v) { return Read(v); } +bool StreamReader::Read4s(int32_t* v) { return Read(v); } +bool StreamReader::Read8(uint64_t* v) { return Read(v); } +bool StreamReader::Read8s(int64_t* v) { return Read(v); } + +bool StreamReader::ReadFourCC(FourCC* v) { + return Read4(reinterpret_cast(v)); +} + +bool StreamReader::ReadVec(std::vector* vec, int count) { + RCHECK(HasBytes(count)); + vec->resize(count); + assert(start_ + pos_ <= stream_->Length()); + uint32_t bytesRead = 0; + if (!stream_->ReadAt(start_ + pos_, vec->data(), count, &bytesRead)) { + return false; + } + pos_ += bytesRead; + return true; +} + +bool StreamReader::SkipBytes(int bytes) { + RCHECK(HasBytes(bytes)); + pos_ += bytes; + return true; +} + +bool StreamReader::Read4Into8(uint64_t* v) { + uint32_t tmp; + RCHECK(Read4(&tmp)); + *v = tmp; + return true; +} + +bool StreamReader::Read4sInto8s(int64_t* v) { + // Beware of the need for sign extension. + int32_t tmp; + RCHECK(Read4s(&tmp)); + *v = tmp; + return true; +} + +int64_t StreamReader::size() const { + return size_; +} + +int64_t StreamReader::pos() const { + return pos_; +} + +BoxReader::BoxReader(Stream* stream, int64_t offset, int64_t size) + : StreamReader(stream, offset, size), + type_(FOURCC_NULL), + version_(0), + flags_(0), + scanned_(false) { +} + +BoxReader::~BoxReader() { + if (scanned_ && !children_.empty()) { + for (ChildMap::iterator itr = children_.begin(); + itr != children_.end(); ++itr) { + auto reader = itr->second; + DMX_LOG("Skipping unknown box: '%s' reader type'%s'\n", + FourCCToString(itr->first).c_str(), + FourCCToString(reader.type()).c_str()); + } + } +} + +// static +BoxReader* BoxReader::ReadTopLevelBox(Stream* stream, + int64_t offset, + bool* err) { + nsAutoPtr reader(new BoxReader(stream, offset, stream->Length())); + if (!reader->ReadHeader(err)) + return NULL; + + if (!IsValidTopLevelBox(reader->type())) { + *err = true; + return NULL; + } + + if (reader->size() <= stream->Length()) + return reader.forget(); + + return NULL; +} + +// static +bool BoxReader::StartTopLevelBox(Stream* stream, + int64_t offset, + FourCC* type, + int* box_size) { + assert(stream->Length() > offset); + BoxReader reader(stream, offset, stream->Length() - offset); + bool err = false; + if (!reader.ReadHeader(&err)) return false; + if (!IsValidTopLevelBox(reader.type()) || err) { + return false; + } + *type = reader.type(); + *box_size = reader.size(); + return true; +} + +// static +bool BoxReader::IsValidTopLevelBox(const FourCC& type) { + switch (type) { + case FOURCC_FTYP: + case FOURCC_PDIN: + case FOURCC_BLOC: + case FOURCC_MOOV: + case FOURCC_MOOF: + case FOURCC_MFRA: + case FOURCC_MDAT: + case FOURCC_FREE: + case FOURCC_SKIP: + case FOURCC_META: + case FOURCC_MECO: + case FOURCC_STYP: + case FOURCC_SIDX: + case FOURCC_SSIX: + case FOURCC_PRFT: + return true; + default: + // Hex is used to show nonprintable characters and aid in debugging + DMX_LOG("Unrecognized top-level box type 0x%x\n", type); + return false; + } +} + +bool BoxReader::ScanChildren() { + DCHECK(!scanned_); + scanned_ = true; + + bool err = false; + while (pos() < size()) { + BoxReader child(stream_, start_ + pos_, size_ - pos_); + if (!child.ReadHeader(&err)) break; + assert(child.size() < size()); + children_.insert(std::pair(child.type(), child)); + pos_ += child.size(); + } + + DCHECK(!err); + return !err && pos() == size(); +} + +bool BoxReader::ReadChild(Box* child) { + DCHECK(scanned_); + FourCC child_type = child->BoxType(); + + ChildMap::iterator itr = children_.find(child_type); + if (itr == children_.end()) { + DMX_LOG("No child of type %s\n", FourCCToString(child_type).c_str()); + } + RCHECK(itr != children_.end()); + DMX_LOG("Found a %s box\n", FourCCToString(child_type).c_str()); + RCHECK(child->Parse(&itr->second)); + children_.erase(itr); + return true; +} + +bool BoxReader::MaybeReadChild(Box* child) { + if (!children_.count(child->BoxType())) return true; + return ReadChild(child); +} + +bool BoxReader::ReadFullBoxHeader() { + uint32_t vflags; + RCHECK(Read4(&vflags)); + version_ = vflags >> 24; + flags_ = vflags & 0xffffff; + return true; +} + +bool BoxReader::ReadHeader(bool* err) { + uint64_t size = 0; + *err = false; + + if (!HasBytes(8)) return false; + CHECK(Read4Into8(&size) && ReadFourCC(&type_)); + + DMX_LOG("BoxReader::ReadHeader() read %s size=%d\n", FourCCToString(type_).c_str(), size); + + if (size == 0) { + // Media Source specific: we do not support boxes that run to EOS. + *err = true; + return false; + } else if (size == 1) { + if (!HasBytes(8)) return false; + CHECK(Read8(&size)); + } + + // Implementation-specific: support for boxes larger than 2^31 has been + // removed. + if (size < static_cast(pos_) || + size > static_cast(kint32max)) { + *err = true; + return false; + } + + // Note that the pos_ head has advanced to the byte immediately after the + // header, which is where we want it. + size_ = size; + + return true; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/box_reader.h b/content/media/fmp4/demuxer/box_reader.h new file mode 100644 index 000000000000..9c891328092d --- /dev/null +++ b/content/media/fmp4/demuxer/box_reader.h @@ -0,0 +1,216 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_BOX_READER_H_ +#define MEDIA_MP4_BOX_READER_H_ + +#include +#include + +#include "mp4_demuxer/basictypes.h" +#include "mp4_demuxer/fourccs.h" + +#include "nsAutoPtr.h" + +namespace mp4_demuxer { + +class BoxReader; +class Stream; + +struct Box { + virtual ~Box(); + virtual bool Parse(BoxReader* reader) = 0; + virtual FourCC BoxType() const = 0; +}; + +class StreamReader { + public: + StreamReader(Stream* stream, int64_t offset, int64_t size) + : stream_(stream), start_(offset), pos_(0), size_(size) {} + + bool HasBytes(int count) { return (pos() + count <= size()); } + + // Read a value from the stream, perfoming endian correction, and advance the + // stream pointer. + bool Read1(uint8_t* v) WARN_UNUSED_RESULT; + bool Read2(uint16_t* v) WARN_UNUSED_RESULT; + bool Read2s(int16_t* v) WARN_UNUSED_RESULT; + bool Read4(uint32_t* v) WARN_UNUSED_RESULT; + bool Read4s(int32_t* v) WARN_UNUSED_RESULT; + bool Read8(uint64_t* v) WARN_UNUSED_RESULT; + bool Read8s(int64_t* v) WARN_UNUSED_RESULT; + + bool ReadFourCC(FourCC* v) WARN_UNUSED_RESULT; + + bool ReadVec(std::vector* t, int count) WARN_UNUSED_RESULT; + + // These variants read a 4-byte integer of the corresponding signedness and + // store it in the 8-byte return type. + bool Read4Into8(uint64_t* v) WARN_UNUSED_RESULT; + bool Read4sInto8s(int64_t* v) WARN_UNUSED_RESULT; + + // Advance the stream by this many bytes. + bool SkipBytes(int nbytes) WARN_UNUSED_RESULT; + + //const uint8_t* data() const { return buf_; } + int64_t size() const; + int64_t pos() const; + +protected: + + // The start offset of the box in the stream. + const int64_t start_; + + // The size of the box in the stream. + int64_t size_; + + // The offset from start_ at which the read cursor is. + // 0 initially. + int64_t pos_; + + // The stream that we read from. + Stream* stream_; + + template bool Read(T* t) WARN_UNUSED_RESULT; +}; + +class BoxReader : public StreamReader { + public: + ~BoxReader(); + + // Create a BoxReader from a buffer. Note that this function may return NULL + // if an intact, complete box was not available in the buffer. If |*err| is + // set, there was a stream-level error when creating the box; otherwise, NULL + // values are only expected when insufficient data is available. + // + // |buf| is retained but not owned, and must outlive the BoxReader instance. + static BoxReader* ReadTopLevelBox(Stream* stream, + int64_t offset, + bool* err); + + // Read the box header from the current buffer. This function returns true if + // the header is sane; that is, it does not check to ensure the entire box is + // in the buffer before returning true. + static bool StartTopLevelBox(Stream* stream, + int64_t offset, + FourCC* type, + int* box_size); + + // Returns true if |type| is recognized to be a top-level box, false + // otherwise. This returns true for some boxes which we do not parse. + // Helpful in debugging misaligned appends. + static bool IsValidTopLevelBox(const FourCC& type); + + // Scan through all boxes within the current box, starting at the current + // buffer position. Must be called before any of the *Child functions work. + bool ScanChildren() WARN_UNUSED_RESULT; + + // Read exactly one child box from the set of children. The type of the child + // will be determined by the BoxType() method of |child|. + bool ReadChild(Box* child) WARN_UNUSED_RESULT; + + // Read one child if available. Returns false on error, true on successful + // read or on child absent. + bool MaybeReadChild(Box* child) WARN_UNUSED_RESULT; + + // Read at least one child. False means error or no such child present. + template bool ReadChildren( + std::vector* children) WARN_UNUSED_RESULT; + + // Read any number of children. False means error. + template bool MaybeReadChildren( + std::vector* children) WARN_UNUSED_RESULT; + + // Read all children, regardless of FourCC. This is used from exactly one box, + // corresponding to a rather significant inconsistency in the BMFF spec. + // Note that this method is mutually exclusive with ScanChildren(). + template bool ReadAllChildren( + std::vector* children) WARN_UNUSED_RESULT; + + // Populate the values of 'version()' and 'flags()' from a full box header. + // Many boxes, but not all, use these values. This call should happen after + // the box has been initialized, and does not re-read the main box header. + bool ReadFullBoxHeader() WARN_UNUSED_RESULT; + + FourCC type() const { return type_; } + uint8_t version() const { return version_; } + uint32_t flags() const { return flags_; } + +private: + + BoxReader(Stream* stream, int64_t offset, int64_t size); + + // Must be called immediately after init. If the return is false, this + // indicates that the box header and its contents were not available in the + // stream or were nonsensical, and that the box must not be used further. In + // this case, if |*err| is false, the problem was simply a lack of data, and + // should only be an error condition if some higher-level component knows that + // no more data is coming (i.e. EOS or end of containing box). If |*err| is + // true, the error is unrecoverable and the stream should be aborted. + bool ReadHeader(bool* err); + + FourCC type_; + uint8_t version_; + uint32_t flags_; + + typedef std::multimap ChildMap; + + // The set of child box FourCCs and their corresponding buffer readers. Only + // valid if scanned_ is true. + ChildMap children_; + bool scanned_; +}; + +// Template definitions +template bool BoxReader::ReadChildren(std::vector* children) { + RCHECK(MaybeReadChildren(children) && !children->empty()); + return true; +} + +template +bool BoxReader::MaybeReadChildren(std::vector* children) { + DCHECK(scanned_); + DCHECK(children->empty()); + + children->resize(1); + FourCC child_type = (*children)[0].BoxType(); + + ChildMap::iterator start_itr = children_.lower_bound(child_type); + ChildMap::iterator end_itr = children_.upper_bound(child_type); + children->resize(std::distance(start_itr, end_itr)); + typename std::vector::iterator child_itr = children->begin(); + for (ChildMap::iterator itr = start_itr; itr != end_itr; ++itr) { + RCHECK(child_itr->Parse(&itr->second)); + ++child_itr; + } + children_.erase(start_itr, end_itr); + + DMX_LOG("Found %d %s boxes\n", + children->size(), + FourCCToString(child_type).c_str()); + + return true; +} + +template +bool BoxReader::ReadAllChildren(std::vector* children) { + DCHECK(!scanned_); + scanned_ = true; + + bool err = false; + while (pos() < size()) { + BoxReader child_reader(stream_, start_ + pos_, size_ - pos_); + if (!child_reader.ReadHeader(&err)) break; + T child; + RCHECK(child.Parse(&child_reader)); + children->push_back(child); + pos_ += child_reader.size(); + } + + return !err; +} + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_BOX_READER_H_ diff --git a/content/media/fmp4/demuxer/cenc.cc b/content/media/fmp4/demuxer/cenc.cc new file mode 100644 index 000000000000..533cbe1f8333 --- /dev/null +++ b/content/media/fmp4/demuxer/cenc.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/cenc.h" + +#include + +#include "mp4_demuxer/box_reader.h" + +namespace mp4_demuxer { + +FrameCENCInfo::FrameCENCInfo() {} +FrameCENCInfo::~FrameCENCInfo() {} + +bool FrameCENCInfo::Parse(int iv_size, StreamReader* reader) { + const int kEntrySize = 6; + // Mandated by CENC spec + RCHECK(iv_size == 8 || iv_size == 16); + + memset(iv, 0, sizeof(iv)); + for (int i = 0; i < iv_size; i++) + RCHECK(reader->Read1(&iv[i])); + + if (!reader->HasBytes(1)) return true; + + uint16_t subsample_count; + RCHECK(reader->Read2(&subsample_count) && + reader->HasBytes(subsample_count * kEntrySize)); + + subsamples.resize(subsample_count); + for (int i = 0; i < subsample_count; i++) { + uint16_t clear_bytes; + uint32_t cypher_bytes; + RCHECK(reader->Read2(&clear_bytes) && + reader->Read4(&cypher_bytes)); + subsamples[i].clear_bytes = clear_bytes; + subsamples[i].cypher_bytes = cypher_bytes; + } + return true; +} + +size_t FrameCENCInfo::GetTotalSizeOfSubsamples() const { + size_t size = 0; + for (size_t i = 0; i < subsamples.size(); i++) { + size += subsamples[i].clear_bytes + subsamples[i].cypher_bytes; + } + return size; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/cenc.h b/content/media/fmp4/demuxer/cenc.h new file mode 100644 index 000000000000..6a3d62ff5151 --- /dev/null +++ b/content/media/fmp4/demuxer/cenc.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_CENC_H_ +#define MEDIA_MP4_CENC_H_ + +#include + +#include "mp4_demuxer/basictypes.h" +#include "mp4_demuxer/decrypt_config.h" + +namespace mp4_demuxer { + +class StreamReader; + +struct FrameCENCInfo { + uint8_t iv[16]; + std::vector subsamples; + + FrameCENCInfo(); + ~FrameCENCInfo(); + bool Parse(int iv_size, StreamReader* r); + size_t GetTotalSizeOfSubsamples() const; +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_CENC_H_ diff --git a/content/media/fmp4/demuxer/channel_layout.cc b/content/media/fmp4/demuxer/channel_layout.cc new file mode 100644 index 000000000000..ba7d275d346c --- /dev/null +++ b/content/media/fmp4/demuxer/channel_layout.cc @@ -0,0 +1,186 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/channel_layout.h" + +#include "mp4_demuxer/basictypes.h" + +namespace mp4_demuxer { + +static const int kLayoutToChannels[] = { + 0, // CHANNEL_LAYOUT_NONE + 0, // CHANNEL_LAYOUT_UNSUPPORTED + 1, // CHANNEL_LAYOUT_MONO + 2, // CHANNEL_LAYOUT_STEREO + 3, // CHANNEL_LAYOUT_2_1 + 3, // CHANNEL_LAYOUT_SURROUND + 4, // CHANNEL_LAYOUT_4_0 + 4, // CHANNEL_LAYOUT_2_2 + 4, // CHANNEL_LAYOUT_QUAD + 5, // CHANNEL_LAYOUT_5_0 + 6, // CHANNEL_LAYOUT_5_1 + 5, // CHANNEL_LAYOUT_5_0_BACK + 6, // CHANNEL_LAYOUT_5_1_BACK + 7, // CHANNEL_LAYOUT_7_0 + 8, // CHANNEL_LAYOUT_7_1 + 8, // CHANNEL_LAYOUT_7_1_WIDE + 2, // CHANNEL_LAYOUT_STEREO_DOWNMIX + 3, // CHANNEL_LAYOUT_2POINT1 + 4, // CHANNEL_LAYOUT_3_1 + 5, // CHANNEL_LAYOUT_4_1 + 6, // CHANNEL_LAYOUT_6_0 + 6, // CHANNEL_LAYOUT_6_0_FRONT + 6, // CHANNEL_LAYOUT_HEXAGONAL + 7, // CHANNEL_LAYOUT_6_1 + 7, // CHANNEL_LAYOUT_6_1_BACK + 7, // CHANNEL_LAYOUT_6_1_FRONT + 7, // CHANNEL_LAYOUT_7_0_FRONT + 8, // CHANNEL_LAYOUT_7_1_WIDE_BACK + 8, // CHANNEL_LAYOUT_OCTAGONAL + 0, // CHANNEL_LAYOUT_DISCRETE +}; + +// The channel orderings for each layout as specified by FFmpeg. Each value +// represents the index of each channel in each layout. Values of -1 mean the +// channel at that index is not used for that layout.For example, the left side +// surround sound channel in FFmpeg's 5.1 layout is in the 5th position (because +// the order is L, R, C, LFE, LS, RS), so +// kChannelOrderings[CHANNEL_LAYOUT_5POINT1][SIDE_LEFT] = 4; +static const int kChannelOrderings[CHANNEL_LAYOUT_MAX][CHANNELS_MAX] = { + // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR + + // CHANNEL_LAYOUT_NONE + { -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_UNSUPPORTED + { -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_MONO + { -1 , -1 , 0 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_STEREO + { 0 , 1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_2_1 + { 0 , 1 , -1 , -1 , -1 , -1 , -1 , -1 , 2 , -1 , -1 }, + + // CHANNEL_LAYOUT_SURROUND + { 0 , 1 , 2 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_4_0 + { 0 , 1 , 2 , -1 , -1 , -1 , -1 , -1 , 3 , -1 , -1 }, + + // CHANNEL_LAYOUT_2_2 + { 0 , 1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , 2 , 3 }, + + // CHANNEL_LAYOUT_QUAD + { 0 , 1 , -1 , -1 , 2 , 3 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_5_0 + { 0 , 1 , 2 , -1 , -1 , -1 , -1 , -1 , -1 , 3 , 4 }, + + // CHANNEL_LAYOUT_5_1 + { 0 , 1 , 2 , 3 , -1 , -1 , -1 , -1 , -1 , 4 , 5 }, + + // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR + + // CHANNEL_LAYOUT_5_0_BACK + { 0 , 1 , 2 , -1 , 3 , 4 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_5_1_BACK + { 0 , 1 , 2 , 3 , 4 , 5 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_7_0 + { 0 , 1 , 2 , -1 , 5 , 6 , -1 , -1 , -1 , 3 , 4 }, + + // CHANNEL_LAYOUT_7_1 + { 0 , 1 , 2 , 3 , 6 , 7 , -1 , -1 , -1 , 4 , 5 }, + + // CHANNEL_LAYOUT_7_1_WIDE + { 0 , 1 , 2 , 3 , -1 , -1 , 6 , 7 , -1 , 4 , 5 }, + + // CHANNEL_LAYOUT_STEREO_DOWNMIX + { 0 , 1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_2POINT1 + { 0 , 1 , -1 , 2 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_3_1 + { 0 , 1 , 2 , 3 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_4_1 + { 0 , 1 , 2 , 4 , -1 , -1 , -1 , -1 , 3 , -1 , -1 }, + + // CHANNEL_LAYOUT_6_0 + { 0 , 1 , 2 , -1 , -1 , -1 , -1 , -1 , 5 , 3 , 4 }, + + // CHANNEL_LAYOUT_6_0_FRONT + { 0 , 1 , -1 , -1 , -1 , -1 , 4 , 5 , -1 , 2 , 3 }, + + // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR + + // CHANNEL_LAYOUT_HEXAGONAL + { 0 , 1 , 2 , -1 , 3 , 4 , -1 , -1 , 5 , -1 , -1 }, + + // CHANNEL_LAYOUT_6_1 + { 0 , 1 , 2 , 3 , -1 , -1 , -1 , -1 , 6 , 4 , 5 }, + + // CHANNEL_LAYOUT_6_1_BACK + { 0 , 1 , 2 , 3 , 4 , 5 , -1 , -1 , 6 , -1 , -1 }, + + // CHANNEL_LAYOUT_6_1_FRONT + { 0 , 1 , -1 , 6 , -1 , -1 , 4 , 5 , -1 , 2 , 3 }, + + // CHANNEL_LAYOUT_7_0_FRONT + { 0 , 1 , 2 , -1 , -1 , -1 , 5 , 6 , -1 , 3 , 4 }, + + // CHANNEL_LAYOUT_7_1_WIDE_BACK + { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , -1 , -1 , -1 }, + + // CHANNEL_LAYOUT_OCTAGONAL + { 0 , 1 , 2 , -1 , 5 , 6 , -1 , -1 , 7 , 3 , 4 }, + + // CHANNEL_LAYOUT_DISCRETE + { -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 }, + + // FL | FR | FC | LFE | BL | BR | FLofC | FRofC | BC | SL | SR +}; + +int ChannelLayoutToChannelCount(ChannelLayout layout) { + DCHECK_LT(static_cast(layout), arraysize(kLayoutToChannels)); + return kLayoutToChannels[layout]; +} + +// Converts a channel count into a channel layout. +ChannelLayout GuessChannelLayout(int channels) { + switch (channels) { + case 1: + return CHANNEL_LAYOUT_MONO; + case 2: + return CHANNEL_LAYOUT_STEREO; + case 3: + return CHANNEL_LAYOUT_SURROUND; + case 4: + return CHANNEL_LAYOUT_QUAD; + case 5: + return CHANNEL_LAYOUT_5_0; + case 6: + return CHANNEL_LAYOUT_5_1; + case 7: + return CHANNEL_LAYOUT_6_1; + case 8: + return CHANNEL_LAYOUT_7_1; + default: + DMX_LOG("Unsupported channel count: %d\n", channels); + } + return CHANNEL_LAYOUT_UNSUPPORTED; +} + +int ChannelOrder(ChannelLayout layout, Channels channel) { + DCHECK_LT(static_cast(layout), arraysize(kChannelOrderings)); + DCHECK_LT(static_cast(channel), arraysize(kChannelOrderings[0])); + return kChannelOrderings[layout][channel]; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/channel_layout.h b/content/media/fmp4/demuxer/channel_layout.h new file mode 100644 index 000000000000..6377b28575d1 --- /dev/null +++ b/content/media/fmp4/demuxer/channel_layout.h @@ -0,0 +1,134 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_CHANNEL_LAYOUT_H_ +#define MEDIA_BASE_CHANNEL_LAYOUT_H_ + + +namespace mp4_demuxer { + +// Enumerates the various representations of the ordering of audio channels. +// Logged to UMA, so never reuse a value, always add new/greater ones! +enum ChannelLayout { + CHANNEL_LAYOUT_NONE = 0, + CHANNEL_LAYOUT_UNSUPPORTED = 1, + + // Front C + CHANNEL_LAYOUT_MONO = 2, + + // Front L, Front R + CHANNEL_LAYOUT_STEREO = 3, + + // Front L, Front R, Back C + CHANNEL_LAYOUT_2_1 = 4, + + // Front L, Front R, Front C + CHANNEL_LAYOUT_SURROUND = 5, + + // Front L, Front R, Front C, Back C + CHANNEL_LAYOUT_4_0 = 6, + + // Front L, Front R, Side L, Side R + CHANNEL_LAYOUT_2_2 = 7, + + // Front L, Front R, Back L, Back R + CHANNEL_LAYOUT_QUAD = 8, + + // Front L, Front R, Front C, Side L, Side R + CHANNEL_LAYOUT_5_0 = 9, + + // Front L, Front R, Front C, Side L, Side R, LFE + CHANNEL_LAYOUT_5_1 = 10, + + // Front L, Front R, Front C, Back L, Back R + CHANNEL_LAYOUT_5_0_BACK = 11, + + // Front L, Front R, Front C, Back L, Back R, LFE + CHANNEL_LAYOUT_5_1_BACK = 12, + + // Front L, Front R, Front C, Side L, Side R, Back L, Back R + CHANNEL_LAYOUT_7_0 = 13, + + // Front L, Front R, Front C, Side L, Side R, LFE, Back L, Back R + CHANNEL_LAYOUT_7_1 = 14, + + // Front L, Front R, Front C, Side L, Side R, LFE, Front LofC, Front RofC + CHANNEL_LAYOUT_7_1_WIDE = 15, + + // Stereo L, Stereo R + CHANNEL_LAYOUT_STEREO_DOWNMIX = 16, + + // Stereo L, Stereo R, LFE + CHANNEL_LAYOUT_2POINT1 = 17, + + // Stereo L, Stereo R, Front C, LFE + CHANNEL_LAYOUT_3_1 = 18, + + // Stereo L, Stereo R, Front C, Rear C, LFE + CHANNEL_LAYOUT_4_1 = 19, + + // Stereo L, Stereo R, Front C, Side L, Side R, Back C + CHANNEL_LAYOUT_6_0 = 20, + + // Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC + CHANNEL_LAYOUT_6_0_FRONT = 21, + + // Stereo L, Stereo R, Side L, Side R, Front C, Rear C. + CHANNEL_LAYOUT_HEXAGONAL = 22, + + // Stereo L, Stereo R, Side L, Side R, Front C, Rear Center, LFE + CHANNEL_LAYOUT_6_1 = 23, + + // Stereo L, Stereo R, Back L, Back R, Front C, Rear Center, LFE + CHANNEL_LAYOUT_6_1_BACK = 24, + + // Stereo L, Stereo R, Side L, Side R, Front LofC, Front RofC, LFE + CHANNEL_LAYOUT_6_1_FRONT = 25, + + // Front L, Front R, Front C, Side L, Side R, Front LofC, Front RofC + CHANNEL_LAYOUT_7_0_FRONT = 26, + + // Front L, Front R, Front C, Back L, Back R, LFE, Front LofC, Front RofC + CHANNEL_LAYOUT_7_1_WIDE_BACK = 27, + + // Front L, Front R, Front C, Side L, Side R, Rear C, Back L, Back R. + CHANNEL_LAYOUT_OCTAGONAL = 28, + + // Channels are not explicitly mapped to speakers. + CHANNEL_LAYOUT_DISCRETE = 29, + + // Total number of layouts. + CHANNEL_LAYOUT_MAX // Must always be last! +}; + +enum Channels { + LEFT = 0, + RIGHT, + CENTER, + LFE, + BACK_LEFT, + BACK_RIGHT, + LEFT_OF_CENTER, + RIGHT_OF_CENTER, + BACK_CENTER, + SIDE_LEFT, + SIDE_RIGHT, + CHANNELS_MAX +}; + +// Returns the expected channel position in an interleaved stream. Values of -1 +// mean the channel at that index is not used for that layout. Values range +// from 0 to CHANNELS_MAX - 1. +int ChannelOrder(ChannelLayout layout, Channels channel); + +// Returns the number of channels in a given ChannelLayout. +int ChannelLayoutToChannelCount(ChannelLayout layout); + +// Given the number of channels, return the best layout, +// or return CHANNEL_LAYOUT_UNSUPPORTED if there is no good match. +ChannelLayout GuessChannelLayout(int channels); + +} // namespace mp4_demuxer + +#endif // MEDIA_BASE_CHANNEL_LAYOUT_H_ diff --git a/content/media/fmp4/demuxer/decrypt_config.cc b/content/media/fmp4/demuxer/decrypt_config.cc new file mode 100644 index 000000000000..809725db1d58 --- /dev/null +++ b/content/media/fmp4/demuxer/decrypt_config.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/decrypt_config.h" + +namespace mp4_demuxer { + +DecryptConfig::DecryptConfig(const std::string& key_id, + const std::string& iv, + const int data_offset, + const std::vector& subsamples) + : key_id_(key_id), + iv_(iv), + data_offset_(data_offset), + subsamples_(subsamples) { + DCHECK_GT(key_id.size(), 0u); + DCHECK(iv.size() == static_cast(DecryptConfig::kDecryptionKeySize) || + iv.empty()); + DCHECK_GE(data_offset, 0); +} + +DecryptConfig::~DecryptConfig() {} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/decrypt_config.h b/content/media/fmp4/demuxer/decrypt_config.h new file mode 100644 index 000000000000..3c56eb1f4a0b --- /dev/null +++ b/content/media/fmp4/demuxer/decrypt_config.h @@ -0,0 +1,78 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_DECRYPT_CONFIG_H_ +#define MEDIA_BASE_DECRYPT_CONFIG_H_ + +#include +#include + +#include "mp4_demuxer/basictypes.h" + +namespace mp4_demuxer { + +// The Common Encryption spec provides for subsample encryption, where portions +// of a sample are set in cleartext. A SubsampleEntry specifies the number of +// clear and encrypted bytes in each subsample. For decryption, all of the +// encrypted bytes in a sample should be considered a single logical stream, +// regardless of how they are divided into subsamples, and the clear bytes +// should not be considered as part of decryption. This is logically equivalent +// to concatenating all 'cypher_bytes' portions of subsamples, decrypting that +// result, and then copying each byte from the decrypted block over the +// position of the corresponding encrypted byte. +struct SubsampleEntry { + uint32_t clear_bytes; + uint32_t cypher_bytes; +}; + +// Contains all information that a decryptor needs to decrypt a media sample. +class DecryptConfig { + public: + // Keys are always 128 bits. + static const int kDecryptionKeySize = 16; + + // |key_id| is the ID that references the decryption key for this sample. + // |iv| is the initialization vector defined by the encrypted format. + // Currently |iv| must be 16 bytes as defined by WebM and ISO. Or must be + // empty which signals an unencrypted frame. + // |data_offset| is the amount of data that should be discarded from the + // head of the sample buffer before applying subsample information. A + // decrypted buffer will be shorter than an encrypted buffer by this amount. + // |subsamples| defines the clear and encrypted portions of the sample as + // described above. A decrypted buffer will be equal in size to the sum + // of the subsample sizes. + // + // |data_offset| is applied before |subsamples|. + DecryptConfig(const std::string& key_id, + const std::string& iv, + const int data_offset, + const std::vector& subsamples); + ~DecryptConfig(); + + const std::string& key_id() const { return key_id_; } + const std::string& iv() const { return iv_; } + int data_offset() const { return data_offset_; } + const std::vector& subsamples() const { return subsamples_; } + + private: + const std::string key_id_; + + // Initialization vector. + const std::string iv_; + + // TODO(fgalligan): Remove |data_offset_| if there is no plan to use it in + // the future. + // Amount of data to be discarded before applying subsample information. + const int data_offset_; + + // Subsample information. May be empty for some formats, meaning entire frame + // (less data ignored by data_offset_) is encrypted. + const std::vector subsamples_; + + DISALLOW_COPY_AND_ASSIGN(DecryptConfig); +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_BASE_DECRYPT_CONFIG_H_ diff --git a/content/media/fmp4/demuxer/es_descriptor.cc b/content/media/fmp4/demuxer/es_descriptor.cc new file mode 100644 index 000000000000..fb7c5f20fc9f --- /dev/null +++ b/content/media/fmp4/demuxer/es_descriptor.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/es_descriptor.h" +#include "mp4_demuxer/bit_reader.h" + +namespace mp4_demuxer { + +// The elementary stream size is specific by up to 4 bytes. +// The MSB of a byte indicates if there are more bytes for the size. +static bool ReadESSize(BitReader* reader, uint32_t* size) { + uint8_t msb; + uint8_t byte; + + *size = 0; + + for (size_t i = 0; i < 4; ++i) { + RCHECK(reader->ReadBits(1, &msb)); + RCHECK(reader->ReadBits(7, &byte)); + *size = (*size << 7) + byte; + + if (msb == 0) + break; + } + + return true; +} + +ESDescriptor::ESDescriptor() + : object_type_(kForbidden) { +} + +ESDescriptor::~ESDescriptor() {} + +bool ESDescriptor::Parse(const std::vector& data) { + BitReader reader(&data[0], data.size()); + uint8_t tag; + uint32_t size; + uint8_t stream_dependency_flag; + uint8_t url_flag; + uint8_t ocr_stream_flag; + uint16_t dummy; + + RCHECK(reader.ReadBits(8, &tag)); + RCHECK(tag == kESDescrTag); + RCHECK(ReadESSize(&reader, &size)); + + RCHECK(reader.ReadBits(16, &dummy)); // ES_ID + RCHECK(reader.ReadBits(1, &stream_dependency_flag)); + RCHECK(reader.ReadBits(1, &url_flag)); + RCHECK(!url_flag); // We don't support url flag + RCHECK(reader.ReadBits(1, &ocr_stream_flag)); + RCHECK(reader.ReadBits(5, &dummy)); // streamPriority + + if (stream_dependency_flag) + RCHECK(reader.ReadBits(16, &dummy)); // dependsOn_ES_ID + if (ocr_stream_flag) + RCHECK(reader.ReadBits(16, &dummy)); // OCR_ES_Id + + RCHECK(ParseDecoderConfigDescriptor(&reader)); + + return true; +} + +uint8_t ESDescriptor::object_type() const { + return object_type_; +} + +const std::vector& ESDescriptor::decoder_specific_info() const { + return decoder_specific_info_; +} + +bool ESDescriptor::ParseDecoderConfigDescriptor(BitReader* reader) { + uint8_t tag; + uint32_t size; + uint64_t dummy; + + RCHECK(reader->ReadBits(8, &tag)); + RCHECK(tag == kDecoderConfigDescrTag); + RCHECK(ReadESSize(reader, &size)); + + RCHECK(reader->ReadBits(8, &object_type_)); + RCHECK(reader->ReadBits(64, &dummy)); + RCHECK(reader->ReadBits(32, &dummy)); + RCHECK(ParseDecoderSpecificInfo(reader)); + + return true; +} + +bool ESDescriptor::ParseDecoderSpecificInfo(BitReader* reader) { + uint8_t tag; + uint32_t size; + + RCHECK(reader->ReadBits(8, &tag)); + RCHECK(tag == kDecoderSpecificInfoTag); + RCHECK(ReadESSize(reader, &size)); + + decoder_specific_info_.resize(size); + for (uint32_t i = 0; i < size; ++i) + RCHECK(reader->ReadBits(8, &decoder_specific_info_[i])); + + return true; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/es_descriptor.h b/content/media/fmp4/demuxer/es_descriptor.h new file mode 100644 index 000000000000..b213eba274ec --- /dev/null +++ b/content/media/fmp4/demuxer/es_descriptor.h @@ -0,0 +1,53 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_ES_DESCRIPTOR_H_ +#define MEDIA_MP4_ES_DESCRIPTOR_H_ + +#include + +#include "mp4_demuxer/basictypes.h" + +namespace mp4_demuxer { + +class BitReader; + +// The following values are extracted from ISO 14496 Part 1 Table 5 - +// objectTypeIndication Values. Only values currently in use are included. +enum ObjectType { + kForbidden = 0, + kISO_14496_3 = 0x40, // MPEG4 AAC + kISO_13818_7_AAC_LC = 0x67 // MPEG2 AAC-LC +}; + +// This class parse object type and decoder specific information from an +// elementary stream descriptor, which is usually contained in an esds box. +// Please refer to ISO 14496 Part 1 7.2.6.5 for more details. +class ESDescriptor { + public: + ESDescriptor(); + ~ESDescriptor(); + + bool Parse(const std::vector& data); + + uint8_t object_type() const; + const std::vector& decoder_specific_info() const; + + private: + enum Tag { + kESDescrTag = 0x03, + kDecoderConfigDescrTag = 0x04, + kDecoderSpecificInfoTag = 0x05 + }; + + bool ParseDecoderConfigDescriptor(BitReader* reader); + bool ParseDecoderSpecificInfo(BitReader* reader); + + uint8_t object_type_; + std::vector decoder_specific_info_; +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_ES_DESCRIPTOR_H_ diff --git a/content/media/fmp4/demuxer/fourccs.h b/content/media/fmp4/demuxer/fourccs.h new file mode 100644 index 000000000000..3c584aa462d6 --- /dev/null +++ b/content/media/fmp4/demuxer/fourccs.h @@ -0,0 +1,97 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_FOURCCS_H_ +#define MEDIA_MP4_FOURCCS_H_ + +#include + +namespace mp4_demuxer { + +enum FourCC { + FOURCC_NULL = 0, + FOURCC_AVC1 = 0x61766331, + FOURCC_AVCC = 0x61766343, + FOURCC_BLOC = 0x626C6F63, + FOURCC_CENC = 0x63656e63, + FOURCC_CO64 = 0x636f3634, + FOURCC_CTTS = 0x63747473, + FOURCC_DINF = 0x64696e66, + FOURCC_EDTS = 0x65647473, + FOURCC_ELST = 0x656c7374, + FOURCC_ENCA = 0x656e6361, + FOURCC_ENCV = 0x656e6376, + FOURCC_ESDS = 0x65736473, + FOURCC_FREE = 0x66726565, + FOURCC_FRMA = 0x66726d61, + FOURCC_FTYP = 0x66747970, + FOURCC_HDLR = 0x68646c72, + FOURCC_HINT = 0x68696e74, + FOURCC_IODS = 0x696f6473, + FOURCC_MDAT = 0x6d646174, + FOURCC_MDHD = 0x6d646864, + FOURCC_MDIA = 0x6d646961, + FOURCC_MECO = 0x6d65636f, + FOURCC_MEHD = 0x6d656864, + FOURCC_META = 0x6d657461, + FOURCC_MFHD = 0x6d666864, + FOURCC_MFRA = 0x6d667261, + FOURCC_MINF = 0x6d696e66, + FOURCC_MOOF = 0x6d6f6f66, + FOURCC_MOOV = 0x6d6f6f76, + FOURCC_MP4A = 0x6d703461, + FOURCC_MP4V = 0x6d703476, + FOURCC_MVEX = 0x6d766578, + FOURCC_MVHD = 0x6d766864, + FOURCC_PASP = 0x70617370, + FOURCC_PDIN = 0x7064696e, + FOURCC_PRFT = 0x70726674, + FOURCC_PSSH = 0x70737368, + FOURCC_SAIO = 0x7361696f, + FOURCC_SAIZ = 0x7361697a, + FOURCC_SCHI = 0x73636869, + FOURCC_SCHM = 0x7363686d, + FOURCC_SDTP = 0x73647470, + FOURCC_SIDX = 0x73696478, + FOURCC_SINF = 0x73696e66, + FOURCC_SKIP = 0x736b6970, + FOURCC_SMHD = 0x736d6864, + FOURCC_SOUN = 0x736f756e, + FOURCC_SSIX = 0x73736978, + FOURCC_STBL = 0x7374626c, + FOURCC_STCO = 0x7374636f, + FOURCC_STSC = 0x73747363, + FOURCC_STSD = 0x73747364, + FOURCC_STSS = 0x73747373, + FOURCC_STSZ = 0x7374737a, + FOURCC_STTS = 0x73747473, + FOURCC_STYP = 0x73747970, + FOURCC_TENC = 0x74656e63, + FOURCC_TFDT = 0x74666474, + FOURCC_TFHD = 0x74666864, + FOURCC_TKHD = 0x746b6864, + FOURCC_TRAF = 0x74726166, + FOURCC_TRAK = 0x7472616b, + FOURCC_TREX = 0x74726578, + FOURCC_TRUN = 0x7472756e, + FOURCC_UDTA = 0x75647461, + FOURCC_UUID = 0x75756964, + FOURCC_VIDE = 0x76696465, + FOURCC_VMHD = 0x766d6864, + FOURCC_WIDE = 0x77696465, +}; + +const inline std::string FourCCToString(FourCC fourcc) { + char buf[5]; + buf[0] = (fourcc >> 24) & 0xff; + buf[1] = (fourcc >> 16) & 0xff; + buf[2] = (fourcc >> 8) & 0xff; + buf[3] = (fourcc) & 0xff; + buf[4] = 0; + return std::string(buf); +} + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_FOURCCS_H_ diff --git a/content/media/fmp4/demuxer/mp4_demuxer.cc b/content/media/fmp4/demuxer/mp4_demuxer.cc new file mode 100644 index 000000000000..b1994644b077 --- /dev/null +++ b/content/media/fmp4/demuxer/mp4_demuxer.cc @@ -0,0 +1,535 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +#include "mp4_demuxer/mp4_demuxer.h" + +#include "mp4_demuxer/Streams.h" +#include "mp4_demuxer/box_reader.h" +#include "mp4_demuxer/box_definitions.h" +#include "mp4_demuxer/basictypes.h" +#include "mp4_demuxer/es_descriptor.h" +#include "mp4_demuxer/video_util.h" +#include "mp4_demuxer/track_run_iterator.h" +#include "mp4_demuxer/audio_decoder_config.h" +#include "mp4_demuxer/video_decoder_config.h" + +#include + +using namespace std; + +namespace mp4_demuxer { + + +MP4Sample::MP4Sample(Microseconds _decode_timestamp, + Microseconds _composition_timestamp, + Microseconds _duration, + int64_t _byte_offset, + std::vector* _data, + TrackType _type, + DecryptConfig* _decrypt_config, + bool _is_sync_point) + : decode_timestamp(_decode_timestamp), + composition_timestamp(_composition_timestamp), + duration(_duration), + byte_offset(_byte_offset), + data(_data), + type(_type), + decrypt_config(_decrypt_config), + is_sync_point(_is_sync_point) +{ +} + +MP4Sample::~MP4Sample() +{ +} + +bool MP4Sample::is_encrypted() const { + return decrypt_config != nullptr; +}; + + + + +MP4Demuxer::MP4Demuxer(Stream* stream) + : state_(kWaitingForInit), + stream_(stream), + stream_offset_(0), + duration_(InfiniteMicroseconds), + moof_head_(0), + mdat_tail_(0), + audio_track_id_(0), + video_track_id_(0), + audio_frameno(0), + video_frameno(0), + has_audio_(false), + has_sbr_(false), + is_audio_track_encrypted_(false), + has_video_(false), + is_video_track_encrypted_(false), + can_seek_(false) +{ +} + +MP4Demuxer::~MP4Demuxer() +{ +} + +bool MP4Demuxer::Init() +{ + ChangeState(kParsingBoxes); + + // Read from the stream until the moov box is read. This will have the + // header data that we need to initialize the decoders. + bool ok = true; + const int64_t length = stream_->Length(); + while (ok && + stream_offset_ < length && + !moov_ && + state_ == kParsingBoxes) { + ok = ParseBox(); + } + return state_ >= kParsingBoxes && + state_ < kError; +} + +void MP4Demuxer::Reset() { + moov_ = nullptr; + runs_ = nullptr; + stream_offset_; // TODO; Not sure if this needs to be reset? + DMX_LOG("Warning: resetting stream_offset_\n"); + moof_head_ = 0; + mdat_tail_ = 0; +} + +// TODO(xhwang): Figure out the init data type appropriately once it's spec'ed. +static const char kMp4InitDataType[] = "video/mp4"; + +bool MP4Demuxer::ParseMoov(BoxReader* reader) { + RCHECK(state_ < kError); + moov_ = new Movie(); + RCHECK(moov_->Parse(reader)); + runs_ = new TrackRunIterator(moov_.get()); + + has_audio_ = false; + has_video_ = false; + + for (std::vector::const_iterator track = moov_->tracks.begin(); + track != moov_->tracks.end(); ++track) { + // TODO(strobe): Only the first audio and video track present in a file are + // used. (Track selection is better accomplished via Source IDs, though, so + // adding support for track selection within a stream is low-priority.) + const SampleDescription& samp_descr = + track->media.information.sample_table.description; + + // TODO(strobe): When codec reconfigurations are supported, detect and send + // a codec reconfiguration for fragments using a sample description index + // different from the previous one + size_t desc_idx = 0; + for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { + const TrackExtends& trex = moov_->extends.tracks[t]; + if (trex.track_id == track->header.track_id) { + desc_idx = trex.default_sample_description_index; + break; + } + } + RCHECK(desc_idx > 0); + desc_idx -= 1; // BMFF descriptor index is one-based + + if (track->media.handler.type == kAudio && !audio_config_.IsValidConfig()) { + RCHECK(!samp_descr.audio_entries.empty()); + + // It is not uncommon to find otherwise-valid files with incorrect sample + // description indices, so we fail gracefully in that case. + if (desc_idx >= samp_descr.audio_entries.size()) + desc_idx = 0; + const AudioSampleEntry& entry = samp_descr.audio_entries[desc_idx]; + const AAC& aac = entry.esds.aac; + + if (!(entry.format == FOURCC_MP4A || + (entry.format == FOURCC_ENCA && + entry.sinf.format.format == FOURCC_MP4A))) { + DMX_LOG("Unsupported audio format 0x%x in stsd box\n", entry.format); + return false; + } + + int audio_type = entry.esds.object_type; + DMX_LOG("audio_type 0x%x\n", audio_type); + + const std::vector& asc = aac.AudioSpecificConfig(); + if (asc.size() > 0) { + DMX_LOG("audio specific config:"); + for (unsigned i=0; iheader.track_id; + } + if (track->media.handler.type == kVideo && !video_config_.IsValidConfig()) { + RCHECK(!samp_descr.video_entries.empty()); + if (desc_idx >= samp_descr.video_entries.size()) + desc_idx = 0; + const VideoSampleEntry& entry = samp_descr.video_entries[desc_idx]; + + if (!(entry.format == FOURCC_AVC1 || + (entry.format == FOURCC_ENCV && + entry.sinf.format.format == FOURCC_AVC1))) { + DMX_LOG("Unsupported video format 0x%x in stsd box.\n", entry.format); + return false; + } + + // TODO(strobe): Recover correct crop box + IntSize coded_size(entry.width, entry.height); + IntRect visible_rect(0, 0, coded_size.width(), coded_size.height()); + IntSize natural_size = GetNaturalSize(visible_rect.size(), + entry.pixel_aspect.h_spacing, + entry.pixel_aspect.v_spacing); + is_video_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted; + DMX_LOG("is_video_track_encrypted_: %d\n", is_video_track_encrypted_); + video_config_.Initialize(kCodecH264, H264PROFILE_MAIN, VideoFrameFormat::YV12, + coded_size, visible_rect, natural_size, + // No decoder-specific buffer needed for AVC; + // SPS/PPS are embedded in the video stream + NULL, 0, is_video_track_encrypted_, true); + has_video_ = true; + video_track_id_ = track->header.track_id; + } + } + + //RCHECK(config_cb_.Run(audio_config, video_config)); + + if (moov_->extends.header.fragment_duration > 0) { + duration_ = MicrosecondsFromRational(moov_->extends.header.fragment_duration, + moov_->header.timescale); + } else if (moov_->header.duration > 0 && + moov_->header.duration != kuint64max) { + duration_ = MicrosecondsFromRational(moov_->header.duration, + moov_->header.timescale); + } else { + duration_ = InfiniteMicroseconds; + } + + //if (!init_cb_.is_null()) + // base::ResetAndReturn(&init_cb_).Run(true, duration); + + return true; +} + +Microseconds +MP4Demuxer::Duration() const { + return duration_; +} + +bool MP4Demuxer::ParseMoof(BoxReader* reader) { + RCHECK(state_ < kError); + RCHECK(moov_.get()); // Must already have initialization segment + MovieFragment moof; + RCHECK(moof.Parse(reader)); + RCHECK(runs_->Init(moof)); + //new_segment_cb_.Run(runs_->GetMinDecodeTimestamp()); + ChangeState(kEmittingSamples); + return true; +} + +bool MP4Demuxer::ParseBox() { + RCHECK(state_ < kError); + bool err = false; + nsAutoPtr reader(BoxReader::ReadTopLevelBox(stream_, + stream_offset_, + &err)); + if (!reader || err) { + DMX_LOG("Failed to read box at offset=%lld", stream_offset_); + return false; + } + string type = FourCCToString(reader->type()); + + DMX_LOG("offset=%lld version=0x%x flags=0x%x size=%d", + stream_offset_, (uint32_t)reader->version(), + reader->flags(), reader->size()); + + if (reader->type() == FOURCC_MOOV) { + DMX_LOG("ParseMoov\n"); + if (!ParseMoov(reader.get())) { + DMX_LOG("ParseMoov failed\n"); + return false; + } + } else if (reader->type() == FOURCC_MOOF) { + DMX_LOG("MOOF encountered\n."); + moof_head_ = stream_offset_; + if (!ParseMoof(reader.get())) { + DMX_LOG("ParseMoof failed\n"); + return false; + } + mdat_tail_ = stream_offset_ + reader->size(); + } + + stream_offset_ += reader->size(); + + return true; +} + +bool MP4Demuxer::EmitSample(nsAutoPtr* sample) { + bool ok = true; + if (!runs_->IsRunValid()) { + + // Flush any buffers we've gotten in this chunk so that buffers don't + // cross NewSegment() calls + //ok = SendAndFlushSamples(/*audio_buffers, video_buffers*/); + //if (!ok) + // return false; + + ChangeState(kParsingBoxes); + //end_of_segment_cb_.Run(); + return true; + } + + if (!runs_->IsSampleValid()) { + runs_->AdvanceRun(); + return true; + } + + bool audio = has_audio_ && audio_track_id_ == runs_->track_id(); + bool video = has_video_ && video_track_id_ == runs_->track_id(); + + // Skip this entire track if it's not one we're interested in + if (!audio && !video) + runs_->AdvanceRun(); + + // Attempt to cache the auxiliary information first. Aux info is usually + // placed in a contiguous block before the sample data, rather than being + // interleaved. If we didn't cache it, this would require that we retain the + // start of the segment buffer while reading samples. Aux info is typically + // quite small compared to sample data, so this pattern is useful on + // memory-constrained devices where the source buffer consumes a substantial + // portion of the total system memory. + if (runs_->AuxInfoNeedsToBeCached()) { + int64_t aux_info_offset = runs_->aux_info_offset() + moof_head_; + if (stream_->Length() - aux_info_offset < runs_->aux_info_size()) { + return false; + } + + return runs_->CacheAuxInfo(stream_, moof_head_); + } + + nsAutoPtr decrypt_config; + std::vector subsamples; + if (runs_->is_encrypted()) { + runs_->GetDecryptConfig(decrypt_config); + subsamples = decrypt_config->subsamples(); + } + + nsAutoPtr> frame_buf(new vector()); + const int64_t sample_offset = runs_->sample_offset() + moof_head_; + StreamReader reader(stream_, sample_offset, runs_->sample_size()); + reader.ReadVec(frame_buf, runs_->sample_size()); + + if (video) { + if (!PrepareAVCBuffer(runs_->video_description().avcc, + frame_buf, &subsamples)) { + DMX_LOG("Failed to prepare AVC sample for decode\n"); + return false; + } + } + + if (audio) { + if (!PrepareAACBuffer(runs_->audio_description().esds.aac, + frame_buf, &subsamples)) { + DMX_LOG("Failed to prepare AAC sample for decode\n"); + return false; + } + } + + const bool is_encrypted = (audio && is_audio_track_encrypted_) || + (video && is_video_track_encrypted_); + assert(runs_->is_encrypted() == is_encrypted); + if (decrypt_config) { + if (!subsamples.empty()) { + // Create a new config with the updated subsamples. + decrypt_config = new DecryptConfig(decrypt_config->key_id(), + decrypt_config->iv(), + decrypt_config->data_offset(), + subsamples); + } + // else, use the existing config. + } else if (is_encrypted) { + // The media pipeline requires a DecryptConfig with an empty |iv|. + // TODO(ddorwin): Refactor so we do not need a fake key ID ("1"); + decrypt_config = new DecryptConfig("1", "", 0, std::vector()); + } + + assert(audio || video); + *sample = new MP4Sample(runs_->dts(), + runs_->cts(), + runs_->duration(), + sample_offset, + frame_buf.forget(), + audio ? kAudio : kVideo, + decrypt_config.forget(), + runs_->is_keyframe()); + runs_->AdvanceSample(); + return true; +} + +bool MP4Demuxer::PrepareAVCBuffer( + const AVCDecoderConfigurationRecord& avc_config, + std::vector* frame_buf, + std::vector* subsamples) const { + // Convert the AVC NALU length fields to Annex B headers, as expected by + // decoding libraries. Since this may enlarge the size of the buffer, we also + // update the clear byte count for each subsample if encryption is used to + // account for the difference in size between the length prefix and Annex B + // start code. + RCHECK(AVC::ConvertFrameToAnnexB(avc_config.length_size, frame_buf)); + if (!subsamples->empty()) { + const int nalu_size_diff = 4 - avc_config.length_size; + size_t expected_size = runs_->sample_size() + + subsamples->size() * nalu_size_diff; + RCHECK(frame_buf->size() == expected_size); + for (size_t i = 0; i < subsamples->size(); i++) + (*subsamples)[i].clear_bytes += nalu_size_diff; + } + + if (runs_->is_keyframe()) { + // If this is a keyframe, we (re-)inject SPS and PPS headers at the start of + // a frame. If subsample info is present, we also update the clear byte + // count for that first subsample. + std::vector param_sets; + RCHECK(AVC::ConvertConfigToAnnexB(avc_config, ¶m_sets)); + frame_buf->insert(frame_buf->begin(), + param_sets.begin(), param_sets.end()); + if (!subsamples->empty()) + (*subsamples)[0].clear_bytes += param_sets.size(); + } + return true; +} + +bool MP4Demuxer::PrepareAACBuffer(const AAC& aac_config, + std::vector* frame_buf, + std::vector* subsamples) const { + // Append an ADTS header to every audio sample. + RCHECK(aac_config.ConvertEsdsToADTS(frame_buf)); + + // As above, adjust subsample information to account for the headers. AAC is + // not required to use subsample encryption, so we may need to add an entry. + if (subsamples->empty()) { + SubsampleEntry entry; + entry.clear_bytes = AAC::kADTSHeaderSize; + entry.cypher_bytes = frame_buf->size() - AAC::kADTSHeaderSize; + subsamples->push_back(entry); + } else { + (*subsamples)[0].clear_bytes += AAC::kADTSHeaderSize; + } + return true; +} + +// Reads the metadata boxes. +bool MP4Demuxer::Demux(nsAutoPtr* sample, + bool* end_of_stream) +{ + RCHECK(state_ < kError); + assert(state_ > kWaitingForInit); + *end_of_stream = false; + + const int64_t length = stream_->Length(); + bool ok = true; + while (ok) { + if (state_ == kParsingBoxes) { + if (stream_offset_ < length) { + ok = ParseBox(); + } else { + DMX_LOG("End of stream reached.\n"); + *end_of_stream = true; + break; + } + } else { + DCHECK_EQ(kEmittingSamples, state_); + ok = EmitSample(sample); + if (ok && *sample) { + // Got a sample, return. + break; + } + } + } + + if (!ok) { + DMX_LOG("Error demuxing stream\n"); + ChangeState(kError); + return false; + } + + return true; +} + +void MP4Demuxer::ChangeState(State new_state) { + DMX_LOG("Demuxer changing state: %d\n", new_state); + state_ = new_state; + if (state_ == kError) { + Reset(); + } +} + +const AudioDecoderConfig& +MP4Demuxer::AudioConfig() const +{ + return audio_config_; +} + +const VideoDecoderConfig& +MP4Demuxer::VideoConfig() const +{ + return video_config_; +} + +bool +MP4Demuxer::HasAudio() const +{ + return has_audio_; +} + +bool +MP4Demuxer::HasVideo() const +{ + return has_video_; +} + +bool +MP4Demuxer::CanSeek() const +{ + return can_seek_; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/mp4_demuxer.h b/content/media/fmp4/demuxer/mp4_demuxer.h new file mode 100644 index 000000000000..05d90df2b61b --- /dev/null +++ b/content/media/fmp4/demuxer/mp4_demuxer.h @@ -0,0 +1,159 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_MP4DEMUXER_H +#define MEDIA_MP4_MP4DEMUXER_H + +#include "mp4_demuxer/audio_decoder_config.h" +#include "mp4_demuxer/video_decoder_config.h" +#include "mp4_demuxer/decrypt_config.h" +#include "mp4_demuxer/box_definitions.h" + + +#include "nsAutoPtr.h" +#include + +namespace mp4_demuxer { + +class Stream; +class BoxReader; +struct Movie; +class TrackRunIterator; +struct AVCDecoderConfigurationRecord; +class AAC; + +// Constructs an MP4 Sample. Note this assumes ownership of the |data| vector +// passed in. +struct MP4Sample { + MP4Sample(Microseconds decode_timestamp, + Microseconds composition_timestamp, + Microseconds duration, + int64_t byte_offset, + std::vector* data, + TrackType type, + DecryptConfig* decrypt_config, + bool is_sync_point); + ~MP4Sample(); + + const Microseconds decode_timestamp; + + const Microseconds composition_timestamp; + + const Microseconds duration; + + // Offset of sample in byte stream. + const int64_t byte_offset; + + // Raw demuxed data. + const nsAutoPtr> data; + + // Is this an audio or video sample? + const TrackType type; + + const nsAutoPtr decrypt_config; + + // Whether this is a keyframe or not. + const bool is_sync_point; + + bool is_encrypted() const; +}; + +class MP4Demuxer { +public: + MP4Demuxer(Stream* stream); + ~MP4Demuxer(); + + bool Init(); + + // Reads the metadata boxes, up to the first fragment. + bool Demux(nsAutoPtr* sample, + bool* end_of_stream); + + bool HasAudio() const; + const AudioDecoderConfig& AudioConfig() const; + + bool HasVideo() const; + const VideoDecoderConfig& VideoConfig() const; + + Microseconds Duration() const; + + bool CanSeek() const; + +private: + + enum State { + kWaitingForInit, + kParsingBoxes, + kEmittingSamples, + kError + }; + + // Parses the bitstream. Returns false on error. + bool Parse(nsAutoPtr* sample, + bool& end_of_stream); + + void ChangeState(State new_state); + + // Return true on success, false on failure. + bool ParseBox(); + bool ParseMoov(BoxReader* reader); + bool ParseMoof(BoxReader* reader); + + void Reset(); + + bool EmitSample(nsAutoPtr* sample); + + bool PrepareAACBuffer(const AAC& aac_config, + std::vector* frame_buf, + std::vector* subsamples) const; + + bool PrepareAVCBuffer(const AVCDecoderConfigurationRecord& avc_config, + std::vector* frame_buf, + std::vector* subsamples) const; + + State state_; + + // Stream abstraction that we read from. It is the responsibility of the + // owner of the demuxer to ensure that it stays alive for the lifetime + // of the demuxer. + Stream* stream_; + int64_t stream_offset_; + + Microseconds duration_; + + // These two parameters are only valid in the |kEmittingSegments| state. + // + // |moof_head_| is the offset of the start of the most recently parsed moof + // block. All byte offsets in sample information are relative to this offset, + // as mandated by the Media Source spec. + int64_t moof_head_; + // |mdat_tail_| is the stream offset of the end of the current 'mdat' box. + // Valid iff it is greater than the head of the queue. + int64_t mdat_tail_; + + nsAutoPtr moov_; + nsAutoPtr runs_; + + uint32_t audio_track_id_; + uint32_t video_track_id_; + + uint32_t audio_frameno; + uint32_t video_frameno; + + AudioDecoderConfig audio_config_; + VideoDecoderConfig video_config_; + + bool has_audio_; + bool has_sbr_; // NOTE: This is not initialized! + bool is_audio_track_encrypted_; + + bool has_video_; + bool is_video_track_encrypted_; + + bool can_seek_; +}; + +} // mp4_demuxer + +#endif // MEDIA_MP4_MP4DEMUXER_H diff --git a/content/media/fmp4/demuxer/track_run_iterator.cc b/content/media/fmp4/demuxer/track_run_iterator.cc new file mode 100644 index 000000000000..e0eaa523d3e6 --- /dev/null +++ b/content/media/fmp4/demuxer/track_run_iterator.cc @@ -0,0 +1,451 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/track_run_iterator.h" +#include "mp4_demuxer/basictypes.h" +#include "mp4_demuxer/Streams.h" + +#include +#include +#include + +using namespace std; + +namespace mp4_demuxer { + +static const uint32_t kSampleIsDifferenceSampleFlagMask = 0x10000; + +struct SampleInfo { + int size; + int duration; + int cts_offset; + bool is_keyframe; +}; + +struct TrackRunInfo { + uint32_t track_id; + std::vector samples; + int64_t timescale; + int64_t start_dts; + int64_t sample_start_offset; + + bool is_audio; + const AudioSampleEntry* audio_description; + const VideoSampleEntry* video_description; + + int64_t aux_info_start_offset; // Only valid if aux_info_total_size > 0. + int aux_info_default_size; + std::vector aux_info_sizes; // Populated if default_size == 0. + int aux_info_total_size; + + TrackRunInfo(); + ~TrackRunInfo(); +}; + +TrackRunInfo::TrackRunInfo() + : track_id(0), + timescale(-1), + start_dts(-1), + sample_start_offset(-1), + is_audio(false), + aux_info_start_offset(-1), + aux_info_default_size(-1), + aux_info_total_size(-1) { +} +TrackRunInfo::~TrackRunInfo() {} + +Microseconds TimeDeltaFromRational(int64_t numer, int64_t denom) { + DCHECK_LT((numer > 0 ? numer : -numer), + kint64max / MicrosecondsPerSecond); + return MicrosecondsPerSecond * numer / denom; +} + +TrackRunIterator::TrackRunIterator(const Movie* moov) + : moov_(moov), sample_offset_(0) { + CHECK(moov); +} + +TrackRunIterator::~TrackRunIterator() {} + +static void PopulateSampleInfo(const TrackExtends& trex, + const TrackFragmentHeader& tfhd, + const TrackFragmentRun& trun, + const int64_t edit_list_offset, + const uint32_t i, + SampleInfo* sample_info) { + if (i < trun.sample_sizes.size()) { + sample_info->size = trun.sample_sizes[i]; + } else if (tfhd.default_sample_size > 0) { + sample_info->size = tfhd.default_sample_size; + } else { + sample_info->size = trex.default_sample_size; + } + + if (i < trun.sample_durations.size()) { + sample_info->duration = trun.sample_durations[i]; + } else if (tfhd.default_sample_duration > 0) { + sample_info->duration = tfhd.default_sample_duration; + } else { + sample_info->duration = trex.default_sample_duration; + } + + if (i < trun.sample_composition_time_offsets.size()) { + sample_info->cts_offset = trun.sample_composition_time_offsets[i]; + } else { + sample_info->cts_offset = 0; + } + sample_info->cts_offset += edit_list_offset; + + uint32_t flags; + if (i < trun.sample_flags.size()) { + flags = trun.sample_flags[i]; + } else if (tfhd.has_default_sample_flags) { + flags = tfhd.default_sample_flags; + } else { + flags = trex.default_sample_flags; + } + sample_info->is_keyframe = !(flags & kSampleIsDifferenceSampleFlagMask); +} + +// In well-structured encrypted media, each track run will be immediately +// preceded by its auxiliary information; this is the only optimal storage +// pattern in terms of minimum number of bytes from a serial stream needed to +// begin playback. It also allows us to optimize caching on memory-constrained +// architectures, because we can cache the relatively small auxiliary +// information for an entire run and then discard data from the input stream, +// instead of retaining the entire 'mdat' box. +// +// We optimize for this situation (with no loss of generality) by sorting track +// runs during iteration in order of their first data offset (either sample data +// or auxiliary data). +class CompareMinTrackRunDataOffset { + public: + bool operator()(const TrackRunInfo& a, const TrackRunInfo& b) { + int64_t a_aux = a.aux_info_total_size ? a.aux_info_start_offset : kint64max; + int64_t b_aux = b.aux_info_total_size ? b.aux_info_start_offset : kint64max; + + int64_t a_lesser = std::min(a_aux, a.sample_start_offset); + int64_t a_greater = std::max(a_aux, a.sample_start_offset); + int64_t b_lesser = std::min(b_aux, b.sample_start_offset); + int64_t b_greater = std::max(b_aux, b.sample_start_offset); + + if (a_lesser == b_lesser) return a_greater < b_greater; + return a_lesser < b_lesser; + } +}; + +bool TrackRunIterator::Init(const MovieFragment& moof) { + runs_.clear(); + + for (size_t i = 0; i < moof.tracks.size(); i++) { + const TrackFragment& traf = moof.tracks[i]; + + const Track* trak = NULL; + for (size_t t = 0; t < moov_->tracks.size(); t++) { + if (moov_->tracks[t].header.track_id == traf.header.track_id) + trak = &moov_->tracks[t]; + } + RCHECK(trak); + + const TrackExtends* trex = NULL; + for (size_t t = 0; t < moov_->extends.tracks.size(); t++) { + if (moov_->extends.tracks[t].track_id == traf.header.track_id) + trex = &moov_->extends.tracks[t]; + } + RCHECK(trex); + + const SampleDescription& stsd = + trak->media.information.sample_table.description; + if (stsd.type != kAudio && stsd.type != kVideo) { + DMX_LOG("Skipping unhandled track type\n"); + continue; + } + size_t desc_idx = traf.header.sample_description_index; + if (!desc_idx) desc_idx = trex->default_sample_description_index; + RCHECK(desc_idx > 0); // Descriptions are one-indexed in the file + desc_idx -= 1; + + // Process edit list to remove CTS offset introduced in the presence of + // B-frames (those that contain a single edit with a nonnegative media + // time). Other uses of edit lists are not supported, as they are + // both uncommon and better served by higher-level protocols. + int64_t edit_list_offset = 0; + const std::vector& edits = trak->edit.list.edits; + if (!edits.empty()) { + if (edits.size() > 1) + DMX_LOG("Multi-entry edit box detected; some components ignored.\n"); + + if (edits[0].media_time < 0) { + DMX_LOG("Empty edit list entry ignored.\n"); + } else { + edit_list_offset = -edits[0].media_time; + } + } + + int64_t run_start_dts = traf.decode_time.decode_time; + int sample_count_sum = 0; + for (size_t j = 0; j < traf.runs.size(); j++) { + const TrackFragmentRun& trun = traf.runs[j]; + TrackRunInfo tri; + tri.track_id = traf.header.track_id; + tri.timescale = trak->media.header.timescale; + tri.start_dts = run_start_dts; + tri.sample_start_offset = trun.data_offset; + + tri.is_audio = (stsd.type == kAudio); + if (tri.is_audio) { + RCHECK(!stsd.audio_entries.empty()); + if (desc_idx > stsd.audio_entries.size()) + desc_idx = 0; + tri.audio_description = &stsd.audio_entries[desc_idx]; + } else { + RCHECK(!stsd.video_entries.empty()); + if (desc_idx > stsd.video_entries.size()) + desc_idx = 0; + tri.video_description = &stsd.video_entries[desc_idx]; + } + + // Collect information from the auxiliary_offset entry with the same index + // in the 'saiz' container as the current run's index in the 'trun' + // container, if it is present. + if (traf.auxiliary_offset.offsets.size() > j) { + // There should be an auxiliary info entry corresponding to each sample + // in the auxiliary offset entry's corresponding track run. + RCHECK(traf.auxiliary_size.sample_count >= + sample_count_sum + trun.sample_count); + tri.aux_info_start_offset = traf.auxiliary_offset.offsets[j]; + tri.aux_info_default_size = + traf.auxiliary_size.default_sample_info_size; + if (tri.aux_info_default_size == 0) { + const std::vector& sizes = + traf.auxiliary_size.sample_info_sizes; + tri.aux_info_sizes.insert(tri.aux_info_sizes.begin(), + sizes.begin() + sample_count_sum, + sizes.begin() + sample_count_sum + trun.sample_count); + } + + // If the default info size is positive, find the total size of the aux + // info block from it, otherwise sum over the individual sizes of each + // aux info entry in the aux_offset entry. + if (tri.aux_info_default_size) { + tri.aux_info_total_size = + tri.aux_info_default_size * trun.sample_count; + } else { + tri.aux_info_total_size = 0; + for (size_t k = 0; k < trun.sample_count; k++) { + tri.aux_info_total_size += tri.aux_info_sizes[k]; + } + } + } else { + tri.aux_info_start_offset = -1; + tri.aux_info_total_size = 0; + } + + tri.samples.resize(trun.sample_count); + for (size_t k = 0; k < trun.sample_count; k++) { + PopulateSampleInfo(*trex, traf.header, trun, edit_list_offset, + k, &tri.samples[k]); + run_start_dts += tri.samples[k].duration; + } + runs_.push_back(tri); + sample_count_sum += trun.sample_count; + } + } + + std::sort(runs_.begin(), runs_.end(), CompareMinTrackRunDataOffset()); + run_itr_ = runs_.begin(); + ResetRun(); + return true; +} + +void TrackRunIterator::AdvanceRun() { + ++run_itr_; + ResetRun(); +} + +void TrackRunIterator::ResetRun() { + if (!IsRunValid()) return; + sample_dts_ = run_itr_->start_dts; + sample_offset_ = run_itr_->sample_start_offset; + sample_itr_ = run_itr_->samples.begin(); + cenc_info_.clear(); +} + +void TrackRunIterator::AdvanceSample() { + DCHECK(IsSampleValid()); + sample_dts_ += sample_itr_->duration; + sample_offset_ += sample_itr_->size; + ++sample_itr_; +} + +// This implementation only indicates a need for caching if CENC auxiliary +// info is available in the stream. +bool TrackRunIterator::AuxInfoNeedsToBeCached() { + DCHECK(IsRunValid()); + return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0; +} + +// This implementation currently only caches CENC auxiliary info. +bool TrackRunIterator::CacheAuxInfo(Stream* stream, int64_t moof_offset) { + RCHECK(AuxInfoNeedsToBeCached()); + + int64_t offset = aux_info_offset() + moof_offset; + if (stream->Length() - offset < aux_info_size()) { + return false; + } + + assert(run_itr_ == runs_.begin()); + cenc_info_.resize(run_itr_->samples.size()); + int64_t pos = 0; + for (size_t i = 0; i < run_itr_->samples.size(); i++) { + int info_size = run_itr_->aux_info_default_size; + if (!info_size) + info_size = run_itr_->aux_info_sizes[i]; + + StreamReader reader(stream, offset + pos, info_size); + RCHECK(cenc_info_[i].Parse(track_encryption().default_iv_size, &reader)); + pos += info_size; + } + + return true; +} + +bool TrackRunIterator::IsRunValid() const { + return run_itr_ != runs_.end(); +} + +bool TrackRunIterator::IsSampleValid() const { + return IsRunValid() && (sample_itr_ != run_itr_->samples.end()); +} + +// Because tracks are in sorted order and auxiliary information is cached when +// returning samples, it is guaranteed that no data will be required before the +// lesser of the minimum data offset of this track and the next in sequence. +// (The stronger condition - that no data is required before the minimum data +// offset of this track alone - is not guaranteed, because the BMFF spec does +// not have any inter-run ordering restrictions.) +int64_t TrackRunIterator::GetMaxClearOffset() { + int64_t offset = kint64max; + + if (IsSampleValid()) { + offset = std::min(offset, sample_offset_); + if (AuxInfoNeedsToBeCached()) + offset = std::min(offset, aux_info_offset()); + } + if (run_itr_ != runs_.end()) { + std::vector::const_iterator next_run = run_itr_ + 1; + if (next_run != runs_.end()) { + offset = std::min(offset, next_run->sample_start_offset); + if (next_run->aux_info_total_size) + offset = std::min(offset, next_run->aux_info_start_offset); + } + } + if (offset == kint64max) return 0; + return offset; +} + +Microseconds TrackRunIterator::GetMinDecodeTimestamp() { + Microseconds dts = -1; + for (size_t i = 0; i < runs_.size(); i++) { + dts = std::min(dts, MicrosecondsFromRational(runs_[i].start_dts, + runs_[i].timescale)); + } + return dts; +} + +uint32_t TrackRunIterator::track_id() const { + DCHECK(IsRunValid()); + return run_itr_->track_id; +} + +bool TrackRunIterator::is_encrypted() const { + DCHECK(IsRunValid()); + return track_encryption().is_encrypted; +} + +int64_t TrackRunIterator::aux_info_offset() const { + return run_itr_->aux_info_start_offset; +} + +int TrackRunIterator::aux_info_size() const { + return run_itr_->aux_info_total_size; +} + +bool TrackRunIterator::is_audio() const { + DCHECK(IsRunValid()); + return run_itr_->is_audio; +} + +const AudioSampleEntry& TrackRunIterator::audio_description() const { + DCHECK(is_audio()); + DCHECK(run_itr_->audio_description); + return *run_itr_->audio_description; +} + +const VideoSampleEntry& TrackRunIterator::video_description() const { + DCHECK(!is_audio()); + DCHECK(run_itr_->video_description); + return *run_itr_->video_description; +} + +int64_t TrackRunIterator::sample_offset() const { + DCHECK(IsSampleValid()); + return sample_offset_; +} + +int TrackRunIterator::sample_size() const { + DCHECK(IsSampleValid()); + return sample_itr_->size; +} + +Microseconds TrackRunIterator::dts() const { + DCHECK(IsSampleValid()); + return MicrosecondsFromRational(sample_dts_, run_itr_->timescale); +} + +Microseconds TrackRunIterator::cts() const { + DCHECK(IsSampleValid()); + return MicrosecondsFromRational(sample_dts_ + sample_itr_->cts_offset, + run_itr_->timescale); +} + +Microseconds TrackRunIterator::duration() const { + DCHECK(IsSampleValid()); + return MicrosecondsFromRational(sample_itr_->duration, run_itr_->timescale); +} + +bool TrackRunIterator::is_keyframe() const { + DCHECK(IsSampleValid()); + return sample_itr_->is_keyframe; +} + +const TrackEncryption& TrackRunIterator::track_encryption() const { + if (is_audio()) + return audio_description().sinf.info.track_encryption; + return video_description().sinf.info.track_encryption; +} + +void TrackRunIterator::GetDecryptConfig(nsAutoPtr& config) { + size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); + DCHECK(sample_idx < cenc_info_.size()); + const FrameCENCInfo& cenc_info = cenc_info_[sample_idx]; + DCHECK(is_encrypted() && !AuxInfoNeedsToBeCached()); + + if (!cenc_info.subsamples.empty() && + (cenc_info.GetTotalSizeOfSubsamples() != + static_cast(sample_size()))) { + DMX_LOG("Incorrect CENC subsample size.\n"); + return; + } + + const std::vector& kid = track_encryption().default_kid; + config = new DecryptConfig( + std::string(reinterpret_cast(&kid[0]), kid.size()), + std::string(reinterpret_cast(cenc_info.iv), + arraysize(cenc_info.iv)), + 0, // No offset to start of media data in MP4 using CENC. + cenc_info.subsamples); +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/track_run_iterator.h b/content/media/fmp4/demuxer/track_run_iterator.h new file mode 100644 index 000000000000..2d7f0fdeca12 --- /dev/null +++ b/content/media/fmp4/demuxer/track_run_iterator.h @@ -0,0 +1,107 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MP4_TRACK_RUN_ITERATOR_H_ +#define MEDIA_MP4_TRACK_RUN_ITERATOR_H_ + +#include +#include + +#include "mp4_demuxer/box_definitions.h" +#include "mp4_demuxer/cenc.h" +#include "nsAutoPtr.h" + +namespace mp4_demuxer { + +class DecryptConfig; + +Microseconds MicrosecondsFromRational(int64_t numer, int64_t denom); + +struct SampleInfo; +struct TrackRunInfo; + +class TrackRunIterator { + public: + // Create a new TrackRunIterator. A reference to |moov| will be retained for + // the lifetime of this object. + TrackRunIterator(const Movie* moov); + ~TrackRunIterator(); + + void Reset(); + + // Sets up the iterator to handle all the runs from the current fragment. + bool Init(const MovieFragment& moof); + + // Returns true if the properties of the current run or sample are valid. + bool IsRunValid() const; + bool IsSampleValid() const; + + // Advance the properties to refer to the next run or sample. Requires that + // the current sample be valid. + void AdvanceRun(); + void AdvanceSample(); + + // Returns true if this track run has auxiliary information and has not yet + // been cached. Only valid if IsRunValid(). + bool AuxInfoNeedsToBeCached(); + + // Caches the CENC data from the given buffer. |buf| must be a buffer starting + // at the offset given by cenc_offset(), with a |size| of at least + // cenc_size(). Returns true on success, false on error. + //bool CacheAuxInfo(const uint8_t* buf, int size); + bool CacheAuxInfo(Stream* stream, int64_t moof_offset); + + // Returns the maximum buffer location at which no data earlier in the stream + // will be required in order to read the current or any subsequent sample. You + // may clear all data up to this offset before reading the current sample + // safely. Result is in the same units as offset() (for Media Source this is + // in bytes past the the head of the MOOF box). + int64_t GetMaxClearOffset(); + + // Returns the minimum timestamp (or kInfiniteDuration if no runs present). + Microseconds GetMinDecodeTimestamp(); + + // Property of the current run. Only valid if IsRunValid(). + uint32_t track_id() const; + int64_t aux_info_offset() const; + int aux_info_size() const; + bool is_encrypted() const; + bool is_audio() const; + // Only one is valid, based on the value of is_audio(). + const AudioSampleEntry& audio_description() const; + const VideoSampleEntry& video_description() const; + + // Properties of the current sample. Only valid if IsSampleValid(). + int64_t sample_offset() const; + int sample_size() const; + Microseconds dts() const; + Microseconds cts() const; + Microseconds duration() const; + bool is_keyframe() const; + + // Only call when is_encrypted() is true and AuxInfoNeedsToBeCached() is + // false. Result is owned by caller. + void GetDecryptConfig(nsAutoPtr& config); + + private: + void ResetRun(); + const TrackEncryption& track_encryption() const; + + const Movie* moov_; + + std::vector runs_; + std::vector::const_iterator run_itr_; + std::vector::const_iterator sample_itr_; + + std::vector cenc_info_; + + int64_t sample_dts_; + int64_t sample_offset_; + + DISALLOW_COPY_AND_ASSIGN(TrackRunIterator); +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_MP4_TRACK_RUN_ITERATOR_H_ diff --git a/content/media/fmp4/demuxer/video_decoder_config.cc b/content/media/fmp4/demuxer/video_decoder_config.cc new file mode 100644 index 000000000000..3abf12ac1ac0 --- /dev/null +++ b/content/media/fmp4/demuxer/video_decoder_config.cc @@ -0,0 +1,158 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/video_decoder_config.h" + +#include + +namespace mp4_demuxer { + +VideoDecoderConfig::VideoDecoderConfig() + : codec_(kUnknownVideoCodec), + profile_(VIDEO_CODEC_PROFILE_UNKNOWN), + format_(VideoFrameFormat::INVALID), + is_encrypted_(false) { +} + +VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec, + VideoCodecProfile profile, + VideoFrameFormat format, + const IntSize& coded_size, + const IntRect& visible_rect, + const IntSize& natural_size, + const uint8_t* extra_data, + size_t extra_data_size, + bool is_encrypted) { + Initialize(codec, profile, format, coded_size, visible_rect, natural_size, + extra_data, extra_data_size, is_encrypted, true); +} + +VideoDecoderConfig::~VideoDecoderConfig() {} + +// Some videos just want to watch the world burn, with a height of 0; cap the +// "infinite" aspect ratio resulting. +static const int kInfiniteRatio = 99999; + +// Common aspect ratios (multiplied by 100 and truncated) used for histogramming +// video sizes. These were taken on 20111103 from +// http://wikipedia.org/wiki/Aspect_ratio_(image)#Previous_and_currently_used_aspect_ratios +static const int kCommonAspectRatios100[] = { + 100, 115, 133, 137, 143, 150, 155, 160, 166, 175, 177, 185, 200, 210, 220, + 221, 235, 237, 240, 255, 259, 266, 276, 293, 400, 1200, kInfiniteRatio, +}; + +void VideoDecoderConfig::Initialize(VideoCodec codec, + VideoCodecProfile profile, + VideoFrameFormat format, + const IntSize& coded_size, + const IntRect& visible_rect, + const IntSize& natural_size, + const uint8_t* extra_data, + size_t extra_data_size, + bool is_encrypted, + bool record_stats) { + CHECK((extra_data_size != 0) == (extra_data != NULL)); + + codec_ = codec; + profile_ = profile; + format_ = format; + coded_size_ = coded_size; + visible_rect_ = visible_rect; + natural_size_ = natural_size; + extra_data_.assign(extra_data, extra_data + extra_data_size); + is_encrypted_ = is_encrypted; +} + +bool VideoDecoderConfig::IsValidConfig() const { + return codec_ != kUnknownVideoCodec && + natural_size_.width() > 0 && + natural_size_.height() > 0 && + + // Copied from: + // VideoFrame::IsValidConfig(format_, coded_size_, visible_rect_, natural_size_) + format_ != VideoFrameFormat::INVALID && + !coded_size_.IsEmpty() && + coded_size_.GetArea() <= kMaxCanvas && + coded_size_.width() <= kMaxDimension && + coded_size_.height() <= kMaxDimension && + !visible_rect_.IsEmpty() && + visible_rect_.x() >= 0 && visible_rect_.y() >= 0 && + visible_rect_.right() <= coded_size_.width() && + visible_rect_.bottom() <= coded_size_.height() && + !natural_size_.IsEmpty() && + natural_size_.GetArea() <= kMaxCanvas && + natural_size_.width() <= kMaxDimension && + natural_size_.height() <= kMaxDimension; +} + +bool VideoDecoderConfig::Matches(const VideoDecoderConfig& config) const { + return ((codec() == config.codec()) && + (format() == config.format()) && + (profile() == config.profile()) && + (coded_size() == config.coded_size()) && + (visible_rect() == config.visible_rect()) && + (natural_size() == config.natural_size()) && + (extra_data_size() == config.extra_data_size()) && + (!extra_data() || !memcmp(extra_data(), config.extra_data(), + extra_data_size())) && + (is_encrypted() == config.is_encrypted())); +} + +std::string VideoDecoderConfig::AsHumanReadableString() const { + std::ostringstream s; + s << "codec: " << codec() + << " format: " << format() + << " profile: " << profile() + << " coded size: [" << coded_size().width() + << "," << coded_size().height() << "]" + << " visible rect: [" << visible_rect().x() + << "," << visible_rect().y() + << "," << visible_rect().width() + << "," << visible_rect().height() << "]" + << " natural size: [" << natural_size().width() + << "," << natural_size().height() << "]" + << " has extra data? " << (extra_data() ? "true" : "false") + << " encrypted? " << (is_encrypted() ? "true" : "false"); + return s.str(); +} + +VideoCodec VideoDecoderConfig::codec() const { + return codec_; +} + +VideoCodecProfile VideoDecoderConfig::profile() const { + return profile_; +} + +VideoFrameFormat VideoDecoderConfig::format() const { + return format_; +} + +IntSize VideoDecoderConfig::coded_size() const { + return coded_size_; +} + +IntRect VideoDecoderConfig::visible_rect() const { + return visible_rect_; +} + +IntSize VideoDecoderConfig::natural_size() const { + return natural_size_; +} + +const uint8_t* VideoDecoderConfig::extra_data() const { + if (extra_data_.empty()) + return NULL; + return &extra_data_[0]; +} + +size_t VideoDecoderConfig::extra_data_size() const { + return extra_data_.size(); +} + +bool VideoDecoderConfig::is_encrypted() const { + return is_encrypted_; +} + +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/video_decoder_config.h b/content/media/fmp4/demuxer/video_decoder_config.h new file mode 100644 index 000000000000..0751f9250104 --- /dev/null +++ b/content/media/fmp4/demuxer/video_decoder_config.h @@ -0,0 +1,171 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_VIDEO_DECODER_CONFIG_H_ +#define MEDIA_BASE_VIDEO_DECODER_CONFIG_H_ + +#include +#include + +#include "mp4_demuxer/basictypes.h" + +namespace mp4_demuxer { + +enum VideoCodec { + // These values are histogrammed over time; do not change their ordinal + // values. When deleting a codec replace it with a dummy value; when adding a + // codec, do so at the bottom (and update kVideoCodecMax). + kUnknownVideoCodec = 0, + kCodecH264, + kCodecVC1, + kCodecMPEG2, + kCodecMPEG4, + kCodecTheora, + kCodecVP8, + kCodecVP9, + // DO NOT ADD RANDOM VIDEO CODECS! + // + // The only acceptable time to add a new codec is if there is production code + // that uses said codec in the same CL. + + kVideoCodecMax = kCodecVP9 // Must equal the last "real" codec above. +}; + +// Video stream profile. This *must* match PP_VideoDecoder_Profile. +// (enforced in webkit/plugins/ppapi/ppb_video_decoder_impl.cc) +enum VideoCodecProfile { + // Keep the values in this enum unique, as they imply format (h.264 vs. VP8, + // for example), and keep the values for a particular format grouped + // together for clarity. + VIDEO_CODEC_PROFILE_UNKNOWN = -1, + H264PROFILE_MIN = 0, + H264PROFILE_BASELINE = H264PROFILE_MIN, + H264PROFILE_MAIN = 1, + H264PROFILE_EXTENDED = 2, + H264PROFILE_HIGH = 3, + H264PROFILE_HIGH10PROFILE = 4, + H264PROFILE_HIGH422PROFILE = 5, + H264PROFILE_HIGH444PREDICTIVEPROFILE = 6, + H264PROFILE_SCALABLEBASELINE = 7, + H264PROFILE_SCALABLEHIGH = 8, + H264PROFILE_STEREOHIGH = 9, + H264PROFILE_MULTIVIEWHIGH = 10, + H264PROFILE_MAX = H264PROFILE_MULTIVIEWHIGH, + VP8PROFILE_MIN = 11, + VP8PROFILE_MAIN = VP8PROFILE_MIN, + VP8PROFILE_MAX = VP8PROFILE_MAIN, + VP9PROFILE_MIN = 12, + VP9PROFILE_MAIN = VP9PROFILE_MIN, + VP9PROFILE_MAX = VP9PROFILE_MAIN, + VIDEO_CODEC_PROFILE_MAX = VP9PROFILE_MAX, +}; + +// Surface formats roughly based on FOURCC labels, see: +// http://www.fourcc.org/rgb.php +// http://www.fourcc.org/yuv.php +enum VideoFrameFormat { // VideoFrame::Format + INVALID = 0, // Invalid format value. Used for error reporting. + RGB32 = 4, // 32bpp RGB packed with extra byte 8:8:8 + YV12 = 6, // 12bpp YVU planar 1x1 Y, 2x2 VU samples + YV16 = 7, // 16bpp YVU planar 1x1 Y, 2x1 VU samples + EMPTY = 9, // An empty frame. + I420 = 11, // 12bpp YVU planar 1x1 Y, 2x2 UV samples. + NATIVE_TEXTURE = 12, // Native texture. Pixel-format agnostic. +#if defined(GOOGLE_TV) + HOLE = 13, // Hole frame. +#endif + YV12A = 14, // 20bpp YUVA planar 1x1 Y, 2x2 VU, 1x1 A samples. +}; + +class VideoDecoderConfig { + public: + // Constructs an uninitialized object. Clients should call Initialize() with + // appropriate values before using. + VideoDecoderConfig(); + + // Constructs an initialized object. It is acceptable to pass in NULL for + // |extra_data|, otherwise the memory is copied. + VideoDecoderConfig(VideoCodec codec, + VideoCodecProfile profile, + VideoFrameFormat format, + const IntSize& coded_size, + const IntRect& visible_rect, + const IntSize& natural_size, + const uint8_t* extra_data, size_t extra_data_size, + bool is_encrypted); + + ~VideoDecoderConfig(); + + // Resets the internal state of this object. + void Initialize(VideoCodec codec, + VideoCodecProfile profile, + VideoFrameFormat format, + const IntSize& coded_size, + const IntRect& visible_rect, + const IntSize& natural_size, + const uint8_t* extra_data, size_t extra_data_size, + bool is_encrypted, + bool record_stats); + + // Returns true if this object has appropriate configuration values, false + // otherwise. + bool IsValidConfig() const; + + // Returns true if all fields in |config| match this config. + // Note: The contents of |extra_data_| are compared not the raw pointers. + bool Matches(const VideoDecoderConfig& config) const; + + // Returns a human-readable string describing |*this|. For debugging & test + // output only. + std::string AsHumanReadableString() const; + + VideoCodec codec() const; + VideoCodecProfile profile() const; + + // Video format used to determine YUV buffer sizes. + VideoFrameFormat format() const; + + // Width and height of video frame immediately post-decode. Not all pixels + // in this region are valid. + IntSize coded_size() const; + + // Region of |coded_size_| that is visible. + IntRect visible_rect() const; + + // Final visible width and height of a video frame with aspect ratio taken + // into account. + IntSize natural_size() const; + + // Optional byte data required to initialize video decoders, such as H.264 + // AAVC data. + const uint8_t* extra_data() const; + size_t extra_data_size() const; + + // Whether the video stream is potentially encrypted. + // Note that in a potentially encrypted video stream, individual buffers + // can be encrypted or not encrypted. + bool is_encrypted() const; + + private: + VideoCodec codec_; + VideoCodecProfile profile_; + + VideoFrameFormat format_; + + IntSize coded_size_; + IntRect visible_rect_; + IntSize natural_size_; + + std::vector extra_data_; + + bool is_encrypted_; + + // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler + // generated copy constructor and assignment operator. Since the extra data is + // typically small, the performance impact is minimal. +}; + +} // namespace mp4_demuxer + +#endif // MEDIA_BASE_VIDEO_DECODER_CONFIG_H_ diff --git a/content/media/fmp4/demuxer/video_util.cc b/content/media/fmp4/demuxer/video_util.cc new file mode 100644 index 000000000000..15eae7f0e72b --- /dev/null +++ b/content/media/fmp4/demuxer/video_util.cc @@ -0,0 +1,299 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mp4_demuxer/video_util.h" + +#include + +namespace mp4_demuxer { + +IntSize GetNaturalSize(const IntSize& visible_size, + int aspect_ratio_numerator, + int aspect_ratio_denominator) { + if (aspect_ratio_denominator == 0 || + aspect_ratio_numerator < 0 || + aspect_ratio_denominator < 0) + return IntSize(); + + double aspect_ratio = aspect_ratio_numerator / + static_cast(aspect_ratio_denominator); + + int width = floor(visible_size.width() * aspect_ratio + 0.5); + int height = visible_size.height(); + + // An even width makes things easier for YV12 and appears to be the behavior + // expected by WebKit layout tests. + return IntSize(width & ~1, height); +} + +/* +void CopyPlane(size_t plane, const uint8_t* source, int stride, int rows, + VideoFrame* frame) { + uint8_t* dest = frame->data(plane); + int dest_stride = frame->stride(plane); + + // Clamp in case source frame has smaller stride. + int bytes_to_copy_per_row = std::min(frame->row_bytes(plane), stride); + + // Clamp in case source frame has smaller height. + int rows_to_copy = std::min(frame->rows(plane), rows); + + // Copy! + for (int row = 0; row < rows_to_copy; ++row) { + memcpy(dest, source, bytes_to_copy_per_row); + source += stride; + dest += dest_stride; + } +} + +void CopyYPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { + CopyPlane(VideoFrame::kYPlane, source, stride, rows, frame); +} + +void CopyUPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { + CopyPlane(VideoFrame::kUPlane, source, stride, rows, frame); +} + +void CopyVPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { + CopyPlane(VideoFrame::kVPlane, source, stride, rows, frame); +} + +void CopyAPlane(const uint8_t* source, int stride, int rows, VideoFrame* frame) { + CopyPlane(VideoFrame::kAPlane, source, stride, rows, frame); +} + +void MakeOpaqueAPlane(int stride, int rows, VideoFrame* frame) { + int rows_to_clear = std::min(frame->rows(VideoFrame::kAPlane), rows); + memset(frame->data(VideoFrame::kAPlane), 255, + frame->stride(VideoFrame::kAPlane) * rows_to_clear); +} + +void FillYUV(VideoFrame* frame, uint8_t y, uint8_t u, uint8_t v) { + // Fill the Y plane. + uint8_t* y_plane = frame->data(VideoFrame::kYPlane); + int y_rows = frame->rows(VideoFrame::kYPlane); + int y_row_bytes = frame->row_bytes(VideoFrame::kYPlane); + for (int i = 0; i < y_rows; ++i) { + memset(y_plane, y, y_row_bytes); + y_plane += frame->stride(VideoFrame::kYPlane); + } + + // Fill the U and V planes. + uint8_t* u_plane = frame->data(VideoFrame::kUPlane); + uint8_t* v_plane = frame->data(VideoFrame::kVPlane); + int uv_rows = frame->rows(VideoFrame::kUPlane); + int u_row_bytes = frame->row_bytes(VideoFrame::kUPlane); + int v_row_bytes = frame->row_bytes(VideoFrame::kVPlane); + for (int i = 0; i < uv_rows; ++i) { + memset(u_plane, u, u_row_bytes); + memset(v_plane, v, v_row_bytes); + u_plane += frame->stride(VideoFrame::kUPlane); + v_plane += frame->stride(VideoFrame::kVPlane); + } +} + +static void LetterboxPlane(VideoFrame* frame, + int plane, + const gfx::Rect& view_area, + uint8_t fill_byte) { + uint8_t* ptr = frame->data(plane); + const int rows = frame->rows(plane); + const int row_bytes = frame->row_bytes(plane); + const int stride = frame->stride(plane); + + CHECK_GE(stride, row_bytes); + CHECK_GE(view_area.x(), 0); + CHECK_GE(view_area.y(), 0); + CHECK_LE(view_area.right(), row_bytes); + CHECK_LE(view_area.bottom(), rows); + + int y = 0; + for (; y < view_area.y(); y++) { + memset(ptr, fill_byte, row_bytes); + ptr += stride; + } + if (view_area.width() < row_bytes) { + for (; y < view_area.bottom(); y++) { + if (view_area.x() > 0) { + memset(ptr, fill_byte, view_area.x()); + } + if (view_area.right() < row_bytes) { + memset(ptr + view_area.right(), + fill_byte, + row_bytes - view_area.right()); + } + ptr += stride; + } + } else { + y += view_area.height(); + ptr += stride * view_area.height(); + } + for (; y < rows; y++) { + memset(ptr, fill_byte, row_bytes); + ptr += stride; + } +} + +void LetterboxYUV(VideoFrame* frame, const gfx::Rect& view_area) { + DCHECK(!(view_area.x() & 1)); + DCHECK(!(view_area.y() & 1)); + DCHECK(!(view_area.width() & 1)); + DCHECK(!(view_area.height() & 1)); + DCHECK_EQ(frame->format(), VideoFrame::YV12); + LetterboxPlane(frame, VideoFrame::kYPlane, view_area, 0x00); + gfx::Rect half_view_area(view_area.x() / 2, + view_area.y() / 2, + view_area.width() / 2, + view_area.height() / 2); + LetterboxPlane(frame, VideoFrame::kUPlane, half_view_area, 0x80); + LetterboxPlane(frame, VideoFrame::kVPlane, half_view_area, 0x80); +} + +void RotatePlaneByPixels( + const uint8_t* src, + uint8_t* dest, + int width, + int height, + int rotation, // Clockwise. + bool flip_vert, + bool flip_horiz) { + DCHECK((width > 0) && (height > 0) && + ((width & 1) == 0) && ((height & 1) == 0) && + (rotation >= 0) && (rotation < 360) && (rotation % 90 == 0)); + + // Consolidate cases. Only 0 and 90 are left. + if (rotation == 180 || rotation == 270) { + rotation -= 180; + flip_vert = !flip_vert; + flip_horiz = !flip_horiz; + } + + int num_rows = height; + int num_cols = width; + int src_stride = width; + // During pixel copying, the corresponding incremental of dest pointer + // when src pointer moves to next row. + int dest_row_step = width; + // During pixel copying, the corresponding incremental of dest pointer + // when src pointer moves to next column. + int dest_col_step = 1; + + if (rotation == 0) { + if (flip_horiz) { + // Use pixel copying. + dest_col_step = -1; + if (flip_vert) { + // Rotation 180. + dest_row_step = -width; + dest += height * width - 1; + } else { + dest += width - 1; + } + } else { + if (flip_vert) { + // Fast copy by rows. + dest += width * (height - 1); + for (int row = 0; row < height; ++row) { + memcpy(dest, src, width); + src += width; + dest -= width; + } + } else { + memcpy(dest, src, width * height); + } + return; + } + } else if (rotation == 90) { + int offset; + if (width > height) { + offset = (width - height) / 2; + src += offset; + num_rows = num_cols = height; + } else { + offset = (height - width) / 2; + src += width * offset; + num_rows = num_cols = width; + } + + dest_col_step = (flip_vert ? -width : width); + dest_row_step = (flip_horiz ? 1 : -1); + if (flip_horiz) { + if (flip_vert) { + dest += (width > height ? width * (height - 1) + offset : + width * (height - offset - 1)); + } else { + dest += (width > height ? offset : width * offset); + } + } else { + if (flip_vert) { + dest += (width > height ? width * height - offset - 1 : + width * (height - offset) - 1); + } else { + dest += (width > height ? width - offset - 1 : + width * (offset + 1) - 1); + } + } + } else { + NOTREACHED(); + } + + // Copy pixels. + for (int row = 0; row < num_rows; ++row) { + const uint8_t* src_ptr = src; + uint8_t* dest_ptr = dest; + for (int col = 0; col < num_cols; ++col) { + *dest_ptr = *src_ptr++; + dest_ptr += dest_col_step; + } + src += src_stride; + dest += dest_row_step; + } +} + +gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds, + const IntSize& content) { + int64_t x = static_cast(content.width()) * bounds.height(); + int64_t y = static_cast(content.height()) * bounds.width(); + + IntSize letterbox(bounds.width(), bounds.height()); + if (y < x) + letterbox.set_height(static_cast(y / content.width())); + else + letterbox.set_width(static_cast(x / content.height())); + gfx::Rect result = bounds; + result.ClampToCenteredSize(letterbox); + return result; +} + +void CopyRGBToVideoFrame(const uint8_t* source, + int stride, + const gfx::Rect& region_in_frame, + VideoFrame* frame) { + const int kY = VideoFrame::kYPlane; + const int kU = VideoFrame::kUPlane; + const int kV = VideoFrame::kVPlane; + CHECK_EQ(frame->stride(kU), frame->stride(kV)); + const int uv_stride = frame->stride(kU); + + if (region_in_frame != gfx::Rect(frame->coded_size())) { + LetterboxYUV(frame, region_in_frame); + } + + const int y_offset = region_in_frame.x() + + (region_in_frame.y() * frame->stride(kY)); + const int uv_offset = region_in_frame.x() / 2 + + (region_in_frame.y() / 2 * uv_stride); + + ConvertRGB32ToYUV(source, + frame->data(kY) + y_offset, + frame->data(kU) + uv_offset, + frame->data(kV) + uv_offset, + region_in_frame.width(), + region_in_frame.height(), + stride, + frame->stride(kY), + uv_stride); +} +*/ +} // namespace mp4_demuxer diff --git a/content/media/fmp4/demuxer/video_util.h b/content/media/fmp4/demuxer/video_util.h new file mode 100644 index 000000000000..2c568788ee80 --- /dev/null +++ b/content/media/fmp4/demuxer/video_util.h @@ -0,0 +1,86 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_VIDEO_UTIL_H_ +#define MEDIA_BASE_VIDEO_UTIL_H_ + +#include "mp4_demuxer/basictypes.h" + +namespace mp4_demuxer { + +class VideoFrame; + +// Computes the size of |visible_size| for a given aspect ratio. +IntSize GetNaturalSize(const IntSize& visible_size, + int aspect_ratio_numerator, + int aspect_ratio_denominator); +/* +// Copies a plane of YUV(A) source into a VideoFrame object, taking into account +// source and destinations dimensions. +// +// NOTE: rows is *not* the same as height! +void CopyYPlane(const uint8_t* source, int stride, int rows, + VideoFrame* frame); +void CopyUPlane(const uint8_t* source, int stride, int rows, + VideoFrame* frame); +void CopyVPlane(const uint8_t* source, int stride, int rows, + VideoFrame* frame); +void CopyAPlane(const uint8_t* source, int stride, int rows, + VideoFrame* frame); + +// Sets alpha plane values to be completely opaque (all 255's). +void MakeOpaqueAPlane(int stride, int rows, VideoFrame* frame); + +// |plane| is one of VideoFrame::kYPlane, VideoFrame::kUPlane, +// VideoFrame::kVPlane or VideoFrame::kAPlane +void CopyPlane(size_t plane, const uint8_t* source, int stride, + int rows, VideoFrame* frame); + + +// Fills |frame| containing YUV data to the given color values. +void FillYUV(VideoFrame* frame, uint8_t y, uint8_t u, uint8_t v); + +// Creates a border in |frame| such that all pixels outside of +// |view_area| are black. The size and position of |view_area| +// must be even to align correctly with the color planes. +// Only YV12 format video frames are currently supported. +void LetterboxYUV(VideoFrame* frame, + const gfx::Rect& view_area); + +// Rotates |src| plane by |rotation| degree with possible flipping vertically +// and horizontally. +// |rotation| is limited to {0, 90, 180, 270}. +// |width| and |height| are expected to be even numbers. +// Both |src| and |dest| planes are packed and have same |width| and |height|. +// When |width| != |height| and rotated by 90/270, only the maximum square +// portion located in the center is rotated. For example, for width=640 and +// height=480, the rotated area is 480x480 located from row 0 through 479 and +// from column 80 through 559. The leftmost and rightmost 80 columns are +// ignored for both |src| and |dest|. +// The caller is responsible for blanking out the margin area. +void RotatePlaneByPixels( + const uint8_t* src, + uint8_t* dest, + int width, + int height, + int rotation, // Clockwise. + bool flip_vert, + bool flip_horiz); + +// Return the largest centered rectangle with the same aspect ratio of |content| +// that fits entirely inside of |bounds|. +gfx::Rect ComputeLetterboxRegion(const gfx::Rect& bounds, + const IntSize& content); + +// Copy an RGB bitmap into the specified |region_in_frame| of a YUV video frame. +// Fills the regions outside |region_in_frame| with black. +void CopyRGBToVideoFrame(const uint8_t* source, + int stride, + const gfx::Rect& region_in_frame, + VideoFrame* frame); +*/ + +} // namespace mp4_demuxer + +#endif // MEDIA_BASE_VIDEO_UTIL_H_ diff --git a/content/media/fmp4/moz.build b/content/media/fmp4/moz.build new file mode 100644 index 000000000000..8dfa81ba5d9f --- /dev/null +++ b/content/media/fmp4/moz.build @@ -0,0 +1,49 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +EXPORTS += [ +] + +EXPORTS.mp4_demuxer += [ + 'demuxer/aac.h', + 'demuxer/audio_decoder_config.h', + 'demuxer/avc.h', + 'demuxer/basictypes.h', + 'demuxer/bit_reader.h', + 'demuxer/box_definitions.h', + 'demuxer/box_reader.h', + 'demuxer/cenc.h', + 'demuxer/channel_layout.h', + 'demuxer/decrypt_config.h', + 'demuxer/es_descriptor.h', + 'demuxer/fourccs.h', + 'demuxer/mp4_demuxer.h', + 'demuxer/Streams.h', + 'demuxer/track_run_iterator.h', + 'demuxer/video_decoder_config.h', + 'demuxer/video_util.h' +] + +SOURCES += [ + 'demuxer/aac.cc', + 'demuxer/audio_decoder_config.cc', + 'demuxer/avc.cc', + 'demuxer/bit_reader.cc', + 'demuxer/box_definitions.cc', + 'demuxer/box_reader.cc', + 'demuxer/cenc.cc', + 'demuxer/channel_layout.cc', + 'demuxer/decrypt_config.cc', + 'demuxer/es_descriptor.cc', + 'demuxer/mp4_demuxer.cc', + 'demuxer/track_run_iterator.cc', + 'demuxer/video_decoder_config.cc', + 'demuxer/video_util.cc' +] + +FINAL_LIBRARY = 'gklayout' + +FAIL_ON_WARNINGS = True diff --git a/content/media/moz.build b/content/media/moz.build index 31bd33881f54..c0685af7cc9e 100644 --- a/content/media/moz.build +++ b/content/media/moz.build @@ -35,6 +35,9 @@ if CONFIG['MOZ_MEDIA_PLUGINS']: if CONFIG['MOZ_WMF']: PARALLEL_DIRS += ['wmf'] +if CONFIG['MOZ_FMP4']: + PARALLEL_DIRS += ['fmp4'] + if CONFIG['MOZ_APPLEMEDIA']: PARALLEL_DIRS += ['apple'] From b88e7b502918e40105829b2cfd2adf045ec55282 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 21 Nov 2013 10:04:33 +1300 Subject: [PATCH 150/268] Bug 886196 - MP4 demuxing using Chromium's MP4 demuxer. No decoding yet. r=kinetik --- content/media/fmp4/MP4Decoder.cpp | 78 ++++ content/media/fmp4/MP4Decoder.h | 41 ++ content/media/fmp4/MP4Reader.cpp | 393 +++++++++++++++++++ content/media/fmp4/MP4Reader.h | 88 +++++ content/media/fmp4/PlatformDecoderModule.cpp | 29 ++ content/media/fmp4/PlatformDecoderModule.h | 84 ++++ content/media/fmp4/demuxer/basictypes.h | 11 +- content/media/fmp4/moz.build | 10 +- 8 files changed, 731 insertions(+), 3 deletions(-) create mode 100644 content/media/fmp4/MP4Decoder.cpp create mode 100644 content/media/fmp4/MP4Decoder.h create mode 100644 content/media/fmp4/MP4Reader.cpp create mode 100644 content/media/fmp4/MP4Reader.h create mode 100644 content/media/fmp4/PlatformDecoderModule.cpp create mode 100644 content/media/fmp4/PlatformDecoderModule.h diff --git a/content/media/fmp4/MP4Decoder.cpp b/content/media/fmp4/MP4Decoder.cpp new file mode 100644 index 000000000000..72005edc21e2 --- /dev/null +++ b/content/media/fmp4/MP4Decoder.cpp @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "MP4Decoder.h" +#include "MP4Reader.h" +#include "MediaDecoderStateMachine.h" +#include "mozilla/Preferences.h" + +namespace mozilla { + +MediaDecoderStateMachine* MP4Decoder::CreateStateMachine() +{ + return new MediaDecoderStateMachine(this, new MP4Reader(this)); +} + +bool +MP4Decoder::GetSupportedCodecs(const nsACString& aType, + char const *const ** aCodecList) +{ + if (!IsEnabled()) { + return false; + } + + // AAC in M4A. + static char const *const aacAudioCodecs[] = { + "mp4a.40.2", // AAC-LC + // TODO: AAC-HE ? + nullptr + }; + if (aType.EqualsASCII("audio/mp4") || + aType.EqualsASCII("audio/x-m4a")) { + if (aCodecList) { + *aCodecList = aacAudioCodecs; + } + return true; + } + + // H.264 + AAC in MP4. + static char const *const h264Codecs[] = { + "avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0 + "avc1.42001E", // H.264 Baseline Profile Level 3.0 + "avc1.58A01E", // H.264 Extended Profile Level 3.0 + "avc1.4D401E", // H.264 Main Profile Level 3.0 + "avc1.64001E", // H.264 High Profile Level 3.0 + "avc1.64001F", // H.264 High Profile Level 3.1 + "mp4a.40.2", // AAC-LC + // TODO: There must be more profiles here? + nullptr + }; + if (aType.EqualsASCII("video/mp4")) { + if (aCodecList) { + *aCodecList = h264Codecs; + } + return true; + } + + return false; +} + +static bool +HavePlatformMPEGDecoders() +{ + return false; +} + +/* static */ +bool +MP4Decoder::IsEnabled() +{ + return HavePlatformMPEGDecoders() && + Preferences::GetBool("media.fragmented-mp4.enabled"); +} + +} // namespace mozilla + diff --git a/content/media/fmp4/MP4Decoder.h b/content/media/fmp4/MP4Decoder.h new file mode 100644 index 000000000000..323381f0b50b --- /dev/null +++ b/content/media/fmp4/MP4Decoder.h @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#if !defined(MP4Decoder_h_) +#define MP4Decoder_h_ + +#include "MediaDecoder.h" + +namespace mozilla { + +// Decoder that uses a bundled MP4 demuxer and platform decoders to play MP4. +class MP4Decoder : public MediaDecoder +{ +public: + + virtual MediaDecoder* Clone() { + if (!IsEnabled()) { + return nullptr; + } + return new MP4Decoder(); + } + + virtual MediaDecoderStateMachine* CreateStateMachine(); + + // Returns true if aType is a MIME type that we can render with the + // a MP4 platform decoder backend. If aCodecList is non null, + // it is filled with a (static const) null-terminated list of strings + // denoting the codecs we'll playback. + static bool GetSupportedCodecs(const nsACString& aType, + char const *const ** aCodecList); + + // Returns true if the MP4 backend is preffed on, and we're running on a + // platform that is likely to have decoders for the contained formats. + static bool IsEnabled(); +}; + +} // namespace mozilla + +#endif diff --git a/content/media/fmp4/MP4Reader.cpp b/content/media/fmp4/MP4Reader.cpp new file mode 100644 index 000000000000..0a3bf7948ed3 --- /dev/null +++ b/content/media/fmp4/MP4Reader.cpp @@ -0,0 +1,393 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "MP4Reader.h" +#include "MediaResource.h" +#include "mp4_demuxer/mp4_demuxer.h" +#include "mp4_demuxer/Streams.h" +#include "nsSize.h" +#include "VideoUtils.h" +#include "mozilla/dom/HTMLMediaElement.h" +#include "ImageContainer.h" +#include "Layers.h" + +using mozilla::layers::Image; +using mozilla::layers::LayerManager; +using mozilla::layers::LayersBackend; + +#ifdef PR_LOGGING +PRLogModuleInfo* GetDemuxerLog() { + static PRLogModuleInfo* log = nullptr; + if (!log) { + log = PR_NewLogModule("MP4Demuxer"); + } + return log; +} +#define LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__)) +#else +#define LOG(...) +#endif + +using namespace mp4_demuxer; + +namespace mozilla { + +// Uncomment to enable verbose per-sample logging. +//#define LOG_SAMPLE_DECODE 1 + +class MP4Stream : public mp4_demuxer::Stream { +public: + + MP4Stream(MediaResource* aResource) + : mResource(aResource) + { + MOZ_COUNT_CTOR(MP4Stream); + MOZ_ASSERT(aResource); + } + ~MP4Stream() { + MOZ_COUNT_DTOR(MP4Stream); + } + + virtual bool ReadAt(int64_t aOffset, + uint8_t* aBuffer, + uint32_t aCount, + uint32_t* aBytesRead) MOZ_OVERRIDE { + uint32_t sum = 0; + do { + uint32_t offset = aOffset + sum; + char* buffer = reinterpret_cast(aBuffer + sum); + uint32_t toRead = aCount - sum; + uint32_t bytesRead = 0; + nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead); + if (NS_FAILED(rv)) { + return false; + } + sum += bytesRead; + } while (sum < aCount); + *aBytesRead = sum; + return true; + } + + virtual int64_t Length() const MOZ_OVERRIDE { + return mResource->GetLength(); + } + +private: + RefPtr mResource; +}; + +MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder) + : MediaDecoderReader(aDecoder), + mLayersBackendType(layers::LAYERS_NONE), + mHasAudio(false), + mHasVideo(false) +{ + MOZ_COUNT_CTOR(MP4Reader); +} + +MP4Reader::~MP4Reader() +{ + MOZ_COUNT_DTOR(MP4Reader); +} + +nsresult +MP4Reader::Init(MediaDecoderReader* aCloneDonor) +{ + MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); + mMP4Stream = new MP4Stream(mDecoder->GetResource()); + mDemuxer = new MP4Demuxer(mMP4Stream); + + mPlatform = PlatformDecoderModule::Create(); + NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE); + + if (IsVideoContentType(mDecoder->GetResource()->GetContentType())) { + // Extract the layer manager backend type so that platform decoders + // can determine whether it's worthwhile using hardware accelerated + // video decoding. + MediaDecoderOwner* owner = mDecoder->GetOwner(); + NS_ENSURE_TRUE(owner, NS_ERROR_FAILURE); + + dom::HTMLMediaElement* element = owner->GetMediaElement(); + NS_ENSURE_TRUE(element, NS_ERROR_FAILURE); + + nsRefPtr layerManager = + nsContentUtils::LayerManagerForDocument(element->OwnerDoc()); + NS_ENSURE_TRUE(layerManager, NS_ERROR_FAILURE); + + mLayersBackendType = layerManager->GetBackendType(); + } + + return NS_OK; +} + +nsresult +MP4Reader::ReadMetadata(MediaInfo* aInfo, + MetadataTags** aTags) +{ + bool ok = mDemuxer->Init(); + NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); + + mInfo.mAudio.mHasAudio = mHasAudio = mDemuxer->HasAudio(); + if (mHasAudio) { + const AudioDecoderConfig& config = mDemuxer->AudioConfig(); + mInfo.mAudio.mRate = config.samples_per_second(); + mInfo.mAudio.mChannels = ChannelLayoutToChannelCount(config.channel_layout()); + mAudioDecoder = mPlatform->CreateAudioDecoder(mInfo.mAudio.mChannels, + mInfo.mAudio.mRate, + config.bits_per_channel(), + config.extra_data(), + config.extra_data_size()); + NS_ENSURE_TRUE(mAudioDecoder != nullptr, NS_ERROR_FAILURE); + } + + mInfo.mVideo.mHasVideo = mHasVideo = mDemuxer->HasVideo(); + if (mHasVideo) { + const VideoDecoderConfig& config = mDemuxer->VideoConfig(); + IntSize sz = config.natural_size(); + mInfo.mVideo.mDisplay = nsIntSize(sz.width(), sz.height()); + + mVideoDecoder = mPlatform->CreateVideoDecoder(mLayersBackendType, + mDecoder->GetImageContainer()); + NS_ENSURE_TRUE(mVideoDecoder != nullptr, NS_ERROR_FAILURE); + } + + // Get the duration, and report it to the decoder if we have it. + Microseconds duration = mDemuxer->Duration(); + if (duration != -1) { + ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); + mDecoder->SetMediaDuration(duration); + } + // We can seek if we get a duration *and* the reader reports that it's + // seekable. + if (!mDemuxer->CanSeek()) { + mDecoder->SetMediaSeekable(false); + } + + *aInfo = mInfo; + *aTags = nullptr; + + return NS_OK; +} + +bool +MP4Reader::HasAudio() +{ + return mHasAudio; +} + +bool +MP4Reader::HasVideo() +{ + return mHasVideo; +} + +MP4SampleQueue& +MP4Reader::SampleQueue(TrackType aTrack) +{ + MOZ_ASSERT(aTrack == kAudio || aTrack == kVideo); + return (aTrack == kAudio) ? mCompressedAudioQueue + : mCompressedVideoQueue; +} + +MediaDataDecoder* +MP4Reader::Decoder(mp4_demuxer::TrackType aTrack) +{ + MOZ_ASSERT(aTrack == kAudio || aTrack == kVideo); + return (aTrack == kAudio) ? mAudioDecoder + : mVideoDecoder; +} + +MP4Sample* +MP4Reader::PopSample(TrackType aTrack) +{ + // Unfortunately the demuxer outputs in the order samples appear in the + // media, not on a per stream basis. We cache the samples we get from + // streams other than the one we want. + MP4SampleQueue& sampleQueue = SampleQueue(aTrack); + while (sampleQueue.empty()) { + nsAutoPtr sample; + bool eos = false; + bool ok = mDemuxer->Demux(&sample, &eos); + if (!ok || eos) { + MOZ_ASSERT(!sample); + return nullptr; + } + MOZ_ASSERT(sample); + MP4Sample* s = sample.forget(); + SampleQueue(s->type).push_back(s); + } + MOZ_ASSERT(!sampleQueue.empty()); + MP4Sample* sample = sampleQueue.front(); + sampleQueue.pop_front(); + return sample; +} + +bool +MP4Reader::Decode(TrackType aTrack, nsAutoPtr& aOutData) +{ + MP4SampleQueue& sampleQueue = SampleQueue(aTrack); + MediaDataDecoder* decoder = Decoder(aTrack); + + MOZ_ASSERT(decoder); + + // Loop until we hit a return condition; we produce samples, or hit an error. + while (true) { + DecoderStatus status = decoder->Output(aOutData); + if (status == DECODE_STATUS_OK) { + MOZ_ASSERT(aOutData); + return true; + } + // |aOutData| should only be non-null in success case. + MOZ_ASSERT(!aOutData); + + if (status == DECODE_STATUS_ERROR) { + return false; + } + + if (status == DECODE_STATUS_NEED_MORE_INPUT) { + // We need to push more data from the demuxer into the decoder. + // Now loop back and try to extract output again. + nsAutoPtr compressed; + do { + compressed = PopSample(aTrack); + if (!compressed) { + // EOS, or error. Let the state machine know there are no more + // frames coming. + return false; + } + const std::vector* data = compressed->data; + status = decoder->Input(&data->front(), + data->size(), + compressed->decode_timestamp, + compressed->composition_timestamp, + compressed->byte_offset); + } while (status == DECODE_STATUS_OK); + if (status == DECODE_STATUS_NOT_ACCEPTING) { + // Decoder should now be able to produce an output. + SampleQueue(aTrack).push_front(compressed.forget()); + continue; + } + LOG("MP4Reader decode failure. track=%d status=%d\n", aTrack, status); + return false; + } else { + LOG("MP4Reader unexpected error. track=%d status=%d\n", aTrack, status); + return false; + } + } +} + +bool +MP4Reader::DecodeAudioData() +{ + MOZ_ASSERT(mHasAudio && mPlatform && mAudioDecoder); + nsAutoPtr audio; + bool ok = Decode(kAudio, audio); + if (ok && audio && audio->mType == MediaData::AUDIO_SAMPLES) { +#ifdef LOG_SAMPLE_DECODE + LOG("DecodeAudioData time=%lld dur=%lld", audio->mTime, audio->mDuration); +#endif + mAudioQueue.Push(static_cast(audio.forget())); + } + return ok; +} + +bool +MP4Reader::SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed) +{ + MOZ_ASSERT(mVideoDecoder); + + // Purge the current decoder's state. + mVideoDecoder->Flush(); + + // Loop until we reach the next keyframe after the threshold. + while (true) { + nsAutoPtr compressed(PopSample(kVideo)); + if (!compressed) { + // EOS, or error. Let the state machine know. + return false; + } + parsed++; + if (!compressed->is_sync_point || + compressed->composition_timestamp < aTimeThreshold) { + continue; + } + mCompressedVideoQueue.push_front(compressed.forget()); + break; + } + + return true; +} + +bool +MP4Reader::DecodeVideoFrame(bool &aKeyframeSkip, + int64_t aTimeThreshold) +{ + // Record number of frames decoded and parsed. Automatically update the + // stats counters using the AutoNotifyDecoded stack-based class. + uint32_t parsed = 0, decoded = 0; + AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); + + MOZ_ASSERT(mHasVideo && mPlatform && mVideoDecoder); + + if (aKeyframeSkip) { + bool ok = SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed); + if (!ok) { + NS_WARNING("Failed to skip demux up to next keyframe"); + return false; + } + aKeyframeSkip = false; + } + + nsAutoPtr data; + bool ok = Decode(kVideo, data); + MOZ_ASSERT(!data || data->mType == MediaData::VIDEO_FRAME); + if (ok && data) { + parsed++; + if (data->mTime < aTimeThreshold) { + // Skip frame, it's too late to be displayed. + return true; + } + decoded++; + VideoData* video = static_cast(data.forget()); +#ifdef LOG_SAMPLE_DECODE + LOG("DecodeVideoData time=%lld dur=%lld", video->mTime, video->mDuration); +#endif + mVideoQueue.Push(video); + } + return ok; +} + +nsresult +MP4Reader::Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) +{ + if (!mDemuxer->CanSeek()) { + return NS_ERROR_FAILURE; + } + return NS_ERROR_NOT_IMPLEMENTED; +} + +void +MP4Reader::OnDecodeThreadStart() +{ + MOZ_ASSERT(!NS_IsMainThread(), "Must not be on main thread."); + MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); + MOZ_ASSERT(mPlatform); + mPlatform->OnDecodeThreadStart(); +} + +void +MP4Reader::OnDecodeThreadFinish() +{ + MOZ_ASSERT(!NS_IsMainThread(), "Must not be on main thread."); + MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread."); + MOZ_ASSERT(mPlatform); + mPlatform->OnDecodeThreadFinish(); +} + +} // namespace mozilla diff --git a/content/media/fmp4/MP4Reader.h b/content/media/fmp4/MP4Reader.h new file mode 100644 index 000000000000..d7d1e23597c8 --- /dev/null +++ b/content/media/fmp4/MP4Reader.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if !defined(MP4Reader_h_) +#define MP4Reader_h_ + +#include "MediaDecoderReader.h" +#include "nsAutoPtr.h" +#include "PlatformDecoderModule.h" +#include "mp4_demuxer/mp4_demuxer.h" +#include "mp4_demuxer/box_definitions.h" + +#include + +namespace mozilla { + +namespace dom { +class TimeRanges; +} + +typedef std::deque MP4SampleQueue; + +class MP4Stream; + +class MP4Reader : public MediaDecoderReader +{ +public: + MP4Reader(AbstractMediaDecoder* aDecoder); + + virtual ~MP4Reader(); + + virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE; + + virtual bool DecodeAudioData() MOZ_OVERRIDE; + virtual bool DecodeVideoFrame(bool &aKeyframeSkip, + int64_t aTimeThreshold) MOZ_OVERRIDE; + + virtual bool HasAudio() MOZ_OVERRIDE; + virtual bool HasVideo() MOZ_OVERRIDE; + + virtual nsresult ReadMetadata(MediaInfo* aInfo, + MetadataTags** aTags) MOZ_OVERRIDE; + + virtual nsresult Seek(int64_t aTime, + int64_t aStartTime, + int64_t aEndTime, + int64_t aCurrentTime) MOZ_OVERRIDE; + + virtual void OnDecodeThreadStart() MOZ_OVERRIDE; + virtual void OnDecodeThreadFinish() MOZ_OVERRIDE; + +private: + + MP4SampleQueue& SampleQueue(mp4_demuxer::TrackType aTrack); + + // Blocks until the demuxer produces an sample of specified type. + // Returns nullptr on error on EOS. Caller must delete sample. + mp4_demuxer::MP4Sample* PopSample(mp4_demuxer::TrackType aTrack); + + bool Decode(mp4_demuxer::TrackType aTrack, + nsAutoPtr& aOutData); + + MediaDataDecoder* Decoder(mp4_demuxer::TrackType aTrack); + + bool SkipVideoDemuxToNextKeyFrame(int64_t aTimeThreshold, uint32_t& parsed); + + nsAutoPtr mDemuxer; + nsAutoPtr mMP4Stream; + nsAutoPtr mPlatform; + nsAutoPtr mVideoDecoder; + nsAutoPtr mAudioDecoder; + + MP4SampleQueue mCompressedAudioQueue; + MP4SampleQueue mCompressedVideoQueue; + + layers::LayersBackend mLayersBackendType; + + bool mHasAudio; + bool mHasVideo; + +}; + +} // namespace mozilla + +#endif diff --git a/content/media/fmp4/PlatformDecoderModule.cpp b/content/media/fmp4/PlatformDecoderModule.cpp new file mode 100644 index 000000000000..928eb49b2240 --- /dev/null +++ b/content/media/fmp4/PlatformDecoderModule.cpp @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "PlatformDecoderModule.h" + +namespace mozilla { + +/* static */ +PlatformDecoderModule* +PlatformDecoderModule::Create() +{ + // TODO: Create appropriate PlatformDecoderModule... + return nullptr; +} + +void +PlatformDecoderModule::OnDecodeThreadStart() +{ +} + +void +PlatformDecoderModule::OnDecodeThreadFinish() +{ +} + +} // namespace mozilla diff --git a/content/media/fmp4/PlatformDecoderModule.h b/content/media/fmp4/PlatformDecoderModule.h new file mode 100644 index 000000000000..182c3ce3ebb0 --- /dev/null +++ b/content/media/fmp4/PlatformDecoderModule.h @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if !defined(PlatformDecoderModule_h_) +#define PlatformDecoderModule_h_ + +#include "MediaDecoderReader.h" +#include "mozilla/layers/LayersTypes.h" + +namespace mozilla { + +namespace layers { +class ImageContainer; +} + +typedef int64_t Microseconds; + +enum DecoderStatus { + DECODE_STATUS_NOT_ACCEPTING, // Can't accept input at this time. + DECODE_STATUS_NEED_MORE_INPUT, // Nothing in pipeline to produce output with at this time. + DECODE_STATUS_OK, + DECODE_STATUS_ERROR +}; + +class MediaDataDecoder { +public: + virtual ~MediaDataDecoder() {}; + + virtual nsresult Shutdown() = 0; + + // Returns true if future decodes may produce output, or false + // on end of segment. + // Inserts data into the decoder's pipeline. + virtual DecoderStatus Input(const uint8_t* aData, + uint32_t aLength, + Microseconds aDTS, + Microseconds aPTS, + int64_t aOffsetInStream) = 0; + + // Blocks until decoded sample is produced by the deoder. + virtual DecoderStatus Output(nsAutoPtr& aOutData) = 0; + + virtual DecoderStatus Flush() = 0; +}; + +class PlatformDecoderModule { +public: + + // Creates the appropriate PlatformDecoderModule for this platform. + // Caller is responsible for deleting this instance. It's safe to have + // multiple PlatformDecoderModules alive at the same time. + // There is one PlatformDecoderModule's created per media decoder. + static PlatformDecoderModule* Create(); + + // Called when the decoders have shutdown. Main thread only. + virtual nsresult Shutdown() = 0; + + // TODO: Parameters for codec type. + // Decode thread. + virtual MediaDataDecoder* CreateVideoDecoder(layers::LayersBackend aLayersBackend, + layers::ImageContainer* aImageContainer) = 0; + + // Decode thread. + virtual MediaDataDecoder* CreateAudioDecoder(uint32_t aChannelCount, + uint32_t aSampleRate, + uint16_t aBitsPerSample, + const uint8_t* aUserData, + uint32_t aUserDataLength) = 0; + + // Platform decoders can override these. Base implementation does nothing. + virtual void OnDecodeThreadStart(); + virtual void OnDecodeThreadFinish(); + + virtual ~PlatformDecoderModule() {} +protected: + PlatformDecoderModule() {} +}; + +} // namespace mozilla + +#endif diff --git a/content/media/fmp4/demuxer/basictypes.h b/content/media/fmp4/demuxer/basictypes.h index ad77f0a9dc3a..00b463507bc4 100644 --- a/content/media/fmp4/demuxer/basictypes.h +++ b/content/media/fmp4/demuxer/basictypes.h @@ -7,6 +7,11 @@ #include #include +#include "prlog.h" + +#ifdef PR_LOGGING +PRLogModuleInfo* GetDemuxerLog(); +#endif namespace mp4_demuxer { @@ -52,7 +57,11 @@ namespace mp4_demuxer { #define arraysize(f) (sizeof(f) / sizeof(*f)) #ifdef LOG_DEMUXER -#define DMX_LOG(...) printf(__VA_ARGS__) +#ifdef PR_LOGGING +#define DMX_LOG(...) PR_LOG(GetDemuxerLog(), PR_LOG_DEBUG, (__VA_ARGS__)) +#else +#define DMX_LOG(...) 0 +#endif #else // define DMX_LOG as 0, so that if(condition){DMX_LOG(...)} branches don't elicit // a warning-as-error. diff --git a/content/media/fmp4/moz.build b/content/media/fmp4/moz.build index 8dfa81ba5d9f..012d5de46aa5 100644 --- a/content/media/fmp4/moz.build +++ b/content/media/fmp4/moz.build @@ -5,6 +5,9 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. EXPORTS += [ + 'MP4Decoder.h', + 'MP4Reader.h', + 'PlatformDecoderModule.h', ] EXPORTS.mp4_demuxer += [ @@ -24,7 +27,7 @@ EXPORTS.mp4_demuxer += [ 'demuxer/Streams.h', 'demuxer/track_run_iterator.h', 'demuxer/video_decoder_config.h', - 'demuxer/video_util.h' + 'demuxer/video_util.h', ] SOURCES += [ @@ -41,7 +44,10 @@ SOURCES += [ 'demuxer/mp4_demuxer.cc', 'demuxer/track_run_iterator.cc', 'demuxer/video_decoder_config.cc', - 'demuxer/video_util.cc' + 'demuxer/video_util.cc', + 'MP4Decoder.cpp', + 'MP4Reader.cpp', + 'PlatformDecoderModule.cpp', ] FINAL_LIBRARY = 'gklayout' From 2547f6703fa3c3c4a4815b4e3b15f0eb030d9519 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 21 Nov 2013 10:04:33 +1300 Subject: [PATCH 151/268] Bug 886196 - Add pref to enable creation of fmp4 reader in DecoderTraits. Preffed of by default. r=kinetik --- content/media/DecoderTraits.cpp | 53 +++++++++++++++++++++++++++++++-- modules/libpref/src/init/all.js | 4 +++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/content/media/DecoderTraits.cpp b/content/media/DecoderTraits.cpp index ec1622f31f7b..44fe3ff6bee0 100644 --- a/content/media/DecoderTraits.cpp +++ b/content/media/DecoderTraits.cpp @@ -61,6 +61,10 @@ #include "AppleDecoder.h" #include "AppleMP3Reader.h" #endif +#ifdef MOZ_FMP4 +#include "MP4Reader.h" +#include "MP4Decoder.h" +#endif namespace mozilla { @@ -298,6 +302,15 @@ IsDirectShowSupportedType(const nsACString& aType) } #endif +#ifdef MOZ_FMP4 +static bool +IsMP4SupportedType(const nsACString& aType) +{ + return Preferences::GetBool("media.fragmented-mp4.exposed", false) && + MP4Decoder::GetSupportedCodecs(aType, nullptr); +} +#endif + #ifdef MOZ_APPLEMEDIA static const char * const gAppleMP3Types[] = { "audio/mp3", @@ -445,30 +458,35 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType, return CANPLAY_YES; } -/* static */ +// Instantiates but does not initialize decoder. +static already_AddRefed -DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner) +InstantiateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner) { nsRefPtr decoder; #ifdef MOZ_GSTREAMER if (IsGStreamerSupportedType(aType)) { decoder = new GStreamerDecoder(); + return decoder.forget(); } #endif #ifdef MOZ_RAW if (IsRawType(aType)) { decoder = new RawDecoder(); + return decoder.forget(); } #endif #ifdef MOZ_OGG if (IsOggType(aType)) { decoder = new OggDecoder(); + return decoder.forget(); } #endif #ifdef MOZ_WAVE if (IsWaveType(aType)) { decoder = new WaveDecoder(); + return decoder.forget(); } #endif #ifdef MOZ_OMX_DECODER @@ -489,22 +507,26 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner) } } decoder = new MediaOmxDecoder(); + return decoder.forget(); } #endif #ifdef NECKO_PROTOCOL_rtsp if (IsRtspSupportedType(aType)) { decoder = new RtspOmxDecoder(); + return decoder.forget(); } #endif #ifdef MOZ_MEDIA_PLUGINS if (MediaDecoder::IsMediaPluginsEnabled() && GetMediaPluginHost()->FindDecoder(aType, nullptr)) { decoder = new MediaPluginDecoder(aType); + return decoder.forget(); } #endif #ifdef MOZ_WEBM if (IsWebMType(aType)) { decoder = new WebMDecoder(); + return decoder.forget(); } #endif #ifdef MOZ_DIRECTSHOW @@ -512,21 +534,40 @@ DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner) // "media.directshow.preferred" won't be honored. if (IsDirectShowSupportedType(aType)) { decoder = new DirectShowDecoder(); + return decoder.forget(); + } +#endif +#ifdef MOZ_FMP4 + if (IsMP4SupportedType(aType)) { + decoder = new MP4Decoder(); + return decoder.forget(); } #endif #ifdef MOZ_WMF if (IsWMFSupportedType(aType)) { decoder = new WMFDecoder(); + return decoder.forget(); } #endif #ifdef MOZ_APPLEMEDIA if (IsAppleMediaSupportedType(aType)) { decoder = new AppleDecoder(); + return decoder.forget(); } #endif NS_ENSURE_TRUE(decoder != nullptr, nullptr); NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr); + return nullptr; +} + +/* static */ +already_AddRefed +DecoderTraits::CreateDecoder(const nsACString& aType, MediaDecoderOwner* aOwner) +{ + nsRefPtr decoder(InstantiateDecoder(aType, aOwner)); + NS_ENSURE_TRUE(decoder != nullptr, nullptr); + NS_ENSURE_TRUE(decoder->Init(aOwner), nullptr); return decoder.forget(); } @@ -579,6 +620,11 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac decoderReader = new DirectShowReader(aDecoder); } else #endif +#ifdef MOZ_FMP4 + if (IsMP4SupportedType(aType)) { + decoderReader = new MP4Reader(aDecoder); + } else +#endif #ifdef MOZ_WMF if (IsWMFSupportedType(aType)) { decoderReader = new WMFReader(aDecoder); @@ -615,6 +661,9 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType) #ifdef MOZ_MEDIA_PLUGINS (MediaDecoder::IsMediaPluginsEnabled() && IsMediaPluginsType(aType)) || #endif +#ifdef MOZ_FMP4 + IsMP4SupportedType(aType) || +#endif #ifdef MOZ_WMF (IsWMFSupportedType(aType) && Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true)) || diff --git a/modules/libpref/src/init/all.js b/modules/libpref/src/init/all.js index d2a49fc5df4b..449557e2f735 100644 --- a/modules/libpref/src/init/all.js +++ b/modules/libpref/src/init/all.js @@ -198,6 +198,10 @@ pref("media.directshow.enabled", true); #endif #ifdef MOZ_FMP4 pref("media.fragmented-mp4.enabled", true); +// Denotes that the fragmented MP4 parser can be created by