Bug 1588745 - part 4: Make TextControlState reuse its instance by itself r=Ehsan

Currently, only `HTMLInputElement` reuses `TextControlState` instance since
`HTMLTextAreaElement` had the instance as a member rather than allocate it.

Now, all instances are allocated in the heap independently for guaranteeing
their lifetime.  So, the reuse mechanism should be managed by
`TextControlState` itself.

Depends on D51393

Differential Revision: https://phabricator.services.mozilla.com/D51394
This commit is contained in:
Masayuki Nakano
2019-11-01 20:51:48 +00:00
parent c14ab80c37
commit 55109d6fed
5 changed files with 58 additions and 50 deletions

View File

@@ -1802,7 +1802,7 @@ void nsContentUtils::Shutdown() {
NS_RELEASE(sUserInteractionObserver);
}
HTMLInputElement::Shutdown();
TextControlState::Shutdown();
nsMappedAttributes::Shutdown();
}

View File

@@ -937,28 +937,6 @@ static nsresult FireEventForAccessibility(HTMLInputElement* aTarget,
EventMessage aEventMessage);
#endif
TextControlState* HTMLInputElement::sCachedTextControlState = nullptr;
bool HTMLInputElement::sShutdown = false;
/* static */
void HTMLInputElement::ReleaseTextControlState(TextControlState* aState) {
if (!sShutdown && !sCachedTextControlState && !aState->IsBusy()) {
aState->PrepareForReuse();
sCachedTextControlState = aState;
} else {
aState->Destroy();
}
}
/* static */
void HTMLInputElement::Shutdown() {
sShutdown = true;
if (sCachedTextControlState) {
sCachedTextControlState->Destroy();
sCachedTextControlState = nullptr;
}
}
//
// construction, destruction
//
@@ -1001,8 +979,7 @@ HTMLInputElement::HTMLInputElement(
"performance regression!");
// We are in a type=text so we now we currenty need a TextControlState.
mInputData.mState =
TextControlState::Construct(this, &sCachedTextControlState);
mInputData.mState = TextControlState::Construct(this);
void* memory = mInputTypeMem;
mInputType = InputType::Create(this, mType, memory);
@@ -1033,7 +1010,7 @@ void HTMLInputElement::FreeData() {
mInputData.mValue = nullptr;
} else {
UnbindFromFrame(nullptr);
ReleaseTextControlState(mInputData.mState);
mInputData.mState->Destroy();
mInputData.mState = nullptr;
}
@@ -4515,8 +4492,7 @@ void HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify) {
mInputType = InputType::Create(this, mType, memory);
if (IsSingleLineTextControl()) {
mInputData.mState =
TextControlState::Construct(this, &sCachedTextControlState);
mInputData.mState = TextControlState::Construct(this);
if (!sp.IsDefault()) {
mInputData.mState->SetSelectionProperties(sp);
}

View File

@@ -846,8 +846,6 @@ class HTMLInputElement final : public nsGenericHTMLFormElementWithState,
void UpdateEntries(
const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories);
static void Shutdown();
/**
* Returns if the required attribute applies for the current type.
*/
@@ -1660,11 +1658,6 @@ class HTMLInputElement final : public nsGenericHTMLFormElementWithState,
nsCOMPtr<nsIFilePicker> mFilePicker;
RefPtr<HTMLInputElement> mInput;
};
static void ReleaseTextControlState(TextControlState* aState);
static TextControlState* sCachedTextControlState;
static bool sShutdown;
};
} // namespace dom

View File

