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);