From e318c2a18bbe07b414d2ef2ca2c73f165424c3b7 Mon Sep 17 00:00:00 2001 From: Scott Violet Date: Wed, 25 Jan 2023 00:21:22 +0000 Subject: [PATCH] blink: removes ElementRecord and folds into stackitem This simplifies some of the consuming code, in so far as it doesn't need to iterate over the ElementRecords, but can instead iterate over the HTMLStackItems, which is really what it wants. Doing this avoids an allocation per element, and gives a slight win on some benchmarks. ~.5% on the Vanilla tests. Overall speedometer score doesn't doesn't move in a statistically significant way. See last two pinpoint runs for details. Bug: 1406507 Change-Id: I9f855913801ff7a59d2e734e7c66e5dd2071b632 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4179378 Commit-Queue: Scott Violet Reviewed-by: Mason Freed Cr-Commit-Position: refs/heads/main@{#1096520} --- .../html/parser/html_construction_site.cc | 34 ++-- .../core/html/parser/html_construction_site.h | 13 +- .../core/html/parser/html_element_stack.cc | 147 ++++++++---------- .../core/html/parser/html_element_stack.h | 49 ++---- .../core/html/parser/html_stack_item.h | 34 +++- .../core/html/parser/html_tree_builder.cc | 75 ++++----- 6 files changed, 162 insertions(+), 190 deletions(-) diff --git a/third_party/blink/renderer/core/html/parser/html_construction_site.cc b/third_party/blink/renderer/core/html/parser/html_construction_site.cc index 0e7d87ba83c552..c06c397ab60f6d 100644 --- a/third_party/blink/renderer/core/html/parser/html_construction_site.cc +++ b/third_party/blink/renderer/core/html/parser/html_construction_site.cc @@ -831,8 +831,7 @@ void HTMLConstructionSite::InsertHTMLTemplateElement( // TODO(crbug.com/1063157): Add an attribute for imperative slot // assignment. auto slot_assignment_mode = SlotAssignmentMode::kNamed; - HTMLStackItem* shadow_host_stack_item = - open_elements_.TopRecord()->StackItem(); + HTMLStackItem* shadow_host_stack_item = open_elements_.TopStackItem(); Element* host = shadow_host_stack_item->GetElement(); ShadowRootType type = declarative_shadow_root_type == DeclarativeShadowRootType::kStreamingOpen @@ -884,7 +883,7 @@ void HTMLConstructionSite::InsertFormattingElement(AtomicHTMLToken* token) { // Possible active formatting elements include: // a, b, big, code, em, font, i, nobr, s, small, strike, strong, tt, and u. InsertHTMLElement(token); - active_formatting_elements_.Append(CurrentElementRecord()->StackItem()); + active_formatting_elements_.Append(CurrentStackItem()); } void HTMLConstructionSite::InsertScriptElement(AtomicHTMLToken* token) { @@ -963,15 +962,7 @@ void HTMLConstructionSite::InsertTextNode(const StringView& string, whitespace_mode); } -void HTMLConstructionSite::Reparent(HTMLElementStack::ElementRecord* new_parent, - HTMLElementStack::ElementRecord* child) { - HTMLConstructionSiteTask task(HTMLConstructionSiteTask::kReparent); - task.parent = new_parent->GetNode(); - task.child = child->GetNode(); - QueueTask(task, true); -} - -void HTMLConstructionSite::Reparent(HTMLElementStack::ElementRecord* new_parent, +void HTMLConstructionSite::Reparent(HTMLStackItem* new_parent, HTMLStackItem* child) { HTMLConstructionSiteTask task(HTMLConstructionSiteTask::kReparent); task.parent = new_parent->GetNode(); @@ -979,9 +970,8 @@ void HTMLConstructionSite::Reparent(HTMLElementStack::ElementRecord* new_parent, QueueTask(task, true); } -void HTMLConstructionSite::InsertAlreadyParsedChild( - HTMLStackItem* new_parent, - HTMLElementStack::ElementRecord* child) { +void HTMLConstructionSite::InsertAlreadyParsedChild(HTMLStackItem* new_parent, + HTMLStackItem* child) { if (new_parent->CausesFosterParenting()) { FosterParent(child->GetNode()); return; @@ -994,9 +984,8 @@ void HTMLConstructionSite::InsertAlreadyParsedChild( QueueTask(task, true); } -void HTMLConstructionSite::TakeAllChildren( - HTMLStackItem* new_parent, - HTMLElementStack::ElementRecord* old_parent) { +void HTMLConstructionSite::TakeAllChildren(HTMLStackItem* new_parent, + HTMLStackItem* old_parent) { HTMLConstructionSiteTask task(HTMLConstructionSiteTask::kTakeAllChildren); task.parent = new_parent->GetNode(); task.child = old_parent->GetNode(); @@ -1265,15 +1254,16 @@ bool HTMLConstructionSite::InQuirksMode() { // https://html.spec.whatwg.org/C/#appropriate-place-for-inserting-a-node void HTMLConstructionSite::FindFosterSite(HTMLConstructionSiteTask& task) { // 2.1 - HTMLElementStack::ElementRecord* last_template = + HTMLStackItem* last_template = open_elements_.Topmost(html_names::HTMLTag::kTemplate); // 2.2 - HTMLElementStack::ElementRecord* last_table = + HTMLStackItem* last_table = open_elements_.Topmost(html_names::HTMLTag::kTable); // 2.3 - if (last_template && (!last_table || last_template->IsAbove(last_table))) { + if (last_template && + (!last_table || last_template->IsAboveItemInStack(last_table))) { task.parent = last_template->GetElement(); return; } @@ -1293,7 +1283,7 @@ void HTMLConstructionSite::FindFosterSite(HTMLConstructionSiteTask& task) { } // 2.6, 2.7 - task.parent = last_table->Next()->GetElement(); + task.parent = last_table->NextItemInStack()->GetElement(); } bool HTMLConstructionSite::ShouldFosterParent() const { diff --git a/third_party/blink/renderer/core/html/parser/html_construction_site.h b/third_party/blink/renderer/core/html/parser/html_construction_site.h index 87990db32b15f6..aad8d2589d7c5c 100644 --- a/third_party/blink/renderer/core/html/parser/html_construction_site.h +++ b/third_party/blink/renderer/core/html/parser/html_construction_site.h @@ -163,18 +163,14 @@ class HTMLConstructionSite final { void InsertHTMLHtmlStartTagInBody(AtomicHTMLToken*); void InsertHTMLBodyStartTagInBody(AtomicHTMLToken*); - void Reparent(HTMLElementStack::ElementRecord* new_parent, - HTMLElementStack::ElementRecord* child); - void Reparent(HTMLElementStack::ElementRecord* new_parent, - HTMLStackItem* child); + void Reparent(HTMLStackItem* new_parent, HTMLStackItem* child); // insertAlreadyParsedChild assumes that |child| has already been parsed // (i.e., we're just moving it around in the tree rather than parsing it for // the first time). That means this function doesn't call beginParsingChildren // / finishParsingChildren. void InsertAlreadyParsedChild(HTMLStackItem* new_parent, - HTMLElementStack::ElementRecord* child); - void TakeAllChildren(HTMLStackItem* new_parent, - HTMLElementStack::ElementRecord* old_parent); + HTMLStackItem* child); + void TakeAllChildren(HTMLStackItem* new_parent, HTMLStackItem* old_parent); HTMLStackItem* CreateElementFromSavedToken(HTMLStackItem*); @@ -191,9 +187,6 @@ class HTMLConstructionSite final { bool InQuirksMode(); bool IsEmpty() const { return !open_elements_.StackDepth(); } - HTMLElementStack::ElementRecord* CurrentElementRecord() const { - return open_elements_.TopRecord(); - } Element* CurrentElement() const { return open_elements_.Top(); } ContainerNode* CurrentNode() const { return open_elements_.TopNode(); } HTMLStackItem* CurrentStackItem() const { diff --git a/third_party/blink/renderer/core/html/parser/html_element_stack.cc b/third_party/blink/renderer/core/html/parser/html_element_stack.cc index a0a59f28a2f80b..788319f2336cb2 100644 --- a/third_party/blink/renderer/core/html/parser/html_element_stack.cc +++ b/third_party/blink/renderer/core/html/parser/html_element_stack.cc @@ -174,32 +174,6 @@ inline bool IsSelectScopeMarker(HTMLStackItem* item) { } // namespace -HTMLElementStack::ElementRecord::ElementRecord(HTMLStackItem* item, - ElementRecord* next) - : item_(item), next_(next) { - DCHECK(item_); -} - -void HTMLElementStack::ElementRecord::ReplaceElement(HTMLStackItem* item) { - DCHECK(item); - DCHECK(!item_ || item_->IsElementNode()); - // FIXME: Should this call finishParsingChildren? - item_ = item; -} - -bool HTMLElementStack::ElementRecord::IsAbove(ElementRecord* other) const { - for (ElementRecord* below = Next(); below; below = below->Next()) { - if (below == other) - return true; - } - return false; -} - -void HTMLElementStack::ElementRecord::Trace(Visitor* visitor) const { - visitor->Trace(item_); - visitor->Trace(next_); -} - HTMLElementStack::HTMLElementStack() : root_node_(nullptr), head_element_(nullptr), @@ -207,7 +181,7 @@ HTMLElementStack::HTMLElementStack() stack_depth_(0) {} bool HTMLElementStack::HasOnlyOneElement() const { - return !TopRecord()->Next(); + return !TopStackItem()->NextItemInStack(); } bool HTMLElementStack::SecondElementIsHTMLBodyElement() const { @@ -246,7 +220,7 @@ void HTMLElementStack::PopAll() { if (auto* select = DynamicTo(node)) select->SetBlocksFormSubmission(true); } - top_ = top_->ReleaseNext(); + top_ = top_->ReleaseNextItemInStack(); } } @@ -381,44 +355,42 @@ void HTMLElementStack::Push(HTMLStackItem* item) { } void HTMLElementStack::InsertAbove(HTMLStackItem* item, - ElementRecord* record_below) { + HTMLStackItem* item_below) { + DCHECK(!item->NextItemInStack()); DCHECK(item); - DCHECK(record_below); + DCHECK(item_below); DCHECK(top_); DCHECK(!item->HasTagName(html_names::kHTMLTag)); DCHECK(!item->HasTagName(html_names::kHeadTag)); DCHECK(!item->HasTagName(html_names::kBodyTag)); DCHECK(root_node_); - if (record_below == top_) { + if (item_below == top_) { Push(item); return; } - for (ElementRecord* record_above = top_.Get(); record_above; - record_above = record_above->Next()) { - if (record_above->Next() != record_below) + for (HTMLStackItem* item_above = top_.Get(); item_above; + item_above = item_above->NextItemInStack()) { + if (item_above->NextItemInStack() != item_below) { continue; + } stack_depth_++; - record_above->SetNext( - MakeGarbageCollected(item, record_above->ReleaseNext())); - record_above->Next()->GetElement()->BeginParsingChildren(); + item->SetNextItemInStack(item_above->ReleaseNextItemInStack()); + item_above->SetNextItemInStack(item); + item->GetElement()->BeginParsingChildren(); return; } NOTREACHED(); } -HTMLElementStack::ElementRecord* HTMLElementStack::TopRecord() const { - DCHECK(top_); - return top_.Get(); -} - HTMLStackItem* HTMLElementStack::OneBelowTop() const { // We should never call this if there are fewer than 2 elements on the stack. DCHECK(top_); - DCHECK(top_->Next()); - if (top_->Next()->StackItem()->IsElementNode()) - return top_->Next()->StackItem(); + DCHECK(top_->NextItemInStack()); + if (top_->NextItemInStack()->IsElementNode()) { + return top_->NextItemInStack(); + } return nullptr; } @@ -441,24 +413,22 @@ void HTMLElementStack::Remove(Element* element) { RemoveNonTopCommon(element); } -HTMLElementStack::ElementRecord* HTMLElementStack::Find( - Element* element) const { - for (ElementRecord* pos = top_.Get(); pos; pos = pos->Next()) { - if (pos->GetNode() == element) - return pos; +HTMLStackItem* HTMLElementStack::Find(Element* element) const { + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { + if (item->GetNode() == element) { + return item; + } } return nullptr; } -HTMLElementStack::ElementRecord* HTMLElementStack::Topmost( - html_names::HTMLTag tag) const { +HTMLStackItem* HTMLElementStack::Topmost(html_names::HTMLTag tag) const { // kUnknown by itself is not enough to uniquely a tag. This code should only // be called with HTMLTags other than kUnknown. DCHECK_NE(tag, HTMLTag::kUnknown); - for (ElementRecord* pos = top_.Get(); pos; pos = pos->Next()) { - if (pos->StackItem()->IsHTMLNamespace() && - tag == pos->StackItem()->GetHTMLTag()) { - return pos; + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { + if (item->IsHTMLNamespace() && tag == item->GetHTMLTag()) { + return item; } } return nullptr; @@ -469,13 +439,11 @@ bool HTMLElementStack::Contains(Element* element) const { } template -bool InScopeCommon(HTMLElementStack::ElementRecord* top, - html_names::HTMLTag tag) { +bool InScopeCommon(HTMLStackItem* top, html_names::HTMLTag tag) { // kUnknown by itself is not enough to uniquely a tag. This code should only // be called with HTMLTags other than kUnknown. DCHECK_NE(HTMLTag::kUnknown, tag); - for (HTMLElementStack::ElementRecord* pos = top; pos; pos = pos->Next()) { - HTMLStackItem* item = pos->StackItem(); + for (HTMLStackItem* item = top; item; item = item->NextItemInStack()) { if (tag == item->GetHTMLTag() && item->IsHTMLNamespace()) return true; if (isMarker(item)) @@ -486,8 +454,7 @@ bool InScopeCommon(HTMLElementStack::ElementRecord* top, } bool HTMLElementStack::HasNumberedHeaderElementInScope() const { - for (ElementRecord* record = top_.Get(); record; record = record->Next()) { - HTMLStackItem* item = record->StackItem(); + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { if (item->IsNumberedHeaderElement()) return true; if (IsScopeMarker(item)) @@ -498,8 +465,7 @@ bool HTMLElementStack::HasNumberedHeaderElementInScope() const { } bool HTMLElementStack::InScope(Element* target_element) const { - for (ElementRecord* pos = top_.Get(); pos; pos = pos->Next()) { - HTMLStackItem* item = pos->StackItem(); + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { if (item->GetNode() == target_element) return true; if (IsScopeMarker(item)) @@ -557,7 +523,8 @@ void HTMLElementStack::PushCommon(HTMLStackItem* item) { DCHECK(root_node_); stack_depth_++; - top_ = MakeGarbageCollected(item, top_.Release()); + item->SetNextItemInStack(top_.Release()); + top_ = item; } void HTMLElementStack::PopCommon() { @@ -565,7 +532,7 @@ void HTMLElementStack::PopCommon() { DCHECK(!TopStackItem()->HasTagName(html_names::kHeadTag) || !head_element_); DCHECK(!TopStackItem()->HasTagName(html_names::kBodyTag) || !body_element_); Top()->FinishParsingChildren(); - top_ = top_->ReleaseNext(); + top_ = top_->ReleaseNextItemInStack(); stack_depth_--; } @@ -574,12 +541,13 @@ void HTMLElementStack::RemoveNonTopCommon(Element* element) { DCHECK(!IsA(element)); DCHECK(!IsA(element)); DCHECK_NE(Top(), element); - for (ElementRecord* pos = top_.Get(); pos; pos = pos->Next()) { - if (pos->Next()->GetElement() == element) { + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { + if (item->NextItemInStack()->GetElement() == element) { // FIXME: Is it OK to call finishParsingChildren() // when the children aren't actually finished? element->FinishParsingChildren(); - pos->SetNext(pos->Next()->ReleaseNext()); + item->SetNextItemInStack( + item->ReleaseNextItemInStack()->ReleaseNextItemInStack()); stack_depth_--; return; } @@ -587,20 +555,42 @@ void HTMLElementStack::RemoveNonTopCommon(Element* element) { NOTREACHED(); } -HTMLElementStack::ElementRecord* -HTMLElementStack::FurthestBlockForFormattingElement( +HTMLStackItem* HTMLElementStack::FurthestBlockForFormattingElement( Element* formatting_element) const { - ElementRecord* furthest_block = nullptr; - for (ElementRecord* pos = top_.Get(); pos; pos = pos->Next()) { - if (pos->GetElement() == formatting_element) + HTMLStackItem* furthest_block = nullptr; + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { + if (item->GetElement() == formatting_element) { return furthest_block; - if (pos->StackItem()->IsSpecialNode()) - furthest_block = pos; + } + if (item->IsSpecialNode()) { + furthest_block = item; + } } NOTREACHED(); return nullptr; } +void HTMLElementStack::Replace(HTMLStackItem* old_item, + HTMLStackItem* new_item) { + DCHECK(old_item); + DCHECK(new_item); + DCHECK(!new_item->NextItemInStack()); + HTMLStackItem* previous_item = nullptr; + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { + if (item == old_item) { + if (previous_item) { + previous_item->ReleaseNextItemInStack(); + previous_item->SetNextItemInStack(new_item); + } + new_item->SetNextItemInStack(old_item->ReleaseNextItemInStack()); + return; + } + previous_item = item; + } + // This should only be called with items in the stack. + NOTREACHED(); +} + void HTMLElementStack::Trace(Visitor* visitor) const { visitor->Trace(top_); visitor->Trace(root_node_); @@ -611,8 +601,9 @@ void HTMLElementStack::Trace(Visitor* visitor) const { #ifndef NDEBUG void HTMLElementStack::Show() { - for (ElementRecord* record = top_.Get(); record; record = record->Next()) - LOG(INFO) << *record->GetElement(); + for (HTMLStackItem* item = top_.Get(); item; item = item->NextItemInStack()) { + LOG(INFO) << *item->GetElement(); + } } #endif diff --git a/third_party/blink/renderer/core/html/parser/html_element_stack.h b/third_party/blink/renderer/core/html/parser/html_element_stack.h index 0d6a26f95461e4..87ef6fe21b8209 100644 --- a/third_party/blink/renderer/core/html/parser/html_element_stack.h +++ b/third_party/blink/renderer/core/html/parser/html_element_stack.h @@ -46,34 +46,6 @@ class HTMLElementStack { HTMLElementStack(const HTMLElementStack&) = delete; HTMLElementStack& operator=(const HTMLElementStack&) = delete; - class ElementRecord final : public GarbageCollected { - public: - ElementRecord(HTMLStackItem*, ElementRecord*); - ElementRecord(const ElementRecord&) = delete; - ElementRecord& operator=(const ElementRecord&) = delete; - - Element* GetElement() const { return item_->GetElement(); } - ContainerNode* GetNode() const { return item_->GetNode(); } - const AtomicString& NamespaceURI() const { return item_->NamespaceURI(); } - HTMLStackItem* StackItem() const { return item_; } - void ReplaceElement(HTMLStackItem*); - - bool IsAbove(ElementRecord*) const; - - ElementRecord* Next() const { return next_.Get(); } - - void Trace(Visitor*) const; - - private: - friend class HTMLElementStack; - - ElementRecord* ReleaseNext() { return next_.Release(); } - void SetNext(ElementRecord* next) { next_ = next; } - - Member item_; - Member next_; - }; - unsigned StackDepth() const { return stack_depth_; } // Inlining this function is a (small) performance win on the parsing @@ -84,28 +56,29 @@ class HTMLElementStack { } ContainerNode* TopNode() const { + DCHECK(top_); DCHECK(top_->GetNode()); return top_->GetNode(); } HTMLStackItem* TopStackItem() const { - DCHECK(top_->StackItem()); - return top_->StackItem(); + DCHECK(top_); + return top_; } HTMLStackItem* OneBelowTop() const; - ElementRecord* TopRecord() const; - ElementRecord* Find(Element*) const; - ElementRecord* FurthestBlockForFormattingElement(Element*) const; - ElementRecord* Topmost(html_names::HTMLTag tag) const; + HTMLStackItem* Find(Element*) const; + HTMLStackItem* FurthestBlockForFormattingElement(Element*) const; + HTMLStackItem* Topmost(html_names::HTMLTag tag) const; - void InsertAbove(HTMLStackItem*, ElementRecord*); + void InsertAbove(HTMLStackItem*, HTMLStackItem*); void Push(HTMLStackItem*); void PushRootNode(HTMLStackItem*); void PushHTMLHtmlElement(HTMLStackItem*); void PushHTMLHeadElement(HTMLStackItem*); void PushHTMLBodyElement(HTMLStackItem*); + void Replace(HTMLStackItem* old_item, HTMLStackItem* new_item); void Pop(); void PopUntil(html_names::HTMLTag tag); @@ -167,10 +140,10 @@ class HTMLElementStack { void PopCommon(); void RemoveNonTopCommon(Element*); - Member top_; + Member top_; - // We remember the root node, and as they are pushed. Their - // ElementRecords keep them alive. The root node is never popped. + // We remember the root node, and as they are pushed. The root + // node is never popped. // FIXME: We don't currently require type-specific information about these // elements so we haven't yet bothered to plumb the types all the way down // through createElement, etc. diff --git a/third_party/blink/renderer/core/html/parser/html_stack_item.h b/third_party/blink/renderer/core/html/parser/html_stack_item.h index e9b91b43a35faa..282ce3d2b2ff08 100644 --- a/third_party/blink/renderer/core/html/parser/html_stack_item.h +++ b/third_party/blink/renderer/core/html/parser/html_stack_item.h @@ -296,9 +296,38 @@ class HTMLStackItem final : public GarbageCollected { return false; } - void Trace(Visitor* visitor) const { visitor->Trace(node_); } + HTMLStackItem* NextItemInStack() { return next_item_in_stack_; } + + bool IsAboveItemInStack(const HTMLStackItem* item) const { + DCHECK(item); + HTMLStackItem* below = next_item_in_stack_; + while (below) { + if (below == item) { + return true; + } + below = below->NextItemInStack(); + } + return false; + } + + void Trace(Visitor* visitor) const { + visitor->Trace(node_); + visitor->Trace(next_item_in_stack_); + } private: + void SetNextItemInStack(HTMLStackItem* item) { + DCHECK(!item || (item && !next_item_in_stack_)); + next_item_in_stack_ = item; + } + + HTMLStackItem* ReleaseNextItemInStack() { + return next_item_in_stack_.Release(); + } + + // Needed for stack related functions. + friend class HTMLElementStack; + // The attributes are stored directly after the HTMLStackItem in memory // (using Oilpan's AdditionalBytes system). Space for this is guaranteed // by Create(). @@ -313,6 +342,9 @@ class HTMLStackItem final : public GarbageCollected { Member node_; + // This member is maintained by HTMLElementStack. + Member next_item_in_stack_{nullptr}; + HTMLTokenName token_name_; AtomicString namespace_uri_; wtf_size_t num_token_attributes_ = 0; diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc index 3b1d0eac9f6a15..0210b753000f85 100644 --- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc +++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc @@ -494,10 +494,8 @@ bool IsDdOrDt(const HTMLStackItem* item) { template void HTMLTreeBuilder::ProcessCloseWhenNestedTag(AtomicHTMLToken* token) { frameset_ok_ = false; - HTMLElementStack::ElementRecord* node_record = - tree_.OpenElements()->TopRecord(); + HTMLStackItem* item = tree_.OpenElements()->TopStackItem(); while (true) { - HTMLStackItem* item = node_record->StackItem(); if (shouldClose(item)) { DCHECK(item->IsElementNode()); ProcessFakeEndTag(*item); @@ -507,7 +505,7 @@ void HTMLTreeBuilder::ProcessCloseWhenNestedTag(AtomicHTMLToken* token) { !item->MatchesHTMLTag(HTMLTag::kDiv) && !item->MatchesHTMLTag(HTMLTag::kP)) break; - node_record = node_record->Next(); + item = item->NextItemInStack(); } ProcessFakePEndTagIfPInButtonScope(); tree_.InsertHTMLElement(token); @@ -1062,11 +1060,9 @@ bool HTMLTreeBuilder::ProcessTemplateEndTag(AtomicHTMLToken* token) { if (!tree_.CurrentStackItem()->MatchesHTMLTag(HTMLTag::kTemplate)) ParseError(token); tree_.OpenElements()->PopUntil(HTMLTag::kTemplate); - HTMLStackItem* template_stack_item = - tree_.OpenElements()->TopRecord()->StackItem(); + HTMLStackItem* template_stack_item = tree_.OpenElements()->TopStackItem(); tree_.OpenElements()->Pop(); - HTMLStackItem* shadow_host_stack_item = - tree_.OpenElements()->TopRecord()->StackItem(); + HTMLStackItem* shadow_host_stack_item = tree_.OpenElements()->TopStackItem(); tree_.ActiveFormattingElements()->ClearToLastMarker(); template_insertion_modes_.pop_back(); ResetInsertionModeAppropriately(); @@ -1640,9 +1636,8 @@ bool HTMLTreeBuilder::ProcessBodyEndTagForInBody(AtomicHTMLToken* token) { void HTMLTreeBuilder::ProcessAnyOtherEndTagForInBody(AtomicHTMLToken* token) { DCHECK_EQ(token->GetType(), HTMLToken::kEndTag); - HTMLElementStack::ElementRecord* record = tree_.OpenElements()->TopRecord(); + HTMLStackItem* item = tree_.OpenElements()->TopStackItem(); while (true) { - HTMLStackItem* item = record->StackItem(); if (item->MatchesHTMLTag(token->GetTokenName())) { tree_.GenerateImpliedEndTagsWithExclusion(token->GetTokenName()); if (!tree_.CurrentStackItem()->MatchesHTMLTag(token->GetTokenName())) @@ -1654,7 +1649,7 @@ void HTMLTreeBuilder::ProcessAnyOtherEndTagForInBody(AtomicHTMLToken* token) { ParseError(token); return; } - record = record->Next(); + item = item->NextItemInStack(); } } @@ -1698,9 +1693,9 @@ void HTMLTreeBuilder::CallTheAdoptionAgency(AtomicHTMLToken* token) { return; } // 4.b - HTMLElementStack::ElementRecord* formatting_element_record = + HTMLStackItem* formatting_element_item = tree_.OpenElements()->Find(formatting_element); - if (!formatting_element_record) { + if (!formatting_element_item) { ParseError(token); tree_.ActiveFormattingElements()->Remove(formatting_element); return; @@ -1709,7 +1704,7 @@ void HTMLTreeBuilder::CallTheAdoptionAgency(AtomicHTMLToken* token) { if (formatting_element != tree_.CurrentElement()) ParseError(token); // 5. - HTMLElementStack::ElementRecord* furthest_block = + HTMLStackItem* furthest_block = tree_.OpenElements()->FurthestBlockForFormattingElement( formatting_element); // 6. @@ -1719,16 +1714,15 @@ void HTMLTreeBuilder::CallTheAdoptionAgency(AtomicHTMLToken* token) { return; } // 7. - DCHECK(furthest_block->IsAbove(formatting_element_record)); - HTMLStackItem* common_ancestor = - formatting_element_record->Next()->StackItem(); + DCHECK(furthest_block->IsAboveItemInStack(formatting_element_item)); + HTMLStackItem* common_ancestor = formatting_element_item->NextItemInStack(); // 8. HTMLFormattingElementList::Bookmark bookmark = tree_.ActiveFormattingElements()->BookmarkFor(formatting_element); // 9. - HTMLElementStack::ElementRecord* node = furthest_block; - HTMLElementStack::ElementRecord* next_node = node->Next(); - HTMLElementStack::ElementRecord* last_node = furthest_block; + HTMLStackItem* node = furthest_block; + HTMLStackItem* next_node = node->NextItemInStack(); + HTMLStackItem* last_node = furthest_block; // 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop. for (int j = 0; j < kInnerIterationLimit; ++j) { // 9.4 @@ -1736,7 +1730,7 @@ void HTMLTreeBuilder::CallTheAdoptionAgency(AtomicHTMLToken* token) { DCHECK(node); // Save node->next() for the next iteration in case node is deleted in // 9.5. - next_node = node->Next(); + next_node = node->NextItemInStack(); // 9.5 if (!tree_.ActiveFormattingElements()->Contains(node->GetElement())) { tree_.OpenElements()->Remove(node->GetElement()); @@ -1744,16 +1738,17 @@ void HTMLTreeBuilder::CallTheAdoptionAgency(AtomicHTMLToken* token) { continue; } // 9.6 - if (node == formatting_element_record) + if (node == formatting_element_item) { break; + } // 9.7 - HTMLStackItem* new_item = - tree_.CreateElementFromSavedToken(node->StackItem()); + HTMLStackItem* new_item = tree_.CreateElementFromSavedToken(node); HTMLFormattingElementList::Entry* node_entry = tree_.ActiveFormattingElements()->Find(node->GetElement()); node_entry->ReplaceElement(new_item); - node->ReplaceElement(new_item); + tree_.OpenElements()->Replace(node, new_item); + node = new_item; // 9.8 if (last_node == furthest_block) @@ -1766,8 +1761,8 @@ void HTMLTreeBuilder::CallTheAdoptionAgency(AtomicHTMLToken* token) { // 10. tree_.InsertAlreadyParsedChild(common_ancestor, last_node); // 11. - HTMLStackItem* new_item = tree_.CreateElementFromSavedToken( - formatting_element_record->StackItem()); + HTMLStackItem* new_item = + tree_.CreateElementFromSavedToken(formatting_element_item); // 12. tree_.TakeAllChildren(new_item, furthest_block); // 13. @@ -1784,10 +1779,8 @@ void HTMLTreeBuilder::CallTheAdoptionAgency(AtomicHTMLToken* token) { void HTMLTreeBuilder::ResetInsertionModeAppropriately() { // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately bool last = false; - HTMLElementStack::ElementRecord* node_record = - tree_.OpenElements()->TopRecord(); + HTMLStackItem* item = tree_.OpenElements()->TopStackItem(); while (true) { - HTMLStackItem* item = node_record->StackItem(); if (item->GetNode() == tree_.OpenElements()->RootNode()) { last = true; if (IsParsingFragment()) @@ -1802,8 +1795,7 @@ void HTMLTreeBuilder::ResetInsertionModeAppropriately() { if (!last) { while (item->GetNode() != tree_.OpenElements()->RootNode() && !item->MatchesHTMLTag(HTMLTag::kTemplate)) { - node_record = node_record->Next(); - item = node_record->StackItem(); + item = item->NextItemInStack(); if (item->MatchesHTMLTag(HTMLTag::kTable)) return SetInsertionMode(kInSelectInTableMode); } @@ -1847,7 +1839,7 @@ void HTMLTreeBuilder::ResetInsertionModeAppropriately() { DCHECK(IsParsingFragment()); return SetInsertionMode(kInBodyMode); } - node_record = node_record->Next(); + item = item->NextItemInStack(); } } @@ -3020,20 +3012,21 @@ void HTMLTreeBuilder::ProcessTokenInForeignContent(AtomicHTMLToken* token) { } if (!tree_.CurrentStackItem()->IsInHTMLNamespace()) { // FIXME: This code just wants an Element* iterator, instead of an - // ElementRecord* - HTMLElementStack::ElementRecord* node_record = - tree_.OpenElements()->TopRecord(); - if (!node_record->StackItem()->HasLocalName(token->GetName())) + // HTMLStackItem* + HTMLStackItem* item = tree_.OpenElements()->TopStackItem(); + if (!item->HasLocalName(token->GetName())) { ParseError(token); + } while (true) { - if (node_record->StackItem()->HasLocalName(token->GetName())) { - tree_.OpenElements()->PopUntilPopped(node_record->GetElement()); + if (item->HasLocalName(token->GetName())) { + tree_.OpenElements()->PopUntilPopped(item->GetElement()); return; } - node_record = node_record->Next(); + item = item->NextItemInStack(); - if (node_record->StackItem()->IsInHTMLNamespace()) + if (item->IsInHTMLNamespace()) { break; + } } } // Otherwise, process the token according to the rules given in the