@@ -1127,7 +1127,7 @@ class MOZ_STACK_CLASS AutoTextControlHandlingState {
~AutoTextControlHandlingState() {
mTextControlState.mHandlingState = mParent;
if (!mParent && mTextControlStateDestroyed) {
mTextControlState.Destroy();
mTextControlState.DeleteOrCacheForReuse();
}
}
@@ -1180,6 +1180,9 @@ class MOZ_STACK_CLASS AutoTextControlHandlingState {
* mozilla::TextControlState
*****************************************************************************/
TextControlState* TextControlState::sReleasedInstance = nullptr;
bool TextControlState::sHasShutDown = false;
TextControlState::TextControlState(nsITextControlElement* aOwningElement)
: mTextCtrlElement(aOwningElement),
mBoundFrame(nullptr),
@@ -1199,11 +1202,11 @@ TextControlState::TextControlState(nsITextControlElement* aOwningElement)
}
TextControlState* TextControlState::Construct(
nsITextControlElement* aOwningElement, TextControlState** aReusedState) {
if (aReusedState && *aReusedState) {
TextControlState* state = *aReusedState;
MOZ_ASSERT(!state->IsBusy());
*aReusedState = nullptr;
nsITextControlElement* aOwningElement) {
if (sReleasedInstance) {
MOZ_ASSERT(!sReleasedInstance->IsBusy());
TextControlState* state = sReleasedInstance;
sReleasedInstance = nullptr;
state->mTextCtrlElement = aOwningElement;
state->mBoundFrame = nullptr;
state->mSelectionProperties = SelectionProperties();
@@ -1228,12 +1231,32 @@ TextControlState::~TextControlState() {
Clear();
}
void TextControlState::Shutdown() {
sHasShutDown = true;
if (sReleasedInstance) {
sReleasedInstance->DeleteOrCacheForReuse();
sReleasedInstance = nullptr;
}
}
void TextControlState::Destroy() {
// If we're handling something, we should be deleted later.
if (mHandlingState) {
mHandlingState->OnDestroyTextControlState();
return;
}
DeleteOrCacheForReuse();
}
void TextControlState::DeleteOrCacheForReuse() {
MOZ_ASSERT(!IsBusy());
// If we can cache this instance, we should do it instead of deleting it.
if (!sHasShutDown && !sReleasedInstance) {
sReleasedInstance = this;
sReleasedInstance->PrepareForReuse();
return;
}
delete this;
}

View File

@@ -141,8 +141,9 @@ class TextControlState final : public SupportsWeakPtr<TextControlState> {
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(TextControlState)
static TextControlState* Construct(nsITextControlElement* aOwningElement,
TextControlState** aReusedState = nullptr);
static TextControlState* Construct(nsITextControlElement* aOwningElement);
static void Shutdown();
/**
* Destroy() deletes the instance immediately or later.
@@ -161,13 +162,6 @@ class TextControlState final : public SupportsWeakPtr<TextControlState> {
bool IsBusy() const { return !!mHandlingState || mValueTransferInProgress; }
void PrepareForReuse() {
MOZ_ASSERT(!IsBusy());
Unlink();
mValue.reset();
mTextCtrlElement = nullptr;
}
TextEditor* GetTextEditor();
TextEditor* GetTextEditorWithoutCreation();
nsISelectionController* GetSelectionController() const;
@@ -386,6 +380,18 @@ class TextControlState final : public SupportsWeakPtr<TextControlState> {
explicit TextControlState(nsITextControlElement* aOwningElement);
MOZ_CAN_RUN_SCRIPT_BOUNDARY ~TextControlState();
/**
* Delete the instance or cache to reuse it if possible.
*/
void DeleteOrCacheForReuse();
void PrepareForReuse() {
MOZ_ASSERT(!IsBusy());
Unlink();
mValue.reset();
mTextCtrlElement = nullptr;
}
void ValueWasChanged(bool aNotify);
MOZ_CAN_RUN_SCRIPT void DestroyEditor();
@@ -425,6 +431,16 @@ class TextControlState final : public SupportsWeakPtr<TextControlState> {
bool mPlaceholderVisibility;
bool mPreviewVisibility;
/**
* For avoiding allocation cost of the instance, we should reuse instances
* as far as possible.
* TODO: Maybe, we should cache more instances with array. Then, it must
* be faster to load pages which have a lot of `<input type="text">`
* elements.
*/
static TextControlState* sReleasedInstance;
static bool sHasShutDown;
friend class AutoTextControlHandlingState;
friend class PrepareEditorEvent;
friend class RestoreSelectionState;