瀏覽代碼

dom.pp: Customized memory management, fixes 17 test cases and all memory leaks in testsuite:
* Every node created by Document.CreateXXX method is now guaranteed to be destroyed with the
document, whether it is part of the tree or not. Therefore, DOM methods which remove nodes
from the tree (namely, TDOMNode.RemoveChild, TDOMNode.ReplaceChild,
TDOMElement.SetAttributeNode and TDOMElement.SetAttributeNodeNS) no longer need to destroy
their return value and are now conformant to the specs.
* Nodes are allocated in arrays of instances (emulates 'placement new operator' in C++ terms).
Allocation and freeing are as fast as possible (just assigns a couple of pointers).
* Behaviour of nodes that are created by direct call to constructor is unchanged.

git-svn-id: trunk@13185 -

sergei 16 年之前
父節點
當前提交
733d2c38d5
共有 1 個文件被更改,包括 29 次插入32 次删除
  1. 29 32
      packages/fcl-xml/src/dom.pp

+ 29 - 32
packages/fcl-xml/src/dom.pp

@@ -928,9 +928,7 @@ end;
 
 
 function TDOMNode.RemoveChild(OldChild: TDOMNode): TDOMNode;
 function TDOMNode.RemoveChild(OldChild: TDOMNode): TDOMNode;
 begin
 begin
-  DetachChild(OldChild);
-  OldChild.Free;
-  Result:=nil;
+  Result := DetachChild(OldChild);
 end;
 end;
 
 
 function TDOMNode.AppendChild(NewChild: TDOMNode): TDOMNode;
 function TDOMNode.AppendChild(NewChild: TDOMNode): TDOMNode;
@@ -1248,8 +1246,7 @@ begin
   InsertBefore(NewChild, OldChild);
   InsertBefore(NewChild, OldChild);
   if Assigned(OldChild) then
   if Assigned(OldChild) then
     RemoveChild(OldChild);
     RemoveChild(OldChild);
-  // TODO: per DOM spec, must return OldChild, but OldChild is destroyed
-  Result := NewChild;
+  Result := OldChild;
 end;
 end;
 
 
 function TDOMNode_WithChildren.DetachChild(OldChild: TDOMNode): TDOMNode;
 function TDOMNode_WithChildren.DetachChild(OldChild: TDOMNode): TDOMNode;
@@ -1352,7 +1349,8 @@ end;
 procedure TDOMNode_WithChildren.SetTextContent(const AValue: DOMString);
 procedure TDOMNode_WithChildren.SetTextContent(const AValue: DOMString);
 begin
 begin
   Changing;
   Changing;
-  FreeChildren;
+  while Assigned(FFirstChild) do
+    DetachChild(FFirstChild);
   if AValue <> '' then
   if AValue <> '' then
     AppendChild(FOwnerDocument.CreateTextNode(AValue));
     AppendChild(FOwnerDocument.CreateTextNode(AValue));
 end;
 end;
@@ -1972,31 +1970,36 @@ function TDOMDocument.CreateElement(const tagName: DOMString): TDOMElement;
 begin
 begin
   if not IsXmlName(tagName, FXML11) then
   if not IsXmlName(tagName, FXML11) then
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'DOMDocument.CreateElement');
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'DOMDocument.CreateElement');
-  Result := TDOMElement.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMElement);
+  Result.Create(Self);
   Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(tagName), Length(tagName));
   Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(tagName), Length(tagName));
   // TODO: attach default attributes
   // TODO: attach default attributes
 end;
 end;
 
 
 function TDOMDocument.CreateElementBuf(Buf: DOMPChar; Length: Integer): TDOMElement;
 function TDOMDocument.CreateElementBuf(Buf: DOMPChar; Length: Integer): TDOMElement;
 begin
 begin
-  Result := TDOMElement.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMElement);
+  Result.Create(Self);
   Result.FNSI.QName := FNames.FindOrAdd(Buf, Length);
   Result.FNSI.QName := FNames.FindOrAdd(Buf, Length);
 end;
 end;
 
 
 function TDOMDocument.CreateDocumentFragment: TDOMDocumentFragment;
 function TDOMDocument.CreateDocumentFragment: TDOMDocumentFragment;
 begin
 begin
-  Result := TDOMDocumentFragment.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMDocumentFragment);
+  Result.Create(Self);
 end;
 end;
 
 
 function TDOMDocument.CreateTextNode(const data: DOMString): TDOMText;
 function TDOMDocument.CreateTextNode(const data: DOMString): TDOMText;
 begin
 begin
-  Result := TDOMText.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMText);
+  Result.Create(Self);
   Result.FNodeValue := data;
   Result.FNodeValue := data;
 end;
 end;
 
 
 function TDOMDocument.CreateTextNodeBuf(Buf: DOMPChar; Length: Integer; IgnWS: Boolean): TDOMText;
 function TDOMDocument.CreateTextNodeBuf(Buf: DOMPChar; Length: Integer; IgnWS: Boolean): TDOMText;
 begin
 begin
-  Result := TDOMText.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMText);
+  Result.Create(Self);
   SetString(Result.FNodeValue, Buf, Length);
   SetString(Result.FNodeValue, Buf, Length);
   if IgnWS then
   if IgnWS then
     Include(Result.FFlags, nfIgnorableWS);
     Include(Result.FFlags, nfIgnorableWS);
@@ -2005,13 +2008,15 @@ end;
 
 
 function TDOMDocument.CreateComment(const data: DOMString): TDOMComment;
 function TDOMDocument.CreateComment(const data: DOMString): TDOMComment;
 begin
 begin
