--- a/parser/html/moz.build
+++ b/parser/html/moz.build
@@ -30,21 +30,21 @@ EXPORTS += [
'nsHtml5Module.h',
'nsHtml5NamedCharacters.h',
'nsHtml5NamedCharactersAccel.h',
'nsHtml5OplessBuilder.h',
'nsHtml5OwningUTF16Buffer.h',
'nsHtml5Parser.h',
'nsHtml5PlainTextUtils.h',
'nsHtml5Portability.h',
- 'nsHtml5RefPtr.h',
'nsHtml5Speculation.h',
'nsHtml5SpeculativeLoad.h',
'nsHtml5StreamListener.h',
'nsHtml5StreamParser.h',
+ 'nsHtml5StreamParserPtr.h',
'nsHtml5String.h',
'nsHtml5StringParser.h',
'nsHtml5SVGLoadDispatcher.h',
'nsHtml5TreeOperation.h',
'nsHtml5TreeOpExecutor.h',
'nsHtml5TreeOpStage.h',
'nsHtml5UTF16Buffer.h',
'nsHtml5UTF16BufferHSupplement.h',
deleted file mode 100644
--- a/parser/html/nsHtml5RefPtr.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef nsHtml5RefPtr_h
-#define nsHtml5RefPtr_h
-
-#include "nsThreadUtils.h"
-
-template <class T>
-class nsHtml5RefPtrReleaser : public mozilla::Runnable
- {
- private:
- T* mPtr;
- public:
- explicit nsHtml5RefPtrReleaser(T* aPtr)
- : mozilla::Runnable("nsHtml5RefPtrReleaser")
- , mPtr(aPtr)
- {}
- NS_IMETHOD Run() override
- {
- mPtr->Release();
- return NS_OK;
- }
- };
-
-// template <class T> class nsHtml5RefPtrGetterAddRefs;
-
-/**
- * Like nsRefPtr except release is proxied to the main thread. Mostly copied
- * from nsRefPtr.
- */
-template <class T>
-class nsHtml5RefPtr
- {
- private:
-
- void
- assign_with_AddRef( T* rawPtr )
- {
- if ( rawPtr )
- rawPtr->AddRef();
- assign_assuming_AddRef(rawPtr);
- }
-
- void**
- begin_assignment()
- {
- assign_assuming_AddRef(0);
- return reinterpret_cast<void**>(&mRawPtr);
- }
-
- void
- assign_assuming_AddRef( T* newPtr )
- {
- T* oldPtr = mRawPtr;
- mRawPtr = newPtr;
- if ( oldPtr )
- release(oldPtr);
- }
-
- void
- release( T* aPtr )
- {
- nsCOMPtr<nsIRunnable> releaser = new nsHtml5RefPtrReleaser<T>(aPtr);
- if (NS_FAILED(NS_DispatchToMainThread(releaser)))
- {
- NS_WARNING("Failed to dispatch releaser event.");
- }
- }
-
- private:
- T* mRawPtr;
-
- public:
- typedef T element_type;
-
- ~nsHtml5RefPtr()
- {
- if ( mRawPtr )
- release(mRawPtr);
- }
-
- // Constructors
-
- nsHtml5RefPtr()
- : mRawPtr(0)
- // default constructor
- {
- }
-
- nsHtml5RefPtr( const nsHtml5RefPtr<T>& aSmartPtr )
- : mRawPtr(aSmartPtr.mRawPtr)
- // copy-constructor
- {
- if ( mRawPtr )
- mRawPtr->AddRef();
- }
-
- explicit nsHtml5RefPtr( T* aRawPtr )
- : mRawPtr(aRawPtr)
- // construct from a raw pointer (of the right type)
- {
- if ( mRawPtr )
- mRawPtr->AddRef();
- }
-
- explicit nsHtml5RefPtr( const already_AddRefed<T>& aSmartPtr )
- : mRawPtr(aSmartPtr.mRawPtr)
- // construct from |dont_AddRef(expr)|
- {
- }
-
- // Assignment operators
-
- nsHtml5RefPtr<T>&
- operator=( const nsHtml5RefPtr<T>& rhs )
- // copy assignment operator
- {
- assign_with_AddRef(rhs.mRawPtr);
- return *this;
- }
-
- nsHtml5RefPtr<T>&
- operator=( T* rhs )
- // assign from a raw pointer (of the right type)
- {
- assign_with_AddRef(rhs);
- return *this;
- }
-
- nsHtml5RefPtr<T>&
- operator=( const already_AddRefed<T>& rhs )
- // assign from |dont_AddRef(expr)|
- {
- assign_assuming_AddRef(rhs.mRawPtr);
- return *this;
- }
-
- // Other pointer operators
-
- void
- swap( nsHtml5RefPtr<T>& rhs )
- // ...exchange ownership with |rhs|; can save a pair of refcount operations
- {
- T* temp = rhs.mRawPtr;
- rhs.mRawPtr = mRawPtr;
- mRawPtr = temp;
- }
-
- void
- swap( T*& rhs )
- // ...exchange ownership with |rhs|; can save a pair of refcount operations
- {
- T* temp = rhs;
- rhs = mRawPtr;
- mRawPtr = temp;
- }
-
- already_AddRefed<T>
- forget()
- // return the value of mRawPtr and null out mRawPtr. Useful for
- // already_AddRefed return values.
- {
- T* temp = 0;
- swap(temp);
- return temp;
- }
-
- template <typename I>
- void
- forget( I** rhs)
- // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
- // Useful to avoid unnecessary AddRef/Release pairs with "out"
- // parameters where rhs bay be a T** or an I** where I is a base class
- // of T.
- {
- NS_ASSERTION(rhs, "Null pointer passed to forget!");
- *rhs = mRawPtr;
- mRawPtr = 0;
- }
-
- T*
- get() const
- /*
- Prefer the implicit conversion provided automatically by |operator T*() const|.
- Use |get()| to resolve ambiguity or to get a castable pointer.
- */
- {
- return const_cast<T*>(mRawPtr);
- }
-
- operator T*() const
- /*
- ...makes an |nsHtml5RefPtr| act like its underlying raw pointer type whenever it
- is used in a context where a raw pointer is expected. It is this operator
- that makes an |nsHtml5RefPtr| substitutable for a raw pointer.
-
- Prefer the implicit use of this operator to calling |get()|, except where
- necessary to resolve ambiguity.
- */
- {
- return get();
- }
-
- T*
- operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
- {
- NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator->().");
- return get();
- }
-
- nsHtml5RefPtr<T>*
- get_address()
- // This is not intended to be used by clients. See |address_of|
- // below.
- {
- return this;
- }
-
- const nsHtml5RefPtr<T>*
- get_address() const
- // This is not intended to be used by clients. See |address_of|
- // below.
- {
- return this;
- }
-
- public:
- T&
- operator*() const
- {
- NS_PRECONDITION(mRawPtr != 0, "You can't dereference a NULL nsHtml5RefPtr with operator*().");
- return *get();
- }
-
- T**
- StartAssignment()
- {
-#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
- return reinterpret_cast<T**>(begin_assignment());
-#else
- assign_assuming_AddRef(0);
- return reinterpret_cast<T**>(&mRawPtr);
-#endif
- }
- };
-
-template <class T>
-inline
-nsHtml5RefPtr<T>*
-address_of( nsHtml5RefPtr<T>& aPtr )
- {
- return aPtr.get_address();
- }
-
-template <class T>
-inline
-const nsHtml5RefPtr<T>*
-address_of( const nsHtml5RefPtr<T>& aPtr )
- {
- return aPtr.get_address();
- }
-
-template <class T>
-class nsHtml5RefPtrGetterAddRefs
- /*
- ...
-
- This class is designed to be used for anonymous temporary objects in the
- argument list of calls that return COM interface pointers, e.g.,
-
- nsHtml5RefPtr<IFoo> fooP;
- ...->GetAddRefedPointer(getter_AddRefs(fooP))
-
- DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
-
- When initialized with a |nsHtml5RefPtr|, as in the example above, it returns
- a |void**|, a |T**|, or an |nsISupports**| as needed, that the
- outer call (|GetAddRefedPointer| in this case) can fill in.
-
- This type should be a nested class inside |nsHtml5RefPtr<T>|.
- */
- {
- public:
- explicit
- nsHtml5RefPtrGetterAddRefs( nsHtml5RefPtr<T>& aSmartPtr )
- : mTargetSmartPtr(aSmartPtr)
- {
- // nothing else to do
- }
-
- operator void**()
- {
- return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
- }
-
- operator T**()
- {
- return mTargetSmartPtr.StartAssignment();
- }
-
- T*&
- operator*()
- {
- return *(mTargetSmartPtr.StartAssignment());
- }
-
- private:
- nsHtml5RefPtr<T>& mTargetSmartPtr;
- };
-
-template <class T>
-inline
-nsHtml5RefPtrGetterAddRefs<T>
-getter_AddRefs( nsHtml5RefPtr<T>& aSmartPtr )
- /*
- Used around a |nsHtml5RefPtr| when
- ...makes the class |nsHtml5RefPtrGetterAddRefs<T>| invisible.
- */
- {
- return nsHtml5RefPtrGetterAddRefs<T>(aSmartPtr);
- }
-
-
-
- // Comparing two |nsHtml5RefPtr|s
-
-template <class T, class U>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, const nsHtml5RefPtr<U>& rhs )
- {
- return static_cast<const T*>(lhs.get()) == static_cast<const U*>(rhs.get());
- }
-
-
-template <class T, class U>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, const nsHtml5RefPtr<U>& rhs )
- {
- return static_cast<const T*>(lhs.get()) != static_cast<const U*>(rhs.get());
- }
-
-
- // Comparing an |nsHtml5RefPtr| to a raw pointer
-
-template <class T, class U>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, const U* rhs )
- {
- return static_cast<const T*>(lhs.get()) == static_cast<const U*>(rhs);
- }
-
-template <class T, class U>
-inline
-bool
-operator==( const U* lhs, const nsHtml5RefPtr<T>& rhs )
- {
- return static_cast<const U*>(lhs) == static_cast<const T*>(rhs.get());
- }
-
-template <class T, class U>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, const U* rhs )
- {
- return static_cast<const T*>(lhs.get()) != static_cast<const U*>(rhs);
- }
-
-template <class T, class U>
-inline
-bool
-operator!=( const U* lhs, const nsHtml5RefPtr<T>& rhs )
- {
- return static_cast<const U*>(lhs) != static_cast<const T*>(rhs.get());
- }
-
-template <class T, class U>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, U* rhs )
- {
- return static_cast<const T*>(lhs.get()) == const_cast<const U*>(rhs);
- }
-
-template <class T, class U>
-inline
-bool
-operator==( U* lhs, const nsHtml5RefPtr<T>& rhs )
- {
- return const_cast<const U*>(lhs) == static_cast<const T*>(rhs.get());
- }
-
-template <class T, class U>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, U* rhs )
- {
- return static_cast<const T*>(lhs.get()) != const_cast<const U*>(rhs);
- }
-
-template <class T, class U>
-inline
-bool
-operator!=( U* lhs, const nsHtml5RefPtr<T>& rhs )
- {
- return const_cast<const U*>(lhs) != static_cast<const T*>(rhs.get());
- }
-
-
-
- // Comparing an |nsHtml5RefPtr| to |0|
-
-template <class T>
-inline
-bool
-operator==( const nsHtml5RefPtr<T>& lhs, decltype(nullptr) )
- {
- return lhs.get() == nullptr;
- }
-
-template <class T>
-inline
-bool
-operator==( decltype(nullptr), const nsHtml5RefPtr<T>& rhs )
- {
- return nullptr == rhs.get();
- }
-
-template <class T>
-inline
-bool
-operator!=( const nsHtml5RefPtr<T>& lhs, decltype(nullptr) )
- {
- return lhs.get() != nullptr;
- }
-
-template <class T>
-inline
-bool
-operator!=( decltype(nullptr), const nsHtml5RefPtr<T>& rhs )
- {
- return nullptr != rhs.get();
- }
-
-#endif // !defined(nsHtml5RefPtr_h)
--- a/parser/html/nsHtml5StreamListener.h
+++ b/parser/html/nsHtml5StreamListener.h
@@ -2,35 +2,35 @@
* 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 nsHtml5StreamListener_h
#define nsHtml5StreamListener_h
#include "nsIStreamListener.h"
#include "nsIThreadRetargetableStreamListener.h"
-#include "nsHtml5RefPtr.h"
+#include "nsHtml5StreamParserPtr.h"
#include "nsHtml5StreamParser.h"
/**
* The purpose of this class is to reconcile the problem that
* nsHtml5StreamParser is a cycle collection participant, which means that it
* can only be refcounted on the main thread, but
* nsIThreadRetargetableStreamListener can be refcounted from another thread,
* so nsHtml5StreamParser being an nsIThreadRetargetableStreamListener was
* a memory corruption problem.
*
- * mDelegate is an nsHtml5RefPtr, which releases the object that it points
+ * mDelegate is an nsHtml5StreamParserPtr, which releases the object that it points
* to from a runnable on the main thread. DropDelegate() is only called on
* the main thread. This call will finish before the main-thread derefs the
* nsHtml5StreamListener itself, so there is no risk of another thread making
* the refcount of nsHtml5StreamListener go to zero and running the destructor
* concurrently. Other than that, the thread-safe nsISupports implementation
* takes care of the destructor not running concurrently from different
- * threads, so there is no need to have a mutex around nsHtml5RefPtr to
+ * threads, so there is no need to have a mutex around nsHtml5StreamParserPtr to
* prevent it from double-releasing nsHtml5StreamParser.
*/
class nsHtml5StreamListener : public nsIStreamListener,
public nsIThreadRetargetableStreamListener
{
public:
explicit nsHtml5StreamListener(nsHtml5StreamParser* aDelegate);
@@ -44,12 +44,12 @@ public:
return mDelegate;
}
void DropDelegate();
private:
virtual ~nsHtml5StreamListener();
- nsHtml5RefPtr<nsHtml5StreamParser> mDelegate;
+ nsHtml5StreamParserPtr mDelegate;
};
#endif // nsHtml5StreamListener_h
--- a/parser/html/nsHtml5StreamParser.cpp
+++ b/parser/html/nsHtml5StreamParser.cpp
@@ -10,30 +10,31 @@
#include "mozilla/Encoding.h"
#include "nsContentUtils.h"
#include "nsHtml5Tokenizer.h"
#include "nsIHttpChannel.h"
#include "nsHtml5Parser.h"
#include "nsHtml5TreeBuilder.h"
#include "nsHtml5AtomTable.h"
#include "nsHtml5Module.h"
-#include "nsHtml5RefPtr.h"
+#include "nsHtml5StreamParserPtr.h"
#include "nsIScriptError.h"
#include "mozilla/Preferences.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsHtml5Highlighter.h"
#include "expat_config.h"
#include "expat.h"
#include "nsINestedURI.h"
#include "nsCharsetSource.h"
#include "nsIWyciwygChannel.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsPrintfCString.h"
#include "nsNetUtil.h"
#include "nsXULAppAPI.h"
+#include "mozilla/SchedulerGroup.h"
using namespace mozilla;
int32_t nsHtml5StreamParser::sTimerInitialDelay = 120;
int32_t nsHtml5StreamParser::sTimerSubsequentDelay = 120;
// static
void
@@ -47,22 +48,22 @@ nsHtml5StreamParser::InitializeStatics()
/*
* Note that nsHtml5StreamParser implements cycle collecting AddRef and
* Release. Therefore, nsHtml5StreamParser must never be refcounted from
* the parser thread!
*
* To work around this limitation, runnables posted by the main thread to the
* parser thread hold their reference to the stream parser in an
- * nsHtml5RefPtr. Upon creation, nsHtml5RefPtr addrefs the object it holds
+ * nsHtml5StreamParserPtr. Upon creation, nsHtml5StreamParserPtr addrefs the object it holds
* just like a regular nsRefPtr. This is OK, since the creation of the
- * runnable and the nsHtml5RefPtr happens on the main thread.
+ * runnable and the nsHtml5StreamParserPtr happens on the main thread.
*
* When the runnable is done on the parser thread, the destructor of
- * nsHtml5RefPtr runs there. It doesn't call Release on the held object
+ * nsHtml5StreamParserPtr runs there. It doesn't call Release on the held object
* directly. Instead, it posts another runnable back to the main thread where
* that runnable calls Release on the wrapped object.
*
* When posting runnables in the other direction, the runnables have to be
* created on the main thread when nsHtml5StreamParser is instantiated and
* held for the lifetime of the nsHtml5StreamParser. This works, because the
* same runnabled can be dispatched multiple times and currently runnables
* posted from the parser thread to main thread don't need to wrap any
@@ -950,18 +951,24 @@ nsHtml5StreamParser::OnStartRequest(nsIR
rv = NS_OK;
// The line below means that the encoding can end up being wrong if
// a view-source URL is loaded without having the encoding hint from a
// previous normal load in the history.
mReparseForbidden = !(mMode == NORMAL || mMode == PLAIN_TEXT);
+ mDocGroup = mExecutor->GetDocument()->GetDocGroup();
+
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mRequest, &rv));
if (NS_SUCCEEDED(rv)) {
+ // Non-HTTP channels are bogus enough that we let them work with unlabeled
+ // runnables for now. Asserting for HTTP channels only.
+ MOZ_ASSERT(mDocGroup || mMode == LOAD_AS_DATA, "How come the doc group is still null?");
+
nsAutoCString method;
Unused << httpChannel->GetRequestMethod(method);
// XXX does Necko have a way to renavigate POST, etc. without hitting
// the network?
if (!method.EqualsLiteral("GET")) {
// This is the old Gecko behavior but the HTML5 spec disagrees.
// Don't reparse on POST.
mReparseForbidden = true;
@@ -1054,17 +1061,18 @@ nsHtml5StreamParser::DoStopRequest()
}
ParseAvailableData();
}
class nsHtml5RequestStopper : public Runnable
{
private:
- nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
+ nsHtml5StreamParserPtr mStreamParser;
+
public:
explicit nsHtml5RequestStopper(nsHtml5StreamParser* aStreamParser)
: Runnable("nsHtml5RequestStopper")
, mStreamParser(aStreamParser)
{}
NS_IMETHOD Run() override
{
mozilla::MutexAutoLock autoLock(mStreamParser->mTokenizerMutex);
@@ -1140,19 +1148,20 @@ nsHtml5StreamParser::DoDataAvailable(con
"nsHtml5StreamParser::DoDataAvailable");
}
mFlushTimerArmed = true;
}
class nsHtml5DataAvailable : public Runnable
{
private:
- nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
- UniquePtr<uint8_t[]> mData;
- uint32_t mLength;
+ nsHtml5StreamParserPtr mStreamParser;
+ UniquePtr<uint8_t[]> mData;
+ uint32_t mLength;
+
public:
nsHtml5DataAvailable(nsHtml5StreamParser* aStreamParser,
UniquePtr<uint8_t[]> aData,
uint32_t aLength)
: Runnable("nsHtml5DataAvailable")
, mStreamParser(aStreamParser)
, mData(Move(aData))
, mLength(aLength)
@@ -1337,19 +1346,17 @@ nsHtml5StreamParser::FlushTreeOpsAndDisa
}
mFlushTimerArmed = false;
}
if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
mTokenizer->FlushViewSource();
}
mTreeBuilder->Flush();
nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
- if (NS_FAILED(mExecutor->GetDocument()->Dispatch("nsHtml5ExecutorFlusher",
- TaskCategory::Other,
- runnable.forget()))) {
+ if (NS_FAILED(DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event");
}
}
void
nsHtml5StreamParser::ParseAvailableData()
{
NS_ASSERTION(IsParserThread(), "Wrong thread!");
@@ -1370,21 +1377,25 @@ nsHtml5StreamParser::ParseAvailableData(
case STREAM_BEING_READ:
// never release the last buffer.
if (!mSpeculating) {
// reuse buffer space if not speculating
mFirstBuffer->setStart(0);
mFirstBuffer->setEnd(0);
}
mTreeBuilder->FlushLoads();
- // Dispatch this runnable unconditionally, because the loads
- // that need flushing may have been flushed earlier even if the
- // flush right above here did nothing.
- if (NS_FAILED(NS_DispatchToMainThread(mLoadFlusher))) {
- NS_WARNING("failed to dispatch load flush event");
+ {
+ // Dispatch this runnable unconditionally, because the loads
+ // that need flushing may have been flushed earlier even if the
+ // flush right above here did nothing.
+ nsCOMPtr<nsIRunnable> runnable(mLoadFlusher);
+ if (NS_FAILED(
+ DispatchToMain("nsHtml5LoadFlusher", runnable.forget()))) {
+ NS_WARNING("failed to dispatch load flush event");
+ }
}
return; // no more data for now but expecting more
case STREAM_ENDED:
if (mAtEOF) {
return;
}
mAtEOF = true;
if (mCharsetSource < kCharsetFromMetaTag) {
@@ -1471,17 +1482,18 @@ nsHtml5StreamParser::ParseAvailableData(
}
continue;
}
}
class nsHtml5StreamParserContinuation : public Runnable
{
private:
- nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
+ nsHtml5StreamParserPtr mStreamParser;
+
public:
explicit nsHtml5StreamParserContinuation(nsHtml5StreamParser* aStreamParser)
: Runnable("nsHtml5StreamParserContinuation")
, mStreamParser(aStreamParser)
{}
NS_IMETHOD Run() override
{
mozilla::MutexAutoLock autoLock(mStreamParser->mTokenizerMutex);
@@ -1635,17 +1647,18 @@ nsHtml5StreamParser::ContinueAfterFailed
if (NS_FAILED(mEventTarget->Dispatch(event, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch nsHtml5StreamParserContinuation");
}
}
class nsHtml5TimerKungFu : public Runnable
{
private:
- nsHtml5RefPtr<nsHtml5StreamParser> mStreamParser;
+ nsHtml5StreamParserPtr mStreamParser;
+
public:
explicit nsHtml5TimerKungFu(nsHtml5StreamParser* aStreamParser)
: Runnable("nsHtml5TimerKungFu")
, mStreamParser(aStreamParser)
{}
NS_IMETHOD Run() override
{
mozilla::MutexAutoLock flushTimerLock(mStreamParser->mFlushTimerMutex);
@@ -1668,20 +1681,20 @@ nsHtml5StreamParser::DropTimer()
* the thread where nsTimerImpl::Fire would run. It's not safe to
* dispatch a runnable to cancel the timer from the destructor of this
* class, because the timer has a weak (void*) pointer back to this instance
* of the stream parser and having the timer fire before the runnable
* cancels it would make the timer access a deleted object.
*
* This DropTimer method addresses these issues. This method must be called
* on the main thread before the destructor of this class is reached.
- * The nsHtml5TimerKungFu object has an nsHtml5RefPtr that addrefs this
+ * The nsHtml5TimerKungFu object has an nsHtml5StreamParserPtr that addrefs this
* stream parser object to keep it alive until the runnable is done.
* The runnable cancels the timer on the parser thread, drops the timer
- * and lets nsHtml5RefPtr send a runnable back to the main thread to
+ * and lets nsHtml5StreamParserPtr send a runnable back to the main thread to
* release the stream parser.
*/
mozilla::MutexAutoLock flushTimerLock(mFlushTimerMutex);
if (mFlushTimer) {
nsCOMPtr<nsIRunnable> event = new nsHtml5TimerKungFu(this);
if (NS_FAILED(mEventTarget->Dispatch(event, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch TimerKungFu event");
}
@@ -1712,37 +1725,54 @@ nsHtml5StreamParser::TimerFlush()
if (IsTerminatedOrInterrupted()) {
return;
}
if (mMode == VIEW_SOURCE_HTML || mMode == VIEW_SOURCE_XML) {
mTreeBuilder->Flush(); // delete useless ops
if (mTokenizer->FlushViewSource()) {
- if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
- NS_WARNING("failed to dispatch executor flush event");
- }
- }
+ nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
+ if (NS_FAILED(
+ DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
+ NS_WARNING("failed to dispatch executor flush event");
+ }
+ }
} else {
// we aren't speculating and we don't know when new data is
// going to arrive. Send data to the main thread.
if (mTreeBuilder->Flush(true)) {
- if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
+ nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
+ if (NS_FAILED(
+ DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event");
}
}
}
}
void
nsHtml5StreamParser::MarkAsBroken(nsresult aRv)
{
NS_ASSERTION(IsParserThread(), "Wrong thread!");
mTokenizerMutex.AssertCurrentThreadOwns();
Terminate();
mTreeBuilder->MarkAsBroken(aRv);
mozilla::DebugOnly<bool> hadOps = mTreeBuilder->Flush(false);
NS_ASSERTION(hadOps, "Should have had the markAsBroken op!");
- if (NS_FAILED(NS_DispatchToMainThread(mExecutorFlusher))) {
+ nsCOMPtr<nsIRunnable> runnable(mExecutorFlusher);
+ if (NS_FAILED(DispatchToMain("nsHtml5ExecutorFlusher", runnable.forget()))) {
NS_WARNING("failed to dispatch executor flush event");
}
}
+
+nsresult
+nsHtml5StreamParser::DispatchToMain(const char* aName,
+ already_AddRefed<nsIRunnable>&& aRunnable)
+{
+ nsCOMPtr<nsIRunnable> runnable(aRunnable);
+ if (mDocGroup) {
+ return mDocGroup->Dispatch(aName, TaskCategory::Network, runnable.forget());
+ }
+ return SchedulerGroup::UnlabeledDispatch(
+ aName, TaskCategory::Network, runnable.forget());
+}
--- a/parser/html/nsHtml5StreamParser.h
+++ b/parser/html/nsHtml5StreamParser.h
@@ -16,16 +16,17 @@
#include "nsIInputStream.h"
#include "mozilla/Mutex.h"
#include "mozilla/UniquePtr.h"
#include "nsHtml5AtomTable.h"
#include "nsHtml5Speculation.h"
#include "nsISerialEventTarget.h"
#include "nsITimer.h"
#include "nsICharsetDetector.h"
+#include "mozilla/dom/DocGroup.h"
class nsHtml5Parser;
#define NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE 1024
#define NS_HTML5_STREAM_PARSER_SNIFFING_BUFFER_SIZE 1024
enum eParserMode {
/**
@@ -104,59 +105,60 @@ enum eHtml5StreamState {
class nsHtml5StreamParser final : public nsICharsetDetectionObserver {
template <typename T> using NotNull = mozilla::NotNull<T>;
using Encoding = mozilla::Encoding;
friend class nsHtml5RequestStopper;
friend class nsHtml5DataAvailable;
friend class nsHtml5StreamParserContinuation;
friend class nsHtml5TimerKungFu;
-
- public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser,
- nsICharsetDetectionObserver)
+ friend class nsHtml5StreamParserPtr;
- static void InitializeStatics();
+public:
+ NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+ NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHtml5StreamParser,
+ nsICharsetDetectionObserver)
- nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
- nsHtml5Parser* aOwner,
- eParserMode aMode);
+ static void InitializeStatics();
- // Methods that nsHtml5StreamListener calls
- nsresult CheckListenerChain();
+ nsHtml5StreamParser(nsHtml5TreeOpExecutor* aExecutor,
+ nsHtml5Parser* aOwner,
+ eParserMode aMode);
- nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
+ // Methods that nsHtml5StreamListener calls
+ nsresult CheckListenerChain();
+
+ nsresult OnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
- nsresult OnDataAvailable(nsIRequest* aRequest,
- nsISupports* aContext,
- nsIInputStream* aInStream,
- uint64_t aSourceOffset,
- uint32_t aLength);
+ nsresult OnDataAvailable(nsIRequest* aRequest,
+ nsISupports* aContext,
+ nsIInputStream* aInStream,
+ uint64_t aSourceOffset,
+ uint32_t aLength);
- nsresult OnStopRequest(nsIRequest* aRequest,
- nsISupports* aContext,
- nsresult status);
+ nsresult OnStopRequest(nsIRequest* aRequest,
+ nsISupports* aContext,
+ nsresult status);
- // nsICharsetDetectionObserver
- /**
+ // nsICharsetDetectionObserver
+ /**
* Chardet calls this to report the detection result
*/
- NS_IMETHOD Notify(const char* aCharset, nsDetectionConfident aConf) override;
+ NS_IMETHOD Notify(const char* aCharset, nsDetectionConfident aConf) override;
- // EncodingDeclarationHandler
- // https://hg.mozilla.org/projects/htmlparser/file/tip/src/nu/validator/htmlparser/common/EncodingDeclarationHandler.java
- /**
+ // EncodingDeclarationHandler
+ // https://hg.mozilla.org/projects/htmlparser/file/tip/src/nu/validator/htmlparser/common/EncodingDeclarationHandler.java
+ /**
* Tree builder uses this to report a late <meta charset>
*/
- bool internalEncodingDeclaration(nsHtml5String aEncoding);
+ bool internalEncodingDeclaration(nsHtml5String aEncoding);
- // Not from an external interface
+ // Not from an external interface
- /**
+ /**
* Call this method once you've created a parser, and want to instruct it
* about what charset to load
*
* @param aEncoding the charset of a document
* @param aCharsetSource the source of the charset
*/
inline void SetDocumentCharset(NotNull<const Encoding*> aEncoding,
int32_t aSource) {
@@ -379,16 +381,23 @@ class nsHtml5StreamParser final : public
* small (so most pages are not affected) but small enough that we don't end
* up with failed speculations over and over in pathological cases.
*/
bool IsSpeculationEnabled()
{
return mSpeculationFailureCount < 100;
}
+ /**
+ * Dispatch an event to a Quantum DOM main thread-ish thread.
+ * (Not the parser thread.)
+ */
+ nsresult DispatchToMain(const char* aName,
+ already_AddRefed<nsIRunnable>&& aRunnable);
+
nsCOMPtr<nsIRequest> mRequest;
nsCOMPtr<nsIRequestObserver> mObserver;
/**
* The document title to use if this turns out to be a View Source parser.
*/
nsCString mViewSourceTitle;
@@ -446,16 +455,21 @@ class nsHtml5StreamParser final : public
// a buffer of the size NS_HTML5_STREAM_PARSER_READ_BUFFER_SIZE
/**
* The tree operation executor
*/
nsHtml5TreeOpExecutor* mExecutor;
/**
+ * The same as mExecutor->mDocument->mDocGroup.
+ */
+ RefPtr<mozilla::dom::DocGroup> mDocGroup;
+
+ /**
* The HTML5 tree builder
*/
nsAutoPtr<nsHtml5TreeBuilder> mTreeBuilder;
/**
* The HTML5 tokenizer
*/
nsAutoPtr<nsHtml5Tokenizer> mTokenizer;
new file mode 100644
--- /dev/null
+++ b/parser/html/nsHtml5StreamParserPtr.h
@@ -0,0 +1,269 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#ifndef nsHtml5StreamParserPtr_h
+#define nsHtml5StreamParserPtr_h
+#include "nsThreadUtils.h"
+#include "mozilla/dom/DocGroup.h"
+
+class nsHtml5StreamParserReleaser : public mozilla::Runnable
+{
+private:
+ nsHtml5StreamParser* mPtr;
+
+public:
+ explicit nsHtml5StreamParserReleaser(nsHtml5StreamParser* aPtr)
+ : mozilla::Runnable("nsHtml5StreamParserReleaser")
+ , mPtr(aPtr)
+ {
+ }
+ NS_IMETHOD Run() override
+ {
+ mPtr->Release();
+ return NS_OK;
+ }
+};
+/**
+ * Like nsRefPtr except release is proxied to the main
+ * thread. Mostly copied from nsRefPtr.
+ */
+class nsHtml5StreamParserPtr
+{
+private:
+ void assign_with_AddRef(nsHtml5StreamParser* rawPtr)
+ {
+ if (rawPtr)
+ rawPtr->AddRef();
+ assign_assuming_AddRef(rawPtr);
+ }
+ void** begin_assignment()
+ {
+ assign_assuming_AddRef(0);
+ return reinterpret_cast<void**>(&mRawPtr);
+ }
+ void assign_assuming_AddRef(nsHtml5StreamParser* newPtr)
+ {
+ nsHtml5StreamParser* oldPtr = mRawPtr;
+ mRawPtr = newPtr;
+ if (oldPtr)
+ release(oldPtr);
+ }
+ void release(nsHtml5StreamParser* aPtr)
+ {
+ nsCOMPtr<nsIRunnable> releaser = new nsHtml5StreamParserReleaser(aPtr);
+ if (NS_FAILED(aPtr->DispatchToMain("nsHtml5StreamParserReleaser",
+ releaser.forget()))) {
+ NS_WARNING("Failed to dispatch releaser event.");
+ }
+ }
+
+private:
+ nsHtml5StreamParser* mRawPtr;
+
+public:
+ ~nsHtml5StreamParserPtr()
+ {
+ if (mRawPtr)
+ release(mRawPtr);
+ }
+ // Constructors
+ nsHtml5StreamParserPtr()
+ : mRawPtr(0)
+ // default constructor
+ {
+ }
+ nsHtml5StreamParserPtr(const nsHtml5StreamParserPtr& aSmartPtr)
+ : mRawPtr(aSmartPtr.mRawPtr)
+ // copy-constructor
+ {
+ if (mRawPtr)
+ mRawPtr->AddRef();
+ }
+ explicit nsHtml5StreamParserPtr(nsHtml5StreamParser* aRawPtr)
+ : mRawPtr(aRawPtr)
+ // construct from a raw pointer (of the right type)
+ {
+ if (mRawPtr)
+ mRawPtr->AddRef();
+ }
+ // Assignment operators
+ nsHtml5StreamParserPtr& operator=(const nsHtml5StreamParserPtr& rhs)
+ // copy assignment operator
+ {
+ assign_with_AddRef(rhs.mRawPtr);
+ return *this;
+ }
+ nsHtml5StreamParserPtr& operator=(nsHtml5StreamParser* rhs)
+ // assign from a raw pointer (of the right type)
+ {
+ assign_with_AddRef(rhs);
+ return *this;
+ }
+ // Other pointer operators
+ void swap(nsHtml5StreamParserPtr& rhs)
+ // ...exchange ownership with |rhs|; can save a pair of refcount operations
+ {
+ nsHtml5StreamParser* temp = rhs.mRawPtr;
+ rhs.mRawPtr = mRawPtr;
+ mRawPtr = temp;
+ }
+ void swap(nsHtml5StreamParser*& rhs)
+ // ...exchange ownership with |rhs|; can save a pair of refcount operations
+ {
+ nsHtml5StreamParser* temp = rhs;
+ rhs = mRawPtr;
+ mRawPtr = temp;
+ }
+ template<typename I>
+ void forget(I** rhs)
+ // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
+ // Useful to avoid unnecessary AddRef/Release pairs with "out"
+ // parameters where rhs bay be a T** or an I** where I is a base class
+ // of T.
+ {
+ NS_ASSERTION(rhs, "Null pointer passed to forget!");
+ *rhs = mRawPtr;
+ mRawPtr = 0;
+ }
+ nsHtml5StreamParser* get() const
+ /*
+ Prefer the implicit conversion provided automatically by |operator nsHtml5StreamParser*() const|.
+ Use |get()| to resolve ambiguity or to get a castable pointer.
+ */
+ {
+ return const_cast<nsHtml5StreamParser*>(mRawPtr);
+ }
+ operator nsHtml5StreamParser*() const
+ /*
+ ...makes an |nsHtml5StreamParserPtr| act like its underlying raw pointer type whenever it
+ is used in a context where a raw pointer is expected. It is this operator
+ that makes an |nsHtml5StreamParserPtr| substitutable for a raw pointer.
+ Prefer the implicit use of this operator to calling |get()|, except where
+ necessary to resolve ambiguity.
+ */
+ {
+ return get();
+ }
+ nsHtml5StreamParser* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
+ {
+ NS_PRECONDITION(
+ mRawPtr != 0,
+ "You can't dereference a NULL nsHtml5StreamParserPtr with operator->().");
+ return get();
+ }
+ nsHtml5StreamParserPtr* get_address()
+ // This is not intended to be used by clients. See |address_of|
+ // below.
+ {
+ return this;
+ }
+ const nsHtml5StreamParserPtr* get_address() const
+ // This is not intended to be used by clients. See |address_of|
+ // below.
+ {
+ return this;
+ }
+
+public:
+ nsHtml5StreamParser& operator*() const
+ {
+ NS_PRECONDITION(
+ mRawPtr != 0,
+ "You can't dereference a NULL nsHtml5StreamParserPtr with operator*().");
+ return *get();
+ }
+ nsHtml5StreamParser** StartAssignment()
+ {
+#ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
+ return reinterpret_cast<nsHtml5StreamParser**>(begin_assignment());
+#else
+ assign_assuming_AddRef(0);
+ return reinterpret_cast<nsHtml5StreamParser**>(&mRawPtr);
+#endif
+ }
+};
+
+inline nsHtml5StreamParserPtr*
+address_of(nsHtml5StreamParserPtr& aPtr)
+{
+ return aPtr.get_address();
+}
+
+inline const nsHtml5StreamParserPtr*
+address_of(const nsHtml5StreamParserPtr& aPtr)
+{
+ return aPtr.get_address();
+}
+
+class nsHtml5StreamParserPtrGetterAddRefs
+/*
+ ...
+ This class is designed to be used for anonymous temporary objects in the
+ argument list of calls that return COM interface pointers, e.g.,
+ nsHtml5StreamParserPtr<IFoo> fooP;
+ ...->GetAddRefedPointer(getter_AddRefs(fooP))
+ DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
+ When initialized with a |nsHtml5StreamParserPtr|, as in the example above, it returns
+ a |void**|, a |T**|, or an |nsISupports**| as needed, that the
+ outer call (|GetAddRefedPointer| in this case) can fill in.
+ This type should be a nested class inside |nsHtml5StreamParserPtr<T>|.
+ */
+{
+public:
+ explicit nsHtml5StreamParserPtrGetterAddRefs(
+ nsHtml5StreamParserPtr& aSmartPtr)
+ : mTargetSmartPtr(aSmartPtr)
+ {
+ // nothing else to do
+ }
+ operator void**()
+ {
+ return reinterpret_cast<void**>(mTargetSmartPtr.StartAssignment());
+ }
+ operator nsHtml5StreamParser**() { return mTargetSmartPtr.StartAssignment(); }
+ nsHtml5StreamParser*& operator*()
+ {
+ return *(mTargetSmartPtr.StartAssignment());
+ }
+
+private:
+ nsHtml5StreamParserPtr& mTargetSmartPtr;
+};
+
+inline nsHtml5StreamParserPtrGetterAddRefs
+getter_AddRefs(nsHtml5StreamParserPtr& aSmartPtr)
+/*
+ Used around a |nsHtml5StreamParserPtr| when
+ ...makes the class |nsHtml5StreamParserPtrGetterAddRefs| invisible.
+ */
+{
+ return nsHtml5StreamParserPtrGetterAddRefs(aSmartPtr);
+}
+
+// Comparing an |nsHtml5StreamParserPtr| to |0|
+
+inline bool
+operator==(const nsHtml5StreamParserPtr& lhs, decltype(nullptr))
+{
+ return lhs.get() == nullptr;
+}
+
+inline bool
+operator==(decltype(nullptr), const nsHtml5StreamParserPtr& rhs)
+{
+ return nullptr == rhs.get();
+}
+
+inline bool
+operator!=(const nsHtml5StreamParserPtr& lhs, decltype(nullptr))
+{
+ return lhs.get() != nullptr;
+}
+
+inline bool
+operator!=(decltype(nullptr), const nsHtml5StreamParserPtr& rhs)
+{
+ return nullptr != rhs.get();
+}
+#endif // !defined(nsHtml5StreamParserPtr_h)
--- a/parser/html/nsHtml5TreeOpExecutor.cpp
+++ b/parser/html/nsHtml5TreeOpExecutor.cpp
@@ -234,20 +234,24 @@ nsHtml5TreeOpExecutor::MarkAsBroken(nsre
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mBroken = aReason;
if (mStreamParser) {
mStreamParser->Terminate();
}
// We are under memory pressure, but let's hope the following allocation
// works out so that we get to terminate and clean up the parser from
// a safer point.
- if (mParser) { // can mParser ever be null here?
- MOZ_ALWAYS_SUCCEEDS(
- NS_DispatchToMainThread(NewRunnableMethod("nsHtml5Parser::Terminate",
- GetParser(), &nsHtml5Parser::Terminate)));
+ if (mParser && mDocument) { // can mParser ever be null here?
+ nsCOMPtr<nsIRunnable> terminator =
+ NewRunnableMethod("nsHtml5Parser::Terminate", GetParser(), &nsHtml5Parser::Terminate);
+ if (NS_FAILED(mDocument->Dispatch("nsHtml5Parser::Terminate",
+ TaskCategory::Network,
+ terminator.forget()))) {
+ NS_WARNING("failed to dispatch executor flush event");
+ }
}
return aReason;
}
void
FlushTimerCallback(nsITimer* aTimer, void* aClosure)
{
RefPtr<nsHtml5TreeOpExecutor> ex = gBackgroundFlushList->popFirst();
@@ -261,19 +265,19 @@ FlushTimerCallback(nsITimer* aTimer, voi
NS_RELEASE(gFlushTimer);
}
}
void
nsHtml5TreeOpExecutor::ContinueInterruptedParsingAsync()
{
if (!mDocument || !mDocument->IsInBackgroundWindow()) {
- nsCOMPtr<nsIRunnable> flusher = new nsHtml5ExecutorReflusher(this);
+ nsCOMPtr<nsIRunnable> flusher = new nsHtml5ExecutorReflusher(this);
if (NS_FAILED(mDocument->Dispatch("nsHtml5ExecutorReflusher",
- TaskCategory::Other,
+ TaskCategory::Network,
flusher.forget()))) {
NS_WARNING("failed to dispatch executor flush event");
}
} else {
if (!gBackgroundFlushList) {
gBackgroundFlushList = new mozilla::LinkedList<nsHtml5TreeOpExecutor>();
}
if (!isInList()) {
--- a/parser/html/nsHtml5TreeOperation.cpp
+++ b/parser/html/nsHtml5TreeOperation.cpp
@@ -609,19 +609,18 @@ nsHtml5TreeOperation::DoneCreatingElemen
{
aNode->DoneCreatingElement();
}
void
nsHtml5TreeOperation::SvgLoad(nsIContent* aNode)
{
nsCOMPtr<nsIRunnable> event = new nsHtml5SVGLoadDispatcher(aNode);
- if (NS_FAILED(aNode->OwnerDoc()->Dispatch("nsHtml5SVGLoadDispatcher",
- TaskCategory::Other,
- event.forget()))) {
+ if (NS_FAILED(aNode->OwnerDoc()->Dispatch(
+ "nsHtml5SVGLoadDispatcher", TaskCategory::Network, event.forget()))) {
NS_WARNING("failed to dispatch svg load dispatcher");
}
}
void
nsHtml5TreeOperation::MarkMalformedIfScript(nsIContent* aNode)
{
nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(aNode);