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:
@@ -1802,7 +1802,7 @@ void nsContentUtils::Shutdown() {
|
||||
NS_RELEASE(sUserInteractionObserver);
|
||||
}
|
||||
|
||||
HTMLInputElement::Shutdown();
|
||||
TextControlState::Shutdown();
|
||||
nsMappedAttributes::Shutdown();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user