-  Result := TDOMComment.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMComment);
+  Result.Create(Self);
   Result.FNodeValue := data;
   Result.FNodeValue := data;
 end;
 end;
 
 
 function TDOMDocument.CreateCommentBuf(Buf: DOMPChar; Length: Integer): TDOMComment;
 function TDOMDocument.CreateCommentBuf(Buf: DOMPChar; Length: Integer): TDOMComment;
 begin
 begin
-  Result := TDOMComment.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMComment);
+  Result.Create(Self);
   SetString(Result.FNodeValue, Buf, Length);
   SetString(Result.FNodeValue, Buf, Length);
 end;
 end;
 
 
@@ -2033,20 +2038,23 @@ function TDOMDocument.CreateAttribute(const name: DOMString): TDOMAttr;
 begin
 begin
   if not IsXmlName(name, FXML11) then
   if not IsXmlName(name, FXML11) then
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'DOMDocument.CreateAttribute');
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'DOMDocument.CreateAttribute');
-  Result := TDOMAttr.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMAttr);
+  Result.Create(Self);
   Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(name), Length(name));
   Result.FNSI.QName := FNames.FindOrAdd(DOMPChar(name), Length(name));
   Include(Result.FFlags, nfSpecified);
   Include(Result.FFlags, nfSpecified);
 end;
 end;
 
 
 function TDOMDocument.CreateAttributeBuf(Buf: DOMPChar; Length: Integer): TDOMAttr;
 function TDOMDocument.CreateAttributeBuf(Buf: DOMPChar; Length: Integer): TDOMAttr;
 begin
 begin
-  Result := TDOMAttr.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMAttr);
+  Result.Create(Self);
   Result.FNSI.QName := FNames.FindOrAdd(buf, Length);
   Result.FNSI.QName := FNames.FindOrAdd(buf, Length);
   Include(Result.FFlags, nfSpecified);
   Include(Result.FFlags, nfSpecified);
 end;
 end;
 
 
 function TDOMDocument.CreateAttributeDef(Buf: DOMPChar; Length: Integer): TDOMAttrDef;
 function TDOMDocument.CreateAttributeDef(Buf: DOMPChar; Length: Integer): TDOMAttrDef;
 begin
 begin
+// not using custom allocation here
   Result := TDOMAttrDef.Create(Self);
   Result := TDOMAttrDef.Create(Self);
   Result.FNSI.QName := FNames.FindOrAdd(Buf, Length);
   Result.FNSI.QName := FNames.FindOrAdd(Buf, Length);
 end;
 end;
@@ -2183,7 +2191,8 @@ end;
 function TXMLDocument.CreateCDATASection(const data: DOMString):
 function TXMLDocument.CreateCDATASection(const data: DOMString):
   TDOMCDATASection;
   TDOMCDATASection;
 begin
 begin
-  Result := TDOMCDATASection.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMCDATASection);
+  Result.Create(Self);
   Result.FNodeValue := data;
   Result.FNodeValue := data;
 end;
 end;
 
 
@@ -2192,7 +2201,8 @@ function TXMLDocument.CreateProcessingInstruction(const target,
 begin
 begin
   if not IsXmlName(target, FXML11) then
   if not IsXmlName(target, FXML11) then
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'XMLDocument.CreateProcessingInstruction');
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'XMLDocument.CreateProcessingInstruction');
-  Result := TDOMProcessingInstruction.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMProcessingInstruction);
+  Result.Create(Self);
   Result.FTarget := target;
   Result.FTarget := target;
   Result.FNodeValue := data;
   Result.FNodeValue := data;
 end;
 end;
@@ -2205,7 +2215,8 @@ var
 begin
 begin
   if not IsXmlName(name, FXML11) then
   if not IsXmlName(name, FXML11) then
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'XMLDocument.CreateEntityReference');
     raise EDOMError.Create(INVALID_CHARACTER_ERR, 'XMLDocument.CreateEntityReference');
-  Result := TDOMEntityReference.Create(Self);
+  TDOMNode(Result) := Alloc(TDOMEntityReference);
+  Result.Create(Self);
   Result.FName := name;
   Result.FName := name;
   dType := DocType;
   dType := DocType;
   if Assigned(dType) then
   if Assigned(dType) then
@@ -2459,25 +2470,11 @@ end;
 function TDOMElement.SetAttributeNode(NewAttr: TDOMAttr): TDOMAttr;
 function TDOMElement.SetAttributeNode(NewAttr: TDOMAttr): TDOMAttr;
 begin
 begin
   Result := Attributes.SetNamedItem(NewAttr) as TDOMAttr;
   Result := Attributes.SetNamedItem(NewAttr) as TDOMAttr;
-
-  // TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
-  if Assigned(Result) and (Result <> NewAttr) then
-  begin
-    Result.Free;
-    Result := nil;
-  end;  
 end;
 end;
 
 
 function TDOMElement.SetAttributeNodeNS(NewAttr: TDOMAttr): TDOMAttr;
 function TDOMElement.SetAttributeNodeNS(NewAttr: TDOMAttr): TDOMAttr;
 begin
 begin
   Result := Attributes.SetNamedItemNS(NewAttr) as TDOMAttr;
   Result := Attributes.SetNamedItemNS(NewAttr) as TDOMAttr;
-
-  // TODO -cConformance: here goes inconsistency with DOM 2 - same as in TDOMNode.RemoveChild
-  if Assigned(Result) and (Result <> NewAttr) then
-  begin
-    Result.Free;
-    Result := nil;
-  end;  
 end;
 end;