diff --git a/parser/html/javasrc/StackNode.java b/parser/html/javasrc/StackNode.java index 9aeaba0be0..305376da38 100644 --- a/parser/html/javasrc/StackNode.java +++ b/parser/html/javasrc/StackNode.java @@ -28,24 +28,29 @@ import nu.validator.htmlparser.annotation.Local; import nu.validator.htmlparser.annotation.NsUri; final class StackNode { - final int flags; + // Index where this stack node is stored in the tree builder's list of stack nodes. + // A value of -1 indicates that the stack node is not owned by a tree builder and + // must delete itself when its refcount reaches 0. + final int idxInTreeBuilder; - final @Local String name; + int flags; - final @Local String popName; + @Local String name; - final @NsUri String ns; + @Local String popName; - final T node; + @NsUri String ns; + + T node; // Only used on the list of formatting elements HtmlAttributes attributes; - private int refcount = 1; + private int refcount = 0; // [NOCPP[ - private final TaintableLocatorImpl locator; + private TaintableLocatorImpl locator; public TaintableLocatorImpl getLocator() { return locator; @@ -85,9 +90,14 @@ final class StackNode { // ]NOCPP] + StackNode(int idxInTreeBuilder) { + this.idxInTreeBuilder = idxInTreeBuilder; + this.refcount = 0; + } + /** - * Constructor for copying. This doesn't take another StackNode - * because in C++ the caller is reponsible for reobtaining the local names + * Setter for copying. This doesn't take another StackNode + * because in C++ the caller is responsible for reobtaining the local names * from another interner. * * @param flags @@ -97,12 +107,13 @@ final class StackNode { * @param popName * @param attributes */ - StackNode(int flags, @NsUri String ns, @Local String name, T node, + void setValues(int flags, @NsUri String ns, @Local String name, T node, @Local String popName, HtmlAttributes attributes // [NOCPP[ , TaintableLocatorImpl locator - // ]NOCPP] + // ]NOCPP] ) { + assert isUnused(); this.flags = flags; this.name = name; this.popName = popName; @@ -121,11 +132,12 @@ final class StackNode { * @param elementName * @param node */ - StackNode(ElementName elementName, T node - // [NOCPP[ + void setValues(ElementName elementName, T node + // [NOCPP[ , TaintableLocatorImpl locator - // ]NOCPP] + // ]NOCPP] ) { + assert isUnused(); this.flags = elementName.getFlags(); this.name = elementName.name; this.popName = elementName.name; @@ -140,17 +152,18 @@ final class StackNode { } /** - * Constructor for HTML formatting elements. + * Setter for HTML formatting elements. * * @param elementName * @param node * @param attributes */ - StackNode(ElementName elementName, T node, HtmlAttributes attributes - // [NOCPP[ + void setValues(ElementName elementName, T node, HtmlAttributes attributes + // [NOCPP[ , TaintableLocatorImpl locator - // ]NOCPP] + // ]NOCPP] ) { + assert isUnused(); this.flags = elementName.getFlags(); this.name = elementName.name; this.popName = elementName.name; @@ -165,17 +178,18 @@ final class StackNode { } /** - * The common-case HTML constructor. + * The common-case HTML setter. * * @param elementName * @param node * @param popName */ - StackNode(ElementName elementName, T node, @Local String popName - // [NOCPP[ + void setValues(ElementName elementName, T node, @Local String popName + // [NOCPP[ , TaintableLocatorImpl locator - // ]NOCPP] + // ]NOCPP] ) { + assert isUnused(); this.flags = elementName.getFlags(); this.name = elementName.name; this.popName = popName; @@ -189,8 +203,8 @@ final class StackNode { } /** - * Constructor for SVG elements. Note that the order of the arguments is - * what distinguishes this from the HTML constructor. This is ugly, but + * Setter for SVG elements. Note that the order of the arguments is + * what distinguishes this from the HTML setter. This is ugly, but * AFAICT the least disruptive way to make this work with Java's generics * and without unnecessary branches. :-( * @@ -198,11 +212,12 @@ final class StackNode { * @param popName * @param node */ - StackNode(ElementName elementName, @Local String popName, T node - // [NOCPP[ + void setValues(ElementName elementName, @Local String popName, T node + // [NOCPP[ , TaintableLocatorImpl locator - // ]NOCPP] + // ]NOCPP] ) { + assert isUnused(); this.flags = prepareSvgFlags(elementName.getFlags()); this.name = elementName.name; this.popName = popName; @@ -216,19 +231,20 @@ final class StackNode { } /** - * Constructor for MathML. + * Setter for MathML. * * @param elementName * @param node * @param popName * @param markAsIntegrationPoint */ - StackNode(ElementName elementName, T node, @Local String popName, + void setValues(ElementName elementName, T node, @Local String popName, boolean markAsIntegrationPoint // [NOCPP[ , TaintableLocatorImpl locator - // ]NOCPP] + // ]NOCPP] ) { + assert isUnused(); this.flags = prepareMathFlags(elementName.getFlags(), markAsIntegrationPoint); this.name = elementName.name; @@ -265,7 +281,7 @@ final class StackNode { } @SuppressWarnings("unused") private void destructor() { - Portability.delete(attributes); + // The translator adds refcount debug code here. } public void dropAttributes() { @@ -286,10 +302,21 @@ final class StackNode { refcount++; } - public void release() { + public void release(TreeBuilder owningTreeBuilder) { refcount--; + assert refcount >= 0; if (refcount == 0) { - Portability.delete(this); + Portability.delete(attributes); + if (idxInTreeBuilder >= 0) { + owningTreeBuilder.notifyUnusedStackNode(idxInTreeBuilder); + } else { + assert owningTreeBuilder == null; + Portability.delete(this); + } } } + + boolean isUnused() { + return refcount == 0; + } } diff --git a/parser/html/javasrc/StateSnapshot.java b/parser/html/javasrc/StateSnapshot.java index ff89e04430..169727021c 100644 --- a/parser/html/javasrc/StateSnapshot.java +++ b/parser/html/javasrc/StateSnapshot.java @@ -193,11 +193,11 @@ public class StateSnapshot implements TreeBuilderState { @SuppressWarnings("unused") private void destructor() { for (int i = 0; i < stack.length; i++) { - stack[i].release(); + stack[i].release(null); } for (int i = 0; i < listOfActiveFormattingElements.length; i++) { if (listOfActiveFormattingElements[i] != null) { - listOfActiveFormattingElements[i].release(); + listOfActiveFormattingElements[i].release(null); } } } diff --git a/parser/html/javasrc/TreeBuilder.java b/parser/html/javasrc/TreeBuilder.java index 5e83d18473..6882084818 100644 --- a/parser/html/javasrc/TreeBuilder.java +++ b/parser/html/javasrc/TreeBuilder.java @@ -425,6 +425,15 @@ public abstract class TreeBuilder implements TokenHandler, */ private int templateModePtr = -1; + private @Auto StackNode[] stackNodes; + + /** + * Index of the earliest possible unused or empty element in stackNodes. + */ + private int stackNodesIdx = -1; + + private int numStackNodes = 0; + private @Auto StackNode[] stack; private int currentPtr = -1; @@ -583,12 +592,15 @@ public abstract class TreeBuilder implements TokenHandler, @SuppressWarnings("unchecked") public final void startTokenization(Tokenizer self) throws SAXException { tokenizer = self; + stackNodes = new StackNode[64]; stack = new StackNode[64]; templateModeStack = new int[64]; listOfActiveFormattingElements = new StackNode[64]; needToDropLF = false; originalMode = INITIAL; templateModePtr = -1; + stackNodesIdx = 0; + numStackNodes = 0; currentPtr = -1; listPtr = -1; formPointer = null; @@ -631,7 +643,7 @@ public abstract class TreeBuilder implements TokenHandler, elementName = ElementName.FOREIGNOBJECT; } // This is the SVG variant of the StackNode constructor. - StackNode node = new StackNode(elementName, + StackNode node = createStackNode(elementName, elementName.camelCaseName, elt // [NOCPP[ , errorHandler == null ? null @@ -662,7 +674,7 @@ public abstract class TreeBuilder implements TokenHandler, // is resolved. } // This is the MathML variant of the StackNode constructor. - StackNode node = new StackNode(elementName, elt, + StackNode node = createStackNode(elementName, elt, elementName.name, false // [NOCPP[ , errorHandler == null ? null @@ -677,7 +689,7 @@ public abstract class TreeBuilder implements TokenHandler, // ends up being allowed as HTML frameset in the fragment case. mode = FRAMESET_OK; } else { // html - StackNode node = new StackNode(ElementName.HTML, elt + StackNode node = createStackNode(ElementName.HTML, elt // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) @@ -720,7 +732,7 @@ public abstract class TreeBuilder implements TokenHandler, // CPPONLY: T elt = createElement("http://www.w3.org/2000/svg", // CPPONLY: "svg", // CPPONLY: tokenizer.emptyAttributes(), null); - // CPPONLY: StackNode node = new StackNode(ElementName.SVG, + // CPPONLY: StackNode node = createStackNode(ElementName.SVG, // CPPONLY: "svg", // CPPONLY: elt); // CPPONLY: currentPtr++; @@ -1623,7 +1635,7 @@ public abstract class TreeBuilder implements TokenHandler, templateModeStack = null; if (stack != null) { while (currentPtr > -1) { - stack[currentPtr].release(); + stack[currentPtr].release(this); currentPtr--; } stack = null; @@ -1631,12 +1643,21 @@ public abstract class TreeBuilder implements TokenHandler, if (listOfActiveFormattingElements != null) { while (listPtr > -1) { if (listOfActiveFormattingElements[listPtr] != null) { - listOfActiveFormattingElements[listPtr].release(); + listOfActiveFormattingElements[listPtr].release(this); } listPtr--; } listOfActiveFormattingElements = null; } + if (stackNodes != null) { + for (int i = 0; i < numStackNodes; i++) { + assert stackNodes[i].isUnused(); + Portability.delete(stackNodes[i]); + } + numStackNodes = 0; + stackNodesIdx = 0; + stackNodes = null; + } // [NOCPP[ idLocations.clear(); // ]NOCPP] @@ -2218,7 +2239,7 @@ public abstract class TreeBuilder implements TokenHandler, if (activeAPos != -1) { removeFromListOfActiveFormattingElements(activeAPos); } - activeA.release(); + activeA.release(this); } reconstructTheActiveFormattingElements(); appendToCurrentNodeAndPushFormattingElementMayFoster( @@ -4626,7 +4647,7 @@ public abstract class TreeBuilder implements TokenHandler, --listPtr; return; } - listOfActiveFormattingElements[listPtr].release(); + listOfActiveFormattingElements[listPtr].release(this); --listPtr; } } @@ -4641,7 +4662,7 @@ public abstract class TreeBuilder implements TokenHandler, pop(); } else { fatal(); - stack[pos].release(); + stack[pos].release(this); System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos); assert debugOnlyClearLastStackSlot(); currentPtr--; @@ -4661,7 +4682,7 @@ public abstract class TreeBuilder implements TokenHandler, return; } fatal(); - node.release(); + node.release(this); System.arraycopy(stack, pos + 1, stack, pos, currentPtr - pos); currentPtr--; } @@ -4669,7 +4690,7 @@ public abstract class TreeBuilder implements TokenHandler, private void removeFromListOfActiveFormattingElements(int pos) { assert listOfActiveFormattingElements[pos] != null; - listOfActiveFormattingElements[pos].release(); + listOfActiveFormattingElements[pos].release(this); if (pos == listPtr) { assert debugOnlyClearLastListSlot(); listPtr--; @@ -4815,7 +4836,7 @@ public abstract class TreeBuilder implements TokenHandler, assert node == stack[nodePos]; T clone = createElement("http://www.w3.org/1999/xhtml", node.name, node.attributes.cloneAttributes(null), commonAncestor.node); - StackNode newNode = new StackNode(node.getFlags(), node.ns, + StackNode newNode = createStackNode(node.getFlags(), node.ns, node.name, clone, node.popName, node.attributes // [NOCPP[ , node.getLocator() @@ -4825,8 +4846,8 @@ public abstract class TreeBuilder implements TokenHandler, stack[nodePos] = newNode; newNode.retain(); // retain for list listOfActiveFormattingElements[nodeListPos] = newNode; - node.release(); // release from stack - node.release(); // release from list + node.release(this); // release from stack + node.release(this); // release from list node = newNode; // } XXX AAA CHANGE detachFromParent(lastNode.node); @@ -4844,7 +4865,7 @@ public abstract class TreeBuilder implements TokenHandler, T clone = createElement("http://www.w3.org/1999/xhtml", formattingElt.name, formattingElt.attributes.cloneAttributes(null), furthestBlock.node); - StackNode formattingClone = new StackNode( + StackNode formattingClone = createStackNode( formattingElt.getFlags(), formattingElt.ns, formattingElt.name, clone, formattingElt.popName, formattingElt.attributes @@ -4987,7 +5008,7 @@ public abstract class TreeBuilder implements TokenHandler, assert headPointer != null; assert mode == AFTER_HEAD; fatal(); - silentPush(new StackNode(ElementName.HEAD, headPointer + silentPush(createStackNode(ElementName.HEAD, headPointer // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) // ]NOCPP] @@ -5034,7 +5055,7 @@ public abstract class TreeBuilder implements TokenHandler, appendElement(clone, currentNode.node); } - StackNode entryClone = new StackNode(entry.getFlags(), + StackNode entryClone = createStackNode(entry.getFlags(), entry.ns, entry.name, clone, entry.popName, entry.attributes // [NOCPP[ @@ -5048,11 +5069,132 @@ public abstract class TreeBuilder implements TokenHandler, // stack takes ownership of the local variable listOfActiveFormattingElements[entryPos] = entryClone; // overwriting the old entry on the list, so release & retain - entry.release(); + entry.release(this); entryClone.retain(); } } + void notifyUnusedStackNode(int idxInStackNodes) { + // stackNodesIdx is the earliest possible index of a stack node that might be unused, + // so update the index if necessary. + if (idxInStackNodes < stackNodesIdx) { + stackNodesIdx = idxInStackNodes; + } + } + + private StackNode getUnusedStackNode() { + // Search for an unused stack node. + while (stackNodesIdx < numStackNodes) { + if (stackNodes[stackNodesIdx].isUnused()) { + return stackNodes[stackNodesIdx++]; + } + stackNodesIdx++; + } + + if (stackNodesIdx < stackNodes.length) { + // No unused stack nodes, but there is still space in the storage array. + stackNodes[stackNodesIdx] = new StackNode(stackNodesIdx); + numStackNodes++; + return stackNodes[stackNodesIdx++]; + } + + // Could not find an unused stack node and storage array is full. + StackNode[] newStack = new StackNode[stackNodes.length + 64]; + System.arraycopy(stackNodes, 0, newStack, 0, stackNodes.length); + stackNodes = newStack; + + // Create a new stack node and return it. + stackNodes[stackNodesIdx] = new StackNode(stackNodesIdx); + numStackNodes++; + return stackNodes[stackNodesIdx++]; + } + + private StackNode createStackNode(int flags, @NsUri String ns, @Local String name, T node, + @Local String popName, HtmlAttributes attributes + // [NOCPP[ + , TaintableLocatorImpl locator + // ]NOCPP] + ) { + StackNode instance = getUnusedStackNode(); + instance.setValues(flags, ns, name, node, popName, attributes + // [NOCPP[ + , locator + // ]NOCPP] + ); + return instance; + } + + private StackNode createStackNode(ElementName elementName, T node + // [NOCPP[ + , TaintableLocatorImpl locator + // ]NOCPP] + ) { + StackNode instance = getUnusedStackNode(); + instance.setValues(elementName, node + // [NOCPP[ + , locator + // ]NOCPP] + ); + return instance; + } + + private StackNode createStackNode(ElementName elementName, T node, HtmlAttributes attributes + // [NOCPP[ + , TaintableLocatorImpl locator + // ]NOCPP] + ) { + StackNode instance = getUnusedStackNode(); + instance.setValues(elementName, node, attributes + // [NOCPP[ + , locator + // ]NOCPP] + ); + return instance; + } + + private StackNode createStackNode(ElementName elementName, T node, @Local String popName + // [NOCPP[ + , TaintableLocatorImpl locator + // ]NOCPP] + ) { + StackNode instance = getUnusedStackNode(); + instance.setValues(elementName, node, popName + // [NOCPP[ + , locator + // ]NOCPP] + ); + return instance; + } + + private StackNode createStackNode(ElementName elementName, @Local String popName, T node + // [NOCPP[ + , TaintableLocatorImpl locator + // ]NOCPP] + ) { + StackNode instance = getUnusedStackNode(); + instance.setValues(elementName, popName, node + // [NOCPP[ + , locator + // ]NOCPP] + ); + return instance; + } + + private StackNode createStackNode(ElementName elementName, T node, @Local String popName, + boolean markAsIntegrationPoint + // [NOCPP[ + , TaintableLocatorImpl locator + // ]NOCPP] + ) { + StackNode instance = getUnusedStackNode(); + instance.setValues(elementName, node, popName, markAsIntegrationPoint + // [NOCPP[ + , locator + // ]NOCPP] + ); + return instance; + } + private void insertIntoFosterParent(T child) throws SAXException { int tablePos = findLastOrRoot(TreeBuilder.TABLE); int templatePos = findLastOrRoot(TreeBuilder.TEMPLATE); @@ -5104,14 +5246,14 @@ public abstract class TreeBuilder implements TokenHandler, assert debugOnlyClearLastStackSlot(); currentPtr--; elementPopped(node.ns, node.popName, node.node); - node.release(); + node.release(this); } private void silentPop() throws SAXException { StackNode node = stack[currentPtr]; assert debugOnlyClearLastStackSlot(); currentPtr--; - node.release(); + node.release(this); } private void popOnEof() throws SAXException { @@ -5120,7 +5262,7 @@ public abstract class TreeBuilder implements TokenHandler, currentPtr--; markMalformedIfScript(node.node); elementPopped(node.ns, node.popName, node.node); - node.release(); + node.release(this); } // [NOCPP[ @@ -5222,7 +5364,7 @@ public abstract class TreeBuilder implements TokenHandler, checkAttributes(attributes, "http://www.w3.org/1999/xhtml"); // ]NOCPP] T elt = createHtmlElementSetAsRoot(attributes); - StackNode node = new StackNode(ElementName.HTML, + StackNode node = createStackNode(ElementName.HTML, elt // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) @@ -5244,7 +5386,7 @@ public abstract class TreeBuilder implements TokenHandler, T elt = createElement("http://www.w3.org/1999/xhtml", "head", attributes, currentNode); appendElement(elt, currentNode); headPointer = elt; - StackNode node = new StackNode(ElementName.HEAD, + StackNode node = createStackNode(ElementName.HEAD, elt // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) @@ -5283,7 +5425,7 @@ public abstract class TreeBuilder implements TokenHandler, formPointer = elt; } - StackNode node = new StackNode(ElementName.FORM, + StackNode node = createStackNode(ElementName.FORM, elt // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) @@ -5311,7 +5453,7 @@ public abstract class TreeBuilder implements TokenHandler, elt = createElement("http://www.w3.org/1999/xhtml", elementName.name, attributes, current.node); appendElement(elt, current.node); } - StackNode node = new StackNode(elementName, elt, clone + StackNode node = createStackNode(elementName, elt, clone // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) // ]NOCPP] @@ -5334,7 +5476,7 @@ public abstract class TreeBuilder implements TokenHandler, if (ElementName.TEMPLATE == elementName) { elt = getDocumentFragmentForTemplate(elt); } - StackNode node = new StackNode(elementName, elt + StackNode node = createStackNode(elementName, elt // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) // ]NOCPP] @@ -5361,7 +5503,7 @@ public abstract class TreeBuilder implements TokenHandler, elt = createElement("http://www.w3.org/1999/xhtml", popName, attributes, current.node); appendElement(elt, current.node); } - StackNode node = new StackNode(elementName, elt, popName + StackNode node = createStackNode(elementName, elt, popName // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) // ]NOCPP] @@ -5395,7 +5537,7 @@ public abstract class TreeBuilder implements TokenHandler, elt = createElement("http://www.w3.org/1998/Math/MathML", popName, attributes, current.node); appendElement(elt, current.node); } - StackNode node = new StackNode(elementName, elt, popName, + StackNode node = createStackNode(elementName, elt, popName, markAsHtmlIntegrationPoint // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) @@ -5444,7 +5586,7 @@ public abstract class TreeBuilder implements TokenHandler, elt = createElement("http://www.w3.org/2000/svg", popName, attributes, current.node); appendElement(elt, current.node); } - StackNode node = new StackNode(elementName, popName, elt + StackNode node = createStackNode(elementName, popName, elt // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) // ]NOCPP] @@ -5471,7 +5613,7 @@ public abstract class TreeBuilder implements TokenHandler, attributes, formOwner, current.node); appendElement(elt, current.node); } - StackNode node = new StackNode(elementName, elt + StackNode node = createStackNode(elementName, elt // [NOCPP[ , errorHandler == null ? null : new TaintableLocatorImpl(tokenizer) // ]NOCPP] @@ -5954,12 +6096,13 @@ public abstract class TreeBuilder implements TokenHandler, for (int i = 0; i < listCopy.length; i++) { StackNode node = listOfActiveFormattingElements[i]; if (node != null) { - StackNode newNode = new StackNode(node.getFlags(), node.ns, + StackNode newNode = new StackNode(-1); + newNode.setValues(node.getFlags(), node.ns, node.name, node.node, node.popName, node.attributes.cloneAttributes(null) // [NOCPP[ , node.getLocator() - // ]NOCPP] + // ]NOCPP] ); listCopy[i] = newNode; } else { @@ -5971,12 +6114,13 @@ public abstract class TreeBuilder implements TokenHandler, StackNode node = stack[i]; int listIndex = findInListOfActiveFormattingElements(node); if (listIndex == -1) { - StackNode newNode = new StackNode(node.getFlags(), node.ns, + StackNode newNode = new StackNode(-1); + newNode.setValues(node.getFlags(), node.ns, node.name, node.node, node.popName, null // [NOCPP[ , node.getLocator() - // ]NOCPP] + // ]NOCPP] ); stackCopy[i] = newNode; } else { @@ -6051,7 +6195,7 @@ public abstract class TreeBuilder implements TokenHandler, for (int i = 0; i <= listPtr; i++) { if (listOfActiveFormattingElements[i] != null) { - listOfActiveFormattingElements[i].release(); + listOfActiveFormattingElements[i].release(this); } } if (listOfActiveFormattingElements.length < listLen) { @@ -6060,7 +6204,7 @@ public abstract class TreeBuilder implements TokenHandler, listPtr = listLen - 1; for (int i = 0; i <= currentPtr; i++) { - stack[i].release(); + stack[i].release(this); } if (stack.length < stackLen) { stack = new StackNode[stackLen]; @@ -6075,7 +6219,7 @@ public abstract class TreeBuilder implements TokenHandler, for (int i = 0; i < listLen; i++) { StackNode node = listCopy[i]; if (node != null) { - StackNode newNode = new StackNode(node.getFlags(), node.ns, + StackNode newNode = createStackNode(node.getFlags(), node.ns, Portability.newLocalFromLocal(node.name, interner), node.node, Portability.newLocalFromLocal(node.popName, interner), node.attributes.cloneAttributes(null) @@ -6092,7 +6236,7 @@ public abstract class TreeBuilder implements TokenHandler, StackNode node = stackCopy[i]; int listIndex = findInArray(node, listCopy); if (listIndex == -1) { - StackNode newNode = new StackNode(node.getFlags(), node.ns, + StackNode newNode = createStackNode(node.getFlags(), node.ns, Portability.newLocalFromLocal(node.name, interner), node.node, Portability.newLocalFromLocal(node.popName, interner), null diff --git a/parser/html/nsHtml5StackNode.cpp b/parser/html/nsHtml5StackNode.cpp index 41163ae40f..ed3767ba2b 100644 --- a/parser/html/nsHtml5StackNode.cpp +++ b/parser/html/nsHtml5StackNode.cpp @@ -85,84 +85,112 @@ nsHtml5StackNode::isHtmlIntegrationPoint() return (flags & NS_HTML5ELEMENT_NAME_HTML_INTEGRATION_POINT); } - -nsHtml5StackNode::nsHtml5StackNode(int32_t flags, int32_t ns, nsIAtom* name, nsIContentHandle* node, nsIAtom* popName, nsHtml5HtmlAttributes* attributes) - : flags(flags), - name(name), - popName(popName), - ns(ns), - node(node), - attributes(attributes), - refcount(1) +nsHtml5StackNode::nsHtml5StackNode(int32_t idxInTreeBuilder) + : idxInTreeBuilder(idxInTreeBuilder) + , refcount(0) { MOZ_COUNT_CTOR(nsHtml5StackNode); } -nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node) - : flags(elementName->getFlags()), - name(elementName->name), - popName(elementName->name), - ns(kNameSpaceID_XHTML), - node(node), - attributes(nullptr), - refcount(1) +void +nsHtml5StackNode::setValues(int32_t flags, + int32_t ns, + nsIAtom* name, + nsIContentHandle* node, + nsIAtom* popName, + nsHtml5HtmlAttributes* attributes) { - MOZ_COUNT_CTOR(nsHtml5StackNode); + MOZ_ASSERT(isUnused()); + this->flags = flags; + this->name = name; + this->popName = popName; + this->ns = ns; + this->node = node; + this->attributes = attributes; + this->refcount = 1; +} + +void +nsHtml5StackNode::setValues(nsHtml5ElementName* elementName, + nsIContentHandle* node) +{ + MOZ_ASSERT(isUnused()); + this->flags = elementName->getFlags(); + this->name = elementName->name; + this->popName = elementName->name; + this->ns = kNameSpaceID_XHTML; + this->node = node; + this->attributes = nullptr; + this->refcount = 1; MOZ_ASSERT(!elementName->isCustom(), "Don't use this constructor for custom elements."); } -nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsHtml5HtmlAttributes* attributes) - : flags(elementName->getFlags()), - name(elementName->name), - popName(elementName->name), - ns(kNameSpaceID_XHTML), - node(node), - attributes(attributes), - refcount(1) +void +nsHtml5StackNode::setValues(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsHtml5HtmlAttributes* attributes) { - MOZ_COUNT_CTOR(nsHtml5StackNode); + MOZ_ASSERT(isUnused()); + this->flags = elementName->getFlags(); + this->name = elementName->name; + this->popName = elementName->name; + this->ns = kNameSpaceID_XHTML; + this->node = node; + this->attributes = attributes; + this->refcount = 1; MOZ_ASSERT(!elementName->isCustom(), "Don't use this constructor for custom elements."); } -nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsIAtom* popName) - : flags(elementName->getFlags()), - name(elementName->name), - popName(popName), - ns(kNameSpaceID_XHTML), - node(node), - attributes(nullptr), - refcount(1) +void +nsHtml5StackNode::setValues(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName) { - MOZ_COUNT_CTOR(nsHtml5StackNode); + MOZ_ASSERT(isUnused()); + this->flags = elementName->getFlags(); + this->name = elementName->name; + this->popName = popName; + this->ns = kNameSpaceID_XHTML; + this->node = node; + this->attributes = nullptr; + this->refcount = 1; } -nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIAtom* popName, nsIContentHandle* node) - : flags(prepareSvgFlags(elementName->getFlags())), - name(elementName->name), - popName(popName), - ns(kNameSpaceID_SVG), - node(node), - attributes(nullptr), - refcount(1) +void +nsHtml5StackNode::setValues(nsHtml5ElementName* elementName, + nsIAtom* popName, + nsIContentHandle* node) { - MOZ_COUNT_CTOR(nsHtml5StackNode); + MOZ_ASSERT(isUnused()); + this->flags = prepareSvgFlags(elementName->getFlags()); + this->name = elementName->name; + this->popName = popName; + this->ns = kNameSpaceID_SVG; + this->node = node; + this->attributes = nullptr; + this->refcount = 1; } -nsHtml5StackNode::nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsIAtom* popName, bool markAsIntegrationPoint) - : flags(prepareMathFlags(elementName->getFlags(), markAsIntegrationPoint)), - name(elementName->name), - popName(popName), - ns(kNameSpaceID_MathML), - node(node), - attributes(nullptr), - refcount(1) +void +nsHtml5StackNode::setValues(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName, + bool markAsIntegrationPoint) { - MOZ_COUNT_CTOR(nsHtml5StackNode); + MOZ_ASSERT(isUnused()); + this->flags = + prepareMathFlags(elementName->getFlags(), markAsIntegrationPoint); + this->name = elementName->name; + this->popName = popName; + this->ns = kNameSpaceID_MathML; + this->node = node; + this->attributes = nullptr; + this->refcount = 1; } int32_t @@ -192,7 +220,6 @@ nsHtml5StackNode::prepareMathFlags(int32_t flags, bool markAsIntegrationPoint) nsHtml5StackNode::~nsHtml5StackNode() { MOZ_COUNT_DTOR(nsHtml5StackNode); - delete attributes; } void @@ -207,15 +234,28 @@ nsHtml5StackNode::retain() refcount++; } -void -nsHtml5StackNode::release() +void +nsHtml5StackNode::release(nsHtml5TreeBuilder* owningTreeBuilder) { refcount--; + MOZ_ASSERT(refcount >= 0); if (!refcount) { - delete this; + delete attributes; + if (idxInTreeBuilder >= 0) { + owningTreeBuilder->notifyUnusedStackNode(idxInTreeBuilder); + } else { + MOZ_ASSERT(!owningTreeBuilder); + delete this; + } } } +bool +nsHtml5StackNode::isUnused() +{ + return !refcount; +} + void nsHtml5StackNode::initializeStatics() { diff --git a/parser/html/nsHtml5StackNode.h b/parser/html/nsHtml5StackNode.h index 1677ec5716..e9f22e03f5 100644 --- a/parser/html/nsHtml5StackNode.h +++ b/parser/html/nsHtml5StackNode.h @@ -60,6 +60,7 @@ class nsHtml5Portability; class nsHtml5StackNode { public: + int32_t idxInTreeBuilder; int32_t flags; nsIAtom* name; nsIAtom* popName; @@ -79,12 +80,28 @@ class nsHtml5StackNode bool isSpecial(); bool isFosterParenting(); bool isHtmlIntegrationPoint(); - nsHtml5StackNode(int32_t flags, int32_t ns, nsIAtom* name, nsIContentHandle* node, nsIAtom* popName, nsHtml5HtmlAttributes* attributes); - nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node); - nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsHtml5HtmlAttributes* attributes); - nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsIAtom* popName); - nsHtml5StackNode(nsHtml5ElementName* elementName, nsIAtom* popName, nsIContentHandle* node); - nsHtml5StackNode(nsHtml5ElementName* elementName, nsIContentHandle* node, nsIAtom* popName, bool markAsIntegrationPoint); + explicit nsHtml5StackNode(int32_t idxInTreeBuilder); + void setValues(int32_t flags, + int32_t ns, + nsIAtom* name, + nsIContentHandle* node, + nsIAtom* popName, + nsHtml5HtmlAttributes* attributes); + void setValues(nsHtml5ElementName* elementName, nsIContentHandle* node); + void setValues(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsHtml5HtmlAttributes* attributes); + void setValues(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName); + void setValues(nsHtml5ElementName* elementName, + nsIAtom* popName, + nsIContentHandle* node); + void setValues(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName, + bool markAsIntegrationPoint); + private: static int32_t prepareSvgFlags(int32_t flags); static int32_t prepareMathFlags(int32_t flags, bool markAsIntegrationPoint); @@ -92,7 +109,8 @@ class nsHtml5StackNode ~nsHtml5StackNode(); void dropAttributes(); void retain(); - void release(); + void release(nsHtml5TreeBuilder* owningTreeBuilder); + bool isUnused(); static void initializeStatics(); static void releaseStatics(); }; diff --git a/parser/html/nsHtml5StateSnapshot.cpp b/parser/html/nsHtml5StateSnapshot.cpp index 90780738b7..05844d78b2 100644 --- a/parser/html/nsHtml5StateSnapshot.cpp +++ b/parser/html/nsHtml5StateSnapshot.cpp @@ -160,11 +160,11 @@ nsHtml5StateSnapshot::~nsHtml5StateSnapshot() { MOZ_COUNT_DTOR(nsHtml5StateSnapshot); for (int32_t i = 0; i < stack.length; i++) { - stack[i]->release(); + stack[i]->release(nullptr); } for (int32_t i = 0; i < listOfActiveFormattingElements.length; i++) { if (listOfActiveFormattingElements[i]) { - listOfActiveFormattingElements[i]->release(); + listOfActiveFormattingElements[i]->release(nullptr); } } } diff --git a/parser/html/nsHtml5TreeBuilder.cpp b/parser/html/nsHtml5TreeBuilder.cpp index 457c7deb11..30cc2a699e 100644 --- a/parser/html/nsHtml5TreeBuilder.cpp +++ b/parser/html/nsHtml5TreeBuilder.cpp @@ -75,12 +75,15 @@ void nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) { tokenizer = self; + stackNodes = jArray::newJArray(64); stack = jArray::newJArray(64); templateModeStack = jArray::newJArray(64); listOfActiveFormattingElements = jArray::newJArray(64); needToDropLF = false; originalMode = NS_HTML5TREE_BUILDER_INITIAL; templateModePtr = -1; + stackNodesIdx = 0; + numStackNodes = 0; currentPtr = -1; listPtr = -1; formPointer = nullptr; @@ -102,7 +105,7 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) if (nsHtml5Atoms::title == contextName || nsHtml5Atoms::desc == contextName || nsHtml5Atoms::foreignObject == contextName) { elementName = nsHtml5ElementName::ELT_FOREIGNOBJECT; } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elementName->camelCaseName, elt); + nsHtml5StackNode* node = createStackNode(elementName, elementName->camelCaseName, elt); currentPtr++; stack[currentPtr] = node; tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName); @@ -114,13 +117,13 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) } else if (nsHtml5Atoms::annotation_xml == contextName) { elementName = nsHtml5ElementName::ELT_ANNOTATION_XML; } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, elementName->name, false); + nsHtml5StackNode* node = createStackNode(elementName, elt, elementName->name, false); currentPtr++; stack[currentPtr] = node; tokenizer->setStateAndEndTagExpectation(NS_HTML5TOKENIZER_DATA, contextName); mode = NS_HTML5TREE_BUILDER_FRAMESET_OK; } else { - nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HTML, elt); + nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HTML, elt); currentPtr++; stack[currentPtr] = node; if (nsHtml5Atoms::template_ == contextName) { @@ -146,7 +149,7 @@ nsHtml5TreeBuilder::startTokenization(nsHtml5Tokenizer* self) mode = NS_HTML5TREE_BUILDER_INITIAL; if (tokenizer->isViewingXmlSource()) { nsIContentHandle* elt = createElement(kNameSpaceID_SVG, nsHtml5Atoms::svg, tokenizer->emptyAttributes(), nullptr); - nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_SVG, nsHtml5Atoms::svg, elt); + nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_SVG, nsHtml5Atoms::svg, elt); currentPtr++; stack[currentPtr] = node; } @@ -584,7 +587,7 @@ nsHtml5TreeBuilder::endTokenization() templateModeStack = nullptr; if (stack) { while (currentPtr > -1) { - stack[currentPtr]->release(); + stack[currentPtr]->release(this); currentPtr--; } stack = nullptr; @@ -592,12 +595,21 @@ nsHtml5TreeBuilder::endTokenization() if (listOfActiveFormattingElements) { while (listPtr > -1) { if (listOfActiveFormattingElements[listPtr]) { - listOfActiveFormattingElements[listPtr]->release(); + listOfActiveFormattingElements[listPtr]->release(this); } listPtr--; } listOfActiveFormattingElements = nullptr; } + if (stackNodes) { + for (int32_t i = 0; i < numStackNodes; i++) { + MOZ_ASSERT(stackNodes[i]->isUnused()); + delete stackNodes[i]; + } + numStackNodes = 0; + stackNodesIdx = 0; + stackNodes = nullptr; + } charBuffer = nullptr; end(); } @@ -1134,7 +1146,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu if (activeAPos != -1) { removeFromListOfActiveFormattingElements(activeAPos); } - activeA->release(); + activeA->release(this); } reconstructTheActiveFormattingElements(); appendToCurrentNodeAndPushFormattingElementMayFoster(elementName, attributes); @@ -3505,7 +3517,7 @@ nsHtml5TreeBuilder::clearTheListOfActiveFormattingElementsUpToTheLastMarker() --listPtr; return; } - listOfActiveFormattingElements[listPtr]->release(); + listOfActiveFormattingElements[listPtr]->release(this); --listPtr; } } @@ -3517,7 +3529,7 @@ nsHtml5TreeBuilder::removeFromStack(int32_t pos) pop(); } else { - stack[pos]->release(); + stack[pos]->release(this); nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos); MOZ_ASSERT(debugOnlyClearLastStackSlot()); currentPtr--; @@ -3538,7 +3550,7 @@ nsHtml5TreeBuilder::removeFromStack(nsHtml5StackNode* node) return; } - node->release(); + node->release(this); nsHtml5ArrayCopy::arraycopy(stack, pos + 1, pos, currentPtr - pos); currentPtr--; } @@ -3548,7 +3560,7 @@ void nsHtml5TreeBuilder::removeFromListOfActiveFormattingElements(int32_t pos) { MOZ_ASSERT(!!listOfActiveFormattingElements[pos]); - listOfActiveFormattingElements[pos]->release(); + listOfActiveFormattingElements[pos]->release(this); if (pos == listPtr) { MOZ_ASSERT(debugOnlyClearLastListSlot()); listPtr--; @@ -3660,13 +3672,18 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name) MOZ_ASSERT(node == listOfActiveFormattingElements[nodeListPos]); MOZ_ASSERT(node == stack[nodePos]); nsIContentHandle* clone = createElement(kNameSpaceID_XHTML, node->name, node->attributes->cloneAttributes(nullptr), commonAncestor->node); - nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, node->name, clone, node->popName, node->attributes); + nsHtml5StackNode* newNode = createStackNode(node->getFlags(), + node->ns, + node->name, + clone, + node->popName, + node->attributes); node->dropAttributes(); stack[nodePos] = newNode; newNode->retain(); listOfActiveFormattingElements[nodeListPos] = newNode; - node->release(); - node->release(); + node->release(this); + node->release(this); node = newNode; detachFromParent(lastNode->node); appendElement(lastNode->node, node->node); @@ -3681,7 +3698,13 @@ nsHtml5TreeBuilder::adoptionAgencyEndTag(nsIAtom* name) appendElement(lastNode->node, commonAncestor->node); } nsIContentHandle* clone = createElement(kNameSpaceID_XHTML, formattingElt->name, formattingElt->attributes->cloneAttributes(nullptr), furthestBlock->node); - nsHtml5StackNode* formattingClone = new nsHtml5StackNode(formattingElt->getFlags(), formattingElt->ns, formattingElt->name, clone, formattingElt->popName, formattingElt->attributes); + nsHtml5StackNode* formattingClone = + createStackNode(formattingElt->getFlags(), + formattingElt->ns, + formattingElt->name, + clone, + formattingElt->popName, + formattingElt->attributes); formattingElt->dropAttributes(); appendChildrenToNewParent(furthestBlock->node, clone); appendElement(clone, furthestBlock->node); @@ -3812,7 +3835,7 @@ nsHtml5TreeBuilder::pushHeadPointerOntoStack() MOZ_ASSERT(!!headPointer); MOZ_ASSERT(mode == NS_HTML5TREE_BUILDER_AFTER_HEAD); - silentPush(new nsHtml5StackNode(nsHtml5ElementName::ELT_HEAD, headPointer)); + silentPush(createStackNode(nsHtml5ElementName::ELT_HEAD, headPointer)); } void @@ -3849,16 +3872,110 @@ nsHtml5TreeBuilder::reconstructTheActiveFormattingElements() clone = createElement(kNameSpaceID_XHTML, entry->name, entry->attributes->cloneAttributes(nullptr), currentNode->node); appendElement(clone, currentNode->node); } - nsHtml5StackNode* entryClone = new nsHtml5StackNode(entry->getFlags(), entry->ns, entry->name, clone, entry->popName, entry->attributes); + nsHtml5StackNode* entryClone = createStackNode(entry->getFlags(), entry->ns, entry->name, clone, entry->popName, entry->attributes); entry->dropAttributes(); push(entryClone); listOfActiveFormattingElements[entryPos] = entryClone; - entry->release(); + entry->release(this); entryClone->retain(); } } -void +void +nsHtml5TreeBuilder::notifyUnusedStackNode(int32_t idxInStackNodes) +{ + if (idxInStackNodes < stackNodesIdx) { + stackNodesIdx = idxInStackNodes; + } +} + +nsHtml5StackNode* +nsHtml5TreeBuilder::getUnusedStackNode() +{ + while (stackNodesIdx < numStackNodes) { + if (stackNodes[stackNodesIdx]->isUnused()) { + return stackNodes[stackNodesIdx++]; + } + stackNodesIdx++; + } + if (stackNodesIdx < stackNodes.length) { + stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx); + numStackNodes++; + return stackNodes[stackNodesIdx++]; + } + jArray newStack = + jArray::newJArray(stackNodes.length + 64); + nsHtml5ArrayCopy::arraycopy(stackNodes, newStack, stackNodes.length); + stackNodes = newStack; + stackNodes[stackNodesIdx] = new nsHtml5StackNode(stackNodesIdx); + numStackNodes++; + return stackNodes[stackNodesIdx++]; +} + +nsHtml5StackNode* +nsHtml5TreeBuilder::createStackNode(int32_t flags, + int32_t ns, + nsIAtom* name, + nsIContentHandle* node, + nsIAtom* popName, + nsHtml5HtmlAttributes* attributes) +{ + nsHtml5StackNode* instance = getUnusedStackNode(); + instance->setValues(flags, ns, name, node, popName, attributes); + return instance; +} + +nsHtml5StackNode* +nsHtml5TreeBuilder::createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node) +{ + nsHtml5StackNode* instance = getUnusedStackNode(); + instance->setValues(elementName, node); + return instance; +} + +nsHtml5StackNode* +nsHtml5TreeBuilder::createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsHtml5HtmlAttributes* attributes) +{ + nsHtml5StackNode* instance = getUnusedStackNode(); + instance->setValues(elementName, node, attributes); + return instance; +} + +nsHtml5StackNode* +nsHtml5TreeBuilder::createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName) +{ + nsHtml5StackNode* instance = getUnusedStackNode(); + instance->setValues(elementName, node, popName); + return instance; +} + +nsHtml5StackNode* +nsHtml5TreeBuilder::createStackNode(nsHtml5ElementName* elementName, + nsIAtom* popName, + nsIContentHandle* node) +{ + nsHtml5StackNode* instance = getUnusedStackNode(); + instance->setValues(elementName, popName, node); + return instance; +} + +nsHtml5StackNode* +nsHtml5TreeBuilder::createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName, + bool markAsIntegrationPoint) +{ + nsHtml5StackNode* instance = getUnusedStackNode(); + instance->setValues(elementName, node, popName, markAsIntegrationPoint); + return instance; +} + +void nsHtml5TreeBuilder::insertIntoFosterParent(nsIContentHandle* child) { int32_t tablePos = findLastOrRoot(NS_HTML5TREE_BUILDER_TABLE); @@ -3915,7 +4032,7 @@ nsHtml5TreeBuilder::pop() MOZ_ASSERT(debugOnlyClearLastStackSlot()); currentPtr--; elementPopped(node->ns, node->popName, node->node); - node->release(); + node->release(this); } void @@ -3924,7 +4041,7 @@ nsHtml5TreeBuilder::silentPop() nsHtml5StackNode* node = stack[currentPtr]; MOZ_ASSERT(debugOnlyClearLastStackSlot()); currentPtr--; - node->release(); + node->release(this); } void @@ -3935,14 +4052,14 @@ nsHtml5TreeBuilder::popOnEof() currentPtr--; markMalformedIfScript(node->node); elementPopped(node->ns, node->popName, node->node); - node->release(); + node->release(this); } void nsHtml5TreeBuilder::appendHtmlElementToDocumentAndPush(nsHtml5HtmlAttributes* attributes) { nsIContentHandle* elt = createHtmlElementSetAsRoot(attributes); - nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HTML, elt); + nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HTML, elt); push(node); } @@ -3959,7 +4076,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushHeadElement(nsHtml5HtmlAttributes* nsIContentHandle* elt = createElement(kNameSpaceID_XHTML, nsHtml5Atoms::head, attributes, currentNode); appendElement(elt, currentNode); headPointer = elt; - nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_HEAD, elt); + nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_HEAD, elt); push(node); } @@ -3990,7 +4107,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormElementMayFoster(nsHtml5HtmlAt if (!isTemplateContents()) { formPointer = elt; } - nsHtml5StackNode* node = new nsHtml5StackNode(nsHtml5ElementName::ELT_FORM, elt); + nsHtml5StackNode* node = createStackNode(nsHtml5ElementName::ELT_FORM, elt); push(node); } @@ -4007,7 +4124,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushFormattingElementMayFoster(nsHtml5 elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes, current->node); appendElement(elt, current->node); } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, clone); + nsHtml5StackNode* node = createStackNode(elementName, elt, clone); push(node); append(node); node->retain(); @@ -4022,7 +4139,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElement(nsHtml5ElementName* elemen if (nsHtml5ElementName::ELT_TEMPLATE == elementName) { elt = getDocumentFragmentForTemplate(elt); } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt); + nsHtml5StackNode* node = createStackNode(elementName, elt); push(node); } @@ -4039,7 +4156,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementNam elt = createElement(kNameSpaceID_XHTML, popName, attributes, current->node); appendElement(elt, current->node); } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, popName); + nsHtml5StackNode* node = createStackNode(elementName, elt, popName); push(node); } @@ -4060,7 +4177,8 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterMathML(nsHtml5Elem elt = createElement(kNameSpaceID_MathML, popName, attributes, current->node); appendElement(elt, current->node); } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt, popName, markAsHtmlIntegrationPoint); + nsHtml5StackNode* node = + createStackNode(elementName, elt, popName, markAsHtmlIntegrationPoint); push(node); } @@ -4088,7 +4206,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFosterSVG(nsHtml5Element elt = createElement(kNameSpaceID_SVG, popName, attributes, current->node); appendElement(elt, current->node); } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, popName, elt); + nsHtml5StackNode* node = createStackNode(elementName, popName, elt); push(node); } @@ -4105,7 +4223,7 @@ nsHtml5TreeBuilder::appendToCurrentNodeAndPushElementMayFoster(nsHtml5ElementNam elt = createElement(kNameSpaceID_XHTML, elementName->name, attributes, formOwner, current->node); appendElement(elt, current->node); } - nsHtml5StackNode* node = new nsHtml5StackNode(elementName, elt); + nsHtml5StackNode* node = createStackNode(elementName, elt); push(node); } @@ -4309,7 +4427,13 @@ nsHtml5TreeBuilder::newSnapshot() for (int32_t i = 0; i < listCopy.length; i++) { nsHtml5StackNode* node = listOfActiveFormattingElements[i]; if (node) { - nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, node->name, node->node, node->popName, node->attributes->cloneAttributes(nullptr)); + nsHtml5StackNode* newNode = new nsHtml5StackNode(-1); + newNode->setValues(node->getFlags(), + node->ns, + node->name, + node->node, + node->popName, + node->attributes->cloneAttributes(nullptr)); listCopy[i] = newNode; } else { listCopy[i] = nullptr; @@ -4320,7 +4444,13 @@ nsHtml5TreeBuilder::newSnapshot() nsHtml5StackNode* node = stack[i]; int32_t listIndex = findInListOfActiveFormattingElements(node); if (listIndex == -1) { - nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, node->name, node->node, node->popName, nullptr); + nsHtml5StackNode* newNode = new nsHtml5StackNode(-1); + newNode->setValues(node->getFlags(), + node->ns, + node->name, + node->node, + node->popName, + nullptr); stackCopy[i] = newNode; } else { stackCopy[i] = listCopy[listIndex]; @@ -4378,7 +4508,7 @@ nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot, nsHtml5AtomTab int32_t templateModeStackLen = snapshot->getTemplateModeStackLength(); for (int32_t i = 0; i <= listPtr; i++) { if (listOfActiveFormattingElements[i]) { - listOfActiveFormattingElements[i]->release(); + listOfActiveFormattingElements[i]->release(this); } } if (listOfActiveFormattingElements.length < listLen) { @@ -4386,7 +4516,7 @@ nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot, nsHtml5AtomTab } listPtr = listLen - 1; for (int32_t i = 0; i <= currentPtr; i++) { - stack[i]->release(); + stack[i]->release(this); } if (stack.length < stackLen) { stack = jArray::newJArray(stackLen); @@ -4399,7 +4529,13 @@ nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot, nsHtml5AtomTab for (int32_t i = 0; i < listLen; i++) { nsHtml5StackNode* node = listCopy[i]; if (node) { - nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, nsHtml5Portability::newLocalFromLocal(node->name, interner), node->node, nsHtml5Portability::newLocalFromLocal(node->popName, interner), node->attributes->cloneAttributes(nullptr)); + nsHtml5StackNode* newNode = createStackNode( + node->getFlags(), + node->ns, + nsHtml5Portability::newLocalFromLocal(node->name, interner), + node->node, + nsHtml5Portability::newLocalFromLocal(node->popName, interner), + node->attributes->cloneAttributes(nullptr)); listOfActiveFormattingElements[i] = newNode; } else { listOfActiveFormattingElements[i] = nullptr; @@ -4409,7 +4545,13 @@ nsHtml5TreeBuilder::loadState(nsAHtml5TreeBuilderState* snapshot, nsHtml5AtomTab nsHtml5StackNode* node = stackCopy[i]; int32_t listIndex = findInArray(node, listCopy); if (listIndex == -1) { - nsHtml5StackNode* newNode = new nsHtml5StackNode(node->getFlags(), node->ns, nsHtml5Portability::newLocalFromLocal(node->name, interner), node->node, nsHtml5Portability::newLocalFromLocal(node->popName, interner), nullptr); + nsHtml5StackNode* newNode = createStackNode( + node->getFlags(), + node->ns, + nsHtml5Portability::newLocalFromLocal(node->name, interner), + node->node, + nsHtml5Portability::newLocalFromLocal(node->popName, interner), + nullptr); stack[i] = newNode; } else { stack[i] = listOfActiveFormattingElements[listIndex]; diff --git a/parser/html/nsHtml5TreeBuilder.h b/parser/html/nsHtml5TreeBuilder.h index 67f5010c5d..9e4e50fcfb 100644 --- a/parser/html/nsHtml5TreeBuilder.h +++ b/parser/html/nsHtml5TreeBuilder.h @@ -88,6 +88,9 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState nsIContentHandle* contextNode; autoJArray templateModeStack; int32_t templateModePtr; + autoJArray stackNodes; + int32_t stackNodesIdx; + int32_t numStackNodes; autoJArray stack; int32_t currentPtr; autoJArray listOfActiveFormattingElements; @@ -187,6 +190,33 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState void addAttributesToHtml(nsHtml5HtmlAttributes* attributes); void pushHeadPointerOntoStack(); void reconstructTheActiveFormattingElements(); + + public: + void notifyUnusedStackNode(int32_t idxInStackNodes); + + private: + nsHtml5StackNode* getUnusedStackNode(); + nsHtml5StackNode* createStackNode(int32_t flags, + int32_t ns, + nsIAtom* name, + nsIContentHandle* node, + nsIAtom* popName, + nsHtml5HtmlAttributes* attributes); + nsHtml5StackNode* createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node); + nsHtml5StackNode* createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsHtml5HtmlAttributes* attributes); + nsHtml5StackNode* createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName); + nsHtml5StackNode* createStackNode(nsHtml5ElementName* elementName, + nsIAtom* popName, + nsIContentHandle* node); + nsHtml5StackNode* createStackNode(nsHtml5ElementName* elementName, + nsIContentHandle* node, + nsIAtom* popName, + bool markAsIntegrationPoint); void insertIntoFosterParent(nsIContentHandle* child); nsIContentHandle* createAndInsertFosterParentedElement(int32_t ns, nsIAtom* name, nsHtml5HtmlAttributes* attributes); nsIContentHandle* createAndInsertFosterParentedElement(int32_t ns, nsIAtom* name, nsHtml5HtmlAttributes* attributes, nsIContentHandle* form);