* coding/RefPtr.html: Added. First draft of a document about RefPtr.
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Mar 2007 06:38:56 +0000 (06:38 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Mar 2007 06:38:56 +0000 (06:38 +0000)
        Also tweaked the MIME types of a few files and removed a stray executable bit.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@20481 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitSite/ChangeLog
WebKitSite/coding/RefPtr.html [new file with mode: 0644]
WebKitSite/specs/movie-status-states.png [changed mode: 0755->0644]

index dc76315..ac479f9 100644 (file)
@@ -1,12 +1,14 @@
-2007-03-21  David Kilzer  <ddkilzer@apple.com>
+2007-03-24  Darin Adler  <darin@apple.com>
 
 
-        Reviewed by NOBODY (more word tweaking).
+        * coding/RefPtr.html: Added. First draft of a document about RefPtr.
 
 
-        * building/checkout.html: By popular demand, the link to the svn 1.3 client has been removed.
+        Also tweaked the MIME types of a few files and removed a stray executable bit.
 
 2007-03-21  David Kilzer  <ddkilzer@apple.com>
 
 
 2007-03-21  David Kilzer  <ddkilzer@apple.com>
 
-        Reviewed by NOBODY (tweaked wording).
+        * building/checkout.html: By popular demand, the link to the svn 1.3 client has been removed.
+
+2007-03-21  David Kilzer  <ddkilzer@apple.com>
 
         * building/checkout.html: Got rid of "click here" link and restructured sentences
         linking to svn clients.
 
         * building/checkout.html: Got rid of "click here" link and restructured sentences
         linking to svn clients.
diff --git a/WebKitSite/coding/RefPtr.html b/WebKitSite/coding/RefPtr.html
new file mode 100644 (file)
index 0000000..c22eb2a
--- /dev/null
@@ -0,0 +1,370 @@
+<?php 
+    $title="WebKit RefPtr and PassRefPtr Basics";
+    include("../header.inc"); 
+?>
+
+<style type="text/css">
+    .code {
+        background-color: #eee;
+        padding: 1em;
+        margin-left: 2em;
+        margin-right: 2em;
+        overflow-x: auto;
+    }
+    .comment {
+        font-style: italic;
+    }
+    p .function, p .class, p .variable, li .function, li .class, li .variable {
+        font-style: italic;
+    }
+</style>
+
+<h1>WebKit <span class="class">RefPtr</span> and <span class="class">PassRefPtr</span> Basics</h1>
+<div>Darin Adler</div>
+<div>first draft, 2007-03-24</div>
+
+<h2>History</h2>
+
+<p>Many objects in WebKit are reference counted. The pattern used is that classes have
+member functions <span class="function">ref</span> and <span class="function">deref</span>
+that increment and decrement the reference count. Each call to <span class="function">ref</span>
+has to be matched by a call to <span class="function">deref</span>. When the reference count hits 0,
+the object is deleted. Many of these classes create new objects with a reference count of 0; this
+is referred to as the floating state. An object in floating state must have <span class="function">ref</span> and then
+<span class="function">deref</span> called on it before it will be deleted. Many classes in WebCore implement this by
+inheriting from the <span class="class">Shared</span> class template.</p>
+
+<p>Back in 2005, we discovered that there were many memory leaks, especially in WebCore
+editor code, caused either by mismatches of <span class="function">ref</span> and
+<span class="function">deref</span> calls or by objects that were created with new
+that never got a <span class="function">ref</span> call at all that remained in the floating state.</p>
+
+<p>We decided that we’d like
+to use smart pointers to mitigate the problem. However, some early experiments showed that
+smart pointers led to additional manipulation of reference counts that hurt performance.
+For example, if a function took a smart pointer as a parameter and returned that same smart
+pointer as a return value, just passing the parameter and returning the value would increment
+and then decrement the reference count two to four times
+as the object moved from one smart pointer to another. So we looked for an
+idiom that would let us use smart pointers and avoid this reference count churn.</p>
+
+<p>The inspiration for a solution came from the C++ standard class template <span class="class">std::auto_ptr</span>.
+These objects implement a model where assignment is transfer of ownership. When you assign
+from one <span class="class">auto_ptr</span> to another, the donor becomes 0.</p>
+
+<p>Maciej Stachowiak devised a pair of class templates, <span class="class">RefPtr</span>
+and <span class="class">PassRefPtr</span>, that implement this scheme
+for WebCore’s intrusive reference counting.</p>
+
+<h2>Raw pointers</h2>
+
+<p>When discussing smart pointer such as the <span class="class">RefPtr</span>
+class template we use the term raw pointer to refer to the C++ language’s built in pointer type.
+Here’s the canonical setter function, written with raw pointers:</p>
+
+<pre class="code"><span class="comment">// example, not preferred style</span>
+
+class Document {
+    <span class="comment">[...]</span>
+    Title* m_title;
+}
+
+Document::Document()
+    : m_title(0)
+{
+}
+
+Document::~Document()
+{
+    if (m_title)
+        m_title-&gt;deref();
+}
+
+void Document::setTitle(Title* t)
+{
+    if (t)
+        t-&gt;ref();
+    if (m_title)
+        m_title-&gt;deref();
+    m_title = t;
+}</pre>
+
+<h2><span class="class">RefPtr</span></h2>
+
+<p><span class="class">RefPtr</span> is a simple smart pointer class that calls <span class="function">ref</span>
+on incoming values and
+<span class="function">deref</span> on outgoing values.
+<span class="class">RefPtr</span> works on any object with both a <span class="function">ref</span> and
+a <span class="function">deref</span> member function.
+Here’s the setter function example, written with <span class="class">RefPtr</span>:</p>
+
+<pre class="code"><span class="comment">// example, not preferred style</span>
+class Document {
+    <span class="comment">[...]</span>
+    RefPtr&lt;Title&gt; m_title;
+}
+
+void Document::setTitle(Title* t)
+{
+    m_title = t;
+}</pre>
+
+<p>Use of <span class="class">RefPtr</span> alone can lead to reference count churn.</p>
+
+<pre class="code"><span class="comment">// example, not preferred style</span>
+RefPtr&lt;Node&gt; createSpecialNode()
+{
+    RefPtr&lt;Node&gt; a = new Node;
+    a-&gt;setSpecial(true);
+    return a;
+}
+
+RefPtr&lt;Node&gt; b = createSpecialNode();</pre>
+
+<p>The node object starts with a reference count of 0. When it’s assigned to <span class="variable">a</span>,
+the reference count is incremented to 1. The reference count is incremented to 2 to
+create the return value, then decremented back to 1 when <span class="variable">a</span> is destroyed.
+Then the reference count is incremented to 2 to create <span class="variable">b</span>, and then decremented back
+to 1 when the return value of <span class="function">createSpecialNode</span> is destroyed.</p>
+
+<p>(This analysis ignores the possibility that the compiler might implement the
+<a href="http://www.awprofessional.com/articles/article.asp?p=25033&seqNum=3&rl=1">return value optimization</a>.
+If the compiler does, some of the reference count churn may be mitigated.)</p>
+
+<p>The overhead of reference count churn is even greater when both function arguments and return
+values are involved. The solution is <span class="class">PassRefPtr</span>.</p>
+
+<h2><span class="class">PassRefPtr</span></h2>
+
+<p><span class="class">PassRefPtr</span> is like <span class="class">RefPtr</span> with a difference.
+When you copy a <span class="class">PassRefPtr</span> or
+assign the value of a <span class="class">PassRefPtr</span> to a <span class="class">RefPtr</span> or
+another <span class="class">PassRefPtr</span>, the original
+pointer value is set to 0; the operation is done without any change to the reference count.
+Lets take a look at a new version of our example:</p>
+
+<pre class="code"><span class="comment">// example, not preferred style<span>
+
+PassRefPtr&lt;Node&gt; createSpecialNode()
+{
+    PassRefPtr&lt;Node&gt; a = new Node;
+    a-&gt;setSpecial(true);
+    return a;
+}
+
+RefPtr&lt;Node&gt; b = createSpecialNode();</pre>
+
+<p>The node object starts with a reference count of 0. When it’s assigned to <span class="variable">a</span>,
+the reference count is incremented to 1. Then <span class="variable">a</span> gets set to 0 when the return
+value <span class="class">PassRefPtr</span> is created. Then the return value is set to 0 when
+<span class="variable">b</span> is created.</p>
+
+<p>However, as the Safari team learned when we started programming with <span class="class">PassRefPtr</span>,
+the rule that a pointer becomes 0 when it’s assigned to another variable can easily lead to mistakes.</p>
+
+<pre class="code"><span class="comment">// example, not preferred style</span>
+static RefPtr&lt;Ring&gt; g_oneRingToRuleThemAll;
+
+void finish(PassRefPtr&lt;Ring&gt; ring)
+{
+    g_oneRingToRuleThemAll = ring;
+    <span class="comment">...</span>
+    ring-&gt;wear();
+}</pre>
+
+<p>By the time <span class="function">wear</span> is called, <span class="variable">ring</span>
+is already 0. To avoid this, we recommend <span class="class">PassRefPtr</span> only for
+function argument and result types, copying arguments into <span class="class">RefPtr</span>
+local variables.</p>
+
+<pre class="code">static RefPtr&lt;Ring&gt; g_oneRingToRuleThemAll;
+
+void finish(PassRefPtr&lt;Ring&gt; prpRing)
+{
+    RefPtr&lt;Ring&gt; ring = prpRing;
+    g_oneRingToRuleThemAll = ring;
+    <span class="comment">...</span>
+    ring-&gt;wear();
+}</pre>
+
+<h2>Mixing <span class="class">RefPtr</span> and <span class="class">PassRefPtr</span></h2>
+
+<p>Since we recommend use of <span class="class">RefPtr</span> in all cases except when passing arguments to or
+returning values from a function, there will be times when you have a <span class="class">RefPtr</span>
+and wish to transfer ownership as <span class="class">PassRefPtr</span> does.
+<span class="class">RefPtr</span> has a member function named
+<span class="function">release</span> which does the trick. It sets the value of the original
+<span class="class">RefPtr</span> to 0 and constructs a <span class="class">PassRefPtr</span>, without
+changing reference counts.</p>
+
+<pre class="code">PassRefPtr&lt;Node&gt; createSpecialNode()
+{
+    RefPtr&lt;Node&gt; a = new Node;
+    a-&gt;setCreated(true);
+    return a.release();
+}
+
+RefPtr&lt;Node&gt; b = createSpecialNode();</pre>
+
+<p>This keeps the efficiency of <span class="class">PassRefPtr</span> while reducing the chance
+that its relatively tricky semantics will cause problems.</p>
+
+<h2>Mixing with raw pointers</h2>
+
+<p>When using a <span class="class">RefPtr</span> to call a function that takes a raw pointer,
+use <span class="function">get</span>.</p>
+
+<pre class="code">printNode(stderr, a.get());</pre>
+
+<p>However, there are operations that can be done on a <span class="class">RefPtr</span>
+or <span class="class">PassRefPtr</span> directly, without resorting to an explicit <span class="function">get</span> call.</p>
+
+<pre class="code">RefPtr&lt;Node&gt; a = createSpecialNode();
+Node* b = getOrdinaryNode();
+
+<span class="comment">// the * operator</span>
+*a = value;
+
+<span class="comment">// the -&gt; operator</span>
+a-&gt;clear();
+
+<span class="comment">// null check in an if statement</span>
+if (a)
+    log("not empty");
+
+<span class="comment">// the ! operator</span>
+if (!a)
+    log("empty");
+
+<span class="comment">// the == and != operators, mixing with raw pointers</span>
+if (a == b)
+    log("equal");
+if (a != b)
+    log("not equal");
+
+<span class="comment">// some type casts</span>
+RefPtr&lt;DerivedNode&gt; d = static_pointer_cast&lt;DerivedNode&gt;(a);</pre>
+
+<p>Normally, <span class="class">RefPtr</span> and <span class="class">PassRefPtr</span>
+enforce a simple rule; they always balance <span class="function">ref</span> and
+<span class="function">deref</span> calls, guaranteeing a programmer can’t miss a
+<span class="function">deref</span>. But in the case where we have a raw pointer,
+already have a reference count, and want to transfer ownership the
+<span class="function">adoptRef</span> function should be used.</p>
+
+<pre class="code"><span class="comment">// warning, requires a pointer that already has a ref</span>
+RefPtr&lt;Node&gt; node = adoptRef(rawNodePointer);</pre>
+
+<p>To transfer from a <span class="class">RefPtr</span> to a raw pointer without
+changing the reference count, <span class="class">PassRefPtr</span> provides the
+<span class="function">releaseRef</span> function.</p>
+
+<pre class="code"><span class="comment">// warning, results in a pointer that must get an explicit deref</span>
+RefPtr&lt;Node&gt; node = createSpecialNode();
+Node* rawNodePointer = node.release().releaseRef();</pre>
+
+<p>Since releaseRef is rarely used, it’s provided only in the
+<span class="class">PassRefPtr</span> class, hence the need to call <span class="function">release</span>,
+then <span class="function">releaseRef</span>. If we find this is used often we could
+provide <span class="function">releaseRef</span> for <span class="class">RefPtr</span> too.</p>
+
+<h2>Guidelines</h2>
+
+<p>We’ve developed these guidelines for use of <span class="class">RefPtr</span>
+and <span class="class">PassRefPtr</span> in WebKit code.</p>
+
+<h3>Local variables</h3>
+<ul>
+<li><p>If ownership and lifetime are guaranteed, a local variable can be a raw pointer.</p></li>
+<li><p>If the code needs to hold ownership or guarantee lifetime, a local variable should
+be a <span class="class">RefPtr</span>.</p></li>
+<li><p>Local variables should never be <span class="class">PassRefPtr</span>.</p></li>
+</ul>
+
+<h3>Data members</h3>
+<ul>
+<li><p>If ownership and lifetime are guaranteed, a data member can be a raw pointer.</p></li>
+<li><p>If the class needs to hold ownership or guarantee lifetime, the data member should
+be a <span class="class">RefPtr</span>.</p></li>
+<li><p>Data members should never be <span class="class">PassRefPtr</span>.</p></li>
+</ul>
+
+<h3>Function arguments</h3>
+<ul>
+<li><p>If a function does not take ownership of an object, the argument should be a raw pointer.</p></li>
+<li><p>If a function does take ownership of an object, the argument should be a <span class="class">PassRefPtr</span>.
+This includes most setter functions.</p>
+<p>Unless the use of the argument is very simple, the argument should be transferred to a
+<span class="class">RefPtr</span> at the start of the function; the argument can be named with
+a “prp” prefix in such cases.</p></li>
+</ul>
+
+<h3>Function results</h3>
+<ul>
+<li><p>If a function’s result is an object, but ownership is not being transferred, the result
+should be a raw pointer. This includes most getter functions.</p></li>
+<li><p>If a function’s result is a new object or ownership is being transferred for any other
+reason, the result should be a <span class="class">PassRefPtr</span>.</p>
+<p>Since local variables are typically <span class="class">RefPtr</span>, it’s common to call
+<span class="function">release</span> in the return statement to transfer the
+<span class="class">RefPtr</span> to the <span class="class">PassRefPtr</span>.</p></li>
+</ul>
+
+<h3>New objects</h3>
+<ul>
+<li><p>New objects should by put into a <span class="class">RefPtr</span> as soon as possible
+after creation to avoid possibly leaking an object while it’s in a floating state.</p></li>
+<li><p>Best idiom is to use a private constructor and have a public factory function that
+returns a <span class="class">PassRefPtr</span>.</p></li>
+</ul>
+
+<h2>Improving this document</h2>
+
+<p>What frequently asked questions are not covered by this document?</p>
+
+<p>Which of these topics should also be covered by this document?</p>
+
+<ul>
+
+<li>Perils of programming with floating objects.</li>
+
+<li>Why we should use create functions that return <span class="class">PassRefPtr</span>
+rather than use <span class="function">new</span> directly.</li>
+
+<li>Perils of programming with <span class="class">TreeShared</span>.</li>
+
+<li>How we we mix reference counting with garbage collection to implement the DOM
+and the JavaScript and Objective-C DOM bindings.</li>
+
+<li>Our desire to rename <span class="class">Shared</span> to <span class="class">RefCounted</span>.</li>
+
+<li>Our desire to eliminate <span class="class">TreeShared</span> and instead have
+<span class="variable">m_firstChild</span> and <span class="variable">m_next</span> be
+<span class="class">ListRefPtr</span> or the equivalent.</li>
+
+<li>Comparison of our intrusive reference counting over other schemes, like the
+external reference counting in Boost <span class="class">shared_ptr</class>.</li>
+
+<li>The <span class="class">OwnPtr</span> class template, and how
+<span class="class">auto_ptr</span> functions as a <span class="class">PassOwnPtr</span>.</li>
+
+<li>The <span class="class">OwnArrayPtr</span> class template,
+and the lack of a <span class="class">PassOwnArrayPtr</span>.</li>
+
+<li>The <span class="class">RetainPtr</span> class template,
+and the lack of a <span class="class">PassRetainPtr</span>.</li>
+
+<li>The <span class="class">DocPtr</span> class template.</li>
+
+<li>The <span class="class">ListRefPtr</span> class template.</li>
+
+</ul>
+
+<p>Any other ideas about improving the clarity, scope, or presentation?</p>
+
+<?php
+    include("../footer.inc");
+?>
old mode 100755 (executable)
new mode 100644 (file)